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 + -
显示快捷键?