+/* Copyright (c) 1979 Regents of the University of California */
+#include "ex.h"
+#include "ex_argv.h"
+#include "ex_temp.h"
+#include "ex_tty.h"
+#include "ex_vis.h"
+
+bool pflag, nflag;
+int poffset;
+
+/*
+ * Subroutines for major command loop.
+ */
+
+/*
+ * Is there a single letter indicating a named buffer next?
+ */
+cmdreg()
+{
+ register int c = 0;
+
+ pastwh();
+ if (isalpha(peekchar()))
+ c = getchar();
+ return (c);
+}
+
+/*
+ * Tell whether the character ends a command
+ */
+endcmd(ch)
+ int ch;
+{
+ switch (ch) {
+
+ case '\n':
+ case EOF:
+ endline = 1;
+ return (1);
+
+ case '|':
+ endline = 0;
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Insist on the end of the command.
+ */
+eol()
+{
+
+ if (!skipend())
+ error("Extra chars|Extra characters at end of command");
+ ignnEOF();
+}
+
+/*
+ * Print out the message in the error message file at str,
+ * with i an integer argument to printf.
+ */
+/*VARARGS2*/
+error(str, i)
+#ifdef lint
+ register char *str;
+#else
+ register int str;
+#endif
+ int i;
+{
+
+ error0();
+ merror(str, i);
+ error1(str);
+}
+
+/*
+ * Rewind the argument list.
+ */
+erewind()
+{
+
+ argc = argc0;
+ argv = argv0;
+ args = args0;
+ if (argc > 1 && !hush) {
+ printf(mesg("%d files@to edit"), argc);
+ if (inopen)
+ putchar(' ');
+ else
+ putNFL();
+ }
+}
+
+/*
+ * Guts of the pre-printing error processing.
+ * If in visual and catching errors, then we dont mung up the internals,
+ * just fixing up the echo area for the print.
+ * Otherwise we reset a number of externals, and discard unused input.
+ */
+error0()
+{
+
+ intag = 0;
+ if (vcatch) {
+ if (splitw == 0)
+ fixech();
+ if (!SO || !SE)
+ dingdong();
+ return;
+ }
+ if (input) {
+ input = strend(input) - 1;
+ if (*input == '\n')
+ setlastchar('\n');
+ input = 0;
+ }
+ setoutt();
+ flush();
+ resetflav();
+ if (laste) {
+ laste = 0;
+ sync();
+ }
+ if (!SO || !SE)
+ dingdong();
+ if (inopen) {
+ /*
+ * We are coming out of open/visual ungracefully.
+ * Restore COLUMNS, undo, and fix tty mode.
+ */
+ COLUMNS = OCOLUMNS;
+ undvis();
+ ostop(normf);
+ putpad(VE);
+ putnl();
+ }
+ inopen = 0;
+ holdcm = 0;
+}
+
+/*
+ * Post error printing processing.
+ * Close the i/o file if left open.
+ * If catching in visual then throw to the visual catch,
+ * else if a child after a fork, then exit.
+ * Otherwise, in the normal command mode error case,
+ * finish state reset, and throw to top.
+ */
+error1(str)
+ char *str;
+{
+
+ if (io > 0) {
+ close(io);
+ io = -1;
+ }
+ if (vcatch && !die) {
+ inglobal = 0;
+ inopen = 1;
+ vcatch = 0;
+ fixol();
+ longjmp(vreslab);
+ }
+ if (str)
+ putNFL();
+ if (die)
+ exit(1);
+ lseek(0, 0L, 2);
+ if (inglobal)
+ setlastchar('\n');
+ inglobal = 0;
+ globp = 0;
+ while (lastchar() != '\n' && lastchar() != EOF)
+ ignchar();
+ ungetchar(0);
+ endline = 1;
+ reset();
+}
+
+fixol()
+{
+ if (Outchar != vputchar) {
+ flush();
+ if (state == ONEOPEN || state == HARDOPEN)
+ outline = destline = 0;
+ Outchar = vputchar;
+ vcontin(1);
+ } else {
+ if (destcol)
+ vclreol();
+ vclean();
+ }
+}
+
+/*
+ * Does an ! character follow in the command stream?
+ */
+exclam()
+{
+
+ if (peekchar() == '!') {
+ ignchar();
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Make an argument list for e.g. next.
+ */
+makargs()
+{
+
+ glob(&frob);
+ argc0 = frob.argc0;
+ argv0 = frob.argv;
+ args0 = argv0[0];
+ erewind();
+}
+
+/*
+ * Advance to next file in argument list.
+ */
+next()
+{
+
+ if (argc == 0)
+ error("No more files@to edit");
+ morargc = argc;
+ if (savedfile[0])
+ CP(altfile, savedfile);
+ CP(savedfile, args);
+ argc--;
+ args = argv ? *++argv : strend(args) + 1;
+}
+
+/*
+ * Eat trailing flags and offsets after a command,
+ * saving for possible later post-command prints.
+ */
+newline()
+{
+ register int c;
+
+ resetflav();
+ for (;;) {
+ c = getchar();
+ switch (c) {
+
+ case '^':
+ case '-':
+ poffset--;
+ break;
+
+ case '+':
+ poffset++;
+ break;
+
+ case 'l':
+ listf++;
+ break;
+
+ case '#':
+ nflag++;
+ break;
+
+ case 'p':
+ listf = 0;
+ break;
+
+ case ' ':
+ case '\t':
+ continue;
+
+ default:
+ if (!endcmd(c))
+ serror("Extra chars|Extra characters at end of \"%s\" command", Command);
+ if (c == EOF)
+ ungetchar(c);
+ setflav();
+ return;
+ }
+ pflag++;
+ }
+}
+
+/*
+ * Before quit or respec of arg list, check that there are
+ * no more files in the arg list.
+ */
+nomore()
+{
+
+ if (argc == 0 || morargc == argc)
+ return;
+ morargc = argc;
+ merror("%d more file", argc);
+ serror("%s@to edit", plural((long) argc));
+}
+
+/*
+ * Before edit of new file check that either an ! follows
+ * or the file has not been changed.
+ */
+quickly()
+{
+
+ if (exclam())
+ return (1);
+ if (chng) {
+/*
+ chng = 0;
+*/
+ xchng = 0;
+ error("No write@since last change (%s! overrides)", Command);
+ }
+ return (0);
+}
+
+/*
+ * Reset the flavor of the output to print mode with no numbering.
+ */
+resetflav()
+{
+
+ if (inopen)
+ return;
+ listf = 0;
+ nflag = 0;
+ pflag = 0;
+ poffset = 0;
+ setflav();
+}
+
+/*
+ * Print an error message with a %s type argument to printf.
+ * Message text comes from error message file.
+ */
+serror(str, cp)
+#ifdef lint
+ register char *str;
+#else
+ register int str;
+#endif
+ char *cp;
+{
+
+ error0();
+ smerror(str, cp);
+ error1(str);
+}
+
+/*
+ * Set the flavor of the output based on the flags given
+ * and the number and list options to either number or not number lines
+ * and either use normally decoded (ARPAnet standard) characters or list mode,
+ * where end of lines are marked and tabs print as ^I.
+ */
+setflav()
+{
+
+ if (inopen)
+ return;
+ setnumb(nflag || value(NUMBER));
+ setlist(listf || value(LIST));
+ setoutt();
+}
+
+/*
+ * Skip white space and tell whether command ends then.
+ */
+skipend()
+{
+
+ pastwh();
+ return (endcmd(peekchar()));
+}
+
+/*
+ * Set the command name for non-word commands.
+ */
+tailspec(c)
+ int c;
+{
+ static char foocmd[2];
+
+ foocmd[0] = c;
+ Command = foocmd;
+}
+
+/*
+ * Try to read off the rest of the command word.
+ * If alphabetics follow, then this is not the command we seek.
+ */
+tail(comm)
+ char *comm;
+{
+
+ tailprim(comm, 1, 0);
+}
+
+tail2of(comm)
+ char *comm;
+{
+
+ tailprim(comm, 2, 0);
+}
+
+char tcommand[20];
+
+tailprim(comm, i, notinvis)
+ register char *comm;
+ int i;
+ bool notinvis;
+{
+ register char *cp;
+ register int c;
+
+ Command = comm;
+ for (cp = tcommand; i > 0; i--)
+ *cp++ = *comm++;
+ while (*comm && peekchar() == *comm)
+ *cp++ = getchar(), comm++;
+ c = peekchar();
+ if (notinvis || isalpha(c)) {
+ /*
+ * Of the trailing lp funny buisness, only dl and dp
+ * survive the move from ed to ex.
+ */
+ if (tcommand[0] == 'd' && any(c, "lp"))
+ goto ret;
+ while (cp < &tcommand[19] && isalpha(peekchar()))
+ *cp++ = getchar();
+ *cp = 0;
+ if (notinvis)
+ serror("What?|%s: No such command from open/visual", tcommand);
+ else
+ serror("What?|%s: Not an editor command", tcommand);
+ }
+ret:
+ *cp = 0;
+}
+
+/*
+ * Continue after a shell escape from open/visual.
+ */
+vcontin(ask)
+ bool ask;
+{
+
+ if (vcnt > 0)
+ vcnt = -vcnt;
+ if (inopen) {
+ if (state != VISUAL) {
+/*
+ vtube[WECHO][0] = '*';
+ vnfl();
+*/
+ return;
+ }
+ if (ask) {
+ merror("[Hit return to continue] ");
+ flush();
+ }
+#ifdef V6
+ vraw();
+#endif
+ if (ask && getkey() == ':')
+ ungetkey(':');
+ }
+}
+
+/*
+ * Put out a newline (before a shell escape)
+ * if in open/visual.
+ */
+vnfl()
+{
+
+ if (inopen) {
+ if (state != VISUAL && state != CRTOPEN && destline <= WECHO)
+ vclean();
+ else
+ vmoveitup(1);
+ vgoto(WECHO, 0);
+ vclrbyte(vtube[WECHO], WCOLS);
+ flush();
+ }
+}