/* * This routine looks at a line (pointed * to by the LINE pointer "dlp") and the current * vertical motion goal column (set by the "setgoal" * routine above) and returns the best offset to use * when a vertical motion is made into the line. */ int getgoal(struct line *dlp) { int c, i, col = 0; char tmp[5]; for (i = 0; i < llength(dlp); i++) { c = lgetc(dlp, i); if (c == '\t' #ifdef NOTAB && !(curbp->b_flag & BFNOTAB) #endif ) { col |= 0x07; col++; } else if (ISCTRL(c) != FALSE) { col += 2; } else if (isprint(c)) col++; else { col += snprintf(tmp, sizeof(tmp), "\\%o", c); } if (col > curgoal) break; } return (i); }
/* * 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); } }
/* convert a line/offset pair to a column position (for indenting) */ static int findcolpos(const struct buffer *bp, const struct line *lp, int lo) { int col, i, c; char tmp[5]; /* determine column */ col = 0; for (i = 0; i < lo; ++i) { c = lgetc(lp, i); if (c == '\t' #ifdef NOTAB && !(bp->b_flag & BFNOTAB) #endif /* NOTAB */ ) { col |= 0x07; col++; } else if (ISCTRL(c) != FALSE) col += 2; else if (isprint(c)) { col++; } else { col += snprintf(tmp, sizeof(tmp), "\\%o", c); } } return (col); }
static void dodisplay(const char *buf, size_t cnt) { size_t i,j; const char *p=0; char charbuf[6]; for (i=j=0; i<cnt; i++) { switch (buf[i]) { case '<': p="<"; break; case '>': p=">"; break; case '&': p="&"; break; case '"': p="""; break; default: if (ISCTRL(buf[i]) && buf[i] != '\n') { sprintf(charbuf, "&#%d;", (int)(unsigned char)buf[i]); p=charbuf; } else continue; } if (i > j) (*handler_func)(buf+j, i-j); (*handler_func)(p, strlen(p)); j=i+1; } if (i > j) (*handler_func)(buf+j, i-j); }
/* * 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; } }
/* * Add a character, checking for word wrapping. * Check to see if we're past fillcol, and if so, * justify this line. As a last step, justify the line. */ int fillword (int f, int n, int k) { register char c; register int col, i, nce; for (i = col = 0; col <= fillcol; ++i, ++col) { if (i == curwp->w_dot.o) return selfinsert (f, n, k); c = lgetc (curwp->w_dot.p, i); if (c == '\t') col += (tabsize - col % tabsize) - 1; else if (ISCTRL (c) != FALSE) ++col; } if (curwp->w_dot.o != llength (curwp->w_dot.p)) { selfinsert (f, n, k); nce = llength (curwp->w_dot.p) - curwp->w_dot.o; } else nce = 0; curwp->w_dot.o = i; if ((c = lgetc (curwp->w_dot.p, curwp->w_dot.o)) != ' ' && c != '\t') do { backchar (FALSE, 1, KRANDOM); } while ((c = lgetc (curwp->w_dot.p, curwp->w_dot.o)) != ' ' && c != '\t' && curwp->w_dot.o > 0); if (curwp->w_dot.o == 0) do { forwchar (FALSE, 1, KRANDOM); } while ((c = lgetc (curwp->w_dot.p, curwp->w_dot.o)) != ' ' && c != '\t' && curwp->w_dot.o < llength (curwp->w_dot.p)); delwhite (FALSE, 1, KRANDOM); backdel (FALSE, 1, KRANDOM); lnewline (); curwp->w_dot.o = llength (curwp->w_dot.p) - nce; curwp->w_flag |= WFMOVE; if (nce == 0 && curwp->w_dot.o != 0) return (fillword (f, n, k)); return (TRUE); }
/* ARGSUSED */ int fillword(int f, int n) { char c; int col, i, nce; for (i = col = 0; col <= fillcol; ++i, ++col) { if (i == curwp->w_doto) return selfinsert(f, n); c = lgetc(curwp->w_dotp, i); if (c == '\t' #ifdef NOTAB && !(curbp->b_flag & BFNOTAB) #endif ) col |= 0x07; else if (ISCTRL(c) != FALSE) ++col; } if (curwp->w_doto != llength(curwp->w_dotp)) { (void)selfinsert(f, n); nce = llength(curwp->w_dotp) - curwp->w_doto; } else nce = 0; curwp->w_doto = i; if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t') do { (void)backchar(FFRAND, 1); } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t' && curwp->w_doto > 0); if (curwp->w_doto == 0) do { (void)forwchar(FFRAND, 1); } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t' && curwp->w_doto < llength(curwp->w_dotp)); (void)delwhite(FFRAND, 1); (void)lnewline(); i = llength(curwp->w_dotp) - nce; curwp->w_doto = i > 0 ? i : 0; curwp->w_rflag |= WFMOVE; if (nce == 0 && curwp->w_doto != 0) return (fillword(f, n)); return (TRUE); }
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); }
/* * 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 */ }