xref: /onnv-gate/usr/src/cmd/vi/port/ex_cmds2.c (revision 4488:810f99638c34)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51897Scf46844  * Common Development and Distribution License (the "License").
61897Scf46844  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21802Scf46844 /*
22*4488Scf46844  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23802Scf46844  * Use is subject to license terms.
24802Scf46844  */
25802Scf46844 
260Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
270Sstevel@tonic-gate /*	  All Rights Reserved  	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include "ex.h"
350Sstevel@tonic-gate #include "ex_argv.h"
360Sstevel@tonic-gate #include "ex_temp.h"
370Sstevel@tonic-gate #include "ex_tty.h"
380Sstevel@tonic-gate #include "ex_vis.h"
39802Scf46844 #include <unistd.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate extern bool	pflag, nflag;		/* extern; also in ex_cmds.c */
420Sstevel@tonic-gate extern int	poffset;		/* extern; also in ex_cmds.c */
430Sstevel@tonic-gate extern short	slevel;			/* extern; has level of source() */
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * Subroutines for major command loop.
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Is there a single letter indicating a named buffer next?
510Sstevel@tonic-gate  */
52802Scf46844 int
cmdreg(void)53802Scf46844 cmdreg(void)
540Sstevel@tonic-gate {
55802Scf46844 	int c = 0;
56802Scf46844 	int wh = skipwh();
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #ifdef XPG4
590Sstevel@tonic-gate 	if (wh && isalpha(c = peekchar()) && isascii(c) && !isdigit(c))
600Sstevel@tonic-gate #else /* XPG4 */
610Sstevel@tonic-gate 	if (wh && isalpha(c = peekchar()) && isascii(c))
620Sstevel@tonic-gate #endif /* XPG4 */
630Sstevel@tonic-gate 		c = getchar();
640Sstevel@tonic-gate 
650Sstevel@tonic-gate #ifdef XPG4
660Sstevel@tonic-gate 	if (isdigit(c)) {
670Sstevel@tonic-gate 		c = 0;
680Sstevel@tonic-gate 	}
690Sstevel@tonic-gate #endif /* XPG4 */
700Sstevel@tonic-gate 	return (c);
710Sstevel@tonic-gate }
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * Tell whether the character ends a command
750Sstevel@tonic-gate  */
76802Scf46844 int
endcmd(int ch)77802Scf46844 endcmd(int ch)
780Sstevel@tonic-gate {
790Sstevel@tonic-gate 	switch (ch) {
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	case '\n':
820Sstevel@tonic-gate 	case EOF:
830Sstevel@tonic-gate 		endline = 1;
840Sstevel@tonic-gate 		return (1);
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	case '|':
870Sstevel@tonic-gate 	case '"':
880Sstevel@tonic-gate 		endline = 0;
890Sstevel@tonic-gate 		return (1);
900Sstevel@tonic-gate 	}
910Sstevel@tonic-gate 	return (0);
920Sstevel@tonic-gate }
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate  * Insist on the end of the command.
960Sstevel@tonic-gate  */
97802Scf46844 void
eol(void)98802Scf46844 eol(void)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	if (!skipend())
1020Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Extra chars") :
1030Sstevel@tonic-gate 			gettext("Extra characters at end of command"));
1040Sstevel@tonic-gate 	ignnEOF();
1050Sstevel@tonic-gate }
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate #ifdef XPG4
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * Print out the message in the error message file at str,
1100Sstevel@tonic-gate  * with i an integer argument to printf.
1110Sstevel@tonic-gate  */
1120Sstevel@tonic-gate /*VARARGS2*/
113802Scf46844 void
error(str,i)1140Sstevel@tonic-gate error(str, i)
115802Scf46844 	unsigned char *str;
1160Sstevel@tonic-gate 	int i;
1170Sstevel@tonic-gate {
118*4488Scf46844 	tagflg = 0;
1190Sstevel@tonic-gate 	errcnt++;
1200Sstevel@tonic-gate 	noerror(str, i);
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate /*
1240Sstevel@tonic-gate  * noerror(): like error(), but doesn't inc errcnt.
1250Sstevel@tonic-gate  * the reason why we created this routine, instead of fixing up errcnt
1260Sstevel@tonic-gate  * after error() is called, is because we will do a longjmp, and
1270Sstevel@tonic-gate  * not a return. it does other things closing file i/o, reset, etc;
1280Sstevel@tonic-gate  * so we follow those procedures.
1290Sstevel@tonic-gate  */
1300Sstevel@tonic-gate /*VARARGS2*/
131802Scf46844 void
noerror(str,i)1320Sstevel@tonic-gate noerror(str, i)
133802Scf46844 	unsigned char *str;
1340Sstevel@tonic-gate 	int i;
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	error0();
1380Sstevel@tonic-gate 	merror(str, i);
1390Sstevel@tonic-gate 	if (writing) {
140802Scf46844 		serror((unsigned char *)
141802Scf46844 		    gettext(" [Warning - %s is incomplete]"), file);
1420Sstevel@tonic-gate 		writing = 0;
1430Sstevel@tonic-gate 	}
1440Sstevel@tonic-gate 	error1(str);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate #else /* !XPG4 */
1480Sstevel@tonic-gate /*
1490Sstevel@tonic-gate  * Print out the message in the error message file at str,
1500Sstevel@tonic-gate  * with i an integer argument to printf.
1510Sstevel@tonic-gate  */
1520Sstevel@tonic-gate /*VARARGS2*/
153802Scf46844 void
error(str,i)1540Sstevel@tonic-gate error(str, i)
155802Scf46844 	unsigned char *str;
1560Sstevel@tonic-gate 	int i;
1570Sstevel@tonic-gate {
158*4488Scf46844 	tagflg = 0;
1590Sstevel@tonic-gate 	errcnt++;
1600Sstevel@tonic-gate 	error0();
1610Sstevel@tonic-gate 	merror(str, i);
1620Sstevel@tonic-gate 	if (writing) {
163802Scf46844 		serror((unsigned char *)
164802Scf46844 		    gettext(" [Warning - %s is incomplete]"), file);
1650Sstevel@tonic-gate 		writing = 0;
1660Sstevel@tonic-gate 	}
1670Sstevel@tonic-gate 	error1(str);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate #endif /* XPG4 */
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate  * Rewind the argument list.
1730Sstevel@tonic-gate  */
174802Scf46844 void
erewind(void)175802Scf46844 erewind(void)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	argc = argc0;
1790Sstevel@tonic-gate 	argv = argv0;
1800Sstevel@tonic-gate 	args = args0;
1810Sstevel@tonic-gate 	if (argc > 1 && !hush && cur_term) {
182802Scf46844 		viprintf(mesg(value(vi_TERSE) ? gettext("%d files") :
1830Sstevel@tonic-gate 			gettext("%d files to edit")), argc);
1840Sstevel@tonic-gate 		if (inopen)
1850Sstevel@tonic-gate 			putchar(' ');
1860Sstevel@tonic-gate 		else
1870Sstevel@tonic-gate 			putNFL();
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate /*
1920Sstevel@tonic-gate  * Guts of the pre-printing error processing.
1930Sstevel@tonic-gate  * If in visual and catching errors, then we don't mung up the internals,
1940Sstevel@tonic-gate  * just fixing up the echo area for the print.
1950Sstevel@tonic-gate  * Otherwise we reset a number of externals, and discard unused input.
1960Sstevel@tonic-gate  */
197802Scf46844 void
error0(void)198802Scf46844 error0(void)
1990Sstevel@tonic-gate {
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	if (laste) {
2020Sstevel@tonic-gate #ifdef VMUNIX
2030Sstevel@tonic-gate 		tlaste();
2040Sstevel@tonic-gate #endif
2050Sstevel@tonic-gate 		laste = 0;
2060Sstevel@tonic-gate 		sync();
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate 	if (vcatch) {
2090Sstevel@tonic-gate 		if (splitw == 0)
2100Sstevel@tonic-gate 			fixech();
2110Sstevel@tonic-gate 		if (!enter_standout_mode || !exit_bold)
2120Sstevel@tonic-gate 			dingdong();
2130Sstevel@tonic-gate 		return;
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 	if (input) {
2160Sstevel@tonic-gate 		input = strend(input) - 1;
2170Sstevel@tonic-gate 		if (*input == '\n')
2180Sstevel@tonic-gate 			setlastchar('\n');
2190Sstevel@tonic-gate 		input = 0;
2200Sstevel@tonic-gate 	}
2210Sstevel@tonic-gate 	setoutt();
2220Sstevel@tonic-gate 	flush();
2230Sstevel@tonic-gate 	resetflav();
2240Sstevel@tonic-gate 	if (!enter_standout_mode || !exit_bold)
2250Sstevel@tonic-gate 		dingdong();
2260Sstevel@tonic-gate 	if (inopen) {
2270Sstevel@tonic-gate 		/*
2280Sstevel@tonic-gate 		 * We are coming out of open/visual ungracefully.
2290Sstevel@tonic-gate 		 * Restore columns, undo, and fix tty mode.
2300Sstevel@tonic-gate 		 */
2310Sstevel@tonic-gate 		columns = OCOLUMNS;
2320Sstevel@tonic-gate 		undvis();
2330Sstevel@tonic-gate 		ostop(normf);
2340Sstevel@tonic-gate 		/* ostop should be doing this
2350Sstevel@tonic-gate 		putpad(cursor_normal);
2360Sstevel@tonic-gate 		putpad(key_eol);
2370Sstevel@tonic-gate 		*/
2380Sstevel@tonic-gate 		putnl();
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 	inopen = 0;
2410Sstevel@tonic-gate 	holdcm = 0;
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate /*
2450Sstevel@tonic-gate  * Post error printing processing.
2460Sstevel@tonic-gate  * Close the i/o file if left open.
2470Sstevel@tonic-gate  * If catching in visual then throw to the visual catch,
2480Sstevel@tonic-gate  * else if a child after a fork, then exit.
2490Sstevel@tonic-gate  * Otherwise, in the normal command mode error case,
2500Sstevel@tonic-gate  * finish state reset, and throw to top.
2510Sstevel@tonic-gate  */
252802Scf46844 void
error1(unsigned char * str)253802Scf46844 error1(unsigned char *str)
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate 	bool die;
2560Sstevel@tonic-gate 	extern short ttyindes;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	if ((io > 0) && (io != ttyindes)) {
2590Sstevel@tonic-gate 		close(io);
2600Sstevel@tonic-gate 		io = -1;
2610Sstevel@tonic-gate 	}
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	die = (getpid() != ppid);	/* Only children die */
2640Sstevel@tonic-gate 	inappend = inglobal = 0;
2650Sstevel@tonic-gate 	globp = vglobp = vmacp = 0;
2660Sstevel@tonic-gate 	if (vcatch && !die) {
2670Sstevel@tonic-gate 		inopen = 1;
2680Sstevel@tonic-gate 		vcatch = 0;
2690Sstevel@tonic-gate 		if (str)
2700Sstevel@tonic-gate 			noonl();
2710Sstevel@tonic-gate 		fixol();
2720Sstevel@tonic-gate 		if (slevel > 0)
2730Sstevel@tonic-gate 			reset();
2740Sstevel@tonic-gate 		longjmp(vreslab,1);
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 	if (str && !vcatch)
2770Sstevel@tonic-gate 		putNFL();
2780Sstevel@tonic-gate 	if (die)
2790Sstevel@tonic-gate 		exit(++errcnt);
2800Sstevel@tonic-gate 	lseek(0, 0L, 2);
2810Sstevel@tonic-gate 	if (inglobal)
2820Sstevel@tonic-gate 		setlastchar('\n');
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	if (inexrc) {
2851897Scf46844 		/*
2861897Scf46844 		 * Set inexrc to 0 so that this error is printed only
2871897Scf46844 		 * once (eg. when stdin is redirected from /dev/null and
2881897Scf46844 		 * vi prints "Input read error" because it is unable to
2891897Scf46844 		 * read() the <CR>).
2901897Scf46844 		 */
2911897Scf46844 		inexrc = 0;
2921897Scf46844 		lprintf(gettext(
2931897Scf46844 		    "Error detected in .exrc.[Hit return to continue] "),
2941897Scf46844 		    0);
2951897Scf46844 		putNFL();
2961897Scf46844 		getkey();
2970Sstevel@tonic-gate 	}
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	while ((lastchar() != '\n') && (lastchar() != EOF))
3000Sstevel@tonic-gate 		ignchar();
3010Sstevel@tonic-gate 	ungetchar(0);
3020Sstevel@tonic-gate 	endline = 1;
3030Sstevel@tonic-gate 	reset();
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate 
306802Scf46844 void
fixol(void)307802Scf46844 fixol(void)
3080Sstevel@tonic-gate {
3090Sstevel@tonic-gate 	if (Outchar != vputchar) {
3100Sstevel@tonic-gate 		flush();
3110Sstevel@tonic-gate 		if (state == ONEOPEN || state == HARDOPEN)
3120Sstevel@tonic-gate 			outline = destline = 0;
3130Sstevel@tonic-gate 		Outchar = vputchar;
3140Sstevel@tonic-gate 		vcontin(1);
3150Sstevel@tonic-gate 		/*
3160Sstevel@tonic-gate 		 * Outchar could be set to termchar() through vcontin().
3170Sstevel@tonic-gate 		 * So reset it again.
3180Sstevel@tonic-gate 		 */
3190Sstevel@tonic-gate 		Outchar = vputchar;
3200Sstevel@tonic-gate 	} else {
3210Sstevel@tonic-gate 		if (destcol)
3220Sstevel@tonic-gate 			vclreol();
3230Sstevel@tonic-gate 		vclean();
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate /*
3280Sstevel@tonic-gate  * Does an ! character follow in the command stream?
3290Sstevel@tonic-gate  */
330802Scf46844 int
exclam(void)331802Scf46844 exclam(void)
3320Sstevel@tonic-gate {
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	if (peekchar() == '!') {
3350Sstevel@tonic-gate 		ignchar();
3360Sstevel@tonic-gate 		return (1);
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate 	return (0);
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate /*
3420Sstevel@tonic-gate  * Make an argument list for e.g. next.
3430Sstevel@tonic-gate  */
344802Scf46844 void
makargs(void)345802Scf46844 makargs(void)
3460Sstevel@tonic-gate {
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	glob(&frob);
3490Sstevel@tonic-gate 	argc0 = frob.argc0;
3500Sstevel@tonic-gate 	argv0 = frob.argv;
3510Sstevel@tonic-gate 	args0 = argv0[0];
3520Sstevel@tonic-gate 	erewind();
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate /*
3560Sstevel@tonic-gate  * Advance to next file in argument list.
3570Sstevel@tonic-gate  */
358802Scf46844 void
next(void)359802Scf46844 next(void)
3600Sstevel@tonic-gate {
3610Sstevel@tonic-gate 	extern short isalt;	/* defined in ex_io.c */
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	if (argc == 0)
364802Scf46844 		error(value(vi_TERSE) ?
365802Scf46844 			(unsigned char *)gettext("No more files") :
366802Scf46844 			(unsigned char *)gettext("No more files to edit"));
3670Sstevel@tonic-gate 	morargc = argc;
3680Sstevel@tonic-gate 	isalt = (strcmp(altfile, args)==0) + 1;
3690Sstevel@tonic-gate 	if (savedfile[0])
3700Sstevel@tonic-gate 		CP(altfile, savedfile);
3710Sstevel@tonic-gate 	(void) strlcpy(savedfile, args, sizeof (savedfile));
3720Sstevel@tonic-gate 	argc--;
3730Sstevel@tonic-gate 	args = argv ? *++argv : strend(args) + 1;
3740Sstevel@tonic-gate #if i386 || i286
3750Sstevel@tonic-gate 	destcol = 0;
3760Sstevel@tonic-gate #endif
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate  * Eat trailing flags and offsets after a command,
3810Sstevel@tonic-gate  * saving for possible later post-command prints.
3820Sstevel@tonic-gate  */
383802Scf46844 void
donewline(void)384802Scf46844 donewline(void)
3850Sstevel@tonic-gate {
386802Scf46844 	int c;
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	resetflav();
3890Sstevel@tonic-gate 	for (;;) {
3900Sstevel@tonic-gate 		c = getchar();
3910Sstevel@tonic-gate 		switch (c) {
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 		case '^':
3940Sstevel@tonic-gate 		case '-':
3950Sstevel@tonic-gate 			poffset--;
3960Sstevel@tonic-gate 			break;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 		case '+':
3990Sstevel@tonic-gate 			poffset++;
4000Sstevel@tonic-gate 			break;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 		case 'l':
4030Sstevel@tonic-gate 			listf++;
4040Sstevel@tonic-gate 			break;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 		case '#':
4070Sstevel@tonic-gate 			nflag++;
4080Sstevel@tonic-gate 			break;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 		case 'p':
4110Sstevel@tonic-gate 			listf = 0;
4120Sstevel@tonic-gate 			break;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 		case ' ':
4150Sstevel@tonic-gate 		case '\t':
4160Sstevel@tonic-gate 			continue;
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 		case '"':
4190Sstevel@tonic-gate 			comment();
4200Sstevel@tonic-gate 			setflav();
4210Sstevel@tonic-gate 			return;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 		default:
4240Sstevel@tonic-gate 			if (!endcmd(c))
425802Scf46844 			    serror(value(vi_TERSE) ?
426802Scf46844 				(unsigned char *)gettext("Extra chars") :
427802Scf46844 				(unsigned char *)gettext(
428802Scf46844 				"Extra characters at end of \"%s\" command"),
429802Scf46844 				    Command);
4300Sstevel@tonic-gate 			if (c == EOF)
4310Sstevel@tonic-gate 				ungetchar(c);
4320Sstevel@tonic-gate 			setflav();
4330Sstevel@tonic-gate 			return;
4340Sstevel@tonic-gate 		}
4350Sstevel@tonic-gate 		pflag++;
4360Sstevel@tonic-gate 	}
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate /*
4400Sstevel@tonic-gate  * Before quit or respec of arg list, check that there are
4410Sstevel@tonic-gate  * no more files in the arg list.
4420Sstevel@tonic-gate  */
443802Scf46844 int
nomore(void)444802Scf46844 nomore(void)
4450Sstevel@tonic-gate {
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	if (argc == 0 || morargc == argc)
4480Sstevel@tonic-gate 		return(0);
4490Sstevel@tonic-gate 	morargc = argc;
4500Sstevel@tonic-gate 	if (argc == 1) {
4510Sstevel@tonic-gate 		merror(value(vi_TERSE) ? gettext("1 more file") :
4520Sstevel@tonic-gate 		       gettext("1 more file to edit"), argc);
4530Sstevel@tonic-gate 	} else {
4540Sstevel@tonic-gate 		merror(value(vi_TERSE) ? gettext("%d more files") :
4550Sstevel@tonic-gate 			gettext("%d more files to edit"), argc);
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate 	return(1);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate /*
4610Sstevel@tonic-gate  * Before edit of new file check that either an ! follows
4620Sstevel@tonic-gate  * or the file has not been changed.
4630Sstevel@tonic-gate  */
464802Scf46844 int
quickly(void)465802Scf46844 quickly(void)
4660Sstevel@tonic-gate {
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	if (exclam())
4690Sstevel@tonic-gate 		return (1);
4700Sstevel@tonic-gate 	if (chng && dol > zero) {
4710Sstevel@tonic-gate /*
4720Sstevel@tonic-gate 		chng = 0;
4730Sstevel@tonic-gate */
4740Sstevel@tonic-gate 		xchng = 0;
475802Scf46844 		error(value(vi_TERSE) ? (unsigned char *)gettext("No write") :
476802Scf46844 		    (unsigned char *)
477802Scf46844 		    gettext("No write since last change (:%s! overrides)"),
478802Scf46844 		    Command);
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 	return (0);
4810Sstevel@tonic-gate }
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate /*
4840Sstevel@tonic-gate  * Reset the flavor of the output to print mode with no numbering.
4850Sstevel@tonic-gate  */
486802Scf46844 void
resetflav(void)487802Scf46844 resetflav(void)
4880Sstevel@tonic-gate {
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	if (inopen)
4910Sstevel@tonic-gate 		return;
4920Sstevel@tonic-gate 	listf = 0;
4930Sstevel@tonic-gate 	nflag = 0;
4940Sstevel@tonic-gate 	pflag = 0;
4950Sstevel@tonic-gate 	poffset = 0;
4960Sstevel@tonic-gate 	setflav();
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate /*
5000Sstevel@tonic-gate  * Print an error message with a %s type argument to printf.
5010Sstevel@tonic-gate  * Message text comes from error message file.
5020Sstevel@tonic-gate  */
503802Scf46844 void
serror(unsigned char * str,unsigned char * cp)504802Scf46844 serror(unsigned char *str, unsigned char *cp)
5050Sstevel@tonic-gate {
506*4488Scf46844 	tagflg = 0;
5070Sstevel@tonic-gate 	error0();
5080Sstevel@tonic-gate 	smerror(str, cp);
5090Sstevel@tonic-gate 	error1(str);
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate /*
5130Sstevel@tonic-gate  * Set the flavor of the output based on the flags given
5140Sstevel@tonic-gate  * and the number and list options to either number or not number lines
5150Sstevel@tonic-gate  * and either use normally decoded (ARPAnet standard) characters or list mode,
5160Sstevel@tonic-gate  * where end of lines are marked and tabs print as ^I.
5170Sstevel@tonic-gate  */
518802Scf46844 void
setflav(void)519802Scf46844 setflav(void)
5200Sstevel@tonic-gate {
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	if (inopen)
5230Sstevel@tonic-gate 		return;
5240Sstevel@tonic-gate 	setnumb(nflag || value(vi_NUMBER));
5250Sstevel@tonic-gate 	setlist(listf || value(vi_LIST));
5260Sstevel@tonic-gate 	if (!inopen)
5270Sstevel@tonic-gate 		setoutt();
5280Sstevel@tonic-gate }
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate /*
5310Sstevel@tonic-gate  * Skip white space and tell whether command ends then.
5320Sstevel@tonic-gate  */
533802Scf46844 int
skipend(void)534802Scf46844 skipend(void)
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	pastwh();
5380Sstevel@tonic-gate 	return (endcmd(peekchar()) && peekchar() != '"');
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate /*
5420Sstevel@tonic-gate  * Set the command name for non-word commands.
5430Sstevel@tonic-gate  */
544802Scf46844 void
tailspec(int c)545802Scf46844 tailspec(int c)
5460Sstevel@tonic-gate {
5470Sstevel@tonic-gate 	static unsigned char foocmd[2];
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	foocmd[0] = c;
5500Sstevel@tonic-gate 	Command = foocmd;
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate /*
5540Sstevel@tonic-gate  * Try to read off the rest of the command word.
5550Sstevel@tonic-gate  * If alphabetics follow, then this is not the command we seek.
5560Sstevel@tonic-gate  */
557802Scf46844 void
tail(unsigned char * comm)558802Scf46844 tail(unsigned char *comm)
5590Sstevel@tonic-gate {
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	tailprim(comm, 1, 0);
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate 
564802Scf46844 void
tail2of(unsigned char * comm)565802Scf46844 tail2of(unsigned char *comm)
5660Sstevel@tonic-gate {
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	tailprim(comm, 2, 0);
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate unsigned char	tcommand[20];
5720Sstevel@tonic-gate 
573802Scf46844 void
tailprim(unsigned char * comm,int i,bool notinvis)574802Scf46844 tailprim(unsigned char *comm, int i, bool notinvis)
5750Sstevel@tonic-gate {
576802Scf46844 	unsigned char *cp;
577802Scf46844 	int c;
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	Command = comm;
5800Sstevel@tonic-gate 	for (cp = tcommand; i > 0; i--)
5810Sstevel@tonic-gate 		*cp++ = *comm++;
5820Sstevel@tonic-gate 	while (*comm && peekchar() == *comm)
5830Sstevel@tonic-gate 		*cp++ = getchar(), comm++;
5840Sstevel@tonic-gate 	c = peekchar();
5850Sstevel@tonic-gate 	if (notinvis || (isalpha(c) && isascii(c))) {
5860Sstevel@tonic-gate 		/*
5870Sstevel@tonic-gate 		 * Of the trailing lp funny business, only dl and dp
5880Sstevel@tonic-gate 		 * survive the move from ed to ex.
5890Sstevel@tonic-gate 		 */
5900Sstevel@tonic-gate 		if (tcommand[0] == 'd' && any(c, "lp"))
5910Sstevel@tonic-gate 			goto ret;
5920Sstevel@tonic-gate 		if (tcommand[0] == 's' && any(c, "gcr"))
5930Sstevel@tonic-gate 			goto ret;
5940Sstevel@tonic-gate 		while (cp < &tcommand[19] && isalpha(c = peekchar()) && isascii(c))
5950Sstevel@tonic-gate 			*cp++ = getchar();
5960Sstevel@tonic-gate 		*cp = 0;
5970Sstevel@tonic-gate 		if (notinvis)
598802Scf46844 			serror(value(vi_TERSE) ?
599802Scf46844 			    (unsigned char *)gettext("What?") :
600802Scf46844 			    (unsigned char *)gettext(
601802Scf46844 			    "%s: No such command from open/visual"), tcommand);
6020Sstevel@tonic-gate 		else
603802Scf46844 			serror(value(vi_TERSE) ?
604802Scf46844 			    (unsigned char *)gettext("What?") :
605802Scf46844 			    (unsigned char *)gettext(
606802Scf46844 			    "%s: Not an editor command"), tcommand);
6070Sstevel@tonic-gate 	}
6080Sstevel@tonic-gate ret:
6090Sstevel@tonic-gate 	*cp = 0;
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate /*
6130Sstevel@tonic-gate  * Continue after a : command from open/visual.
6140Sstevel@tonic-gate  */
615802Scf46844 void
vcontin(bool ask)616802Scf46844 vcontin(bool ask)
6170Sstevel@tonic-gate {
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	if (vcnt > 0)
6200Sstevel@tonic-gate 		vcnt = -vcnt;
6210Sstevel@tonic-gate 	if (inopen) {
6220Sstevel@tonic-gate 		if (state != VISUAL) {
6230Sstevel@tonic-gate 			/*
6240Sstevel@tonic-gate 			 * We don't know what a shell command may have left on
6250Sstevel@tonic-gate 			 * the screen, so we move the cursor to the right place
6260Sstevel@tonic-gate 			 * and then put out a newline.  But this makes an extra
6270Sstevel@tonic-gate 			 * blank line most of the time so we only do it for :sh
6280Sstevel@tonic-gate 			 * since the prompt gets left on the screen.
6290Sstevel@tonic-gate 			 *
6300Sstevel@tonic-gate 			 * BUG: :!echo longer than current line \\c
6310Sstevel@tonic-gate 			 * will mess it up.
6320Sstevel@tonic-gate 			 */
6330Sstevel@tonic-gate 			if (state == CRTOPEN) {
6340Sstevel@tonic-gate 				termreset();
6350Sstevel@tonic-gate 				vgoto(WECHO, 0);
6360Sstevel@tonic-gate 			}
6370Sstevel@tonic-gate 			if (!ask) {
638802Scf46844 				(void) putch('\r');
639802Scf46844 				(void) putch('\n');
6400Sstevel@tonic-gate 			}
6410Sstevel@tonic-gate 			return;
6420Sstevel@tonic-gate 		}
6430Sstevel@tonic-gate 		if (ask) {
6440Sstevel@tonic-gate 			merror(gettext("[Hit return to continue] "));
6450Sstevel@tonic-gate 			flush();
6460Sstevel@tonic-gate 		}
6470Sstevel@tonic-gate #ifndef CBREAK
6480Sstevel@tonic-gate 		vraw();
6490Sstevel@tonic-gate #endif
6500Sstevel@tonic-gate 		if (ask) {
6510Sstevel@tonic-gate #ifdef notdef
6520Sstevel@tonic-gate 			/*
6530Sstevel@tonic-gate 			 * Gobble ^Q/^S since the tty driver should be eating
6540Sstevel@tonic-gate 			 * them (as far as the user can see)
6550Sstevel@tonic-gate 			 */
6560Sstevel@tonic-gate 			while (peekkey() == CTRL('Q') || peekkey() == CTRL('S'))
6570Sstevel@tonic-gate 				ignore(getkey());
6580Sstevel@tonic-gate #endif
6590Sstevel@tonic-gate 			if(getkey() == ':') {
6600Sstevel@tonic-gate 				/* Extra newlines, but no other way */
661802Scf46844 				(void) putch('\n');
6620Sstevel@tonic-gate 				outline = WECHO;
6630Sstevel@tonic-gate 				ungetkey(':');
6640Sstevel@tonic-gate 			}
6650Sstevel@tonic-gate 		}
6660Sstevel@tonic-gate 		vclrech(1);
6670Sstevel@tonic-gate 		if (Peekkey != ':') {
6680Sstevel@tonic-gate 			fixterm();
669802Scf46844 			putpad((unsigned char *)enter_ca_mode);
6700Sstevel@tonic-gate 			tostart();
6710Sstevel@tonic-gate 		}
6720Sstevel@tonic-gate 	}
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate /*
6760Sstevel@tonic-gate  * Put out a newline (before a shell escape)
6770Sstevel@tonic-gate  * if in open/visual.
6780Sstevel@tonic-gate  */
679802Scf46844 void
vnfl(void)680802Scf46844 vnfl(void)
6810Sstevel@tonic-gate {
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	if (inopen) {
6840Sstevel@tonic-gate 		if (state != VISUAL && state != CRTOPEN && destline <= WECHO)
6850Sstevel@tonic-gate 			vclean();
6860Sstevel@tonic-gate 		else
6870Sstevel@tonic-gate 			vmoveitup(1, 0);
6880Sstevel@tonic-gate 		vgoto(WECHO, 0);
6890Sstevel@tonic-gate 		vclrbyte(vtube[WECHO], WCOLS);
6900Sstevel@tonic-gate 		tostop();
6910Sstevel@tonic-gate 		/* replaced by the ostop above
6920Sstevel@tonic-gate 		putpad(cursor_normal);
6930Sstevel@tonic-gate 		putpad(key_eol);
6940Sstevel@tonic-gate 		*/
6950Sstevel@tonic-gate 	}
6960Sstevel@tonic-gate 	flush();
6970Sstevel@tonic-gate }
698