GetLine.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 $Header$
00004 
00005 */
00006 
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <ctype.h>
00010 #include <string.h>
00011 #include <strings.h>
00012 
00013 #include "Memory.h"
00014 #include "Error.h"
00015 
00016 #include "GetLine.h"
00017 
00018 // Public methods.
00019 
00020 GetLine::GetLine() : Object()
00021 {
00022   _mode = GL_MODE_NORMAL;
00023   _initDone = -1;
00024   _termW = GL_DEFAULT_TERM_WIDTH;
00025   _scroll = GL_DEFAULT_SCROLL;
00026 
00027   _extent = 0;
00028   _searchMode = 0;
00029   _cnt = 0;
00030   _overwrite = 0;
00031   _pos = 0;
00032   _histPrevEntry = 0;
00033 
00034   init();
00035   histInit();
00036 }
00037 
00038 GetLine::~GetLine()
00039 {
00040   cleanup();
00041   histCleanup();
00042 }
00043 
00044 int GetLine::historyAdd(char *buf)
00045 {
00046   if (!buf)
00047     return ERROR(MSG_NULL_POINTER);
00048 
00049   char *p = buf;
00050   int len;
00051 
00052   // In case we call gl_history_add() before we call gl_new().
00053   if (_initDone < 0) { // -1 only on startup.
00054     histInit();
00055     _initDone = 0;
00056   }
00057   while (*p == ' ' || *p == '\t' || *p == '\n')
00058     ++p;
00059   if (*p) {
00060     len = strlen(buf);
00061     if (strchr(p, '\n')) // Previously line already has NL stripped.
00062       --len;
00063     if (_histPrevEntry == 0 || (int)strlen(_histPrevEntry) != len ||
00064         strncmp(_histPrevEntry, buf, len) != 0) {
00065       _histBuf[_histLast] = histSave(buf);
00066       _histPrevEntry = _histBuf[_histLast];
00067       _histLast = (_histLast + 1) % GL_LIMIT_HISTORY_SIZE;
00068       if (_histBuf[_histLast] && *(_histBuf[_histLast]))
00069         MEM_FREE(_histBuf[_histLast]);
00070       _histBuf[_histLast] = "";
00071     }
00072   }
00073   _histPos = _histLast;
00074 
00075   return OK;
00076 }
00077 
00078 int GetLine::setWidth(const int w)
00079 {
00080   if (w >= (int)GL_LIMIT_MIN_SCREEN_WIDTH) {
00081     _termW = w;
00082     _scroll = w / 3;
00083   } else
00084       return ERROR(ERROR_GETLINE_WRONG_SCREEN_WIDTH, w);
00085 
00086   return OK;
00087 }
00088 
00089 int GetLine::setPrompt(const char *prompt)
00090 {
00091   int res;
00092 
00093   bzero(_prompt, sizeof(_prompt));
00094   strncpy(_prompt, prompt, sizeof(_prompt) - 1);
00095   _buf[0] = '\0';
00096 
00097   if (FAILED(res = onInput(_buf)))
00098     return ERROR_BACKTRACE(res);
00099   fixup(_prompt, -2, GL_LIMIT_BUFFER_SIZE);
00100 
00101   return OK;
00102 }
00103 
00104 // Params: c --- next character need to be processsed by getline.
00105 int GetLine::pushChar(char c)
00106 {
00107   int loc, tmp;
00108   int res;
00109 
00110   if (_initDone <= 0)
00111     return OK;
00112 
00113   switch (_mode) {
00114     case GL_MODE_NORMAL:
00115       _extent = 0; // Reset to full extent.
00116       if (isprint(c)) {
00117         if (_searchMode)
00118           searchAddChar(c);
00119         else
00120           addChar(c);
00121       } else {
00122           if (_searchMode) {
00123             if (c == '\033' || c == '\016' || c == '\020') {
00124               searchTerm();
00125               c = 0; // Ignore the character.
00126             } else
00127                 if (c == '\010' || c == '\177') {
00128                   searchAddChar(-1); // Unwind search String.
00129                   c = 0;
00130                 } else
00131                     if (c != '\022' && c != '\023')
00132                       searchTerm(); // Terminate and handle char.
00133           }
00134           switch (c) {
00135             case '\n':
00136             case '\r': // New line.
00137               if (c == '\n' && _prevCr && _cnt == 0)
00138                 break;
00139               newLine();
00140               _buf[0] = '\0';
00141               break;
00142             case '\001': // ^A
00143               fixup(_prompt, -1, 0);
00144               break;
00145             case '\002': // ^B
00146               fixup(_prompt, -1, _pos - 1);
00147               break;
00148             case '\004': // ^D
00149               if (_cnt == 0) {
00150                 _buf[0] = '\0';
00151                 if (FAILED(res = onOutput(""))) // End session.
00152                   return ERROR_BACKTRACE(res);
00153                 return OK;
00154               } else
00155                   del(0);
00156               break;
00157             case '\005': // ^E
00158               fixup(_prompt, -1, _cnt);
00159               break;
00160             case '\006': // ^F
00161               fixup(_prompt, -1, _pos + 1);
00162               break;
00163             case '\010':
00164             case '\177': // ^H and DEL
00165               del(-1);
00166               break;
00167             case '\t': // TAB
00168               tmp = _pos;
00169               if (FAILED(res = onTab(_buf, onStrlen(_prompt), &tmp, &loc)))
00170                 return ERROR_BACKTRACE(res);
00171               if (loc >= 0 || tmp != _pos)
00172                 fixup(_prompt, loc, tmp);
00173               break;
00174             case '\013': // ^K
00175               kill(_pos);
00176               break;
00177             case '\014': // ^L
00178               redraw();
00179               break;
00180             case '\016': // ^N
00181               strcpy(_buf, histNext());
00182               if (FAILED(res = onInput(_buf)))
00183                 return ERROR_BACKTRACE(res);
00184               fixup(_prompt, 0, GL_LIMIT_BUFFER_SIZE);
00185               break;
00186             case '\017': // ^O
00187               _overwrite = !_overwrite;
00188               break;
00189             case '\020': // ^P
00190               strcpy(_buf, histPrev());
00191               if (FAILED(res = onInput(_buf)))
00192                 return ERROR_BACKTRACE(res);
00193               fixup(_prompt, 0, GL_LIMIT_BUFFER_SIZE);
00194               break;
00195             case '\022': // ^R
00196               searchBack(1);
00197               break;
00198             case '\023': // ^S
00199               searchForw(1);
00200               break;
00201             case '\024': // ^T
00202               transpose();
00203               break;
00204             case '\025': // ^U
00205               kill(0);
00206               break;
00207             case '\031': // ^Y
00208               yank();
00209               break;
00210             case '\033': // ansi arrow keys.
00211               _mode = GL_MODE_ESC;
00212               break;
00213             default: // Ignore all other.
00214               ;
00215           }
00216         }
00217       break;
00218 
00219     case GL_MODE_ESC:
00220       if (c == '[')
00221         _mode = GL_MODE_SQ_PAR;
00222       else {
00223         if (c == 'f' || c == 'F')
00224           word(1);
00225         else
00226           if (c == 'b' || c == 'B')
00227             word(-1);
00228           else
00229             if (FAILED(res = onPutc('\007')))
00230               return ERROR_BACKTRACE(res);
00231         _mode = GL_MODE_NORMAL;
00232       }
00233       break;
00234 
00235     case GL_MODE_SQ_PAR:
00236       switch (c) {
00237         case 'A': // Up
00238           strcpy(_buf, histPrev());
00239           if (FAILED(res = onInput(_buf)))
00240             return ERROR_BACKTRACE(res);
00241           fixup(_prompt, 0, GL_LIMIT_BUFFER_SIZE);
00242           break;
00243         case 'B': // Down
00244           strcpy(_buf, histNext());
00245           if (FAILED(res = onInput(_buf)))
00246             return ERROR_BACKTRACE(res);
00247           fixup(_prompt, 0, GL_LIMIT_BUFFER_SIZE);
00248           break;
00249         case 'C': // Right
00250           fixup(_prompt, -1, _pos + 1);
00251           break;
00252         case 'D': // Left
00253           fixup(_prompt, -1, _pos - 1);
00254           break;
00255         default: // Who knows.
00256           if (FAILED(res = onPutc('\007')))
00257             return ERROR_BACKTRACE(res);
00258           break;
00259       }
00260       _mode = GL_MODE_NORMAL;
00261       break;
00262   }
00263   _prevNl = (c == '\n');
00264   _prevCr = (c == '\r');
00265 
00266   return OK;
00267 }
00268 
00269 // Private methods.
00270 
00271 // Set up variables and terminal.
00272 void GetLine::init()
00273 {
00274   if (_initDone < 0) // -1 only on startup.
00275     histInit();
00276   _initDone = 1;
00277 }
00278 
00279 // Undo effects of GetLine::init, as necessary.
00280 void GetLine::cleanup()
00281 {
00282   _initDone = 0;
00283 }
00284 
00285 // Adds the character c to the input buffer at current location.
00286 void GetLine::addChar(int c)
00287 {
00288   int i;
00289 
00290   if (_cnt >= (int)GL_LIMIT_BUFFER_SIZE - 1)
00291     ERROR(ERROR_GETLINE_INPUT_BUFFER_OVERFLOW);
00292   if (_overwrite == 0 || _pos == _cnt) {
00293     for (i = _cnt; i >= _pos; --i)
00294       _buf[i + 1] = _buf[i];
00295     _buf[_pos] = c;
00296     fixup(_prompt, _pos, _pos + 1);
00297   } else {
00298       _buf[_pos] = c;
00299       _extent = 1;
00300       fixup(_prompt, _pos, _pos + 1);
00301     }
00302 }
00303 
00304 // Adds the kill buffer to the input buffer at current location.
00305 void GetLine::yank()
00306 {
00307   int i, len;
00308   int res;
00309 
00310   len = strlen(_killBuf);
00311   if (len > 0) {
00312     if (_overwrite == 0) {
00313       if (_cnt + len >= (int)GL_LIMIT_BUFFER_SIZE - 1)
00314         ERROR(ERROR_GETLINE_INPUT_BUFFER_OVERFLOW);
00315       for (i = _cnt; i >= _pos; --i)
00316         _buf[i + len] = _buf[i];
00317       for (i = 0; i < len; ++i)
00318         _buf[_pos + i] = _killBuf[i];
00319       fixup(_prompt, _pos, _pos + len);
00320     } else {
00321         if (_pos + len > _cnt) {
00322           if (_pos + len >= (int)GL_LIMIT_BUFFER_SIZE - 1)
00323             ERROR(ERROR_GETLINE_INPUT_BUFFER_OVERFLOW);
00324           _buf[_pos + len] = '\0';
00325         }
00326         for (i = 0; i < len; ++i)
00327           _buf[_pos + i] = _killBuf[i];
00328         _extent = len;
00329         fixup(_prompt, _pos, _pos + len);
00330       }
00331   } else
00332       if (FAILED(res = onPutc('\007')))
00333         ERROR_BACKTRACE(res);
00334 }
00335 
00336 // Switch character under cursor and to left of cursor.
00337 void GetLine::transpose()
00338 {
00339   int c;
00340   int res;
00341 
00342   if (_pos > 0 && _cnt > _pos) {
00343     c = _buf[_pos - 1];
00344     _buf[_pos - 1] = _buf[_pos];
00345     _buf[_pos] = c;
00346     _extent = 2;
00347     fixup(_prompt, _pos - 1, _pos);
00348   } else
00349       if (FAILED(res = onPutc('\007')))
00350         ERROR_BACKTRACE(res);
00351 }
00352 
00353 // Cleans up entire line before returning to caller. A \n is appended.
00354 // If line longer than screen, we redraw starting at beginning.
00355 void GetLine::newLine()
00356 {
00357   int res;
00358 
00359   if (_cnt >= (int)GL_LIMIT_BUFFER_SIZE - 1)
00360     ERROR(ERROR_GETLINE_INPUT_BUFFER_OVERFLOW);
00361   if (FAILED(res = historyAdd(_buf)))
00362     ERROR_BACKTRACE(res);
00363   if (_cnt > 0)
00364     if (FAILED(res = onOutput(_buf)))
00365       ERROR_BACKTRACE(res);
00366   if (FAILED(res = onPutc('\n')))
00367     ERROR_BACKTRACE(res);
00368   _buf[0] = '\0';
00369   if (FAILED(res = onInput(_buf)))
00370     ERROR_BACKTRACE(res);
00371   fixup(_prompt, -2, GL_LIMIT_BUFFER_SIZE);
00372 }
00373 
00374 // Delete a character.  The loc variable can be:
00375 //    -1 : delete character to left of cursor.
00376 //     0 : delete character under cursor.
00377 void GetLine::del(int loc)
00378 {
00379   int i;
00380   int res;
00381 
00382   if ((loc == -1 && _pos > 0) || (loc == 0 && _pos < _cnt)) {
00383     for (i = _pos + loc; i < _cnt; ++i)
00384       _buf[i] = _buf[i + 1];
00385     fixup(_prompt, _pos + loc, _pos + loc);
00386   } else
00387       if (FAILED(res = onPutc('\007')))
00388         ERROR_BACKTRACE(res);
00389 }
00390 
00391 // Delete from pos to the end of line.
00392 void GetLine::kill(int pos)
00393 {
00394   int res;
00395 
00396   if (pos < _cnt) {
00397     strcpy(_killBuf, _buf + pos);
00398     _buf[pos] = '\0';
00399     fixup(_prompt, pos, pos);
00400   } else
00401       if (FAILED(res = onPutc('\007')))
00402         ERROR_BACKTRACE(res);
00403 }
00404 
00405 // Move forward or backword one word.
00406 void GetLine::word(int direction)
00407 {
00408   int pos = _pos;
00409 
00410   if (direction > 0) { // Forward
00411     while (!isspace(_buf[pos]) && pos < _cnt)
00412       ++pos;
00413     while (isspace(_buf[pos]) && pos < _cnt)
00414       ++pos;
00415   } else { // Backword
00416       if (pos > 0)
00417         --pos;
00418       while (isspace(_buf[pos]) && pos > 0)
00419         --pos;
00420       while (!isspace(_buf[pos]) && pos > 0)
00421         --pos;
00422       if (pos < _cnt && isspace(_buf[pos])) // Move onto word.
00423         ++pos;
00424     }
00425   fixup(_prompt, -1, pos);
00426 }
00427 
00428 // Emit a newline, reset and redraw prompt and current input line.
00429 void GetLine::redraw()
00430 {
00431   int res;
00432 
00433   if (_initDone > 0) {
00434     if (FAILED(res = onPutc('\n')))
00435       ERROR_BACKTRACE(res);
00436     fixup(_prompt, -2, _pos);
00437   }
00438 }
00439 
00440 // This function is used both for redrawing when input changes or for
00441 // moving within the input line.  The parameters are:
00442 //   prompt:  compared to lastPrompt[] for changes;
00443 //   change:  the index of the start of changes in the input buffer,
00444 //            with -1 indicating no changes, -2 indicating we are on
00445 //            a new line, redraw everything.
00446 //   cursor:  the desired location of the cursor after the call.
00447 //            A value of GL_LIMIT_BUFFER_SIZE can be used  to indicate the cursor should
00448 //            move just past the end of the input line.
00449 void GetLine::fixup(char *prompt, int change, int cursor)
00450 {
00451   int left = 0, right = -1;     // Bounds for redraw.
00452   int pad;                      // How much to erase at end of line.
00453   int backup;                   // How far to backup before fixing.
00454   int newShift;                // Value of shift based on cursor.
00455   int extra;                    // Adjusts when shift (scroll) happens.
00456   int i;
00457   int newRight = -1;           // Alternate right bound, using gl_extent.
00458   int l1, l2;
00459   int res;
00460 
00461   if (change == -2) { // Reset
00462     _pos = _cnt = _shift = _offRight = _offLeft = 0;
00463     if (FAILED(res = onPutc('\r')))
00464       ERROR_BACKTRACE(res);
00465     if (FAILED(res = onPuts(_prompt)))
00466       ERROR_BACKTRACE(res);
00467     strcpy(_lastPrompt, prompt);
00468     change = 0;
00469     _width = _termW - onStrlen(prompt);
00470   } else
00471       if (strcmp(prompt, _lastPrompt) != 0) {
00472         l1 = onStrlen(_lastPrompt);
00473         l2 = onStrlen(prompt);
00474         _cnt += l1 - l2;
00475         strcpy(_lastPrompt, prompt);
00476         if (FAILED(res = onPutc('\r')))
00477           ERROR_BACKTRACE(res);
00478         if (FAILED(res = onPuts(_prompt)))
00479           ERROR_BACKTRACE(res);
00480         _pos = _shift;
00481         _width = _termW - l2;
00482         change = 0;
00483       }
00484   pad = (_offRight) ? _width - 1 : _cnt - _shift; // Old length.
00485   backup = _pos - _shift;
00486   if (change >= 0) {
00487     _cnt = strlen(_buf);
00488     if (change > _cnt)
00489       change = _cnt;
00490   }
00491   if (cursor > _cnt) {
00492     if (cursor != (int)GL_LIMIT_BUFFER_SIZE) // GL_LIMIT_BUFFER_SIZE means end of line.
00493       if (FAILED(res = onPutc('\007')))
00494         ERROR_BACKTRACE(res);
00495     cursor = _cnt;
00496   }
00497   if (cursor < 0) {
00498     if (FAILED(res = onPutc('\007')))
00499       ERROR_BACKTRACE(res);
00500     cursor = 0;
00501   }
00502   if (_offRight || (_offLeft && cursor < _shift + _width - _scroll / 2))
00503     extra = 2; // Shift the scrolling boundary.
00504   else
00505     extra = 0;
00506   newShift = cursor + extra + _scroll - _width;
00507   if (newShift > 0) {
00508     newShift /= _scroll;
00509     newShift *= _scroll;
00510   } else
00511       newShift = 0;
00512   if (newShift != _shift) { // Scroll occurs.
00513     _shift = newShift;
00514     _offLeft = (_shift) ? 1 : 0;
00515     _offRight = (_cnt > _shift + _width - 1) ? 1 : 0;
00516     left = _shift;
00517     newRight = right = (_offRight) ? _shift + _width - 2 : _cnt;
00518   } else
00519       if (change >= 0) { // No scroll, but text changed.
00520         if (change < _shift + _offLeft)
00521           left = _shift;
00522         else {
00523           left = change;
00524           backup = _pos - change;
00525         }
00526         _offRight = (_cnt > _shift + _width - 1) ? 1 : 0;
00527         right = (_offRight) ? _shift + _width - 2 : _cnt;
00528         newRight = (_extent && (right > left + _extent)) ? left + _extent : right;
00529       }
00530   pad -= _offRight ? _width - 1 : _cnt - _shift;
00531   pad = pad < 0 ? 0 : pad;
00532   if (left <= right) { // Clean up screen.
00533     for (i = 0; i < backup; ++i)
00534       if (FAILED(res = onPutc('\b')))
00535         ERROR_BACKTRACE(res);
00536     if (left == _shift && _offLeft) {
00537       if (FAILED(res = onPutc('$')))
00538         ERROR_BACKTRACE(res);
00539       ++left;
00540     }
00541     for (i = left; i < newRight; ++i)
00542       if (FAILED(res = onPutc(_buf[i])))
00543         ERROR_BACKTRACE(res);
00544     _pos = newRight;
00545     if (_offRight && newRight == right) {
00546       if (FAILED(res = onPutc('$')))
00547         ERROR_BACKTRACE(res);
00548       ++_pos;
00549     } else {
00550         for (i = 0; i < pad; ++i) // Erase remains of prev line.
00551           if (FAILED(res = onPutc(' ')))
00552             ERROR_BACKTRACE(res);
00553         _pos += pad;
00554       }
00555   }
00556   i = _pos - cursor; // Move to final cursor location.
00557   if (i > 0) {
00558     while (i--)
00559       if (FAILED(res = onPutc('\b')))
00560         ERROR_BACKTRACE(res);
00561   } else
00562       for (i = _pos; i < cursor; ++i)
00563         if (FAILED(res = onPutc(_buf[i])))
00564           ERROR_BACKTRACE(res);
00565 
00566   _pos = cursor;
00567 }
00568 
00569 void GetLine::histInit()
00570 {
00571   int i;
00572 
00573   _histBuf[0] = "";
00574   _histPos = 0;
00575   _histLast = 0;
00576   for (i = 1; i < (int)GL_LIMIT_HISTORY_SIZE; ++i)
00577     _histBuf[i] = (char *)0;
00578 }
00579 
00580 void GetLine::histCleanup()
00581 {
00582   int i;
00583 
00584   for (i = 0; i < (int)GL_LIMIT_HISTORY_SIZE; ++i)
00585     if (_histBuf[i] && *(_histBuf[i]))
00586       MEM_FREE(_histBuf[i]);
00587 }
00588 
00589 // Loads previous hist entry into input buffer, sticks on first.
00590 char *GetLine::histPrev()
00591 {
00592   char *p = 0;
00593   int next = (_histPos - 1 + GL_LIMIT_HISTORY_SIZE) % GL_LIMIT_HISTORY_SIZE;
00594   int res;
00595 
00596   if (_histBuf[_histPos] != 0 && next != _histLast) {
00597     _histPos = next;
00598     p = _histBuf[_histPos];
00599   }
00600   if (p == 0) {
00601     p = "";
00602     if (FAILED(res = onPutc('\007')))
00603       ERROR_BACKTRACE(res);
00604   }
00605   return p;
00606 }
00607 
00608 // Loads next hist entry into input buffer, clears on last.
00609 char *GetLine::histNext()
00610 {
00611   char *p = 0;
00612   int res;
00613 
00614   if (_histPos != _histLast) {
00615     _histPos = (_histPos + 1) % GL_LIMIT_HISTORY_SIZE;
00616     p = _histBuf[_histPos];
00617   }
00618   if (p == 0) {
00619     p = "";
00620     if (FAILED(res = onPutc('\007')))
00621       ERROR_BACKTRACE(res);
00622   }
00623   return p;
00624 }
00625 
00626 // Makes a copy of the String.
00627 char *GetLine::histSave(char *p)
00628 {
00629   char *s = 0;
00630   int len = strlen(p);
00631   char *nl = strchr(p, '\n');
00632   int size = 0;
00633 
00634   if (nl) {
00635     if ((s = (char *)MEM_ALLOC(len))) {
00636       strncpy(s, p, len - 1);
00637       s[len - 1] = '\0';
00638     } else
00639         size = len;
00640   } else {
00641       if ((s = (char *)MEM_ALLOC(len + 1)))
00642         strcpy(s, p);
00643       else
00644         size = len + 1;
00645     }
00646   if (s == 0)
00647     ERROR(MSG_MEMORY_CANNOT_ALLOCATE, size, strerror(errno));
00648   return s;
00649 }
00650 
00651 void GetLine::searchUpdate(int c)
00652 {
00653   int res;
00654 
00655   if (c == 0) {
00656     _searchPos = 0;
00657     _searchString[0] = 0;
00658     _searchPrompt[0] = '?';
00659     _searchPrompt[1] = ' ';
00660     _searchPrompt[2] = 0;
00661   } else
00662       if (c > 0) {
00663         _searchString[_searchPos] = c;
00664         _searchString[_searchPos + 1] = 0;
00665         _searchPrompt[_searchPos] = c;
00666         _searchPrompt[_searchPos + 1] = '?';
00667         _searchPrompt[_searchPos + 2] = ' ';
00668         _searchPrompt[_searchPos + 3] = 0;
00669         ++(_searchPos);
00670       } else {
00671           if (_searchPos > 0) {
00672             --(_searchPos);
00673             _searchString[_searchPos] = 0;
00674             _searchPrompt[_searchPos] = '?';
00675             _searchPrompt[_searchPos + 1] = ' ';
00676             _searchPrompt[_searchPos + 2] = 0;
00677           } else {
00678               if (FAILED(res = onPutc('\007')))
00679                 ERROR_BACKTRACE(res);
00680               _histPos = _histLast;
00681             }
00682         }
00683 }
00684 
00685 void GetLine::searchAddChar(int c)
00686 {
00687   char *loc;
00688 
00689   searchUpdate(c);
00690   if (c < 0) {
00691     if (_searchPos > 0)
00692       _histPos = _searchLast;
00693     else {
00694       _buf[0] = '\0';
00695       _histPos = _histLast;
00696     }
00697     strcpy(_buf, _histBuf[_histPos]);
00698   }
00699   if ((loc = strstr(_buf, _searchString)) != 0)
00700     fixup(_searchPrompt, 0, loc - _buf);
00701   else
00702     if (_searchPos > 0) {
00703       if (_searchForwFlg)
00704         searchForw(0);
00705       else
00706         searchBack(0);
00707     } else
00708         fixup(_searchPrompt, 0, 0);
00709 }
00710 
00711 void GetLine::searchTerm()
00712 {
00713   int res;
00714 
00715   _searchMode = 0;
00716   if (_buf[0] == '\0') // Not found, reset hist list.
00717     _histPos = _histLast;
00718   if (FAILED(res = onInput(_buf)))
00719     ERROR_BACKTRACE(res);
00720   fixup(_prompt, 0, _pos);
00721 }
00722 
00723 void GetLine::searchBack(int newSearch)
00724 {
00725   int found = 0;
00726   char *p, *loc;
00727   int res;
00728 
00729   _searchForwFlg = 0;
00730   if (_searchMode == 0) {
00731     _searchLast = _histPos = _histLast;
00732     searchUpdate(0);
00733     _searchMode = 1;
00734     _buf[0] = '\0';
00735     fixup(_searchPrompt, 0, 0);
00736   } else
00737       if (_searchPos > 0) {
00738         while (!found) {
00739           p = histPrev();
00740           if (*p == 0) { // Not found, done looking.
00741             _buf[0] = '\0';
00742             fixup(_searchPrompt, 0, 0);
00743             found = 1;
00744           } else
00745               if ((loc = strstr(p, _searchString)) != 0) {
00746                 strcpy(_buf, p);
00747                 fixup(_searchPrompt, 0, loc - p);
00748                 if (newSearch)
00749                   _searchLast = _histPos;
00750                 found = 1;
00751               }
00752         }
00753       } else
00754           if (FAILED(res = onPutc('\007')))
00755             ERROR_BACKTRACE(res);
00756 }
00757 
00758 void GetLine::searchForw(int newSearch)
00759 {
00760   int found = 0;
00761   char *p, *loc;
00762   int res;
00763 
00764   _searchForwFlg = 1;
00765   if (_searchMode == 0) {
00766     _searchLast = _histPos = _histLast;
00767     searchUpdate(0);
00768     _searchMode = 1;
00769     _buf[0] = '\0';
00770     fixup(_searchPrompt, 0, 0);
00771   } else
00772       if (_searchPos > 0) {
00773         while (!found) {
00774           p = histNext();
00775           if (*p == 0) { // Not found, done looking.
00776             _buf[0] = '\0';
00777             fixup(_searchPrompt, 0, 0);
00778             found = 1;
00779           } else
00780               if ((loc = strstr(p, _searchString)) != 0) {
00781                 strcpy(_buf, p);
00782                 fixup(_searchPrompt, 0, loc - p);
00783                 if (newSearch)
00784                   _searchLast = _histPos;
00785                 found = 1;
00786               }
00787         }
00788       } else
00789           if (FAILED(res = onPutc('\007')))
00790             ERROR_BACKTRACE(res);
00791 }
00792 
00793 // Default event handlers.
00794 
00795 int GetLine::onInput(const char *)
00796 {
00797   return OK;
00798 }
00799 
00800 // Default tab handler, acts like tabstops every 8 cols.
00801 int GetLine::onTab(char *buf, const int offset, int *loc, int *i)
00802 {
00803   int count, len;
00804 
00805   len = strlen(buf);
00806   count = 8 - (offset + *loc) % 8;
00807   for (*i = len; *i >= *loc; --i)
00808     buf[*i + count] = buf[*i];
00809   for (*i = 0; *i < count; ++(*i))
00810     buf[*loc + *i] = ' ';
00811   *i = *loc;
00812   *loc = *i + count;
00813   return OK;
00814 }
00815 
00816 unsigned int GetLine::onStrlen(const char *str)
00817 {
00818   return strlen(str);
00819 }
00820 
00821 String GetLine::prompt() const
00822 {
00823   return _prompt;
00824 }

Generated on Thu Sep 6 20:11:25 2007 for Pylon Application Platform by  doxygen 1.5.1