xref: /original-bsd/usr.bin/ex/ex_cmds2.c (revision e049d966)
1cd8169f0Sbostic /*-
2*e049d966Sbostic  * Copyright (c) 1980, 1993
3*e049d966Sbostic  *	The Regents of the University of California.  All rights reserved.
4cd8169f0Sbostic  *
5cd8169f0Sbostic  * %sccs.include.proprietary.c%
69643a6a3Sdist  */
79643a6a3Sdist 
89643a6a3Sdist #ifndef lint
9*e049d966Sbostic static char sccsid[] = "@(#)ex_cmds2.c	8.1 (Berkeley) 06/09/93";
10cd8169f0Sbostic #endif /* not lint */
119643a6a3Sdist 
1292a99d14Smark #include "ex.h"
1392a99d14Smark #include "ex_argv.h"
1492a99d14Smark #include "ex_temp.h"
1592a99d14Smark #include "ex_tty.h"
1692a99d14Smark #include "ex_vis.h"
1792a99d14Smark 
18af37c860Sdist extern bool	pflag, nflag;		/* mjm: extern; also in ex_cmds.c */
19af37c860Sdist extern int	poffset;		/* mjm: extern; also in ex_cmds.c */
2092a99d14Smark 
2192a99d14Smark /*
2292a99d14Smark  * Subroutines for major command loop.
2392a99d14Smark  */
2492a99d14Smark 
2592a99d14Smark /*
2692a99d14Smark  * Is there a single letter indicating a named buffer next?
2792a99d14Smark  */
cmdreg()2892a99d14Smark cmdreg()
2992a99d14Smark {
3092a99d14Smark 	register int c = 0;
3192a99d14Smark 	register int wh = skipwh();
3292a99d14Smark 
3392a99d14Smark 	if (wh && isalpha(peekchar()))
34c0a5300eSconrad 		c = ex_getchar();
3592a99d14Smark 	return (c);
3692a99d14Smark }
3792a99d14Smark 
3892a99d14Smark /*
3992a99d14Smark  * Tell whether the character ends a command
4092a99d14Smark  */
endcmd(ch)4192a99d14Smark endcmd(ch)
4292a99d14Smark 	int ch;
4392a99d14Smark {
4492a99d14Smark 	switch (ch) {
4592a99d14Smark 
4692a99d14Smark 	case '\n':
4792a99d14Smark 	case EOF:
4892a99d14Smark 		endline = 1;
4992a99d14Smark 		return (1);
5092a99d14Smark 
5192a99d14Smark 	case '|':
520b2fc746Smark 	case '"':
5392a99d14Smark 		endline = 0;
5492a99d14Smark 		return (1);
5592a99d14Smark 	}
5692a99d14Smark 	return (0);
5792a99d14Smark }
5892a99d14Smark 
5992a99d14Smark /*
6092a99d14Smark  * Insist on the end of the command.
6192a99d14Smark  */
eol()6292a99d14Smark eol()
6392a99d14Smark {
6492a99d14Smark 
6592a99d14Smark 	if (!skipend())
6692a99d14Smark 		error("Extra chars|Extra characters at end of command");
6792a99d14Smark 	ignnEOF();
6892a99d14Smark }
6992a99d14Smark 
7092a99d14Smark /*
7192a99d14Smark  * Print out the message in the error message file at str,
7292a99d14Smark  * with i an integer argument to printf.
7392a99d14Smark  */
7492a99d14Smark /*VARARGS2*/
error(str,i)7592a99d14Smark error(str, i)
76c0a5300eSconrad #ifndef EXSTRINGS
77c0a5300eSconrad 	char *str;
7892a99d14Smark #else
79c0a5300eSconrad # ifdef lint
80c0a5300eSconrad 	char *str;
81c0a5300eSconrad # else
82c0a5300eSconrad 	int str;
83c0a5300eSconrad # endif
8492a99d14Smark #endif
8592a99d14Smark 	int i;
8692a99d14Smark {
8792a99d14Smark 
8892a99d14Smark 	error0();
8992a99d14Smark 	merror(str, i);
90af37c860Sdist 	if (writing) {
91af37c860Sdist 		serror(" [Warning - %s is incomplete]", file);
92af37c860Sdist 		writing = 0;
93af37c860Sdist 	}
9492a99d14Smark 	error1(str);
9592a99d14Smark }
9692a99d14Smark 
9792a99d14Smark /*
9892a99d14Smark  * Rewind the argument list.
9992a99d14Smark  */
erewind()10092a99d14Smark erewind()
10192a99d14Smark {
10292a99d14Smark 
10392a99d14Smark 	argc = argc0;
10492a99d14Smark 	argv = argv0;
10592a99d14Smark 	args = args0;
10692a99d14Smark 	if (argc > 1 && !hush) {
107c0a5300eSconrad 		ex_printf(mesg("%d files@to edit"), argc);
10892a99d14Smark 		if (inopen)
109c0a5300eSconrad 			ex_putchar(' ');
11092a99d14Smark 		else
11192a99d14Smark 			putNFL();
11292a99d14Smark 	}
11392a99d14Smark }
11492a99d14Smark 
11592a99d14Smark /*
11692a99d14Smark  * Guts of the pre-printing error processing.
11792a99d14Smark  * If in visual and catching errors, then we dont mung up the internals,
11892a99d14Smark  * just fixing up the echo area for the print.
11992a99d14Smark  * Otherwise we reset a number of externals, and discard unused input.
12092a99d14Smark  */
error0()12192a99d14Smark error0()
12292a99d14Smark {
12392a99d14Smark 
12492a99d14Smark 	if (vcatch) {
12592a99d14Smark 		if (splitw == 0)
12692a99d14Smark 			fixech();
12792a99d14Smark 		if (!SO || !SE)
12892a99d14Smark 			dingdong();
12992a99d14Smark 		return;
13092a99d14Smark 	}
13192a99d14Smark 	if (input) {
13292a99d14Smark 		input = strend(input) - 1;
13392a99d14Smark 		if (*input == '\n')
13492a99d14Smark 			setlastchar('\n');
13592a99d14Smark 		input = 0;
13692a99d14Smark 	}
13792a99d14Smark 	setoutt();
13892a99d14Smark 	flush();
13992a99d14Smark 	resetflav();
14092a99d14Smark 	if (!SO || !SE)
14192a99d14Smark 		dingdong();
14292a99d14Smark 	if (inopen) {
14392a99d14Smark 		/*
14492a99d14Smark 		 * We are coming out of open/visual ungracefully.
14592a99d14Smark 		 * Restore COLUMNS, undo, and fix tty mode.
14692a99d14Smark 		 */
14792a99d14Smark 		COLUMNS = OCOLUMNS;
14892a99d14Smark 		undvis();
14992a99d14Smark 		ostop(normf);
1500b2fc746Smark 		/* ostop should be doing this
15192a99d14Smark 		putpad(VE);
15292a99d14Smark 		putpad(KE);
1530b2fc746Smark 		*/
15492a99d14Smark 		putnl();
15592a99d14Smark 	}
15692a99d14Smark 	inopen = 0;
15792a99d14Smark 	holdcm = 0;
15892a99d14Smark }
15992a99d14Smark 
16092a99d14Smark /*
16192a99d14Smark  * Post error printing processing.
16292a99d14Smark  * Close the i/o file if left open.
16392a99d14Smark  * If catching in visual then throw to the visual catch,
16492a99d14Smark  * else if a child after a fork, then exit.
16592a99d14Smark  * Otherwise, in the normal command mode error case,
16692a99d14Smark  * finish state reset, and throw to top.
16792a99d14Smark  */
error1(str)16892a99d14Smark error1(str)
16992a99d14Smark 	char *str;
17092a99d14Smark {
17192a99d14Smark 	bool die;
17292a99d14Smark 
17392a99d14Smark 	if (io > 0) {
17492a99d14Smark 		close(io);
17592a99d14Smark 		io = -1;
17692a99d14Smark 	}
17792a99d14Smark 	die = (getpid() != ppid);	/* Only children die */
1780b2fc746Smark 	inappend = inglobal = 0;
1793ea65064Smark 	globp = vglobp = vmacp = 0;
1803ea65064Smark 	if (vcatch && !die) {
18192a99d14Smark 		inopen = 1;
18292a99d14Smark 		vcatch = 0;
1833ea65064Smark 		if (str)
1843ea65064Smark 			noonl();
18592a99d14Smark 		fixol();
18692a99d14Smark 		longjmp(vreslab,1);
18792a99d14Smark 	}
18892a99d14Smark 	if (str && !vcatch)
18992a99d14Smark 		putNFL();
19092a99d14Smark 	if (die)
191c0a5300eSconrad 		ex_exit(1);
19292a99d14Smark 	lseek(0, 0L, 2);
19392a99d14Smark 	if (inglobal)
19492a99d14Smark 		setlastchar('\n');
19592a99d14Smark 	while (lastchar() != '\n' && lastchar() != EOF)
19692a99d14Smark 		ignchar();
19792a99d14Smark 	ungetchar(0);
19892a99d14Smark 	endline = 1;
19992a99d14Smark 	reset();
20092a99d14Smark }
20192a99d14Smark 
fixol()20292a99d14Smark fixol()
20392a99d14Smark {
20492a99d14Smark 	if (Outchar != vputchar) {
20592a99d14Smark 		flush();
20692a99d14Smark 		if (state == ONEOPEN || state == HARDOPEN)
20792a99d14Smark 			outline = destline = 0;
20892a99d14Smark 		Outchar = vputchar;
20992a99d14Smark 		vcontin(1);
21092a99d14Smark 	} else {
21192a99d14Smark 		if (destcol)
21292a99d14Smark 			vclreol();
21392a99d14Smark 		vclean();
21492a99d14Smark 	}
21592a99d14Smark }
21692a99d14Smark 
21792a99d14Smark /*
21892a99d14Smark  * Does an ! character follow in the command stream?
21992a99d14Smark  */
exclam()22092a99d14Smark exclam()
22192a99d14Smark {
22292a99d14Smark 
22392a99d14Smark 	if (peekchar() == '!') {
22492a99d14Smark 		ignchar();
22592a99d14Smark 		return (1);
22692a99d14Smark 	}
22792a99d14Smark 	return (0);
22892a99d14Smark }
22992a99d14Smark 
23092a99d14Smark /*
23192a99d14Smark  * Make an argument list for e.g. next.
23292a99d14Smark  */
makargs()23392a99d14Smark makargs()
23492a99d14Smark {
23592a99d14Smark 
23692a99d14Smark 	glob(&frob);
23792a99d14Smark 	argc0 = frob.argc0;
23892a99d14Smark 	argv0 = frob.argv;
23992a99d14Smark 	args0 = argv0[0];
24092a99d14Smark 	erewind();
24192a99d14Smark }
24292a99d14Smark 
24392a99d14Smark /*
24492a99d14Smark  * Advance to next file in argument list.
24592a99d14Smark  */
next()24692a99d14Smark next()
24792a99d14Smark {
2480b2fc746Smark 	extern short isalt;	/* defined in ex_io.c */
24992a99d14Smark 
25092a99d14Smark 	if (argc == 0)
25192a99d14Smark 		error("No more files@to edit");
25292a99d14Smark 	morargc = argc;
2530b2fc746Smark 	isalt = (strcmp(altfile, args)==0) + 1;
25492a99d14Smark 	if (savedfile[0])
25592a99d14Smark 		CP(altfile, savedfile);
25692a99d14Smark 	CP(savedfile, args);
25792a99d14Smark 	argc--;
25892a99d14Smark 	args = argv ? *++argv : strend(args) + 1;
25992a99d14Smark }
26092a99d14Smark 
26192a99d14Smark /*
26292a99d14Smark  * Eat trailing flags and offsets after a command,
26392a99d14Smark  * saving for possible later post-command prints.
26492a99d14Smark  */
newline()26592a99d14Smark newline()
26692a99d14Smark {
26792a99d14Smark 	register int c;
26892a99d14Smark 
26992a99d14Smark 	resetflav();
27092a99d14Smark 	for (;;) {
271c0a5300eSconrad 		c = ex_getchar();
27292a99d14Smark 		switch (c) {
27392a99d14Smark 
27492a99d14Smark 		case '^':
27592a99d14Smark 		case '-':
27692a99d14Smark 			poffset--;
27792a99d14Smark 			break;
27892a99d14Smark 
27992a99d14Smark 		case '+':
28092a99d14Smark 			poffset++;
28192a99d14Smark 			break;
28292a99d14Smark 
28392a99d14Smark 		case 'l':
28492a99d14Smark 			listf++;
28592a99d14Smark 			break;
28692a99d14Smark 
28792a99d14Smark 		case '#':
28892a99d14Smark 			nflag++;
28992a99d14Smark 			break;
29092a99d14Smark 
29192a99d14Smark 		case 'p':
29292a99d14Smark 			listf = 0;
29392a99d14Smark 			break;
29492a99d14Smark 
29592a99d14Smark 		case ' ':
29692a99d14Smark 		case '\t':
29792a99d14Smark 			continue;
29892a99d14Smark 
2990b2fc746Smark 		case '"':
3000b2fc746Smark 			comment();
3010b2fc746Smark 			setflav();
3020b2fc746Smark 			return;
3030b2fc746Smark 
30492a99d14Smark 		default:
30592a99d14Smark 			if (!endcmd(c))
30692a99d14Smark serror("Extra chars|Extra characters at end of \"%s\" command", Command);
30792a99d14Smark 			if (c == EOF)
30892a99d14Smark 				ungetchar(c);
30992a99d14Smark 			setflav();
31092a99d14Smark 			return;
31192a99d14Smark 		}
31292a99d14Smark 		pflag++;
31392a99d14Smark 	}
31492a99d14Smark }
31592a99d14Smark 
31692a99d14Smark /*
31792a99d14Smark  * Before quit or respec of arg list, check that there are
31892a99d14Smark  * no more files in the arg list.
31992a99d14Smark  */
nomore()32092a99d14Smark nomore()
32192a99d14Smark {
32292a99d14Smark 
32392a99d14Smark 	if (argc == 0 || morargc == argc)
32492a99d14Smark 		return;
32592a99d14Smark 	morargc = argc;
32692a99d14Smark 	merror("%d more file", argc);
32792a99d14Smark 	serror("%s@to edit", plural((long) argc));
32892a99d14Smark }
32992a99d14Smark 
33092a99d14Smark /*
33192a99d14Smark  * Before edit of new file check that either an ! follows
33292a99d14Smark  * or the file has not been changed.
33392a99d14Smark  */
quickly()33492a99d14Smark quickly()
33592a99d14Smark {
33692a99d14Smark 
33792a99d14Smark 	if (exclam())
33892a99d14Smark 		return (1);
33992a99d14Smark 	if (chng && dol > zero) {
34092a99d14Smark /*
34192a99d14Smark 		chng = 0;
34292a99d14Smark */
34392a99d14Smark 		xchng = 0;
344c0a5300eSconrad 		serror("No write@since last change (:%s! overrides)", Command);
34592a99d14Smark 	}
34692a99d14Smark 	return (0);
34792a99d14Smark }
34892a99d14Smark 
34992a99d14Smark /*
35092a99d14Smark  * Reset the flavor of the output to print mode with no numbering.
35192a99d14Smark  */
resetflav()35292a99d14Smark resetflav()
35392a99d14Smark {
35492a99d14Smark 
35592a99d14Smark 	if (inopen)
35692a99d14Smark 		return;
35792a99d14Smark 	listf = 0;
35892a99d14Smark 	nflag = 0;
35992a99d14Smark 	pflag = 0;
36092a99d14Smark 	poffset = 0;
36192a99d14Smark 	setflav();
36292a99d14Smark }
36392a99d14Smark 
36492a99d14Smark /*
36592a99d14Smark  * Print an error message with a %s type argument to printf.
36692a99d14Smark  * Message text comes from error message file.
36792a99d14Smark  */
serror(str,cp)36892a99d14Smark serror(str, cp)
36992a99d14Smark #ifdef lint
37092a99d14Smark 	register char *str;
37192a99d14Smark #else
37292a99d14Smark 	register int str;
37392a99d14Smark #endif
37492a99d14Smark 	char *cp;
37592a99d14Smark {
37692a99d14Smark 
37792a99d14Smark 	error0();
37892a99d14Smark 	smerror(str, cp);
37992a99d14Smark 	error1(str);
38092a99d14Smark }
38192a99d14Smark 
38292a99d14Smark /*
38392a99d14Smark  * Set the flavor of the output based on the flags given
38492a99d14Smark  * and the number and list options to either number or not number lines
38592a99d14Smark  * and either use normally decoded (ARPAnet standard) characters or list mode,
38692a99d14Smark  * where end of lines are marked and tabs print as ^I.
38792a99d14Smark  */
setflav()38892a99d14Smark setflav()
38992a99d14Smark {
39092a99d14Smark 
39192a99d14Smark 	if (inopen)
39292a99d14Smark 		return;
393c0a5300eSconrad 	ignorf(setnumb(nflag || value(NUMBER)));
394c0a5300eSconrad 	ignorf(setlist(listf || value(LIST)));
39592a99d14Smark 	setoutt();
39692a99d14Smark }
39792a99d14Smark 
39892a99d14Smark /*
39992a99d14Smark  * Skip white space and tell whether command ends then.
40092a99d14Smark  */
skipend()40192a99d14Smark skipend()
40292a99d14Smark {
40392a99d14Smark 
40492a99d14Smark 	pastwh();
4050b2fc746Smark 	return (endcmd(peekchar()) && peekchar() != '"');
40692a99d14Smark }
40792a99d14Smark 
40892a99d14Smark /*
40992a99d14Smark  * Set the command name for non-word commands.
41092a99d14Smark  */
tailspec(c)41192a99d14Smark tailspec(c)
41292a99d14Smark 	int c;
41392a99d14Smark {
41492a99d14Smark 	static char foocmd[2];
41592a99d14Smark 
41692a99d14Smark 	foocmd[0] = c;
41792a99d14Smark 	Command = foocmd;
41892a99d14Smark }
41992a99d14Smark 
42092a99d14Smark /*
42192a99d14Smark  * Try to read off the rest of the command word.
42292a99d14Smark  * If alphabetics follow, then this is not the command we seek.
42392a99d14Smark  */
tail(comm)42492a99d14Smark tail(comm)
42592a99d14Smark 	char *comm;
42692a99d14Smark {
42792a99d14Smark 
42892a99d14Smark 	tailprim(comm, 1, 0);
42992a99d14Smark }
43092a99d14Smark 
tail2of(comm)43192a99d14Smark tail2of(comm)
43292a99d14Smark 	char *comm;
43392a99d14Smark {
43492a99d14Smark 
43592a99d14Smark 	tailprim(comm, 2, 0);
43692a99d14Smark }
43792a99d14Smark 
43892a99d14Smark char	tcommand[20];
43992a99d14Smark 
tailprim(comm,i,notinvis)44092a99d14Smark tailprim(comm, i, notinvis)
44192a99d14Smark 	register char *comm;
44292a99d14Smark 	int i;
44392a99d14Smark 	bool notinvis;
44492a99d14Smark {
44592a99d14Smark 	register char *cp;
44692a99d14Smark 	register int c;
44792a99d14Smark 
44892a99d14Smark 	Command = comm;
44992a99d14Smark 	for (cp = tcommand; i > 0; i--)
45092a99d14Smark 		*cp++ = *comm++;
45192a99d14Smark 	while (*comm && peekchar() == *comm)
452c0a5300eSconrad 		*cp++ = ex_getchar(), comm++;
45392a99d14Smark 	c = peekchar();
45492a99d14Smark 	if (notinvis || isalpha(c)) {
45592a99d14Smark 		/*
45692a99d14Smark 		 * Of the trailing lp funny business, only dl and dp
45792a99d14Smark 		 * survive the move from ed to ex.
45892a99d14Smark 		 */
45992a99d14Smark 		if (tcommand[0] == 'd' && any(c, "lp"))
46092a99d14Smark 			goto ret;
46192a99d14Smark 		if (tcommand[0] == 's' && any(c, "gcr"))
46292a99d14Smark 			goto ret;
46392a99d14Smark 		while (cp < &tcommand[19] && isalpha(peekchar()))
464c0a5300eSconrad 			*cp++ = ex_getchar();
46592a99d14Smark 		*cp = 0;
46692a99d14Smark 		if (notinvis)
46792a99d14Smark 			serror("What?|%s: No such command from open/visual", tcommand);
46892a99d14Smark 		else
46992a99d14Smark 			serror("What?|%s: Not an editor command", tcommand);
47092a99d14Smark 	}
47192a99d14Smark ret:
47292a99d14Smark 	*cp = 0;
47392a99d14Smark }
47492a99d14Smark 
47592a99d14Smark /*
4763ea65064Smark  * Continue after a : command from open/visual.
47792a99d14Smark  */
vcontin(ask)47892a99d14Smark vcontin(ask)
47992a99d14Smark 	bool ask;
48092a99d14Smark {
48192a99d14Smark 
48292a99d14Smark 	if (vcnt > 0)
48392a99d14Smark 		vcnt = -vcnt;
48492a99d14Smark 	if (inopen) {
48592a99d14Smark 		if (state != VISUAL) {
48692a99d14Smark 			/*
4873ea65064Smark 			 * We don't know what a shell command may have left on
4883ea65064Smark 			 * the screen, so we move the cursor to the right place
4893ea65064Smark 			 * and then put out a newline.  But this makes an extra
4903ea65064Smark 			 * blank line most of the time so we only do it for :sh
4913ea65064Smark 			 * since the prompt gets left on the screen.
4923ea65064Smark 			 *
4933ea65064Smark 			 * BUG: :!echo longer than current line \\c
4943ea65064Smark 			 * will screw it up, but be reasonable!
49592a99d14Smark 			 */
4963ea65064Smark 			if (state == CRTOPEN) {
4973ea65064Smark 				termreset();
4983ea65064Smark 				vgoto(WECHO, 0);
4993ea65064Smark 			}
5003ea65064Smark 			if (!ask) {
5013ea65064Smark 				putch('\r');
5023ea65064Smark 				putch('\n');
5033ea65064Smark 			}
50492a99d14Smark 			return;
50592a99d14Smark 		}
50692a99d14Smark 		if (ask) {
50792a99d14Smark 			merror("[Hit return to continue] ");
50892a99d14Smark 			flush();
50992a99d14Smark 		}
51092a99d14Smark #ifndef CBREAK
51192a99d14Smark 		vraw();
51292a99d14Smark #endif
51392a99d14Smark 		if (ask) {
5143ea65064Smark #ifdef EATQS
51592a99d14Smark 			/*
51692a99d14Smark 			 * Gobble ^Q/^S since the tty driver should be eating
51792a99d14Smark 			 * them (as far as the user can see)
51892a99d14Smark 			 */
5192949201cSbostic 			while (peekkey() == CTRL('Q') || peekkey() == CTRL('S'))
52092a99d14Smark 				ignore(getkey());
5213ea65064Smark #endif
5223ea65064Smark 			if(getkey() == ':') {
5233ea65064Smark 				/* Ugh. Extra newlines, but no other way */
5243ea65064Smark 				putch('\n');
5253ea65064Smark 				outline = WECHO;
52692a99d14Smark 				ungetkey(':');
52792a99d14Smark 			}
5283ea65064Smark 		}
5293ea65064Smark 		vclrech(1);
530c0a5300eSconrad 		if (Peek_key != ':') {
5313ea65064Smark 			putpad(TI);
5320b2fc746Smark 			tostart();
5330b2fc746Smark 			/* replaced by ostart.
53492a99d14Smark 			putpad(VS);
53592a99d14Smark 			putpad(KS);
5360b2fc746Smark 			*/
53792a99d14Smark 		}
53892a99d14Smark 	}
5393ea65064Smark }
54092a99d14Smark 
54192a99d14Smark /*
54292a99d14Smark  * Put out a newline (before a shell escape)
54392a99d14Smark  * if in open/visual.
54492a99d14Smark  */
vnfl()54592a99d14Smark vnfl()
54692a99d14Smark {
54792a99d14Smark 
54892a99d14Smark 	if (inopen) {
54992a99d14Smark 		if (state != VISUAL && state != CRTOPEN && destline <= WECHO)
55092a99d14Smark 			vclean();
55192a99d14Smark 		else
55292a99d14Smark 			vmoveitup(1, 0);
55392a99d14Smark 		vgoto(WECHO, 0);
55492a99d14Smark 		vclrbyte(vtube[WECHO], WCOLS);
5550b2fc746Smark 		tostop();
5560b2fc746Smark 		/* replaced by the ostop above
55792a99d14Smark 		putpad(VE);
55892a99d14Smark 		putpad(KE);
5590b2fc746Smark 		*/
56092a99d14Smark 	}
56192a99d14Smark 	flush();
56292a99d14Smark }
563