/* * This routine does the real work of a backward search. The pattern is * sitting in the external variable "pat". If found, dot is updated, the * window system is notified of the change, and TRUE is returned. If the * string isn't found, FALSE is returned. */ int backsrch(void) { struct line *clp, *tlp; int cbo, tbo, c, i, xcase = 0; char *epp, *pp; int nline, pline; for (epp = &pat[0]; epp[1] != 0; ++epp); clp = curwp->w_dotp; cbo = curwp->w_doto; nline = curwp->w_dotline; for (i = 0; pat[i]; i++) if (ISUPPER(CHARMASK(pat[i]))) xcase = 1; for (;;) { if (cbo == 0) { clp = lback(clp); if (clp == curbp->b_headp) return (FALSE); nline--; cbo = llength(clp) + 1; } if (--cbo == llength(clp)) c = CCHR('J'); else c = lgetc(clp, cbo); if (eq(c, *epp, xcase) != FALSE) { tlp = clp; tbo = cbo; pp = epp; pline = nline; while (pp != &pat[0]) { if (tbo == 0) { tlp = lback(tlp); if (tlp == curbp->b_headp) goto fail; nline--; tbo = llength(tlp) + 1; } if (--tbo == llength(tlp)) c = CCHR('J'); else c = lgetc(tlp, tbo); if (eq(c, *--pp, xcase) == FALSE) { nline = pline; goto fail; } } curwp->w_dotp = tlp; curwp->w_doto = tbo; curwp->w_dotline = nline; curwp->w_rflag |= WFMOVE; return (TRUE); } fail: ; } /* NOTREACHED */ }
/* * This routine does the real work of a forward search. The pattern is sitting * in the external variable "pat". If found, dot is updated, the window system * is notified of the change, and TRUE is returned. If the string isn't found, * FALSE is returned. */ int forwsrch(void) { struct line *clp, *tlp; int cbo, tbo, c, i, xcase = 0; char *pp; int nline; clp = curwp->w_dotp; cbo = curwp->w_doto; nline = curwp->w_dotline; for (i = 0; pat[i]; i++) if (ISUPPER(CHARMASK(pat[i]))) xcase = 1; for (;;) { if (cbo == llength(clp)) { if ((clp = lforw(clp)) == curbp->b_headp) break; nline++; cbo = 0; c = CCHR('J'); } else c = lgetc(clp, cbo++); if (eq(c, pat[0], xcase) != FALSE) { tlp = clp; tbo = cbo; pp = &pat[1]; while (*pp != 0) { if (tbo == llength(tlp)) { tlp = lforw(tlp); if (tlp == curbp->b_headp) goto fail; tbo = 0; c = CCHR('J'); if (eq(c, *pp++, xcase) == FALSE) goto fail; nline++; } else { c = lgetc(tlp, tbo++); if (eq(c, *pp++, xcase) == FALSE) goto fail; } } curwp->w_dotp = tlp; curwp->w_doto = tbo; curwp->w_dotline = nline; curwp->w_rflag |= WFMOVE; return (TRUE); } fail: ; } return (FALSE); }
/* * Display matching character. Matching characters that are not in the * current window are displayed in the echo line. If in the current window, * move dot to the matching character, sit there a while, then move back. */ static void displaymatch(struct line *clp, int cbo) { struct line *tlp; int tbo; int cp; int bufo; int c; int inwindow; char buf[NLINE]; /* * Figure out if matching char is in current window by * searching from the top of the window to dot. */ inwindow = FALSE; for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp); tlp = lforw(tlp)) if (tlp == clp) inwindow = TRUE; if (inwindow == TRUE) { tlp = curwp->w_dotp; /* save current position */ tbo = curwp->w_doto; curwp->w_dotp = clp; /* move to new position */ curwp->w_doto = cbo; curwp->w_rflag |= WFMOVE; update(); /* show match */ ttwait(1000); /* wait for key or 1 second */ curwp->w_dotp = tlp; /* return to old position */ curwp->w_doto = tbo; curwp->w_rflag |= WFMOVE; update(); } else { /* match is not in this window, so display line in echo area */ bufo = 0; for (cp = 0; cp < llength(clp); cp++) { c = lgetc(clp, cp); if (c != '\t' #ifdef NOTAB || (curbp->b_flag & BFNOTAB) #endif ) if (ISCTRL(c)) { buf[bufo++] = '^'; buf[bufo++] = CCHR(c); } else buf[bufo++] = c; else do { buf[bufo++] = ' '; } while (bufo & 7); } buf[bufo++] = '\0'; ewprintf("Matches %s", buf); } }
void ungetkey(int c) { if (use_metakey && pushed && c == CCHR('[')) pushedc |= METABIT; else pushedc = c; pushed = TRUE; }
/* * Wrapper for bindkey() that converts escapes. */ int dobindkey(KEYMAP *map, const char *func, const char *str) { int i; for (i = 0; *str && i < MAXKEY; i++) { /* XXX - convert numbers w/ strol()? */ if (*str == '^' && *(str + 1) != '\0') { key.k_chars[i] = CCHR(toupper(*++str)); } else if (*str == '\\' && *(str + 1) != '\0') { switch (*++str) { case '^': key.k_chars[i] = '^'; break; case 't': case 'T': key.k_chars[i] = '\t'; break; case 'n': case 'N': key.k_chars[i] = '\n'; break; case 'r': case 'R': key.k_chars[i] = '\r'; break; case 'e': case 'E': key.k_chars[i] = CCHR('['); break; case '\\': key.k_chars[i] = '\\'; break; } } else key.k_chars[i] = *str; str++; } key.k_count = i; return (bindkey(&map, func, key.k_chars, key.k_count)); }
int getkey(int flag) { int c; if (flag && !pushed) { if (prompt[0] != '\0' && ttwait(2000)) { /* avoid problems with % */ ewprintf("%s", prompt); /* put the cursor back */ update(CMODE); epresf = KCLEAR; } if (promptp > prompt) *(promptp - 1) = ' '; } if (pushed) { c = pushedc; pushed = FALSE; } else c = ttgetc(); if (bs_map) { if (c == CCHR('H')) c = CCHR('?'); else if (c == CCHR('?')) c = CCHR('H'); } if (use_metakey && (c & METABIT)) { pushedc = c & ~METABIT; pushed = TRUE; c = CCHR('['); } if (flag && promptp < &prompt[PROMPTL - 5]) { promptp = getkeyname(promptp, sizeof(prompt) - (promptp - prompt) - 1, c); *promptp++ = '-'; *promptp = '\0'; } return (c); }
/* * Ask a "yes" or "no" question. Return ABORT if the user answers the * question with the abort ("^G") character. Return FALSE for "no" and * TRUE for "yes". No formatting services are available. No newline * required. */ int eyorn(const char *sp) { int s; if (inmacro) return (TRUE); ewprintf("%s? (y or n) ", sp); for (;;) { s = getkey(FALSE); if (s == 'y' || s == 'Y' || s == ' ') return (TRUE); if (s == 'n' || s == 'N' || s == CCHR('M')) return (FALSE); if (s == CCHR('G')) return (ctrlg(FFRAND, 1)); ewprintf("Please answer y or n. %s? (y or n) ", sp); } /* NOTREACHED */ }
/* * Put character. Watch for control characters, and for the line getting * too long. */ static void eputc(char c) { if (ttcol + 2 < ncol) { if (ISCTRL(c)) { eputc('^'); c = CCHR(c); } ttputc(c); ++ttcol; } }
/* * Find the name of a keystroke. Needs to be changed to handle 8-bit printing * characters and function keys better. Returns a pointer to the terminating * '\0'. Returns NULL on failure. */ char * getkeyname(char *cp, size_t len, int k) { const char *np; size_t copied; if (k < 0) k = CHARMASK(k); /* sign extended char */ switch (k) { case CCHR('@'): np = "C-SPC"; break; case CCHR('I'): np = "TAB"; break; case CCHR('M'): np = "RET"; break; case CCHR('['): np = "ESC"; break; case ' ': np = "SPC"; break; /* yuck again */ case CCHR('?'): np = "DEL"; break; default: #ifdef FKEYS #ifndef MONA if (k >= KFIRST && k <= KLAST && (np = keystrings[k - KFIRST]) != NULL) break; #endif #endif if (k > CCHR('?')) { *cp++ = '0'; *cp++ = ((k >> 6) & 7) + '0'; *cp++ = ((k >> 3) & 7) + '0'; *cp++ = (k & 7) + '0'; *cp = '\0'; return (cp); } else if (k < ' ') {
/* * Do completion on a list of objects. * c is SPACE, TAB, or CR * return TRUE if matched (or partially matched) * FALSE is result is ambiguous, * ABORT on error. */ static int complt(int flags, int c, char *buf, size_t nbuf, int cpos, int *nx) { struct list *lh, *lh2; struct list *wholelist = NULL; int i, nxtra, nhits, bxtra, msglen, nshown; int wflag = FALSE; char *msg; lh = lh2 = NULL; if ((flags & EFFUNC) != 0) { buf[cpos] = '\0'; wholelist = lh = complete_function_list(buf); } else if ((flags & EFBUF) != 0) { lh = &(bheadp->b_list); } else if ((flags & EFFILE) != 0) { buf[cpos] = '\0'; wholelist = lh = make_file_list(buf); } else panic("broken complt call: flags"); if (c == ' ') wflag = TRUE; else if (c != '\t' && c != CCHR('M')) panic("broken complt call: c"); nhits = 0; nxtra = HUGE; for (; lh != NULL; lh = lh->l_next) { if (memcmp(buf, lh->l_name, cpos) != 0) continue; if (nhits == 0) lh2 = lh; ++nhits; if (lh->l_name[cpos] == '\0') nxtra = -1; /* exact match */ else { bxtra = getxtra(lh, lh2, cpos, wflag); if (bxtra < nxtra) nxtra = bxtra; lh2 = lh; } } if (nhits == 0) msg = " [No match]"; else if (nhits > 1 && nxtra == 0) msg = " [Ambiguous. Ctrl-G to cancel]"; else { /* * Being lazy - ought to check length, but all things * autocompleted have known types/lengths. */ if (nxtra < 0 && nhits > 1 && c == ' ') nxtra = 1; /* ??? */ for (i = 0; i < nxtra && cpos < nbuf; ++i) { buf[cpos] = lh2->l_name[cpos]; eputc(buf[cpos++]); } /* XXX should grow nbuf */ ttflush(); free_file_list(wholelist); *nx = nxtra; if (nxtra < 0 && c != CCHR('M')) /* exact */ *nx = 0; return (TRUE); } /* * wholelist is NULL if we are doing buffers. Want to free lists * that were created for us, but not the buffer list! */ free_file_list(wholelist); /* Set up backspaces, etc., being mindful of echo line limit. */ msglen = strlen(msg); nshown = (ttcol + msglen + 2 > ncol) ? ncol - ttcol - 2 : msglen; eputs(msg); ttcol -= (i = nshown); /* update ttcol! */ while (i--) /* move back before msg */ ttputc('\b'); ttflush(); /* display to user */ i = nshown; while (i--) /* blank out on next flush */ eputc(' '); ttcol -= (i = nshown); /* update ttcol on BS's */ while (i--) ttputc('\b'); /* update ttcol again! */ *nx = nxtra; return ((nhits > 0) ? TRUE : FALSE); }
static char * veread(const char *fp, char *buf, size_t nbuf, int flag, va_list ap) { int dynbuf = (buf == NULL); int cpos, epos; /* cursor, end position in buf */ int c, i, y; int cplflag = FALSE; /* display completion list */ int cwin = FALSE; /* completion list created */ int mr = 0; /* match left arrow */ int ml = 0; /* match right arrow */ int esc = 0; /* position in esc pattern */ struct buffer *bp; /* completion list buffer */ struct mgwin *wp; /* window for compl list */ int match; /* esc match found */ int cc, rr; /* saved ttcol, ttrow */ char *ret; /* return value */ static char emptyval[] = ""; /* XXX hackish way to return err msg*/ if (inmacro) { if (dynbuf) { if ((buf = malloc(maclcur->l_used + 1)) == NULL) return (NULL); } else if (maclcur->l_used >= nbuf) return (NULL); bcopy(maclcur->l_text, buf, maclcur->l_used); buf[maclcur->l_used] = '\0'; maclcur = maclcur->l_fp; return (buf); } epos = cpos = 0; ml = mr = esc = 0; cplflag = FALSE; if ((flag & EFNEW) != 0 || ttrow != nrow - 1) { ttcolor(CTEXT); ttmove(nrow - 1, 0); epresf = TRUE; } else eputc(' '); eformat(fp, ap); if ((flag & EFDEF) != 0) { if (buf == NULL) return (NULL); eputs(buf); epos = cpos += strlen(buf); } tteeol(); ttflush(); for (;;) { c = getkey(FALSE); if ((flag & EFAUTO) != 0 && c == CCHR('I')) { if (cplflag == TRUE) { complt_list(flag, buf, cpos); cwin = TRUE; } else if (complt(flag, c, buf, nbuf, epos, &i) == TRUE) { cplflag = TRUE; epos += i; cpos = epos; } continue; } cplflag = FALSE; if (esc > 0) { /* ESC sequence started */ match = 0; if (ml == esc && key_left[ml] && c == key_left[ml]) { match++; if (key_left[++ml] == '\0') { c = CCHR('B'); esc = 0; } } if (mr == esc && key_right[mr] && c == key_right[mr]) { match++; if (key_right[++mr] == '\0') { c = CCHR('F'); esc = 0; } } if (match == 0) { esc = 0; continue; /* hack. how do we know esc pattern is done? */ } if (esc > 0) { esc++; continue; } } switch (c) { case CCHR('A'): /* start of line */ while (cpos > 0) { if (ISCTRL(buf[--cpos]) != FALSE) { ttputc('\b'); --ttcol; } ttputc('\b'); --ttcol; } ttflush(); break; case CCHR('D'): if (cpos != epos) { tteeol(); epos--; rr = ttrow; cc = ttcol; for (i = cpos; i < epos; i++) { buf[i] = buf[i + 1]; eputc(buf[i]); } ttmove(rr, cc); ttflush(); } break; case CCHR('E'): /* end of line */ while (cpos < epos) { eputc(buf[cpos++]); } ttflush(); break; case CCHR('B'): /* back */ if (cpos > 0) { if (ISCTRL(buf[--cpos]) != FALSE) { ttputc('\b'); --ttcol; } ttputc('\b'); --ttcol; ttflush(); } break; case CCHR('F'): /* forw */ if (cpos < epos) { eputc(buf[cpos++]); ttflush(); } break; case CCHR('Y'): /* yank from kill buffer */ i = 0; while ((y = kremove(i++)) >= 0 && y != '\n') { int t; if (dynbuf && epos + 1 >= nbuf) { void *newp; size_t newsize = epos + epos + 16; if ((newp = realloc(buf, newsize)) == NULL) goto memfail; buf = newp; nbuf = newsize; } if (!dynbuf && epos + 1 >= nbuf) { ewprintf("Line too long"); return (emptyval); } for (t = epos; t > cpos; t--) buf[t] = buf[t - 1]; buf[cpos++] = (char)y; epos++; eputc((char)y); cc = ttcol; rr = ttrow; for (t = cpos; t < epos; t++) eputc(buf[t]); ttmove(rr, cc); } ttflush(); break; case CCHR('K'): /* copy here-EOL to kill buffer */ kdelete(); for (i = cpos; i < epos; i++) kinsert(buf[i], KFORW); tteeol(); epos = cpos; ttflush(); break; case CCHR('['): ml = mr = esc = 1; break; case CCHR('J'): c = CCHR('M'); /* FALLTHROUGH */ case CCHR('M'): /* return, done */ /* if there's nothing in the minibuffer, abort */ if (epos == 0 && !(flag & EFNUL)) { (void)ctrlg(FFRAND, 0); ttflush(); return (NULL); } if ((flag & EFFUNC) != 0) { if (complt(flag, c, buf, nbuf, epos, &i) == FALSE) continue; if (i > 0) epos += i; } buf[epos] = '\0'; if ((flag & EFCR) != 0) { ttputc(CCHR('M')); ttflush(); } if (macrodef) { struct line *lp; if ((lp = lalloc(cpos)) == NULL) goto memfail; lp->l_fp = maclcur->l_fp; maclcur->l_fp = lp; lp->l_bp = maclcur; maclcur = lp; bcopy(buf, lp->l_text, cpos); } ret = buf; goto done; case CCHR('G'): /* bell, abort */ eputc(CCHR('G')); (void)ctrlg(FFRAND, 0); ttflush(); ret = NULL; goto done; case CCHR('H'): /* rubout, erase */ case CCHR('?'): if (cpos != 0) { y = buf[--cpos]; epos--; ttputc('\b'); ttcol--; if (ISCTRL(y) != FALSE) { ttputc('\b'); ttcol--; } rr = ttrow; cc = ttcol; for (i = cpos; i < epos; i++) { buf[i] = buf[i + 1]; eputc(buf[i]); } ttputc(' '); if (ISCTRL(y) != FALSE) { ttputc(' '); ttputc('\b'); } ttputc('\b'); ttmove(rr, cc); ttflush(); } break; case CCHR('X'): /* kill line */ case CCHR('U'): while (cpos != 0) { ttputc('\b'); ttputc(' '); ttputc('\b'); --ttcol; if (ISCTRL(buf[--cpos]) != FALSE) { ttputc('\b'); ttputc(' '); ttputc('\b'); --ttcol; } epos--; } ttflush(); break; case CCHR('W'): /* kill to beginning of word */ while ((cpos > 0) && !ISWORD(buf[cpos - 1])) { ttputc('\b'); ttputc(' '); ttputc('\b'); --ttcol; if (ISCTRL(buf[--cpos]) != FALSE) { ttputc('\b'); ttputc(' '); ttputc('\b'); --ttcol; } epos--; } while ((cpos > 0) && ISWORD(buf[cpos - 1])) { ttputc('\b'); ttputc(' '); ttputc('\b'); --ttcol; if (ISCTRL(buf[--cpos]) != FALSE) { ttputc('\b'); ttputc(' '); ttputc('\b'); --ttcol; } epos--; } ttflush(); break; case CCHR('\\'): case CCHR('Q'): /* quote next */ c = getkey(FALSE); /* FALLTHROUGH */ default: if (dynbuf && epos + 1 >= nbuf) { void *newp; size_t newsize = epos + epos + 16; if ((newp = realloc(buf, newsize)) == NULL) goto memfail; buf = newp; nbuf = newsize; } if (!dynbuf && epos + 1 >= nbuf) { ewprintf("Line too long"); return (emptyval); } for (i = epos; i > cpos; i--) buf[i] = buf[i - 1]; buf[cpos++] = (char)c; epos++; eputc((char)c); cc = ttcol; rr = ttrow; for (i = cpos; i < epos; i++) eputc(buf[i]); ttmove(rr, cc); ttflush(); } } done: if (cwin == TRUE) { /* blow away cpltion window */ bp = bfind("*Completions*", TRUE); if ((wp = popbuf(bp, WEPHEM)) != NULL) { if (wp->w_flag & WEPHEM) { curwp = wp; delwind(FFRAND, 1); } else { killbuffer(bp); } } } return (ret); memfail: if (dynbuf && buf) free(buf); ewprintf("Out of memory"); return (emptyval); }
#ifndef NO_HELP static PF cHcG[] = { ctrlg, /* ^G */ help_help, /* ^H */ }; static PF cHa[] = { apropos_command,/* a */ wallchart, /* b */ desckey, /* c */ }; static struct KEYMAPE(2+IMAPEXT) helpmap = { 2, 2+IMAPEXT, rescan, { {CCHR('G'),CCHR('H'), cHcG, (KEYMAP *)NULL}, {'a', 'c', cHa, (KEYMAP *)NULL}, } }; #endif static PF cX4cF[] = { poptofile, /* ^f */ ctrlg, /* ^g */ }; static PF cX4b[] = { poptobuffer, /* b */ rescan, /* c */ rescan, /* d */ rescan, /* e */ poptofile, /* f */
/* * excline - run a line from a load file or eval-expression. If FKEYS is * defined, duplicate functionality of dobind so function key values don't * have to fit in type char. */ int excline(char *line) { PF fp; struct line *lp, *np; int status, c, f, n; char *funcp, *tmp; char *argp = NULL; long nl; #ifdef FKEYS int bind; KEYMAP *curmap; #define BINDARG 0 /* this arg is key to bind (local/global set key) */ #define BINDNO 1 /* not binding or non-quoted BINDARG */ #define BINDNEXT 2 /* next arg " (define-key) */ #define BINDDO 3 /* already found key to bind */ #define BINDEXT 1 /* space for trailing \0 */ #else /* FKEYS */ #define BINDEXT 0 #endif /* FKEYS */ lp = NULL; if (macrodef || inmacro) { ewprintf("Not now!"); return (FALSE); } f = 0; n = 1; funcp = skipwhite(line); if (*funcp == '\0') return (TRUE); /* No error on blank lines */ line = parsetoken(funcp); if (*line != '\0') { *line++ = '\0'; line = skipwhite(line); if (ISDIGIT(*line) || *line == '-') { argp = line; line = parsetoken(line); } } if (argp != NULL) { f = FFARG; nl = strtol(argp, &tmp, 10); if (*tmp != '\0') return (FALSE); if (nl >= INT_MAX || nl <= INT_MIN) return (FALSE); n = (int)nl; } if ((fp = name_function(funcp)) == NULL) { ewprintf("Unknown function: %s", funcp); return (FALSE); } #ifdef FKEYS if (fp == bindtokey || fp == unbindtokey) { bind = BINDARG; curmap = fundamental_map; } else if (fp == localbind || fp == localunbind) { bind = BINDARG; curmap = curbp->b_modes[curbp->b_nmodes]->p_map; } else if (fp == redefine_key) bind = BINDNEXT; else bind = BINDNO; #endif /* FKEYS */ /* Pack away all the args now... */ if ((np = lalloc(0)) == FALSE) return (FALSE); np->l_fp = np->l_bp = maclcur = np; while (*line != '\0') { argp = skipwhite(line); if (*argp == '\0') break; line = parsetoken(argp); if (*argp != '"') { if (*argp == '\'') ++argp; if ((lp = lalloc((int) (line - argp) + BINDEXT)) == NULL) { status = FALSE; goto cleanup; } bcopy(argp, ltext(lp), (int)(line - argp)); #ifdef FKEYS /* don't count BINDEXT */ lp->l_used--; if (bind == BINDARG) bind = BINDNO; #endif /* FKEYS */ } else { /* quoted strings are special */ ++argp; #ifdef FKEYS if (bind != BINDARG) { #endif /* FKEYS */ lp = lalloc((int)(line - argp) + BINDEXT); if (lp == NULL) { status = FALSE; goto cleanup; } lp->l_used = 0; #ifdef FKEYS } else key.k_count = 0; #endif /* FKEYS */ while (*argp != '"' && *argp != '\0') { if (*argp != '\\') c = *argp++; else { switch (*++argp) { case 't': case 'T': c = CCHR('I'); break; case 'n': case 'N': c = CCHR('J'); break; case 'r': case 'R': c = CCHR('M'); break; case 'e': case 'E': c = CCHR('['); break; case '^': /* * split into two statements * due to bug in OSK cpp */ c = CHARMASK(*++argp); c = ISLOWER(c) ? CCHR(TOUPPER(c)) : CCHR(c); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c = *argp - '0'; if (argp[1] <= '7' && argp[1] >= '0') { c <<= 3; c += *++argp - '0'; if (argp[1] <= '7' && argp[1] >= '0') { c <<= 3; c += *++argp - '0'; } } break; #ifdef FKEYS case 'f': case 'F': c = *++argp - '0'; if (ISDIGIT(argp[1])) { c *= 10; c += *++argp - '0'; } c += KFIRST; break; #endif /* FKEYS */ default: c = CHARMASK(*argp); break; } argp++; } #ifdef FKEYS if (bind == BINDARG) key.k_chars[key.k_count++] = c; else #endif /* FKEYS */ lp->l_text[lp->l_used++] = c; } if (*line) line++; } #ifdef FKEYS switch (bind) { case BINDARG: bind = BINDDO; break; case BINDNEXT: lp->l_text[lp->l_used] = '\0'; if ((curmap = name_map(lp->l_text)) == NULL) { ewprintf("No such mode: %s", lp->l_text); status = FALSE; free(lp); goto cleanup; } free(lp); bind = BINDARG; break; default: #endif /* FKEYS */ lp->l_fp = np->l_fp; lp->l_bp = np; np->l_fp = lp; np = lp; #ifdef FKEYS } #endif /* FKEYS */ } #ifdef FKEYS switch (bind) { default: ewprintf("Bad args to set key"); status = FALSE; break; case BINDDO: if (fp != unbindtokey && fp != localunbind) { lp->l_text[lp->l_used] = '\0'; status = bindkey(&curmap, lp->l_text, key.k_chars, key.k_count); } else status = bindkey(&curmap, NULL, key.k_chars, key.k_count); break; case BINDNO: #endif /* FKEYS */ inmacro = TRUE; maclcur = maclcur->l_fp; status = (*fp)(f, n); inmacro = FALSE; #ifdef FKEYS } #endif /* FKEYS */ cleanup: lp = maclcur->l_fp; while (lp != maclcur) { np = lp->l_fp; free(lp); lp = np; } free(lp); return (status); }
/* ARGSUSED */ int re_queryrepl(int f, int n) { int rcnt = 0; /* replacements made so far */ int plen, s; /* length of found string */ char news[NPAT]; /* replacement string */ if ((s = re_readpattern("RE Query replace")) != TRUE) return (s); if (eread("Query replace %s with: ", news, NPAT, EFNUL | EFNEW | EFCR, re_pat) == NULL) return (ABORT); ewprintf("Query replacing %s with %s:", re_pat, news); /* * Search forward repeatedly, checking each time whether to insert * or not. The "!" case makes the check always true, so it gets put * into a tighter loop for efficiency. */ while (re_forwsrch() == TRUE) { retry: update(); switch (getkey(FALSE)) { case ' ': plen = regex_match[0].rm_eo - regex_match[0].rm_so; if (re_doreplace((RSIZE)plen, news) == FALSE) return (FALSE); rcnt++; break; case '.': plen = regex_match[0].rm_eo - regex_match[0].rm_so; if (re_doreplace((RSIZE)plen, news) == FALSE) return (FALSE); rcnt++; goto stopsearch; case CCHR('G'): /* ^G */ (void)ctrlg(FFRAND, 0); goto stopsearch; case CCHR('['): /* ESC */ case '`': goto stopsearch; case '!': do { plen = regex_match[0].rm_eo - regex_match[0].rm_so; if (re_doreplace((RSIZE)plen, news) == FALSE) return (FALSE); rcnt++; } while (re_forwsrch() == TRUE); goto stopsearch; case CCHR('?'): /* To not replace */ break; default: ewprintf("<SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit"); goto retry; } } stopsearch: curwp->w_rflag |= WFFULL; update(); if (!inmacro) { if (rcnt == 0) ewprintf("(No replacements done)"); else if (rcnt == 1) ewprintf("(1 replacement done)"); else ewprintf("(%d replacements done)", rcnt); } return (TRUE); }
static PF direddl[] = { d_undelbak /* del */ }; #ifndef DIRED_XMAPS #define NDIRED_XMAPS 0 /* number of extra map sections */ #endif /* DIRED_XMAPS */ static struct KEYMAPE (6 + NDIRED_XMAPS + IMAPEXT) diredmap = { 6 + NDIRED_XMAPS, 6 + NDIRED_XMAPS + IMAPEXT, rescan, { #ifndef NO_HELP { CCHR('@'), CCHR('H'), dirednul, (KEYMAP *) & helpmap }, #else /* !NO_HELP */ { CCHR('@'), CCHR('G'), dirednul, NULL }, #endif /* !NO_HELP */ { CCHR('L'), CCHR('X'), diredcl, (KEYMAP *) & cXmap }, { CCHR('Z'), '+', diredcz, (KEYMAP *) & metamap }, { 'c', 'f', diredc, NULL },
/* ARGSUSED */ int queryrepl(int f, int n) { int s; int rcnt = 0; /* replacements made so far */ int plen; /* length of found string */ char news[NPAT], *rep; /* replacement string */ #ifndef NO_MACRO if (macrodef) { ewprintf("Can't query replace in macro"); return (FALSE); } #endif /* !NO_MACRO */ if ((s = readpattern("Query replace")) != TRUE) return (s); if ((rep = eread("Query replace %s with: ", news, NPAT, EFNUL | EFNEW | EFCR, pat)) == NULL) return (ABORT); else if (rep[0] == '\0') news[0] = '\0'; ewprintf("Query replacing %s with %s:", pat, news); plen = strlen(pat); /* * Search forward repeatedly, checking each time whether to insert * or not. The "!" case makes the check always true, so it gets put * into a tighter loop for efficiency. */ while (forwsrch() == TRUE) { retry: update(); switch (getkey(FALSE)) { case 'y': case ' ': if (lreplace((RSIZE)plen, news) == FALSE) return (FALSE); rcnt++; break; case '.': if (lreplace((RSIZE)plen, news) == FALSE) return (FALSE); rcnt++; goto stopsearch; /* ^G, CR or ESC */ case CCHR('G'): (void)ctrlg(FFRAND, 0); goto stopsearch; case CCHR('['): case CCHR('M'): goto stopsearch; case '!': do { if (lreplace((RSIZE)plen, news) == FALSE) return (FALSE); rcnt++; } while (forwsrch() == TRUE); goto stopsearch; case 'n': case CCHR('H'): /* To not replace */ case CCHR('?'): break; default: ewprintf("y/n or <SP>/<DEL>: replace/don't, [.] repl-end, [!] repl-rest, <CR>/<ESC> quit"); goto retry; } } stopsearch: curwp->w_rflag |= WFFULL; update(); if (rcnt == 1) ewprintf("Replaced 1 occurrence"); else ewprintf("Replaced %d occurrences", rcnt); return (TRUE); }
/* * Incremental Search. * dir is used as the initial direction to search. * ^S switch direction to forward * ^R switch direction to reverse * ^Q quote next character (allows searching for ^N etc.) * <ESC> exit from Isearch * <DEL> undoes last character typed. (tricky job to do this correctly). * other ^ exit search, don't set mark * else accumulate into search string */ static int isearch(int dir) { struct line *clp; /* Saved line pointer */ int c; int cbo; /* Saved offset */ int success; int pptr; int firstc; int xcase; int i; char opat[NPAT]; int cdotline; /* Saved line number */ #ifndef NO_MACRO if (macrodef) { ewprintf("Can't isearch in macro"); return (FALSE); } #endif /* !NO_MACRO */ for (cip = 0; cip < NSRCH; cip++) cmds[cip].s_code = SRCH_NOPR; (void)strlcpy(opat, pat, sizeof(opat)); cip = 0; pptr = -1; clp = curwp->w_dotp; cbo = curwp->w_doto; cdotline = curwp->w_dotline; is_lpush(); is_cpush(SRCH_BEGIN); success = TRUE; is_prompt(dir, TRUE, success); for (;;) { update(); switch (c = getkey(FALSE)) { case CCHR('['): /* * If new characters come in the next 300 msec, * we can assume that they belong to a longer * escaped sequence so we should ungetkey the * ESC to avoid writing out garbage. */ if (ttwait(300) == FALSE) ungetkey(c); srch_lastdir = dir; curwp->w_markp = clp; curwp->w_marko = cbo; curwp->w_markline = cdotline; ewprintf("Mark set"); return (TRUE); case CCHR('G'): if (success != TRUE) { while (is_peek() == SRCH_ACCM) is_undo(&pptr, &dir); success = TRUE; is_prompt(dir, pptr < 0, success); break; } curwp->w_dotp = clp; curwp->w_doto = cbo; curwp->w_dotline = cdotline; curwp->w_rflag |= WFMOVE; srch_lastdir = dir; (void)ctrlg(FFRAND, 0); (void)strlcpy(pat, opat, sizeof(pat)); return (ABORT); case CCHR('S'): if (dir == SRCH_BACK) { dir = SRCH_FORW; is_lpush(); is_cpush(SRCH_FORW); success = TRUE; } if (success == FALSE && dir == SRCH_FORW) { /* wrap the search to beginning */ curwp->w_dotp = bfirstlp(curbp); curwp->w_doto = 0; curwp->w_dotline = 1; if (is_find(dir) != FALSE) { is_cpush(SRCH_MARK); success = TRUE; } ewprintf("Overwrapped I-search: %s", pat); break; } is_lpush(); pptr = strlen(pat); (void)forwchar(FFRAND, 1); if (is_find(SRCH_FORW) != FALSE) is_cpush(SRCH_MARK); else { (void)backchar(FFRAND, 1); ttbeep(); success = FALSE; ewprintf("Failed I-search: %s", pat); } is_prompt(dir, pptr < 0, success); break; case CCHR('R'): if (dir == SRCH_FORW) { dir = SRCH_BACK; is_lpush(); is_cpush(SRCH_BACK); success = TRUE; } if (success == FALSE && dir == SRCH_BACK) { /* wrap the search to end */ curwp->w_dotp = blastlp(curbp); curwp->w_doto = llength(curwp->w_dotp); curwp->w_dotline = curwp->w_bufp->b_lines; if (is_find(dir) != FALSE) { is_cpush(SRCH_MARK); success = TRUE; } ewprintf("Overwrapped I-search: %s", pat); break; } is_lpush(); pptr = strlen(pat); (void)backchar(FFRAND, 1); if (is_find(SRCH_BACK) != FALSE) is_cpush(SRCH_MARK); else { (void)forwchar(FFRAND, 1); ttbeep(); success = FALSE; } is_prompt(dir, pptr < 0, success); break; case CCHR('W'): /* add the rest of the current word to the pattern */ clp = curwp->w_dotp; cbo = curwp->w_doto; firstc = 1; if (pptr == -1) pptr = 0; if (dir == SRCH_BACK) { /* when isearching backwards, cbo is the start of the pattern */ cbo += pptr; } /* if the search is case insensitive, add to pattern using lowercase */ xcase = 0; for (i = 0; pat[i]; i++) if (ISUPPER(CHARMASK(pat[i]))) xcase = 1; while (cbo < llength(clp)) { c = lgetc(clp, cbo++); if ((!firstc && !isalnum(c))) break; if (pptr == NPAT - 1) { ttbeep(); break; } firstc = 0; if (!xcase && ISUPPER(c)) c = TOLOWER(c); pat[pptr++] = c; pat[pptr] = '\0'; /* cursor only moves when isearching forwards */ if (dir == SRCH_FORW) { curwp->w_doto = cbo; curwp->w_rflag |= WFMOVE; update(); } } is_prompt(dir, pptr < 0, success); break; case CCHR('H'): case CCHR('?'): is_undo(&pptr, &dir); if (is_peek() != SRCH_ACCM) success = TRUE; is_prompt(dir, pptr < 0, success); break; case CCHR('\\'): case CCHR('Q'): c = (char)getkey(FALSE); goto addchar; case CCHR('M'): c = CCHR('J'); goto addchar; default: if (ISCTRL(c)) { ungetkey(c); curwp->w_markp = clp; curwp->w_marko = cbo; curwp->w_markline = cdotline; ewprintf("Mark set"); curwp->w_rflag |= WFMOVE; return (TRUE); } /* FALLTHRU */ case CCHR('I'): case CCHR('J'): addchar: if (pptr == -1) pptr = 0; if (pptr == 0) success = TRUE; if (pptr == NPAT - 1) ttbeep(); else { pat[pptr++] = c; pat[pptr] = '\0'; } is_lpush(); if (success != FALSE) { if (is_find(dir) != FALSE) is_cpush(c); else { success = FALSE; ttbeep(); is_cpush(SRCH_ACCM); } } else is_cpush(SRCH_ACCM); is_prompt(dir, FALSE, success); } } /* NOTREACHED */ }
void theo_init(void); static int theo_analyze(int, int); static int theo(int, int); static PF theo_pf[] = { theo_analyze }; static struct KEYMAPE (1 + IMAPEXT) theomap = { 1, 1 + IMAPEXT, rescan, { { CCHR('M'), CCHR('M'), theo_pf, NULL } } }; void theo_init(void) { funmap_add(theo, "theo"); maps_add((KEYMAP *)&theomap, "theo"); } /* ARGSUSED */ static int theo(int f, int n) { struct buffer *bp;
static struct KEYMAPE (1 + IMAPEXT) cmode_cmap = { 1, 1 + IMAPEXT, rescan, { { 'P', 'P', cmode_cCP, NULL } } }; static struct KEYMAPE (3 + IMAPEXT) cmodemap = { 3, 3 + IMAPEXT, rescan, { { CCHR('C'), CCHR('M'), cmode_cc, (KEYMAP *) &cmode_cmap }, { ':', ':', cmode_spec, NULL }, { '}', '}', cmode_brace, NULL } } }; /* Funtion, Mode hooks */ void cmode_init(void) { funmap_add(cmode, "c-mode"); funmap_add(cc_char, "c-handle-special-char"); funmap_add(cc_brace, "c-handle-special-brace"); funmap_add(cc_tab, "c-tab-or-indent"); funmap_add(cc_indent, "c-indent");
static PF listbuf_pf[] = { listbuf_goto_buffer }; static PF listbuf_one[] = { listbuf_goto_buffer_one }; static struct KEYMAPE (2) listbufmap = { 2, 2, rescan, { { CCHR('M'), CCHR('M'), listbuf_pf, NULL }, { '1', '1', listbuf_one, NULL } } }; /* * Display the buffer list. This is done * in two parts. The "makelist" routine figures out * the text, and puts it in a buffer. "popbuf" * then pops the data onto the screen. Bound to * "C-X C-B". */ /* ARGSUSED */
* * XXX - need some kind of callback to find out when those get killed. */ struct mgwin *compile_win; struct buffer *compile_buffer; static PF compile_pf[] = { compile_goto_error }; static struct KEYMAPE (1) compilemap = { 1, 1, rescan, { { CCHR('M'), CCHR('M'), compile_pf, NULL } } }; void grep_init(void) { funmap_add(compile_goto_error, "compile-goto-error"); funmap_add(next_error, "next-error"); funmap_add(grep, "grep"); funmap_add(compile, "compile"); funmap_add(gid, "gid"); maps_add((KEYMAP *)&compilemap, "compile"); } /* ARGSUSED */
break; default: #ifdef FKEYS if (k >= KFIRST && k <= KLAST && (np = keystrings[k - KFIRST]) != NULL) break; #endif if (k > CCHR('?')) { *cp++ = '0'; *cp++ = ((k >> 6) & 7) + '0'; *cp++ = ((k >> 3) & 7) + '0'; *cp++ = (k & 7) + '0'; *cp = '\0'; return (cp); } else if (k < ' ') { *cp++ = 'C'; *cp++ = '-'; k = CCHR(k); if (ISUPPER(k)) k = TOLOWER(k); } *cp++ = k; *cp = '\0'; return (cp); } copied = strlcpy(cp, np, len); if (copied >= len) copied = len - 1; return (cp + copied); }
help_help /* ^H */ }; static PF cHa[] = { apropos_command, /* a */ wallchart, /* b */ desckey /* c */ }; struct KEYMAPE (2 + IMAPEXT) helpmap = { 2, 2 + IMAPEXT, rescan, { { CCHR('G'), CCHR('H'), cHcG, NULL }, { 'a', 'c', cHa, NULL } } }; static PF cCsc[] = { cscallerfuncs, /* c */ csdefinition, /* d */ csegrep, /* e */ csfindfile, /* f */ rescan, /* g */ rescan, /* h */ csfindinc, /* i */