00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include "compat.h"
00047
00048
00049
00050
00051 #include "sys.h"
00052 #include <stdlib.h>
00053 #if HAVE_SYS_TYPES_H
00054 # include <sys/types.h>
00055 #endif
00056 #if defined(REGEX)
00057 # include <regex.h>
00058 #elif defined(REGEXP)
00059 # include <regexp.h>
00060 #endif
00061 #include "el.h"
00062 #include "enhance.h"
00063
00064 #define ANCHOR_SEARCHES 1
00065
00066
00067
00068
00069
00070 #define EL_CURSOR(el) \
00071 ((el)->fLine.fCursor + (((el)->fMap.fType == MAP_VI) && \
00072 ((el)->fMap.fCurrent == (el)->fMap.fAlt)))
00073
00074
00075
00076
00077 el_protected int
00078 search_init(EditLine_t* el) {
00079 el->fSearch.fPatBuf = (char*) el_malloc(EL_BUFSIZ);
00080
00081 if (el->fSearch.fPatBuf == NULL) {
00082 return -1;
00083 }
00084 el->fSearch.fPatLen = 0;
00085 el->fSearch.fPatDir = -1;
00086 el->fSearch.fChaCha = '\0';
00087 el->fSearch.fChaDir = -1;
00088 return 0;
00089 }
00090
00091
00092
00093
00094
00095 el_protected void
00096 search_end(EditLine_t* el) {
00097 el_free((ptr_t) el->fSearch.fPatBuf);
00098 el->fSearch.fPatBuf = NULL;
00099 }
00100
00101
00102 #ifdef REGEXP
00103
00104
00105
00106
00107 el_public void
00108
00109 regerror(const char* msg) {
00110 }
00111
00112
00113 #endif
00114
00115
00116
00117
00118
00119 el_protected int
00120 el_match(const char* str, const char* pat) {
00121 #if defined(REGEX)
00122 regex_t re;
00123 int rv;
00124 #elif defined(REGEXP)
00125 regexp* rp;
00126 int rv;
00127 #else
00128 extern char* re_comp(const char*);
00129 extern int re_exec(const char*);
00130 #endif
00131
00132 if (strstr(str, pat) != NULL) {
00133 return 1;
00134 }
00135
00136 #if defined(REGEX)
00137
00138 if (regcomp(&re, pat, 0) == 0) {
00139 rv = regexec(&re, str, 0, NULL, 0) == 0;
00140 regfree(&re);
00141 } else {
00142 rv = 0;
00143 }
00144 return rv;
00145 #elif defined(REGEXP)
00146
00147 if ((re = regcomp(pat)) != NULL) {
00148 rv = regexec(re, str);
00149 free((ptr_t) re);
00150 } else {
00151 rv = 0;
00152 }
00153 return rv;
00154 #else
00155
00156 if (re_comp(pat) != NULL) {
00157 return 0;
00158 } else {
00159 return re_exec(str) == 1;
00160 }
00161 #endif
00162 }
00163
00164
00165
00166
00167
00168 el_protected int
00169 c_hmatch(EditLine_t* el, const char* str) {
00170 #ifdef SDEBUG
00171 (void) fprintf(el->fErrFile, "match `%s' with `%s'\n",
00172 el->fSearch.fPatBuf, str);
00173 #endif
00174
00175 return el_match(str, el->fSearch.fPatBuf);
00176 }
00177
00178
00179
00180
00181
00182 el_protected void
00183 c_setpat(EditLine_t* el) {
00184 if (el->fState.fLastCmd != ED_SEARCH_PREV_HISTORY &&
00185 el->fState.fLastCmd != ED_SEARCH_NEXT_HISTORY) {
00186 el->fSearch.fPatLen = EL_CURSOR(el) - el->fLine.fBuffer;
00187
00188 if (el->fSearch.fPatLen >= EL_BUFSIZ) {
00189 el->fSearch.fPatLen = EL_BUFSIZ - 1;
00190 }
00191
00192 if (el->fSearch.fPatLen != 0) {
00193 (void) strncpy(el->fSearch.fPatBuf, el->fLine.fBuffer,
00194 el->fSearch.fPatLen);
00195 el->fSearch.fPatBuf[el->fSearch.fPatLen] = '\0';
00196 } else {
00197 el->fSearch.fPatLen = strlen(el->fSearch.fPatBuf);
00198 }
00199 }
00200 #ifdef SDEBUG
00201 (void) fprintf(el->fErrFile, "\neventno = %d\n",
00202 el->fHistory.fEventNo);
00203 (void) fprintf(el->fErrFile, "patlen = %d\n", el->fSearch.fPatLen);
00204 (void) fprintf(el->fErrFile, "patbuf = \"%s\"\n",
00205 el->fSearch.fPatBuf);
00206 (void) fprintf(el->fErrFile, "cursor %d lastchar %d\n",
00207 EL_CURSOR(el) - el->fLine.fBuffer,
00208 el->fLine.fLastChar - el->fLine.fBuffer);
00209 #endif
00210 }
00211
00212
00213
00214
00215
00216 el_protected ElAction_t
00217 ce_inc_search(EditLine_t* el, int dir) {
00218 static const char strfwd[] = { 'f', 'w', 'd', '\0' },
00219 strbck[] = { 'b', 'c', 'k', '\0' };
00220 static char pchar = ':';
00221 static char endcmd[2] = { '\0', '\0' };
00222 char ch, * ocursor = el->fLine.fCursor, oldpchar = pchar;
00223 const char* cp;
00224
00225 ElAction_t ret = CC_NORM;
00226
00227 int ohisteventno = el->fHistory.fEventNo;
00228 int oldpatlen = el->fSearch.fPatLen;
00229 int newdir = dir;
00230 int done, redo;
00231
00232 if (el->fLine.fLastChar + sizeof(strfwd) / sizeof(char) + 2 +
00233 el->fSearch.fPatLen >= el->fLine.fLimit) {
00234 return CC_ERROR;
00235 }
00236
00237 for ( ; ;) {
00238 if (el->fSearch.fPatLen == 0) {
00239 pchar = ':';
00240 #if ANCHOR_SEARCHES
00241 el->fSearch.fPatBuf[el->fSearch.fPatLen++] = '.';
00242 el->fSearch.fPatBuf[el->fSearch.fPatLen++] = '*';
00243 #endif
00244 }
00245 done = redo = 0;
00246 el->fLine.fBufColor[el->fLine.fLastChar - el->fLine.fBuffer] = -1;
00247 *el->fLine.fLastChar++ = '\n';
00248
00249 for (cp = (newdir == ED_SEARCH_PREV_HISTORY) ? strbck : strfwd;
00250 *cp; *el->fLine.fLastChar++ = *cp++) {
00251 el->fLine.fBufColor[el->fLine.fLastChar - el->fLine.fBuffer] = -1;
00252 }
00253 el->fLine.fBufColor[el->fLine.fLastChar - el->fLine.fBuffer] = -1;
00254 *el->fLine.fLastChar++ = pchar;
00255 #if ANCHOR_SEARCHES
00256 cp = &el->fSearch.fPatBuf[2];
00257 #else
00258 cp = &el->fSearch.fPatBuf[1];
00259 #endif
00260
00261 for ( ;
00262 cp < &el->fSearch.fPatBuf[el->fSearch.fPatLen];
00263 *el->fLine.fLastChar++ = *cp++) {
00264 el->fLine.fBufColor[el->fLine.fLastChar - el->fLine.fBuffer] = -1;
00265 continue;
00266 }
00267 el->fLine.fBufColor[el->fLine.fLastChar - el->fLine.fBuffer] = -1;
00268 *el->fLine.fLastChar = '\0';
00269
00270
00271
00272 re_refresh(el);
00273
00274 if (el_getc(el, &ch) != 1) {
00275 return ed_end_of_file(el, 0);
00276 }
00277
00278
00279
00280
00281
00282 switch (el->fMap.fCurrent[(unsigned char) ch]) {
00283 case ED_INSERT:
00284 case ED_DIGIT:
00285
00286 if (el->fSearch.fPatLen > EL_BUFSIZ - 3) {
00287 term_beep(el);
00288 } else {
00289 el->fSearch.fPatBuf[el->fSearch.fPatLen++] =
00290 ch;
00291 el->fLine.fBufColor[el->fLine.fLastChar - el->fLine.fBuffer] = -1;
00292 *el->fLine.fLastChar++ = ch;
00293 el->fLine.fBufColor[el->fLine.fLastChar - el->fLine.fBuffer] = -1;
00294 *el->fLine.fLastChar = '\0';
00295 re_refresh(el);
00296 }
00297 break;
00298
00299 case EM_INC_SEARCH_NEXT:
00300 newdir = ED_SEARCH_NEXT_HISTORY;
00301 redo++;
00302 break;
00303
00304 case EM_INC_SEARCH_PREV:
00305 newdir = ED_SEARCH_PREV_HISTORY;
00306 redo++;
00307 break;
00308
00309 case ED_DELETE_PREV_CHAR:
00310
00311 if (el->fSearch.fPatLen > 1) {
00312 done++;
00313 } else {
00314 term_beep(el);
00315 }
00316 break;
00317
00318 default:
00319
00320 switch (ch) {
00321 case 0007:
00322 ret = CC_ERROR;
00323 done++;
00324 break;
00325
00326 case 0027:
00327
00328
00329 for (cp = &el->fSearch.fPatBuf[1]; ; cp++) {
00330 if (cp >= &el->fSearch.fPatBuf[el->fSearch.fPatLen]) {
00331 el->fLine.fCursor +=
00332 el->fSearch.fPatLen - 1;
00333 cp = c__next_word(el->fLine.fCursor,
00334 el->fLine.fLastChar, 1,
00335 ce__isword);
00336
00337 while (el->fLine.fCursor < cp &&
00338 *el->fLine.fCursor != '\n') {
00339 if (el->fSearch.fPatLen >
00340 EL_BUFSIZ - 3) {
00341 term_beep(el);
00342 break;
00343 }
00344 el->fSearch.fPatBuf[el->fSearch.fPatLen++] =
00345 *el->fLine.fCursor;
00346 el->fLine.fBufColor[el->fLine.fLastChar - el->fLine.fBuffer] =
00347 el->fLine.fBufColor[el->fLine.fCursor - el->fLine.fBuffer];
00348 *el->fLine.fLastChar++ =
00349 *el->fLine.fCursor++;
00350 }
00351 el->fLine.fCursor = ocursor;
00352 el->fLine.fBufColor[el->fLine.fLastChar - el->fLine.fBuffer] = -1;
00353 *el->fLine.fLastChar = '\0';
00354 re_refresh(el);
00355 break;
00356 } else if (isglob(*cp)) {
00357 term_beep(el);
00358 break;
00359 }
00360 }
00361 break;
00362
00363 default:
00364 endcmd[0] = ch;
00365 el_push(el, endcmd);
00366 ret = CC_REFRESH;
00367 done++;
00368 break;
00369 }
00370 break;
00371 }
00372
00373 while (el->fLine.fLastChar > el->fLine.fBuffer &&
00374 *el->fLine.fLastChar != '\n') {
00375 el->fLine.fBufColor[el->fLine.fLastChar - el->fLine.fBuffer] = -1;
00376 *el->fLine.fLastChar-- = '\0';
00377 }
00378 el->fLine.fBufColor[el->fLine.fLastChar - el->fLine.fBuffer] = -1;
00379 *el->fLine.fLastChar = '\0';
00380
00381 if (!done) {
00382
00383 ch = ']';
00384 for (cp = &el->fSearch.fPatBuf[el->fSearch.fPatLen - 1];
00385 cp > el->fSearch.fPatBuf; cp--) {
00386 if (*cp == '[' || *cp == ']') {
00387 ch = *cp;
00388 break;
00389 }
00390 }
00391
00392 if (el->fSearch.fPatLen > 1 && ch != '[') {
00393 if (redo && newdir == dir) {
00394 if (pchar == '?') {
00395 el->fHistory.fEventNo =
00396 newdir == ED_SEARCH_PREV_HISTORY ? 0 : 0x7fffffff;
00397
00398 if (hist_get(el) == CC_ERROR) {
00399
00400
00401
00402 (void) hist_get(el);
00403 }
00404 el->fLine.fCursor = newdir ==
00405 ED_SEARCH_PREV_HISTORY ?
00406 el->fLine.fLastChar :
00407 el->fLine.fBuffer;
00408 } else {
00409 el->fLine.fCursor +=
00410 newdir ==
00411 ED_SEARCH_PREV_HISTORY ?
00412 -1 : 1;
00413 }
00414 }
00415 #if ANCHOR_SEARCHES
00416 el->fSearch.fPatBuf[el->fSearch.fPatLen++] =
00417 '.';
00418 el->fSearch.fPatBuf[el->fSearch.fPatLen++] =
00419 '*';
00420 #endif
00421 el->fSearch.fPatBuf[el->fSearch.fPatLen] =
00422 '\0';
00423
00424 if (el->fLine.fCursor < el->fLine.fBuffer ||
00425 el->fLine.fCursor > el->fLine.fLastChar ||
00426 (ret = ce_search_line(el, &el->fSearch.fPatBuf[1], newdir)) == CC_ERROR) {
00427
00428 el->fState.fLastCmd =
00429 (ElAction_t) newdir;
00430 ret = newdir == ED_SEARCH_PREV_HISTORY ?
00431 ed_search_prev_history(el, 0) :
00432 ed_search_next_history(el, 0);
00433
00434 if (ret != CC_ERROR) {
00435 el->fLine.fCursor = newdir ==
00436 ED_SEARCH_PREV_HISTORY ?
00437 el->fLine.fLastChar :
00438 el->fLine.fBuffer;
00439 (void) ce_search_line(el,
00440 &el->fSearch.fPatBuf[1],
00441 newdir);
00442 }
00443 }
00444 #if ANCHOR_SEARCHES
00445 el->fSearch.fPatLen -= 2;
00446 el->fSearch.fPatBuf[el->fSearch.fPatLen] = 0;
00447 #else
00448 el->fSearch.fPatBuf[--el->fSearch.fPatLen] = 0;
00449 #endif
00450
00451 if (ret == CC_ERROR) {
00452 term_beep(el);
00453
00454 if (el->fHistory.fEventNo !=
00455 ohisteventno) {
00456 el->fHistory.fEventNo =
00457 ohisteventno;
00458
00459 if (hist_get(el) == CC_ERROR) {
00460 return CC_ERROR;
00461 }
00462 }
00463 el->fLine.fCursor = ocursor;
00464 pchar = '?';
00465 } else {
00466 pchar = ':';
00467 }
00468 }
00469 ret = ce_inc_search(el, newdir);
00470
00471 if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
00472
00473
00474
00475
00476 ret = CC_NORM;
00477 }
00478
00479 }
00480
00481 if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
00482
00483 pchar = oldpchar;
00484 el->fSearch.fPatLen = oldpatlen;
00485
00486 if (el->fHistory.fEventNo != ohisteventno) {
00487 el->fHistory.fEventNo = ohisteventno;
00488
00489 if (hist_get(el) == CC_ERROR) {
00490 return CC_ERROR;
00491 }
00492 }
00493 el->fLine.fCursor = ocursor;
00494
00495 if (ret == CC_ERROR) {
00496 re_refresh(el);
00497 }
00498 }
00499
00500 if (done || ret != CC_NORM) {
00501 return ret;
00502 }
00503 }
00504 }
00505
00506
00507
00508
00509
00510 el_protected ElAction_t
00511 cv_search(EditLine_t* el, int dir) {
00512 char ch;
00513 char tmpbuf[EL_BUFSIZ];
00514 int tmplen;
00515
00516 tmplen = 0;
00517 #if ANCHOR_SEARCHES
00518 tmpbuf[tmplen++] = '.';
00519 tmpbuf[tmplen++] = '*';
00520 #endif
00521
00522 el->fLine.fBuffer[0] = '\0';
00523 el->fLine.fLastChar = el->fLine.fBuffer;
00524 el->fLine.fCursor = el->fLine.fBuffer;
00525 el->fSearch.fPatDir = dir;
00526
00527 c_insert(el, 2);
00528 *el->fLine.fCursor++ = '\n';
00529 *el->fLine.fCursor++ = dir == ED_SEARCH_PREV_HISTORY ? '/' : '?';
00530 re_refresh(el);
00531
00532 #if ANCHOR_SEARCHES
00533 # define LEN 2
00534 #else
00535 # define LEN 0
00536 #endif
00537
00538 tmplen = c_gets(el, &tmpbuf[LEN]) + LEN;
00539 ch = tmpbuf[tmplen];
00540 tmpbuf[tmplen] = '\0';
00541
00542 if (tmplen == LEN) {
00543
00544
00545
00546 if (el->fSearch.fPatLen == 0) {
00547 el->fLine.fBuffer[0] = '\0';
00548 el->fLine.fLastChar = el->fLine.fBuffer;
00549 el->fLine.fCursor = el->fLine.fBuffer;
00550 re_refresh(el);
00551 return CC_ERROR;
00552 }
00553 #if ANCHOR_SEARCHES
00554
00555 if (el->fSearch.fPatBuf[0] != '.' &&
00556 el->fSearch.fPatBuf[0] != '*') {
00557 (void) strncpy(tmpbuf, el->fSearch.fPatBuf,
00558 sizeof(tmpbuf) - 1);
00559 el->fSearch.fPatBuf[0] = '.';
00560 el->fSearch.fPatBuf[1] = '*';
00561 (void) strncpy(&el->fSearch.fPatBuf[2], tmpbuf,
00562 EL_BUFSIZ - 3);
00563 el->fSearch.fPatLen++;
00564 el->fSearch.fPatBuf[el->fSearch.fPatLen++] = '.';
00565 el->fSearch.fPatBuf[el->fSearch.fPatLen++] = '*';
00566 el->fSearch.fPatBuf[el->fSearch.fPatLen] = '\0';
00567 }
00568 #endif
00569 } else {
00570 #if ANCHOR_SEARCHES
00571 tmpbuf[tmplen++] = '.';
00572 tmpbuf[tmplen++] = '*';
00573 #endif
00574 tmpbuf[tmplen] = '\0';
00575 (void) strncpy(el->fSearch.fPatBuf, tmpbuf, EL_BUFSIZ - 1);
00576 el->fSearch.fPatLen = tmplen;
00577 }
00578 el->fState.fLastCmd = (ElAction_t) dir;
00579 el->fLine.fCursor = el->fLine.fLastChar = el->fLine.fBuffer;
00580
00581 if ((dir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) :
00582 ed_search_next_history(el, 0)) == CC_ERROR) {
00583 re_refresh(el);
00584 return CC_ERROR;
00585 } else {
00586 if (ch == 0033) {
00587 re_refresh(el);
00588 *el->fLine.fLastChar++ = '\n';
00589 *el->fLine.fLastChar = '\0';
00590 re_goto_bottom(el);
00591 return CC_NEWLINE;
00592 } else {
00593 return CC_REFRESH;
00594 }
00595 }
00596 }
00597
00598
00599
00600
00601
00602 el_protected ElAction_t
00603 ce_search_line(EditLine_t* el, char* pattern, int dir) {
00604 char* cp;
00605
00606 if (dir == ED_SEARCH_PREV_HISTORY) {
00607 for (cp = el->fLine.fCursor; cp >= el->fLine.fBuffer; cp--) {
00608 if (el_match(cp, pattern)) {
00609 el->fLine.fCursor = cp;
00610 return CC_NORM;
00611 }
00612 }
00613 return CC_ERROR;
00614 } else {
00615 for (cp = el->fLine.fCursor; *cp != '\0' &&
00616 cp < el->fLine.fLimit; cp++) {
00617 if (el_match(cp, pattern)) {
00618 el->fLine.fCursor = cp;
00619 return CC_NORM;
00620 }
00621 }
00622 return CC_ERROR;
00623 }
00624 }
00625
00626
00627
00628
00629
00630 el_protected ElAction_t
00631 cv_repeat_srch(EditLine_t* el, int c) {
00632 #ifdef SDEBUG
00633 (void) fprintf(el->fErrFile, "dir %d patlen %d patbuf %s\n",
00634 c, el->fSearch.fPatLen, el->fSearch.fPatBuf);
00635 #endif
00636
00637 el->fState.fLastCmd = (ElAction_t) c;
00638 el->fLine.fLastChar = el->fLine.fBuffer;
00639
00640 switch (c) {
00641 case ED_SEARCH_NEXT_HISTORY:
00642 return ed_search_next_history(el, 0);
00643 case ED_SEARCH_PREV_HISTORY:
00644 return ed_search_prev_history(el, 0);
00645 default:
00646 return CC_ERROR;
00647 }
00648 }
00649
00650
00651
00652
00653
00654 el_protected ElAction_t
00655 cv_csearch_back(EditLine_t* el, int ch, int count, int tflag) {
00656 char* cp;
00657
00658 cp = el->fLine.fCursor;
00659
00660 while (count--) {
00661 if (*cp == ch) {
00662 cp--;
00663 }
00664
00665 while (cp > el->fLine.fBuffer && *cp != ch)
00666 cp--;
00667 }
00668
00669 if (cp < el->fLine.fBuffer || (cp == el->fLine.fBuffer && *cp != ch)) {
00670 return CC_ERROR;
00671 }
00672
00673 if (*cp == ch && tflag) {
00674 cp++;
00675 }
00676
00677 el->fLine.fCursor = cp;
00678
00679 if (el->fCharEd.fVCmd.fAction & DELETE) {
00680 el->fLine.fCursor++;
00681 cv_delfini(el);
00682 return CC_REFRESH;
00683 }
00684 re_refresh_cursor(el);
00685 return CC_NORM;
00686 }
00687
00688
00689
00690
00691
00692 el_protected ElAction_t
00693 cv_csearch_fwd(EditLine_t* el, int ch, int count, int tflag) {
00694 char* cp;
00695
00696 cp = el->fLine.fCursor;
00697
00698 while (count--) {
00699 if (*cp == ch) {
00700 cp++;
00701 }
00702
00703 while (cp < el->fLine.fLastChar && *cp != ch)
00704 cp++;
00705 }
00706
00707 if (cp >= el->fLine.fLastChar) {
00708 return CC_ERROR;
00709 }
00710
00711 if (*cp == ch && tflag) {
00712 cp--;
00713 }
00714
00715 el->fLine.fCursor = cp;
00716
00717 if (el->fCharEd.fVCmd.fAction & DELETE) {
00718 el->fLine.fCursor++;
00719 cv_delfini(el);
00720 return CC_REFRESH;
00721 }
00722 re_refresh_cursor(el);
00723 return CC_NORM;
00724 }