/* * This code contains changes by * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved. * * Conditions 1, 2, and 4 and the no-warranty notice below apply * to these changes. * * * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * Redistributions of source code and documentation must retain the * above copyright notice, this list of conditions and the following * disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of * other contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef lint #ifdef DOSCCS static char sccsid[] = "@(#)ex_cmds2.c 1.18 (gritter) 2/17/05"; #endif #endif /* from ex_cmds2.c 7.4 (Berkeley) 6/7/85 */ #include "ex.h" #include "ex_argv.h" #include "ex_temp.h" #include "ex_tty.h" #include "ex_vis.h" extern bool pflag, nflag; /* mjm: extern; also in ex_cmds.c */ extern int poffset; /* mjm: extern; also in ex_cmds.c */ /* * Subroutines for major command loop. */ /* * Is there a single letter indicating a named buffer next? */ int cmdreg(void) { register int c = 0; register int wh = skipwh(); if (wh && isalpha(peekchar())) c = getchar(); return (c); } /* * Tell whether the character ends a command */ int endcmd(int ch) { switch (ch) { case '\n': case EOF: endline = 1; return (1); case '|': case '"': endline = 0; return (1); } return (0); } /* * Insist on the end of the command. */ void eol(void) { if (!skipend()) error(catgets(catd, 1, 28, "Extra chars|Extra characters at end of command")); ignnEOF(); } /* * 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. */ void error0(void) { if (vcatch) { if (splitw == 0) fixech(); if (!SO || !SE) dingdong(); return; } if (input && exitoneof) { input = strend(input) - 1; if (*input == '\n') setlastchar('\n'); input = 0; } setoutt(); flush(); resetflav(); if (!SO || !SE) dingdong(); if (inopen) { /* * We are coming out of open/visual ungracefully. * Restore TCOLUMNS, undo, and fix tty mode. */ TCOLUMNS = OCOLUMNS; undvis(); ostop(normf); /* ostop should be doing this putpad(VE); putpad(KE); */ 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. */ int error1(char *str) { bool die; if (io > 0) { close(io); io = -1; } die = (getpid() != ppid); /* Only children die */ inappend = inglobal = 0; globp = NULL, vmacp = NULL, vglobp = NULL; if (vcatch && !die) { inopen = 1; vcatch = 0; if (str) noonl(); fixol(); LONGJMP(vreslab,1); } if (str && !vcatch) putNFL(); if (die) exitex(1); if (exitoneof) lseek(0, (off_t)0, SEEK_END); if (inglobal) setlastchar('\n'); while (lastchar() != '\n' && lastchar() != EOF) ignchar(); ungetchar(0); endline = 1; reset(); } /* * Print out the message in the error message file at str, * with i an integer argument to printf. */ /*VARARGS2*/ void error(char *str, ...) { va_list ap; error0(); va_start(ap, str); vmerror(str, ap); va_end(ap); if (writing) { serror(catgets(catd, 1, 29, " [Warning - %s is incomplete]"), file); writing = 0; } error1(str); } /* * Same as error(), but using a va_list as argument. */ void verror(char *str, va_list ap) { error0(); vmerror(str, ap); error(NULL); if (writing) { serror(catgets(catd, 1, 29, " [Warning - %s is incomplete]"), file); writing = 0; } error1(str); } /* * Rewind the argument list. */ void erewind(void) { argc = argc0; argv = argv0; args = args0; if (argc > 1 && !hush) { printf(mesg(catgets(catd, 1, 30, "%d files@to edit")), argc); if (inopen) putchar(' '); else putNFL(); } } void fixol(void) { 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? */ int exclam(void) { if (peekchar() == '!') { ignchar(); return (1); } return (0); } /* * Make an argument list for e.g. next. */ void makargs(void) { gglob(&frob); argc0 = frob.argc0; argv0 = frob.argv; args0 = argv0[0]; erewind(); } /* * Advance to next file in argument list. */ void next(void) { extern short isalt; /* defined in ex_io.c */ if (argc == 0) error(catgets(catd, 1, 31, "No more files@to edit")); morargc = argc; isalt = (strcmp(altfile, args)==0) + 1; if (savedfile[0]) strcpy(altfile, savedfile); safecp(savedfile, args, sizeof savedfile, "File name too long"); argc--; args = argv ? *++argv : strend(args) + 1; } /* * Eat trailing flags and offsets after a command, * saving for possible later post-command prints. */ void newline(void) { 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; case '"': comment(); setflav(); return; default: if (!endcmd(c)) serror(catgets(catd, 1, 32, "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. */ void nomore(void) { if (argc == 0 || morargc == argc) return; morargc = argc; merror(catgets(catd, 1, 33, "%d more file"), argc); serror(catgets(catd, 1, 34, "%s@to edit"), plural((long) argc)); } /* * Before edit of new file check that either an ! follows * or the file has not been changed. */ int quickly(void) { if (exclam()) return (1); if (chng && dol > zero) { /* chng = 0; */ xchng = 0; error(catgets(catd, 1, 35, "No write@since last change (:%s! overrides)"), Command); } return (0); } /* * Reset the flavor of the output to print mode with no numbering. */ void resetflav(void) { 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. */ void serror(char *str, ...) { va_list ap; if (str == NULL) return; va_start(ap, str); error0(); vsmerror(str, ap); error1(str); va_end(ap); } /* * 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. */ void setflav(void) { if (inopen) return; setnumb(nflag || value(NUMBER)); setlist(listf || value(LIST)); setoutt(); } /* * Skip white space and tell whether command ends then. */ int skipend(void) { pastwh(); return (endcmd(peekchar()) && peekchar() != '"'); } /* * Set the command name for non-word commands. */ void tailspec(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. */ void tail(char *comm) { tailprim(comm, 1, 0); } void tail2of(char *comm) { tailprim(comm, 2, 0); } char tcommand[20]; void tailprim(register char *comm, int xi, bool notinvis) { register char *cp; register int c; int i = xi; Command = comm; for (cp = tcommand; i > 0; i--) *cp++ = *comm++; while (*comm && peekchar() == *comm) *cp++ = getchar(), comm++; c = peekchar(); if (notinvis || isalpha(c) #ifdef BIT8 || xi == 0 && (c&(0200|QUOTE)) == 0200 #endif ) { /* * Of the trailing lp funny business, only dl and dp * survive the move from ed to ex. */ if (tcommand[0] == 'd' && any(c, "lp")) goto ret; if (tcommand[0] == 's' && any(c, "gcr")) goto ret; while (cp < &tcommand[19] && (c = peekchar(), isalpha(c) #ifdef BIT8 || xi == 0 && (c&(0200|QUOTE)) == 0200 #endif )) *cp++ = getchar(); *cp = 0; if (notinvis) serror(catgets(catd, 1, 36, "What?|%s: No such command from open/visual"), tcommand); else serror(catgets(catd, 1, 37, "What?|%s: Not an editor command"), tcommand); } ret: *cp = 0; } /* * Continue after a : command from open/visual. */ void vcontin(bool ask) { if (vcnt > 0) vcnt = -vcnt; if (inopen) { if (state != VISUAL) { /* * We don't know what a shell command may have left on * the screen, so we move the cursor to the right place * and then put out a newline. But this makes an extra * blank line most of the time so we only do it for :sh * since the prompt gets left on the screen. * * BUG: :!echo longer than current line \\c * will screw it up, but be reasonable! */ if (state == CRTOPEN) { termreset(); vgoto(WECHO, 0); } if (!ask) { putch('\r'); putch('\n'); } return; } if (ask) { merror(catgets(catd, 1, 38, "[Hit return to continue] ")); flush(); } if (ask) { #ifdef EATQS /* * Gobble ^Q/^S since the tty driver should be eating * them (as far as the user can see) */ while (peekkey(0) == CTRL('Q') || peekkey() == CTRL('S')) ignore(getkey()); #endif if(getkey() == ':') { /* Ugh. Extra newlines, but no other way */ putch('\n'); outline = WECHO; ungetkey(':'); } } vclrech(1); if (Peekkey != ':') { putpad(TI); tostart(); /* replaced by ostart. putpad(VS); putpad(KS); */ } } } /* * Put out a newline (before a shell escape) * if in open/visual. */ void vnfl(void) { if (inopen) { if (state != VISUAL && state != CRTOPEN && destline <= WECHO) vclean(); else vmoveitup(1, 0); vgoto(WECHO, 0); vclrcell(vtube[WECHO], WCOLS); tostop(); /* replaced by the ostop above putpad(VE); putpad(KE); */ } flush(); }