* Copyright (c) 1992 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Christos Zoulas of Cornell University.
* %sccs.include.redist.c%
#if !defined(lint) && !defined(SCCSID)
static char sccsid
[] = "@(#)search.c 5.5 (Berkeley) %G%";
#endif /* not lint && not SCCSID */
* search.c: History and character search functions
* Adjust cursor in vi mode to include the character under it
((el)->el_line.cursor + (((el)->el_map.type == MAP_VI) && \
((el)->el_map.current == (el)->el_map.alt)))
* Initialize the search stuff
el
->el_search
.patbuf
= (char *) el_malloc(EL_BUFSIZ
);
el
->el_search
.patlen
= 0;
el
->el_search
.patdir
= -1;
el
->el_search
.chacha
= '\0';
el
->el_search
.chadir
= -1;
* Initialize the search stuff
el_free((ptr_t
) el
->el_search
.patbuf
);
el
->el_search
.patbuf
= NULL
;
* Handle regular expression errors
* Return if string matches pattern
extern char *re_comp
__P((const char *));
extern int re_exec
__P((const char *));
if (strstr(str
, pat
) != NULL
)
if (re_comp(pat
) != NULL
)
return re_exec(str
) == 1;
if ((re
= regcomp(pat
)) != NULL
) {
* return True if the pattern matches the prefix
(void) fprintf(el
->el_errfile
, "match `%s' with `%s'\n",
el
->el_search
.patbuf
, str
);
return el_match(str
, el
->el_search
.patbuf
);
* Set the history seatch pattern
if (el
->el_state
.lastcmd
!= ED_SEARCH_PREV_HISTORY
&&
el
->el_state
.lastcmd
!= ED_SEARCH_NEXT_HISTORY
) {
el
->el_search
.patlen
= EL_CURSOR(el
) - el
->el_line
.buffer
;
if (el
->el_search
.patlen
>= EL_BUFSIZ
)
el
->el_search
.patlen
= EL_BUFSIZ
-1;
if (el
->el_search
.patlen
>= 0) {
(void) strncpy(el
->el_search
.patbuf
, el
->el_line
.buffer
,
el
->el_search
.patbuf
[el
->el_search
.patlen
] = '\0';
el
->el_search
.patlen
= strlen(el
->el_search
.patbuf
);
(void) fprintf(el
->el_errfile
, "\neventno = %d\n", el
->el_history
.eventno
);
(void) fprintf(el
->el_errfile
, "patlen = %d\n", el
->el_search
.patlen
);
(void) fprintf(el
->el_errfile
, "patbuf = \"%s\"\n", el
->el_search
.patbuf
);
(void) fprintf(el
->el_errfile
, "cursor %d lastchar %d\n",
EL_CURSOR(el
) - el
->el_line
.buffer
,
el
->el_line
.lastchar
- el
->el_line
.buffer
);
* Emacs incremental search
static char STRfwd
[] = { 'f', 'w', 'd', '\0' },
STRbck
[] = { 'b', 'c', 'k', '\0' };
static char pchar
= ':'; /* ':' = normal, '?' = failed */
static char endcmd
[2] = { '\0', '\0' };
char ch
, *cp
, *ocursor
= el
->el_line
.cursor
, oldpchar
= pchar
;
el_action_t ret
= CC_NORM
;
int ohisteventno
= el
->el_history
.eventno
,
oldpatlen
= el
->el_search
.patlen
,
if (el
->el_line
.lastchar
+ sizeof(STRfwd
) / sizeof(char) + 2 +
el
->el_search
.patlen
>= el
->el_line
.limit
)
if (el
->el_search
.patlen
== 0) { /* first round */
el
->el_search
.patbuf
[el
->el_search
.patlen
++] = '.';
el
->el_search
.patbuf
[el
->el_search
.patlen
++] = '*';
*el
->el_line
.lastchar
++ = '\n';
for (cp
= newdir
== ED_SEARCH_PREV_HISTORY
? STRbck
: STRfwd
;
*cp
; *el
->el_line
.lastchar
++ = *cp
++)
*el
->el_line
.lastchar
++ = pchar
;
for (cp
= &el
->el_search
.patbuf
[1];
cp
< &el
->el_search
.patbuf
[el
->el_search
.patlen
];
*el
->el_line
.lastchar
++ = *cp
++)
*el
->el_line
.lastchar
= '\0';
if (el_getc(el
, &ch
) != 1)
return ed_end_of_file(el
, 0);
switch (el
->el_map
.current
[(unsigned char) ch
]) {
if (el
->el_search
.patlen
> EL_BUFSIZ
- 3)
el
->el_search
.patbuf
[el
->el_search
.patlen
++] = ch
;
*el
->el_line
.lastchar
++ = ch
;
*el
->el_line
.lastchar
= '\0';
newdir
= ED_SEARCH_NEXT_HISTORY
;
newdir
= ED_SEARCH_PREV_HISTORY
;
case ED_DELETE_PREV_CHAR
:
if (el
->el_search
.patlen
> 1)
case 0007: /* ^G: Abort */
case 0027: /* ^W: Append word */
/* No can do if globbing characters in pattern */
for (cp
= &el
->el_search
.patbuf
[1]; ; cp
++)
if (cp
>= &el
->el_search
.patbuf
[el
->el_search
.patlen
]) {
el
->el_line
.cursor
+= el
->el_search
.patlen
- 1;
cp
= c__next_word(el
->el_line
.cursor
,
el
->el_line
.lastchar
, 1, ce__isword
);
while (el
->el_line
.cursor
< cp
&&
*el
->el_line
.cursor
!= '\n') {
if (el
->el_search
.patlen
> EL_BUFSIZ
- 3) {
el
->el_search
.patbuf
[el
->el_search
.patlen
++] =
*el
->el_line
.lastchar
++ = *el
->el_line
.cursor
++;
el
->el_line
.cursor
= ocursor
;
*el
->el_line
.lastchar
= '\0';
} else if (isglob(*cp
)) {
default: /* Terminate and execute cmd */
case 0033: /* ESC: Terminate */
while (el
->el_line
.lastchar
> el
->el_line
.buffer
&&
*el
->el_line
.lastchar
!= '\n')
*el
->el_line
.lastchar
-- = '\0';
*el
->el_line
.lastchar
= '\0';
/* Can't search if unmatched '[' */
for (cp
= &el
->el_search
.patbuf
[el
->el_search
.patlen
-1], ch
= ']';
cp
> el
->el_search
.patbuf
; cp
--)
if (*cp
== '[' || *cp
== ']') {
if (el
->el_search
.patlen
> 1 && ch
!= '[') {
if (redo
&& newdir
== dir
) {
if (pchar
== '?') { /* wrap around */
newdir
== ED_SEARCH_PREV_HISTORY
? 0 : 0x7fffffff;
if (hist_get(el
) == CC_ERROR
)
/* el->el_history.eventno was fixed by first call */
el
->el_line
.cursor
= newdir
== ED_SEARCH_PREV_HISTORY
?
el
->el_line
.lastchar
: el
->el_line
.buffer
;
newdir
== ED_SEARCH_PREV_HISTORY
? -1 : 1;
el
->el_search
.patbuf
[el
->el_search
.patlen
++] = '.';
el
->el_search
.patbuf
[el
->el_search
.patlen
++] = '*';
el
->el_search
.patbuf
[el
->el_search
.patlen
] = '\0';
if (el
->el_line
.cursor
< el
->el_line
.buffer
||
el
->el_line
.cursor
> el
->el_line
.lastchar
||
(ret
= ce_search_line(el
, &el
->el_search
.patbuf
[1],
el
->el_state
.lastcmd
= (el_action_t
) newdir
;
ret
= newdir
== ED_SEARCH_PREV_HISTORY
?
ed_search_prev_history(el
, 0) :
ed_search_next_history(el
, 0);
el
->el_line
.cursor
= newdir
== ED_SEARCH_PREV_HISTORY
?
el
->el_line
.lastchar
: el
->el_line
.buffer
;
(void) ce_search_line(el
, &el
->el_search
.patbuf
[1],
el
->el_search
.patbuf
[--el
->el_search
.patlen
] = '\0';
if (el
->el_history
.eventno
!= ohisteventno
) {
el
->el_history
.eventno
= ohisteventno
;
if (hist_get(el
) == CC_ERROR
)
el
->el_line
.cursor
= ocursor
;
ret
= ce_inc_search(el
, newdir
);
if (ret
== CC_ERROR
&& pchar
== '?' && oldpchar
== ':')
/* break abort of failed search at last non-failed */
if (ret
== CC_NORM
|| (ret
== CC_ERROR
&& oldpatlen
== 0)) {
/* restore on normal return or error exit */
el
->el_search
.patlen
= oldpatlen
;
if (el
->el_history
.eventno
!= ohisteventno
) {
el
->el_history
.eventno
= ohisteventno
;
if (hist_get(el
) == CC_ERROR
)
el
->el_line
.cursor
= ocursor
;
if (done
|| ret
!= CC_NORM
)
el
->el_line
.buffer
[0] = '\0';
el
->el_line
.lastchar
= el
->el_line
.buffer
;
el
->el_line
.cursor
= el
->el_line
.buffer
;
el
->el_search
.patdir
= dir
;
c_insert(el
, 2); /* prompt + '\n' */
*el
->el_line
.cursor
++ = '\n';
*el
->el_line
.cursor
++ = dir
== ED_SEARCH_PREV_HISTORY
? '/' : '?';
tmplen
= c_gets(el
, &tmpbuf
[LEN
]) + LEN
;
* Use the old pattern, but wild-card it.
if (el
->el_search
.patlen
== 0) {
el
->el_line
.buffer
[0] = '\0';
el
->el_line
.lastchar
= el
->el_line
.buffer
;
el
->el_line
.cursor
= el
->el_line
.buffer
;
if (el
->el_search
.patbuf
[0] != '.' && el
->el_search
.patbuf
[0] != '*') {
(void) strcpy(tmpbuf
, el
->el_search
.patbuf
);
el
->el_search
.patbuf
[0] = '.';
el
->el_search
.patbuf
[1] = '*';
(void) strcpy(&el
->el_search
.patbuf
[2], tmpbuf
);
el
->el_search
.patbuf
[el
->el_search
.patlen
++] = '.';
el
->el_search
.patbuf
[el
->el_search
.patlen
++] = '*';
el
->el_search
.patbuf
[el
->el_search
.patlen
] = '\0';
(void) strcpy(el
->el_search
.patbuf
, tmpbuf
);
el
->el_search
.patlen
= tmplen
;
el
->el_state
.lastcmd
= (el_action_t
) dir
; /* avoid c_setpat */
el
->el_line
.cursor
= el
->el_line
.lastchar
= el
->el_line
.buffer
;
if ((dir
== ED_SEARCH_PREV_HISTORY
? ed_search_prev_history(el
, 0) :
ed_search_next_history(el
, 0)) == CC_ERROR
) {
*el
->el_line
.lastchar
++ = '\n';
*el
->el_line
.lastchar
= '\0';
* Look for a pattern inside a line
ce_search_line(el
, pattern
, dir
)
if (dir
== ED_SEARCH_PREV_HISTORY
) {
for (cp
= el
->el_line
.cursor
; cp
>= el
->el_line
.buffer
; cp
--)
if (el_match(cp
, pattern
)) {
for (cp
= el
->el_line
.cursor
; *cp
!= '\0' &&
cp
< el
->el_line
.limit
; cp
++)
if (el_match(cp
, pattern
)) {
(void) fprintf(el
->el_errfile
, "dir %d patlen %d patbuf %s\n",
c
, el
->el_search
.patlen
, el
->el_search
.patbuf
);
el
->el_state
.lastcmd
= (el_action_t
) c
; /* Hack to stop c_setpat */
el
->el_line
.lastchar
= el
->el_line
.buffer
;
case ED_SEARCH_NEXT_HISTORY
:
return ed_search_next_history(el
, 0);
case ED_SEARCH_PREV_HISTORY
:
return ed_search_prev_history(el
, 0);
* Vi character search reverse
cv_csearch_back(el
, ch
, count
, tflag
)
while (cp
> el
->el_line
.buffer
&& *cp
!= ch
)
if (cp
< el
->el_line
.buffer
|| (cp
== el
->el_line
.buffer
&& *cp
!= ch
))
if (el
->el_chared
.c_vcmd
.action
& DELETE
) {
* Vi character search forward
cv_csearch_fwd(el
, ch
, count
, tflag
)
while (cp
< el
->el_line
.lastchar
&& *cp
!= ch
)
if (cp
>= el
->el_line
.lastchar
)
if (el
->el_chared
.c_vcmd
.action
& DELETE
) {