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