Пример #1
0
/*
 * Goto column x of the current line.
 */
void
vgotoCL(register int x)
{

	if (splitw)
		vgoto(WECHO, x);
	else
		vgoto(LINE(vcline), x);
}
Пример #2
0
static void
vtab(void)

{

    int		line;			/* line we'll be at next */
    int		i;			/* loop index */

/*
 *
 * Looks for the next vertical tab stop in the vtabstops[] array and moves to that
 * line. If we don't find a tab we'll just move down one line - shouldn't happen.
 *
 */

    endline();

    line = vpos/ovmi + 1;
    for ( i = line; i < COLUMNS; i++ )
	if ( vtabstops[i] == ON )  {
	    line = i;
	    break;
	}   /* End if */

    vgoto(line * ovmi);

}   /* End of vtab */
Пример #3
0
void
drawellip (
    int a,
    int b,			/* axes lengths for the ellipse */
    int c
)


{


/*
 *
 * Draws an ellipse having axes lengths horizontally and vertically of a and
 * b. The left side of the ellipse is at the current point. After we're done
 * drawing the path we move the current position to the right side.
 *
 */


    if ( a == 0 && b == 0 )
	return;

    fprintf(tf, "%d %d %d %d D%c\n", hpos, vpos, a, b, c);

    hgoto(hpos + a);			/* where troff expects to be */
    vgoto(vpos);

    resetpos();				/* not sure where the printer is */

}   /* End of drawellip */
Пример #4
0
void
drawline (
    int dx,
    int dy			/* endpoint is (hpos+dx, vpos+dy) */
)


{


/*
 *
 * Draws a line from (hpos, vpos) to (hpos+dx, vpos+dy), and leaves the current
 * position at the endpoint.
 *
 */


    if ( dx == 0 && dy == 0 )
	drawcirc(1, 'c');
    else fprintf(tf, "%d %d %d %d Dl\n", hpos + dx, vpos + dy, hpos, vpos);

    hgoto(hpos+dx);			/* where troff expects to be */
    vgoto(vpos+dy);

    resetpos();				/* not sure where the printer is */

}   /* End of drawline */
Пример #5
0
/*
 * Clear the echo line.
 * If didphys then its been cleared physically (as
 * a side effect of a clear to end of display, e.g.)
 * so just do it logically.
 * If work here is being held off, just remember, in
 * heldech, if work needs to be done, don't do anything.
 */
void
vclrech(bool didphys)
{

	if (Peekkey == ATTN)
		return;
	if (hold & HOLDECH) {
		heldech = !didphys;
		return;
	}
	if (!didphys && (CD || CE)) {
		splitw++;
		/*
		 * If display is retained below, then MUST use CD or CE
		 * since we don't really know whats out there.
		 * Vigoto might decide (incorrectly) to do nothing.
		 */
		if (DB) {
			vgoto(WECHO, 0);
			vputp(CD ? CD : CE, 1);
		} else {
			if (XT) {
				/*
				 * This code basically handles the t1061
				 * where positioning at (0, 0) won't work
				 * because the terminal won't let you put
				 * the cursor on it's magic cookie.
				 *
				 * Should probably be XS above, or even a
				 * new X? glitch, but right now t1061 is the
				 * only terminal with XT.
				 */
				vgoto(WECHO, 0);
				vputp(DL, 1);
			} else {
				vigoto(WECHO, 0);
				vclreol();
			}
		}
		splitw = 0;
		didphys = 1;
	}
	if (didphys)
		vclrcell(vtube[WECHO], WCOLS);
	heldech = 0;
}
Пример #6
0
void 
showmode(int mode)
{
	int sdc = destcol, sdl = destline;
	char *ocurs, *str;

	if (value(SHOWMODE) == 0 || TCOLUMNS <= 20 || state == ONEOPEN
			|| state == HARDOPEN /*|| vmacp != NULL*/)
		return;
	ocurs = cursor;
	fixech();
	vgoto(WECHO, TCOLUMNS - 20);
	switch (mode) {
	case 0:		str = catgets(catd, 1, 227,
					"               ");
			break;
	case 'A':	/*FALLTHROUGH*/
	case 'a':	str = catgets(catd, 1, 228,
					"AAPPEND MODE");
			break;
	case 'C':	/*FALLTHROUGH*/
	case 'c':	str = catgets(catd, 1, 229,
					"CCHANGE MODE");
			break;
	case 'O':	/*FALLTHROUGH*/
	case 'o':	str = catgets(catd, 1, 230,
					"OOPEN MODE");
			break;
	case 'R':	str = catgets(catd, 1, 231,
					"RREPLACE MODE");
			break;
	case 'r':	str = catgets(catd, 1, 232,
					"rREPLACE 1 CHAR");
			break;
	default:	str = catgets(catd, 1, 233,
					"IINSERT MODE");
	}
	if (value(TERSE))
		putchar(str[0]);
	else
		ex_printf(&str[1]);
	vgoto(sdl, sdc);
	cursor = ocurs;
	splitw = 0;
}
Пример #7
0
static void
ovend(ttymode f)
{

	splitw++;
	vgoto(WECHO, 0);
	vclreol();
	vgoto(WECHO, 0);
	holdcm = 0;
	splitw = 0;
	ostop(f);
	setoutt();
	undvis();
	COLUMNS = OCOLUMNS;
	inopen = 0;
	flusho();
	netchHAD(Vlines);
}
Пример #8
0
/*
 * Read a line from the echo area, with single character prompt c.
 * A return value of 1 means the user blewit or blewit away.
 */
int
readecho(int c)
{
	register char *sc = cursor;
	void (*OP)();
	bool waste;
	register int OPeek;

	if (WBOT == WECHO)
		vclean();
	else
		vclrech(0);
	splitw++;
	vgoto(WECHO, 0);
	ex_putchar(c);
	vclreol();
	vgoto(WECHO, 1);
	cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
	if (peekbr()) {
		if (!INS[0] || (INS[0] & (OVERBUF|TRIM)) == OVERBUF)
			goto blewit;
		vglobp = INS;
	}
	OP = Pline; Pline = normline;
	ignore(vgetline(0, genbuf + 1, &waste, c));
	if (Outchar == termchar)
		ex_putchar('\n');
	vscrap();
	Pline = OP;
	if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL('h')) {
		cursor = sc;
		vclreol();
		return (0);
	}
blewit:
	OPeek = Peekkey==CTRL('h') ? 0 : Peekkey; Peekkey = 0;
	splitw = 0;
	vclean();
	vshow(dot, NOLINE);
	vnline(sc);
	Peekkey = OPeek;
	return (1);
}
Пример #9
0
/*
 * Fix the echo area for use, setting
 * the state variable splitw so we wont rollup
 * when we move the cursor there.
 */
void
fixech(void)
{

	splitw++;
	if (state != VISUAL && state != CRTOPEN) {
		vclean();
		vcnt = 0;
	}
	vgoto(WECHO, 0); flusho();
}
Пример #10
0
void
drawcirc(int d)
{
	int xc, yc;

	xc = hpos;
	yc = vpos;
	conicarc(hpos + d/2, -vpos, hpos, -vpos, hpos, -vpos, d/2, d/2);
	hgoto(xc + d);	/* circle goes to right side */
	vgoto(yc);
}
Пример #11
0
void
drawellip(int a, int b)
{
	int xc, yc;

	xc = hpos;
	yc = vpos;
	conicarc(hpos + a/2, -vpos, hpos, -vpos, hpos, -vpos, a/2, b/2);
	hgoto(xc + a);
	vgoto(yc);
}
Пример #12
0
/*
 * Delete operator.
 *
 * Hard case of deleting a range where both wcursor and wdot
 * are specified is treated as a special case of change and handled
 * by vchange (although vchange may pass it back if it degenerates
 * to a full line range delete.)
 */
void 
vdelete(int c)
{
	register char *cp;
	register int i;

	if (wdot) {
		if (wcursor) {
			vchange(EOF);
			return;
		}
		if ((i = xdw()) < 0)
			return;
		if (state != VISUAL) {
			vgoto(LINE(0), 0);
			vputchar('@');
		}
		wdot = dot;
		vremote(i, delete, 0);
		notenam = "delete";
		DEL[0] = 0;
		killU();
		vreplace(vcline, i, 0);
		if (wdot > dol)
			vcline--;
		vrepaint(NOSTR);
		return;
	}
	if (wcursor < linebuf)
		wcursor = linebuf;
	if (cursor == wcursor) {
		beep();
		return;
	}
	i = vdcMID();
	cp = cursor;
	setDEL();
	CP(cp, wcursor);
	if (cp > linebuf && (cp[0] == 0 || c == '#'))
		cp--;
	if (state == HARDOPEN) {
		bleep(i, cp);
		cursor = cp;
		return;
	}
	physdc(column(cursor + skipleft(linebuf, cursor)), i);
	DEPTH(vcline) = 0;
	vreopen(LINE(vcline), lineDOT(), vcline);
	vsyncCL();
	vsetcurs(cp);
}
Пример #13
0
void
lsmatch(char *cp)
{
	char *save = smalloc(LBSIZE);
	register char *sp = save;
	register char *scurs = cursor;

	wcursor = cp;
	lcpy(sp, linebuf, LBSIZE);
	*wcursor = 0;
	strcpy(cursor, genbuf);
	cursor = strend(linebuf) - 1;
	if (lmatchp(dot - vcline)) {
		register int i = insmode;
		register int c = outcol;
		register int l = outline;

		if (!MI)
			endim();
		vgoto(splitw ? WECHO : LINE(wdot - llimit), column(wcursor) - 1);
		flush();
		sleep(1);
		vgoto(l, c);
		if (i)
			goim();
	}
	else {
		strcLIN(sp);
		strcpy(scurs, genbuf);
		if (!lmatchp((line *) 0))
			beep();
	}
	strcLIN(sp);
	wdot = 0;
	wcursor = 0;
	cursor = scurs;
	free(save);
}
Пример #14
0
void
drawwig(char *s)	/* draw wiggly line */
{
	int x[50], y[50], xp, yp, pxp, pyp;
	float t1, t2, t3, w;
	int i, j, numdots, N;
	int osize;
	char temp[50], *p;

	osize = size;
	setsize(t_size(pstab[osize-1] / drawsize));
	p = s;
	for (N = 2; (p=getstr(p,temp)) != NULL && N < sizeof(x)/sizeof(x[0]); N++) {
		x[N] = atoi(temp);
		p = getstr(p, temp);
		y[N] = atoi(temp);
	}
	x[0] = x[1] = hpos;
	y[0] = y[1] = vpos;
	for (i = 1; i < N; i++) {
		x[i+1] += x[i];
		y[i+1] += y[i];
	}
	x[N] = x[N-1];
	y[N] = y[N-1];
	pxp = pyp = -9999;
	for (i = 0; i < N-1; i++) {	/* interval */
		numdots = (dist(x[i],y[i], x[i+1],y[i+1]) + dist(x[i+1],y[i+1], x[i+2],y[i+2])) / 2;
		numdots /= DX;
		numdots = min(numdots, maxdots);
		for (j = 0; j < numdots; j++) {	/* points within */
			w = (float) j / numdots;
			t1 = 0.5 * w * w;
			w = w - 0.5;
			t2 = 0.75 - w * w;
			w = w - 0.5;
			t3 = 0.5 * w * w;
			xp = t1 * x[i+2] + t2 * x[i+1] + t3 * x[i] + 0.5;
			yp = t1 * y[i+2] + t2 * y[i+1] + t3 * y[i] + 0.5;
			if (xp != pxp || yp != pyp) {
				hgoto(xp);
				vgoto(yp);
				put1(drawdot);
				pxp = xp;
				pyp = yp;
			}
		}
	}
	setsize(osize);
}
Пример #15
0
/*
 * Start harcopy open.
 * Print an image of the line to the left of the cursor
 * under the full print of the line and position the cursor.
 * If we are in a scroll ^D within hardcopy open then all this
 * is suppressed.
 */
void 
sethard(void)
{

	if (state == VISUAL)
		return;
	rubble = 0;
	state = HARDOPEN;
	if (hold & HOLDROL)
		return;
	vup1();
	LINE(0) = WBOT;
	if (Pline == numbline)
		vgoto(WBOT, 0), printf("%6d  ", lineDOT());
}
Пример #16
0
/*
 * Do the real work in deleting cnt lines starting at line p from
 * the display.  First affected line is line l.
 */
void 
vdellin(int p, int cnt, int l)
{
	register int i;

	if (cnt == 0)
		return;
	if (DL == NOSTR || cnt < 0) {
		/*
		 * Can't do it; just remember that line l is munged.
		 */
		FLAGS(l) |= VDIRT;
		return;
	}
#ifdef ADEBUG
	if (trace)
		tfixnl(), fprintf(trace, "vdellin(%d, %d, %d)\n", p, cnt, l);
#endif
	/*
	 * Send the deletes to the screen and then adjust logical
	 * and physical internal data structures.
	 */
	vgoto(p, 0);
	if (DL_PARM && (cnt>1 || *DL==0)) {
		vputp(tgoto(DL_PARM, p, cnt), WECHO-p);
	}
	else if (xCS && *DL==0) {
		/* vt100: fake DL by changing scrolling region */
		vputp(SC, 1);	/* Save since xCS homes stupid cursor */
		vputp(tgoto(xCS, TLINES-1, p), 1);
		vputp(tgoto(CM, 0, TLINES-1), 1);/* Go to lower left corner */
		for (i=0; i<cnt; i++)		/* .. and scroll cnt times */
			putch('\n');		/* should check NL too */
		vputp(tgoto(xCS, TLINES-1, 0), 1);/* restore scrolling region */
		vputp(RC, 1);			/* put cursor back */
	}
	else {
		for (i = 0; i < cnt; i++)
			vputp(DL, WECHO - p);
	}
	vadjDL(p, cnt);
	vcloseup(l, cnt);
}
Пример #17
0
static void
formfeed(void)

{

/*
 *
 * Called whenever we've finished with the last page and want to get ready for the
 * next one. Also used at the beginning and end of each input file, so we have to
 * be careful about what's done. I've added a simple test before the showpage that
 * should eliminate the extra blank page that was put out at the end of many jobs,
 * but the PAGES comments may be wrong.
 *
 */

    if ( fp_out == stdout )		/* count the last page */
	printed++;

    endline();				/* print the last line */

    fprintf(fp_out, "cleartomark\n");
    if ( feof(fp_in) == 0 || markedpage == TRUE )
	fprintf(fp_out, "showpage\n");
    fprintf(fp_out, "saveobj restore\n");
    fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);

    if ( ungetc(getc(fp_in), fp_in) == EOF )
	redirect(-1);
    else redirect(++page);

    fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
    fprintf(fp_out, "/saveobj save def\n");
    fprintf(fp_out, "mark\n");
    writerequest(printed+1, fp_out);
    fprintf(fp_out, "%d pagesetup\n", printed+1);

    vgoto(topmargin);
    hgoto(leftmargin);

    markedpage = FALSE;

}   /* End of formfeed */
Пример #18
0
void
drawarc (
    int dx1,
    int dy1,		/* vector from current pos to center */
    int dx2,
    int dy2,		/* from center to end of the arc */
    int c			/* clockwise if c is A */
)


{


/*
 *
 * If c isn't set to 'A' a counter-clockwise arc is drawn from the current point
 * (hpos, vpos) to (hpos+dx1+dx2, vpos+dy1+dy2). The center of the circle is the
 * point (hpos+dx1, vpos+dy1). If c is 'A' the arc goes clockwise from the point
 * (hpos+dx1+dx2, vpos+dy1+dy2) to (hpos, vpos). Clockwise arcs are only needed
 * if we're building a larger path out of pieces that include arcs, and want to
 * have PostScript manage the path for us. Arguments (for a clockwise arc) are
 * what would have been supplied if the arc was drawn in a counter-clockwise
 * direction, and are converted to values suitable for use with PostScript's arcn
 * operator.
 *
 */


    if ( (dx1 != 0 || dy1 != 0) && (dx2 != 0 || dy2 != 0) )
    {
        fprintf(tf, "%d %d %d %d %d %d D%c\n", hpos, vpos, dx1, dy1, dx2, dy2, c);
    }

    hgoto(hpos + dx1 + dx2);		/* where troff expects to be */
    vgoto(vpos + dy1 + dy2);

    resetpos();				/* not sure where the printer is */

}   /* End of drawarc */
Пример #19
0
/*
 * We need cnt more positions on this line.
 * Open up new space on the screen (this may in fact be a
 * screen rollup).
 *
 * On a dumb terminal we may infact redisplay the rest of the
 * screen here brute force to keep it pretty.
 */
void
vneedpos(int npcnt)
{
	register int d = DEPTH(vcline);
	register int rmdr = d * WCOLS - linend;

	/*
	 * Delete the showmode string on wraparound to last line. Cannot use
	 * vclrech() since the mode string is printed on the echo area, but
	 * not actually a part of it.
	 */
	if (value(SHOWMODE) && (value(REDRAW) || (IM && EI)) &&
			npcnt == rmdr - IN && LINE(vcline) + d == WECHO) {
		int sdc, sdl;
		char *ocurs;

		endim();
		sdc = destcol, sdl = destline, ocurs = cursor;
		splitw++;
		vgoto(WECHO, 0);
		if (CD) {
			vputp(CD, 1);
		} else if (CE) {
			vputp(CE, 1);
		} else {
			int i;

			for (i = 1; i < WCOLS; i++)
				vputchar(' ');
		}
		destcol = sdc, destline = sdl; cursor = ocurs;
		splitw = 0;
	}
	if (npcnt <= rmdr - IN)
		return;
	endim();
	vnpins(1);
}
Пример #20
0
void
main(void)
{
	int c, n;
	char str[100], *args[10];
	int jfont, curfont;

	if(initdraw(0, fontfile, 0) < 0){
		fprint(2, "mnihongo: can't initialize display: %r\n");
		exits("open");
	}
	Binit(&bin, 0, OREAD);
	Binit(&bout, 1, OWRITE);

	jfont = -1;
	curfont = 1;
	while ((c = Bgetc(&bin)) >= 0) {
		switch (c) {
		case '\n':	/* when input is text */
		case ' ':
		case '\0':		/* occasional noise creeps in */
			putchar(c);
			break;
		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			/* two motion digits plus a character */
			putchar(c);	/* digit 1 */
			n = (c-'0')*10;
			c = Bgetc(&bin);
			putchar(c);	/* digit 2 */
			n += c - '0';
			hmot(n);
			putchar(Bgetc(&bin));	/* char itself */
			break;
		case 'c':	/* single character */
			c = Bgetrune(&bin);
			if(c==' ')	/* why does this happen? it's troff - bwk */
				break;
			else if(jfont == curfont){
				Bungetrune(&bin);
				Bgetstr(&bin, str);
				kanji(str);
			}else{
				putchar('c');
				putchar(c);
			}
			break;
		case 'C':
			Bgetstr(&bin, str);
			Bprint(&bout, "C%s", str);
			break;
		case 'f':
			Bgetstr(&bin, str);
			curfont = atoi(str);
			if(curfont < 0 || curfont > 20)
				curfont = 1;	/* sanity */
			Bprint(&bout, "%c%s", c, str);
			break;
		case 'N':	/* absolute character number */
		case 's':
		case 'p':	/* new page */
			Bgetint(&bin, &n);
			Bprint(&bout, "%c%d", c, n);
			break;
		case 'H':	/* absolute horizontal motion */
			Bgetint(&bin, &n);
			Bprint(&bout, "%c%d", c, n);
			hgoto(n);
			break;
		case 'h':	/* relative horizontal motion */
			Bgetint(&bin, &n);
			Bprint(&bout, "%c%d", c, n);
			hmot(n);
			break;
		case 'V':
			Bgetint(&bin, &n);
			Bprint(&bout, "%c%d", c, n);
			vgoto(n);
			break;
		case 'v':
			Bgetint(&bin, &n);
			Bprint(&bout, "%c%d", c, n);
			vmot(n);
			break;

		case 'w':	/* word space */
			putchar(c);
			break;

		case 'x':	/* device control */
			Bgetline(&bin, str);
			Bprint(&bout, "%c%s", c, str);
			if(tokenize(str, args, 10)>2 && args[0][0]=='f' && ('0'<=args[1][0] && args[1][0]<='9')){
				if(strncmp(args[2], "Jp", 2) == 0)
					jfont = atoi(args[1]);
				else if(atoi(args[1]) == jfont)
					jfont = -1;
			}
			break;

		case 'D':	/* draw function */
		case 'n':	/* end of line */
		case '#':	/* comment */
			Bgetline(&bin, str);
			Bprint(&bout, "%c%s", c, str);
			break;
		default:
			fprint(2, "mnihongo: unknown input character %o %c\n", c, c);
			exits("error");
		}
	}
}
Пример #21
0
void movehv(double h, double v)	/* go to internal position h, v */
{
	hgoto(h);
	vgoto(v);
}
Пример #22
0
void move(double x, double y)	/* go to position x, y in external coords */
{
	hgoto(xconv(x));
	vgoto(yconv(y));
}
Пример #23
0
/*
 * 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.  Aescaped is the location
 * where we stick a termination indicator (whether we
 * ended with an ESCAPE or a newline/return.
 *
 * We do erase-kill type processing here and also
 * are careful about the way we do this so that it is
 * repeatable.  (I.e. so that your kill doesn't happen,
 * when you repeat an insert if it was escaped with \ the
 * first time you did it.
 */
char *
vgetline(int cnt, char *gcursor, bool *aescaped)
{
	register int c, ch;
	register char *cp;
	int x, y, iwhite;
	char *iglobp;
	void (*OO)() = Outchar;

	/*
	 * Clear the output state and counters
	 * for autoindent backwards motion (counts of ^D, etc.)
	 * Remember how much white space at beginning of line so
	 * as not to allow backspace over autoindent.
	 */
	*aescaped = 0;
	ogcursor = gcursor;
	flusho();
	CDCNT = 0;
	HADUP = 0;
	HADZERO = 0;
	gobbled = 0;
	iwhite = whitecnt(genbuf);
	iglobp = vglobp;

	/*
	 * Carefully avoid using vinschar in the echo area.
	 */
	if (splitw)
		Outchar = vputchar;
	else {
		Outchar = vinschar;
		vprepins();
	}
	for (;;) {
		if (gobblebl)
			gobblebl--;
		if (cnt != 0) {
			cnt--;
			if (cnt == 0)
				goto vadone;
		}
		ch = c = getkey() & (QUOTE|TRIM);
		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 == tty.c_cc[VERASE])
				c = CTRL('h');
			else if (c == tty.c_cc[VKILL])
				c = -1;
			switch (c) {

			/*
			 * ^?		Interrupt drops you back to visual
			 *		command mode with an unread interrupt
			 *		still in the input buffer.
			 *
			 * ^\		Quit does the same as interrupt.
			 *		If you are a ex command rather than
			 *		a vi command this will drop you
			 *		back to command mode for sure.
			 */
			case ATTN:
			case QUIT:
				ungetkey(c);
				goto vadone;

			/*
			 * ^H		Backs up a character in the input.
			 *
			 * BUG:		Can't back around line boundaries.
			 *		This is hard because stuff has
			 *		already been saved for repeat.
			 */
			case CTRL('h'):
bakchar:
				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((int)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
			 *		the autoindent.
			 */
			case -1:
				cp = ogcursor;
vbackup:
				if (cp == gcursor) {
					beep();
					continue;
				}
				endim();
				*cp = 0;
				c = cindent();
				vgotoCL(qcolumn(cursor - 1, genbuf));
				if (doomed >= 0)
					doomed += c - cindent();
				gcursor = cp;
				continue;

			/*
			 * \		Followed by erase or kill
			 *		maps to just the erase or kill.
			 */
			case '\\':
				x = destcol, y = destline;
				ex_putchar('\\');
				vcsync();
				c = getkey();
				if (c == tty.c_cc[VERASE]
				    || c == tty.c_cc[VKILL]) {
					vgoto(y, x);
					if (doomed >= 0)
						doomed++;
					goto def;
				}
				ungetkey(c), c = '\\';
				goto noput;

			/*
			 * ^Q		Super quote following character
			 *		Only ^@ is verboten (trapped at
			 *		a lower level) and \n forces a line
			 *		split so doesn't really go in.
			 *
			 * ^V		Synonym for ^Q
			 */
			case CTRL('q'):
			case CTRL('v'):
				x = destcol, y = destline;
				ex_putchar('^');
				vgoto(y, x);
				c = getkey();
				if (c != NL) {
					if (doomed >= 0)
						doomed++;
					goto def;
				}
				break;
			}
		}

		/*
		 * If we get a blank not in the echo area
		 * consider splitting the window in the wrapmargin.
		 */
		if (c == ' ' && !splitw) {
			if (gobblebl) {
				gobbled = 1;
				continue;
			}
			if (value(WRAPMARGIN) && outcol >= WCOLS - value(WRAPMARGIN)) {
				c = NL;
				gobblebl = 2;
			}
		}
		switch (c) {

		/*
		 * ^M		Except in repeat maps to \n.
		 */
		case CR:
			if (vglobp)
				goto def;
			c = '\n';
			/* presto chango ... */

		/*
		 * \n		Start new line.
		 */
		case NL:
			*aescaped = c;
			goto vadone;

		/*
		 * escape	End insert unless repeat and more to repeat.
		 */
		case ESCAPE:
			if (vglobp && *vglobp)
				goto def;
			goto vadone;

		/*
		 * ^D		Backtab.
		 * ^T		Software forward tab.
		 *
		 *		Unless in repeat where this means these
		 *		were superquoted in.
		 */
		case CTRL('d'):
		case CTRL('t'):
			if (vglobp)
				goto def;
			/* fall into ... */

		/*
		 * ^D|QUOTE	Is a backtab (in a repeated command).
		 */
		case CTRL('d') | QUOTE:
			*gcursor = 0;
			cp = vpastwh(genbuf);
			c = whitecnt(genbuf);
			if (ch == CTRL('t')) {
				/*
				 * ^t just generates new indent replacing
				 * current white space rounded up to soft
				 * tab stop increment.
				 */
				if (cp != gcursor)
					/*
					 * BUG:		Don't hack ^T except
					 *		right after initial
					 *		white space.
					 */
					continue;
				cp = genindent(iwhite = backtab(c + value(SHIFTWIDTH) + 1));
				ogcursor = cp;
				goto vbackup;
			}
			/*
			 * ^D works only if we are at the (end of) the
			 * generated autoindent.  We count the ^D for repeat
			 * purposes.
			 */
			if (c == iwhite && c != 0) {
				if (cp == gcursor) {
					iwhite = backtab(c);
					CDCNT++;
					ogcursor = cp = genindent(iwhite);
					goto vbackup;
				} else if (&cp[1] == gcursor &&
				    (*cp == '^' || *cp == '0')) {
					/*
					 * ^^D moves to margin, then back
					 * to current indent on next line.
					 *
					 * 0^D moves to margin and then
					 * stays there.
					 */
					HADZERO = *cp == '0';
					ogcursor = cp = genbuf;
					HADUP = 1 - HADZERO;
					CDCNT = 1;
					endim();
					back1();
					vputc(' ');
					goto vbackup;
				}
			}
			if (vglobp && vglobp - iglobp >= 2 &&
			    (vglobp[-2] == '^' || vglobp[-2] == '0')
			    && gcursor == ogcursor + 1)
				goto bakchar;
			continue;

		default:
			/*
			 * Possibly discard control inputs.
			 */
			if (!vglobp && junk(c)) {
				beep();
				continue;
			}
def:
			ex_putchar(c);
noput:
			if (gcursor > &genbuf[LBSIZE - 2])
				error("Line too long");
			*gcursor++ = c & TRIM;
			vcsync();
#ifdef LISP
			if (value(SHOWMATCH) && !iglobp)
				if (c == ')' || c == '}')
					lsmatch(gcursor);
#endif
			continue;
		}
	}
vadone:
	*gcursor = 0;
	Outchar = OO;
	endim();
	return (gcursor);
}
Пример #24
0
/*
 * Subroutine for vgetline to back up a single character position,
 * backwards around end of lines (vgoto can't hack columns which are
 * less than 0 in general).
 */
void
back1(void)
{

	vgoto(destline - 1, WCOLS + destcol - 1);
}
Пример #25
0
vmain()
{
	register int c, cnt, i;
	char esave[TUBECOLS];
	char *oglobp;
	char d;
	line *addr;
	int ind, nlput;
	int shouldpo = 0;
	int onumber, olist, (*OPline)(), (*OPutchar)();

	vch_mac = VC_NOTINMAC;

	/*
	 * If we started as a vi command (on the command line)
	 * then go process initial commands (recover, next or tag).
	 */
	if (initev) {
		oglobp = globp;
		globp = initev;
		hadcnt = cnt = 0;
		i = tchng;
		addr = dot;
		goto doinit;
	}

	/*
	 * NB:
	 *
	 * The current line is always in the line buffer linebuf,
	 * and the cursor at the position cursor.  You should do
	 * a vsave() before moving off the line to make sure the disk
	 * copy is updated if it has changed, and a getDOT() to get
	 * the line back if you mung linebuf.  The motion
	 * routines in ex_vwind.c handle most of this.
	 */
	for (;;) {
		/*
		 * Decode a visual command.
		 * First sync the temp file if there has been a reasonable
		 * amount of change.  Clear state for decoding of next
		 * command.
		 */
		TSYNC();
		vglobp = 0;
		vreg = 0;
		hold = 0;
		seenprompt = 1;
		wcursor = 0;
		Xhadcnt = hadcnt = 0;
		Xcnt = cnt = 1;
		splitw = 0;
		if (i = holdupd) {
			if (state == VISUAL)
				ignore(peekkey());
			holdupd = 0;
/*
			if (LINE(0) < ZERO) {
				vclear();
				vcnt = 0;
				i = 3;
			}
*/
			if (state != VISUAL) {
				vcnt = 0;
				vsave();
				vrepaint(cursor);
			} else if (i == 3)
				vredraw(WTOP);
			else
				vsync(WTOP);
			vfixcurs();
		}

		/*
		 * Gobble up counts and named buffer specifications.
		 */
		for (;;) {
looptop:
#ifdef MDEBUG
			if (trace)
				fprintf(trace, "pc=%c",peekkey());
#endif
			if (isdigit(peekkey()) && peekkey() != '0') {
				hadcnt = 1;
				cnt = vgetcnt();
				forbid (cnt <= 0);
			}
			if (peekkey() != '"')
				break;
			ignore(getkey()), c = getkey();
			/*
			 * Buffer names be letters or digits.
			 * But not '0' as that is the source of
			 * an 'empty' named buffer spec in the routine
			 * kshift (see ex_temp.c).
			 */
			forbid (c == '0' || !isalpha(c) && !isdigit(c));
			vreg = c;
		}
reread:
		/*
		 * Come to reread from below after some macro expansions.
		 * The call to map allows use of function key pads
		 * by performing a terminal dependent mapping of inputs.
		 */
#ifdef MDEBUG
		if (trace)
			fprintf(trace,"pcb=%c,",peekkey());
#endif
		op = getkey();
		maphopcnt = 0;
		do {
			/*
			 * Keep mapping the char as long as it changes.
			 * This allows for double mappings, e.g., q to #,
			 * #1 to something else.
			 */
			c = op;
			op = map(c,arrows);
#ifdef MDEBUG
			if (trace)
				fprintf(trace,"pca=%c,",c);
#endif
			/*
			 * Maybe the mapped to char is a count. If so, we have
			 * to go back to the "for" to interpret it. Likewise
			 * for a buffer name.
			 */
			if ((isdigit(c) && c!='0') || c == '"') {
				ungetkey(c);
				goto looptop;
			}
			if (!value(REMAP)) {
				c = op;
				break;
			}
			if (++maphopcnt > 256)
				error("Infinite macro loop");
		} while (c != op);

		/*
		 * Begin to build an image of this command for possible
		 * later repeat in the buffer workcmd.  It will be copied
		 * to lastcmd by the routine setLAST
		 * if/when completely specified.
		 */
		lastcp = workcmd;
		if (!vglobp)
			*lastcp++ = c;

		/*
		 * First level command decode.
		 */
		switch (c) {

		/*
		 * ^L		Clear screen e.g. after transmission error.
		 */

		/*
		 * ^R		Retype screen, getting rid of @ lines.
		 *		If in open, equivalent to ^L.
		 *		On terminals where the right arrow key sends
		 *		^L we make ^R act like ^L, since there is no
		 *		way to get ^L.  These terminals (adm31, tvi)
		 *		are intelligent so ^R is useless.  Soroc
		 *		will probably foul this up, but nobody has
		 *		one of them.
		 */
		case CTRL(l):
		case CTRL(r):
			if (c == CTRL(l) || (KR && *KR==CTRL(l))) {
				vclear();
				vdirty(0, vcnt);
			}
			if (state != VISUAL) {
				/*
				 * Get a clean line, throw away the
				 * memory of what is displayed now,
				 * and move back onto the current line.
				 */
				vclean();
				vcnt = 0;
				vmoveto(dot, cursor, 0);
				continue;
			}
			vredraw(WTOP);
			/*
			 * Weird glitch -- when we enter visual
			 * in a very small window we may end up with
			 * no lines on the screen because the line
			 * at the top is too long.  This forces the screen
			 * to be expanded to make room for it (after
			 * we have printed @'s ick showing we goofed).
			 */
			if (vcnt == 0)
				vrepaint(cursor);
			vfixcurs();
			continue;

		/*
		 * $		Escape just cancels the current command
		 *		with a little feedback.
		 */
		case ESCAPE:
			beep();
			continue;

		/*
		 * @   		Macros. Bring in the macro and put it
		 *		in vmacbuf, point vglobp there and punt.
		 */
		 case '@':
			c = getesc();
			if (c == 0)
				continue;
			if (c == '@')
				c = lastmac;
			if (isupper(c))
				c = tolower(c);
			forbid(!islower(c));
			lastmac = c;
			vsave();
			CATCH
				char tmpbuf[BUFSIZ];

				regbuf(c,tmpbuf,sizeof(vmacbuf));
				macpush(tmpbuf, 1);
			ONERR
				lastmac = 0;
				splitw = 0;
				getDOT();
				vrepaint(cursor);
				continue;
			ENDCATCH
			vmacp = vmacbuf;
			goto reread;

		/*
		 * .		Repeat the last (modifying) open/visual command.
		 */
		case '.':
			/*
			 * Check that there was a last command, and
			 * take its count and named buffer unless they
			 * were given anew.  Special case if last command
			 * referenced a numeric named buffer -- increment
			 * the number and go to a named buffer again.
			 * This allows a sequence like "1pu.u.u...
			 * to successively look for stuff in the kill chain
			 * much as one does in EMACS with C-Y and M-Y.
			 */
			forbid (lastcmd[0] == 0);
			if (hadcnt)
				lastcnt = cnt;
			if (vreg)
				lastreg = vreg;
			else if (isdigit(lastreg) && lastreg < '9')
				lastreg++;
			vreg = lastreg;
			cnt = lastcnt;
			hadcnt = lasthad;
			vglobp = lastcmd;
			goto reread;

		/*
		 * ^U		Scroll up.  A count sticks around for
		 *		future scrolls as the scroll amount.
		 *		Attempt to hold the indentation from the
		 *		top of the screen (in logical lines).
		 *
		 * BUG:		A ^U near the bottom of the screen
		 *		on a dumb terminal (which can't roll back)
		 *		causes the screen to be cleared and then
		 *		redrawn almost as it was.  In this case
		 *		one should simply move the cursor.
		 */
		case CTRL(u):
			if (hadcnt)
				vSCROLL = cnt;
			cnt = vSCROLL;
			if (state == VISUAL)
				ind = vcline, cnt += ind;
			else
				ind = 0;
			vmoving = 0;
			vup(cnt, ind, 1);
			vnline(NOSTR);
			continue;

		/*
		 * ^D		Scroll down.  Like scroll up.
		 */
		case CTRL(d):
#ifdef TRACE
		if (trace)
			fprintf(trace, "before vdown in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
#endif
			if (hadcnt)
				vSCROLL = cnt;
			cnt = vSCROLL;
			if (state == VISUAL)
				ind = vcnt - vcline - 1, cnt += ind;
			else
				ind = 0;
			vmoving = 0;
			vdown(cnt, ind, 1);
#ifdef TRACE
		if (trace)
			fprintf(trace, "before vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
#endif
			vnline(NOSTR);
#ifdef TRACE
		if (trace)
			fprintf(trace, "after vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
#endif
			continue;

		/*
		 * ^E		Glitch the screen down (one) line.
		 *		Cursor left on same line in file.
		 */
		case CTRL(e):
			if (state != VISUAL)
				continue;
			if (!hadcnt)
				cnt = 1;
			/* Bottom line of file already on screen */
			forbid(lineDOL()-lineDOT() <= vcnt-1-vcline);
			ind = vcnt - vcline - 1 + cnt;
			vdown(ind, ind, 1);
			vnline(cursor);
			continue;

		/*
		 * ^Y		Like ^E but up
		 */
		case CTRL(y):
			if (state != VISUAL)
				continue;
			if (!hadcnt)
				cnt = 1;
			forbid(lineDOT()-1<=vcline); /* line 1 already there */
			ind = vcline + cnt;
			vup(ind, ind, 1);
			vnline(cursor);
			continue;


		/*
		 * m		Mark position in mark register given
		 *		by following letter.  Return is
		 *		accomplished via ' or `; former
		 *		to beginning of line where mark
		 *		was set, latter to column where marked.
		 */
		case 'm':
			/*
			 * Getesc is generally used when a character
			 * is read as a latter part of a command
			 * to allow one to hit rubout/escape to cancel
			 * what you have typed so far.  These characters
			 * are mapped to 0 by the subroutine.
			 */
			c = getesc();
			if (c == 0)
				continue;

			/*
			 * Markreg checks that argument is a letter
			 * and also maps ' and ` to the end of the range
			 * to allow '' or `` to reference the previous
			 * context mark.
			 */
			c = markreg(c);
			forbid (c == 0);
			vsave();
			names[c - 'a'] = (*dot &~ 01);
			ncols[c - 'a'] = cursor;
			anymarks = 1;
			continue;

		/*
		 * ^F		Window forwards, with 2 lines of continuity.
		 *		Count repeats.
		 */
		case CTRL(f):
			vsave();
			if (vcnt > 2) {
				addr = dot + (vcnt - vcline) - 2 + (cnt-1)*basWLINES;
				forbid(addr > dol);
				dot = addr;
				vcnt = vcline = 0;
			}
			vzop(0, 0, '+');
			continue;

		/*
		 * ^B		Window backwards, with 2 lines of continuity.
		 *		Inverse of ^F.
		 */
		case CTRL(b):
			vsave();
			if (one + vcline != dot && vcnt > 2) {
				addr = dot - vcline - 2 + (cnt-1)*basWLINES;
				forbid (addr <= zero);
				dot = addr;
				vcnt = vcline = 0;
			}
			vzop(0, 0, '^');
			continue;

		/*
		 * z		Screen adjustment, taking a following character:
		 *			z<CR>		current line to top
		 *			z<NL>		like z<CR>
		 *			z-		current line to bottom
		 *		also z+, z^ like ^F and ^B.
		 *		A preceding count is line to use rather
		 *		than current line.  A count between z and
		 *		specifier character changes the screen size
		 *		for the redraw.
		 *
		 */
		case 'z':
			if (state == VISUAL) {
				i = vgetcnt();
				if (i > 0)
					vsetsiz(i);
				c = getesc();
				if (c == 0)
					continue;
			}
			vsave();
			vzop(hadcnt, cnt, c);
			continue;

		/*
		 * Y		Yank lines, abbreviation for y_ or yy.
		 *		Yanked lines can be put later if no
		 *		changes intervene, or can be put in named
		 *		buffers and put anytime in this session.
		 */
		case 'Y':
			ungetkey('_');
			c = 'y';
			break;

		/*
		 * J		Join lines, 2 by default.  Count is number
		 *		of lines to join (no join operator sorry.)
		 */
		case 'J':
			forbid (dot == dol);
			if (cnt == 1)
				cnt = 2;
			if (cnt > (i = dol - dot + 1))
				cnt = i;
			vsave();
			vmacchng(1);
			setLAST();
			cursor = strend(linebuf);
			vremote(cnt, join, 0);
			notenam = "join";
			vmoving = 0;
			killU();
			vreplace(vcline, cnt, 1);
			if (!*cursor && cursor > linebuf)
				cursor--;
			if (notecnt == 2)
				notecnt = 0;
			vrepaint(cursor);
			continue;

		/*
		 * S		Substitute text for whole lines, abbrev for c_.
		 *		Count is number of lines to change.
		 */
		case 'S':
			ungetkey('_');
			c = 'c';
			break;

		/*
		 * O		Create a new line above current and accept new
		 *		input text, to an escape, there.
		 *		A count specifies, for dumb terminals when
		 *		slowopen is not set, the number of physical
		 *		line space to open on the screen.
		 *
		 * o		Like O, but opens lines below.
		 */
		case 'O':
		case 'o':
			vmacchng(1);
			voOpen(c, cnt);
			continue;

		/*
		 * C		Change text to end of line, short for c$.
		 */
		case 'C':
			if (*cursor) {
				ungetkey('$'), c = 'c';
				break;
			}
			goto appnd;

		/*
		 * ~	Switch case of letter under cursor
		 */
		case '~':
			{
				char mbuf[4];
				setLAST();
				mbuf[0] = 'r';
				mbuf[1] = *cursor;
				mbuf[2] = cursor[1]==0 ? 0 : ' ';
				mbuf[3] = 0;
				if (isalpha(mbuf[1]))
					mbuf[1] ^= ' ';	/* toggle the case */
				macpush(mbuf, 1);
			}
			continue;


		/*
		 * A		Append at end of line, short for $a.
		 */
		case 'A':
			operate('$', 1);
appnd:
			c = 'a';
			/* fall into ... */

		/*
		 * a		Appends text after cursor.  Text can continue
		 *		through arbitrary number of lines.
		 */
		case 'a':
			if (*cursor) {
				if (state == HARDOPEN)
					putchar(*cursor);
				cursor++;
			}
			goto insrt;

		/*
		 * I		Insert at beginning of whitespace of line,
		 *		short for ^i.
		 */
		case 'I':
			operate('^', 1);
			c = 'i';
			/* fall into ... */

		/*
		 * R		Replace characters, one for one, by input
		 *		(logically), like repeated r commands.
		 *
		 * BUG:		This is like the typeover mode of many other
		 *		editors, and is only rarely useful.  Its
		 *		implementation is a hack in a low level
		 *		routine and it doesn't work very well, e.g.
		 *		you can't move around within a R, etc.
		 */
		case 'R':
			/* fall into... */

		/*
		 * i		Insert text to an escape in the buffer.
		 *		Text is arbitrary.  This command reminds of
		 *		the i command in bare teco.
		 */
		case 'i':
insrt:
			/*
			 * Common code for all the insertion commands.
			 * Save for redo, position cursor, prepare for append
			 * at command and in visual undo.  Note that nothing
			 * is doomed, unless R when all is, and save the
			 * current line in a the undo temporary buffer.
			 */
			vmacchng(1);
			setLAST();
			vcursat(cursor);
			prepapp();
			vnoapp();
			doomed = c == 'R' ? 10000 : 0;
			if(FIXUNDO)
				vundkind = VCHNG;
			vmoving = 0;
			CP(vutmp, linebuf);

			/*
			 * If this is a repeated command, then suppress
			 * fake insert mode on dumb terminals which looks
			 * ridiculous and wastes lots of time even at 9600B.
			 */
			if (vglobp)
				hold = HOLDQIK;
			vappend(c, cnt, 0);
			continue;

		/*
		 * ^?		An attention, normally a ^?, just beeps.
		 *		If you are a vi command within ex, then
		 *		two ATTN's will drop you back to command mode.
		 */
		case ATTN:
			beep();
			if (initev || peekkey() != ATTN)
				continue;
			/* fall into... */

		/*
		 * ^\		A quit always gets command mode.
		 */
		case QUIT:
			/*
			 * Have to be careful if we were called
			 *	g/xxx/vi
			 * since a return will just start up again.
			 * So we simulate an interrupt.
			 */
			if (inglobal)
				onintr();
			/* fall into... */

#ifdef notdef
		/*
		 * q		Quit back to command mode, unless called as
		 *		vi on command line in which case dont do it
		 */
		case 'q':	/* quit */
			if (initev) {
				vsave();
				CATCH
					error("Q gets ex command mode, :q leaves vi");
				ENDCATCH
				splitw = 0;
				getDOT();
				vrepaint(cursor);
				continue;
			}
#endif
			/* fall into... */

		/*
		 * Q		Is like q, but always gets to command mode
		 *		even if command line invocation was as vi.
		 */
		case 'Q':
			vsave();
			/*
			 * If we are in the middle of a macro, throw away
			 * the rest and fix up undo.
			 * This code copied from getbr().
			 */
			if (vmacp) {
				vmacp = 0;
				if (inopen == -1)	/* don't screw up undo for esc esc */
					vundkind = VMANY;
				inopen = 1;	/* restore old setting now that macro done */
			}
			return;


		/*
		 * ZZ		Like :x
		 */
		 case 'Z':
			forbid(getkey() != 'Z');
			oglobp = globp;
			globp = "x";
			vclrech(0);
			goto gogo;
			
		/*
		 * P		Put back text before cursor or before current
		 *		line.  If text was whole lines goes back
		 *		as whole lines.  If part of a single line
		 *		or parts of whole lines splits up current
		 *		line to form many new lines.
		 *		May specify a named buffer, or the delete
		 *		saving buffers 1-9.
		 *
		 * p		Like P but after rather than before.
		 */
		case 'P':
		case 'p':
			vmoving = 0;
#ifdef notdef
			forbid (!vreg && value(UNDOMACRO) && inopen < 0);
#endif
			/*
			 * If previous delete was partial line, use an
			 * append or insert to put it back so as to
			 * use insert mode on intelligent terminals.
			 */
			if (!vreg && DEL[0]) {
				forbid ((DEL[0] & (QUOTE|TRIM)) == OVERBUF);
				vglobp = DEL;
				ungetkey(c == 'p' ? 'a' : 'i');
				goto reread;
			}

			/*
			 * If a register wasn't specified, then make
			 * sure there is something to put back.
			 */
			forbid (!vreg && unddol == dol);
			/*
			 * If we just did a macro the whole buffer is in
			 * the undo save area.  We don't want to put THAT.
			 */
			forbid (vundkind == VMANY && undkind==UNDALL);
			vsave();
			vmacchng(1);
			setLAST();
			i = 0;
			if (vreg && partreg(vreg) || !vreg && pkill[0]) {
				/*
				 * Restoring multiple lines which were partial
				 * lines; will leave cursor in middle
				 * of line after shoving restored text in to
				 * split the current line.
				 */
				i++;
				if (c == 'p' && *cursor)
					cursor++;
			} else {
				/*
				 * In whole line case, have to back up dot
				 * for P; also want to clear cursor so
				 * cursor will eventually be positioned
				 * at the beginning of the first put line.
				 */
				cursor = 0;
				if (c == 'P') {
					dot--, vcline--;
					c = 'p';
				}
			}
			killU();

			/*
			 * The call to putreg can potentially
			 * bomb since there may be nothing in a named buffer.
			 * We thus put a catch in here.  If we didn't and
			 * there was an error we would end up in command mode.
			 */
			addr = dol;	/* old dol */
			CATCH
				vremote(1, vreg ? putreg : put, vreg);
			ONERR
				if (vreg == -1) {
					splitw = 0;
					if (op == 'P')
						dot++, vcline++;
					goto pfixup;
				}
			ENDCATCH
			splitw = 0;
			nlput = dol - addr + 1;
			if (!i) {
				/*
				 * Increment undap1, undap2 to make up
				 * for their incorrect initialization in the
				 * routine vremote before calling put/putreg.
				 */
				if (FIXUNDO)
					undap1++, undap2++;
				vcline++;
				nlput--;

				/*
				 * After a put want current line first line,
				 * and dot was made the last line put in code
				 * run so far.  This is why we increment vcline
				 * above and decrease dot here.
				 */
				dot -= nlput - 1;
			}
#ifdef TRACE
			if (trace)
				fprintf(trace, "vreplace(%d, %d, %d), undap1=%d, undap2=%d, dot=%d\n", vcline, i, nlput, lineno(undap1), lineno(undap2), lineno(dot));
#endif
			vreplace(vcline, i, nlput);
			if (state != VISUAL) {
				/*
				 * Special case in open mode.
				 * Force action on the screen when a single
				 * line is put even if it is identical to
				 * the current line, e.g. on YP; otherwise
				 * you can't tell anything happened.
				 */
				vjumpto(dot, cursor, '.');
				continue;
			}
pfixup:
			vrepaint(cursor);
			vfixcurs();
			continue;

		/*
		 * ^^		Return to previous file.
		 *		Like a :e #, and thus can be used after a
		 *		"No Write" diagnostic.
		 */
		case CTRL(^):
			forbid (hadcnt);
			vsave();
			ckaw();
			oglobp = globp;
			if (value(AUTOWRITE))
				globp = "e! #";
			else
				globp = "e #";
			goto gogo;

		/*
		 * ^]		Takes word after cursor as tag, and then does
		 *		tag command.  Read ``go right to''.
		 */
		case CTRL(]):
			grabtag();
			oglobp = globp;
			globp = "tag";
			goto gogo;

		/*
		 * &		Like :&
		 */
		 case '&':
			oglobp = globp;
			globp = "&";
			goto gogo;
			
		/*
		 * ^G		Bring up a status line at the bottom of
		 *		the screen, like a :file command.
		 *
		 * BUG:		Was ^S but doesn't work in cbreak mode
		 */
		case CTRL(g):
			oglobp = globp;
			globp = "file";
gogo:
			addr = dot;
			vsave();
			goto doinit;

#ifdef SIGTSTP
		/*
		 * ^Z:	suspend editor session and temporarily return
		 * 	to shell.  Only works with Berkeley/IIASA process
		 *	control in kernel.
		 */
		case CTRL(z):
			forbid(dosusp == 0 || !ldisc);
			vsave();
			oglobp = globp;
			globp = "stop";
			goto gogo;
#endif

		/*
		 * :		Read a command from the echo area and
		 *		execute it in command mode.
		 */
		case ':':
			forbid (hadcnt);
			vsave();
			i = tchng;
			addr = dot;
			if (readecho(c)) {
				esave[0] = 0;
				goto fixup;
			}
			getDOT();
			/*
			 * Use the visual undo buffer to store the global
			 * string for command mode, since it is idle right now.
			 */
			oglobp = globp; strcpy(vutmp, genbuf+1); globp = vutmp;
doinit:
			esave[0] = 0;
			fixech();

			/*
			 * Have to finagle around not to lose last
			 * character after this command (when run from ex
			 * command mode).  This is clumsy.
			 */
			d = peekc; ungetchar(0);
			if (shouldpo) {
				/*
				 * So after a "Hit return..." ":", we do
				 * another "Hit return..." the next time
				 */
				pofix();
				shouldpo = 0;
			}
			CATCH
				/*
				 * Save old values of options so we can
				 * notice when they change; switch into
				 * cooked mode so we are interruptible.
				 */
				onumber = value(NUMBER);
				olist = value(LIST);
				OPline = Pline;
				OPutchar = Putchar;
#ifndef CBREAK
				vcook();
#endif
				commands(1, 1);
				if (dot == zero && dol > zero)
					dot = one;
#ifndef CBREAK
				vraw();
#endif
			ONERR
#ifndef CBREAK
				vraw();
#endif
				copy(esave, vtube[WECHO], TUBECOLS);
			ENDCATCH
			fixol();
			Pline = OPline;
			Putchar = OPutchar;
			ungetchar(d);
			globp = oglobp;

			/*
			 * If we ended up with no lines in the buffer, make
			 * a line, and don't consider the buffer changed.
			 */
			if (dot == zero) {
				fixzero();
				sync();
			}
			splitw = 0;

			/*
			 * Special case: did list/number options change?
			 */
			if (onumber != value(NUMBER))
				setnumb(value(NUMBER));
			if (olist != value(LIST))
				setlist(value(LIST));

fixup:
			/*
			 * If a change occurred, other than
			 * a write which clears changes, then
			 * we should allow an undo even if .
			 * didn't move.
			 *
			 * BUG: You can make this wrong by
			 * tricking around with multiple commands
			 * on one line of : escape, and including
			 * a write command there, but its not
			 * worth worrying about.
			 */
			if (FIXUNDO && tchng && tchng != i)
				vundkind = VMANY, cursor = 0;

			/*
			 * If we are about to do another :, hold off
			 * updating of screen.
			 */
			if (vcnt < 0 && Peekkey == ':') {
				getDOT();
				shouldpo = 1;
				continue;
			}
			shouldpo = 0;

			/*
			 * In the case where the file being edited is
			 * new; e.g. if the initial state hasn't been
			 * saved yet, then do so now.
			 */
			if (unddol == truedol) {
				vundkind = VNONE;
				Vlines = lineDOL();
				if (!inglobal)
					savevis();
				addr = zero;
				vcnt = 0;
				if (esave[0] == 0)
					copy(esave, vtube[WECHO], TUBECOLS);
			}

			/*
			 * If the current line moved reset the cursor position.
			 */
			if (dot != addr) {
				vmoving = 0;
				cursor = 0;
			}

			/*
			 * If current line is not on screen or if we are
			 * in open mode and . moved, then redraw.
			 */
			i = vcline + (dot - addr);
			if (i < 0 || i >= vcnt && i >= -vcnt || state != VISUAL && dot != addr) {
				if (state == CRTOPEN)
					vup1();
				if (vcnt > 0)
					vcnt = 0;
				vjumpto(dot, (char *) 0, '.');
			} else {
				/*
				 * Current line IS on screen.
				 * If we did a [Hit return...] then
				 * restore vcnt and clear screen if in visual
				 */
				vcline = i;
				if (vcnt < 0) {
					vcnt = -vcnt;
					if (state == VISUAL)
						vclear();
					else if (state == CRTOPEN) {
						vcnt = 0;
					}
				}

				/*
				 * Limit max value of vcnt based on $
				 */
				i = vcline + lineDOL() - lineDOT() + 1;
				if (i < vcnt)
					vcnt = i;
				
				/*
				 * Dirty and repaint.
				 */
				vdirty(0, LINES);
				vrepaint(cursor);
			}

			/*
			 * If in visual, put back the echo area
			 * if it was clobberred.
			 */
			if (state == VISUAL) {
				int sdc = destcol, sdl = destline;

				splitw++;
				vigoto(WECHO, 0);
				for (i = 0; i < TUBECOLS - 1; i++) {
					if (esave[i] == 0)
						break;
					vputchar(esave[i]);
				}
				splitw = 0;
				vgoto(sdl, sdc);
			}
			continue;

		/*
		 * u		undo the last changing command.
		 */
		case 'u':
			vundo(1);
			continue;

		/*
		 * U		restore current line to initial state.
		 */
		case 'U':
			vUndo();
			continue;

fonfon:
			beep();
			vmacp = 0;
			inopen = 1;	/* might have been -1 */
			continue;
		}

		/*
		 * Rest of commands are decoded by the operate
		 * routine.
		 */
		operate(c, cnt);
	}
}
Пример #26
0
void
drawline(int dx, int dy, char *s) /* draw line from here to dx, dy using s */
{
	int xd, yd;
	float val, slope;
	int i, numdots;
	int dirmot, perp;
	int motincr, perpincr;
	int ohpos, ovpos, osize;
	float incrway;

	int itemp; /*temp. storage for value returned byint function sgn*/
	osize = size;
	setsize(t_size(pstab[osize-1] / drawsize));
	ohpos = hpos;
	ovpos = vpos;
	xd = dx / DX;
	yd = dy / DX;
	if (xd == 0) {
		numdots = abs (yd);
		numdots = min(numdots, maxdots);
		motincr = DX * sgn (yd);
		for (i = 0; i < numdots; i++) {
			vmot(motincr);
			put1(drawdot);
		}
		vgoto(ovpos + dy);
		setsize(osize);
		return;
	}
	if (yd == 0) {
		numdots = abs (xd);
		motincr = DX * sgn (xd);
		for (i = 0; i < numdots; i++) {
			hmot(motincr);
			put1(drawdot);
		}
		hgoto(ohpos + dx);
		setsize(osize);
		return;
	}
	if (abs (xd) > abs (yd)) {
		val = slope = (float) xd/yd;
		numdots = abs (xd);
		numdots = min(numdots, maxdots);
		dirmot = 'h';
		perp = 'v';
		motincr = DX * sgn (xd);
		perpincr = DX * sgn (yd);
	}
	else {
		val = slope = (float) yd/xd;
		numdots = abs (yd);
		numdots = min(numdots, maxdots);
		dirmot = 'v';
		perp = 'h';
		motincr = DX * sgn (yd);
		perpincr = DX * sgn (xd);
	}
	incrway = itemp = sgn ((int) slope);
	for (i = 0; i < numdots; i++) {
		val -= incrway;
		if (dirmot == 'h')
			hmot(motincr);
		else
			vmot(motincr);
		if (val * slope < 0) {
			if (perp == 'h')
				hmot(perpincr);
			else
				vmot(perpincr);
			val += slope;
		}
		put1(drawdot);
	}
	hgoto(ohpos + dx);
	vgoto(ovpos + dy);
	setsize(osize);
}
Пример #27
0
/*
 * Insert cnt blank lines before line p,
 * logically and (if supported) physically.
 */
void 
vinslin(register int p, register int cnt, int l)
{
	register int i;
	bool could = 1;

#ifdef ADEBUG
	if (trace)
		tfixnl(), fprintf(trace, "vinslin(%d, %d, %d)\n", p, cnt, l);
#endif
	if (p + cnt > WBOT && CD) {
		/*
		 * Really quick -- clear to end of screen.
		 */
		cnt = WECHO + 1 - p;
		vgoto(p, 0), vputp(CD, cnt);
		vclrech(1);
		vadjAL(p, cnt);
	} else if (SR && p == WTOP && costSR < costAL) {
		/*
		 * Use reverse scroll mode of the terminal, at
		 * the top of the window.  Reverse linefeed works
		 * too, since we only use it from line WTOP.
		 */
		for (i = cnt; i > 0; i--) {
			vgoto(p, 0), vputp(SR, 0);
			if (i > 1 && (hold & HOLDAT) == 0)
				putchar('@');
			/*
			 * If we are at the top of the screen, and the
			 * terminal retains display above, then we
			 * should try to clear to end of line.
			 * Have to use CE since we don't remember what is
			 * actually on the line.
			 */
			if (CE && (DA || p != 0))
				vputp(CE, 1);
		}
		vadjAL(p, cnt);
	} else if (AL) {
		/*
		 * Use insert line.
		 */
		vgoto(p, 0);
		if (AL_PARM && (cnt>1 || *AL==0)) {
			/* insert cnt lines.  Should do @'s too. */
			vputp(tgoto(AL_PARM, p, cnt), WECHO+1-p);
		}
		else if (xCS && *AL==0) {
			/* vt100 change scrolling region to fake AL */
			vputp(SC, 1);
			vputp(tgoto(xCS, TLINES-1,p), 1);
			vputp(RC, 1);	/* xCS homes stupid cursor */
			for (i=cnt; i>0; i--)
				vputp(SR, 1);	/* should do @'s */
			vputp(tgoto(xCS, TLINES-1,0), 1);
			vputp(RC, 1);	/* Once again put it back */
		}
		else {
			vputp(AL, WECHO + 1 - p);
			for (i = cnt - 1; i > 0; i--) {
				vgoto(outline+1, 0);
				vputp(AL, WECHO + 1 - outline);
				if ((hold & HOLDAT) == 0)
					putchar('@');
			}
		}
		vadjAL(p, cnt);
	} else
		could = 0;
	vopenup(cnt, could, l);
}
Пример #28
0
/*
 * 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.  Aescaped is the location
 * where we stick a termination indicator (whether we
 * ended with an ESCAPE or a newline/return.
 *
 * We do erase-kill type processing here and also
 * are careful about the way we do this so that it is
 * repeatable.  (I.e. so that your kill doesn't happen,
 * when you repeat an insert if it was escaped with \ the
 * first time you did it.  commch is the command character
 * involved, including the prompt for readline.
 */
char *
vgetline(int cnt, char *gcursor, bool *aescaped, int commch)
{
	register int c, ch;
	register char *cp;
	int x, y, iwhite, backsl=0;
	cell *iglobp;
	char cstr[2];
	int (*OO)(int) = Outchar;

	/*
	 * Clear the output state and counters
	 * for autoindent backwards motion (counts of ^D, etc.)
	 * Remember how much white space at beginning of line so
	 * as not to allow backspace over autoindent.
	 */
	*aescaped = 0;
	ogcursor = gcursor;
	flusho();
	CDCNT = 0;
	HADUP = 0;
	HADZERO = 0;
	gobbled = 0;
	iwhite = whitecnt(genbuf);
	iglobp = vglobp;

	/*
	 * Carefully avoid using vinschar in the echo area.
	 */
	if (splitw)
		Outchar = vputchar;
	else {
		Outchar = vinschar;
		vprepins();
	}
	for (;;) {
		backsl = 0;
		if (gobblebl)
			gobblebl--;
		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 (!value(REMAP))
					break;
				if (++maphopcnt > 256)
					error(catgets(catd, 1, 234,
						"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 == tty.c_cc[VERASE])
				c = CTRL('h');
			else if (c == tty.c_cc[VKILL])
				c = -1;
			if (c == ATTN)
				goto case_ATTN;
			switch (c) {

			/*
			 * ^?		Interrupt drops you back to visual
			 *		command mode with an unread interrupt
			 *		still in the input buffer.
			 *
			 * ^\		Quit does the same as interrupt.
			 *		If you are a ex command rather than
			 *		a vi command this will drop you
			 *		back to command mode for sure.
			 */
			case QUIT:
case_ATTN:
				ungetkey(c);
				goto vadone;

			/*
			 * ^H		Backs up a character in the input.
			 *
			 * BUG:		Can't back around line boundaries.
			 *		This is hard because stuff has
			 *		already been saved for repeat.
			 */
			case CTRL('h'):
bakchar:
				cp = gcursor + skipleft(ogcursor, gcursor);
				if (cp < ogcursor) {
					if (splitw) {
						/*
						 * Backspacing over readecho
						 * prompt. Pretend delete but
						 * don't beep.
						 */
						ungetkey(c);
						goto vadone;
					}
					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]&0377); 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
			 *		the autoindent.
			 */
			case -1:
				cp = ogcursor;
vbackup:
				if (cp == gcursor) {
					beep();
					continue;
				}
				endim();
				*cp = 0;
				c = cindent();
				vgotoCL(qcolumn(cursor +
					skipleft(linebuf, cursor), genbuf));
				if (doomed >= 0)
					doomed += c - cindent();
				gcursor = cp;
				continue;

			/*
			 * \		Followed by erase or kill
			 *		maps to just the erase or kill.
			 */
			case '\\':
				x = destcol, y = destline;
				putchar('\\');
				vcsync();
				c = getkey();
				if (c == tty.c_cc[VERASE]
				    || c == tty.c_cc[VKILL])
				{
					vgoto(y, x);
					if (doomed >= 0)
						doomed++;
					goto def;
				}
				ungetkey(c), c = '\\';
				backsl = 1;
				break;

			/*
			 * ^Q		Super quote following character
			 *		Only ^@ is verboten (trapped at
			 *		a lower level) and \n forces a line
			 *		split so doesn't really go in.
			 *
			 * ^V		Synonym for ^Q
			 */
			case CTRL('q'):
			case CTRL('v'):
				x = destcol, y = destline;
				putchar('^');
				vgoto(y, x);
				c = getkey();
				if (c != NL) {
					if (doomed >= 0)
						doomed++;
					goto def;
				}
				break;
			}
		}

		/*
		 * If we get a blank not in the echo area
		 * consider splitting the window in the wrapmargin.
		 */
		if (c != NL && !splitw) {
			if (c == ' ' && gobblebl) {
				gobbled = 1;
				continue;
			}
			if (value(WRAPMARGIN) &&
				(outcol >= OCOLUMNS - value(WRAPMARGIN) ||
				 (backsl && outcol == 0)) &&
				commch != 'r') {
				/*
				 * At end of word and hit wrapmargin.
				 * Move the word to next line and keep going.
				 */
				wdkind = 1;
				gappend(c);
				if (backsl)
					gappend(getkey());
				*gcursor = 0;
				/*
				 * Find end of previous word if we are past it.
				 */
				for (cp=gcursor; cp>ogcursor
						&& isspace(cp[-1]&0377); cp--)
					;
				if (outcol+(backsl?OCOLUMNS:0) - (gcursor-cp) >= OCOLUMNS - value(WRAPMARGIN)) {
					/*
					 * Find beginning of previous word.
					 */
					for (; cp>ogcursor && !isspace(cp[-1]&0377); cp--)
						;
					if (cp <= ogcursor) {
						/*
						 * There is a single word that
						 * is too long to fit.  Just
						 * let it pass, but beep for
						 * each new letter to warn
						 * the luser.
						 */
						c = *--gcursor;
						*gcursor = 0;
						beep();
						goto dontbreak;
					}
					/*
					 * Save it for next line.
					 */
					macpush(cp, 0);
					cp--;
				}
				macpush("\n", 0);
				/*
				 * Erase white space before the word.
				 */
				while (cp > ogcursor && isspace(cp[-1]&0377))
					cp--;	/* skip blank */
				gobblebl = 3;
				goto vbackup;
			}
		dontbreak:;
		}

		/*
		 * Word abbreviation mode.
		 */
		cstr[0] = c;
		if (anyabbrs && gcursor > ogcursor && !wordch(cstr) && wordch(gcursor-1)) {
				int wdtype, abno;

				cstr[1] = 0;
				wdkind = 1;
				cp = gcursor + skipleft(ogcursor, gcursor);
				for (wdtype = wordch(cp - 1);
				    cp > ogcursor && wordof(wdtype, cp - 1); cp--)
					;
				*gcursor = 0;
				for (abno=0; abbrevs[abno].mapto; abno++) {
					if (!abbrevs[abno].hadthis &&
						eq(cp, abbrevs[abno].cap)) {
						abbrevs[abno].hadthis++;
						macpush(cstr, 0);
						macpush(abbrevs[abno].mapto, 0);
						goto vbackup;
					}
				}
		}

#ifdef	BIT8
		if (c == OVERBUF)
			goto btrp;
#endif
		switch (c) {

		/*
		 * ^M		Except in repeat maps to \n.
		 */
		case CR:
			if (vglobp)
				goto def;
			c = '\n';
			/* presto chango ... */

		/*
		 * \n		Start new line.
		 */
		case NL:
			*aescaped = c;
			goto vadone;

		/*
		 * escape	End insert unless repeat and more to repeat.
		 */
		case ESCAPE:
			if (lastvgk)
				goto def;
			goto vadone;

		/*
		 * ^D		Backtab.
		 * ^T		Software forward tab.
		 *
		 *		Unless in repeat where this means these
		 *		were superquoted in.
		 */
		case CTRL('d'):
		case CTRL('t'):
			if (vglobp)
				goto def;
			/* fall into ... */

		/*
		 * ^D|QUOTE	Is a backtab (in a repeated command).
		 */
#ifndef	BIT8
		case CTRL('d') | QUOTE:
#else
btrp:
#endif
			*gcursor = 0;
			cp = vpastwh(genbuf);
			c = whitecnt(genbuf);
			if (ch == CTRL('t')) {
				/*
				 * ^t just generates new indent replacing
				 * current white space rounded up to soft
				 * tab stop increment.
				 */
				if (cp != gcursor)
					/*
					 * BUG:		Don't hack ^T except
					 *		right after initial
					 *		white space.
					 */
					continue;
				cp = genindent(iwhite = backtab(c + value(SHIFTWIDTH) + 1));
				ogcursor = cp;
				goto vbackup;
			}
			/*
			 * ^D works only if we are at the (end of) the
			 * generated autoindent.  We count the ^D for repeat
			 * purposes.
			 */
			if (c == iwhite && c != 0) {
				if (cp == gcursor) {
					iwhite = backtab(c);
					CDCNT++;
					ogcursor = cp = genindent(iwhite);
					goto vbackup;
				} else if (&cp[1] == gcursor &&
				    (*cp == '^' || *cp == '0')) {
					/*
					 * ^^D moves to margin, then back
					 * to current indent on next line.
					 *
					 * 0^D moves to margin and then
					 * stays there.
					 */
					HADZERO = *cp == '0';
					ogcursor = cp = genbuf;
					HADUP = 1 - HADZERO;
					CDCNT = 1;
					endim();
					back1();
					vputchar(' ');
					goto vbackup;
				}
			}
			if (vglobp && vglobp - iglobp >= 2 &&
			    (vglobp[-2] == '^' || vglobp[-2] == '0')
			    && gcursor == ogcursor + 1)
				goto bakchar;
			continue;

		default:
			/*
			 * Possibly discard control inputs.
			 */
			if (!vglobp && junk(c)) {
				beep();
				continue;
			}
def:
			if (!backsl) {
				/* int cnt; */
				putchar(c);
				flush();
			}
			if (gcursor > &genbuf[LBSIZE - 2])
				error(catgets(catd, 1, 235, "Line too long"));
			gappend(c & TRIM);
			vcsync();
			if (value(SHOWMATCH) && !iglobp)
				if (c == ')' || c == '}')
					lsmatch(gcursor);
			continue;
		}
	}
vadone:
	*gcursor = 0;
	if (Outchar != termchar)
		Outchar = OO;
	endim();
	return (gcursor);
}
Пример #29
0
static void
escape(void)

{

    int		ch;			/* control character */

/*
 *
 * Handles special codes that are expected to follow an escape character. The
 * initial escape character is followed by one or two bytes.
 *
 */

    switch ( ch = getc(fp_in) ) {
	case 'T':			/* top margin */
		topmargin = vpos;
		break;

	case 'L':			/* bottom margin */
		bottommargin = vpos;
		break;

	case 'C':			/* clear top and bottom margins */
		bottommargin = BOTTOMMARGIN;
		topmargin = TOPMARGIN;
		break;

	case '9':			/* left margin */
		leftmargin = hpos;
		break;

	case '0':			/* right margin */
		rightmargin = hpos;
		break;

	case '1':			/* set horizontal tab */
		htabstops[hpos/ohmi] = ON;
		break;

	case '8':			/* clear horizontal tab at hpos */
		htabstops[hpos/ohmi] = OFF;
		break;

	case '-':			/* set vertical tab */
		vtabstops[vpos/ovmi] = ON;
		break;

	case '2':			/* clear all tabs */
		cleartabs();
		break;

	case '\014':			/* set lines per page */
		linespp = getc(fp_in);
		break;

	case '\037':			/* set hmi to next byte minus 1 */
		hmi = HSCALE * (getc(fp_in) - 1);
		break;

	case 'S':			/* reset hmi to default */
		hmi = ohmi;
		break;

	case '\011':			/* move to column given by next byte */
		hgoto((getc(fp_in)-1) * ohmi);
		break;

	case '?':			/* do carriage return after line feed */
		lfiscr = ON;
		break;

	case '!':			/* don't generate carriage return */
		lfiscr = OFF;
		break;

	case '5':			/* forward print mode */
		advance = 1;
		break;

	case '6':			/* backward print mode */
		advance = -1;
		break;

	case '\036':			/* set vmi to next byte minus 1 */
		vmi = VSCALE * (getc(fp_in) - 1);
		break;

	case '\013':			/* move to line given by next byte */
		vgoto((getc(fp_in)-1) * ovmi);
		break;

	case 'U':			/* positive half line feed */
		vmot(vmi/2);
		break;

	case 'D':			/* negative half line feed */
		vmot(-vmi/2);
		break;

	case '\012':			/* negative line feed */
		vmot(-vmi);
		break;

	case '\015':			/* clear all margins */
		bottommargin = BOTTOMMARGIN;
		topmargin = TOPMARGIN;
		leftmargin = BOTTOMMARGIN;
		rightmargin = RIGHTMARGIN;
		break;

	case 'E':			/* auto underscore - use italic font */
		changefont("/Courier-Oblique");
		break;

	case 'R':			/* disable auto underscore */
		changefont(fontname);
		break;

	case 'O':			/* bold/shadow printing */
	case 'W':
		changefont("/Courier-Bold");
		shadowprint = ON;
		break;

	case '&':			/* disable bold printing */
		changefont(fontname);
		shadowprint = OFF;
		break;

	case '/':			/* ignored 2 byte escapes */
	case '\\':
	case '<':
	case '>':
	case '%':
	case '=':
	case '.':
	case '4':
	case 'A':
	case 'B':
	case 'M':
	case 'N':
	case 'P':
	case 'Q':
	case 'X':
	case '\010':
		break;

	case ',':			/* ignored 3 byte escapes */
	case '\016':
	case '\021':
		getc(fp_in);
		break;

	case '3':			/* graphics mode - should quit! */
	case '7':
	case 'G':
	case 'V':
	case 'Y':
	case 'Z':
		error(FATAL, "graphics mode is not implemented");
		break;

	default:
		error(FATAL, "missing case for escape o%o\n", ch);
		break;
    }	/* End switch */

}   /* End of escape */
Пример #30
0
void
conv(Biobuf *Bp) {
	long n;
	int r;
	char special[10];
	int save;

	inputlineno = 1;
	if (debug) Bprint(Bstderr, "conv(Biobufhdr *Bp=0x%x)\n", Bp);
	while ((r = Bgetrune(Bp)) >= 0) {
/* Bprint(Bstderr, "r=<%c>,0x%x\n", r, r); */
/*		Bflush(Bstderr); */
		switch (r) {
		case 's':	/* set point size */
			Bgetfield(Bp, 'd', &fontsize, 0);
			break;
		case 'f':	/* set font to postion */
			Bgetfield(Bp, 'd', &fontpos, 0);
			save = inputlineno;
			settrfont();
			inputlineno = save;	/* ugh */
			break;
		case 'c':	/* print rune */
			r = Bgetrune(Bp);
			runeout(r);
			break;
		case 'C':	/* print special character */
			Bgetfield(Bp, 's', special, 10);
			specialout(special);
			break;
		case 'N':	/* print character with numeric value from current font */
			Bgetfield(Bp, 'd', &n, 0);
			break;
		case 'H':	/* go to absolute horizontal position */
			Bgetfield(Bp, 'd', &n, 0);
			hgoto(n);
			break;
		case 'V':	/* go to absolute vertical position */
			Bgetfield(Bp, 'd', &n, 0);
			vgoto(n);
			break;
		case 'h':	/* go to relative horizontal position */
			Bgetfield(Bp, 'd', &n, 0);
			hmot(n);
			break;
		case 'v':	/* go to relative vertical position */
			Bgetfield(Bp, 'd', &n, 0);
			vmot(n);
			break;
		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
				/* move right nn units, then print character c */
			n = (r - '0') * 10;
			r = Bgetrune(Bp);
			if (r < 0)
				error(FATAL, "EOF or error reading input\n");
			else if (r < '0' || r > '9')
				error(FATAL, "integer expected\n");
			n += r - '0';
			r = Bgetrune(Bp);
			hmot(n);
			runeout(r);
			break;
		case 'p':	/* begin page */
			Bgetfield(Bp, 'd', &n, 0);
			endpage();
			startpage();
			break;
		case 'n':	/* end of line (information only 'b a' follows) */
			Brdline(Bp, '\n');	/* toss rest of line */
			inputlineno++;
			break;
		case 'w':	/* paddable word space (information only) */
			break;
		case 'D':	/* graphics function */
			draw(Bp);
			break;
		case 'x':	/* device control functions */
			devcntl(Bp);
			break;
		case '#':	/* comment */
			Brdline(Bp, '\n');	/* toss rest of line */
		case '\n':
			inputlineno++;
			break;
		default:
			error(WARNING, "unknown troff function <%c>\n", r);
			break;
		}
	}
	endpage();
	if (debug) Bprint(Bstderr, "r=0x%x\n", r);
	if (debug) Bprint(Bstderr, "leaving conv\n");
}