sh.edit.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 3,065 行 · 第 1/4 页
C
3,065 行
for (backptr = srchptr; backptr > srchcmd && isspace(backptr[-1]); backptr--) continue; for (c = wordch(backptr - 1); backptr > srchcmd && wordof(c, backptr - 1); backptr--) continue; goto srchbackup; /* * users kill Kill input on this line, back to * (^U) start of insert. */ case -1: backptr = srchcmd;srchbackup: if (backptr == srchptr) { beep(); continue; /* get new char */ } *backptr = '\0'; vgoto(outcol - (srchptr-backptr),outline); srchptr = backptr; continue; /* get new char */ } /* end switch (i) */ /* * Have a normal character, echo it and save it */ *srchptr++ = i; exputchar(i); exflush(); } /* * Over-ran srchcmd buffer, terminate search string */ beep(); srchcmd[0] = '\0'; editevent++; redraw(); return(0);}/* * Redraw the line */redraw(){ char *holdcurs; holdcurs = cursor; vsetcurs(linebuf); normline(); /* * Clear from last char to end of line */ destcol = column(strend(linebuf)) + 1; vclreol(); /* * Reset cursor */ cursor = holdcurs; vsetcurs(cursor);}char *longname(bp, def) register char *bp; char *def;{ register char *cp; while (*bp && *bp != ':' && *bp != '|') bp++; if (*bp == '|') { bp++; cp = bp; while (*cp && *cp != ':' && *cp != '|') cp++; *cp = 0; return (bp); } return (def);}/* * Ring terminal bell. */beep(){ vputc(CTRL(g));}/* * Mapping for special keys on the terminal only. * Map the command input character c, * for keypads and labelled keys which do cursor * motions. I.e. on an adm3a we might map ^K to ^P. * DM1520 for example has a lot of mappable characters. */map(c,maps) register int c; register struct maps *maps;{ register int d; register char *p, *q; char b[10]; /* Assumption: no keypad sends string longer than 10 */ /* * If c==0, the char came from getesc typing escape. Pass it through * unchanged. 0 messes up the following code anyway. */ if (c==0) return(0); b[0] = c; b[1] = 0; for (d=0; maps[d].mapto; d++) { if (p = maps[d].cap) { for (q=b; *p; p++, q++) { if (*q==0) { /* * Is there another char waiting? * * This test is oversimplified, but * should work mostly. It handles the * case where we get an ESCAPE that * wasn't part of a keypad string. */ if ((c=='#' ? peekkey() : fastpeekkey()) == 0) { /* * Nothing waiting. Push back * what we peeked at & return * failure (c). */ macpush(&b[1]); return(c); } *q = getkey(); q[1] = 0; } if (*p != *q) goto contin; } macpush(maps[d].mapto); c = getkey(); return(c); /* first char of map string */ contin:; } } macpush(&b[1]); return(c);}/* * Push st onto the front of vmacp. This is tricky because we have to * worry about where vmacp was previously pointing. We also have to * check for overflow (which is typically from a recursive macro) */macpush(st) char *st;{ char tmpbuf[BUFSIZ]; if (st==0 || *st==0) return; if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZ) error("Macro too long@ - maybe recursive?"); if (vmacp) { strcpy(tmpbuf, vmacp); } strcpy(vmacbuf, st); if (vmacp) strcat(vmacbuf, tmpbuf); vmacp = vmacbuf;}/************************************************************* * The following routines deal with carying out the command actions *************************************************************//* * Find single character c, in direction dir from cursor. */find(c) char c;{ for(;;) { if (edge()) return (0); wcursor += dir; if (*wcursor == c) return (1); }}/* * Do a word motion with operator op, and cnt more words * to go after this. */exword(op, cnt) register int (*op)(); int cnt;{ register int which; register char *iwc; if (dir == 1) { iwc = wcursor; which = wordch(wcursor); while (wordof(which, wcursor)) { if (cnt == 1 && op != vmove && wcursor[1] == 0) { wcursor++; break; } if (!lnext()) return (0); if (wcursor == linebuf) break; } /* Unless last segment of a change skip blanks */ if (op != vchange || cnt > 1) while (!margin() && blank()) wcursor++; else if (wcursor == iwc && *iwc) wcursor++; if (op == vmove && margin()) wcursor--; } else { if (!lnext()) return (0); while (blank()) if (!lnext()) return (0); if (!margin()) { which = wordch(wcursor); while (!margin() && wordof(which, wcursor)) wcursor--; } if (wcursor < linebuf || !wordof(which, wcursor)) wcursor++; } return (1);}lnext(){ if (dir > 0) { if (*wcursor) wcursor++; if (*wcursor) return (1); else if (wcursor > linebuf) wcursor--; return (0); } else { --wcursor; if (wcursor >= linebuf) return (1); else { wcursor++; /* 11/16 fixes 'b' past start of line bug */ return (0); } }}/* * To end of word, with operator op and cnt more motions * remaining after this. */eend(op) register int (*op)();{ register int which; if (!lnext()) return; while (blank()) if (!lnext()) return; which = wordch(wcursor); while (wordof(which, wcursor)) { if (wcursor[1] == 0) { wcursor++; break; } if (!lnext()) return; } if (op != vchange && op != vdelete && wcursor > linebuf) wcursor--;}/* * Wordof tells whether the character at *wc is in a word of * kind which (blank/nonblank words are 0, conservative words 1). */wordof(which, wc) char which; register char *wc;{ if (isspace(*wc)) return (0); return (!wdkind || wordch(wc) == which);}/* * Wordch tells whether character at *wc is a word character * i.e. an alfa, digit, or underscore. */wordch(wc) char *wc;{ register int c; c = wc[0]; return (isalpha(c) || isdigit(c) || c == '_');}/* * Edge tells when we hit the last character in the current line. */edge(){ if (linebuf[0] == 0) return (1); if (dir == 1) return (wcursor[1] == 0); else return (wcursor == linebuf);}/* * Margin tells us when we have fallen off the end of the line. */margin(){ return (wcursor < linebuf || wcursor[0] == 0);}/* * Find words, repeated count times. * 'f' is the operation to be performed eventually. */lfind(pastatom, cnt, f) bool pastatom; /* == 2 for word; == 3 for end */ int cnt, (*f)();{ int rc = 0; /* return code */ wcursor = cursor; while (cnt > 0 && exword(f, cnt)) cnt--; if (pastatom == 3) eend(f); if (cursor == wcursor) rc = -1; return (rc);}/* * Delete operator. */vdelete(c) char c;{ register char *cp; if (wcursor < linebuf) wcursor = linebuf; if (cursor == wcursor) { beep(); return; } (void) vdcMID(); cp = cursor; setBUF(DEL); /* save del text for put */ CP(cp, wcursor); if (cp > linebuf && (cp[0] == 0 || c == '#')) cp--; /* * Redraw the line now that we deleted some */ vsetcurs(linebuf); normline(); /* * Clear from last char to end of line */ destcol = column(strend(linebuf)) + 1; vclreol(); /* * Reset cursor */ vsetcurs(cp);}/* * Common code for middle part of delete * and change operating on parts of lines. */vdcMID(){ register char *cp; setLAST(); if (wcursor < cursor) cp = wcursor, wcursor = cursor, cursor = cp; return (column(wcursor - 1));}/* * Change operator. * We mark the end of the changed area with '$'. * Delete the text in the linebuf then do an insert. */vchange(c) char c;{ register char *cp; register int i; /* 006 - GAG */ if (wcursor < linebuf) wcursor = linebuf; if (cursor == wcursor) { beep(); return; } i = vdcMID(); cp = cursor; vsetcurs(cursor); /* * Mark the end of the change with $. */ vgoto(i,0); exputchar('$'); /* * Copy text over the deleted portion, * then execute the input portion of the change. */ cursor = cp; CP(cursor, wcursor); vgoto(column(cursor),0); doomed = i; vappend('c', 1, 0);}/* * Replace a single character with the next input character. * A funny kind of insert. */vrep(cnt) register int cnt;{ register int i, c; if (cnt > strlen(cursor)) { beep(); return; } i = column(cursor + cnt - 1); vgoto(column(cursor),0); doomed = i; if (!vglobp) { c = getesc(); if (c == 0) { vsetcurs(cursor); return; } ungetkey(c); } wcursor = cursor + cnt; CP(cursor, wcursor); vappend('r', cnt, 0); *lastcp++ = INS[0]; setLAST();}char *ogcursor;/* * Append command (append, insert, change) * Called for insert (i), append (a), replace (r), and change (c) */vappend(ch, cnt, indent) int ch; /* type of text addition: i, a, r, c */ int cnt, indent; /* repeat count on command */{ register char *gcursor; int repcnt; short oldcol; /* hold destcol while updating line */ short oldline; /* hold destline while updating line */ /* * Handle replace character by (eventually) * limiting the number of input characters allowed * in the vgetline routine. */ if (ch == 'r' || (emacs && (!vglobp))) repcnt = 2; else repcnt = 0; gcursor = genbuf; *gcursor = 0; /* * If we are in a repeated command then * use the previous inserted text (in INS buffer). * If there is none or it was too long to be saved, * then beep() and also arrange to undo any damage done * so far (e.g. if we are a change.) */ if (vglobp && *vglobp == 0) { if (INS[0] == NULL) { beep(); doomed = 0; return; } /* * Unread input from INS. * An escape will be generated at end of string. * Hold off n^^2 type update on dumb terminals. */ vglobp = INS; } else if (vglobp == 0) /* * Not a repeated command, get * a new inserted text for repeat. */ INS[0] = 0; /* * Text gathering. * New text goes into genbuf starting at gcursor. * cursor preserves place in linebuf where text will eventually go. */ if (ch != 'r' || repcnt != 0) { /* 006 - GAG */ gcursor = vgetline(repcnt, gcursor, ch); addtext(ogcursor); } repcnt = 0; /* * Limit the repetition count based on maximum * possible line length; do output implied * by further count (> 1) and cons up the new line * in linebuf (cursor pointer). */ cnt = vmaxrep(ch, cnt); CP(gcursor + 1, cursor); do { CP(cursor, genbuf); if (cnt > 1) { Outchar = vinschar; oldcol = destcol; oldline = destline; updateline(cursor); destcol = oldcol; destline = oldline; insmode = 1; vgoto(destcol,destline); insmode = 0; exflush(); vgoto(destcol,destline); Outchar = vputchar; } cursor += gcursor - genbuf; } while (--cnt > 0); CP(cursor, gcursor + 1); /* * If doomed characters remain, clobber them, * and update the line on the screen. */ if (doomed > 0) { doomed = 0; } /* * Now that insert is done: * for emacs mode: increment the cursor. * for vi mode: redraw the line. */ if ((!emacs) || (hadcnt != 0) || vglobp) { redraw(); /* * All done with insertion, position the cursor. */ if ((cursor > linebuf) && (!emacs)) cursor--; doomed = 0; } wcursor = cursor; vsetcurs(cursor);}/* * Get a line into genbuf after gcursor. * Cnt limits the number of input characters * accepted and is used for handling the replace * single character command. * * We do erase-kill type processing here. * commch is the command character involved. * * Input mode mappings are done here also. */char *vgetline(cnt, gcursor, commch) int cnt; register char *gcursor; char commch;{ register int c, ch; register char *cp; char *iglobp; int (*OO)() = Outchar; short oldcol; /* hold destcol while updating line */ short oldline; /* hold destline while updating line */ short farcol; /* farthest point of advance before delete */ /* * Clear the output state and counters. */ ogcursor = gcursor; flusho(); iglobp = vglobp; farcol = 0; Outchar = vinschar; for (;;) { if (cnt != 0) { cnt--; if (cnt == 0) goto vadone; } c = getkey(); if (c != ATTN) c &= (QUOTE|TRIM); ch = c; maphopcnt = 0; if (vglobp == 0 && Peekkey == 0 && commch != 'r') while ((ch = map(c, immacs)) != c) { c = ch; if (++maphopcnt > 256) error("Infinite macro loop"); } if (!iglobp) { /* * Erase-kill type processing. * Only happens if we were not reading * from untyped input when we started. * Map users erase to ^H, kill to -1 for switch. */ if (c == hold_tty.sg_erase) c = CTRL(h); else if (c == hold_tty.sg_kill) c = -1; switch (c) { /* * ^? Interrupt * * ^\ Quit */ case ATTN: ungetkey(c); case QUIT: /* 009 RNF */ goto vadone; /* * ^H Backs up a character in the input. */ case CTRL(h): cp = gcursor - 1; if (cp < ogcursor) { beep(); continue; } goto vbackup; /* * ^W Back up a white/non-white word. */ case CTRL(w): wdkind = 1; for (cp = gcursor; cp > ogcursor && isspace(cp[-1]); cp--) continue; for (c = wordch(cp - 1); cp > ogcursor && wordof(c, cp - 1); cp--) continue; goto vbackup; /* * users kill Kill input on this line, back to * (^U) start of insert. */ case -1: cp = ogcursor;vbackup: if (cp == gcursor) { beep(); continue; } *cp = 0; c = 0; vgoto(outcol - (gcursor-cp),outline); if (doomed >= 0) doomed += c; gcursor = cp; continue; } /* end switch (c) */ } switch (c) { /* * ^M Except in repeat maps to \n. */ case CR: if (vglobp) goto def; c = '\n'; /* presto chango ... */ /* * \n End insert & set flag for top level cmd loop. */ case NL: done_edit = 1; goto vadone; /* * escape End insert. */ case ESCAPE: if (lastvgk) goto def; goto vadone; default: /* * Possibly discard control inputs. */ if (!vglobp && junk(c)) { beep(); continue; }def: /* * Put out the new char. * If insert, append, or change beyond '$', and * not getting chars from delete buffer (iglobp set), * and not on multiple lines (UP) without ND * then reprint the rest of the line * to give the illusion of shifting over. */ exputchar(c); if (destcol > farcol) farcol = destcol; if (!(commch == 'r' || (commch == 'c' && destcol < column(wcursor)) || (destcol < farcol) || iglobp || (UP && !(ND)))) { oldcol = destcol; oldline = destline; updateline(cursor); destcol = oldcol; destline = oldline; insmode = 1; vgoto(destcol,destline); insmode = 0; } exflush(); if (gcursor > &genbuf[LBSIZE - 2]) error("Line too long"); *gcursor++ = c & (QUOTE|TRIM); vgoto(destcol,destline); continue; } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?