diff options
author | peter <peter@FreeBSD.org> | 2013-08-11 08:38:10 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2013-08-11 08:38:10 +0000 |
commit | 75700a8c067d4d910e2017f0aa29cbbca644f9cc (patch) | |
tree | fcfc8dee7b416cacdea763f18f34e0930234186a /contrib/nvi/ex | |
parent | 3102470d94db36e49a2262542f69cc4219ae1aee (diff) | |
download | FreeBSD-src-75700a8c067d4d910e2017f0aa29cbbca644f9cc.zip FreeBSD-src-75700a8c067d4d910e2017f0aa29cbbca644f9cc.tar.gz |
Post-cvs2svn flatten pass.
Diffstat (limited to 'contrib/nvi/ex')
54 files changed, 0 insertions, 15658 deletions
diff --git a/contrib/nvi/ex/ex.awk b/contrib/nvi/ex/ex.awk deleted file mode 100644 index 3ee372e..0000000 --- a/contrib/nvi/ex/ex.awk +++ /dev/null @@ -1,6 +0,0 @@ -# @(#)ex.awk 10.1 (Berkeley) 6/8/95 - -/^\/\* C_[0-9A-Z_]* \*\/$/ { - printf("#define %s %d\n", $2, cnt++); - next; -} diff --git a/contrib/nvi/ex/ex.c b/contrib/nvi/ex/ex.c deleted file mode 100644 index f92d8f7..0000000 --- a/contrib/nvi/ex/ex.c +++ /dev/null @@ -1,2370 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex.c 10.57 (Berkeley) 10/10/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/stat.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" -#include "../vi/vi.h" - -#if defined(DEBUG) && defined(COMLOG) -static void ex_comlog __P((SCR *, EXCMD *)); -#endif -static EXCMDLIST const * - ex_comm_search __P((char *, size_t)); -static int ex_discard __P((SCR *)); -static int ex_line __P((SCR *, EXCMD *, MARK *, int *, int *)); -static int ex_load __P((SCR *)); -static void ex_unknown __P((SCR *, char *, size_t)); - -/* - * ex -- - * Main ex loop. - * - * PUBLIC: int ex __P((SCR **)); - */ -int -ex(spp) - SCR **spp; -{ - EX_PRIVATE *exp; - GS *gp; - MSGS *mp; - SCR *sp; - TEXT *tp; - u_int32_t flags; - - sp = *spp; - gp = sp->gp; - exp = EXP(sp); - - /* Start the ex screen. */ - if (ex_init(sp)) - return (1); - - /* Flush any saved messages. */ - while ((mp = gp->msgq.lh_first) != NULL) { - gp->scr_msg(sp, mp->mtype, mp->buf, mp->len); - LIST_REMOVE(mp, q); - free(mp->buf); - free(mp); - } - - /* If reading from a file, errors should have name and line info. */ - if (F_ISSET(gp, G_SCRIPTED)) { - gp->excmd.if_lno = 1; - gp->excmd.if_name = "script"; - } - - /* - * !!! - * Initialize the text flags. The beautify edit option historically - * applied to ex command input read from a file. In addition, the - * first time a ^H was discarded from the input, there was a message, - * "^H discarded", that was displayed. We don't bother. - */ - LF_INIT(TXT_BACKSLASH | TXT_CNTRLD | TXT_CR); - for (;; ++gp->excmd.if_lno) { - /* Display status line and flush. */ - if (F_ISSET(sp, SC_STATUS)) { - if (!F_ISSET(sp, SC_EX_SILENT)) - msgq_status(sp, sp->lno, 0); - F_CLR(sp, SC_STATUS); - } - (void)ex_fflush(sp); - - /* Set the flags the user can reset. */ - if (O_ISSET(sp, O_BEAUTIFY)) - LF_SET(TXT_BEAUTIFY); - if (O_ISSET(sp, O_PROMPT)) - LF_SET(TXT_PROMPT); - - /* Clear any current interrupts, and get a command. */ - CLR_INTERRUPT(sp); - if (ex_txt(sp, &sp->tiq, ':', flags)) - return (1); - if (INTERRUPTED(sp)) { - (void)ex_puts(sp, "\n"); - (void)ex_fflush(sp); - continue; - } - - /* Initialize the command structure. */ - CLEAR_EX_PARSER(&gp->excmd); - - /* - * If the user entered a single carriage return, send - * ex_cmd() a separator -- it discards single newlines. - */ - tp = sp->tiq.cqh_first; - if (tp->len == 0) { - gp->excmd.cp = " "; /* __TK__ why not |? */ - gp->excmd.clen = 1; - } else { - gp->excmd.cp = tp->lb; - gp->excmd.clen = tp->len; - } - F_INIT(&gp->excmd, E_NRSEP); - - if (ex_cmd(sp) && F_ISSET(gp, G_SCRIPTED)) - return (1); - - if (INTERRUPTED(sp)) { - CLR_INTERRUPT(sp); - msgq(sp, M_ERR, "170|Interrupted"); - } - - /* - * If the last command caused a restart, or switched screens - * or into vi, return. - */ - if (F_ISSET(gp, G_SRESTART) || F_ISSET(sp, SC_SSWITCH | SC_VI)) { - *spp = sp; - break; - } - - /* If the last command switched files, we don't care. */ - F_CLR(sp, SC_FSWITCH); - - /* - * If we're exiting this screen, move to the next one. By - * definition, this means returning into vi, so return to the - * main editor loop. The ordering is careful, don't discard - * the contents of sp until the end. - */ - if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) { - if (file_end(sp, NULL, F_ISSET(sp, SC_EXIT_FORCE))) - return (1); - *spp = screen_next(sp); - return (screen_end(sp)); - } - } - return (0); -} - -/* - * ex_cmd -- - * The guts of the ex parser: parse and execute a string containing - * ex commands. - * - * !!! - * This code MODIFIES the string that gets passed in, to delete quoting - * characters, etc. The string cannot be readonly/text space, nor should - * you expect to use it again after ex_cmd() returns. - * - * !!! - * For the fun of it, if you want to see if a vi clone got the ex argument - * parsing right, try: - * - * echo 'foo|bar' > file1; echo 'foo/bar' > file2; - * vi - * :edit +1|s/|/PIPE/|w file1| e file2|1 | s/\//SLASH/|wq - * - * or: vi - * :set|file|append|set|file - * - * For extra credit, try them in a startup .exrc file. - * - * PUBLIC: int ex_cmd __P((SCR *)); - */ -int -ex_cmd(sp) - SCR *sp; -{ - enum nresult nret; - EX_PRIVATE *exp; - EXCMD *ecp; - GS *gp; - MARK cur; - recno_t lno; - size_t arg1_len, discard, len; - u_int32_t flags; - long ltmp; - int at_found, gv_found; - int ch, cnt, delim, isaddr, namelen; - int newscreen, notempty, tmp, vi_address; - char *arg1, *p, *s, *t; - - gp = sp->gp; - exp = EXP(sp); - - /* - * We always start running the command on the top of the stack. - * This means that *everything* must be resolved when we leave - * this function for any reason. - */ -loop: ecp = gp->ecq.lh_first; - - /* If we're reading a command from a file, set up error information. */ - if (ecp->if_name != NULL) { - gp->if_lno = ecp->if_lno; - gp->if_name = ecp->if_name; - } - - /* - * If a move to the end of the file is scheduled for this command, - * do it now. - */ - if (F_ISSET(ecp, E_MOVETOEND)) { - if (db_last(sp, &sp->lno)) - goto rfail; - sp->cno = 0; - F_CLR(ecp, E_MOVETOEND); - } - - /* If we found a newline, increment the count now. */ - if (F_ISSET(ecp, E_NEWLINE)) { - ++gp->if_lno; - ++ecp->if_lno; - F_CLR(ecp, E_NEWLINE); - } - - /* (Re)initialize the EXCMD structure, preserving some flags. */ - CLEAR_EX_CMD(ecp); - - /* Initialize the argument structures. */ - if (argv_init(sp, ecp)) - goto err; - - /* Initialize +cmd, saved command information. */ - arg1 = NULL; - ecp->save_cmdlen = 0; - - /* Skip <blank>s, empty lines. */ - for (notempty = 0; ecp->clen > 0; ++ecp->cp, --ecp->clen) - if ((ch = *ecp->cp) == '\n') { - ++gp->if_lno; - ++ecp->if_lno; - } else if (isblank(ch)) - notempty = 1; - else - break; - - /* - * !!! - * Permit extra colons at the start of the line. Historically, - * ex/vi allowed a single extra one. It's simpler not to count. - * The stripping is done here because, historically, any command - * could have preceding colons, e.g. ":g/pattern/:p" worked. - */ - if (ecp->clen != 0 && ch == ':') { - notempty = 1; - while (--ecp->clen > 0 && (ch = *++ecp->cp) == ':'); - } - - /* - * Command lines that start with a double-quote are comments. - * - * !!! - * Historically, there was no escape or delimiter for a comment, e.g. - * :"foo|set was a single comment and nothing was output. Since nvi - * permits users to escape <newline> characters into command lines, we - * have to check for that case. - */ - if (ecp->clen != 0 && ch == '"') { - while (--ecp->clen > 0 && *++ecp->cp != '\n'); - if (*ecp->cp == '\n') { - F_SET(ecp, E_NEWLINE); - ++ecp->cp; - --ecp->clen; - } - goto loop; - } - - /* Skip whitespace. */ - for (; ecp->clen > 0; ++ecp->cp, --ecp->clen) { - ch = *ecp->cp; - if (!isblank(ch)) - break; - } - - /* - * The last point at which an empty line can mean do nothing. - * - * !!! - * Historically, in ex mode, lines containing only <blank> characters - * were the same as a single <carriage-return>, i.e. a default command. - * In vi mode, they were ignored. In .exrc files this was a serious - * annoyance, as vi kept trying to treat them as print commands. We - * ignore backward compatibility in this case, discarding lines that - * contain only <blank> characters from .exrc files. - * - * !!! - * This is where you end up when you're done a command, i.e. clen has - * gone to zero. Continue if there are more commands to run. - */ - if (ecp->clen == 0 && - (!notempty || F_ISSET(sp, SC_VI) || F_ISSET(ecp, E_BLIGNORE))) { - if (ex_load(sp)) - goto rfail; - ecp = gp->ecq.lh_first; - if (ecp->clen == 0) - goto rsuccess; - goto loop; - } - - /* - * Check to see if this is a command for which we may want to move - * the cursor back up to the previous line. (The command :1<CR> - * wants a <newline> separator, but the command :<CR> wants to erase - * the command line.) If the line is empty except for <blank>s, - * <carriage-return> or <eof>, we'll probably want to move up. I - * don't think there's any way to get <blank> characters *after* the - * command character, but this is the ex parser, and I've been wrong - * before. - */ - if (F_ISSET(ecp, E_NRSEP) && - ecp->clen != 0 && (ecp->clen != 1 || ecp->cp[0] != '\004')) - F_CLR(ecp, E_NRSEP); - - /* Parse command addresses. */ - if (ex_range(sp, ecp, &tmp)) - goto rfail; - if (tmp) - goto err; - - /* - * Skip <blank>s and any more colons (the command :3,5:print - * worked, historically). - */ - for (; ecp->clen > 0; ++ecp->cp, --ecp->clen) { - ch = *ecp->cp; - if (!isblank(ch) && ch != ':') - break; - } - - /* - * If no command, ex does the last specified of p, l, or #, and vi - * moves to the line. Otherwise, determine the length of the command - * name by looking for the first non-alphabetic character. (There - * are a few non-alphabetic characters in command names, but they're - * all single character commands.) This isn't a great test, because - * it means that, for the command ":e +cut.c file", we'll report that - * the command "cut" wasn't known. However, it makes ":e+35 file" work - * correctly. - * - * !!! - * Historically, lines with multiple adjacent (or <blank> separated) - * command separators were very strange. For example, the command - * |||<carriage-return>, when the cursor was on line 1, displayed - * lines 2, 3 and 5 of the file. In addition, the command " | " - * would only display the line after the next line, instead of the - * next two lines. No ideas why. It worked reasonably when executed - * from vi mode, and displayed lines 2, 3, and 4, so we do a default - * command for each separator. - */ -#define SINGLE_CHAR_COMMANDS "\004!#&*<=>@~" - newscreen = 0; - if (ecp->clen != 0 && ecp->cp[0] != '|' && ecp->cp[0] != '\n') { - if (strchr(SINGLE_CHAR_COMMANDS, *ecp->cp)) { - p = ecp->cp; - ++ecp->cp; - --ecp->clen; - namelen = 1; - } else { - for (p = ecp->cp; - ecp->clen > 0; --ecp->clen, ++ecp->cp) - if (!isalpha(*ecp->cp)) - break; - if ((namelen = ecp->cp - p) == 0) { - msgq(sp, M_ERR, "080|Unknown command name"); - goto err; - } - } - - /* - * !!! - * Historic vi permitted flags to immediately follow any - * subset of the 'delete' command, but then did not permit - * further arguments (flag, buffer, count). Make it work. - * Permit further arguments for the few shreds of dignity - * it offers. - * - * Adding commands that start with 'd', and match "delete" - * up to a l, p, +, - or # character can break this code. - * - * !!! - * Capital letters beginning the command names ex, edit, - * next, previous, tag and visual (in vi mode) indicate the - * command should happen in a new screen. - */ - switch (p[0]) { - case 'd': - for (s = p, - t = cmds[C_DELETE].name; *s == *t; ++s, ++t); - if (s[0] == 'l' || s[0] == 'p' || s[0] == '+' || - s[0] == '-' || s[0] == '^' || s[0] == '#') { - len = (ecp->cp - p) - (s - p); - ecp->cp -= len; - ecp->clen += len; - ecp->rcmd = cmds[C_DELETE]; - ecp->rcmd.syntax = "1bca1"; - ecp->cmd = &ecp->rcmd; - goto skip_srch; - } - break; - case 'E': case 'F': case 'N': case 'P': case 'T': case 'V': - newscreen = 1; - p[0] = tolower(p[0]); - break; - } - - /* - * Search the table for the command. - * - * !!! - * Historic vi permitted the mark to immediately follow the - * 'k' in the 'k' command. Make it work. - * - * !!! - * Historic vi permitted any flag to follow the s command, e.g. - * "s/e/E/|s|sgc3p" was legal. Make the command "sgc" work. - * Since the following characters all have to be flags, i.e. - * alphabetics, we can let the s command routine return errors - * if it was some illegal command string. This code will break - * if an "sg" or similar command is ever added. The substitute - * code doesn't care if it's a "cgr" flag or a "#lp" flag that - * follows the 's', but we limit the choices here to "cgr" so - * that we get unknown command messages for wrong combinations. - */ - if ((ecp->cmd = ex_comm_search(p, namelen)) == NULL) - switch (p[0]) { - case 'k': - if (namelen == 2) { - ecp->cp -= namelen - 1; - ecp->clen += namelen - 1; - ecp->cmd = &cmds[C_K]; - break; - } - goto unknown; - case 's': - for (s = p + 1, cnt = namelen; --cnt; ++s) - if (s[0] != 'c' && - s[0] != 'g' && s[0] != 'r') - break; - if (cnt == 0) { - ecp->cp -= namelen - 1; - ecp->clen += namelen - 1; - ecp->rcmd = cmds[C_SUBSTITUTE]; - ecp->rcmd.fn = ex_subagain; - ecp->cmd = &ecp->rcmd; - break; - } - /* FALLTHROUGH */ - default: -unknown: if (newscreen) - p[0] = toupper(p[0]); - ex_unknown(sp, p, namelen); - goto err; - } - - /* - * The visual command has a different syntax when called - * from ex than when called from a vi colon command. FMH. - * Make the change now, before we test for the newscreen - * semantic, so that we're testing the right one. - */ -skip_srch: if (ecp->cmd == &cmds[C_VISUAL_EX] && F_ISSET(sp, SC_VI)) - ecp->cmd = &cmds[C_VISUAL_VI]; - - /* - * !!! - * Historic vi permitted a capital 'P' at the beginning of - * any command that started with 'p'. Probably wanted the - * P[rint] command for backward compatibility, and the code - * just made Preserve and Put work by accident. Nvi uses - * Previous to mean previous-in-a-new-screen, so be careful. - */ - if (newscreen && !F_ISSET(ecp->cmd, E_NEWSCREEN) && - (ecp->cmd == &cmds[C_PRINT] || - ecp->cmd == &cmds[C_PRESERVE])) - newscreen = 0; - - /* Test for a newscreen associated with this command. */ - if (newscreen && !F_ISSET(ecp->cmd, E_NEWSCREEN)) - goto unknown; - - /* Secure means no shell access. */ - if (F_ISSET(ecp->cmd, E_SECURE) && O_ISSET(sp, O_SECURE)) { - ex_emsg(sp, ecp->cmd->name, EXM_SECURE); - goto err; - } - - /* - * Multiple < and > characters; another "feature". Note, - * The string passed to the underlying function may not be - * nul terminated in this case. - */ - if ((ecp->cmd == &cmds[C_SHIFTL] && *p == '<') || - (ecp->cmd == &cmds[C_SHIFTR] && *p == '>')) { - for (ch = *p; - ecp->clen > 0; --ecp->clen, ++ecp->cp) - if (*ecp->cp != ch) - break; - if (argv_exp0(sp, ecp, p, ecp->cp - p)) - goto err; - } - - /* Set the format style flags for the next command. */ - if (ecp->cmd == &cmds[C_HASH]) - exp->fdef = E_C_HASH; - else if (ecp->cmd == &cmds[C_LIST]) - exp->fdef = E_C_LIST; - else if (ecp->cmd == &cmds[C_PRINT]) - exp->fdef = E_C_PRINT; - F_CLR(ecp, E_USELASTCMD); - } else { - /* Print is the default command. */ - ecp->cmd = &cmds[C_PRINT]; - - /* Set the saved format flags. */ - F_SET(ecp, exp->fdef); - - /* - * !!! - * If no address was specified, and it's not a global command, - * we up the address by one. (I have no idea why globals are - * exempted, but it's (ahem) historic practice.) - */ - if (ecp->addrcnt == 0 && !F_ISSET(sp, SC_EX_GLOBAL)) { - ecp->addrcnt = 1; - ecp->addr1.lno = sp->lno + 1; - ecp->addr1.cno = sp->cno; - } - - F_SET(ecp, E_USELASTCMD); - } - - /* - * !!! - * Historically, the number option applied to both ex and vi. One - * strangeness was that ex didn't switch display formats until a - * command was entered, e.g. <CR>'s after the set didn't change to - * the new format, but :1p would. - */ - if (O_ISSET(sp, O_NUMBER)) { - F_SET(ecp, E_OPTNUM); - FL_SET(ecp->iflags, E_C_HASH); - } else - F_CLR(ecp, E_OPTNUM); - - /* Check for ex mode legality. */ - if (F_ISSET(sp, SC_EX) && (F_ISSET(ecp->cmd, E_VIONLY) || newscreen)) { - msgq(sp, M_ERR, - "082|%s: command not available in ex mode", ecp->cmd->name); - goto err; - } - - /* Add standard command flags. */ - F_SET(ecp, ecp->cmd->flags); - if (!newscreen) - F_CLR(ecp, E_NEWSCREEN); - - /* - * There are three normal termination cases for an ex command. They - * are the end of the string (ecp->clen), or unescaped (by <literal - * next> characters) <newline> or '|' characters. As we're now past - * possible addresses, we can determine how long the command is, so we - * don't have to look for all the possible terminations. Naturally, - * there are some exciting special cases: - * - * 1: The bang, global, v and the filter versions of the read and - * write commands are delimited by <newline>s (they can contain - * shell pipes). - * 2: The ex, edit, next and visual in vi mode commands all take ex - * commands as their first arguments. - * 3: The s command takes an RE as its first argument, and wants it - * to be specially delimited. - * - * Historically, '|' characters in the first argument of the ex, edit, - * next, vi visual, and s commands didn't delimit the command. And, - * in the filter cases for read and write, and the bang, global and v - * commands, they did not delimit the command at all. - * - * For example, the following commands were legal: - * - * :edit +25|s/abc/ABC/ file.c - * :s/|/PIPE/ - * :read !spell % | columnate - * :global/pattern/p|l - * - * It's not quite as simple as it sounds, however. The command: - * - * :s/a/b/|s/c/d|set - * - * was also legal, i.e. the historic ex parser (using the word loosely, - * since "parser" implies some regularity of syntax) delimited the RE's - * based on its delimiter and not anything so irretrievably vulgar as a - * command syntax. - * - * Anyhow, the following code makes this all work. First, for the - * special cases we move past their special argument(s). Then, we - * do normal command processing on whatever is left. Barf-O-Rama. - */ - discard = 0; /* Characters discarded from the command. */ - arg1_len = 0; - ecp->save_cmd = ecp->cp; - if (ecp->cmd == &cmds[C_EDIT] || ecp->cmd == &cmds[C_EX] || - ecp->cmd == &cmds[C_NEXT] || ecp->cmd == &cmds[C_VISUAL_VI]) { - /* - * Move to the next non-whitespace character. A '!' - * immediately following the command is eaten as a - * force flag. - */ - if (ecp->clen > 0 && *ecp->cp == '!') { - ++ecp->cp; - --ecp->clen; - FL_SET(ecp->iflags, E_C_FORCE); - - /* Reset, don't reparse. */ - ecp->save_cmd = ecp->cp; - } - for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) - if (!isblank(*ecp->cp)) - break; - /* - * QUOTING NOTE: - * - * The historic implementation ignored all escape characters - * so there was no way to put a space or newline into the +cmd - * field. We do a simplistic job of fixing it by moving to the - * first whitespace character that isn't escaped. The escaping - * characters are stripped as no longer useful. - */ - if (ecp->clen > 0 && *ecp->cp == '+') { - ++ecp->cp; - --ecp->clen; - for (arg1 = p = ecp->cp; - ecp->clen > 0; --ecp->clen, ++ecp->cp) { - ch = *ecp->cp; - if (IS_ESCAPE(sp, ecp, ch) && - ecp->clen > 1) { - ++discard; - --ecp->clen; - ch = *++ecp->cp; - } else if (isblank(ch)) - break; - *p++ = ch; - } - arg1_len = ecp->cp - arg1; - - /* Reset, so the first argument isn't reparsed. */ - ecp->save_cmd = ecp->cp; - } - } else if (ecp->cmd == &cmds[C_BANG] || - ecp->cmd == &cmds[C_GLOBAL] || ecp->cmd == &cmds[C_V]) { - /* - * QUOTING NOTE: - * - * We use backslashes to escape <newline> characters, although - * this wasn't historic practice for the bang command. It was - * for the global and v commands, and it's common usage when - * doing text insert during the command. Escaping characters - * are stripped as no longer useful. - */ - for (p = ecp->cp; ecp->clen > 0; --ecp->clen, ++ecp->cp) { - ch = *ecp->cp; - if (ch == '\\' && ecp->clen > 1 && ecp->cp[1] == '\n') { - ++discard; - --ecp->clen; - ch = *++ecp->cp; - - ++gp->if_lno; - ++ecp->if_lno; - } else if (ch == '\n') - break; - *p++ = ch; - } - } else if (ecp->cmd == &cmds[C_READ] || ecp->cmd == &cmds[C_WRITE]) { - /* - * For write commands, if the next character is a <blank>, and - * the next non-blank character is a '!', it's a filter command - * and we want to eat everything up to the <newline>. For read - * commands, if the next non-blank character is a '!', it's a - * filter command and we want to eat everything up to the next - * <newline>. Otherwise, we're done. - */ - for (tmp = 0; ecp->clen > 0; --ecp->clen, ++ecp->cp) { - ch = *ecp->cp; - if (isblank(ch)) - tmp = 1; - else - break; - } - if (ecp->clen > 0 && ch == '!' && - (ecp->cmd == &cmds[C_READ] || tmp)) - for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) - if (ecp->cp[0] == '\n') - break; - } else if (ecp->cmd == &cmds[C_SUBSTITUTE]) { - /* - * Move to the next non-whitespace character, we'll use it as - * the delimiter. If the character isn't an alphanumeric or - * a '|', it's the delimiter, so parse it. Otherwise, we're - * into something like ":s g", so use the special s command. - */ - for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) - if (!isblank(ecp->cp[0])) - break; - - if (isalnum(ecp->cp[0]) || ecp->cp[0] == '|') { - ecp->rcmd = cmds[C_SUBSTITUTE]; - ecp->rcmd.fn = ex_subagain; - ecp->cmd = &ecp->rcmd; - } else if (ecp->clen > 0) { - /* - * QUOTING NOTE: - * - * Backslashes quote delimiter characters for RE's. - * The backslashes are NOT removed since they'll be - * used by the RE code. Move to the third delimiter - * that's not escaped (or the end of the command). - */ - delim = *ecp->cp; - ++ecp->cp; - --ecp->clen; - for (cnt = 2; ecp->clen > 0 && - cnt != 0; --ecp->clen, ++ecp->cp) - if (ecp->cp[0] == '\\' && - ecp->clen > 1) { - ++ecp->cp; - --ecp->clen; - } else if (ecp->cp[0] == delim) - --cnt; - } - } - - /* - * Use normal quoting and termination rules to find the end of this - * command. - * - * QUOTING NOTE: - * - * Historically, vi permitted ^V's to escape <newline>'s in the .exrc - * file. It was almost certainly a bug, but that's what bug-for-bug - * compatibility means, Grasshopper. Also, ^V's escape the command - * delimiters. Literal next quote characters in front of the newlines, - * '|' characters or literal next characters are stripped as they're - * no longer useful. - */ - vi_address = ecp->clen != 0 && ecp->cp[0] != '\n'; - for (p = ecp->cp; ecp->clen > 0; --ecp->clen, ++ecp->cp) { - ch = ecp->cp[0]; - if (IS_ESCAPE(sp, ecp, ch) && ecp->clen > 1) { - tmp = ecp->cp[1]; - if (tmp == '\n' || tmp == '|') { - if (tmp == '\n') { - ++gp->if_lno; - ++ecp->if_lno; - } - ++discard; - --ecp->clen; - ++ecp->cp; - ch = tmp; - } - } else if (ch == '\n' || ch == '|') { - if (ch == '\n') - F_SET(ecp, E_NEWLINE); - --ecp->clen; - break; - } - *p++ = ch; - } - - /* - * Save off the next command information, go back to the - * original start of the command. - */ - p = ecp->cp + 1; - ecp->cp = ecp->save_cmd; - ecp->save_cmd = p; - ecp->save_cmdlen = ecp->clen; - ecp->clen = ((ecp->save_cmd - ecp->cp) - 1) - discard; - - /* - * QUOTING NOTE: - * - * The "set tags" command historically used a backslash, not the - * user's literal next character, to escape whitespace. Handle - * it here instead of complicating the argv_exp3() code. Note, - * this isn't a particularly complex trap, and if backslashes were - * legal in set commands, this would have to be much more complicated. - */ - if (ecp->cmd == &cmds[C_SET]) - for (p = ecp->cp, len = ecp->clen; len > 0; --len, ++p) - if (*p == '\\') - *p = CH_LITERAL; - - /* - * Set the default addresses. It's an error to specify an address for - * a command that doesn't take them. If two addresses are specified - * for a command that only takes one, lose the first one. Two special - * cases here, some commands take 0 or 2 addresses. For most of them - * (the E_ADDR2_ALL flag), 0 defaults to the entire file. For one - * (the `!' command, the E_ADDR2_NONE flag), 0 defaults to no lines. - * - * Also, if the file is empty, some commands want to use an address of - * 0, i.e. the entire file is 0 to 0, and the default first address is - * 0. Otherwise, an entire file is 1 to N and the default line is 1. - * Note, we also add the E_ADDR_ZERO flag to the command flags, for the - * case where the 0 address is only valid if it's a default address. - * - * Also, set a flag if we set the default addresses. Some commands - * (ex: z) care if the user specified an address or if we just used - * the current cursor. - */ - switch (F_ISSET(ecp, E_ADDR1 | E_ADDR2 | E_ADDR2_ALL | E_ADDR2_NONE)) { - case E_ADDR1: /* One address: */ - switch (ecp->addrcnt) { - case 0: /* Default cursor/empty file. */ - ecp->addrcnt = 1; - F_SET(ecp, E_ADDR_DEF); - if (F_ISSET(ecp, E_ADDR_ZERODEF)) { - if (db_last(sp, &lno)) - goto err; - if (lno == 0) { - ecp->addr1.lno = 0; - F_SET(ecp, E_ADDR_ZERO); - } else - ecp->addr1.lno = sp->lno; - } else - ecp->addr1.lno = sp->lno; - ecp->addr1.cno = sp->cno; - break; - case 1: - break; - case 2: /* Lose the first address. */ - ecp->addrcnt = 1; - ecp->addr1 = ecp->addr2; - } - break; - case E_ADDR2_NONE: /* Zero/two addresses: */ - if (ecp->addrcnt == 0) /* Default to nothing. */ - break; - goto two_addr; - case E_ADDR2_ALL: /* Zero/two addresses: */ - if (ecp->addrcnt == 0) { /* Default entire/empty file. */ - F_SET(ecp, E_ADDR_DEF); - ecp->addrcnt = 2; - if (sp->ep == NULL) - ecp->addr2.lno = 0; - else if (db_last(sp, &ecp->addr2.lno)) - goto err; - if (F_ISSET(ecp, E_ADDR_ZERODEF) && - ecp->addr2.lno == 0) { - ecp->addr1.lno = 0; - F_SET(ecp, E_ADDR_ZERO); - } else - ecp->addr1.lno = 1; - ecp->addr1.cno = ecp->addr2.cno = 0; - F_SET(ecp, E_ADDR2_ALL); - break; - } - /* FALLTHROUGH */ - case E_ADDR2: /* Two addresses: */ -two_addr: switch (ecp->addrcnt) { - case 0: /* Default cursor/empty file. */ - ecp->addrcnt = 2; - F_SET(ecp, E_ADDR_DEF); - if (sp->lno == 1 && - F_ISSET(ecp, E_ADDR_ZERODEF)) { - if (db_last(sp, &lno)) - goto err; - if (lno == 0) { - ecp->addr1.lno = ecp->addr2.lno = 0; - F_SET(ecp, E_ADDR_ZERO); - } else - ecp->addr1.lno = - ecp->addr2.lno = sp->lno; - } else - ecp->addr1.lno = ecp->addr2.lno = sp->lno; - ecp->addr1.cno = ecp->addr2.cno = sp->cno; - break; - case 1: /* Default to first address. */ - ecp->addrcnt = 2; - ecp->addr2 = ecp->addr1; - break; - case 2: - break; - } - break; - default: - if (ecp->addrcnt) /* Error. */ - goto usage; - } - - /* - * !!! - * The ^D scroll command historically scrolled the value of the scroll - * option or to EOF. It was an error if the cursor was already at EOF. - * (Leading addresses were permitted, but were then ignored.) - */ - if (ecp->cmd == &cmds[C_SCROLL]) { - ecp->addrcnt = 2; - ecp->addr1.lno = sp->lno + 1; - ecp->addr2.lno = sp->lno + O_VAL(sp, O_SCROLL); - ecp->addr1.cno = ecp->addr2.cno = sp->cno; - if (db_last(sp, &lno)) - goto err; - if (lno != 0 && lno > sp->lno && ecp->addr2.lno > lno) - ecp->addr2.lno = lno; - } - - ecp->flagoff = 0; - for (p = ecp->cmd->syntax; *p != '\0'; ++p) { - /* - * The force flag is sensitive to leading whitespace, i.e. - * "next !" is different from "next!". Handle it before - * skipping leading <blank>s. - */ - if (*p == '!') { - if (ecp->clen > 0 && *ecp->cp == '!') { - ++ecp->cp; - --ecp->clen; - FL_SET(ecp->iflags, E_C_FORCE); - } - continue; - } - - /* Skip leading <blank>s. */ - for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) - if (!isblank(*ecp->cp)) - break; - if (ecp->clen == 0) - break; - - switch (*p) { - case '1': /* +, -, #, l, p */ - /* - * !!! - * Historically, some flags were ignored depending - * on where they occurred in the command line. For - * example, in the command, ":3+++p--#", historic vi - * acted on the '#' flag, but ignored the '-' flags. - * It's unambiguous what the flags mean, so we just - * handle them regardless of the stupidity of their - * location. - */ - for (; ecp->clen; --ecp->clen, ++ecp->cp) - switch (*ecp->cp) { - case '+': - ++ecp->flagoff; - break; - case '-': - case '^': - --ecp->flagoff; - break; - case '#': - F_CLR(ecp, E_OPTNUM); - FL_SET(ecp->iflags, E_C_HASH); - exp->fdef |= E_C_HASH; - break; - case 'l': - FL_SET(ecp->iflags, E_C_LIST); - exp->fdef |= E_C_LIST; - break; - case 'p': - FL_SET(ecp->iflags, E_C_PRINT); - exp->fdef |= E_C_PRINT; - break; - default: - goto end_case1; - } -end_case1: break; - case '2': /* -, ., +, ^ */ - case '3': /* -, ., +, ^, = */ - for (; ecp->clen; --ecp->clen, ++ecp->cp) - switch (*ecp->cp) { - case '-': - FL_SET(ecp->iflags, E_C_DASH); - break; - case '.': - FL_SET(ecp->iflags, E_C_DOT); - break; - case '+': - FL_SET(ecp->iflags, E_C_PLUS); - break; - case '^': - FL_SET(ecp->iflags, E_C_CARAT); - break; - case '=': - if (*p == '3') { - FL_SET(ecp->iflags, E_C_EQUAL); - break; - } - /* FALLTHROUGH */ - default: - goto end_case23; - } -end_case23: break; - case 'b': /* buffer */ - /* - * !!! - * Historically, "d #" was a delete with a flag, not a - * delete into the '#' buffer. If the current command - * permits a flag, don't use one as a buffer. However, - * the 'l' and 'p' flags were legal buffer names in the - * historic ex, and were used as buffers, not flags. - */ - if ((ecp->cp[0] == '+' || ecp->cp[0] == '-' || - ecp->cp[0] == '^' || ecp->cp[0] == '#') && - strchr(p, '1') != NULL) - break; - /* - * !!! - * Digits can't be buffer names in ex commands, or the - * command "d2" would be a delete into buffer '2', and - * not a two-line deletion. - */ - if (!isdigit(ecp->cp[0])) { - ecp->buffer = *ecp->cp; - ++ecp->cp; - --ecp->clen; - FL_SET(ecp->iflags, E_C_BUFFER); - } - break; - case 'c': /* count [01+a] */ - ++p; - /* Validate any signed value. */ - if (!isdigit(*ecp->cp) && (*p != '+' || - (*ecp->cp != '+' && *ecp->cp != '-'))) - break; - /* If a signed value, set appropriate flags. */ - if (*ecp->cp == '-') - FL_SET(ecp->iflags, E_C_COUNT_NEG); - else if (*ecp->cp == '+') - FL_SET(ecp->iflags, E_C_COUNT_POS); - if ((nret = - nget_slong(<mp, ecp->cp, &t, 10)) != NUM_OK) { - ex_badaddr(sp, NULL, A_NOTSET, nret); - goto err; - } - if (ltmp == 0 && *p != '0') { - msgq(sp, M_ERR, "083|Count may not be zero"); - goto err; - } - ecp->clen -= (t - ecp->cp); - ecp->cp = t; - - /* - * Counts as address offsets occur in commands taking - * two addresses. Historic vi practice was to use - * the count as an offset from the *second* address. - * - * Set a count flag; some underlying commands (see - * join) do different things with counts than with - * line addresses. - */ - if (*p == 'a') { - ecp->addr1 = ecp->addr2; - ecp->addr2.lno = ecp->addr1.lno + ltmp - 1; - } else - ecp->count = ltmp; - FL_SET(ecp->iflags, E_C_COUNT); - break; - case 'f': /* file */ - if (argv_exp2(sp, ecp, ecp->cp, ecp->clen)) - goto err; - goto arg_cnt_chk; - case 'l': /* line */ - /* - * Get a line specification. - * - * If the line was a search expression, we may have - * changed state during the call, and we're now - * searching the file. Push ourselves onto the state - * stack. - */ - if (ex_line(sp, ecp, &cur, &isaddr, &tmp)) - goto rfail; - if (tmp) - goto err; - - /* Line specifications are always required. */ - if (!isaddr) { - msgq_str(sp, M_ERR, ecp->cp, - "084|%s: bad line specification"); - goto err; - } - /* - * The target line should exist for these commands, - * but 0 is legal for them as well. - */ - if (cur.lno != 0 && !db_exist(sp, cur.lno)) { - ex_badaddr(sp, NULL, A_EOF, NUM_OK); - goto err; - } - ecp->lineno = cur.lno; - break; - case 'S': /* string, file exp. */ - if (ecp->clen != 0) { - if (argv_exp1(sp, ecp, ecp->cp, - ecp->clen, ecp->cmd == &cmds[C_BANG])) - goto err; - goto addr_verify; - } - /* FALLTHROUGH */ - case 's': /* string */ - if (argv_exp0(sp, ecp, ecp->cp, ecp->clen)) - goto err; - goto addr_verify; - case 'W': /* word string */ - /* - * QUOTING NOTE: - * - * Literal next characters escape the following - * character. Quoting characters are stripped here - * since they are no longer useful. - * - * First there was the word. - */ - for (p = t = ecp->cp; - ecp->clen > 0; --ecp->clen, ++ecp->cp) { - ch = *ecp->cp; - if (IS_ESCAPE(sp, - ecp, ch) && ecp->clen > 1) { - --ecp->clen; - *p++ = *++ecp->cp; - } else if (isblank(ch)) { - ++ecp->cp; - --ecp->clen; - break; - } else - *p++ = ch; - } - if (argv_exp0(sp, ecp, t, p - t)) - goto err; - - /* Delete intervening whitespace. */ - for (; ecp->clen > 0; - --ecp->clen, ++ecp->cp) { - ch = *ecp->cp; - if (!isblank(ch)) - break; - } - if (ecp->clen == 0) - goto usage; - - /* Followed by the string. */ - for (p = t = ecp->cp; ecp->clen > 0; - --ecp->clen, ++ecp->cp, ++p) { - ch = *ecp->cp; - if (IS_ESCAPE(sp, - ecp, ch) && ecp->clen > 1) { - --ecp->clen; - *p = *++ecp->cp; - } else - *p = ch; - } - if (argv_exp0(sp, ecp, t, p - t)) - goto err; - goto addr_verify; - case 'w': /* word */ - if (argv_exp3(sp, ecp, ecp->cp, ecp->clen)) - goto err; -arg_cnt_chk: if (*++p != 'N') { /* N */ - /* - * If a number is specified, must either be - * 0 or that number, if optional, and that - * number, if required. - */ - tmp = *p - '0'; - if ((*++p != 'o' || exp->argsoff != 0) && - exp->argsoff != tmp) - goto usage; - } - goto addr_verify; - default: - msgq(sp, M_ERR, - "085|Internal syntax table error (%s: %s)", - ecp->cmd->name, KEY_NAME(sp, *p)); - } - } - - /* Skip trailing whitespace. */ - for (; ecp->clen > 0; --ecp->clen) { - ch = *ecp->cp++; - if (!isblank(ch)) - break; - } - - /* - * There shouldn't be anything left, and no more required fields, - * i.e neither 'l' or 'r' in the syntax string. - */ - if (ecp->clen != 0 || strpbrk(p, "lr")) { -usage: msgq(sp, M_ERR, "086|Usage: %s", ecp->cmd->usage); - goto err; - } - - /* - * Verify that the addresses are legal. Check the addresses here, - * because this is a place where all ex addresses pass through. - * (They don't all pass through ex_line(), for instance.) We're - * assuming that any non-existent line doesn't exist because it's - * past the end-of-file. That's a pretty good guess. - * - * If it's a "default vi command", an address of zero is okay. - */ -addr_verify: - switch (ecp->addrcnt) { - case 2: - /* - * Historic ex/vi permitted commands with counts to go past - * EOF. So, for example, if the file only had 5 lines, the - * ex command "1,6>" would fail, but the command ">300" - * would succeed. Since we don't want to have to make all - * of the underlying commands handle random line numbers, - * fix it here. - */ - if (ecp->addr2.lno == 0) { - if (!F_ISSET(ecp, E_ADDR_ZERO) && - (F_ISSET(sp, SC_EX) || - !F_ISSET(ecp, E_USELASTCMD))) { - ex_badaddr(sp, ecp->cmd, A_ZERO, NUM_OK); - goto err; - } - } else if (!db_exist(sp, ecp->addr2.lno)) - if (FL_ISSET(ecp->iflags, E_C_COUNT)) { - if (db_last(sp, &lno)) - goto err; - ecp->addr2.lno = lno; - } else { - ex_badaddr(sp, NULL, A_EOF, NUM_OK); - goto err; - } - /* FALLTHROUGH */ - case 1: - if (ecp->addr1.lno == 0) { - if (!F_ISSET(ecp, E_ADDR_ZERO) && - (F_ISSET(sp, SC_EX) || - !F_ISSET(ecp, E_USELASTCMD))) { - ex_badaddr(sp, ecp->cmd, A_ZERO, NUM_OK); - goto err; - } - } else if (!db_exist(sp, ecp->addr1.lno)) { - ex_badaddr(sp, NULL, A_EOF, NUM_OK); - goto err; - } - break; - } - - /* - * If doing a default command and there's nothing left on the line, - * vi just moves to the line. For example, ":3" and ":'a,'b" just - * move to line 3 and line 'b, respectively, but ":3|" prints line 3. - * - * !!! - * In addition, IF THE LINE CHANGES, move to the first nonblank of - * the line. - * - * !!! - * This is done before the absolute mark gets set; historically, - * "/a/,/b/" did NOT set vi's absolute mark, but "/a/,/b/d" did. - */ - if ((F_ISSET(sp, SC_VI) || F_ISSET(ecp, E_NOPRDEF)) && - F_ISSET(ecp, E_USELASTCMD) && vi_address == 0) { - switch (ecp->addrcnt) { - case 2: - if (sp->lno != - (ecp->addr2.lno ? ecp->addr2.lno : 1)) { - sp->lno = - ecp->addr2.lno ? ecp->addr2.lno : 1; - sp->cno = 0; - (void)nonblank(sp, sp->lno, &sp->cno); - } - break; - case 1: - if (sp->lno != - (ecp->addr1.lno ? ecp->addr1.lno : 1)) { - sp->lno = - ecp->addr1.lno ? ecp->addr1.lno : 1; - sp->cno = 0; - (void)nonblank(sp, sp->lno, &sp->cno); - } - break; - } - ecp->cp = ecp->save_cmd; - ecp->clen = ecp->save_cmdlen; - goto loop; - } - - /* - * Set the absolute mark -- we have to set it for vi here, in case - * it's a compound command, e.g. ":5p|6" should set the absolute - * mark for vi. - */ - if (F_ISSET(ecp, E_ABSMARK)) { - cur.lno = sp->lno; - cur.cno = sp->cno; - F_CLR(ecp, E_ABSMARK); - if (mark_set(sp, ABSMARK1, &cur, 1)) - goto err; - } - -#if defined(DEBUG) && defined(COMLOG) - ex_comlog(sp, ecp); -#endif - /* Increment the command count if not called from vi. */ - if (F_ISSET(sp, SC_EX)) - ++sp->ccnt; - - /* - * If file state available, and not doing a global command, - * log the start of an action. - */ - if (sp->ep != NULL && !F_ISSET(sp, SC_EX_GLOBAL)) - (void)log_cursor(sp); - - /* - * !!! - * There are two special commands for the purposes of this code: the - * default command (<carriage-return>) or the scrolling commands (^D - * and <EOF>) as the first non-<blank> characters in the line. - * - * If this is the first command in the command line, we received the - * command from the ex command loop and we're talking to a tty, and - * and there's nothing else on the command line, and it's one of the - * special commands, we move back up to the previous line, and erase - * the prompt character with the output. Since ex runs in canonical - * mode, we don't have to do anything else, a <newline> has already - * been echoed by the tty driver. It's OK if vi calls us -- we won't - * be in ex mode so we'll do nothing. - */ - if (F_ISSET(ecp, E_NRSEP)) { - if (sp->ep != NULL && - F_ISSET(sp, SC_EX) && !F_ISSET(gp, G_SCRIPTED) && - (F_ISSET(ecp, E_USELASTCMD) || ecp->cmd == &cmds[C_SCROLL])) - gp->scr_ex_adjust(sp, EX_TERM_SCROLL); - F_CLR(ecp, E_NRSEP); - } - - /* - * Call the underlying function for the ex command. - * - * XXX - * Interrupts behave like errors, for now. - */ - if (ecp->cmd->fn(sp, ecp) || INTERRUPTED(sp)) { - if (F_ISSET(gp, G_SCRIPTED)) - F_SET(sp, SC_EXIT_FORCE); - goto err; - } - -#ifdef DEBUG - /* Make sure no function left global temporary space locked. */ - if (F_ISSET(gp, G_TMP_INUSE)) { - F_CLR(gp, G_TMP_INUSE); - msgq(sp, M_ERR, "087|%s: temporary buffer not released", - ecp->cmd->name); - } -#endif - /* - * Ex displayed the number of lines modified immediately after each - * command, so the command "1,10d|1,10d" would display: - * - * 10 lines deleted - * 10 lines deleted - * <autoprint line> - * - * Executing ex commands from vi only reported the final modified - * lines message -- that's wrong enough that we don't match it. - */ - if (F_ISSET(sp, SC_EX)) - mod_rpt(sp); - - /* - * Integrate any offset parsed by the underlying command, and make - * sure the referenced line exists. - * - * XXX - * May not match historic practice (which I've never been able to - * completely figure out.) For example, the '=' command from vi - * mode often got the offset wrong, and complained it was too large, - * but didn't seem to have a problem with the cursor. If anyone - * complains, ask them how it's supposed to work, they might know. - */ - if (sp->ep != NULL && ecp->flagoff) { - if (ecp->flagoff < 0) { - if (sp->lno <= -ecp->flagoff) { - msgq(sp, M_ERR, - "088|Flag offset to before line 1"); - goto err; - } - } else { - if (!NPFITS(MAX_REC_NUMBER, sp->lno, ecp->flagoff)) { - ex_badaddr(sp, NULL, A_NOTSET, NUM_OVER); - goto err; - } - if (!db_exist(sp, sp->lno + ecp->flagoff)) { - msgq(sp, M_ERR, - "089|Flag offset past end-of-file"); - goto err; - } - } - sp->lno += ecp->flagoff; - } - - /* - * If the command executed successfully, we may want to display a line - * based on the autoprint option or an explicit print flag. (Make sure - * that there's a line to display.) Also, the autoprint edit option is - * turned off for the duration of global commands. - */ - if (F_ISSET(sp, SC_EX) && sp->ep != NULL && sp->lno != 0) { - /* - * The print commands have already handled the `print' flags. - * If so, clear them. - */ - if (FL_ISSET(ecp->iflags, E_CLRFLAG)) - FL_CLR(ecp->iflags, E_C_HASH | E_C_LIST | E_C_PRINT); - - /* If hash set only because of the number option, discard it. */ - if (F_ISSET(ecp, E_OPTNUM)) - FL_CLR(ecp->iflags, E_C_HASH); - - /* - * If there was an explicit flag to display the new cursor line, - * or autoprint is set and a change was made, display the line. - * If any print flags were set use them, else default to print. - */ - LF_INIT(FL_ISSET(ecp->iflags, E_C_HASH | E_C_LIST | E_C_PRINT)); - if (!LF_ISSET(E_C_HASH | E_C_LIST | E_C_PRINT | E_NOAUTO) && - !F_ISSET(sp, SC_EX_GLOBAL) && - O_ISSET(sp, O_AUTOPRINT) && F_ISSET(ecp, E_AUTOPRINT)) - LF_INIT(E_C_PRINT); - - if (LF_ISSET(E_C_HASH | E_C_LIST | E_C_PRINT)) { - cur.lno = sp->lno; - cur.cno = 0; - (void)ex_print(sp, ecp, &cur, &cur, flags); - } - } - - /* - * If the command had an associated "+cmd", it has to be executed - * before we finish executing any more of this ex command. For - * example, consider a .exrc file that contains the following lines: - * - * :set all - * :edit +25 file.c|s/abc/ABC/|1 - * :3,5 print - * - * This can happen more than once -- the historic vi simply hung or - * dropped core, of course. Prepend the + command back into the - * current command and continue. We may have to add an additional - * <literal next> character. We know that it will fit because we - * discarded at least one space and the + character. - */ - if (arg1_len != 0) { - /* - * If the last character of the + command was a <literal next> - * character, it would be treated differently because of the - * append. Quote it, if necessary. - */ - if (IS_ESCAPE(sp, ecp, arg1[arg1_len - 1])) { - *--ecp->save_cmd = CH_LITERAL; - ++ecp->save_cmdlen; - } - - ecp->save_cmd -= arg1_len; - ecp->save_cmdlen += arg1_len; - memcpy(ecp->save_cmd, arg1, arg1_len); - - /* - * Any commands executed from a +cmd are executed starting at - * the first column of the last line of the file -- NOT the - * first nonblank.) The main file startup code doesn't know - * that a +cmd was set, however, so it may have put us at the - * top of the file. (Note, this is safe because we must have - * switched files to get here.) - */ - F_SET(ecp, E_MOVETOEND); - } - - /* Update the current command. */ - ecp->cp = ecp->save_cmd; - ecp->clen = ecp->save_cmdlen; - - /* - * !!! - * If we've changed screens or underlying files, any pending global or - * v command, or @ buffer that has associated addresses, has to be - * discarded. This is historic practice for globals, and necessary for - * @ buffers that had associated addresses. - * - * Otherwise, if we've changed underlying files, it's not a problem, - * we continue with the rest of the ex command(s), operating on the - * new file. However, if we switch screens (either by exiting or by - * an explicit command), we have no way of knowing where to put output - * messages, and, since we don't control screens here, we could screw - * up the upper layers, (e.g. we could exit/reenter a screen multiple - * times). So, return and continue after we've got a new screen. - */ - if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE | SC_FSWITCH | SC_SSWITCH)) { - at_found = gv_found = 0; - for (ecp = sp->gp->ecq.lh_first; - ecp != NULL; ecp = ecp->q.le_next) - switch (ecp->agv_flags) { - case 0: - case AGV_AT_NORANGE: - break; - case AGV_AT: - if (!at_found) { - at_found = 1; - msgq(sp, M_ERR, - "090|@ with range running when the file/screen changed"); - } - break; - case AGV_GLOBAL: - case AGV_V: - if (!gv_found) { - gv_found = 1; - msgq(sp, M_ERR, - "091|Global/v command running when the file/screen changed"); - } - break; - default: - abort(); - } - if (at_found || gv_found) - goto discard; - if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE | SC_SSWITCH)) - goto rsuccess; - } - - goto loop; - /* NOTREACHED */ - -err: /* - * On command failure, we discard keys and pending commands remaining, - * as well as any keys that were mapped and waiting. The save_cmdlen - * test is not necessarily correct. If we fail early enough we don't - * know if the entire string was a single command or not. Guess, as - * it's useful to know if commands other than the current one are being - * discarded. - */ - if (ecp->save_cmdlen == 0) - for (; ecp->clen; --ecp->clen) { - ch = *ecp->cp++; - if (IS_ESCAPE(sp, ecp, ch) && ecp->clen > 1) { - --ecp->clen; - ++ecp->cp; - } else if (ch == '\n' || ch == '|') { - if (ecp->clen > 1) - ecp->save_cmdlen = 1; - break; - } - } - if (ecp->save_cmdlen != 0 || gp->ecq.lh_first != &gp->excmd) { -discard: msgq(sp, M_BERR, - "092|Ex command failed: pending commands discarded"); - ex_discard(sp); - } - if (v_event_flush(sp, CH_MAPPED)) - msgq(sp, M_BERR, - "093|Ex command failed: mapped keys discarded"); - -rfail: tmp = 1; - if (0) -rsuccess: tmp = 0; - - /* Turn off any file name error information. */ - gp->if_name = NULL; - - /* Turn off the global bit. */ - F_CLR(sp, SC_EX_GLOBAL); - - return (tmp); -} - -/* - * ex_range -- - * Get a line range for ex commands, or perform a vi ex address search. - * - * PUBLIC: int ex_range __P((SCR *, EXCMD *, int *)); - */ -int -ex_range(sp, ecp, errp) - SCR *sp; - EXCMD *ecp; - int *errp; -{ - enum { ADDR_FOUND, ADDR_NEED, ADDR_NONE } addr; - GS *gp; - EX_PRIVATE *exp; - MARK m; - int isaddr; - - *errp = 0; - - /* - * Parse comma or semi-colon delimited line specs. - * - * Semi-colon delimiters update the current address to be the last - * address. For example, the command - * - * :3;/pattern/ecp->cp - * - * will search for pattern from line 3. In addition, if ecp->cp - * is not a valid command, the current line will be left at 3, not - * at the original address. - * - * Extra addresses are discarded, starting with the first. - * - * !!! - * If any addresses are missing, they default to the current line. - * This was historically true for both leading and trailing comma - * delimited addresses as well as for trailing semicolon delimited - * addresses. For consistency, we make it true for leading semicolon - * addresses as well. - */ - gp = sp->gp; - exp = EXP(sp); - for (addr = ADDR_NONE, ecp->addrcnt = 0; ecp->clen > 0;) - switch (*ecp->cp) { - case '%': /* Entire file. */ - /* Vi ex address searches didn't permit % signs. */ - if (F_ISSET(ecp, E_VISEARCH)) - goto ret; - - /* It's an error if the file is empty. */ - if (sp->ep == NULL) { - ex_badaddr(sp, NULL, A_EMPTY, NUM_OK); - *errp = 1; - return (0); - } - /* - * !!! - * A percent character addresses all of the lines in - * the file. Historically, it couldn't be followed by - * any other address. We do it as a text substitution - * for simplicity. POSIX 1003.2 is expected to follow - * this practice. - * - * If it's an empty file, the first line is 0, not 1. - */ - if (addr == ADDR_FOUND) { - ex_badaddr(sp, NULL, A_COMBO, NUM_OK); - *errp = 1; - return (0); - } - if (db_last(sp, &ecp->addr2.lno)) - return (1); - ecp->addr1.lno = ecp->addr2.lno == 0 ? 0 : 1; - ecp->addr1.cno = ecp->addr2.cno = 0; - ecp->addrcnt = 2; - addr = ADDR_FOUND; - ++ecp->cp; - --ecp->clen; - break; - case ',': /* Comma delimiter. */ - /* Vi ex address searches didn't permit commas. */ - if (F_ISSET(ecp, E_VISEARCH)) - goto ret; - /* FALLTHROUGH */ - case ';': /* Semi-colon delimiter. */ - if (sp->ep == NULL) { - ex_badaddr(sp, NULL, A_EMPTY, NUM_OK); - *errp = 1; - return (0); - } - if (addr != ADDR_FOUND) - switch (ecp->addrcnt) { - case 0: - ecp->addr1.lno = sp->lno; - ecp->addr1.cno = sp->cno; - ecp->addrcnt = 1; - break; - case 2: - ecp->addr1 = ecp->addr2; - /* FALLTHROUGH */ - case 1: - ecp->addr2.lno = sp->lno; - ecp->addr2.cno = sp->cno; - ecp->addrcnt = 2; - break; - } - if (*ecp->cp == ';') - switch (ecp->addrcnt) { - case 0: - abort(); - /* NOTREACHED */ - case 1: - sp->lno = ecp->addr1.lno; - sp->cno = ecp->addr1.cno; - break; - case 2: - sp->lno = ecp->addr2.lno; - sp->cno = ecp->addr2.cno; - break; - } - addr = ADDR_NEED; - /* FALLTHROUGH */ - case ' ': /* Whitespace. */ - case '\t': /* Whitespace. */ - ++ecp->cp; - --ecp->clen; - break; - default: - /* Get a line specification. */ - if (ex_line(sp, ecp, &m, &isaddr, errp)) - return (1); - if (*errp) - return (0); - if (!isaddr) - goto ret; - if (addr == ADDR_FOUND) { - ex_badaddr(sp, NULL, A_COMBO, NUM_OK); - *errp = 1; - return (0); - } - switch (ecp->addrcnt) { - case 0: - ecp->addr1 = m; - ecp->addrcnt = 1; - break; - case 1: - ecp->addr2 = m; - ecp->addrcnt = 2; - break; - case 2: - ecp->addr1 = ecp->addr2; - ecp->addr2 = m; - break; - } - addr = ADDR_FOUND; - break; - } - - /* - * !!! - * Vi ex address searches are indifferent to order or trailing - * semi-colons. - */ -ret: if (F_ISSET(ecp, E_VISEARCH)) - return (0); - - if (addr == ADDR_NEED) - switch (ecp->addrcnt) { - case 0: - ecp->addr1.lno = sp->lno; - ecp->addr1.cno = sp->cno; - ecp->addrcnt = 1; - break; - case 2: - ecp->addr1 = ecp->addr2; - /* FALLTHROUGH */ - case 1: - ecp->addr2.lno = sp->lno; - ecp->addr2.cno = sp->cno; - ecp->addrcnt = 2; - break; - } - - if (ecp->addrcnt == 2 && ecp->addr2.lno < ecp->addr1.lno) { - msgq(sp, M_ERR, - "094|The second address is smaller than the first"); - *errp = 1; - } - return (0); -} - -/* - * ex_line -- - * Get a single line address specifier. - * - * The way the "previous context" mark worked was that any "non-relative" - * motion set it. While ex/vi wasn't totally consistent about this, ANY - * numeric address, search pattern, '$', or mark reference in an address - * was considered non-relative, and set the value. Which should explain - * why we're hacking marks down here. The problem was that the mark was - * only set if the command was called, i.e. we have to set a flag and test - * it later. - * - * XXX - * This is probably still not exactly historic practice, although I think - * it's fairly close. - */ -static int -ex_line(sp, ecp, mp, isaddrp, errp) - SCR *sp; - EXCMD *ecp; - MARK *mp; - int *isaddrp, *errp; -{ - enum nresult nret; - EX_PRIVATE *exp; - GS *gp; - long total, val; - int isneg; - int (*sf) __P((SCR *, MARK *, MARK *, char *, size_t, char **, u_int)); - char *endp; - - gp = sp->gp; - exp = EXP(sp); - - *isaddrp = *errp = 0; - F_CLR(ecp, E_DELTA); - - /* No addresses permitted until a file has been read in. */ - if (sp->ep == NULL && strchr("$0123456789'\\/?.+-^", *ecp->cp)) { - ex_badaddr(sp, NULL, A_EMPTY, NUM_OK); - *errp = 1; - return (0); - } - - switch (*ecp->cp) { - case '$': /* Last line in the file. */ - *isaddrp = 1; - F_SET(ecp, E_ABSMARK); - - mp->cno = 0; - if (db_last(sp, &mp->lno)) - return (1); - ++ecp->cp; - --ecp->clen; - break; /* Absolute line number. */ - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - *isaddrp = 1; - F_SET(ecp, E_ABSMARK); - - if ((nret = nget_slong(&val, ecp->cp, &endp, 10)) != NUM_OK) { - ex_badaddr(sp, NULL, A_NOTSET, nret); - *errp = 1; - return (0); - } - if (!NPFITS(MAX_REC_NUMBER, 0, val)) { - ex_badaddr(sp, NULL, A_NOTSET, NUM_OVER); - *errp = 1; - return (0); - } - mp->lno = val; - mp->cno = 0; - ecp->clen -= (endp - ecp->cp); - ecp->cp = endp; - break; - case '\'': /* Use a mark. */ - *isaddrp = 1; - F_SET(ecp, E_ABSMARK); - - if (ecp->clen == 1) { - msgq(sp, M_ERR, "095|No mark name supplied"); - *errp = 1; - return (0); - } - if (mark_get(sp, ecp->cp[1], mp, M_ERR)) { - *errp = 1; - return (0); - } - ecp->cp += 2; - ecp->clen -= 2; - break; - case '\\': /* Search: forward/backward. */ - /* - * !!! - * I can't find any difference between // and \/ or between - * ?? and \?. Mark Horton doesn't remember there being any - * difference. C'est la vie. - */ - if (ecp->clen < 2 || - ecp->cp[1] != '/' && ecp->cp[1] != '?') { - msgq(sp, M_ERR, "096|\\ not followed by / or ?"); - *errp = 1; - return (0); - } - ++ecp->cp; - --ecp->clen; - sf = ecp->cp[0] == '/' ? f_search : b_search; - goto search; - case '/': /* Search forward. */ - sf = f_search; - goto search; - case '?': /* Search backward. */ - sf = b_search; - -search: mp->lno = sp->lno; - mp->cno = sp->cno; - if (sf(sp, mp, mp, ecp->cp, ecp->clen, &endp, - SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | - (F_ISSET(ecp, E_SEARCH_WMSG) ? SEARCH_WMSG : 0))) { - *errp = 1; - return (0); - } - - /* Fix up the command pointers. */ - ecp->clen -= (endp - ecp->cp); - ecp->cp = endp; - - *isaddrp = 1; - F_SET(ecp, E_ABSMARK); - break; - case '.': /* Current position. */ - *isaddrp = 1; - mp->cno = sp->cno; - - /* If an empty file, then '.' is 0, not 1. */ - if (sp->lno == 1) { - if (db_last(sp, &mp->lno)) - return (1); - if (mp->lno != 0) - mp->lno = 1; - } else - mp->lno = sp->lno; - - /* - * !!! - * Historically, .<number> was the same as .+<number>, i.e. - * the '+' could be omitted. (This feature is found in ed - * as well.) - */ - if (ecp->clen > 1 && isdigit(ecp->cp[1])) - *ecp->cp = '+'; - else { - ++ecp->cp; - --ecp->clen; - } - break; - } - - /* Skip trailing <blank>s. */ - for (; ecp->clen > 0 && - isblank(ecp->cp[0]); ++ecp->cp, --ecp->clen); - - /* - * Evaluate any offset. If no address yet found, the offset - * is relative to ".". - */ - total = 0; - if (ecp->clen != 0 && (isdigit(ecp->cp[0]) || - ecp->cp[0] == '+' || ecp->cp[0] == '-' || - ecp->cp[0] == '^')) { - if (!*isaddrp) { - *isaddrp = 1; - mp->lno = sp->lno; - mp->cno = sp->cno; - } - /* - * Evaluate an offset, defined as: - * - * [+-^<blank>]*[<blank>]*[0-9]* - * - * The rough translation is any number of signs, optionally - * followed by numbers, or a number by itself, all <blank> - * separated. - * - * !!! - * All address offsets were additive, e.g. "2 2 3p" was the - * same as "7p", or, "/ZZZ/ 2" was the same as "/ZZZ/+2". - * Note, however, "2 /ZZZ/" was an error. It was also legal - * to insert signs without numbers, so "3 - 2" was legal, and - * equal to 4. - * - * !!! - * Offsets were historically permitted for any line address, - * e.g. the command "1,2 copy 2 2 2 2" copied lines 1,2 after - * line 8. - * - * !!! - * Offsets were historically permitted for search commands, - * and handled as addresses: "/pattern/2 2 2" was legal, and - * referenced the 6th line after pattern. - */ - F_SET(ecp, E_DELTA); - for (;;) { - for (; ecp->clen > 0 && isblank(ecp->cp[0]); - ++ecp->cp, --ecp->clen); - if (ecp->clen == 0 || !isdigit(ecp->cp[0]) && - ecp->cp[0] != '+' && ecp->cp[0] != '-' && - ecp->cp[0] != '^') - break; - if (!isdigit(ecp->cp[0]) && - !isdigit(ecp->cp[1])) { - total += ecp->cp[0] == '+' ? 1 : -1; - --ecp->clen; - ++ecp->cp; - } else { - if (ecp->cp[0] == '-' || - ecp->cp[0] == '^') { - ++ecp->cp; - --ecp->clen; - isneg = 1; - } else - isneg = 0; - - /* Get a signed long, add it to the total. */ - if ((nret = nget_slong(&val, - ecp->cp, &endp, 10)) != NUM_OK || - (nret = NADD_SLONG(sp, - total, val)) != NUM_OK) { - ex_badaddr(sp, NULL, A_NOTSET, nret); - *errp = 1; - return (0); - } - total += isneg ? -val : val; - ecp->clen -= (endp - ecp->cp); - ecp->cp = endp; - } - } - } - - /* - * Any value less than 0 is an error. Make sure that the new value - * will fit into a recno_t. - */ - if (*isaddrp && total != 0) { - if (total < 0) { - if (-total > mp->lno) { - msgq(sp, M_ERR, - "097|Reference to a line number less than 0"); - *errp = 1; - return (0); - } - } else - if (!NPFITS(MAX_REC_NUMBER, mp->lno, total)) { - ex_badaddr(sp, NULL, A_NOTSET, NUM_OVER); - *errp = 1; - return (0); - } - mp->lno += total; - } - return (0); -} - - -/* - * ex_load -- - * Load up the next command, which may be an @ buffer or global command. - */ -static int -ex_load(sp) - SCR *sp; -{ - GS *gp; - EXCMD *ecp; - RANGE *rp; - - F_CLR(sp, SC_EX_GLOBAL); - - /* - * Lose any exhausted commands. We know that the first command - * can't be an AGV command, which makes things a bit easier. - */ - for (gp = sp->gp;;) { - /* - * If we're back to the original structure, leave it around, - * but discard any allocated source name, we've returned to - * the beginning of the command stack. - */ - if ((ecp = gp->ecq.lh_first) == &gp->excmd) { - if (F_ISSET(ecp, E_NAMEDISCARD)) { - free(ecp->if_name); - ecp->if_name = NULL; - } - return (0); - } - - /* - * ecp->clen will be 0 for the first discarded command, but - * may not be 0 for subsequent ones, e.g. if the original - * command was ":g/xx/@a|s/b/c/", then when we discard the - * command pushed on the stack by the @a, we have to resume - * the global command which included the substitute command. - */ - if (ecp->clen != 0) - return (0); - - /* - * If it's an @, global or v command, we may need to continue - * the command on a different line. - */ - if (FL_ISSET(ecp->agv_flags, AGV_ALL)) { - /* Discard any exhausted ranges. */ - while ((rp = ecp->rq.cqh_first) != (void *)&ecp->rq) - if (rp->start > rp->stop) { - CIRCLEQ_REMOVE(&ecp->rq, rp, q); - free(rp); - } else - break; - - /* If there's another range, continue with it. */ - if (rp != (void *)&ecp->rq) - break; - - /* If it's a global/v command, fix up the last line. */ - if (FL_ISSET(ecp->agv_flags, - AGV_GLOBAL | AGV_V) && ecp->range_lno != OOBLNO) - if (db_exist(sp, ecp->range_lno)) - sp->lno = ecp->range_lno; - else { - if (db_last(sp, &sp->lno)) - return (1); - if (sp->lno == 0) - sp->lno = 1; - } - free(ecp->o_cp); - } - - /* Discard the EXCMD. */ - LIST_REMOVE(ecp, q); - free(ecp); - } - - /* - * We only get here if it's an active @, global or v command. Set - * the current line number, and get a new copy of the command for - * the parser. Note, the original pointer almost certainly moved, - * so we have play games. - */ - ecp->cp = ecp->o_cp; - memcpy(ecp->cp, ecp->cp + ecp->o_clen, ecp->o_clen); - ecp->clen = ecp->o_clen; - ecp->range_lno = sp->lno = rp->start++; - - if (FL_ISSET(ecp->agv_flags, AGV_GLOBAL | AGV_V)) - F_SET(sp, SC_EX_GLOBAL); - return (0); -} - -/* - * ex_discard -- - * Discard any pending ex commands. - */ -static int -ex_discard(sp) - SCR *sp; -{ - GS *gp; - EXCMD *ecp; - RANGE *rp; - - /* - * We know the first command can't be an AGV command, so we don't - * process it specially. We do, however, nail the command itself. - */ - for (gp = sp->gp; (ecp = gp->ecq.lh_first) != &gp->excmd;) { - if (FL_ISSET(ecp->agv_flags, AGV_ALL)) { - while ((rp = ecp->rq.cqh_first) != (void *)&ecp->rq) { - CIRCLEQ_REMOVE(&ecp->rq, rp, q); - free(rp); - } - free(ecp->o_cp); - } - LIST_REMOVE(ecp, q); - free(ecp); - } - gp->ecq.lh_first->clen = 0; - return (0); -} - -/* - * ex_unknown -- - * Display an unknown command name. - */ -static void -ex_unknown(sp, cmd, len) - SCR *sp; - char *cmd; - size_t len; -{ - size_t blen; - char *bp; - - GET_SPACE_GOTO(sp, bp, blen, len + 1); - bp[len] = '\0'; - memcpy(bp, cmd, len); - msgq_str(sp, M_ERR, bp, "098|The %s command is unknown"); - FREE_SPACE(sp, bp, blen); - -alloc_err: - return; -} - -/* - * ex_is_abbrev - - * The vi text input routine needs to know if ex thinks this is an - * [un]abbreviate command, so it can turn off abbreviations. See - * the usual ranting in the vi/v_txt_ev.c:txt_abbrev() routine. - * - * PUBLIC: int ex_is_abbrev __P((char *, size_t)); - */ -int -ex_is_abbrev(name, len) - char *name; - size_t len; -{ - EXCMDLIST const *cp; - - return ((cp = ex_comm_search(name, len)) != NULL && - (cp == &cmds[C_ABBR] || cp == &cmds[C_UNABBREVIATE])); -} - -/* - * ex_is_unmap - - * The vi text input routine needs to know if ex thinks this is an - * unmap command, so it can turn off input mapping. See the usual - * ranting in the vi/v_txt_ev.c:txt_unmap() routine. - * - * PUBLIC: int ex_is_unmap __P((char *, size_t)); - */ -int -ex_is_unmap(name, len) - char *name; - size_t len; -{ - EXCMDLIST const *cp; - - /* - * The command the vi input routines are really interested in - * is "unmap!", not just unmap. - */ - if (name[len - 1] != '!') - return (0); - --len; - return ((cp = ex_comm_search(name, len)) != NULL && - cp == &cmds[C_UNMAP]); -} - -/* - * ex_comm_search -- - * Search for a command name. - */ -static EXCMDLIST const * -ex_comm_search(name, len) - char *name; - size_t len; -{ - EXCMDLIST const *cp; - - for (cp = cmds; cp->name != NULL; ++cp) { - if (cp->name[0] > name[0]) - return (NULL); - if (cp->name[0] != name[0]) - continue; - if (!memcmp(name, cp->name, len)) - return (cp); - } - return (NULL); -} - -/* - * ex_badaddr -- - * Display a bad address message. - * - * PUBLIC: void ex_badaddr - * PUBLIC: __P((SCR *, EXCMDLIST const *, enum badaddr, enum nresult)); - */ -void -ex_badaddr(sp, cp, ba, nret) - SCR *sp; - EXCMDLIST const *cp; - enum badaddr ba; - enum nresult nret; -{ - recno_t lno; - - switch (nret) { - case NUM_OK: - break; - case NUM_ERR: - msgq(sp, M_SYSERR, NULL); - return; - case NUM_OVER: - msgq(sp, M_ERR, "099|Address value overflow"); - return; - case NUM_UNDER: - msgq(sp, M_ERR, "100|Address value underflow"); - return; - } - - /* - * When encountering an address error, tell the user if there's no - * underlying file, that's the real problem. - */ - if (sp->ep == NULL) { - ex_emsg(sp, cp->name, EXM_NOFILEYET); - return; - } - - switch (ba) { - case A_COMBO: - msgq(sp, M_ERR, "101|Illegal address combination"); - break; - case A_EOF: - if (db_last(sp, &lno)) - return; - if (lno != 0) { - msgq(sp, M_ERR, - "102|Illegal address: only %lu lines in the file", - lno); - break; - } - /* FALLTHROUGH */ - case A_EMPTY: - msgq(sp, M_ERR, "103|Illegal address: the file is empty"); - break; - case A_NOTSET: - abort(); - /* NOTREACHED */ - case A_ZERO: - msgq(sp, M_ERR, - "104|The %s command doesn't permit an address of 0", - cp->name); - break; - } - return; -} - -#if defined(DEBUG) && defined(COMLOG) -/* - * ex_comlog -- - * Log ex commands. - */ -static void -ex_comlog(sp, ecp) - SCR *sp; - EXCMD *ecp; -{ - TRACE(sp, "ecmd: %s", ecp->cmd->name); - if (ecp->addrcnt > 0) { - TRACE(sp, " a1 %d", ecp->addr1.lno); - if (ecp->addrcnt > 1) - TRACE(sp, " a2: %d", ecp->addr2.lno); - } - if (ecp->lineno) - TRACE(sp, " line %d", ecp->lineno); - if (ecp->flags) - TRACE(sp, " flags 0x%x", ecp->flags); - if (F_ISSET(&exc, E_BUFFER)) - TRACE(sp, " buffer %c", ecp->buffer); - if (ecp->argc) - for (cnt = 0; cnt < ecp->argc; ++cnt) - TRACE(sp, " arg %d: {%s}", cnt, ecp->argv[cnt]->bp); - TRACE(sp, "\n"); -} -#endif diff --git a/contrib/nvi/ex/ex.h b/contrib/nvi/ex/ex.h deleted file mode 100644 index 5870990..0000000 --- a/contrib/nvi/ex/ex.h +++ /dev/null @@ -1,228 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - * - * @(#)ex.h 10.24 (Berkeley) 8/12/96 - */ - -#define PROMPTCHAR ':' /* Prompt using a colon. */ - -typedef struct _excmdlist { /* Ex command table structure. */ - char *name; /* Command name, underlying function. */ - int (*fn) __P((SCR *, EXCMD *)); - -#define E_ADDR1 0x00000001 /* One address. */ -#define E_ADDR2 0x00000002 /* Two addresses. */ -#define E_ADDR2_ALL 0x00000004 /* Zero/two addresses; zero == all. */ -#define E_ADDR2_NONE 0x00000008 /* Zero/two addresses; zero == none. */ -#define E_ADDR_ZERO 0x00000010 /* 0 is a legal addr1. */ -#define E_ADDR_ZERODEF 0x00000020 /* 0 is default addr1 of empty files. */ -#define E_AUTOPRINT 0x00000040 /* Command always sets autoprint. */ -#define E_CLRFLAG 0x00000080 /* Clear the print (#, l, p) flags. */ -#define E_NEWSCREEN 0x00000100 /* Create a new screen. */ -#define E_SECURE 0x00000200 /* Permission denied if O_SECURE set. */ -#define E_VIONLY 0x00000400 /* Meaningful only in vi. */ -#define __INUSE1 0xfffff800 /* Same name space as EX_PRIVATE. */ - u_int16_t flags; - - char *syntax; /* Syntax script. */ - char *usage; /* Usage line. */ - char *help; /* Help line. */ -} EXCMDLIST; - -#define MAXCMDNAMELEN 12 /* Longest command name. */ -extern EXCMDLIST const cmds[]; /* Table of ex commands. */ - -/* - * !!! - * QUOTING NOTE: - * - * Historically, .exrc files and EXINIT variables could only use ^V as an - * escape character, neither ^Q or a user specified character worked. We - * enforce that here, just in case someone depends on it. - */ -#define IS_ESCAPE(sp, cmdp, ch) \ - (F_ISSET(cmdp, E_VLITONLY) ? \ - (ch) == CH_LITERAL : KEY_VAL(sp, ch) == K_VLNEXT) - -/* - * File state must be checked for each command -- any ex command may be entered - * at any time, and most of them won't work well if a file hasn't yet been read - * in. Historic vi generally took the easy way out and dropped core. - */ -#define NEEDFILE(sp, cmdp) { \ - if ((sp)->ep == NULL) { \ - ex_emsg(sp, (cmdp)->cmd->name, EXM_NOFILEYET); \ - return (1); \ - } \ -} - -/* Range structures for global and @ commands. */ -typedef struct _range RANGE; -struct _range { /* Global command range. */ - CIRCLEQ_ENTRY(_range) q; /* Linked list of ranges. */ - recno_t start, stop; /* Start/stop of the range. */ -}; - -/* Ex command structure. */ -struct _excmd { - LIST_ENTRY(_excmd) q; /* Linked list of commands. */ - - char *if_name; /* Associated file. */ - recno_t if_lno; /* Associated line number. */ - - /* Clear the structure for the ex parser. */ -#define CLEAR_EX_PARSER(cmdp) \ - memset(&((cmdp)->cp), 0, ((char *)&(cmdp)->flags - \ - (char *)&((cmdp)->cp)) + sizeof((cmdp)->flags)) - - char *cp; /* Current command text. */ - size_t clen; /* Current command length. */ - - char *save_cmd; /* Remaining command. */ - size_t save_cmdlen; /* Remaining command length. */ - - EXCMDLIST const *cmd; /* Command: entry in command table. */ - EXCMDLIST rcmd; /* Command: table entry/replacement. */ - - CIRCLEQ_HEAD(_rh, _range) rq; /* @/global range: linked list. */ - recno_t range_lno; /* @/global range: set line number. */ - char *o_cp; /* Original @/global command. */ - size_t o_clen; /* Original @/global command length. */ -#define AGV_AT 0x01 /* @ buffer execution. */ -#define AGV_AT_NORANGE 0x02 /* @ buffer execution without range. */ -#define AGV_GLOBAL 0x04 /* global command. */ -#define AGV_V 0x08 /* v command. */ -#define AGV_ALL (AGV_AT | AGV_AT_NORANGE | AGV_GLOBAL | AGV_V) - u_int8_t agv_flags; - - /* Clear the structure before each ex command. */ -#define CLEAR_EX_CMD(cmdp) { \ - u_int32_t L__f = F_ISSET(cmdp, E_PRESERVE); \ - memset(&((cmdp)->buffer), 0, ((char *)&(cmdp)->flags - \ - (char *)&((cmdp)->buffer)) + sizeof((cmdp)->flags)); \ - F_SET(cmdp, L__f); \ -} - - CHAR_T buffer; /* Command: named buffer. */ - recno_t lineno; /* Command: line number. */ - long count; /* Command: signed count. */ - long flagoff; /* Command: signed flag offset. */ - int addrcnt; /* Command: addresses (0, 1 or 2). */ - MARK addr1; /* Command: 1st address. */ - MARK addr2; /* Command: 2nd address. */ - ARGS **argv; /* Command: array of arguments. */ - int argc; /* Command: count of arguments. */ - -#define E_C_BUFFER 0x00001 /* Buffer name specified. */ -#define E_C_CARAT 0x00002 /* ^ flag. */ -#define E_C_COUNT 0x00004 /* Count specified. */ -#define E_C_COUNT_NEG 0x00008 /* Count was signed negative. */ -#define E_C_COUNT_POS 0x00010 /* Count was signed positive. */ -#define E_C_DASH 0x00020 /* - flag. */ -#define E_C_DOT 0x00040 /* . flag. */ -#define E_C_EQUAL 0x00080 /* = flag. */ -#define E_C_FORCE 0x00100 /* ! flag. */ -#define E_C_HASH 0x00200 /* # flag. */ -#define E_C_LIST 0x00400 /* l flag. */ -#define E_C_PLUS 0x00800 /* + flag. */ -#define E_C_PRINT 0x01000 /* p flag. */ - u_int16_t iflags; /* User input information. */ - -#define __INUSE2 0x000004ff /* Same name space as EXCMDLIST. */ -#define E_BLIGNORE 0x00000800 /* Ignore blank lines. */ -#define E_NAMEDISCARD 0x00001000 /* Free/discard the name. */ -#define E_NOAUTO 0x00002000 /* Don't do autoprint output. */ -#define E_NOPRDEF 0x00004000 /* Don't print as default. */ -#define E_NRSEP 0x00008000 /* Need to line adjust ex output. */ -#define E_OPTNUM 0x00010000 /* Number edit option affected. */ -#define E_VLITONLY 0x00020000 /* Use ^V quoting only. */ -#define E_PRESERVE 0x0003f800 /* Bits to preserve across commands. */ - -#define E_ABSMARK 0x00040000 /* Set the absolute mark. */ -#define E_ADDR_DEF 0x00080000 /* Default addresses used. */ -#define E_DELTA 0x00100000 /* Search address with delta. */ -#define E_MODIFY 0x00200000 /* File name expansion modified arg. */ -#define E_MOVETOEND 0x00400000 /* Move to the end of the file first. */ -#define E_NEWLINE 0x00800000 /* Found ending <newline>. */ -#define E_SEARCH_WMSG 0x01000000 /* Display search-wrapped message. */ -#define E_USELASTCMD 0x02000000 /* Use the last command. */ -#define E_VISEARCH 0x04000000 /* It's really a vi search command. */ - u_int32_t flags; /* Current flags. */ -}; - -/* Ex private, per-screen memory. */ -typedef struct _ex_private { - CIRCLEQ_HEAD(_tqh, _tagq) tq; /* Tag queue. */ - TAILQ_HEAD(_tagfh, _tagf) tagfq;/* Tag file list. */ - LIST_HEAD(_csch, _csc) cscq; /* Cscope connection list. */ - char *tag_last; /* Saved last tag string. */ - - CHAR_T *lastbcomm; /* Last bang command. */ - - ARGS **args; /* Command: argument list. */ - int argscnt; /* Command: argument list count. */ - int argsoff; /* Command: offset into arguments. */ - - u_int32_t fdef; /* Saved E_C_* default command flags. */ - - char *ibp; /* File line input buffer. */ - size_t ibp_len; /* File line input buffer length. */ - - /* - * Buffers for the ex output. The screen/vi support doesn't do any - * character buffering of any kind. We do it here so that we're not - * calling the screen output routines on every character. - * - * XXX - * Change to grow dynamically. - */ - char obp[1024]; /* Ex output buffer. */ - size_t obp_len; /* Ex output buffer length. */ - -#define EXP_CSCINIT 0x01 /* Cscope initialized. */ - u_int8_t flags; -} EX_PRIVATE; -#define EXP(sp) ((EX_PRIVATE *)((sp)->ex_private)) - -/* - * Filter actions: - * - * FILTER_BANG !: filter text through the utility. - * FILTER_RBANG !: read from the utility (without stdin). - * FILTER_READ read: read from the utility (with stdin). - * FILTER_WRITE write: write to the utility, display its output. - */ -enum filtertype { FILTER_BANG, FILTER_RBANG, FILTER_READ, FILTER_WRITE }; - -/* Ex common error messages. */ -typedef enum { - EXM_EMPTYBUF, /* Empty buffer. */ - EXM_FILECOUNT, /* Too many file names. */ - EXM_NOCANON, /* No terminal interface. */ - EXM_NOCANON_F, /* EXM_NOCANO: filter version. */ - EXM_NOFILEYET, /* Illegal until a file read in. */ - EXM_NOPREVBUF, /* No previous buffer specified. */ - EXM_NOPREVRE, /* No previous RE specified. */ - EXM_NOSUSPEND, /* No suspension. */ - EXM_SECURE, /* Illegal if secure edit option set. */ - EXM_SECURE_F, /* EXM_SECURE: filter version */ - EXM_USAGE /* Standard usage message. */ -} exm_t; - -/* Ex address error types. */ -enum badaddr { A_COMBO, A_EMPTY, A_EOF, A_NOTSET, A_ZERO }; - -/* Ex common tag error messages. */ -typedef enum { - TAG_BADLNO, /* Tag line doesn't exist. */ - TAG_EMPTY, /* Tags stack is empty. */ - TAG_SEARCH /* Tags search pattern wasn't found. */ -} tagmsg_t; - -#include "ex_def.h" -#include "ex_extern.h" diff --git a/contrib/nvi/ex/ex_abbrev.c b/contrib/nvi/ex/ex_abbrev.c deleted file mode 100644 index 231098c..0000000 --- a/contrib/nvi/ex/ex_abbrev.c +++ /dev/null @@ -1,117 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_abbrev.c 10.7 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" -#include "../vi/vi.h" - -/* - * ex_abbr -- :abbreviate [key replacement] - * Create an abbreviation or display abbreviations. - * - * PUBLIC: int ex_abbr __P((SCR *, EXCMD *)); - */ -int -ex_abbr(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - CHAR_T *p; - size_t len; - - switch (cmdp->argc) { - case 0: - if (seq_dump(sp, SEQ_ABBREV, 0) == 0) - msgq(sp, M_INFO, "105|No abbreviations to display"); - return (0); - case 2: - break; - default: - abort(); - } - - /* - * Check for illegal characters. - * - * !!! - * Another fun one, historically. See vi/v_ntext.c:txt_abbrev() for - * details. The bottom line is that all abbreviations have to end - * with a "word" character, because it's the transition from word to - * non-word characters that triggers the test for an abbreviation. In - * addition, because of the way the test is done, there can't be any - * transitions from word to non-word character (or vice-versa) other - * than between the next-to-last and last characters of the string, - * and there can't be any <blank> characters. Warn the user. - */ - if (!inword(cmdp->argv[0]->bp[cmdp->argv[0]->len - 1])) { - msgq(sp, M_ERR, - "106|Abbreviations must end with a \"word\" character"); - return (1); - } - for (p = cmdp->argv[0]->bp; *p != '\0'; ++p) - if (isblank(p[0])) { - msgq(sp, M_ERR, - "107|Abbreviations may not contain tabs or spaces"); - return (1); - } - if (cmdp->argv[0]->len > 2) - for (p = cmdp->argv[0]->bp, - len = cmdp->argv[0]->len - 2; len; --len, ++p) - if (inword(p[0]) != inword(p[1])) { - msgq(sp, M_ERR, -"108|Abbreviations may not mix word/non-word characters, except at the end"); - return (1); - } - - if (seq_set(sp, NULL, 0, cmdp->argv[0]->bp, cmdp->argv[0]->len, - cmdp->argv[1]->bp, cmdp->argv[1]->len, SEQ_ABBREV, SEQ_USERDEF)) - return (1); - - F_SET(sp->gp, G_ABBREV); - return (0); -} - -/* - * ex_unabbr -- :unabbreviate key - * Delete an abbreviation. - * - * PUBLIC: int ex_unabbr __P((SCR *, EXCMD *)); - */ -int -ex_unabbr(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - ARGS *ap; - - ap = cmdp->argv[0]; - if (!F_ISSET(sp->gp, G_ABBREV) || - seq_delete(sp, ap->bp, ap->len, SEQ_ABBREV)) { - msgq_str(sp, M_ERR, ap->bp, - "109|\"%s\" is not an abbreviation"); - return (1); - } - return (0); -} diff --git a/contrib/nvi/ex/ex_append.c b/contrib/nvi/ex/ex_append.c deleted file mode 100644 index 8d89e12..0000000 --- a/contrib/nvi/ex/ex_append.c +++ /dev/null @@ -1,277 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_append.c 10.30 (Berkeley) 10/23/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" - -enum which {APPEND, CHANGE, INSERT}; - -static int ex_aci __P((SCR *, EXCMD *, enum which)); - -/* - * ex_append -- :[line] a[ppend][!] - * Append one or more lines of new text after the specified line, - * or the current line if no address is specified. - * - * PUBLIC: int ex_append __P((SCR *, EXCMD *)); - */ -int -ex_append(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - return (ex_aci(sp, cmdp, APPEND)); -} - -/* - * ex_change -- :[line[,line]] c[hange][!] [count] - * Change one or more lines to the input text. - * - * PUBLIC: int ex_change __P((SCR *, EXCMD *)); - */ -int -ex_change(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - return (ex_aci(sp, cmdp, CHANGE)); -} - -/* - * ex_insert -- :[line] i[nsert][!] - * Insert one or more lines of new text before the specified line, - * or the current line if no address is specified. - * - * PUBLIC: int ex_insert __P((SCR *, EXCMD *)); - */ -int -ex_insert(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - return (ex_aci(sp, cmdp, INSERT)); -} - -/* - * ex_aci -- - * Append, change, insert in ex. - */ -static int -ex_aci(sp, cmdp, cmd) - SCR *sp; - EXCMD *cmdp; - enum which cmd; -{ - CHAR_T *p, *t; - GS *gp; - TEXT *tp; - TEXTH tiq; - recno_t cnt, lno; - size_t len; - u_int32_t flags; - int need_newline; - - gp = sp->gp; - NEEDFILE(sp, cmdp); - - /* - * If doing a change, replace lines for as long as possible. Then, - * append more lines or delete remaining lines. Changes to an empty - * file are appends, inserts are the same as appends to the previous - * line. - * - * !!! - * Set the address to which we'll append. We set sp->lno to this - * address as well so that autoindent works correctly when get text - * from the user. - */ - lno = cmdp->addr1.lno; - sp->lno = lno; - if ((cmd == CHANGE || cmd == INSERT) && lno != 0) - --lno; - - /* - * !!! - * If the file isn't empty, cut changes into the unnamed buffer. - */ - if (cmd == CHANGE && cmdp->addr1.lno != 0 && - (cut(sp, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE) || - del(sp, &cmdp->addr1, &cmdp->addr2, 1))) - return (1); - - /* - * !!! - * Anything that was left after the command separator becomes part - * of the inserted text. Apparently, it was common usage to enter: - * - * :g/pattern/append|stuff1 - * - * and append the line of text "stuff1" to the lines containing the - * pattern. It was also historically legal to enter: - * - * :append|stuff1 - * stuff2 - * . - * - * and the text on the ex command line would be appended as well as - * the text inserted after it. There was an historic bug however, - * that the user had to enter *two* terminating lines (the '.' lines) - * to terminate text input mode, in this case. This whole thing - * could be taken too far, however. Entering: - * - * :append|stuff1\ - * stuff2 - * stuff3 - * . - * - * i.e. mixing and matching the forms confused the historic vi, and, - * not only did it take two terminating lines to terminate text input - * mode, but the trailing backslashes were retained on the input. We - * match historic practice except that we discard the backslashes. - * - * Input lines specified on the ex command line lines are separated by - * <newline>s. If there is a trailing delimiter an empty line was - * inserted. There may also be a leading delimiter, which is ignored - * unless it's also a trailing delimiter. It is possible to encounter - * a termination line, i.e. a single '.', in a global command, but not - * necessary if the text insert command was the last of the global - * commands. - */ - if (cmdp->save_cmdlen != 0) { - for (p = cmdp->save_cmd, - len = cmdp->save_cmdlen; len > 0; p = t) { - for (t = p; len > 0 && t[0] != '\n'; ++t, --len); - if (t != p || len == 0) { - if (F_ISSET(sp, SC_EX_GLOBAL) && - t - p == 1 && p[0] == '.') { - ++t; - if (len > 0) - --len; - break; - } - if (db_append(sp, 1, lno++, p, t - p)) - return (1); - } - if (len != 0) { - ++t; - if (--len == 0 && - db_append(sp, 1, lno++, "", 0)) - return (1); - } - } - /* - * If there's any remaining text, we're in a global, and - * there's more command to parse. - * - * !!! - * We depend on the fact that non-global commands will eat the - * rest of the command line as text input, and before getting - * any text input from the user. Otherwise, we'd have to save - * off the command text before or during the call to the text - * input function below. - */ - if (len != 0) - cmdp->save_cmd = t; - cmdp->save_cmdlen = len; - } - - if (F_ISSET(sp, SC_EX_GLOBAL)) { - if ((sp->lno = lno) == 0 && db_exist(sp, 1)) - sp->lno = 1; - return (0); - } - - /* - * If not in a global command, read from the terminal. - * - * If this code is called by vi, we want to reset the terminal and use - * ex's line get routine. It actually works fine if we use vi's get - * routine, but it doesn't look as nice. Maybe if we had a separate - * window or something, but getting a line at a time looks awkward. - * However, depending on the screen that we're using, that may not - * be possible. - */ - if (F_ISSET(sp, SC_VI)) { - if (gp->scr_screen(sp, SC_EX)) { - ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON); - return (1); - } - - /* If we're still in the vi screen, move out explicitly. */ - need_newline = !F_ISSET(sp, SC_SCR_EXWROTE); - F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE); - if (need_newline) - (void)ex_puts(sp, "\n"); - - /* - * !!! - * Users of historical versions of vi sometimes get confused - * when they enter append mode, and can't seem to get out of - * it. Give them an informational message. - */ - (void)ex_puts(sp, - msg_cat(sp, "273|Entering ex input mode.", NULL)); - (void)ex_puts(sp, "\n"); - (void)ex_fflush(sp); - } - - /* - * Set input flags; the ! flag turns off autoindent for append, - * change and insert. - */ - LF_INIT(TXT_DOTTERM | TXT_NUMBER); - if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && O_ISSET(sp, O_AUTOINDENT)) - LF_SET(TXT_AUTOINDENT); - if (O_ISSET(sp, O_BEAUTIFY)) - LF_SET(TXT_BEAUTIFY); - - /* - * This code can't use the common screen TEXTH structure (sp->tiq), - * as it may already be in use, e.g. ":append|s/abc/ABC/" would fail - * as we are only halfway through the text when the append code fires. - * Use a local structure instead. (The ex code would have to use a - * local structure except that we're guaranteed to finish remaining - * characters in the common TEXTH structure when they were inserted - * into the file, above.) - */ - memset(&tiq, 0, sizeof(TEXTH)); - CIRCLEQ_INIT(&tiq); - - if (ex_txt(sp, &tiq, 0, flags)) - return (1); - - for (cnt = 0, tp = tiq.cqh_first; - tp != (TEXT *)&tiq; ++cnt, tp = tp->q.cqe_next) - if (db_append(sp, 1, lno++, tp->lb, tp->len)) - return (1); - - /* - * Set sp->lno to the final line number value (correcting for a - * possible 0 value) as that's historically correct for the final - * line value, whether or not the user entered any text. - */ - if ((sp->lno = lno) == 0 && db_exist(sp, 1)) - sp->lno = 1; - - return (0); -} diff --git a/contrib/nvi/ex/ex_args.c b/contrib/nvi/ex/ex_args.c deleted file mode 100644 index bc37109..0000000 --- a/contrib/nvi/ex/ex_args.c +++ /dev/null @@ -1,327 +0,0 @@ -/*- - * Copyright (c) 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1991, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_args.c 10.16 (Berkeley) 7/13/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" -#include "../vi/vi.h" - -static int ex_N_next __P((SCR *, EXCMD *)); - -/* - * ex_next -- :next [+cmd] [files] - * Edit the next file, optionally setting the list of files. - * - * !!! - * The :next command behaved differently from the :rewind command in - * historic vi. See nvi/docs/autowrite for details, but the basic - * idea was that it ignored the force flag if the autowrite flag was - * set. This implementation handles them all identically. - * - * PUBLIC: int ex_next __P((SCR *, EXCMD *)); - */ -int -ex_next(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - ARGS **argv; - FREF *frp; - int noargs; - char **ap; - - /* Check for file to move to. */ - if (cmdp->argc == 0 && (sp->cargv == NULL || sp->cargv[1] == NULL)) { - msgq(sp, M_ERR, "111|No more files to edit"); - return (1); - } - - if (F_ISSET(cmdp, E_NEWSCREEN)) { - /* By default, edit the next file in the old argument list. */ - if (cmdp->argc == 0) { - if (argv_exp0(sp, - cmdp, sp->cargv[1], strlen(sp->cargv[1]))) - return (1); - return (ex_edit(sp, cmdp)); - } - return (ex_N_next(sp, cmdp)); - } - - /* Check modification. */ - if (file_m1(sp, - FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) - return (1); - - /* Any arguments are a replacement file list. */ - if (cmdp->argc) { - /* Free the current list. */ - if (!F_ISSET(sp, SC_ARGNOFREE) && sp->argv != NULL) { - for (ap = sp->argv; *ap != NULL; ++ap) - free(*ap); - free(sp->argv); - } - F_CLR(sp, SC_ARGNOFREE | SC_ARGRECOVER); - sp->cargv = NULL; - - /* Create a new list. */ - CALLOC_RET(sp, - sp->argv, char **, cmdp->argc + 1, sizeof(char *)); - for (ap = sp->argv, - argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) - if ((*ap = - v_strdup(sp, argv[0]->bp, argv[0]->len)) == NULL) - return (1); - *ap = NULL; - - /* Switch to the first file. */ - sp->cargv = sp->argv; - if ((frp = file_add(sp, *sp->cargv)) == NULL) - return (1); - noargs = 0; - - /* Display a file count with the welcome message. */ - F_SET(sp, SC_STATUS_CNT); - } else { - if ((frp = file_add(sp, sp->cargv[1])) == NULL) - return (1); - if (F_ISSET(sp, SC_ARGRECOVER)) - F_SET(frp, FR_RECOVER); - noargs = 1; - } - - if (file_init(sp, frp, NULL, FS_SETALT | - (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) - return (1); - if (noargs) - ++sp->cargv; - - F_SET(sp, SC_FSWITCH); - return (0); -} - -/* - * ex_N_next -- - * New screen version of ex_next. - */ -static int -ex_N_next(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - SCR *new; - FREF *frp; - - /* Get a new screen. */ - if (screen_init(sp->gp, sp, &new)) - return (1); - if (vs_split(sp, new, 0)) { - (void)screen_end(new); - return (1); - } - - /* Get a backing file. */ - if ((frp = file_add(new, cmdp->argv[0]->bp)) == NULL || - file_init(new, frp, NULL, - (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) { - (void)vs_discard(new, NULL); - (void)screen_end(new); - return (1); - } - - /* The arguments are a replacement file list. */ - new->cargv = new->argv = ex_buildargv(sp, cmdp, NULL); - - /* Display a file count with the welcome message. */ - F_SET(new, SC_STATUS_CNT); - - /* Set up the switch. */ - sp->nextdisp = new; - F_SET(sp, SC_SSWITCH); - - return (0); -} - -/* - * ex_prev -- :prev - * Edit the previous file. - * - * PUBLIC: int ex_prev __P((SCR *, EXCMD *)); - */ -int -ex_prev(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - FREF *frp; - - if (sp->cargv == sp->argv) { - msgq(sp, M_ERR, "112|No previous files to edit"); - return (1); - } - - if (F_ISSET(cmdp, E_NEWSCREEN)) { - if (argv_exp0(sp, cmdp, sp->cargv[-1], strlen(sp->cargv[-1]))) - return (1); - return (ex_edit(sp, cmdp)); - } - - if (file_m1(sp, - FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) - return (1); - - if ((frp = file_add(sp, sp->cargv[-1])) == NULL) - return (1); - - if (file_init(sp, frp, NULL, FS_SETALT | - (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) - return (1); - --sp->cargv; - - F_SET(sp, SC_FSWITCH); - return (0); -} - -/* - * ex_rew -- :rew - * Re-edit the list of files. - * - * !!! - * Historic practice was that all files would start editing at the beginning - * of the file. We don't get this right because we may have multiple screens - * and we can't clear the FR_CURSORSET bit for a single screen. I don't see - * anyone noticing, but if they do, we'll have to put information into the SCR - * structure so we can keep track of it. - * - * PUBLIC: int ex_rew __P((SCR *, EXCMD *)); - */ -int -ex_rew(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - FREF *frp; - - /* - * !!! - * Historic practice -- you can rewind to the current file. - */ - if (sp->argv == NULL) { - msgq(sp, M_ERR, "113|No previous files to rewind"); - return (1); - } - - if (file_m1(sp, - FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) - return (1); - - /* Switch to the first one. */ - sp->cargv = sp->argv; - if ((frp = file_add(sp, *sp->cargv)) == NULL) - return (1); - if (file_init(sp, frp, NULL, FS_SETALT | - (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) - return (1); - - /* Switch and display a file count with the welcome message. */ - F_SET(sp, SC_FSWITCH | SC_STATUS_CNT); - - return (0); -} - -/* - * ex_args -- :args - * Display the list of files. - * - * PUBLIC: int ex_args __P((SCR *, EXCMD *)); - */ -int -ex_args(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - GS *gp; - int cnt, col, len, sep; - char **ap; - - if (sp->argv == NULL) { - (void)msgq(sp, M_ERR, "114|No file list to display"); - return (0); - } - - gp = sp->gp; - col = len = sep = 0; - for (cnt = 1, ap = sp->argv; *ap != NULL; ++ap) { - col += len = strlen(*ap) + sep + (ap == sp->cargv ? 2 : 0); - if (col >= sp->cols - 1) { - col = len; - sep = 0; - (void)ex_puts(sp, "\n"); - } else if (cnt != 1) { - sep = 1; - (void)ex_puts(sp, " "); - } - ++cnt; - - (void)ex_printf(sp, "%s%s%s", ap == sp->cargv ? "[" : "", - *ap, ap == sp->cargv ? "]" : ""); - if (INTERRUPTED(sp)) - break; - } - (void)ex_puts(sp, "\n"); - return (0); -} - -/* - * ex_buildargv -- - * Build a new file argument list. - * - * PUBLIC: char **ex_buildargv __P((SCR *, EXCMD *, char *)); - */ -char ** -ex_buildargv(sp, cmdp, name) - SCR *sp; - EXCMD *cmdp; - char *name; -{ - ARGS **argv; - int argc; - char **ap, **s_argv; - - argc = cmdp == NULL ? 1 : cmdp->argc; - CALLOC(sp, s_argv, char **, argc + 1, sizeof(char *)); - if ((ap = s_argv) == NULL) - return (NULL); - - if (cmdp == NULL) { - if ((*ap = v_strdup(sp, name, strlen(name))) == NULL) - return (NULL); - ++ap; - } else - for (argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) - if ((*ap = - v_strdup(sp, argv[0]->bp, argv[0]->len)) == NULL) - return (NULL); - *ap = NULL; - return (s_argv); -} diff --git a/contrib/nvi/ex/ex_argv.c b/contrib/nvi/ex/ex_argv.c deleted file mode 100644 index cc5a201..0000000 --- a/contrib/nvi/ex/ex_argv.c +++ /dev/null @@ -1,756 +0,0 @@ -/*- - * Copyright (c) 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_argv.c 10.26 (Berkeley) 9/20/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" - -static int argv_alloc __P((SCR *, size_t)); -static int argv_comp __P((const void *, const void *)); -static int argv_fexp __P((SCR *, EXCMD *, - char *, size_t, char *, size_t *, char **, size_t *, int)); -static int argv_lexp __P((SCR *, EXCMD *, char *)); -static int argv_sexp __P((SCR *, char **, size_t *, size_t *)); - -/* - * argv_init -- - * Build a prototype arguments list. - * - * PUBLIC: int argv_init __P((SCR *, EXCMD *)); - */ -int -argv_init(sp, excp) - SCR *sp; - EXCMD *excp; -{ - EX_PRIVATE *exp; - - exp = EXP(sp); - exp->argsoff = 0; - argv_alloc(sp, 1); - - excp->argv = exp->args; - excp->argc = exp->argsoff; - return (0); -} - -/* - * argv_exp0 -- - * Append a string to the argument list. - * - * PUBLIC: int argv_exp0 __P((SCR *, EXCMD *, char *, size_t)); - */ -int -argv_exp0(sp, excp, cmd, cmdlen) - SCR *sp; - EXCMD *excp; - char *cmd; - size_t cmdlen; -{ - EX_PRIVATE *exp; - - exp = EXP(sp); - argv_alloc(sp, cmdlen); - memcpy(exp->args[exp->argsoff]->bp, cmd, cmdlen); - exp->args[exp->argsoff]->bp[cmdlen] = '\0'; - exp->args[exp->argsoff]->len = cmdlen; - ++exp->argsoff; - excp->argv = exp->args; - excp->argc = exp->argsoff; - return (0); -} - -/* - * argv_exp1 -- - * Do file name expansion on a string, and append it to the - * argument list. - * - * PUBLIC: int argv_exp1 __P((SCR *, EXCMD *, char *, size_t, int)); - */ -int -argv_exp1(sp, excp, cmd, cmdlen, is_bang) - SCR *sp; - EXCMD *excp; - char *cmd; - size_t cmdlen; - int is_bang; -{ - EX_PRIVATE *exp; - size_t blen, len; - char *bp, *p, *t; - - GET_SPACE_RET(sp, bp, blen, 512); - - len = 0; - exp = EXP(sp); - if (argv_fexp(sp, excp, cmd, cmdlen, bp, &len, &bp, &blen, is_bang)) { - FREE_SPACE(sp, bp, blen); - return (1); - } - - /* If it's empty, we're done. */ - if (len != 0) { - for (p = bp, t = bp + len; p < t; ++p) - if (!isblank(*p)) - break; - if (p == t) - goto ret; - } else - goto ret; - - (void)argv_exp0(sp, excp, bp, len); - -ret: FREE_SPACE(sp, bp, blen); - return (0); -} - -/* - * argv_exp2 -- - * Do file name and shell expansion on a string, and append it to - * the argument list. - * - * PUBLIC: int argv_exp2 __P((SCR *, EXCMD *, char *, size_t)); - */ -int -argv_exp2(sp, excp, cmd, cmdlen) - SCR *sp; - EXCMD *excp; - char *cmd; - size_t cmdlen; -{ - size_t blen, len, n; - int rval; - char *bp, *mp, *p; - - GET_SPACE_RET(sp, bp, blen, 512); - -#define SHELLECHO "echo " -#define SHELLOFFSET (sizeof(SHELLECHO) - 1) - memcpy(bp, SHELLECHO, SHELLOFFSET); - p = bp + SHELLOFFSET; - len = SHELLOFFSET; - -#if defined(DEBUG) && 0 - TRACE(sp, "file_argv: {%.*s}\n", (int)cmdlen, cmd); -#endif - - if (argv_fexp(sp, excp, cmd, cmdlen, p, &len, &bp, &blen, 0)) { - rval = 1; - goto err; - } - -#if defined(DEBUG) && 0 - TRACE(sp, "before shell: %d: {%s}\n", len, bp); -#endif - - /* - * Do shell word expansion -- it's very, very hard to figure out what - * magic characters the user's shell expects. Historically, it was a - * union of v7 shell and csh meta characters. We match that practice - * by default, so ":read \%" tries to read a file named '%'. It would - * make more sense to pass any special characters through the shell, - * but then, if your shell was csh, the above example will behave - * differently in nvi than in vi. If you want to get other characters - * passed through to your shell, change the "meta" option. - * - * To avoid a function call per character, we do a first pass through - * the meta characters looking for characters that aren't expected - * to be there, and then we can ignore them in the user's argument. - */ - if (opts_empty(sp, O_SHELL, 1) || opts_empty(sp, O_SHELLMETA, 1)) - n = 0; - else { - for (p = mp = O_STR(sp, O_SHELLMETA); *p != '\0'; ++p) - if (isblank(*p) || isalnum(*p)) - break; - p = bp + SHELLOFFSET; - n = len - SHELLOFFSET; - if (*p != '\0') { - for (; n > 0; --n, ++p) - if (strchr(mp, *p) != NULL) - break; - } else - for (; n > 0; --n, ++p) - if (!isblank(*p) && - !isalnum(*p) && strchr(mp, *p) != NULL) - break; - } - - /* - * If we found a meta character in the string, fork a shell to expand - * it. Unfortunately, this is comparatively slow. Historically, it - * didn't matter much, since users don't enter meta characters as part - * of pathnames that frequently. The addition of filename completion - * broke that assumption because it's easy to use. As a result, lots - * folks have complained that the expansion code is too slow. So, we - * detect filename completion as a special case, and do it internally. - * Note that this code assumes that the <asterisk> character is the - * match-anything meta character. That feels safe -- if anyone writes - * a shell that doesn't follow that convention, I'd suggest giving them - * a festive hot-lead enema. - */ - switch (n) { - case 0: - p = bp + SHELLOFFSET; - len -= SHELLOFFSET; - rval = argv_exp3(sp, excp, p, len); - break; - case 1: - if (*p == '*') { - *p = '\0'; - rval = argv_lexp(sp, excp, bp + SHELLOFFSET); - break; - } - /* FALLTHROUGH */ - default: - if (argv_sexp(sp, &bp, &blen, &len)) { - rval = 1; - goto err; - } - p = bp; - rval = argv_exp3(sp, excp, p, len); - break; - } - -err: FREE_SPACE(sp, bp, blen); - return (rval); -} - -/* - * argv_exp3 -- - * Take a string and break it up into an argv, which is appended - * to the argument list. - * - * PUBLIC: int argv_exp3 __P((SCR *, EXCMD *, char *, size_t)); - */ -int -argv_exp3(sp, excp, cmd, cmdlen) - SCR *sp; - EXCMD *excp; - char *cmd; - size_t cmdlen; -{ - EX_PRIVATE *exp; - size_t len; - int ch, off; - char *ap, *p; - - for (exp = EXP(sp); cmdlen > 0; ++exp->argsoff) { - /* Skip any leading whitespace. */ - for (; cmdlen > 0; --cmdlen, ++cmd) { - ch = *cmd; - if (!isblank(ch)) - break; - } - if (cmdlen == 0) - break; - - /* - * Determine the length of this whitespace delimited - * argument. - * - * QUOTING NOTE: - * - * Skip any character preceded by the user's quoting - * character. - */ - for (ap = cmd, len = 0; cmdlen > 0; ++cmd, --cmdlen, ++len) { - ch = *cmd; - if (IS_ESCAPE(sp, excp, ch) && cmdlen > 1) { - ++cmd; - --cmdlen; - } else if (isblank(ch)) - break; - } - - /* - * Copy the argument into place. - * - * QUOTING NOTE: - * - * Lose quote chars. - */ - argv_alloc(sp, len); - off = exp->argsoff; - exp->args[off]->len = len; - for (p = exp->args[off]->bp; len > 0; --len, *p++ = *ap++) - if (IS_ESCAPE(sp, excp, *ap)) - ++ap; - *p = '\0'; - } - excp->argv = exp->args; - excp->argc = exp->argsoff; - -#if defined(DEBUG) && 0 - for (cnt = 0; cnt < exp->argsoff; ++cnt) - TRACE(sp, "arg %d: {%s}\n", cnt, exp->argv[cnt]); -#endif - return (0); -} - -/* - * argv_fexp -- - * Do file name and bang command expansion. - */ -static int -argv_fexp(sp, excp, cmd, cmdlen, p, lenp, bpp, blenp, is_bang) - SCR *sp; - EXCMD *excp; - char *cmd, *p, **bpp; - size_t cmdlen, *lenp, *blenp; - int is_bang; -{ - EX_PRIVATE *exp; - char *bp, *t; - size_t blen, len, off, tlen; - - /* Replace file name characters. */ - for (bp = *bpp, blen = *blenp, len = *lenp; cmdlen > 0; --cmdlen, ++cmd) - switch (*cmd) { - case '!': - if (!is_bang) - goto ins_ch; - exp = EXP(sp); - if (exp->lastbcomm == NULL) { - msgq(sp, M_ERR, - "115|No previous command to replace \"!\""); - return (1); - } - len += tlen = strlen(exp->lastbcomm); - off = p - bp; - ADD_SPACE_RET(sp, bp, blen, len); - p = bp + off; - memcpy(p, exp->lastbcomm, tlen); - p += tlen; - F_SET(excp, E_MODIFY); - break; - case '%': - if ((t = sp->frp->name) == NULL) { - msgq(sp, M_ERR, - "116|No filename to substitute for %%"); - return (1); - } - tlen = strlen(t); - len += tlen; - off = p - bp; - ADD_SPACE_RET(sp, bp, blen, len); - p = bp + off; - memcpy(p, t, tlen); - p += tlen; - F_SET(excp, E_MODIFY); - break; - case '#': - if ((t = sp->alt_name) == NULL) { - msgq(sp, M_ERR, - "117|No filename to substitute for #"); - return (1); - } - len += tlen = strlen(t); - off = p - bp; - ADD_SPACE_RET(sp, bp, blen, len); - p = bp + off; - memcpy(p, t, tlen); - p += tlen; - F_SET(excp, E_MODIFY); - break; - case '\\': - /* - * QUOTING NOTE: - * - * Strip any backslashes that protected the file - * expansion characters. - */ - if (cmdlen > 1 && - (cmd[1] == '%' || cmd[1] == '#' || cmd[1] == '!')) { - ++cmd; - --cmdlen; - } - /* FALLTHROUGH */ - default: -ins_ch: ++len; - off = p - bp; - ADD_SPACE_RET(sp, bp, blen, len); - p = bp + off; - *p++ = *cmd; - } - - /* Nul termination. */ - ++len; - off = p - bp; - ADD_SPACE_RET(sp, bp, blen, len); - p = bp + off; - *p = '\0'; - - /* Return the new string length, buffer, buffer length. */ - *lenp = len - 1; - *bpp = bp; - *blenp = blen; - return (0); -} - -/* - * argv_alloc -- - * Make more space for arguments. - */ -static int -argv_alloc(sp, len) - SCR *sp; - size_t len; -{ - ARGS *ap; - EX_PRIVATE *exp; - int cnt, off; - - /* - * Allocate room for another argument, always leaving - * enough room for an ARGS structure with a length of 0. - */ -#define INCREMENT 20 - exp = EXP(sp); - off = exp->argsoff; - if (exp->argscnt == 0 || off + 2 >= exp->argscnt - 1) { - cnt = exp->argscnt + INCREMENT; - REALLOC(sp, exp->args, ARGS **, cnt * sizeof(ARGS *)); - if (exp->args == NULL) { - (void)argv_free(sp); - goto mem; - } - memset(&exp->args[exp->argscnt], 0, INCREMENT * sizeof(ARGS *)); - exp->argscnt = cnt; - } - - /* First argument. */ - if (exp->args[off] == NULL) { - CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS)); - if (exp->args[off] == NULL) - goto mem; - } - - /* First argument buffer. */ - ap = exp->args[off]; - ap->len = 0; - if (ap->blen < len + 1) { - ap->blen = len + 1; - REALLOC(sp, ap->bp, CHAR_T *, ap->blen * sizeof(CHAR_T)); - if (ap->bp == NULL) { - ap->bp = NULL; - ap->blen = 0; - F_CLR(ap, A_ALLOCATED); -mem: msgq(sp, M_SYSERR, NULL); - return (1); - } - F_SET(ap, A_ALLOCATED); - } - - /* Second argument. */ - if (exp->args[++off] == NULL) { - CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS)); - if (exp->args[off] == NULL) - goto mem; - } - /* 0 length serves as end-of-argument marker. */ - exp->args[off]->len = 0; - return (0); -} - -/* - * argv_free -- - * Free up argument structures. - * - * PUBLIC: int argv_free __P((SCR *)); - */ -int -argv_free(sp) - SCR *sp; -{ - EX_PRIVATE *exp; - int off; - - exp = EXP(sp); - if (exp->args != NULL) { - for (off = 0; off < exp->argscnt; ++off) { - if (exp->args[off] == NULL) - continue; - if (F_ISSET(exp->args[off], A_ALLOCATED)) - free(exp->args[off]->bp); - free(exp->args[off]); - } - free(exp->args); - } - exp->args = NULL; - exp->argscnt = 0; - exp->argsoff = 0; - return (0); -} - -/* - * argv_lexp -- - * Find all file names matching the prefix and append them to the - * buffer. - */ -static int -argv_lexp(sp, excp, path) - SCR *sp; - EXCMD *excp; - char *path; -{ - struct dirent *dp; - DIR *dirp; - EX_PRIVATE *exp; - int off; - size_t dlen, len, nlen; - char *dname, *name, *p; - - exp = EXP(sp); - - /* Set up the name and length for comparison. */ - if ((p = strrchr(path, '/')) == NULL) { - dname = "."; - dlen = 0; - name = path; - } else { - if (p == path) { - dname = "/"; - dlen = 1; - } else { - *p = '\0'; - dname = path; - dlen = strlen(path); - } - name = p + 1; - } - nlen = strlen(name); - - /* - * XXX - * We don't use the d_namlen field, it's not portable enough; we - * assume that d_name is nul terminated, instead. - */ - if ((dirp = opendir(dname)) == NULL) { - msgq_str(sp, M_SYSERR, dname, "%s"); - return (1); - } - for (off = exp->argsoff; (dp = readdir(dirp)) != NULL;) { - if (nlen == 0) { - if (dp->d_name[0] == '.') - continue; - len = strlen(dp->d_name); - } else { - len = strlen(dp->d_name); - if (len < nlen || memcmp(dp->d_name, name, nlen)) - continue; - } - - /* Directory + name + slash + null. */ - argv_alloc(sp, dlen + len + 2); - p = exp->args[exp->argsoff]->bp; - if (dlen != 0) { - memcpy(p, dname, dlen); - p += dlen; - if (dlen > 1 || dname[0] != '/') - *p++ = '/'; - } - memcpy(p, dp->d_name, len + 1); - exp->args[exp->argsoff]->len = dlen + len + 1; - ++exp->argsoff; - excp->argv = exp->args; - excp->argc = exp->argsoff; - } - closedir(dirp); - - if (off == exp->argsoff) { - /* - * If we didn't find a match, complain that the expansion - * failed. We can't know for certain that's the error, but - * it's a good guess, and it matches historic practice. - */ - msgq(sp, M_ERR, "304|Shell expansion failed"); - return (1); - } - qsort(exp->args + off, exp->argsoff - off, sizeof(ARGS *), argv_comp); - return (0); -} - -/* - * argv_comp -- - * Alphabetic comparison. - */ -static int -argv_comp(a, b) - const void *a, *b; -{ - return (strcmp((char *)(*(ARGS **)a)->bp, (char *)(*(ARGS **)b)->bp)); -} - -/* - * argv_sexp -- - * Fork a shell, pipe a command through it, and read the output into - * a buffer. - */ -static int -argv_sexp(sp, bpp, blenp, lenp) - SCR *sp; - char **bpp; - size_t *blenp, *lenp; -{ - enum { SEXP_ERR, SEXP_EXPANSION_ERR, SEXP_OK } rval; - FILE *ifp; - pid_t pid; - size_t blen, len; - int ch, std_output[2]; - char *bp, *p, *sh, *sh_path; - - /* Secure means no shell access. */ - if (O_ISSET(sp, O_SECURE)) { - msgq(sp, M_ERR, -"289|Shell expansions not supported when the secure edit option is set"); - return (1); - } - - sh_path = O_STR(sp, O_SHELL); - if ((sh = strrchr(sh_path, '/')) == NULL) - sh = sh_path; - else - ++sh; - - /* Local copies of the buffer variables. */ - bp = *bpp; - blen = *blenp; - - /* - * There are two different processes running through this code, named - * the utility (the shell) and the parent. The utility reads standard - * input and writes standard output and standard error output. The - * parent writes to the utility, reads its standard output and ignores - * its standard error output. Historically, the standard error output - * was discarded by vi, as it produces a lot of noise when file patterns - * don't match. - * - * The parent reads std_output[0], and the utility writes std_output[1]. - */ - ifp = NULL; - std_output[0] = std_output[1] = -1; - if (pipe(std_output) < 0) { - msgq(sp, M_SYSERR, "pipe"); - return (1); - } - if ((ifp = fdopen(std_output[0], "r")) == NULL) { - msgq(sp, M_SYSERR, "fdopen"); - goto err; - } - - /* - * Do the minimal amount of work possible, the shell is going to run - * briefly and then exit. We sincerely hope. - */ - switch (pid = vfork()) { - case -1: /* Error. */ - msgq(sp, M_SYSERR, "vfork"); -err: if (ifp != NULL) - (void)fclose(ifp); - else if (std_output[0] != -1) - close(std_output[0]); - if (std_output[1] != -1) - close(std_output[0]); - return (1); - case 0: /* Utility. */ - /* Redirect stdout to the write end of the pipe. */ - (void)dup2(std_output[1], STDOUT_FILENO); - - /* Close the utility's file descriptors. */ - (void)close(std_output[0]); - (void)close(std_output[1]); - (void)close(STDERR_FILENO); - - /* - * XXX - * Assume that all shells have -c. - */ - execl(sh_path, sh, "-c", bp, NULL); - msgq_str(sp, M_SYSERR, sh_path, "118|Error: execl: %s"); - _exit(127); - default: /* Parent. */ - /* Close the pipe ends the parent won't use. */ - (void)close(std_output[1]); - break; - } - - /* - * Copy process standard output into a buffer. - * - * !!! - * Historic vi apparently discarded leading \n and \r's from - * the shell output stream. We don't on the grounds that any - * shell that does that is broken. - */ - for (p = bp, len = 0, ch = EOF; - (ch = getc(ifp)) != EOF; *p++ = ch, --blen, ++len) - if (blen < 5) { - ADD_SPACE_GOTO(sp, bp, *blenp, *blenp * 2); - p = bp + len; - blen = *blenp - len; - } - - /* Delete the final newline, nul terminate the string. */ - if (p > bp && (p[-1] == '\n' || p[-1] == '\r')) { - --p; - --len; - } - *p = '\0'; - *lenp = len; - *bpp = bp; /* *blenp is already updated. */ - - if (ferror(ifp)) - goto ioerr; - if (fclose(ifp)) { -ioerr: msgq_str(sp, M_ERR, sh, "119|I/O error: %s"); -alloc_err: rval = SEXP_ERR; - } else - rval = SEXP_OK; - - /* - * Wait for the process. If the shell process fails (e.g., "echo $q" - * where q wasn't a defined variable) or if the returned string has - * no characters or only blank characters, (e.g., "echo $5"), complain - * that the shell expansion failed. We can't know for certain that's - * the error, but it's a good guess, and it matches historic practice. - * This won't catch "echo foo_$5", but that's not a common error and - * historic vi didn't catch it either. - */ - if (proc_wait(sp, (long)pid, sh, 1, 0)) - rval = SEXP_EXPANSION_ERR; - - for (p = bp; len; ++p, --len) - if (!isblank(*p)) - break; - if (len == 0) - rval = SEXP_EXPANSION_ERR; - - if (rval == SEXP_EXPANSION_ERR) - msgq(sp, M_ERR, "304|Shell expansion failed"); - - return (rval == SEXP_OK ? 0 : 1); -} diff --git a/contrib/nvi/ex/ex_at.c b/contrib/nvi/ex/ex_at.c deleted file mode 100644 index e9c6c59..0000000 --- a/contrib/nvi/ex/ex_at.c +++ /dev/null @@ -1,126 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_at.c 10.12 (Berkeley) 9/15/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" - -/* - * ex_at -- :@[@ | buffer] - * :*[* | buffer] - * - * Execute the contents of the buffer. - * - * PUBLIC: int ex_at __P((SCR *, EXCMD *)); - */ -int -ex_at(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - CB *cbp; - CHAR_T name; - EXCMD *ecp; - RANGE *rp; - TEXT *tp; - size_t len; - char *p; - - /* - * !!! - * Historically, [@*]<carriage-return> and [@*][@*] executed the most - * recently executed buffer in ex mode. - */ - name = FL_ISSET(cmdp->iflags, E_C_BUFFER) ? cmdp->buffer : '@'; - if (name == '@' || name == '*') { - if (!F_ISSET(sp, SC_AT_SET)) { - ex_emsg(sp, NULL, EXM_NOPREVBUF); - return (1); - } - name = sp->at_lbuf; - } - sp->at_lbuf = name; - F_SET(sp, SC_AT_SET); - - CBNAME(sp, cbp, name); - if (cbp == NULL) { - ex_emsg(sp, KEY_NAME(sp, name), EXM_EMPTYBUF); - return (1); - } - - /* - * !!! - * Historically the @ command took a range of lines, and the @ buffer - * was executed once per line. The historic vi could be trashed by - * this because it didn't notice if the underlying file changed, or, - * for that matter, if there were no more lines on which to operate. - * For example, take a 10 line file, load "%delete" into a buffer, - * and enter :8,10@<buffer>. - * - * The solution is a bit tricky. If the user specifies a range, take - * the same approach as for global commands, and discard the command - * if exit or switch to a new file/screen. If the user doesn't specify - * the range, continue to execute after a file/screen switch, which - * means @ buffers are still useful in a multi-screen environment. - */ - CALLOC_RET(sp, ecp, EXCMD *, 1, sizeof(EXCMD)); - CIRCLEQ_INIT(&ecp->rq); - CALLOC_RET(sp, rp, RANGE *, 1, sizeof(RANGE)); - rp->start = cmdp->addr1.lno; - if (F_ISSET(cmdp, E_ADDR_DEF)) { - rp->stop = rp->start; - FL_SET(ecp->agv_flags, AGV_AT_NORANGE); - } else { - rp->stop = cmdp->addr2.lno; - FL_SET(ecp->agv_flags, AGV_AT); - } - CIRCLEQ_INSERT_HEAD(&ecp->rq, rp, q); - - /* - * Buffers executed in ex mode or from the colon command line in vi - * were ex commands. We can't push it on the terminal queue, since - * it has to be executed immediately, and we may be in the middle of - * an ex command already. Push the command on the ex command stack. - * Build two copies of the command. We need two copies because the - * ex parser may step on the command string when it's parsing it. - */ - for (len = 0, tp = cbp->textq.cqh_last; - tp != (void *)&cbp->textq; tp = tp->q.cqe_prev) - len += tp->len + 1; - - MALLOC_RET(sp, ecp->cp, char *, len * 2); - ecp->o_cp = ecp->cp; - ecp->o_clen = len; - ecp->cp[len] = '\0'; - - /* Copy the buffer into the command space. */ - for (p = ecp->cp + len, tp = cbp->textq.cqh_last; - tp != (void *)&cbp->textq; tp = tp->q.cqe_prev) { - memcpy(p, tp->lb, tp->len); - p += tp->len; - *p++ = '\n'; - } - - LIST_INSERT_HEAD(&sp->gp->ecq, ecp, q); - return (0); -} diff --git a/contrib/nvi/ex/ex_bang.c b/contrib/nvi/ex/ex_bang.c deleted file mode 100644 index 25f3f77..0000000 --- a/contrib/nvi/ex/ex_bang.c +++ /dev/null @@ -1,186 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_bang.c 10.33 (Berkeley) 9/23/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" -#include "../vi/vi.h" - -/* - * ex_bang -- :[line [,line]] ! command - * - * Pass the rest of the line after the ! character to the program named by - * the O_SHELL option. - * - * Historical vi did NOT do shell expansion on the arguments before passing - * them, only file name expansion. This means that the O_SHELL program got - * "$t" as an argument if that is what the user entered. Also, there's a - * special expansion done for the bang command. Any exclamation points in - * the user's argument are replaced by the last, expanded ! command. - * - * There's some fairly amazing slop in this routine to make the different - * ways of getting here display the right things. It took a long time to - * get it right (wrong?), so be careful. - * - * PUBLIC: int ex_bang __P((SCR *, EXCMD *)); - */ -int -ex_bang(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - enum filtertype ftype; - ARGS *ap; - EX_PRIVATE *exp; - MARK rm; - recno_t lno; - int rval; - const char *msg; - - ap = cmdp->argv[0]; - if (ap->len == 0) { - ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); - return (1); - } - - /* Set the "last bang command" remembered value. */ - exp = EXP(sp); - if (exp->lastbcomm != NULL) - free(exp->lastbcomm); - if ((exp->lastbcomm = strdup(ap->bp)) == NULL) { - msgq(sp, M_SYSERR, NULL); - return (1); - } - - /* - * If the command was modified by the expansion, it was historically - * redisplayed. - */ - if (F_ISSET(cmdp, E_MODIFY) && !F_ISSET(sp, SC_EX_SILENT)) { - /* - * Display the command if modified. Historic ex/vi displayed - * the command if it was modified due to file name and/or bang - * expansion. If piping lines in vi, it would be immediately - * overwritten by any error or line change reporting. - */ - if (F_ISSET(sp, SC_VI)) - vs_update(sp, "!", ap->bp); - else { - (void)ex_printf(sp, "!%s\n", ap->bp); - (void)ex_fflush(sp); - } - } - - /* - * If no addresses were specified, run the command. If there's an - * underlying file, it's been modified and autowrite is set, write - * the file back. If the file has been modified, autowrite is not - * set and the warn option is set, tell the user about the file. - */ - if (cmdp->addrcnt == 0) { - msg = NULL; - if (sp->ep != NULL && F_ISSET(sp->ep, F_MODIFIED)) - if (O_ISSET(sp, O_AUTOWRITE)) { - if (file_aw(sp, FS_ALL)) - return (0); - } else if (O_ISSET(sp, O_WARN) && - !F_ISSET(sp, SC_EX_SILENT)) - msg = msg_cat(sp, - "303|File modified since last write.", - NULL); - - /* If we're still in a vi screen, move out explicitly. */ - (void)ex_exec_proc(sp, - cmdp, ap->bp, msg, !F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)); - } - - /* - * If addresses were specified, pipe lines from the file through the - * command. - * - * Historically, vi lines were replaced by both the stdout and stderr - * lines of the command, but ex lines by only the stdout lines. This - * makes no sense to me, so nvi makes it consistent for both, and - * matches vi's historic behavior. - */ - else { - NEEDFILE(sp, cmdp); - - /* Autoprint is set historically, even if the command fails. */ - F_SET(cmdp, E_AUTOPRINT); - - /* - * !!! - * Historical vi permitted "!!" in an empty file. When this - * happens, we arrive here with two addresses of 1,1 and a - * bad attitude. The simple solution is to turn it into a - * FILTER_READ operation, with the exception that stdin isn't - * opened for the utility, and the cursor position isn't the - * same. The only historic glitch (I think) is that we don't - * put an empty line into the default cut buffer, as historic - * vi did. Imagine, if you can, my disappointment. - */ - ftype = FILTER_BANG; - if (cmdp->addr1.lno == 1 && cmdp->addr2.lno == 1) { - if (db_last(sp, &lno)) - return (1); - if (lno == 0) { - cmdp->addr1.lno = cmdp->addr2.lno = 0; - ftype = FILTER_RBANG; - } - } - rval = ex_filter(sp, cmdp, - &cmdp->addr1, &cmdp->addr2, &rm, ap->bp, ftype); - - /* - * If in vi mode, move to the first nonblank. - * - * !!! - * Historic vi wasn't consistent in this area -- if you used - * a forward motion it moved to the first nonblank, but if you - * did a backward motion it didn't. And, if you followed a - * backward motion with a forward motion, it wouldn't move to - * the nonblank for either. Going to the nonblank generally - * seems more useful and consistent, so we do it. - */ - sp->lno = rm.lno; - if (F_ISSET(sp, SC_VI)) { - sp->cno = 0; - (void)nonblank(sp, sp->lno, &sp->cno); - } else - sp->cno = rm.cno; - } - - /* Ex terminates with a bang, even if the command fails. */ - if (!F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_EX_SILENT)) - (void)ex_puts(sp, "!\n"); - - /* - * XXX - * The ! commands never return an error, so that autoprint always - * happens in the ex parser. - */ - return (0); -} diff --git a/contrib/nvi/ex/ex_cd.c b/contrib/nvi/ex/ex_cd.c deleted file mode 100644 index 3307c7b..0000000 --- a/contrib/nvi/ex/ex_cd.c +++ /dev/null @@ -1,129 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_cd.c 10.10 (Berkeley) 8/12/96"; -#endif /* not lint */ - -#include <sys/param.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <errno.h> -#include <limits.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" - -/* - * ex_cd -- :cd[!] [directory] - * Change directories. - * - * PUBLIC: int ex_cd __P((SCR *, EXCMD *)); - */ -int -ex_cd(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - struct passwd *pw; - ARGS *ap; - CHAR_T savech; - char *dir, *p, *t; /* XXX: END OF THE STACK, DON'T TRUST GETCWD. */ - char buf[MAXPATHLEN * 2]; - - /* - * !!! - * Historic practice is that the cd isn't attempted if the file has - * been modified, unless its name begins with a leading '/' or the - * force flag is set. - */ - if (F_ISSET(sp->ep, F_MODIFIED) && - !FL_ISSET(cmdp->iflags, E_C_FORCE) && sp->frp->name[0] != '/') { - msgq(sp, M_ERR, - "120|File modified since last complete write; write or use ! to override"); - return (1); - } - - switch (cmdp->argc) { - case 0: - /* If no argument, change to the user's home directory. */ - if ((dir = getenv("HOME")) == NULL) { - if ((pw = getpwuid(getuid())) == NULL || - pw->pw_dir == NULL || pw->pw_dir[0] == '\0') { - msgq(sp, M_ERR, - "121|Unable to find home directory location"); - return (1); - } - dir = pw->pw_dir; - } - break; - case 1: - dir = cmdp->argv[0]->bp; - break; - default: - abort(); - } - - /* - * Try the current directory first. If this succeeds, don't display - * a message, vi didn't historically, and it should be obvious to the - * user where they are. - */ - if (!chdir(dir)) - return (0); - - /* - * If moving to the user's home directory, or, the path begins with - * "/", "./" or "../", it's the only place we try. - */ - if (cmdp->argc == 0 || - (ap = cmdp->argv[0])->bp[0] == '/' || - ap->len == 1 && ap->bp[0] == '.' || - ap->len >= 2 && ap->bp[0] == '.' && ap->bp[1] == '.' && - (ap->bp[2] == '/' || ap->bp[2] == '\0')) - goto err; - - /* Try the O_CDPATH option values. */ - for (p = t = O_STR(sp, O_CDPATH);; ++p) - if (*p == '\0' || *p == ':') { - /* - * Empty strings specify ".". The only way to get an - * empty string is a leading colon, colons in a row, - * or a trailing colon. Or, to put it the other way, - * if the length is 1 or less, then we're dealing with - * ":XXX", "XXX::XXXX" , "XXX:", or "". Since we've - * already tried dot, we ignore tham all. - */ - if (t < p - 1) { - savech = *p; - *p = '\0'; - (void)snprintf(buf, - sizeof(buf), "%s/%s", t, dir); - *p = savech; - if (!chdir(buf)) { - if (getcwd(buf, sizeof(buf)) != NULL) - msgq_str(sp, M_INFO, buf, "122|New current directory: %s"); - return (0); - } - } - t = p + 1; - if (*p == '\0') - break; - } - -err: msgq_str(sp, M_SYSERR, dir, "%s"); - return (1); -} diff --git a/contrib/nvi/ex/ex_cmd.c b/contrib/nvi/ex/ex_cmd.c deleted file mode 100644 index 8f7fc8d..0000000 --- a/contrib/nvi/ex/ex_cmd.c +++ /dev/null @@ -1,457 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_cmd.c 10.20 (Berkeley) 10/10/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> - -#include "../common/common.h" - -/* - * This array maps ex command names to command functions. - * - * The order in which command names are listed below is important -- - * ambiguous abbreviations are resolved to be the first possible match, - * e.g. "r" means "read", not "rewind", because "read" is listed before - * "rewind". - * - * The syntax of the ex commands is unbelievably irregular, and a special - * case from beginning to end. Each command has an associated "syntax - * script" which describes the "arguments" that are possible. The script - * syntax is as follows: - * - * ! -- ! flag - * 1 -- flags: [+-]*[pl#][+-]* - * 2 -- flags: [-.+^] - * 3 -- flags: [-.+^=] - * b -- buffer - * c[01+a] -- count (0-N, 1-N, signed 1-N, address offset) - * f[N#][or] -- file (a number or N, optional or required) - * l -- line - * S -- string with file name expansion - * s -- string - * W -- word string - * w[N#][or] -- word (a number or N, optional or required) - */ -EXCMDLIST const cmds[] = { -/* C_SCROLL */ - {"\004", ex_pr, E_ADDR2, - "", - "^D", - "scroll lines"}, -/* C_BANG */ - {"!", ex_bang, E_ADDR2_NONE | E_SECURE, - "S", - "[line [,line]] ! command", - "filter lines through commands or run commands"}, -/* C_HASH */ - {"#", ex_number, E_ADDR2|E_CLRFLAG, - "ca1", - "[line [,line]] # [count] [l]", - "display numbered lines"}, -/* C_SUBAGAIN */ - {"&", ex_subagain, E_ADDR2, - "s", - "[line [,line]] & [cgr] [count] [#lp]", - "repeat the last subsitution"}, -/* C_STAR */ - {"*", ex_at, 0, - "b", - "* [buffer]", - "execute a buffer"}, -/* C_SHIFTL */ - {"<", ex_shiftl, E_ADDR2|E_AUTOPRINT, - "ca1", - "[line [,line]] <[<...] [count] [flags]", - "shift lines left"}, -/* C_EQUAL */ - {"=", ex_equal, E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF, - "1", - "[line] = [flags]", - "display line number"}, -/* C_SHIFTR */ - {">", ex_shiftr, E_ADDR2|E_AUTOPRINT, - "ca1", - "[line [,line]] >[>...] [count] [flags]", - "shift lines right"}, -/* C_AT */ - {"@", ex_at, E_ADDR2, - "b", - "@ [buffer]", - "execute a buffer"}, -/* C_APPEND */ - {"append", ex_append, E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF, - "!", - "[line] a[ppend][!]", - "append input to a line"}, -/* C_ABBR */ - {"abbreviate", ex_abbr, 0, - "W", - "ab[brev] [word replace]", - "specify an input abbreviation"}, -/* C_ARGS */ - {"args", ex_args, 0, - "", - "ar[gs]", - "display file argument list"}, -/* C_BG */ - {"bg", ex_bg, E_VIONLY, - "", - "bg", - "put a foreground screen into the background"}, -/* C_CHANGE */ - {"change", ex_change, E_ADDR2|E_ADDR_ZERODEF, - "!ca", - "[line [,line]] c[hange][!] [count]", - "change lines to input"}, -/* C_CD */ - {"cd", ex_cd, 0, - "!f1o", - "cd[!] [directory]", - "change the current directory"}, -/* C_CHDIR */ - {"chdir", ex_cd, 0, - "!f1o", - "chd[ir][!] [directory]", - "change the current directory"}, -/* C_COPY */ - {"copy", ex_copy, E_ADDR2|E_AUTOPRINT, - "l1", - "[line [,line]] co[py] line [flags]", - "copy lines elsewhere in the file"}, -/* C_CSCOPE */ - {"cscope", ex_cscope, 0, - "!s", - "cs[cope] command [args]", - "create a set of tags using a cscope command"}, -/* - * !!! - * Adding new commands starting with 'd' may break the delete command code - * in ex_cmd() (the ex parser). Read through the comments there, first. - */ -/* C_DELETE */ - {"delete", ex_delete, E_ADDR2|E_AUTOPRINT, - "bca1", - "[line [,line]] d[elete][flags] [buffer] [count] [flags]", - "delete lines from the file"}, -/* C_DISPLAY */ - {"display", ex_display, 0, - "w1r", - "display b[uffers] | c[onnections] | s[creens] | t[ags]", - "display buffers, connections, screens or tags"}, -/* C_EDIT */ - {"edit", ex_edit, E_NEWSCREEN, - "f1o", - "[Ee][dit][!] [+cmd] [file]", - "begin editing another file"}, -/* C_EX */ - {"ex", ex_edit, E_NEWSCREEN, - "f1o", - "[Ee]x[!] [+cmd] [file]", - "begin editing another file"}, -/* C_EXUSAGE */ - {"exusage", ex_usage, 0, - "w1o", - "[exu]sage [command]", - "display ex command usage statement"}, -/* C_FILE */ - {"file", ex_file, 0, - "f1o", - "f[ile] [name]", - "display (and optionally set) file name"}, -/* C_FG */ - {"fg", ex_fg, E_NEWSCREEN|E_VIONLY, - "f1o", - "[Ff]g [file]", - "bring a backgrounded screen into the foreground"}, -/* C_GLOBAL */ - {"global", ex_global, E_ADDR2_ALL, - "!s", - "[line [,line]] g[lobal][!] [;/]RE[;/] [commands]", - "execute a global command on lines matching an RE"}, -/* C_HELP */ - {"help", ex_help, 0, - "", - "he[lp]", - "display help statement"}, -/* C_INSERT */ - {"insert", ex_insert, E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF, - "!", - "[line] i[nsert][!]", - "insert input before a line"}, -/* C_JOIN */ - {"join", ex_join, E_ADDR2|E_AUTOPRINT, - "!ca1", - "[line [,line]] j[oin][!] [count] [flags]", - "join lines into a single line"}, -/* C_K */ - {"k", ex_mark, E_ADDR1, - "w1r", - "[line] k key", - "mark a line position"}, -/* C_LIST */ - {"list", ex_list, E_ADDR2|E_CLRFLAG, - "ca1", - "[line [,line]] l[ist] [count] [#]", - "display lines in an unambiguous form"}, -/* C_MOVE */ - {"move", ex_move, E_ADDR2|E_AUTOPRINT, - "l", - "[line [,line]] m[ove] line", - "move lines elsewhere in the file"}, -/* C_MARK */ - {"mark", ex_mark, E_ADDR1, - "w1r", - "[line] ma[rk] key", - "mark a line position"}, -/* C_MAP */ - {"map", ex_map, 0, - "!W", - "map[!] [keys replace]", - "map input or commands to one or more keys"}, -/* C_MKEXRC */ - {"mkexrc", ex_mkexrc, 0, - "!f1r", - "mkexrc[!] file", - "write a .exrc file"}, -/* C_NEXT */ - {"next", ex_next, E_NEWSCREEN, - "!fN", - "[Nn][ext][!] [+cmd] [file ...]", - "edit (and optionally specify) the next file"}, -/* C_NUMBER */ - {"number", ex_number, E_ADDR2|E_CLRFLAG, - "ca1", - "[line [,line]] nu[mber] [count] [l]", - "change display to number lines"}, -/* C_OPEN */ - {"open", ex_open, E_ADDR1, - "s", - "[line] o[pen] [/RE/] [flags]", - "enter \"open\" mode (not implemented)"}, -/* C_PRINT */ - {"print", ex_pr, E_ADDR2|E_CLRFLAG, - "ca1", - "[line [,line]] p[rint] [count] [#l]", - "display lines"}, -/* C_PERLCMD */ - {"perl", ex_perl, E_ADDR2_ALL|E_ADDR_ZERO| - E_ADDR_ZERODEF|E_SECURE, - "s", - "pe[rl] cmd", - "run the perl interpreter with the command"}, -/* C_PERLDOCMD */ - {"perldo", ex_perl, E_ADDR2_ALL|E_ADDR_ZERO| - E_ADDR_ZERODEF|E_SECURE, - "s", - "perld[o] cmd", - "run the perl interpreter with the command, on each line"}, -/* C_PRESERVE */ - {"preserve", ex_preserve, 0, - "", - "pre[serve]", - "preserve an edit session for recovery"}, -/* C_PREVIOUS */ - {"previous", ex_prev, E_NEWSCREEN, - "!", - "[Pp]rev[ious][!]", - "edit the previous file in the file argument list"}, -/* C_PUT */ - {"put", ex_put, - E_ADDR1|E_AUTOPRINT|E_ADDR_ZERO|E_ADDR_ZERODEF, - "b", - "[line] pu[t] [buffer]", - "append a cut buffer to the line"}, -/* C_QUIT */ - {"quit", ex_quit, 0, - "!", - "q[uit][!]", - "exit ex/vi"}, -/* C_READ */ - {"read", ex_read, E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF, - "s", - "[line] r[ead] [!cmd | [file]]", - "append input from a command or file to the line"}, -/* C_RECOVER */ - {"recover", ex_recover, 0, - "!f1r", - "recover[!] file", - "recover a saved file"}, -/* C_RESIZE */ - {"resize", ex_resize, E_VIONLY, - "c+", - "resize [+-]rows", - "grow or shrink the current screen"}, -/* C_REWIND */ - {"rewind", ex_rew, 0, - "!", - "rew[ind][!]", - "re-edit all the files in the file argument list"}, -/* - * !!! - * Adding new commands starting with 's' may break the substitute command code - * in ex_cmd() (the ex parser). Read through the comments there, first. - */ -/* C_SUBSTITUTE */ - {"s", ex_s, E_ADDR2, - "s", - "[line [,line]] s [[/;]RE[/;]repl[/;] [cgr] [count] [#lp]]", - "substitute on lines matching an RE"}, -/* C_SCRIPT */ - {"script", ex_script, E_SECURE, - "!f1o", - "sc[ript][!] [file]", - "run a shell in a screen"}, -/* C_SET */ - {"set", ex_set, 0, - "wN", - "se[t] [option[=[value]]...] [nooption ...] [option? ...] [all]", - "set options (use \":set all\" to see all options)"}, -/* C_SHELL */ - {"shell", ex_shell, E_SECURE, - "", - "sh[ell]", - "suspend editing and run a shell"}, -/* C_SOURCE */ - {"source", ex_source, 0, - "f1r", - "so[urce] file", - "read a file of ex commands"}, -/* C_STOP */ - {"stop", ex_stop, E_SECURE, - "!", - "st[op][!]", - "suspend the edit session"}, -/* C_SUSPEND */ - {"suspend", ex_stop, E_SECURE, - "!", - "su[spend][!]", - "suspend the edit session"}, -/* C_T */ - {"t", ex_copy, E_ADDR2|E_AUTOPRINT, - "l1", - "[line [,line]] t line [flags]", - "copy lines elsewhere in the file"}, -/* C_TAG */ - {"tag", ex_tag_push, E_NEWSCREEN, - "!w1o", - "[Tt]a[g][!] [string]", - "edit the file containing the tag"}, -/* C_TAGNEXT */ - {"tagnext", ex_tag_next, 0, - "!", - "tagn[ext][!]", - "move to the next tag"}, -/* C_TAGPOP */ - {"tagpop", ex_tag_pop, 0, - "!w1o", - "tagp[op][!] [number | file]", - "return to the previous group of tags"}, -/* C_TAGPREV */ - {"tagprev", ex_tag_prev, 0, - "!", - "tagpr[ev][!]", - "move to the previous tag"}, -/* C_TAGTOP */ - {"tagtop", ex_tag_top, 0, - "!", - "tagt[op][!]", - "discard all tags"}, -/* C_TCLCMD */ - {"tcl", ex_tcl, E_ADDR2_ALL|E_ADDR_ZERO| - E_ADDR_ZERODEF|E_SECURE, - "s", - "tc[l] cmd", - "run the tcl interpreter with the command"}, -/* C_UNDO */ - {"undo", ex_undo, E_AUTOPRINT, - "", - "u[ndo]", - "undo the most recent change"}, -/* C_UNABBREVIATE */ - {"unabbreviate",ex_unabbr, 0, - "w1r", - "una[bbrev] word", - "delete an abbreviation"}, -/* C_UNMAP */ - {"unmap", ex_unmap, 0, - "!w1r", - "unm[ap][!] word", - "delete an input or command map"}, -/* C_V */ - {"v", ex_v, E_ADDR2_ALL, - "s", - "[line [,line]] v [;/]RE[;/] [commands]", - "execute a global command on lines NOT matching an RE"}, -/* C_VERSION */ - {"version", ex_version, 0, - "", - "version", - "display the program version information"}, -/* C_VISUAL_EX */ - {"visual", ex_visual, E_ADDR1|E_ADDR_ZERODEF, - "2c11", - "[line] vi[sual] [-|.|+|^] [window_size] [flags]", - "enter visual (vi) mode from ex mode"}, -/* C_VISUAL_VI */ - {"visual", ex_edit, E_NEWSCREEN, - "f1o", - "[Vv]i[sual][!] [+cmd] [file]", - "edit another file (from vi mode only)"}, -/* C_VIUSAGE */ - {"viusage", ex_viusage, 0, - "w1o", - "[viu]sage [key]", - "display vi key usage statement"}, -/* C_WRITE */ - {"write", ex_write, E_ADDR2_ALL|E_ADDR_ZERODEF, - "!s", - "[line [,line]] w[rite][!] [ !cmd | [>>] [file]]", - "write the file"}, -/* C_WN */ - {"wn", ex_wn, E_ADDR2_ALL|E_ADDR_ZERODEF, - "!s", - "[line [,line]] wn[!] [>>] [file]", - "write the file and switch to the next file"}, -/* C_WQ */ - {"wq", ex_wq, E_ADDR2_ALL|E_ADDR_ZERODEF, - "!s", - "[line [,line]] wq[!] [>>] [file]", - "write the file and exit"}, -/* C_XIT */ - {"xit", ex_xit, E_ADDR2_ALL|E_ADDR_ZERODEF, - "!f1o", - "[line [,line]] x[it][!] [file]", - "exit"}, -/* C_YANK */ - {"yank", ex_yank, E_ADDR2, - "bca", - "[line [,line]] ya[nk] [buffer] [count]", - "copy lines to a cut buffer"}, -/* C_Z */ - {"z", ex_z, E_ADDR1, - "3c01", - "[line] z [-|.|+|^|=] [count] [flags]", - "display different screens of the file"}, -/* C_SUBTILDE */ - {"~", ex_subtilde, E_ADDR2, - "s", - "[line [,line]] ~ [cgr] [count] [#lp]", - "replace previous RE with previous replacement string,"}, - {NULL}, -}; diff --git a/contrib/nvi/ex/ex_cscope.c b/contrib/nvi/ex/ex_cscope.c deleted file mode 100644 index c2fa0a5..0000000 --- a/contrib/nvi/ex/ex_cscope.c +++ /dev/null @@ -1,1057 +0,0 @@ -/*- - * Copyright (c) 1994, 1996 - * Rob Mayoff. All rights reserved. - * Copyright (c) 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_cscope.c 10.13 (Berkeley) 9/15/96"; -#endif /* not lint */ - -#include <sys/param.h> -#include <sys/types.h> /* XXX: param.h may not have included types.h */ -#include <sys/queue.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/wait.h> - -#include <bitstring.h> -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <termios.h> -#include <unistd.h> - -#include "../common/common.h" -#include "pathnames.h" -#include "tag.h" - -#define CSCOPE_DBFILE "cscope.out" -#define CSCOPE_PATHS "cscope.tpath" - -/* - * 0name find all uses of name - * 1name find definition of name - * 2name find all function calls made from name - * 3name find callers of name - * 4string find text string (cscope 12.9) - * 4name find assignments to name (cscope 13.3) - * 5pattern change pattern -- NOT USED - * 6pattern find pattern - * 7name find files with name as substring - * 8name find files #including name - */ -#define FINDHELP "\ -find c|d|e|f|g|i|s|t buffer|pattern\n\ - c: find callers of name\n\ - d: find all function calls made from name\n\ - e: find pattern\n\ - f: find files with name as substring\n\ - g: find definition of name\n\ - i: find files #including name\n\ - s: find all uses of name\n\ - t: find assignments to name" - -static int cscope_add __P((SCR *, EXCMD *, char *)); -static int cscope_find __P((SCR *, EXCMD*, char *)); -static int cscope_help __P((SCR *, EXCMD *, char *)); -static int cscope_kill __P((SCR *, EXCMD *, char *)); -static int cscope_reset __P((SCR *, EXCMD *, char *)); - -typedef struct _cc { - char *name; - int (*function) __P((SCR *, EXCMD *, char *)); - char *help_msg; - char *usage_msg; -} CC; - -static CC const cscope_cmds[] = { - { "add", cscope_add, - "Add a new cscope database", "add file | directory" }, - { "find", cscope_find, - "Query the databases for a pattern", FINDHELP }, - { "help", cscope_help, - "Show help for cscope commands", "help [command]" }, - { "kill", cscope_kill, - "Kill a cscope connection", "kill number" }, - { "reset", cscope_reset, - "Discard all current cscope connections", "reset" }, - { NULL } -}; - -static TAGQ *create_cs_cmd __P((SCR *, char *, size_t *)); -static int csc_help __P((SCR *, char *)); -static void csc_file __P((SCR *, - CSC *, char *, char **, size_t *, int *)); -static int get_paths __P((SCR *, CSC *)); -static CC const *lookup_ccmd __P((char *)); -static int parse __P((SCR *, CSC *, TAGQ *, int *)); -static int read_prompt __P((SCR *, CSC *)); -static int run_cscope __P((SCR *, CSC *, char *)); -static int start_cscopes __P((SCR *, EXCMD *)); -static int terminate __P((SCR *, CSC *, int)); - -/* - * ex_cscope -- - * Perform an ex cscope. - * - * PUBLIC: int ex_cscope __P((SCR *, EXCMD *)); - */ -int -ex_cscope(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - CC const *ccp; - EX_PRIVATE *exp; - int i; - char *cmd, *p; - - /* Initialize the default cscope directories. */ - exp = EXP(sp); - if (!F_ISSET(exp, EXP_CSCINIT) && start_cscopes(sp, cmdp)) - return (1); - F_SET(exp, EXP_CSCINIT); - - /* Skip leading whitespace. */ - for (p = cmdp->argv[0]->bp, i = cmdp->argv[0]->len; i > 0; --i, ++p) - if (!isspace(*p)) - break; - if (i == 0) - goto usage; - - /* Skip the command to any arguments. */ - for (cmd = p; i > 0; --i, ++p) - if (isspace(*p)) - break; - if (*p != '\0') { - *p++ = '\0'; - for (; *p && isspace(*p); ++p); - } - - if ((ccp = lookup_ccmd(cmd)) == NULL) { -usage: msgq(sp, M_ERR, "309|Use \"cscope help\" for help"); - return (1); - } - - /* Call the underlying function. */ - return (ccp->function(sp, cmdp, p)); -} - -/* - * start_cscopes -- - * Initialize the cscope package. - */ -static int -start_cscopes(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - size_t blen, len; - char *bp, *cscopes, *p, *t; - - /* - * EXTENSION #1: - * - * If the CSCOPE_DIRS environment variable is set, we treat it as a - * list of cscope directories that we're using, similar to the tags - * edit option. - * - * XXX - * This should probably be an edit option, although that implies that - * we start/stop cscope processes periodically, instead of once when - * the editor starts. - */ - if ((cscopes = getenv("CSCOPE_DIRS")) == NULL) - return (0); - len = strlen(cscopes); - GET_SPACE_RET(sp, bp, blen, len); - memcpy(bp, cscopes, len + 1); - - for (cscopes = t = bp; (p = strsep(&t, "\t :")) != NULL;) - if (*p != '\0') - (void)cscope_add(sp, cmdp, p); - - FREE_SPACE(sp, bp, blen); - return (0); -} - -/* - * cscope_add -- - * The cscope add command. - */ -static int -cscope_add(sp, cmdp, dname) - SCR *sp; - EXCMD *cmdp; - char *dname; -{ - struct stat sb; - EX_PRIVATE *exp; - CSC *csc; - size_t len; - int cur_argc; - char *dbname, path[MAXPATHLEN]; - - exp = EXP(sp); - - /* - * 0 additional args: usage. - * 1 additional args: matched a file. - * >1 additional args: object, too many args. - */ - cur_argc = cmdp->argc; - if (argv_exp2(sp, cmdp, dname, strlen(dname))) - return (1); - if (cmdp->argc == cur_argc) { - (void)csc_help(sp, "add"); - return (1); - } - if (cmdp->argc == cur_argc + 1) - dname = cmdp->argv[cur_argc]->bp; - else { - ex_emsg(sp, dname, EXM_FILECOUNT); - return (1); - } - - /* - * The user can specify a specific file (so they can have multiple - * Cscope databases in a single directory) or a directory. If the - * file doesn't exist, we're done. If it's a directory, append the - * standard database file name and try again. Store the directory - * name regardless so that we can use it as a base for searches. - */ - if (stat(dname, &sb)) { - msgq(sp, M_SYSERR, dname); - return (1); - } - if (S_ISDIR(sb.st_mode)) { - (void)snprintf(path, sizeof(path), - "%s/%s", dname, CSCOPE_DBFILE); - if (stat(path, &sb)) { - msgq(sp, M_SYSERR, path); - return (1); - } - dbname = CSCOPE_DBFILE; - } else if ((dbname = strrchr(dname, '/')) != NULL) - *dbname++ = '\0'; - - /* Allocate a cscope connection structure and initialize its fields. */ - len = strlen(dname); - CALLOC_RET(sp, csc, CSC *, 1, sizeof(CSC) + len); - csc->dname = csc->buf; - csc->dlen = len; - memcpy(csc->dname, dname, len); - csc->mtime = sb.st_mtime; - - /* Get the search paths for the cscope. */ - if (get_paths(sp, csc)) - goto err; - - /* Start the cscope process. */ - if (run_cscope(sp, csc, dbname)) - goto err; - - /* - * Add the cscope connection to the screen's list. From now on, - * on error, we have to call terminate, which expects the csc to - * be on the chain. - */ - LIST_INSERT_HEAD(&exp->cscq, csc, q); - - /* Read the initial prompt from the cscope to make sure it's okay. */ - if (read_prompt(sp, csc)) { - terminate(sp, csc, 0); - return (1); - } - - return (0); - -err: free(csc); - return (1); -} - -/* - * get_paths -- - * Get the directories to search for the files associated with this - * cscope database. - */ -static int -get_paths(sp, csc) - SCR *sp; - CSC *csc; -{ - struct stat sb; - int fd, nentries; - size_t len; - char *p, **pathp, buf[MAXPATHLEN * 2]; - - /* - * EXTENSION #2: - * - * If there's a cscope directory with a file named CSCOPE_PATHS, it - * contains a colon-separated list of paths in which to search for - * files returned by cscope. - * - * XXX - * These paths are absolute paths, and not relative to the cscope - * directory. To fix this, rewrite the each path using the cscope - * directory as a prefix. - */ - (void)snprintf(buf, sizeof(buf), "%s/%s", csc->dname, CSCOPE_PATHS); - if (stat(buf, &sb) == 0) { - /* Read in the CSCOPE_PATHS file. */ - len = sb.st_size; - MALLOC_RET(sp, csc->pbuf, char *, len + 1); - if ((fd = open(buf, O_RDONLY, 0)) < 0 || - read(fd, csc->pbuf, len) != len) { - msgq_str(sp, M_SYSERR, buf, "%s"); - if (fd >= 0) - (void)close(fd); - return (1); - } - (void)close(fd); - csc->pbuf[len] = '\0'; - - /* Count up the entries. */ - for (nentries = 0, p = csc->pbuf; *p != '\0'; ++p) - if (p[0] == ':' && p[1] != '\0') - ++nentries; - - /* Build an array of pointers to the paths. */ - CALLOC_GOTO(sp, - csc->paths, char **, nentries + 1, sizeof(char **)); - for (pathp = csc->paths, p = strtok(csc->pbuf, ":"); - p != NULL; p = strtok(NULL, ":")) - *pathp++ = p; - return (0); - } - - /* - * If the CSCOPE_PATHS file doesn't exist, we look for files - * relative to the cscope directory. - */ - if ((csc->pbuf = strdup(csc->dname)) == NULL) { - msgq(sp, M_SYSERR, NULL); - return (1); - } - CALLOC_GOTO(sp, csc->paths, char **, 2, sizeof(char *)); - csc->paths[0] = csc->pbuf; - return (0); - -alloc_err: - if (csc->pbuf != NULL) { - free(csc->pbuf); - csc->pbuf = NULL; - } - return (1); -} - -/* - * run_cscope -- - * Fork off the cscope process. - */ -static int -run_cscope(sp, csc, dbname) - SCR *sp; - CSC *csc; - char *dbname; -{ - int to_cs[2], from_cs[2]; - char cmd[MAXPATHLEN * 2]; - - /* - * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from - * from_cs[0] and writes to to_cs[1]. - */ - to_cs[0] = to_cs[1] = from_cs[0] = from_cs[0] = -1; - if (pipe(to_cs) < 0 || pipe(from_cs) < 0) { - msgq(sp, M_SYSERR, "pipe"); - goto err; - } - switch (csc->pid = vfork()) { - case -1: - msgq(sp, M_SYSERR, "vfork"); -err: if (to_cs[0] != -1) - (void)close(to_cs[0]); - if (to_cs[1] != -1) - (void)close(to_cs[1]); - if (from_cs[0] != -1) - (void)close(from_cs[0]); - if (from_cs[1] != -1) - (void)close(from_cs[1]); - return (1); - case 0: /* child: run cscope. */ - (void)dup2(to_cs[0], STDIN_FILENO); - (void)dup2(from_cs[1], STDOUT_FILENO); - (void)dup2(from_cs[1], STDERR_FILENO); - - /* Close unused file descriptors. */ - (void)close(to_cs[1]); - (void)close(from_cs[0]); - - /* Run the cscope command. */ -#define CSCOPE_CMD_FMT "cd '%s' && exec cscope -dl -f %s" - (void)snprintf(cmd, sizeof(cmd), - CSCOPE_CMD_FMT, csc->dname, dbname); - (void)execl(_PATH_BSHELL, "sh", "-c", cmd, NULL); - msgq_str(sp, M_SYSERR, cmd, "execl: %s"); - _exit (127); - /* NOTREACHED */ - default: /* parent. */ - /* Close unused file descriptors. */ - (void)close(to_cs[0]); - (void)close(from_cs[1]); - - /* - * Save the file descriptors for later duplication, and - * reopen as streams. - */ - csc->to_fd = to_cs[1]; - csc->to_fp = fdopen(to_cs[1], "w"); - csc->from_fd = from_cs[0]; - csc->from_fp = fdopen(from_cs[0], "r"); - break; - } - return (0); -} - -/* - * cscope_find -- - * The cscope find command. - */ -static int -cscope_find(sp, cmdp, pattern) - SCR *sp; - EXCMD *cmdp; - char *pattern; -{ - CSC *csc, *csc_next; - EX_PRIVATE *exp; - FREF *frp; - TAGQ *rtqp, *tqp; - TAG *rtp; - recno_t lno; - size_t cno, search; - int force, istmp, matches; - - exp = EXP(sp); - - /* Check for connections. */ - if (exp->cscq.lh_first == NULL) { - msgq(sp, M_ERR, "310|No cscope connections running"); - return (1); - } - - /* - * Allocate all necessary memory before doing anything hard. If the - * tags stack is empty, we'll need the `local context' TAGQ structure - * later. - */ - rtp = NULL; - rtqp = NULL; - if (exp->tq.cqh_first == (void *)&exp->tq) { - /* Initialize the `local context' tag queue structure. */ - CALLOC_GOTO(sp, rtqp, TAGQ *, 1, sizeof(TAGQ)); - CIRCLEQ_INIT(&rtqp->tagq); - - /* Initialize and link in its tag structure. */ - CALLOC_GOTO(sp, rtp, TAG *, 1, sizeof(TAG)); - CIRCLEQ_INSERT_HEAD(&rtqp->tagq, rtp, q); - rtqp->current = rtp; - } - - /* Create the cscope command. */ - if ((tqp = create_cs_cmd(sp, pattern, &search)) == NULL) - goto err; - - /* - * Stick the current context in a convenient place, we'll lose it - * when we switch files. - */ - frp = sp->frp; - lno = sp->lno; - cno = sp->cno; - istmp = F_ISSET(sp->frp, FR_TMPFILE) && !F_ISSET(cmdp, E_NEWSCREEN); - - /* Search all open connections for a match. */ - matches = 0; - for (csc = exp->cscq.lh_first; csc != NULL; csc = csc_next) { - /* Copy csc->q.lh_next here in case csc is killed. */ - csc_next = csc->q.le_next; - - /* - * Send the command to the cscope program. (We skip the - * first two bytes of the command, because we stored the - * search cscope command character and a leading space - * there.) - */ - (void)fprintf(csc->to_fp, "%d%s\n", search, tqp->tag + 2); - (void)fflush(csc->to_fp); - - /* Read the output. */ - if (parse(sp, csc, tqp, &matches)) { - if (rtqp != NULL) - free(rtqp); - tagq_free(sp, tqp); - return (1); - } - } - - if (matches == 0) { - msgq(sp, M_INFO, "278|No matches for query"); - return (0); - } - - tqp->current = tqp->tagq.cqh_first; - - /* Try to switch to the first tag. */ - force = FL_ISSET(cmdp->iflags, E_C_FORCE); - if (F_ISSET(cmdp, E_NEWSCREEN)) { - if (ex_tag_Nswitch(sp, tqp->current, force)) - goto err; - - /* Everything else gets done in the new screen. */ - sp = sp->nextdisp; - exp = EXP(sp); - } else - if (ex_tag_nswitch(sp, tqp->current, force)) - goto err; - - /* - * If this is the first tag, put a `current location' queue entry - * in place, so we can pop all the way back to the current mark. - * Note, it doesn't point to much of anything, it's a placeholder. - */ - if (exp->tq.cqh_first == (void *)&exp->tq) { - CIRCLEQ_INSERT_HEAD(&exp->tq, rtqp, q); - } else - rtqp = exp->tq.cqh_first; - - /* Link the current TAGQ structure into place. */ - CIRCLEQ_INSERT_HEAD(&exp->tq, tqp, q); - - (void)cscope_search(sp, tqp, tqp->current); - - /* - * Move the current context from the temporary save area into the - * right structure. - * - * If we were in a temporary file, we don't have a context to which - * we can return, so just make it be the same as what we're moving - * to. It will be a little odd that ^T doesn't change anything, but - * I don't think it's a big deal. - */ - if (istmp) { - rtqp->current->frp = sp->frp; - rtqp->current->lno = sp->lno; - rtqp->current->cno = sp->cno; - } else { - rtqp->current->frp = frp; - rtqp->current->lno = lno; - rtqp->current->cno = cno; - } - - return (0); - -err: -alloc_err: - if (rtqp != NULL) - free(rtqp); - if (rtp != NULL) - free(rtp); - return (1); -} - -/* - * create_cs_cmd -- - * Build a cscope command, creating and initializing the base TAGQ. - */ -static TAGQ * -create_cs_cmd(sp, pattern, searchp) - SCR *sp; - char *pattern; - size_t *searchp; -{ - CB *cbp; - TAGQ *tqp; - size_t tlen; - char *p; - - /* - * Cscope supports a "change pattern" command which we never use, - * cscope command 5. Set CSCOPE_QUERIES[5] to " " since the user - * can't pass " " as the first character of pattern. That way the - * user can't ask for pattern 5 so we don't need any special-case - * code. - */ -#define CSCOPE_QUERIES "sgdct efi" - - if (pattern == NULL) - goto usage; - - /* Skip leading blanks, check for command character. */ - for (; isblank(pattern[0]); ++pattern); - if (pattern[0] == '\0' || !isblank(pattern[1])) - goto usage; - for (*searchp = 0, p = CSCOPE_QUERIES; - *p != '\0' && *p != pattern[0]; ++*searchp, ++p); - if (*p == '\0') { - msgq(sp, M_ERR, - "311|%s: unknown search type: use one of %s", - KEY_NAME(sp, pattern[0]), CSCOPE_QUERIES); - return (NULL); - } - - /* Skip <blank> characters to the pattern. */ - for (p = pattern + 1; *p != '\0' && isblank(*p); ++p); - if (*p == '\0') { -usage: (void)csc_help(sp, "find"); - return (NULL); - } - - /* The user can specify the contents of a buffer as the pattern. */ - cbp = NULL; - if (p[0] == '"' && p[1] != '\0' && p[2] == '\0') - CBNAME(sp, cbp, p[1]); - if (cbp != NULL) { - p = cbp->textq.cqh_first->lb; - tlen = cbp->textq.cqh_first->len; - } else - tlen = strlen(p); - - /* Allocate and initialize the TAGQ structure. */ - CALLOC(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + tlen + 3); - if (tqp == NULL) - return (NULL); - CIRCLEQ_INIT(&tqp->tagq); - tqp->tag = tqp->buf; - tqp->tag[0] = pattern[0]; - tqp->tag[1] = ' '; - tqp->tlen = tlen + 2; - memcpy(tqp->tag + 2, p, tlen); - tqp->tag[tlen + 2] = '\0'; - F_SET(tqp, TAG_CSCOPE); - - return (tqp); -} - -/* - * parse -- - * Parse the cscope output. - */ -static int -parse(sp, csc, tqp, matchesp) - SCR *sp; - CSC *csc; - TAGQ *tqp; - int *matchesp; -{ - TAG *tp; - recno_t slno; - size_t dlen, nlen, slen; - int ch, i, isolder, nlines; - char *dname, *name, *search, *p, *t, dummy[2], buf[2048]; - - for (;;) { - if (!fgets(buf, sizeof(buf), csc->from_fp)) - goto io_err; - - /* - * If the database is out of date, or there's some other - * problem, cscope will output error messages before the - * number-of-lines output. Display/discard any output - * that doesn't match what we want. - */ -#define CSCOPE_NLINES_FMT "cscope: %d lines%1[\n]" - if (sscanf(buf, CSCOPE_NLINES_FMT, &nlines, dummy) == 2) - break; - if ((p = strchr(buf, '\n')) != NULL) - *p = '\0'; - msgq(sp, M_ERR, "%s: \"%s\"", csc->dname, buf); - } - - while (nlines--) { - if (fgets(buf, sizeof(buf), csc->from_fp) == NULL) - goto io_err; - - /* If the line's too long for the buffer, discard it. */ - if ((p = strchr(buf, '\n')) == NULL) { - while ((ch = getc(csc->from_fp)) != EOF && ch != '\n'); - continue; - } - *p = '\0'; - - /* - * The cscope output is in the following format: - * - * <filename> <context> <line number> <pattern> - * - * Figure out how long everything is so we can allocate in one - * swell foop, but discard anything that looks wrong. - */ - for (p = buf, i = 0; - i < 3 && (t = strsep(&p, "\t ")) != NULL; ++i) - switch (i) { - case 0: /* Filename. */ - name = t; - nlen = strlen(name); - break; - case 1: /* Context. */ - break; - case 2: /* Line number. */ - slno = (recno_t)atol(t); - break; - } - if (i != 3 || p == NULL || t == NULL) - continue; - - /* The rest of the string is the search pattern. */ - search = p; - slen = strlen(p); - - /* Resolve the file name. */ - csc_file(sp, csc, name, &dname, &dlen, &isolder); - - /* - * If the file is older than the cscope database, that is, - * the database was built since the file was last modified, - * or there wasn't a search string, use the line number. - */ - if (isolder || strcmp(search, "<unknown>") == 0) { - search = NULL; - slen = 0; - } - - /* - * Allocate and initialize a tag structure plus the variable - * length cscope information that follows it. - */ - CALLOC_RET(sp, tp, - TAG *, 1, sizeof(TAG) + dlen + 2 + nlen + 1 + slen + 1); - tp->fname = tp->buf; - if (dlen != 0) { - memcpy(tp->fname, dname, dlen); - tp->fname[dlen] = '/'; - ++dlen; - } - memcpy(tp->fname + dlen, name, nlen + 1); - tp->fnlen = dlen + nlen; - tp->slno = slno; - if (slen != 0) { - tp->search = tp->fname + tp->fnlen + 1; - memcpy(tp->search, search, (tp->slen = slen) + 1); - } - CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q); - - ++*matchesp; - } - - (void)read_prompt(sp, csc); - return (0); - -io_err: if (feof(csc->from_fp)) - errno = EIO; - msgq_str(sp, M_SYSERR, "%s", csc->dname); - terminate(sp, csc, 0); - return (1); -} - -/* - * csc_file -- - * Search for the right path to this file. - */ -static void -csc_file(sp, csc, name, dirp, dlenp, isolderp) - SCR *sp; - CSC *csc; - char *name, **dirp; - size_t *dlenp; - int *isolderp; -{ - struct stat sb; - char **pp, buf[MAXPATHLEN]; - - /* - * Check for the file in all of the listed paths. If we don't - * find it, we simply return it unchanged. We have to do this - * now, even though it's expensive, because if the user changes - * directories, we can't change our minds as to where the file - * lives. - */ - for (pp = csc->paths; *pp != NULL; ++pp) { - (void)snprintf(buf, sizeof(buf), "%s/%s", *pp, name); - if (stat(buf, &sb) == 0) { - *dirp = *pp; - *dlenp = strlen(*pp); - *isolderp = sb.st_mtime < csc->mtime; - return; - } - } - *dlenp = 0; -} - -/* - * cscope_help -- - * The cscope help command. - */ -static int -cscope_help(sp, cmdp, subcmd) - SCR *sp; - EXCMD *cmdp; - char *subcmd; -{ - return (csc_help(sp, subcmd)); -} - -/* - * csc_help -- - * Display help/usage messages. - */ -static int -csc_help(sp, cmd) - SCR *sp; - char *cmd; -{ - CC const *ccp; - - if (cmd != NULL && *cmd != '\0') - if ((ccp = lookup_ccmd(cmd)) == NULL) { - ex_printf(sp, - "%s doesn't match any cscope command\n", cmd); - return (1); - } else { - ex_printf(sp, - "Command: %s (%s)\n", ccp->name, ccp->help_msg); - ex_printf(sp, " Usage: %s\n", ccp->usage_msg); - return (0); - } - - ex_printf(sp, "cscope commands:\n"); - for (ccp = cscope_cmds; ccp->name != NULL; ++ccp) - ex_printf(sp, " %*s: %s\n", 5, ccp->name, ccp->help_msg); - return (0); -} - -/* - * cscope_kill -- - * The cscope kill command. - */ -static int -cscope_kill(sp, cmdp, cn) - SCR *sp; - EXCMD *cmdp; - char *cn; -{ - return (terminate(sp, NULL, atoi(cn))); -} - -/* - * terminate -- - * Detach from a cscope process. - */ -static int -terminate(sp, csc, n) - SCR *sp; - CSC *csc; - int n; -{ - EX_PRIVATE *exp; - int i, pstat; - - exp = EXP(sp); - - /* - * We either get a csc structure or a number. If not provided a - * csc structure, find the right one. - */ - if (csc == NULL) { - if (n < 1) - goto badno; - for (i = 1, csc = exp->cscq.lh_first; - csc != NULL; csc = csc->q.le_next, i++) - if (i == n) - break; - if (csc == NULL) { -badno: msgq(sp, M_ERR, "312|%d: no such cscope session", n); - return (1); - } - } - - /* - * XXX - * Theoretically, we have the only file descriptors to the process, - * so closing them should let it exit gracefully, deleting temporary - * files, etc. The original vi cscope integration sent the cscope - * connection a SIGTERM signal, so I'm not sure if closing the file - * descriptors is sufficient. - */ - if (csc->from_fp != NULL) - (void)fclose(csc->from_fp); - if (csc->to_fp != NULL) - (void)fclose(csc->to_fp); - (void)waitpid(csc->pid, &pstat, 0); - - /* Discard cscope connection information. */ - LIST_REMOVE(csc, q); - if (csc->pbuf != NULL) - free(csc->pbuf); - if (csc->paths != NULL) - free(csc->paths); - free(csc); - return (0); -} - -/* - * cscope_reset -- - * The cscope reset command. - */ -static int -cscope_reset(sp, cmdp, notusedp) - SCR *sp; - EXCMD *cmdp; - char *notusedp; -{ - EX_PRIVATE *exp; - - for (exp = EXP(sp); exp->cscq.lh_first != NULL;) - if (cscope_kill(sp, cmdp, "1")) - return (1); - return (0); -} - -/* - * cscope_display -- - * Display current connections. - * - * PUBLIC: int cscope_display __P((SCR *)); - */ -int -cscope_display(sp) - SCR *sp; -{ - EX_PRIVATE *exp; - CSC *csc; - int i; - - exp = EXP(sp); - if (exp->cscq.lh_first == NULL) { - ex_printf(sp, "No cscope connections.\n"); - return (0); - } - for (i = 1, - csc = exp->cscq.lh_first; csc != NULL; ++i, csc = csc->q.le_next) - ex_printf(sp, - "%2d %s (process %lu)\n", i, csc->dname, (u_long)csc->pid); - return (0); -} - -/* - * cscope_search -- - * Search a file for a cscope entry. - * - * PUBLIC: int cscope_search __P((SCR *, TAGQ *, TAG *)); - */ -int -cscope_search(sp, tqp, tp) - SCR *sp; - TAGQ *tqp; - TAG *tp; -{ - MARK m; - - /* If we don't have a search pattern, use the line number. */ - if (tp->search == NULL) { - if (!db_exist(sp, tp->slno)) { - tag_msg(sp, TAG_BADLNO, tqp->tag); - return (1); - } - m.lno = tp->slno; - } else { - /* - * Search for the tag; cheap fallback for C functions - * if the name is the same but the arguments have changed. - */ - m.lno = 1; - m.cno = 0; - if (f_search(sp, &m, &m, - tp->search, tp->slen, NULL, SEARCH_CSCOPE | SEARCH_FILE)) { - tag_msg(sp, TAG_SEARCH, tqp->tag); - return (1); - } - - /* - * !!! - * Historically, tags set the search direction if it wasn't - * already set. - */ - if (sp->searchdir == NOTSET) - sp->searchdir = FORWARD; - } - - /* - * !!! - * Tags move to the first non-blank, NOT the search pattern start. - */ - sp->lno = m.lno; - sp->cno = 0; - (void)nonblank(sp, sp->lno, &sp->cno); - return (0); -} - - -/* - * lookup_ccmd -- - * Return a pointer to the command structure. - */ -static CC const * -lookup_ccmd(name) - char *name; -{ - CC const *ccp; - size_t len; - - len = strlen(name); - for (ccp = cscope_cmds; ccp->name != NULL; ++ccp) - if (strncmp(name, ccp->name, len) == 0) - return (ccp); - return (NULL); -} - -/* - * read_prompt -- - * Read a prompt from cscope. - */ -static int -read_prompt(sp, csc) - SCR *sp; - CSC *csc; -{ - int ch; - -#define CSCOPE_PROMPT ">> " - for (;;) { - while ((ch = - getc(csc->from_fp)) != EOF && ch != CSCOPE_PROMPT[0]); - if (ch == EOF) { - terminate(sp, csc, 0); - return (1); - } - if (getc(csc->from_fp) != CSCOPE_PROMPT[1]) - continue; - if (getc(csc->from_fp) != CSCOPE_PROMPT[2]) - continue; - break; - } - return (0); -} diff --git a/contrib/nvi/ex/ex_delete.c b/contrib/nvi/ex/ex_delete.c deleted file mode 100644 index 58734bb..0000000 --- a/contrib/nvi/ex/ex_delete.c +++ /dev/null @@ -1,65 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_delete.c 10.9 (Berkeley) 10/23/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> - -#include "../common/common.h" - -/* - * ex_delete: [line [,line]] d[elete] [buffer] [count] [flags] - * - * Delete lines from the file. - * - * PUBLIC: int ex_delete __P((SCR *, EXCMD *)); - */ -int -ex_delete(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - recno_t lno; - - NEEDFILE(sp, cmdp); - - /* - * !!! - * Historically, lines deleted in ex were not placed in the numeric - * buffers. We follow historic practice so that we don't overwrite - * vi buffers accidentally. - */ - if (cut(sp, - FL_ISSET(cmdp->iflags, E_C_BUFFER) ? &cmdp->buffer : NULL, - &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE)) - return (1); - - /* Delete the lines. */ - if (del(sp, &cmdp->addr1, &cmdp->addr2, 1)) - return (1); - - /* Set the cursor to the line after the last line deleted. */ - sp->lno = cmdp->addr1.lno; - - /* Or the last line in the file if deleted to the end of the file. */ - if (db_last(sp, &lno)) - return (1); - if (sp->lno > lno) - sp->lno = lno; - return (0); -} diff --git a/contrib/nvi/ex/ex_display.c b/contrib/nvi/ex/ex_display.c deleted file mode 100644 index 7531517..0000000 --- a/contrib/nvi/ex/ex_display.c +++ /dev/null @@ -1,145 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_display.c 10.12 (Berkeley) 4/10/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> - -#include "../common/common.h" -#include "tag.h" - -static int bdisplay __P((SCR *)); -static void db __P((SCR *, CB *, CHAR_T *)); - -/* - * ex_display -- :display b[uffers] | c[onnections] | s[creens] | t[ags] - * - * Display cscope connections, buffers, tags or screens. - * - * PUBLIC: int ex_display __P((SCR *, EXCMD *)); - */ -int -ex_display(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - switch (cmdp->argv[0]->bp[0]) { - case 'b': -#undef ARG -#define ARG "buffers" - if (cmdp->argv[0]->len >= sizeof(ARG) || - memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len)) - break; - return (bdisplay(sp)); - case 'c': -#undef ARG -#define ARG "connections" - if (cmdp->argv[0]->len >= sizeof(ARG) || - memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len)) - break; - return (cscope_display(sp)); - case 's': -#undef ARG -#define ARG "screens" - if (cmdp->argv[0]->len >= sizeof(ARG) || - memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len)) - break; - return (ex_sdisplay(sp)); - case 't': -#undef ARG -#define ARG "tags" - if (cmdp->argv[0]->len >= sizeof(ARG) || - memcmp(cmdp->argv[0]->bp, ARG, cmdp->argv[0]->len)) - break; - return (ex_tag_display(sp)); - } - ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); - return (1); -} - -/* - * bdisplay -- - * - * Display buffers. - */ -static int -bdisplay(sp) - SCR *sp; -{ - CB *cbp; - - if (sp->gp->cutq.lh_first == NULL && sp->gp->dcbp == NULL) { - msgq(sp, M_INFO, "123|No cut buffers to display"); - return (0); - } - - /* Display regular cut buffers. */ - for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) { - if (isdigit(cbp->name)) - continue; - if (cbp->textq.cqh_first != (void *)&cbp->textq) - db(sp, cbp, NULL); - if (INTERRUPTED(sp)) - return (0); - } - /* Display numbered buffers. */ - for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) { - if (!isdigit(cbp->name)) - continue; - if (cbp->textq.cqh_first != (void *)&cbp->textq) - db(sp, cbp, NULL); - if (INTERRUPTED(sp)) - return (0); - } - /* Display default buffer. */ - if ((cbp = sp->gp->dcbp) != NULL) - db(sp, cbp, "default buffer"); - return (0); -} - -/* - * db -- - * Display a buffer. - */ -static void -db(sp, cbp, name) - SCR *sp; - CB *cbp; - CHAR_T *name; -{ - CHAR_T *p; - GS *gp; - TEXT *tp; - size_t len; - - gp = sp->gp; - (void)ex_printf(sp, "********** %s%s\n", - name == NULL ? KEY_NAME(sp, cbp->name) : name, - F_ISSET(cbp, CB_LMODE) ? " (line mode)" : " (character mode)"); - for (tp = cbp->textq.cqh_first; - tp != (void *)&cbp->textq; tp = tp->q.cqe_next) { - for (len = tp->len, p = tp->lb; len--; ++p) { - (void)ex_puts(sp, KEY_NAME(sp, *p)); - if (INTERRUPTED(sp)) - return; - } - (void)ex_puts(sp, "\n"); - } -} diff --git a/contrib/nvi/ex/ex_edit.c b/contrib/nvi/ex/ex_edit.c deleted file mode 100644 index 8b18e0f..0000000 --- a/contrib/nvi/ex/ex_edit.c +++ /dev/null @@ -1,153 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_edit.c 10.10 (Berkeley) 4/27/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" -#include "../vi/vi.h" - -static int ex_N_edit __P((SCR *, EXCMD *, FREF *, int)); - -/* - * ex_edit -- :e[dit][!] [+cmd] [file] - * :ex[!] [+cmd] [file] - * :vi[sual][!] [+cmd] [file] - * - * Edit a file; if none specified, re-edit the current file. The third - * form of the command can only be executed while in vi mode. See the - * hack in ex.c:ex_cmd(). - * - * !!! - * Historic vi didn't permit the '+' command form without specifying - * a file name as well. This seems unreasonable, so we support it - * regardless. - * - * PUBLIC: int ex_edit __P((SCR *, EXCMD *)); - */ -int -ex_edit(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - FREF *frp; - int attach, setalt; - - switch (cmdp->argc) { - case 0: - /* - * If the name has been changed, we edit that file, not the - * original name. If the user was editing a temporary file - * (or wasn't editing any file), create another one. The - * reason for not reusing temporary files is that there is - * special exit processing of them, and reuse is tricky. - */ - frp = sp->frp; - if (sp->ep == NULL || F_ISSET(frp, FR_TMPFILE)) { - if ((frp = file_add(sp, NULL)) == NULL) - return (1); - attach = 0; - } else - attach = 1; - setalt = 0; - break; - case 1: - if ((frp = file_add(sp, cmdp->argv[0]->bp)) == NULL) - return (1); - attach = 0; - setalt = 1; - set_alt_name(sp, cmdp->argv[0]->bp); - break; - default: - abort(); - } - - if (F_ISSET(cmdp, E_NEWSCREEN)) - return (ex_N_edit(sp, cmdp, frp, attach)); - - /* - * Check for modifications. - * - * !!! - * Contrary to POSIX 1003.2-1992, autowrite did not affect :edit. - */ - if (file_m2(sp, FL_ISSET(cmdp->iflags, E_C_FORCE))) - return (1); - - /* Switch files. */ - if (file_init(sp, frp, NULL, (setalt ? FS_SETALT : 0) | - (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) - return (1); - - F_SET(sp, SC_FSWITCH); - return (0); -} - -/* - * ex_N_edit -- - * New screen version of ex_edit. - */ -static int -ex_N_edit(sp, cmdp, frp, attach) - SCR *sp; - EXCMD *cmdp; - FREF *frp; - int attach; -{ - SCR *new; - - /* Get a new screen. */ - if (screen_init(sp->gp, sp, &new)) - return (1); - if (vs_split(sp, new, 0)) { - (void)screen_end(new); - return (1); - } - - /* Get a backing file. */ - if (attach) { - /* Copy file state, keep the screen and cursor the same. */ - new->ep = sp->ep; - ++new->ep->refcnt; - - new->frp = frp; - new->frp->flags = sp->frp->flags; - - new->lno = sp->lno; - new->cno = sp->cno; - } else if (file_init(new, frp, NULL, - (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) { - (void)vs_discard(new, NULL); - (void)screen_end(new); - return (1); - } - - /* Create the argument list. */ - new->cargv = new->argv = ex_buildargv(sp, NULL, frp->name); - - /* Set up the switch. */ - sp->nextdisp = new; - F_SET(sp, SC_SSWITCH); - - return (0); -} diff --git a/contrib/nvi/ex/ex_equal.c b/contrib/nvi/ex/ex_equal.c deleted file mode 100644 index 565df66..0000000 --- a/contrib/nvi/ex/ex_equal.c +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_equal.c 10.10 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> - -#include "../common/common.h" - -/* - * ex_equal -- :address = - * - * PUBLIC: int ex_equal __P((SCR *, EXCMD *)); - */ -int -ex_equal(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - recno_t lno; - - NEEDFILE(sp, cmdp); - - /* - * Print out the line number matching the specified address, - * or the number of the last line in the file if no address - * specified. - * - * !!! - * Historically, ":0=" displayed 0, and ":=" or ":1=" in an - * empty file displayed 1. Until somebody complains loudly, - * we're going to do it right. The tables in excmd.c permit - * lno to get away with any address from 0 to the end of the - * file, which, in an empty file, is 0. - */ - if (F_ISSET(cmdp, E_ADDR_DEF)) { - if (db_last(sp, &lno)) - return (1); - } else - lno = cmdp->addr1.lno; - - (void)ex_printf(sp, "%ld\n", lno); - return (0); -} diff --git a/contrib/nvi/ex/ex_file.c b/contrib/nvi/ex/ex_file.c deleted file mode 100644 index 3492f9c..0000000 --- a/contrib/nvi/ex/ex_file.c +++ /dev/null @@ -1,80 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_file.c 10.12 (Berkeley) 7/12/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" - -/* - * ex_file -- :f[ile] [name] - * Change the file's name and display the status line. - * - * PUBLIC: int ex_file __P((SCR *, EXCMD *)); - */ -int -ex_file(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - CHAR_T *p; - FREF *frp; - - NEEDFILE(sp, cmdp); - - switch (cmdp->argc) { - case 0: - break; - case 1: - frp = sp->frp; - - /* Make sure can allocate enough space. */ - if ((p = v_strdup(sp, - cmdp->argv[0]->bp, cmdp->argv[0]->len)) == NULL) - return (1); - - /* If already have a file name, it becomes the alternate. */ - if (!F_ISSET(frp, FR_TMPFILE)) - set_alt_name(sp, frp->name); - - /* Free the previous name. */ - free(frp->name); - frp->name = p; - - /* - * The file has a real name, it's no longer a temporary, - * clear the temporary file flags. - */ - F_CLR(frp, FR_TMPEXIT | FR_TMPFILE); - - /* Have to force a write if the file exists, next time. */ - F_SET(frp, FR_NAMECHANGE); - - /* Notify the screen. */ - (void)sp->gp->scr_rename(sp, sp->frp->name, 1); - break; - default: - abort(); - } - msgq_status(sp, sp->lno, MSTAT_SHOWLAST); - return (0); -} diff --git a/contrib/nvi/ex/ex_filter.c b/contrib/nvi/ex/ex_filter.c deleted file mode 100644 index 2e86e58..0000000 --- a/contrib/nvi/ex/ex_filter.c +++ /dev/null @@ -1,316 +0,0 @@ -/*- - * Copyright (c) 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1991, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_filter.c 10.34 (Berkeley) 10/23/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" - -static int filter_ldisplay __P((SCR *, FILE *)); - -/* - * ex_filter -- - * Run a range of lines through a filter utility and optionally - * replace the original text with the stdout/stderr output of - * the utility. - * - * PUBLIC: int ex_filter __P((SCR *, - * PUBLIC: EXCMD *, MARK *, MARK *, MARK *, char *, enum filtertype)); - */ -int -ex_filter(sp, cmdp, fm, tm, rp, cmd, ftype) - SCR *sp; - EXCMD *cmdp; - MARK *fm, *tm, *rp; - char *cmd; - enum filtertype ftype; -{ - FILE *ifp, *ofp; - pid_t parent_writer_pid, utility_pid; - recno_t nread; - int input[2], output[2], rval; - char *name; - - rval = 0; - - /* Set return cursor position, which is never less than line 1. */ - *rp = *fm; - if (rp->lno == 0) - rp->lno = 1; - - /* We're going to need a shell. */ - if (opts_empty(sp, O_SHELL, 0)) - return (1); - - /* - * There are three different processes running through this code. - * They are the utility, the parent-writer and the parent-reader. - * The parent-writer is the process that writes from the file to - * the utility, the parent reader is the process that reads from - * the utility. - * - * Input and output are named from the utility's point of view. - * The utility reads from input[0] and the parent(s) write to - * input[1]. The parent(s) read from output[0] and the utility - * writes to output[1]. - * - * !!! - * Historically, in the FILTER_READ case, the utility reads from - * the terminal (e.g. :r! cat works). Otherwise open up utility - * input pipe. - */ - ofp = NULL; - input[0] = input[1] = output[0] = output[1] = -1; - if (ftype != FILTER_READ && pipe(input) < 0) { - msgq(sp, M_SYSERR, "pipe"); - goto err; - } - - /* Open up utility output pipe. */ - if (pipe(output) < 0) { - msgq(sp, M_SYSERR, "pipe"); - goto err; - } - if ((ofp = fdopen(output[0], "r")) == NULL) { - msgq(sp, M_SYSERR, "fdopen"); - goto err; - } - - /* Fork off the utility process. */ - switch (utility_pid = vfork()) { - case -1: /* Error. */ - msgq(sp, M_SYSERR, "vfork"); -err: if (input[0] != -1) - (void)close(input[0]); - if (input[1] != -1) - (void)close(input[1]); - if (ofp != NULL) - (void)fclose(ofp); - else if (output[0] != -1) - (void)close(output[0]); - if (output[1] != -1) - (void)close(output[1]); - return (1); - case 0: /* Utility. */ - /* - * Redirect stdin from the read end of the input pipe, and - * redirect stdout/stderr to the write end of the output pipe. - * - * !!! - * Historically, ex only directed stdout into the input pipe, - * letting stderr come out on the terminal as usual. Vi did - * not, directing both stdout and stderr into the input pipe. - * We match that practice in both ex and vi for consistency. - */ - if (input[0] != -1) - (void)dup2(input[0], STDIN_FILENO); - (void)dup2(output[1], STDOUT_FILENO); - (void)dup2(output[1], STDERR_FILENO); - - /* Close the utility's file descriptors. */ - if (input[0] != -1) - (void)close(input[0]); - if (input[1] != -1) - (void)close(input[1]); - (void)close(output[0]); - (void)close(output[1]); - - if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL) - name = O_STR(sp, O_SHELL); - else - ++name; - - execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL); - msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s"); - _exit (127); - /* NOTREACHED */ - default: /* Parent-reader, parent-writer. */ - /* Close the pipe ends neither parent will use. */ - if (input[0] != -1) - (void)close(input[0]); - (void)close(output[1]); - break; - } - - /* - * FILTER_RBANG, FILTER_READ: - * - * Reading is the simple case -- we don't need a parent writer, - * so the parent reads the output from the read end of the output - * pipe until it finishes, then waits for the child. Ex_readfp - * appends to the MARK, and closes ofp. - * - * For FILTER_RBANG, there is nothing to write to the utility. - * Make sure it doesn't wait forever by closing its standard - * input. - * - * !!! - * Set the return cursor to the last line read in for FILTER_READ. - * Historically, this behaves differently from ":r file" command, - * which leaves the cursor at the first line read in. Check to - * make sure that it's not past EOF because we were reading into an - * empty file. - */ - if (ftype == FILTER_RBANG || ftype == FILTER_READ) { - if (ftype == FILTER_RBANG) - (void)close(input[1]); - - if (ex_readfp(sp, "filter", ofp, fm, &nread, 1)) - rval = 1; - sp->rptlines[L_ADDED] += nread; - if (ftype == FILTER_READ) - if (fm->lno == 0) - rp->lno = nread; - else - rp->lno += nread; - goto uwait; - } - - /* - * FILTER_BANG, FILTER_WRITE - * - * Here we need both a reader and a writer. Temporary files are - * expensive and we'd like to avoid disk I/O. Using pipes has the - * obvious starvation conditions. It's done as follows: - * - * fork - * child - * write lines out - * exit - * parent - * FILTER_BANG: - * read lines into the file - * delete old lines - * FILTER_WRITE - * read and display lines - * wait for child - * - * XXX - * We get away without locking the underlying database because we know - * that none of the records that we're reading will be modified until - * after we've read them. This depends on the fact that the current - * B+tree implementation doesn't balance pages or similar things when - * it inserts new records. When the DB code has locking, we should - * treat vi as if it were multiple applications sharing a database, and - * do the required locking. If necessary a work-around would be to do - * explicit locking in the line.c:db_get() code, based on the flag set - * here. - */ - F_SET(sp->ep, F_MULTILOCK); - switch (parent_writer_pid = fork()) { - case -1: /* Error. */ - msgq(sp, M_SYSERR, "fork"); - (void)close(input[1]); - (void)close(output[0]); - rval = 1; - break; - case 0: /* Parent-writer. */ - /* - * Write the selected lines to the write end of the input - * pipe. This instance of ifp is closed by ex_writefp. - */ - (void)close(output[0]); - if ((ifp = fdopen(input[1], "w")) == NULL) - _exit (1); - _exit(ex_writefp(sp, "filter", ifp, fm, tm, NULL, NULL, 1)); - - /* NOTREACHED */ - default: /* Parent-reader. */ - (void)close(input[1]); - if (ftype == FILTER_WRITE) { - /* - * Read the output from the read end of the output - * pipe and display it. Filter_ldisplay closes ofp. - */ - if (filter_ldisplay(sp, ofp)) - rval = 1; - } else { - /* - * Read the output from the read end of the output - * pipe. Ex_readfp appends to the MARK and closes - * ofp. - */ - if (ex_readfp(sp, "filter", ofp, tm, &nread, 1)) - rval = 1; - sp->rptlines[L_ADDED] += nread; - } - - /* Wait for the parent-writer. */ - if (proc_wait(sp, - (long)parent_writer_pid, "parent-writer", 0, 1)) - rval = 1; - - /* Delete any lines written to the utility. */ - if (rval == 0 && ftype == FILTER_BANG && - (cut(sp, NULL, fm, tm, CUT_LINEMODE) || - del(sp, fm, tm, 1))) { - rval = 1; - break; - } - - /* - * If the filter had no output, we may have just deleted - * the cursor. Don't do any real error correction, we'll - * try and recover later. - */ - if (rp->lno > 1 && !db_exist(sp, rp->lno)) - --rp->lno; - break; - } - F_CLR(sp->ep, F_MULTILOCK); - - /* - * !!! - * Ignore errors on vi file reads, to make reads prettier. It's - * completely inconsistent, and historic practice. - */ -uwait: return (proc_wait(sp, (long)utility_pid, cmd, - ftype == FILTER_READ && F_ISSET(sp, SC_VI) ? 1 : 0, 0) || rval); -} - -/* - * filter_ldisplay -- - * Display output from a utility. - * - * !!! - * Historically, the characters were passed unmodified to the terminal. - * We use the ex print routines to make sure they're printable. - */ -static int -filter_ldisplay(sp, fp) - SCR *sp; - FILE *fp; -{ - size_t len; - - EX_PRIVATE *exp; - - for (exp = EXP(sp); !ex_getline(sp, fp, &len) && !INTERRUPTED(sp);) - if (ex_ldisplay(sp, exp->ibp, len, 0, 0)) - break; - if (ferror(fp)) - msgq(sp, M_SYSERR, "filter read"); - (void)fclose(fp); - return (0); -} diff --git a/contrib/nvi/ex/ex_global.c b/contrib/nvi/ex/ex_global.c deleted file mode 100644 index aba9dc5..0000000 --- a/contrib/nvi/ex/ex_global.c +++ /dev/null @@ -1,328 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_global.c 10.22 (Berkeley) 10/10/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" - -enum which {GLOBAL, V}; - -static int ex_g_setup __P((SCR *, EXCMD *, enum which)); - -/* - * ex_global -- [line [,line]] g[lobal][!] /pattern/ [commands] - * Exec on lines matching a pattern. - * - * PUBLIC: int ex_global __P((SCR *, EXCMD *)); - */ -int -ex_global(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - return (ex_g_setup(sp, - cmdp, FL_ISSET(cmdp->iflags, E_C_FORCE) ? V : GLOBAL)); -} - -/* - * ex_v -- [line [,line]] v /pattern/ [commands] - * Exec on lines not matching a pattern. - * - * PUBLIC: int ex_v __P((SCR *, EXCMD *)); - */ -int -ex_v(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - return (ex_g_setup(sp, cmdp, V)); -} - -/* - * ex_g_setup -- - * Ex global and v commands. - */ -static int -ex_g_setup(sp, cmdp, cmd) - SCR *sp; - EXCMD *cmdp; - enum which cmd; -{ - CHAR_T *ptrn, *p, *t; - EXCMD *ecp; - MARK abs; - RANGE *rp; - busy_t btype; - recno_t start, end; - regex_t *re; - regmatch_t match[1]; - size_t len; - int cnt, delim, eval; - char *dbp; - - NEEDFILE(sp, cmdp); - - if (F_ISSET(sp, SC_EX_GLOBAL)) { - msgq(sp, M_ERR, - "124|The %s command can't be used as part of a global or v command", - cmdp->cmd->name); - return (1); - } - - /* - * Skip leading white space. Historic vi allowed any non-alphanumeric - * to serve as the global command delimiter. - */ - if (cmdp->argc == 0) - goto usage; - for (p = cmdp->argv[0]->bp; isblank(*p); ++p); - if (*p == '\0' || isalnum(*p) || - *p == '\\' || *p == '|' || *p == '\n') { -usage: ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); - return (1); - } - delim = *p++; - - /* - * Get the pattern string, toss escaped characters. - * - * QUOTING NOTE: - * Only toss an escaped character if it escapes a delimiter. - */ - for (ptrn = t = p;;) { - if (p[0] == '\0' || p[0] == delim) { - if (p[0] == delim) - ++p; - /* - * !!! - * Nul terminate the pattern string -- it's passed - * to regcomp which doesn't understand anything else. - */ - *t = '\0'; - break; - } - if (p[0] == '\\') - if (p[1] == delim) - ++p; - else if (p[1] == '\\') - *t++ = *p++; - *t++ = *p++; - } - - /* If the pattern string is empty, use the last one. */ - if (*ptrn == '\0') { - if (sp->re == NULL) { - ex_emsg(sp, NULL, EXM_NOPREVRE); - return (1); - } - - /* Re-compile the RE if necessary. */ - if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp, - sp->re, sp->re_len, NULL, NULL, &sp->re_c, RE_C_SEARCH)) - return (1); - } else { - /* Compile the RE. */ - if (re_compile(sp, ptrn, t - ptrn, - &sp->re, &sp->re_len, &sp->re_c, RE_C_SEARCH)) - return (1); - - /* - * Set saved RE. Historic practice is that globals set - * direction as well as the RE. - */ - sp->searchdir = FORWARD; - } - re = &sp->re_c; - - /* The global commands always set the previous context mark. */ - abs.lno = sp->lno; - abs.cno = sp->cno; - if (mark_set(sp, ABSMARK1, &abs, 1)) - return (1); - - /* Get an EXCMD structure. */ - CALLOC_RET(sp, ecp, EXCMD *, 1, sizeof(EXCMD)); - CIRCLEQ_INIT(&ecp->rq); - - /* - * Get a copy of the command string; the default command is print. - * Don't worry about a set of <blank>s with no command, that will - * default to print in the ex parser. We need to have two copies - * because the ex parser may step on the command string when it's - * parsing it. - */ - if ((len = cmdp->argv[0]->len - (p - cmdp->argv[0]->bp)) == 0) { - p = "pp"; - len = 1; - } - - MALLOC_RET(sp, ecp->cp, char *, len * 2); - ecp->o_cp = ecp->cp; - ecp->o_clen = len; - memcpy(ecp->cp + len, p, len); - ecp->range_lno = OOBLNO; - FL_SET(ecp->agv_flags, cmd == GLOBAL ? AGV_GLOBAL : AGV_V); - LIST_INSERT_HEAD(&sp->gp->ecq, ecp, q); - - /* - * For each line... The semantics of global matching are that we first - * have to decide which lines are going to get passed to the command, - * and then pass them to the command, ignoring other changes. There's - * really no way to do this in a single pass, since arbitrary line - * creation, deletion and movement can be done in the ex command. For - * example, a good vi clone test is ":g/X/mo.-3", or "g/X/.,.+1d". - * What we do is create linked list of lines that are tracked through - * each ex command. There's a callback routine which the DB interface - * routines call when a line is created or deleted. This doesn't help - * the layering much. - */ - btype = BUSY_ON; - cnt = INTERRUPT_CHECK; - for (start = cmdp->addr1.lno, - end = cmdp->addr2.lno; start <= end; ++start) { - if (cnt-- == 0) { - if (INTERRUPTED(sp)) { - LIST_REMOVE(ecp, q); - free(ecp->cp); - free(ecp); - break; - } - search_busy(sp, btype); - btype = BUSY_UPDATE; - cnt = INTERRUPT_CHECK; - } - if (db_get(sp, start, DBG_FATAL, &dbp, &len)) - return (1); - match[0].rm_so = 0; - match[0].rm_eo = len; - switch (eval = - regexec(&sp->re_c, dbp, 0, match, REG_STARTEND)) { - case 0: - if (cmd == V) - continue; - break; - case REG_NOMATCH: - if (cmd == GLOBAL) - continue; - break; - default: - re_error(sp, eval, &sp->re_c); - break; - } - - /* If follows the last entry, extend the last entry's range. */ - if ((rp = ecp->rq.cqh_last) != (void *)&ecp->rq && - rp->stop == start - 1) { - ++rp->stop; - continue; - } - - /* Allocate a new range, and append it to the list. */ - CALLOC(sp, rp, RANGE *, 1, sizeof(RANGE)); - if (rp == NULL) - return (1); - rp->start = rp->stop = start; - CIRCLEQ_INSERT_TAIL(&ecp->rq, rp, q); - } - search_busy(sp, BUSY_OFF); - return (0); -} - -/* - * ex_g_insdel -- - * Update the ranges based on an insertion or deletion. - * - * PUBLIC: int ex_g_insdel __P((SCR *, lnop_t, recno_t)); - */ -int -ex_g_insdel(sp, op, lno) - SCR *sp; - lnop_t op; - recno_t lno; -{ - EXCMD *ecp; - RANGE *nrp, *rp; - - /* All insert/append operations are done as inserts. */ - if (op == LINE_APPEND) - abort(); - - if (op == LINE_RESET) - return (0); - - for (ecp = sp->gp->ecq.lh_first; ecp != NULL; ecp = ecp->q.le_next) { - if (!FL_ISSET(ecp->agv_flags, AGV_AT | AGV_GLOBAL | AGV_V)) - continue; - for (rp = ecp->rq.cqh_first; rp != (void *)&ecp->rq; rp = nrp) { - nrp = rp->q.cqe_next; - - /* If range less than the line, ignore it. */ - if (rp->stop < lno) - continue; - - /* - * If range greater than the line, decrement or - * increment the range. - */ - if (rp->start > lno) { - if (op == LINE_DELETE) { - --rp->start; - --rp->stop; - } else { - ++rp->start; - ++rp->stop; - } - continue; - } - - /* - * Lno is inside the range, decrement the end point - * for deletion, and split the range for insertion. - * In the latter case, since we're inserting a new - * element, neither range can be exhausted. - */ - if (op == LINE_DELETE) { - if (rp->start > --rp->stop) { - CIRCLEQ_REMOVE(&ecp->rq, rp, q); - free(rp); - } - } else { - CALLOC_RET(sp, nrp, RANGE *, 1, sizeof(RANGE)); - nrp->start = lno + 1; - nrp->stop = rp->stop + 1; - rp->stop = lno - 1; - CIRCLEQ_INSERT_AFTER(&ecp->rq, rp, nrp, q); - rp = nrp; - } - } - - /* - * If the command deleted/inserted lines, the cursor moves to - * the line after the deleted/inserted line. - */ - ecp->range_lno = lno; - } - return (0); -} diff --git a/contrib/nvi/ex/ex_init.c b/contrib/nvi/ex/ex_init.c deleted file mode 100644 index 6a78416..0000000 --- a/contrib/nvi/ex/ex_init.c +++ /dev/null @@ -1,417 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_init.c 10.26 (Berkeley) 8/12/96"; -#endif /* not lint */ - -#include <sys/param.h> -#include <sys/types.h> /* XXX: param.h may not have included types.h */ -#include <sys/queue.h> -#include <sys/stat.h> - -#include <bitstring.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" -#include "tag.h" -#include "pathnames.h" - -enum rc { NOEXIST, NOPERM, RCOK }; -static enum rc exrc_isok __P((SCR *, struct stat *, char *, int, int)); - -static int ex_run_file __P((SCR *, char *)); - -/* - * ex_screen_copy -- - * Copy ex screen. - * - * PUBLIC: int ex_screen_copy __P((SCR *, SCR *)); - */ -int -ex_screen_copy(orig, sp) - SCR *orig, *sp; -{ - EX_PRIVATE *oexp, *nexp; - - /* Create the private ex structure. */ - CALLOC_RET(orig, nexp, EX_PRIVATE *, 1, sizeof(EX_PRIVATE)); - sp->ex_private = nexp; - - /* Initialize queues. */ - CIRCLEQ_INIT(&nexp->tq); - TAILQ_INIT(&nexp->tagfq); - LIST_INIT(&nexp->cscq); - - if (orig == NULL) { - } else { - oexp = EXP(orig); - - if (oexp->lastbcomm != NULL && - (nexp->lastbcomm = strdup(oexp->lastbcomm)) == NULL) { - msgq(sp, M_SYSERR, NULL); - return(1); - } - if (ex_tag_copy(orig, sp)) - return (1); - } - return (0); -} - -/* - * ex_screen_end -- - * End a vi screen. - * - * PUBLIC: int ex_screen_end __P((SCR *)); - */ -int -ex_screen_end(sp) - SCR *sp; -{ - EX_PRIVATE *exp; - int rval; - - if ((exp = EXP(sp)) == NULL) - return (0); - - rval = 0; - - /* Close down script connections. */ - if (F_ISSET(sp, SC_SCRIPT) && sscr_end(sp)) - rval = 1; - - if (argv_free(sp)) - rval = 1; - - if (exp->ibp != NULL) - free(exp->ibp); - - if (exp->lastbcomm != NULL) - free(exp->lastbcomm); - - if (ex_tag_free(sp)) - rval = 1; - - /* Free private memory. */ - free(exp); - sp->ex_private = NULL; - - return (rval); -} - -/* - * ex_optchange -- - * Handle change of options for ex. - * - * PUBLIC: int ex_optchange __P((SCR *, int, char *, u_long *)); - */ -int -ex_optchange(sp, offset, str, valp) - SCR *sp; - int offset; - char *str; - u_long *valp; -{ - switch (offset) { - case O_TAGS: - return (ex_tagf_alloc(sp, str)); - } - return (0); -} - -/* - * ex_exrc -- - * Read the EXINIT environment variable and the startup exrc files, - * and execute their commands. - * - * PUBLIC: int ex_exrc __P((SCR *)); - */ -int -ex_exrc(sp) - SCR *sp; -{ - struct stat hsb, lsb; - char *p, path[MAXPATHLEN]; - - /* - * Source the system, environment, $HOME and local .exrc values. - * Vi historically didn't check $HOME/.exrc if the environment - * variable EXINIT was set. This is all done before the file is - * read in, because things in the .exrc information can set, for - * example, the recovery directory. - * - * !!! - * While nvi can handle any of the options settings of historic vi, - * the converse is not true. Since users are going to have to have - * files and environmental variables that work with both, we use nvi - * versions of both the $HOME and local startup files if they exist, - * otherwise the historic ones. - * - * !!! - * For a discussion of permissions and when what .exrc files are - * read, see the comment above the exrc_isok() function below. - * - * !!! - * If the user started the historic of vi in $HOME, vi read the user's - * .exrc file twice, as $HOME/.exrc and as ./.exrc. We avoid this, as - * it's going to make some commands behave oddly, and I can't imagine - * anyone depending on it. - */ - switch (exrc_isok(sp, &hsb, _PATH_SYSEXRC, 1, 0)) { - case NOEXIST: - case NOPERM: - break; - case RCOK: - if (ex_run_file(sp, _PATH_SYSEXRC)) - return (1); - break; - } - - /* Run the commands. */ - if (EXCMD_RUNNING(sp->gp)) - (void)ex_cmd(sp); - if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) - return (0); - - if ((p = getenv("NEXINIT")) != NULL) { - if (ex_run_str(sp, "NEXINIT", p, strlen(p), 1, 0)) - return (1); - } else if ((p = getenv("EXINIT")) != NULL) { - if (ex_run_str(sp, "EXINIT", p, strlen(p), 1, 0)) - return (1); - } else if ((p = getenv("HOME")) != NULL && *p) { - (void)snprintf(path, sizeof(path), "%s/%s", p, _PATH_NEXRC); - switch (exrc_isok(sp, &hsb, path, 0, 1)) { - case NOEXIST: - (void)snprintf(path, - sizeof(path), "%s/%s", p, _PATH_EXRC); - if (exrc_isok(sp, - &hsb, path, 0, 1) == RCOK && ex_run_file(sp, path)) - return (1); - break; - case NOPERM: - break; - case RCOK: - if (ex_run_file(sp, path)) - return (1); - break; - } - } - - /* Run the commands. */ - if (EXCMD_RUNNING(sp->gp)) - (void)ex_cmd(sp); - if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) - return (0); - - /* Previous commands may have set the exrc option. */ - if (O_ISSET(sp, O_EXRC)) { - switch (exrc_isok(sp, &lsb, _PATH_NEXRC, 0, 0)) { - case NOEXIST: - if (exrc_isok(sp, &lsb, _PATH_EXRC, 0, 0) == RCOK && - (lsb.st_dev != hsb.st_dev || - lsb.st_ino != hsb.st_ino) && - ex_run_file(sp, _PATH_EXRC)) - return (1); - break; - case NOPERM: - break; - case RCOK: - if ((lsb.st_dev != hsb.st_dev || - lsb.st_ino != hsb.st_ino) && - ex_run_file(sp, _PATH_NEXRC)) - return (1); - break; - } - /* Run the commands. */ - if (EXCMD_RUNNING(sp->gp)) - (void)ex_cmd(sp); - if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) - return (0); - } - - return (0); -} - -/* - * ex_run_file -- - * Set up a file of ex commands to run. - */ -static int -ex_run_file(sp, name) - SCR *sp; - char *name; -{ - ARGS *ap[2], a; - EXCMD cmd; - - ex_cinit(&cmd, C_SOURCE, 0, OOBLNO, OOBLNO, 0, ap); - ex_cadd(&cmd, &a, name, strlen(name)); - return (ex_source(sp, &cmd)); -} - -/* - * ex_run_str -- - * Set up a string of ex commands to run. - * - * PUBLIC: int ex_run_str __P((SCR *, char *, char *, size_t, int, int)); - */ -int -ex_run_str(sp, name, str, len, ex_flags, nocopy) - SCR *sp; - char *name, *str; - size_t len; - int ex_flags, nocopy; -{ - GS *gp; - EXCMD *ecp; - - gp = sp->gp; - if (EXCMD_RUNNING(gp)) { - CALLOC_RET(sp, ecp, EXCMD *, 1, sizeof(EXCMD)); - LIST_INSERT_HEAD(&gp->ecq, ecp, q); - } else - ecp = &gp->excmd; - - F_INIT(ecp, - ex_flags ? E_BLIGNORE | E_NOAUTO | E_NOPRDEF | E_VLITONLY : 0); - - if (nocopy) - ecp->cp = str; - else - if ((ecp->cp = v_strdup(sp, str, len)) == NULL) - return (1); - ecp->clen = len; - - if (name == NULL) - ecp->if_name = NULL; - else { - if ((ecp->if_name = v_strdup(sp, name, strlen(name))) == NULL) - return (1); - ecp->if_lno = 1; - F_SET(ecp, E_NAMEDISCARD); - } - - return (0); -} - -/* - * exrc_isok -- - * Check a .exrc file for source-ability. - * - * !!! - * Historically, vi read the $HOME and local .exrc files if they were owned - * by the user's real ID, or the "sourceany" option was set, regardless of - * any other considerations. We no longer support the sourceany option as - * it's a security problem of mammoth proportions. We require the system - * .exrc file to be owned by root, the $HOME .exrc file to be owned by the - * user's effective ID (or that the user's effective ID be root) and the - * local .exrc files to be owned by the user's effective ID. In all cases, - * the file cannot be writeable by anyone other than its owner. - * - * In O'Reilly ("Learning the VI Editor", Fifth Ed., May 1992, page 106), - * it notes that System V release 3.2 and later has an option "[no]exrc". - * The behavior is that local .exrc files are read only if the exrc option - * is set. The default for the exrc option was off, so, by default, local - * .exrc files were not read. The problem this was intended to solve was - * that System V permitted users to give away files, so there's no possible - * ownership or writeability test to ensure that the file is safe. - * - * POSIX 1003.2-1992 standardized exrc as an option. It required the exrc - * option to be off by default, thus local .exrc files are not to be read - * by default. The Rationale noted (incorrectly) that this was a change - * to historic practice, but correctly noted that a default of off improves - * system security. POSIX also required that vi check the effective user - * ID instead of the real user ID, which is why we've switched from historic - * practice. - * - * We initialize the exrc variable to off. If it's turned on by the system - * or $HOME .exrc files, and the local .exrc file passes the ownership and - * writeability tests, then we read it. This breaks historic 4BSD practice, - * but it gives us a measure of security on systems where users can give away - * files. - */ -static enum rc -exrc_isok(sp, sbp, path, rootown, rootid) - SCR *sp; - struct stat *sbp; - char *path; - int rootown, rootid; -{ - enum { ROOTOWN, OWN, WRITER } etype; - uid_t euid; - int nf1, nf2; - char *a, *b, buf[MAXPATHLEN]; - - /* Check for the file's existence. */ - if (stat(path, sbp)) - return (NOEXIST); - - /* Check ownership permissions. */ - euid = geteuid(); - if (!(rootown && sbp->st_uid == 0) && - !(rootid && euid == 0) && sbp->st_uid != euid) { - etype = rootown ? ROOTOWN : OWN; - goto denied; - } - - /* Check writeability. */ - if (sbp->st_mode & (S_IWGRP | S_IWOTH)) { - etype = WRITER; - goto denied; - } - return (RCOK); - -denied: a = msg_print(sp, path, &nf1); - if (strchr(path, '/') == NULL && getcwd(buf, sizeof(buf)) != NULL) { - b = msg_print(sp, buf, &nf2); - switch (etype) { - case ROOTOWN: - msgq(sp, M_ERR, - "125|%s/%s: not sourced: not owned by you or root", - b, a); - break; - case OWN: - msgq(sp, M_ERR, - "126|%s/%s: not sourced: not owned by you", b, a); - break; - case WRITER: - msgq(sp, M_ERR, - "127|%s/%s: not sourced: writeable by a user other than the owner", b, a); - break; - } - if (nf2) - FREE_SPACE(sp, b, 0); - } else - switch (etype) { - case ROOTOWN: - msgq(sp, M_ERR, - "128|%s: not sourced: not owned by you or root", a); - break; - case OWN: - msgq(sp, M_ERR, - "129|%s: not sourced: not owned by you", a); - break; - case WRITER: - msgq(sp, M_ERR, - "130|%s: not sourced: writeable by a user other than the owner", a); - break; - } - - if (nf1) - FREE_SPACE(sp, a, 0); - return (NOPERM); -} diff --git a/contrib/nvi/ex/ex_join.c b/contrib/nvi/ex/ex_join.c deleted file mode 100644 index c26c424..0000000 --- a/contrib/nvi/ex/ex_join.c +++ /dev/null @@ -1,177 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_join.c 10.10 (Berkeley) 9/15/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" - -/* - * ex_join -- :[line [,line]] j[oin][!] [count] [flags] - * Join lines. - * - * PUBLIC: int ex_join __P((SCR *, EXCMD *)); - */ -int -ex_join(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - recno_t from, to; - size_t blen, clen, len, tlen; - int echar, extra, first; - char *bp, *p, *tbp; - - NEEDFILE(sp, cmdp); - - from = cmdp->addr1.lno; - to = cmdp->addr2.lno; - - /* Check for no lines to join. */ - if (!db_exist(sp, from + 1)) { - msgq(sp, M_ERR, "131|No following lines to join"); - return (1); - } - - GET_SPACE_RET(sp, bp, blen, 256); - - /* - * The count for the join command was off-by-one, - * historically, to other counts for other commands. - */ - if (FL_ISSET(cmdp->iflags, E_C_COUNT)) - ++cmdp->addr2.lno; - - /* - * If only a single address specified, or, the same address - * specified twice, the from/two addresses will be the same. - */ - if (cmdp->addr1.lno == cmdp->addr2.lno) - ++cmdp->addr2.lno; - - clen = tlen = 0; - for (first = 1, - from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) { - /* - * Get next line. Historic versions of vi allowed "10J" while - * less than 10 lines from the end-of-file, so we do too. - */ - if (db_get(sp, from, 0, &p, &len)) { - cmdp->addr2.lno = from - 1; - break; - } - - /* Empty lines just go away. */ - if (len == 0) - continue; - - /* - * Get more space if necessary. Note, tlen isn't the length - * of the new line, it's roughly the amount of space needed. - * tbp - bp is the length of the new line. - */ - tlen += len + 2; - ADD_SPACE_RET(sp, bp, blen, tlen); - tbp = bp + clen; - - /* - * Historic practice: - * - * If force specified, join without modification. - * If the current line ends with whitespace, strip leading - * whitespace from the joined line. - * If the next line starts with a ), do nothing. - * If the current line ends with ., insert two spaces. - * Else, insert one space. - * - * One change -- add ? and ! to the list of characters for - * which we insert two spaces. I expect that POSIX 1003.2 - * will require this as well. - * - * Echar is the last character in the last line joined. - */ - extra = 0; - if (!first && !FL_ISSET(cmdp->iflags, E_C_FORCE)) { - if (isblank(echar)) - for (; len && isblank(*p); --len, ++p); - else if (p[0] != ')') { - if (strchr(".?!", echar)) { - *tbp++ = ' '; - ++clen; - extra = 1; - } - *tbp++ = ' '; - ++clen; - for (; len && isblank(*p); --len, ++p); - } - } - - if (len != 0) { - memcpy(tbp, p, len); - tbp += len; - clen += len; - echar = p[len - 1]; - } else - echar = ' '; - - /* - * Historic practice for vi was to put the cursor at the first - * inserted whitespace character, if there was one, or the - * first character of the joined line, if there wasn't, or the - * last character of the line if joined to an empty line. If - * a count was specified, the cursor was moved as described - * for the first line joined, ignoring subsequent lines. If - * the join was a ':' command, the cursor was placed at the - * first non-blank character of the line unless the cursor was - * "attracted" to the end of line when the command was executed - * in which case it moved to the new end of line. There are - * probably several more special cases, but frankly, my dear, - * I don't give a damn. This implementation puts the cursor - * on the first inserted whitespace character, the first - * character of the joined line, or the last character of the - * line regardless. Note, if the cursor isn't on the joined - * line (possible with : commands), it is reset to the starting - * line. - */ - if (first) { - sp->cno = (tbp - bp) - (1 + extra); - first = 0; - } else - sp->cno = (tbp - bp) - len - (1 + extra); - } - sp->lno = cmdp->addr1.lno; - - /* Delete the joined lines. */ - for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; to > from; --to) - if (db_delete(sp, to)) - goto err; - - /* If the original line changed, reset it. */ - if (!first && db_set(sp, from, bp, tbp - bp)) { -err: FREE_SPACE(sp, bp, blen); - return (1); - } - FREE_SPACE(sp, bp, blen); - - sp->rptlines[L_JOINED] += (cmdp->addr2.lno - cmdp->addr1.lno) + 1; - return (0); -} diff --git a/contrib/nvi/ex/ex_map.c b/contrib/nvi/ex/ex_map.c deleted file mode 100644 index bc2cf08..0000000 --- a/contrib/nvi/ex/ex_map.c +++ /dev/null @@ -1,121 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_map.c 10.9 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" - -/* - * ex_map -- :map[!] [input] [replacement] - * Map a key/string or display mapped keys. - * - * Historical note: - * Historic vi maps were fairly bizarre, and likely to differ in - * very subtle and strange ways from this implementation. Two - * things worth noting are that vi would often hang or drop core - * if the map was strange enough (ex: map X "xy$@x^V), or, simply - * not work. One trick worth remembering is that if you put a - * mark at the start of the map, e.g. map X mx"xy ...), or if you - * put the map in a .exrc file, things would often work much better. - * No clue why. - * - * PUBLIC: int ex_map __P((SCR *, EXCMD *)); - */ -int -ex_map(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - seq_t stype; - CHAR_T *input, *p; - - stype = FL_ISSET(cmdp->iflags, E_C_FORCE) ? SEQ_INPUT : SEQ_COMMAND; - - switch (cmdp->argc) { - case 0: - if (seq_dump(sp, stype, 1) == 0) - msgq(sp, M_INFO, stype == SEQ_INPUT ? - "132|No input map entries" : - "133|No command map entries"); - return (0); - case 2: - input = cmdp->argv[0]->bp; - break; - default: - abort(); - } - - /* - * If the mapped string is #[0-9]* (and wasn't quoted) then store the - * function key mapping. If the screen specific routine has been set, - * call it as well. Note, the SEQ_FUNCMAP type is persistent across - * screen types, maybe the next screen type will get it right. - */ - if (input[0] == '#' && isdigit(input[1])) { - for (p = input + 2; isdigit(*p); ++p); - if (p[0] != '\0') - goto nofunc; - - if (seq_set(sp, NULL, 0, input, cmdp->argv[0]->len, - cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, - SEQ_FUNCMAP | SEQ_USERDEF)) - return (1); - return (sp->gp->scr_fmap == NULL ? 0 : - sp->gp->scr_fmap(sp, stype, input, cmdp->argv[0]->len, - cmdp->argv[1]->bp, cmdp->argv[1]->len)); - } - - /* Some single keys may not be remapped in command mode. */ -nofunc: if (stype == SEQ_COMMAND && input[1] == '\0') - switch (KEY_VAL(sp, input[0])) { - case K_COLON: - case K_ESCAPE: - case K_NL: - msgq(sp, M_ERR, - "134|The %s character may not be remapped", - KEY_NAME(sp, input[0])); - return (1); - } - return (seq_set(sp, NULL, 0, input, cmdp->argv[0]->len, - cmdp->argv[1]->bp, cmdp->argv[1]->len, stype, SEQ_USERDEF)); -} - -/* - * ex_unmap -- (:unmap[!] key) - * Unmap a key. - * - * PUBLIC: int ex_unmap __P((SCR *, EXCMD *)); - */ -int -ex_unmap(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - if (seq_delete(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len, - FL_ISSET(cmdp->iflags, E_C_FORCE) ? SEQ_INPUT : SEQ_COMMAND)) { - msgq_str(sp, M_INFO, - cmdp->argv[0]->bp, "135|\"%s\" isn't currently mapped"); - return (1); - } - return (0); -} diff --git a/contrib/nvi/ex/ex_mark.c b/contrib/nvi/ex/ex_mark.c deleted file mode 100644 index 08ad8c2..0000000 --- a/contrib/nvi/ex/ex_mark.c +++ /dev/null @@ -1,45 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_mark.c 10.8 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> - -#include "../common/common.h" - -/* - * ex_mark -- :mark char - * :k char - * Mark lines. - * - * - * PUBLIC: int ex_mark __P((SCR *, EXCMD *)); - */ -int -ex_mark(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - NEEDFILE(sp, cmdp); - - if (cmdp->argv[0]->len != 1) { - msgq(sp, M_ERR, "136|Mark names must be a single character"); - return (1); - } - return (mark_set(sp, cmdp->argv[0]->bp[0], &cmdp->addr1, 1)); -} diff --git a/contrib/nvi/ex/ex_mkexrc.c b/contrib/nvi/ex/ex_mkexrc.c deleted file mode 100644 index 0eb15d4..0000000 --- a/contrib/nvi/ex/ex_mkexrc.c +++ /dev/null @@ -1,101 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_mkexrc.c 10.11 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/stat.h> - -#include <bitstring.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" -#include "pathnames.h" - -/* - * ex_mkexrc -- :mkexrc[!] [file] - * - * Create (or overwrite) a .exrc file with the current info. - * - * PUBLIC: int ex_mkexrc __P((SCR *, EXCMD *)); - */ -int -ex_mkexrc(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - struct stat sb; - FILE *fp; - int fd, sverrno; - char *fname; - - switch (cmdp->argc) { - case 0: - fname = _PATH_EXRC; - break; - case 1: - fname = cmdp->argv[0]->bp; - set_alt_name(sp, fname); - break; - default: - abort(); - } - - if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && !stat(fname, &sb)) { - msgq_str(sp, M_ERR, fname, - "137|%s exists, not written; use ! to override"); - return (1); - } - - /* Create with max permissions of rw-r--r--. */ - if ((fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { - msgq_str(sp, M_SYSERR, fname, "%s"); - return (1); - } - - if ((fp = fdopen(fd, "w")) == NULL) { - sverrno = errno; - (void)close(fd); - goto e2; - } - - if (seq_save(sp, fp, "abbreviate ", SEQ_ABBREV) || ferror(fp)) - goto e1; - if (seq_save(sp, fp, "map ", SEQ_COMMAND) || ferror(fp)) - goto e1; - if (seq_save(sp, fp, "map! ", SEQ_INPUT) || ferror(fp)) - goto e1; - if (opts_save(sp, fp) || ferror(fp)) - goto e1; - if (fclose(fp)) { - sverrno = errno; - goto e2; - } - - msgq_str(sp, M_INFO, fname, "138|New exrc file: %s"); - return (0); - -e1: sverrno = errno; - (void)fclose(fp); -e2: errno = sverrno; - msgq_str(sp, M_SYSERR, fname, "%s"); - return (1); -} diff --git a/contrib/nvi/ex/ex_move.c b/contrib/nvi/ex/ex_move.c deleted file mode 100644 index d6e45c3..0000000 --- a/contrib/nvi/ex/ex_move.c +++ /dev/null @@ -1,198 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_move.c 10.10 (Berkeley) 9/15/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" - -/* - * ex_copy -- :[line [,line]] co[py] line [flags] - * Copy selected lines. - * - * PUBLIC: int ex_copy __P((SCR *, EXCMD *)); - */ -int -ex_copy(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - CB cb; - MARK fm1, fm2, m, tm; - recno_t cnt; - int rval; - - rval = 0; - - NEEDFILE(sp, cmdp); - - /* - * It's possible to copy things into the area that's being - * copied, e.g. "2,5copy3" is legitimate. Save the text to - * a cut buffer. - */ - fm1 = cmdp->addr1; - fm2 = cmdp->addr2; - memset(&cb, 0, sizeof(cb)); - CIRCLEQ_INIT(&cb.textq); - for (cnt = fm1.lno; cnt <= fm2.lno; ++cnt) - if (cut_line(sp, cnt, 0, 0, &cb)) { - rval = 1; - goto err; - } - cb.flags |= CB_LMODE; - - /* Put the text into place. */ - tm.lno = cmdp->lineno; - tm.cno = 0; - if (put(sp, &cb, NULL, &tm, &m, 1)) - rval = 1; - else { - /* - * Copy puts the cursor on the last line copied. The cursor - * returned by the put routine is the first line put, not the - * last, because that's the historic semantic of vi. - */ - cnt = (fm2.lno - fm1.lno) + 1; - sp->lno = m.lno + (cnt - 1); - sp->cno = 0; - } -err: text_lfree(&cb.textq); - return (rval); -} - -/* - * ex_move -- :[line [,line]] mo[ve] line - * Move selected lines. - * - * PUBLIC: int ex_move __P((SCR *, EXCMD *)); - */ -int -ex_move(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - LMARK *lmp; - MARK fm1, fm2; - recno_t cnt, diff, fl, tl, mfl, mtl; - size_t blen, len; - int mark_reset; - char *bp, *p; - - NEEDFILE(sp, cmdp); - - /* - * It's not possible to move things into the area that's being - * moved. - */ - fm1 = cmdp->addr1; - fm2 = cmdp->addr2; - if (cmdp->lineno >= fm1.lno && cmdp->lineno <= fm2.lno) { - msgq(sp, M_ERR, "139|Destination line is inside move range"); - return (1); - } - - /* - * Log the positions of any marks in the to-be-deleted lines. This - * has to work with the logging code. What happens is that we log - * the old mark positions, make the changes, then log the new mark - * positions. Then the marks end up in the right positions no matter - * which way the log is traversed. - * - * XXX - * Reset the MARK_USERSET flag so that the log can undo the mark. - * This isn't very clean, and should probably be fixed. - */ - fl = fm1.lno; - tl = cmdp->lineno; - - /* Log the old positions of the marks. */ - mark_reset = 0; - for (lmp = sp->ep->marks.lh_first; lmp != NULL; lmp = lmp->q.le_next) - if (lmp->name != ABSMARK1 && - lmp->lno >= fl && lmp->lno <= tl) { - mark_reset = 1; - F_CLR(lmp, MARK_USERSET); - (void)log_mark(sp, lmp); - } - - /* Get memory for the copy. */ - GET_SPACE_RET(sp, bp, blen, 256); - - /* Move the lines. */ - diff = (fm2.lno - fm1.lno) + 1; - if (tl > fl) { /* Destination > source. */ - mfl = tl - diff; - mtl = tl; - for (cnt = diff; cnt--;) { - if (db_get(sp, fl, DBG_FATAL, &p, &len)) - return (1); - BINC_RET(sp, bp, blen, len); - memcpy(bp, p, len); - if (db_append(sp, 1, tl, bp, len)) - return (1); - if (mark_reset) - for (lmp = sp->ep->marks.lh_first; - lmp != NULL; lmp = lmp->q.le_next) - if (lmp->name != ABSMARK1 && - lmp->lno == fl) - lmp->lno = tl + 1; - if (db_delete(sp, fl)) - return (1); - } - } else { /* Destination < source. */ - mfl = tl; - mtl = tl + diff; - for (cnt = diff; cnt--;) { - if (db_get(sp, fl, DBG_FATAL, &p, &len)) - return (1); - BINC_RET(sp, bp, blen, len); - memcpy(bp, p, len); - if (db_append(sp, 1, tl++, bp, len)) - return (1); - if (mark_reset) - for (lmp = sp->ep->marks.lh_first; - lmp != NULL; lmp = lmp->q.le_next) - if (lmp->name != ABSMARK1 && - lmp->lno == fl) - lmp->lno = tl; - ++fl; - if (db_delete(sp, fl)) - return (1); - } - } - FREE_SPACE(sp, bp, blen); - - sp->lno = tl; /* Last line moved. */ - sp->cno = 0; - - /* Log the new positions of the marks. */ - if (mark_reset) - for (lmp = sp->ep->marks.lh_first; - lmp != NULL; lmp = lmp->q.le_next) - if (lmp->name != ABSMARK1 && - lmp->lno >= mfl && lmp->lno <= mtl) - (void)log_mark(sp, lmp); - - - sp->rptlines[L_MOVED] += diff; - return (0); -} diff --git a/contrib/nvi/ex/ex_open.c b/contrib/nvi/ex/ex_open.c deleted file mode 100644 index afffaeb..0000000 --- a/contrib/nvi/ex/ex_open.c +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * Copyright (c) 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_open.c 10.7 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> - -#include "../common/common.h" - -/* - * ex_open -- :[line] o[pen] [/pattern/] [flags] - * - * Switch to single line "open" mode. - * - * PUBLIC: int ex_open __P((SCR *, EXCMD *)); - */ -int -ex_open(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - /* If open option off, disallow open command. */ - if (!O_ISSET(sp, O_OPEN)) { - msgq(sp, M_ERR, - "140|The open command requires that the open option be set"); - return (1); - } - - msgq(sp, M_ERR, "141|The open command is not yet implemented"); - return (1); -} diff --git a/contrib/nvi/ex/ex_perl.c b/contrib/nvi/ex/ex_perl.c deleted file mode 100644 index e620352..0000000 --- a/contrib/nvi/ex/ex_perl.c +++ /dev/null @@ -1,69 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * Copyright (c) 1995 - * George V. Neville-Neil. All rights reserved. - * Copyright (c) 1996 - * Sven Verdoolaege. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_perl.c 8.10 (Berkeley) 9/15/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> -#include <termios.h> -#include <unistd.h> - -#include "../common/common.h" - -/* - * ex_perl -- :[line [,line]] perl [command] - * Run a command through the perl interpreter. - * - * ex_perldo -- :[line [,line]] perldo [command] - * Run a set of lines through the perl interpreter. - * - * PUBLIC: int ex_perl __P((SCR*, EXCMD *)); - */ -int -ex_perl(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ -#ifdef HAVE_PERL_INTERP - CHAR_T *p; - size_t len; - - /* Skip leading white space. */ - if (cmdp->argc != 0) - for (p = cmdp->argv[0]->bp, - len = cmdp->argv[0]->len; len > 0; --len, ++p) - if (!isblank(*p)) - break; - if (cmdp->argc == 0 || len == 0) { - ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); - return (1); - } - return (cmdp->cmd == &cmds[C_PERLCMD] ? - perl_ex_perl(sp, p, len, cmdp->addr1.lno, cmdp->addr2.lno) : - perl_ex_perldo(sp, p, len, cmdp->addr1.lno, cmdp->addr2.lno)); -#else - msgq(sp, M_ERR, "306|Vi was not loaded with a Perl interpreter"); - return (1); -#endif -} diff --git a/contrib/nvi/ex/ex_preserve.c b/contrib/nvi/ex/ex_preserve.c deleted file mode 100644 index 5614c88..0000000 --- a/contrib/nvi/ex/ex_preserve.c +++ /dev/null @@ -1,103 +0,0 @@ -/*- - * Copyright (c) 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_preserve.c 10.12 (Berkeley) 4/27/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> - -#include "../common/common.h" - -/* - * ex_preserve -- :pre[serve] - * Push the file to recovery. - * - * PUBLIC: int ex_preserve __P((SCR *, EXCMD *)); - */ -int -ex_preserve(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - recno_t lno; - - NEEDFILE(sp, cmdp); - - if (!F_ISSET(sp->ep, F_RCV_ON)) { - msgq(sp, M_ERR, "142|Preservation of this file not possible"); - return (1); - } - - /* If recovery not initialized, do so. */ - if (F_ISSET(sp->ep, F_FIRSTMODIFY) && rcv_init(sp)) - return (1); - - /* Force the file to be read in, in case it hasn't yet. */ - if (db_last(sp, &lno)) - return (1); - - /* Sync to disk. */ - if (rcv_sync(sp, RCV_SNAPSHOT)) - return (1); - - msgq(sp, M_INFO, "143|File preserved"); - return (0); -} - -/* - * ex_recover -- :rec[over][!] file - * Recover the file. - * - * PUBLIC: int ex_recover __P((SCR *, EXCMD *)); - */ -int -ex_recover(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - ARGS *ap; - FREF *frp; - - ap = cmdp->argv[0]; - - /* Set the alternate file name. */ - set_alt_name(sp, ap->bp); - - /* - * Check for modifications. Autowrite did not historically - * affect :recover. - */ - if (file_m2(sp, FL_ISSET(cmdp->iflags, E_C_FORCE))) - return (1); - - /* Get a file structure for the file. */ - if ((frp = file_add(sp, ap->bp)) == NULL) - return (1); - - /* Set the recover bit. */ - F_SET(frp, FR_RECOVER); - - /* Switch files. */ - if (file_init(sp, frp, NULL, FS_SETALT | - (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) - return (1); - - F_SET(sp, SC_FSWITCH); - return (0); -} diff --git a/contrib/nvi/ex/ex_print.c b/contrib/nvi/ex/ex_print.c deleted file mode 100644 index 4218e08..0000000 --- a/contrib/nvi/ex/ex_print.c +++ /dev/null @@ -1,352 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_print.c 10.18 (Berkeley) 5/12/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> - -#ifdef __STDC__ -#include <stdarg.h> -#else -#include <varargs.h> -#endif - -#include "../common/common.h" - -static int ex_prchars __P((SCR *, const char *, size_t *, size_t, u_int, int)); - -/* - * ex_list -- :[line [,line]] l[ist] [count] [flags] - * - * Display the addressed lines such that the output is unambiguous. - * - * PUBLIC: int ex_list __P((SCR *, EXCMD *)); - */ -int -ex_list(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - if (ex_print(sp, cmdp, - &cmdp->addr1, &cmdp->addr2, cmdp->iflags | E_C_LIST)) - return (1); - sp->lno = cmdp->addr2.lno; - sp->cno = cmdp->addr2.cno; - return (0); -} - -/* - * ex_number -- :[line [,line]] nu[mber] [count] [flags] - * - * Display the addressed lines with a leading line number. - * - * PUBLIC: int ex_number __P((SCR *, EXCMD *)); - */ -int -ex_number(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - if (ex_print(sp, cmdp, - &cmdp->addr1, &cmdp->addr2, cmdp->iflags | E_C_HASH)) - return (1); - sp->lno = cmdp->addr2.lno; - sp->cno = cmdp->addr2.cno; - return (0); -} - -/* - * ex_pr -- :[line [,line]] p[rint] [count] [flags] - * - * Display the addressed lines. - * - * PUBLIC: int ex_pr __P((SCR *, EXCMD *)); - */ -int -ex_pr(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - if (ex_print(sp, cmdp, &cmdp->addr1, &cmdp->addr2, cmdp->iflags)) - return (1); - sp->lno = cmdp->addr2.lno; - sp->cno = cmdp->addr2.cno; - return (0); -} - -/* - * ex_print -- - * Print the selected lines. - * - * PUBLIC: int ex_print __P((SCR *, EXCMD *, MARK *, MARK *, u_int32_t)); - */ -int -ex_print(sp, cmdp, fp, tp, flags) - SCR *sp; - EXCMD *cmdp; - MARK *fp, *tp; - u_int32_t flags; -{ - GS *gp; - recno_t from, to; - size_t col, len; - char *p, buf[10]; - - NEEDFILE(sp, cmdp); - - gp = sp->gp; - for (from = fp->lno, to = tp->lno; from <= to; ++from) { - col = 0; - - /* - * Display the line number. The %6 format is specified - * by POSIX 1003.2, and is almost certainly large enough. - * Check, though, just in case. - */ - if (LF_ISSET(E_C_HASH)) { - if (from <= 999999) { - snprintf(buf, sizeof(buf), "%6ld ", from); - p = buf; - } else - p = "TOOBIG "; - if (ex_prchars(sp, p, &col, 8, 0, 0)) - return (1); - } - - /* - * Display the line. The format for E_C_PRINT isn't very good, - * especially in handling end-of-line tabs, but they're almost - * backward compatible. - */ - if (db_get(sp, from, DBG_FATAL, &p, &len)) - return (1); - - if (len == 0 && !LF_ISSET(E_C_LIST)) - (void)ex_puts(sp, "\n"); - else if (ex_ldisplay(sp, p, len, col, flags)) - return (1); - - if (INTERRUPTED(sp)) - break; - } - return (0); -} - -/* - * ex_ldisplay -- - * Display a line without any preceding number. - * - * PUBLIC: int ex_ldisplay __P((SCR *, const char *, size_t, size_t, u_int)); - */ -int -ex_ldisplay(sp, p, len, col, flags) - SCR *sp; - const char *p; - size_t len, col; - u_int flags; -{ - if (len > 0 && ex_prchars(sp, p, &col, len, LF_ISSET(E_C_LIST), 0)) - return (1); - if (!INTERRUPTED(sp) && LF_ISSET(E_C_LIST)) { - p = "$"; - if (ex_prchars(sp, p, &col, 1, LF_ISSET(E_C_LIST), 0)) - return (1); - } - if (!INTERRUPTED(sp)) - (void)ex_puts(sp, "\n"); - return (0); -} - -/* - * ex_scprint -- - * Display a line for the substitute with confirmation routine. - * - * PUBLIC: int ex_scprint __P((SCR *, MARK *, MARK *)); - */ -int -ex_scprint(sp, fp, tp) - SCR *sp; - MARK *fp, *tp; -{ - const char *p; - size_t col, len; - - col = 0; - if (O_ISSET(sp, O_NUMBER)) { - p = " "; - if (ex_prchars(sp, p, &col, 8, 0, 0)) - return (1); - } - - if (db_get(sp, fp->lno, DBG_FATAL, (char **)&p, &len)) - return (1); - - if (ex_prchars(sp, p, &col, fp->cno, 0, ' ')) - return (1); - p += fp->cno; - if (ex_prchars(sp, - p, &col, tp->cno == fp->cno ? 1 : tp->cno - fp->cno, 0, '^')) - return (1); - if (INTERRUPTED(sp)) - return (1); - p = "[ynq]"; /* XXX: should be msg_cat. */ - if (ex_prchars(sp, p, &col, 5, 0, 0)) - return (1); - (void)ex_fflush(sp); - return (0); -} - -/* - * ex_prchars -- - * Local routine to dump characters to the screen. - */ -static int -ex_prchars(sp, p, colp, len, flags, repeatc) - SCR *sp; - const char *p; - size_t *colp, len; - u_int flags; - int repeatc; -{ - CHAR_T ch, *kp; - GS *gp; - size_t col, tlen, ts; - - if (O_ISSET(sp, O_LIST)) - LF_SET(E_C_LIST); - gp = sp->gp; - ts = O_VAL(sp, O_TABSTOP); - for (col = *colp; len--;) - if ((ch = *p++) == '\t' && !LF_ISSET(E_C_LIST)) - for (tlen = ts - col % ts; - col < sp->cols && tlen--; ++col) { - (void)ex_printf(sp, - "%c", repeatc ? repeatc : ' '); - if (INTERRUPTED(sp)) - goto intr; - } - else { - kp = KEY_NAME(sp, ch); - tlen = KEY_LEN(sp, ch); - if (!repeatc && col + tlen < sp->cols) { - (void)ex_puts(sp, kp); - col += tlen; - } else - for (; tlen--; ++kp, ++col) { - if (col == sp->cols) { - col = 0; - (void)ex_puts(sp, "\n"); - } - (void)ex_printf(sp, - "%c", repeatc ? repeatc : *kp); - if (INTERRUPTED(sp)) - goto intr; - } - } -intr: *colp = col; - return (0); -} - -/* - * ex_printf -- - * Ex's version of printf. - * - * PUBLIC: int ex_printf __P((SCR *, const char *, ...)); - */ -int -#ifdef __STDC__ -ex_printf(SCR *sp, const char *fmt, ...) -#else -ex_printf(sp, fmt, va_alist) - SCR *sp; - const char *fmt; - va_dcl -#endif -{ - EX_PRIVATE *exp; - va_list ap; - size_t n; - - exp = EXP(sp); - -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - exp->obp_len += n = vsnprintf(exp->obp + exp->obp_len, - sizeof(exp->obp) - exp->obp_len, fmt, ap); - va_end(ap); - - /* Flush when reach a <newline> or half the buffer. */ - if (exp->obp[exp->obp_len - 1] == '\n' || - exp->obp_len > sizeof(exp->obp) / 2) - (void)ex_fflush(sp); - return (n); -} - -/* - * ex_puts -- - * Ex's version of puts. - * - * PUBLIC: int ex_puts __P((SCR *, const char *)); - */ -int -ex_puts(sp, str) - SCR *sp; - const char *str; -{ - EX_PRIVATE *exp; - int doflush, n; - - exp = EXP(sp); - - /* Flush when reach a <newline> or the end of the buffer. */ - for (doflush = n = 0; *str != '\0'; ++n) { - if (exp->obp_len > sizeof(exp->obp)) - (void)ex_fflush(sp); - if ((exp->obp[exp->obp_len++] = *str++) == '\n') - doflush = 1; - } - if (doflush) - (void)ex_fflush(sp); - return (n); -} - -/* - * ex_fflush -- - * Ex's version of fflush. - * - * PUBLIC: int ex_fflush __P((SCR *sp)); - */ -int -ex_fflush(sp) - SCR *sp; -{ - EX_PRIVATE *exp; - - exp = EXP(sp); - - if (exp->obp_len != 0) { - sp->gp->scr_msg(sp, M_NONE, exp->obp, exp->obp_len); - exp->obp_len = 0; - } - return (0); -} diff --git a/contrib/nvi/ex/ex_put.c b/contrib/nvi/ex/ex_put.c deleted file mode 100644 index 2facb03..0000000 --- a/contrib/nvi/ex/ex_put.c +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_put.c 10.7 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> - -#include "../common/common.h" - -/* - * ex_put -- [line] pu[t] [buffer] - * Append a cut buffer into the file. - * - * PUBLIC: int ex_put __P((SCR *, EXCMD *)); - */ -int -ex_put(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - MARK m; - - NEEDFILE(sp, cmdp); - - m.lno = sp->lno; - m.cno = sp->cno; - if (put(sp, NULL, - FL_ISSET(cmdp->iflags, E_C_BUFFER) ? &cmdp->buffer : NULL, - &cmdp->addr1, &m, 1)) - return (1); - sp->lno = m.lno; - sp->cno = m.cno; - return (0); -} diff --git a/contrib/nvi/ex/ex_quit.c b/contrib/nvi/ex/ex_quit.c deleted file mode 100644 index 705fa1a..0000000 --- a/contrib/nvi/ex/ex_quit.c +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_quit.c 10.7 (Berkeley) 4/27/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> - -#include "../common/common.h" - -/* - * ex_quit -- :quit[!] - * Quit. - * - * PUBLIC: int ex_quit __P((SCR *, EXCMD *)); - */ -int -ex_quit(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - int force; - - force = FL_ISSET(cmdp->iflags, E_C_FORCE); - - /* Check for file modifications, or more files to edit. */ - if (file_m2(sp, force) || ex_ncheck(sp, force)) - return (1); - - F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT); - return (0); -} diff --git a/contrib/nvi/ex/ex_read.c b/contrib/nvi/ex/ex_read.c deleted file mode 100644 index 78296ff..0000000 --- a/contrib/nvi/ex/ex_read.c +++ /dev/null @@ -1,360 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_read.c 10.38 (Berkeley) 8/12/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/stat.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" -#include "../vi/vi.h" - -/* - * ex_read -- :read [file] - * :read [!cmd] - * Read from a file or utility. - * - * !!! - * Historical vi wouldn't undo a filter read, for no apparent reason. - * - * PUBLIC: int ex_read __P((SCR *, EXCMD *)); - */ -int -ex_read(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - enum { R_ARG, R_EXPANDARG, R_FILTER } which; - struct stat sb; - CHAR_T *arg, *name; - EX_PRIVATE *exp; - FILE *fp; - FREF *frp; - GS *gp; - MARK rm; - recno_t nlines; - size_t arglen; - int argc, rval; - char *p; - - gp = sp->gp; - - /* - * 0 args: read the current pathname. - * 1 args: check for "read !arg". - */ - switch (cmdp->argc) { - case 0: - which = R_ARG; - break; - case 1: - arg = cmdp->argv[0]->bp; - arglen = cmdp->argv[0]->len; - if (*arg == '!') { - ++arg; - --arglen; - which = R_FILTER; - - /* Secure means no shell access. */ - if (O_ISSET(sp, O_SECURE)) { - ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F); - return (1); - } - } else - which = R_EXPANDARG; - break; - default: - abort(); - /* NOTREACHED */ - } - - /* Load a temporary file if no file being edited. */ - if (sp->ep == NULL) { - if ((frp = file_add(sp, NULL)) == NULL) - return (1); - if (file_init(sp, frp, NULL, 0)) - return (1); - } - - switch (which) { - case R_FILTER: - /* - * File name and bang expand the user's argument. If - * we don't get an additional argument, it's illegal. - */ - argc = cmdp->argc; - if (argv_exp1(sp, cmdp, arg, arglen, 1)) - return (1); - if (argc == cmdp->argc) { - ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); - return (1); - } - argc = cmdp->argc - 1; - - /* Set the last bang command. */ - exp = EXP(sp); - if (exp->lastbcomm != NULL) - free(exp->lastbcomm); - if ((exp->lastbcomm = - strdup(cmdp->argv[argc]->bp)) == NULL) { - msgq(sp, M_SYSERR, NULL); - return (1); - } - - /* - * Vi redisplayed the user's argument if it changed, ex - * always displayed a !, plus the user's argument if it - * changed. - */ - if (F_ISSET(sp, SC_VI)) { - if (F_ISSET(cmdp, E_MODIFY)) - (void)vs_update(sp, "!", cmdp->argv[argc]->bp); - } else { - if (F_ISSET(cmdp, E_MODIFY)) - (void)ex_printf(sp, - "!%s\n", cmdp->argv[argc]->bp); - else - (void)ex_puts(sp, "!\n"); - (void)ex_fflush(sp); - } - - /* - * Historically, filter reads as the first ex command didn't - * wait for the user. If SC_SCR_EXWROTE not already set, set - * the don't-wait flag. - */ - if (!F_ISSET(sp, SC_SCR_EXWROTE)) - F_SET(sp, SC_EX_WAIT_NO); - - /* - * Switch into ex canonical mode. The reason to restore the - * original terminal modes for read filters is so that users - * can do things like ":r! cat /dev/tty". - * - * !!! - * We do not output an extra <newline>, so that we don't touch - * the screen on a normal read. - */ - if (F_ISSET(sp, SC_VI)) { - if (gp->scr_screen(sp, SC_EX)) { - ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON_F); - return (1); - } - /* - * !!! - * Historically, the read command doesn't switch to - * the alternate X11 xterm screen, if doing a filter - * read -- don't set SA_ALTERNATE. - */ - F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE); - } - - if (ex_filter(sp, cmdp, &cmdp->addr1, - NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ)) - return (1); - - /* The filter version of read set the autoprint flag. */ - F_SET(cmdp, E_AUTOPRINT); - - /* - * If in vi mode, move to the first nonblank. Might have - * switched into ex mode, so saved the original SC_VI value. - */ - sp->lno = rm.lno; - if (F_ISSET(sp, SC_VI)) { - sp->cno = 0; - (void)nonblank(sp, sp->lno, &sp->cno); - } - return (0); - case R_ARG: - name = sp->frp->name; - break; - case R_EXPANDARG: - if (argv_exp2(sp, cmdp, arg, arglen)) - return (1); - /* - * 0 args: impossible. - * 1 args: impossible (I hope). - * 2 args: read it. - * >2 args: object, too many args. - * - * The 1 args case depends on the argv_sexp() function refusing - * to return success without at least one non-blank character. - */ - switch (cmdp->argc) { - case 0: - case 1: - abort(); - /* NOTREACHED */ - case 2: - name = cmdp->argv[1]->bp; - /* - * !!! - * Historically, the read and write commands renamed - * "unnamed" files, or, if the file had a name, set - * the alternate file name. - */ - if (F_ISSET(sp->frp, FR_TMPFILE) && - !F_ISSET(sp->frp, FR_EXNAMED)) { - if ((p = v_strdup(sp, cmdp->argv[1]->bp, - cmdp->argv[1]->len)) != NULL) { - free(sp->frp->name); - sp->frp->name = p; - } - /* - * The file has a real name, it's no longer a - * temporary, clear the temporary file flags. - */ - F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE); - F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED); - - /* Notify the screen. */ - (void)sp->gp->scr_rename(sp, sp->frp->name, 1); - } else - set_alt_name(sp, name); - break; - default: - ex_emsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT); - return (1); - - } - break; - } - - /* - * !!! - * Historically, vi did not permit reads from non-regular files, nor - * did it distinguish between "read !" and "read!", so there was no - * way to "force" it. We permit reading from named pipes too, since - * they didn't exist when the original implementation of vi was done - * and they seem a reasonable addition. - */ - if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) { - msgq_str(sp, M_SYSERR, name, "%s"); - return (1); - } - if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) { - (void)fclose(fp); - msgq(sp, M_ERR, - "145|Only regular files and named pipes may be read"); - return (1); - } - - /* Try and get a lock. */ - if (file_lock(sp, NULL, NULL, fileno(fp), 0) == LOCK_UNAVAIL) - msgq(sp, M_ERR, "146|%s: read lock was unavailable", name); - - rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0); - - /* - * In vi, set the cursor to the first line read in, if anything read - * in, otherwise, the address. (Historic vi set it to the line after - * the address regardless, but since that line may not exist we don't - * bother.) - * - * In ex, set the cursor to the last line read in, if anything read in, - * otherwise, the address. - */ - if (F_ISSET(sp, SC_VI)) { - sp->lno = cmdp->addr1.lno; - if (nlines) - ++sp->lno; - } else - sp->lno = cmdp->addr1.lno + nlines; - return (rval); -} - -/* - * ex_readfp -- - * Read lines into the file. - * - * PUBLIC: int ex_readfp __P((SCR *, char *, FILE *, MARK *, recno_t *, int)); - */ -int -ex_readfp(sp, name, fp, fm, nlinesp, silent) - SCR *sp; - char *name; - FILE *fp; - MARK *fm; - recno_t *nlinesp; - int silent; -{ - EX_PRIVATE *exp; - GS *gp; - recno_t lcnt, lno; - size_t len; - u_long ccnt; /* XXX: can't print off_t portably. */ - int nf, rval; - char *p; - - gp = sp->gp; - exp = EXP(sp); - - /* - * Add in the lines from the output. Insertion starts at the line - * following the address. - */ - ccnt = 0; - lcnt = 0; - p = "147|Reading..."; - for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) { - if ((lcnt + 1) % INTERRUPT_CHECK == 0) { - if (INTERRUPTED(sp)) - break; - if (!silent) { - gp->scr_busy(sp, p, - p == NULL ? BUSY_UPDATE : BUSY_ON); - p = NULL; - } - } - if (db_append(sp, 1, lno, exp->ibp, len)) - goto err; - ccnt += len; - } - - if (ferror(fp) || fclose(fp)) - goto err; - - /* Return the number of lines read in. */ - if (nlinesp != NULL) - *nlinesp = lcnt; - - if (!silent) { - p = msg_print(sp, name, &nf); - msgq(sp, M_INFO, - "148|%s: %lu lines, %lu characters", p, lcnt, ccnt); - if (nf) - FREE_SPACE(sp, p, 0); - } - - rval = 0; - if (0) { -err: msgq_str(sp, M_SYSERR, name, "%s"); - (void)fclose(fp); - rval = 1; - } - - if (!silent) - gp->scr_busy(sp, NULL, BUSY_OFF); - return (rval); -} diff --git a/contrib/nvi/ex/ex_screen.c b/contrib/nvi/ex/ex_screen.c deleted file mode 100644 index 9bc5bf0..0000000 --- a/contrib/nvi/ex/ex_screen.c +++ /dev/null @@ -1,138 +0,0 @@ -/*- - * Copyright (c) 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_screen.c 10.11 (Berkeley) 6/29/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" -#include "../vi/vi.h" - -/* - * ex_bg -- :bg - * Hide the screen. - * - * PUBLIC: int ex_bg __P((SCR *, EXCMD *)); - */ -int -ex_bg(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - return (vs_bg(sp)); -} - -/* - * ex_fg -- :fg [file] - * Show the screen. - * - * PUBLIC: int ex_fg __P((SCR *, EXCMD *)); - */ -int -ex_fg(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - SCR *nsp; - int newscreen; - - newscreen = F_ISSET(cmdp, E_NEWSCREEN); - if (vs_fg(sp, &nsp, cmdp->argc ? cmdp->argv[0]->bp : NULL, newscreen)) - return (1); - - /* Set up the switch. */ - if (newscreen) { - sp->nextdisp = nsp; - F_SET(sp, SC_SSWITCH); - } - return (0); -} - -/* - * ex_resize -- :resize [+-]rows - * Change the screen size. - * - * PUBLIC: int ex_resize __P((SCR *, EXCMD *)); - */ -int -ex_resize(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - adj_t adj; - - switch (FL_ISSET(cmdp->iflags, - E_C_COUNT | E_C_COUNT_NEG | E_C_COUNT_POS)) { - case E_C_COUNT: - adj = A_SET; - break; - case E_C_COUNT | E_C_COUNT_NEG: - adj = A_DECREASE; - break; - case E_C_COUNT | E_C_COUNT_POS: - adj = A_INCREASE; - break; - default: - ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); - return (1); - } - return (vs_resize(sp, cmdp->count, adj)); -} - -/* - * ex_sdisplay -- - * Display the list of screens. - * - * PUBLIC: int ex_sdisplay __P((SCR *)); - */ -int -ex_sdisplay(sp) - SCR *sp; -{ - GS *gp; - SCR *tsp; - int cnt, col, len, sep; - - gp = sp->gp; - if ((tsp = gp->hq.cqh_first) == (void *)&gp->hq) { - msgq(sp, M_INFO, "149|No background screens to display"); - return (0); - } - - col = len = sep = 0; - for (cnt = 1; tsp != (void *)&gp->hq && !INTERRUPTED(sp); - tsp = tsp->q.cqe_next) { - col += len = strlen(tsp->frp->name) + sep; - if (col >= sp->cols - 1) { - col = len; - sep = 0; - (void)ex_puts(sp, "\n"); - } else if (cnt != 1) { - sep = 1; - (void)ex_puts(sp, " "); - } - (void)ex_puts(sp, tsp->frp->name); - ++cnt; - } - if (!INTERRUPTED(sp)) - (void)ex_puts(sp, "\n"); - return (0); -} diff --git a/contrib/nvi/ex/ex_script.c b/contrib/nvi/ex/ex_script.c deleted file mode 100644 index 9ca6d60..0000000 --- a/contrib/nvi/ex/ex_script.c +++ /dev/null @@ -1,798 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Brian Hirt. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_script.c 10.30 (Berkeley) 9/24/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/queue.h> -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif -#include <sys/stat.h> -#ifdef HAVE_SYS5_PTY -#include <sys/stropts.h> -#endif -#include <sys/time.h> -#include <sys/wait.h> - -#include <bitstring.h> -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> /* XXX: OSF/1 bug: include before <grp.h> */ -#include <grp.h> -#include <limits.h> -#include <stdlib.h> -#include <string.h> -#include <termios.h> -#include <unistd.h> - -#include "../common/common.h" -#include "../vi/vi.h" -#include "script.h" -#include "pathnames.h" - -static void sscr_check __P((SCR *)); -static int sscr_getprompt __P((SCR *)); -static int sscr_init __P((SCR *)); -static int sscr_insert __P((SCR *)); -static int sscr_matchprompt __P((SCR *, char *, size_t, size_t *)); -static int sscr_pty __P((int *, int *, char *, struct termios *, void *)); -static int sscr_setprompt __P((SCR *, char *, size_t)); - -/* - * ex_script -- : sc[ript][!] [file] - * Switch to script mode. - * - * PUBLIC: int ex_script __P((SCR *, EXCMD *)); - */ -int -ex_script(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - /* Vi only command. */ - if (!F_ISSET(sp, SC_VI)) { - msgq(sp, M_ERR, - "150|The script command is only available in vi mode"); - return (1); - } - - /* Switch to the new file. */ - if (cmdp->argc != 0 && ex_edit(sp, cmdp)) - return (1); - - /* Create the shell, figure out the prompt. */ - if (sscr_init(sp)) - return (1); - - return (0); -} - -/* - * sscr_init -- - * Create a pty setup for a shell. - */ -static int -sscr_init(sp) - SCR *sp; -{ - SCRIPT *sc; - char *sh, *sh_path; - - /* We're going to need a shell. */ - if (opts_empty(sp, O_SHELL, 0)) - return (1); - - MALLOC_RET(sp, sc, SCRIPT *, sizeof(SCRIPT)); - sp->script = sc; - sc->sh_prompt = NULL; - sc->sh_prompt_len = 0; - - /* - * There are two different processes running through this code. - * They are the shell and the parent. - */ - sc->sh_master = sc->sh_slave = -1; - - if (tcgetattr(STDIN_FILENO, &sc->sh_term) == -1) { - msgq(sp, M_SYSERR, "tcgetattr"); - goto err; - } - - /* - * Turn off output postprocessing and echo. - */ - sc->sh_term.c_oflag &= ~OPOST; - sc->sh_term.c_cflag &= ~(ECHO|ECHOE|ECHONL|ECHOK); - -#ifdef TIOCGWINSZ - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &sc->sh_win) == -1) { - msgq(sp, M_SYSERR, "tcgetattr"); - goto err; - } - - if (sscr_pty(&sc->sh_master, - &sc->sh_slave, sc->sh_name, &sc->sh_term, &sc->sh_win) == -1) { - msgq(sp, M_SYSERR, "pty"); - goto err; - } -#else - if (sscr_pty(&sc->sh_master, - &sc->sh_slave, sc->sh_name, &sc->sh_term, NULL) == -1) { - msgq(sp, M_SYSERR, "pty"); - goto err; - } -#endif - - /* - * __TK__ huh? - * Don't use vfork() here, because the signal semantics differ from - * implementation to implementation. - */ - switch (sc->sh_pid = fork()) { - case -1: /* Error. */ - msgq(sp, M_SYSERR, "fork"); -err: if (sc->sh_master != -1) - (void)close(sc->sh_master); - if (sc->sh_slave != -1) - (void)close(sc->sh_slave); - return (1); - case 0: /* Utility. */ - /* - * XXX - * So that shells that do command line editing turn it off. - */ - (void)setenv("TERM", "emacs", 1); - (void)setenv("TERMCAP", "emacs:", 1); - (void)setenv("EMACS", "t", 1); - - (void)setsid(); -#ifdef TIOCSCTTY - /* - * 4.4BSD allocates a controlling terminal using the TIOCSCTTY - * ioctl, not by opening a terminal device file. POSIX 1003.1 - * doesn't define a portable way to do this. If TIOCSCTTY is - * not available, hope that the open does it. - */ - (void)ioctl(sc->sh_slave, TIOCSCTTY, 0); -#endif - (void)close(sc->sh_master); - (void)dup2(sc->sh_slave, STDIN_FILENO); - (void)dup2(sc->sh_slave, STDOUT_FILENO); - (void)dup2(sc->sh_slave, STDERR_FILENO); - (void)close(sc->sh_slave); - - /* Assumes that all shells have -i. */ - sh_path = O_STR(sp, O_SHELL); - if ((sh = strrchr(sh_path, '/')) == NULL) - sh = sh_path; - else - ++sh; - execl(sh_path, sh, "-i", NULL); - msgq_str(sp, M_SYSERR, sh_path, "execl: %s"); - _exit(127); - default: /* Parent. */ - break; - } - - if (sscr_getprompt(sp)) - return (1); - - F_SET(sp, SC_SCRIPT); - F_SET(sp->gp, G_SCRWIN); - return (0); -} - -/* - * sscr_getprompt -- - * Eat lines printed by the shell until a line with no trailing - * carriage return comes; set the prompt from that line. - */ -static int -sscr_getprompt(sp) - SCR *sp; -{ - struct timeval tv; - CHAR_T *endp, *p, *t, buf[1024]; - SCRIPT *sc; - fd_set fdset; - recno_t lline; - size_t llen, len; - u_int value; - int nr; - - FD_ZERO(&fdset); - endp = buf; - len = sizeof(buf); - - /* Wait up to a second for characters to read. */ - tv.tv_sec = 5; - tv.tv_usec = 0; - sc = sp->script; - FD_SET(sc->sh_master, &fdset); - switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) { - case -1: /* Error or interrupt. */ - msgq(sp, M_SYSERR, "select"); - goto prompterr; - case 0: /* Timeout */ - msgq(sp, M_ERR, "Error: timed out"); - goto prompterr; - case 1: /* Characters to read. */ - break; - } - - /* Read the characters. */ -more: len = sizeof(buf) - (endp - buf); - switch (nr = read(sc->sh_master, endp, len)) { - case 0: /* EOF. */ - msgq(sp, M_ERR, "Error: shell: EOF"); - goto prompterr; - case -1: /* Error or interrupt. */ - msgq(sp, M_SYSERR, "shell"); - goto prompterr; - default: - endp += nr; - break; - } - - /* If any complete lines, push them into the file. */ - for (p = t = buf; p < endp; ++p) { - value = KEY_VAL(sp, *p); - if (value == K_CR || value == K_NL) { - if (db_last(sp, &lline) || - db_append(sp, 0, lline, t, p - t)) - goto prompterr; - t = p + 1; - } - } - if (p > buf) { - memmove(buf, t, endp - t); - endp = buf + (endp - t); - } - if (endp == buf) - goto more; - - /* Wait up 1/10 of a second to make sure that we got it all. */ - tv.tv_sec = 0; - tv.tv_usec = 100000; - switch (select(sc->sh_master + 1, &fdset, NULL, NULL, &tv)) { - case -1: /* Error or interrupt. */ - msgq(sp, M_SYSERR, "select"); - goto prompterr; - case 0: /* Timeout */ - break; - case 1: /* Characters to read. */ - goto more; - } - - /* Timed out, so theoretically we have a prompt. */ - llen = endp - buf; - endp = buf; - - /* Append the line into the file. */ - if (db_last(sp, &lline) || db_append(sp, 0, lline, buf, llen)) { -prompterr: sscr_end(sp); - return (1); - } - - return (sscr_setprompt(sp, buf, llen)); -} - -/* - * sscr_exec -- - * Take a line and hand it off to the shell. - * - * PUBLIC: int sscr_exec __P((SCR *, recno_t)); - */ -int -sscr_exec(sp, lno) - SCR *sp; - recno_t lno; -{ - SCRIPT *sc; - recno_t last_lno; - size_t blen, len, last_len, tlen; - int isempty, matchprompt, nw, rval; - char *bp, *p; - - /* If there's a prompt on the last line, append the command. */ - if (db_last(sp, &last_lno)) - return (1); - if (db_get(sp, last_lno, DBG_FATAL, &p, &last_len)) - return (1); - if (sscr_matchprompt(sp, p, last_len, &tlen) && tlen == 0) { - matchprompt = 1; - GET_SPACE_RET(sp, bp, blen, last_len + 128); - memmove(bp, p, last_len); - } else - matchprompt = 0; - - /* Get something to execute. */ - if (db_eget(sp, lno, &p, &len, &isempty)) { - if (isempty) - goto empty; - goto err1; - } - - /* Empty lines aren't interesting. */ - if (len == 0) - goto empty; - - /* Delete any prompt. */ - if (sscr_matchprompt(sp, p, len, &tlen)) { - if (tlen == len) { -empty: msgq(sp, M_BERR, "151|No command to execute"); - goto err1; - } - p += (len - tlen); - len = tlen; - } - - /* Push the line to the shell. */ - sc = sp->script; - if ((nw = write(sc->sh_master, p, len)) != len) - goto err2; - rval = 0; - if (write(sc->sh_master, "\n", 1) != 1) { -err2: if (nw == 0) - errno = EIO; - msgq(sp, M_SYSERR, "shell"); - goto err1; - } - - if (matchprompt) { - ADD_SPACE_RET(sp, bp, blen, last_len + len); - memmove(bp + last_len, p, len); - if (db_set(sp, last_lno, bp, last_len + len)) -err1: rval = 1; - } - if (matchprompt) - FREE_SPACE(sp, bp, blen); - return (rval); -} - -/* - * sscr_input -- - * Read any waiting shell input. - * - * PUBLIC: int sscr_input __P((SCR *)); - */ -int -sscr_input(sp) - SCR *sp; -{ - GS *gp; - struct timeval poll; - fd_set rdfd; - int maxfd; - - gp = sp->gp; - -loop: maxfd = 0; - FD_ZERO(&rdfd); - poll.tv_sec = 0; - poll.tv_usec = 0; - - /* Set up the input mask. */ - for (sp = gp->dq.cqh_first; sp != (void *)&gp->dq; sp = sp->q.cqe_next) - if (F_ISSET(sp, SC_SCRIPT)) { - FD_SET(sp->script->sh_master, &rdfd); - if (sp->script->sh_master > maxfd) - maxfd = sp->script->sh_master; - } - - /* Check for input. */ - switch (select(maxfd + 1, &rdfd, NULL, NULL, &poll)) { - case -1: - msgq(sp, M_SYSERR, "select"); - return (1); - case 0: - return (0); - default: - break; - } - - /* Read the input. */ - for (sp = gp->dq.cqh_first; sp != (void *)&gp->dq; sp = sp->q.cqe_next) - if (F_ISSET(sp, SC_SCRIPT) && - FD_ISSET(sp->script->sh_master, &rdfd) && sscr_insert(sp)) - return (1); - goto loop; -} - -/* - * sscr_insert -- - * Take a line from the shell and insert it into the file. - */ -static int -sscr_insert(sp) - SCR *sp; -{ - struct timeval tv; - CHAR_T *endp, *p, *t; - SCRIPT *sc; - fd_set rdfd; - recno_t lno; - size_t blen, len, tlen; - u_int value; - int nr, rval; - char *bp; - - /* Find out where the end of the file is. */ - if (db_last(sp, &lno)) - return (1); - -#define MINREAD 1024 - GET_SPACE_RET(sp, bp, blen, MINREAD); - endp = bp; - - /* Read the characters. */ - rval = 1; - sc = sp->script; -more: switch (nr = read(sc->sh_master, endp, MINREAD)) { - case 0: /* EOF; shell just exited. */ - sscr_end(sp); - rval = 0; - goto ret; - case -1: /* Error or interrupt. */ - msgq(sp, M_SYSERR, "shell"); - goto ret; - default: - endp += nr; - break; - } - - /* Append the lines into the file. */ - for (p = t = bp; p < endp; ++p) { - value = KEY_VAL(sp, *p); - if (value == K_CR || value == K_NL) { - len = p - t; - if (db_append(sp, 1, lno++, t, len)) - goto ret; - t = p + 1; - } - } - if (p > t) { - len = p - t; - /* - * If the last thing from the shell isn't another prompt, wait - * up to 1/10 of a second for more stuff to show up, so that - * we don't break the output into two separate lines. Don't - * want to hang indefinitely because some program is hanging, - * confused the shell, or whatever. - */ - if (!sscr_matchprompt(sp, t, len, &tlen) || tlen != 0) { - tv.tv_sec = 0; - tv.tv_usec = 100000; - FD_ZERO(&rdfd); - FD_SET(sc->sh_master, &rdfd); - if (select(sc->sh_master + 1, - &rdfd, NULL, NULL, &tv) == 1) { - memmove(bp, t, len); - endp = bp + len; - goto more; - } - } - if (sscr_setprompt(sp, t, len)) - return (1); - if (db_append(sp, 1, lno++, t, len)) - goto ret; - } - - /* The cursor moves to EOF. */ - sp->lno = lno; - sp->cno = len ? len - 1 : 0; - rval = vs_refresh(sp, 1); - -ret: FREE_SPACE(sp, bp, blen); - return (rval); -} - -/* - * sscr_setprompt -- - * - * Set the prompt to the last line we got from the shell. - * - */ -static int -sscr_setprompt(sp, buf, len) - SCR *sp; - char *buf; - size_t len; -{ - SCRIPT *sc; - - sc = sp->script; - if (sc->sh_prompt) - free(sc->sh_prompt); - MALLOC(sp, sc->sh_prompt, char *, len + 1); - if (sc->sh_prompt == NULL) { - sscr_end(sp); - return (1); - } - memmove(sc->sh_prompt, buf, len); - sc->sh_prompt_len = len; - sc->sh_prompt[len] = '\0'; - return (0); -} - -/* - * sscr_matchprompt -- - * Check to see if a line matches the prompt. Nul's indicate - * parts that can change, in both content and size. - */ -static int -sscr_matchprompt(sp, lp, line_len, lenp) - SCR *sp; - char *lp; - size_t line_len, *lenp; -{ - SCRIPT *sc; - size_t prompt_len; - char *pp; - - sc = sp->script; - if (line_len < (prompt_len = sc->sh_prompt_len)) - return (0); - - for (pp = sc->sh_prompt; - prompt_len && line_len; --prompt_len, --line_len) { - if (*pp == '\0') { - for (; prompt_len && *pp == '\0'; --prompt_len, ++pp); - if (!prompt_len) - return (0); - for (; line_len && *lp != *pp; --line_len, ++lp); - if (!line_len) - return (0); - } - if (*pp++ != *lp++) - break; - } - - if (prompt_len) - return (0); - if (lenp != NULL) - *lenp = line_len; - return (1); -} - -/* - * sscr_end -- - * End the pipe to a shell. - * - * PUBLIC: int sscr_end __P((SCR *)); - */ -int -sscr_end(sp) - SCR *sp; -{ - SCRIPT *sc; - - if ((sc = sp->script) == NULL) - return (0); - - /* Turn off the script flags. */ - F_CLR(sp, SC_SCRIPT); - sscr_check(sp); - - /* Close down the parent's file descriptors. */ - if (sc->sh_master != -1) - (void)close(sc->sh_master); - if (sc->sh_slave != -1) - (void)close(sc->sh_slave); - - /* This should have killed the child. */ - (void)proc_wait(sp, (long)sc->sh_pid, "script-shell", 0, 0); - - /* Free memory. */ - free(sc->sh_prompt); - free(sc); - sp->script = NULL; - - return (0); -} - -/* - * sscr_check -- - * Set/clear the global scripting bit. - */ -static void -sscr_check(sp) - SCR *sp; -{ - GS *gp; - - gp = sp->gp; - for (sp = gp->dq.cqh_first; sp != (void *)&gp->dq; sp = sp->q.cqe_next) - if (F_ISSET(sp, SC_SCRIPT)) { - F_SET(gp, G_SCRWIN); - return; - } - F_CLR(gp, G_SCRWIN); -} - -#ifdef HAVE_SYS5_PTY -static int ptys_open __P((int, char *)); -static int ptym_open __P((char *)); - -static int -sscr_pty(amaster, aslave, name, termp, winp) - int *amaster, *aslave; - char *name; - struct termios *termp; - void *winp; -{ - int master, slave, ttygid; - - /* open master terminal */ - if ((master = ptym_open(name)) < 0) { - errno = ENOENT; /* out of ptys */ - return (-1); - } - - /* open slave terminal */ - if ((slave = ptys_open(master, name)) >= 0) { - *amaster = master; - *aslave = slave; - } else { - errno = ENOENT; /* out of ptys */ - return (-1); - } - - if (termp) - (void) tcsetattr(slave, TCSAFLUSH, termp); -#ifdef TIOCSWINSZ - if (winp != NULL) - (void) ioctl(slave, TIOCSWINSZ, (struct winsize *)winp); -#endif - return (0); -} - -/* - * ptym_open -- - * This function opens a master pty and returns the file descriptor - * to it. pts_name is also returned which is the name of the slave. - */ -static int -ptym_open(pts_name) - char *pts_name; -{ - int fdm; - char *ptr, *ptsname(); - - strcpy(pts_name, _PATH_SYSV_PTY); - if ((fdm = open(pts_name, O_RDWR)) < 0 ) - return (-1); - - if (grantpt(fdm) < 0) { - close(fdm); - return (-2); - } - - if (unlockpt(fdm) < 0) { - close(fdm); - return (-3); - } - - if (unlockpt(fdm) < 0) { - close(fdm); - return (-3); - } - - /* get slave's name */ - if ((ptr = ptsname(fdm)) == NULL) { - close(fdm); - return (-3); - } - strcpy(pts_name, ptr); - return (fdm); -} - -/* - * ptys_open -- - * This function opens the slave pty. - */ -static int -ptys_open(fdm, pts_name) - int fdm; - char *pts_name; -{ - int fds; - - if ((fds = open(pts_name, O_RDWR)) < 0) { - close(fdm); - return (-5); - } - - if (ioctl(fds, I_PUSH, "ptem") < 0) { - close(fds); - close(fdm); - return (-6); - } - - if (ioctl(fds, I_PUSH, "ldterm") < 0) { - close(fds); - close(fdm); - return (-7); - } - - if (ioctl(fds, I_PUSH, "ttcompat") < 0) { - close(fds); - close(fdm); - return (-8); - } - - return (fds); -} - -#else /* !HAVE_SYS5_PTY */ - -static int -sscr_pty(amaster, aslave, name, termp, winp) - int *amaster, *aslave; - char *name; - struct termios *termp; - void *winp; -{ - static char line[] = "/dev/ptyXX"; - register char *cp1, *cp2; - register int master, slave, ttygid; - struct group *gr; - - if ((gr = getgrnam("tty")) != NULL) - ttygid = gr->gr_gid; - else - ttygid = -1; - - for (cp1 = "pqrs"; *cp1; cp1++) { - line[8] = *cp1; - for (cp2 = "0123456789abcdef"; *cp2; cp2++) { - line[5] = 'p'; - line[9] = *cp2; - if ((master = open(line, O_RDWR, 0)) == -1) { - if (errno == ENOENT) - return (-1); /* out of ptys */ - } else { - line[5] = 't'; - (void) chown(line, getuid(), ttygid); - (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); -#ifdef HAVE_REVOKE - (void) revoke(line); -#endif - if ((slave = open(line, O_RDWR, 0)) != -1) { - *amaster = master; - *aslave = slave; - if (name) - strcpy(name, line); - if (termp) - (void) tcsetattr(slave, - TCSAFLUSH, termp); -#ifdef TIOCSWINSZ - if (winp) - (void) ioctl(slave, TIOCSWINSZ, - (char *)winp); -#endif - return (0); - } - (void) close(master); - } - } - } - errno = ENOENT; /* out of ptys */ - return (-1); -} -#endif /* HAVE_SYS5_PTY */ diff --git a/contrib/nvi/ex/ex_set.c b/contrib/nvi/ex/ex_set.c deleted file mode 100644 index 11e9297..0000000 --- a/contrib/nvi/ex/ex_set.c +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_set.c 10.7 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> - -#include "../common/common.h" - -/* - * ex_set -- :set - * Ex set option. - * - * PUBLIC: int ex_set __P((SCR *, EXCMD *)); - */ -int -ex_set(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - switch(cmdp->argc) { - case 0: - opts_dump(sp, CHANGED_DISPLAY); - break; - default: - if (opts_set(sp, cmdp->argv, cmdp->cmd->usage)) - return (1); - break; - } - return (0); -} diff --git a/contrib/nvi/ex/ex_shell.c b/contrib/nvi/ex/ex_shell.c deleted file mode 100644 index 9516803..0000000 --- a/contrib/nvi/ex/ex_shell.c +++ /dev/null @@ -1,378 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_shell.c 10.38 (Berkeley) 8/19/96"; -#endif /* not lint */ - -#include <sys/param.h> -#include <sys/queue.h> -#include <sys/wait.h> - -#include <bitstring.h> -#include <errno.h> -#include <limits.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" - -static const char *sigmsg __P((int)); - -/* - * ex_shell -- :sh[ell] - * Invoke the program named in the SHELL environment variable - * with the argument -i. - * - * PUBLIC: int ex_shell __P((SCR *, EXCMD *)); - */ -int -ex_shell(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - int rval; - char buf[MAXPATHLEN]; - - /* We'll need a shell. */ - if (opts_empty(sp, O_SHELL, 0)) - return (1); - - /* - * XXX - * Assumes all shells use -i. - */ - (void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL)); - - /* Restore the window name. */ - (void)sp->gp->scr_rename(sp, NULL, 0); - - /* If we're still in a vi screen, move out explicitly. */ - rval = ex_exec_proc(sp, cmdp, buf, NULL, !F_ISSET(sp, SC_SCR_EXWROTE)); - - /* Set the window name. */ - (void)sp->gp->scr_rename(sp, sp->frp->name, 1); - - /* - * !!! - * Historically, vi didn't require a continue message after the - * return of the shell. Match it. - */ - F_SET(sp, SC_EX_WAIT_NO); - - return (rval); -} - -/* - * ex_exec_proc -- - * Run a separate process. - * - * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, char *, const char *, int)); - */ -int -ex_exec_proc(sp, cmdp, cmd, msg, need_newline) - SCR *sp; - EXCMD *cmdp; - char *cmd; - const char *msg; - int need_newline; -{ - GS *gp; - const char *name; - pid_t pid; - - gp = sp->gp; - - /* We'll need a shell. */ - if (opts_empty(sp, O_SHELL, 0)) - return (1); - - /* Enter ex mode. */ - if (F_ISSET(sp, SC_VI)) { - if (gp->scr_screen(sp, SC_EX)) { - ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON); - return (1); - } - (void)gp->scr_attr(sp, SA_ALTERNATE, 0); - F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE); - } - - /* Put out additional newline, message. */ - if (need_newline) - (void)ex_puts(sp, "\n"); - if (msg != NULL) { - (void)ex_puts(sp, msg); - (void)ex_puts(sp, "\n"); - } - (void)ex_fflush(sp); - - switch (pid = vfork()) { - case -1: /* Error. */ - msgq(sp, M_SYSERR, "vfork"); - return (1); - case 0: /* Utility. */ - if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL) - name = O_STR(sp, O_SHELL); - else - ++name; - execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL); - msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s"); - _exit(127); - /* NOTREACHED */ - default: /* Parent. */ - return (proc_wait(sp, (long)pid, cmd, 0, 0)); - } - /* NOTREACHED */ -} - -/* - * proc_wait -- - * Wait for one of the processes. - * - * !!! - * The pid_t type varies in size from a short to a long depending on the - * system. It has to be cast into something or the standard promotion - * rules get you. I'm using a long based on the belief that nobody is - * going to make it unsigned and it's unlikely to be a quad. - * - * PUBLIC: int proc_wait __P((SCR *, long, const char *, int, int)); - */ -int -proc_wait(sp, pid, cmd, silent, okpipe) - SCR *sp; - long pid; - const char *cmd; - int silent, okpipe; -{ - size_t len; - int nf, pstat; - char *p; - - /* Wait for the utility, ignoring interruptions. */ - for (;;) { - errno = 0; - if (waitpid((pid_t)pid, &pstat, 0) != -1) - break; - if (errno != EINTR) { - msgq(sp, M_SYSERR, "waitpid"); - return (1); - } - } - - /* - * Display the utility's exit status. Ignore SIGPIPE from the - * parent-writer, as that only means that the utility chose to - * exit before reading all of its input. - */ - if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) { - for (; isblank(*cmd); ++cmd); - p = msg_print(sp, cmd, &nf); - len = strlen(p); - msgq(sp, M_ERR, "%.*s%s: received signal: %s%s", - MIN(len, 20), p, len > 20 ? " ..." : "", - sigmsg(WTERMSIG(pstat)), - WCOREDUMP(pstat) ? "; core dumped" : ""); - if (nf) - FREE_SPACE(sp, p, 0); - return (1); - } - - if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) { - /* - * Remain silent for "normal" errors when doing shell file - * name expansions, they almost certainly indicate nothing - * more than a failure to match. - * - * Remain silent for vi read filter errors. It's historic - * practice. - */ - if (!silent) { - for (; isblank(*cmd); ++cmd); - p = msg_print(sp, cmd, &nf); - len = strlen(p); - msgq(sp, M_ERR, "%.*s%s: exited with status %d", - MIN(len, 20), p, len > 20 ? " ..." : "", - WEXITSTATUS(pstat)); - if (nf) - FREE_SPACE(sp, p, 0); - } - return (1); - } - return (0); -} - -/* - * XXX - * The sys_siglist[] table in the C library has this information, but there's - * no portable way to get to it. (Believe me, I tried.) - */ -typedef struct _sigs { - int number; /* signal number */ - char *message; /* related message */ -} SIGS; - -SIGS const sigs[] = { -#ifdef SIGABRT - SIGABRT, "Abort trap", -#endif -#ifdef SIGALRM - SIGALRM, "Alarm clock", -#endif -#ifdef SIGBUS - SIGBUS, "Bus error", -#endif -#ifdef SIGCLD - SIGCLD, "Child exited or stopped", -#endif -#ifdef SIGCHLD - SIGCHLD, "Child exited", -#endif -#ifdef SIGCONT - SIGCONT, "Continued", -#endif -#ifdef SIGDANGER - SIGDANGER, "System crash imminent", -#endif -#ifdef SIGEMT - SIGEMT, "EMT trap", -#endif -#ifdef SIGFPE - SIGFPE, "Floating point exception", -#endif -#ifdef SIGGRANT - SIGGRANT, "HFT monitor mode granted", -#endif -#ifdef SIGHUP - SIGHUP, "Hangup", -#endif -#ifdef SIGILL - SIGILL, "Illegal instruction", -#endif -#ifdef SIGINFO - SIGINFO, "Information request", -#endif -#ifdef SIGINT - SIGINT, "Interrupt", -#endif -#ifdef SIGIO - SIGIO, "I/O possible", -#endif -#ifdef SIGIOT - SIGIOT, "IOT trap", -#endif -#ifdef SIGKILL - SIGKILL, "Killed", -#endif -#ifdef SIGLOST - SIGLOST, "Record lock", -#endif -#ifdef SIGMIGRATE - SIGMIGRATE, "Migrate process to another CPU", -#endif -#ifdef SIGMSG - SIGMSG, "HFT input data pending", -#endif -#ifdef SIGPIPE - SIGPIPE, "Broken pipe", -#endif -#ifdef SIGPOLL - SIGPOLL, "I/O possible", -#endif -#ifdef SIGPRE - SIGPRE, "Programming error", -#endif -#ifdef SIGPROF - SIGPROF, "Profiling timer expired", -#endif -#ifdef SIGPWR - SIGPWR, "Power failure imminent", -#endif -#ifdef SIGRETRACT - SIGRETRACT, "HFT monitor mode retracted", -#endif -#ifdef SIGQUIT - SIGQUIT, "Quit", -#endif -#ifdef SIGSAK - SIGSAK, "Secure Attention Key", -#endif -#ifdef SIGSEGV - SIGSEGV, "Segmentation fault", -#endif -#ifdef SIGSOUND - SIGSOUND, "HFT sound sequence completed", -#endif -#ifdef SIGSTOP - SIGSTOP, "Suspended (signal)", -#endif -#ifdef SIGSYS - SIGSYS, "Bad system call", -#endif -#ifdef SIGTERM - SIGTERM, "Terminated", -#endif -#ifdef SIGTRAP - SIGTRAP, "Trace/BPT trap", -#endif -#ifdef SIGTSTP - SIGTSTP, "Suspended", -#endif -#ifdef SIGTTIN - SIGTTIN, "Stopped (tty input)", -#endif -#ifdef SIGTTOU - SIGTTOU, "Stopped (tty output)", -#endif -#ifdef SIGURG - SIGURG, "Urgent I/O condition", -#endif -#ifdef SIGUSR1 - SIGUSR1, "User defined signal 1", -#endif -#ifdef SIGUSR2 - SIGUSR2, "User defined signal 2", -#endif -#ifdef SIGVTALRM - SIGVTALRM, "Virtual timer expired", -#endif -#ifdef SIGWINCH - SIGWINCH, "Window size changes", -#endif -#ifdef SIGXCPU - SIGXCPU, "Cputime limit exceeded", -#endif -#ifdef SIGXFSZ - SIGXFSZ, "Filesize limit exceeded", -#endif -}; - -/* - * sigmsg -- - * Return a pointer to a message describing a signal. - */ -static const char * -sigmsg(signo) - int signo; -{ - static char buf[40]; - const SIGS *sigp; - int n; - - for (n = 0, - sigp = &sigs[0]; n < sizeof(sigs) / sizeof(sigs[0]); ++n, ++sigp) - if (sigp->number == signo) - return (sigp->message); - (void)snprintf(buf, sizeof(buf), "Unknown signal: %d", signo); - return (buf); -} diff --git a/contrib/nvi/ex/ex_shift.c b/contrib/nvi/ex/ex_shift.c deleted file mode 100644 index 83bd36d..0000000 --- a/contrib/nvi/ex/ex_shift.c +++ /dev/null @@ -1,191 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_shift.c 10.11 (Berkeley) 9/15/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" - -enum which {LEFT, RIGHT}; -static int shift __P((SCR *, EXCMD *, enum which)); - -/* - * ex_shiftl -- :<[<...] - * - * - * PUBLIC: int ex_shiftl __P((SCR *, EXCMD *)); - */ -int -ex_shiftl(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - return (shift(sp, cmdp, LEFT)); -} - -/* - * ex_shiftr -- :>[>...] - * - * PUBLIC: int ex_shiftr __P((SCR *, EXCMD *)); - */ -int -ex_shiftr(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - return (shift(sp, cmdp, RIGHT)); -} - -/* - * shift -- - * Ex shift support. - */ -static int -shift(sp, cmdp, rl) - SCR *sp; - EXCMD *cmdp; - enum which rl; -{ - recno_t from, to; - size_t blen, len, newcol, newidx, oldcol, oldidx, sw; - int curset; - char *p, *bp, *tbp; - - NEEDFILE(sp, cmdp); - - if (O_VAL(sp, O_SHIFTWIDTH) == 0) { - msgq(sp, M_INFO, "152|shiftwidth option set to 0"); - return (0); - } - - /* Copy the lines being shifted into the unnamed buffer. */ - if (cut(sp, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE)) - return (1); - - /* - * The historic version of vi permitted the user to string any number - * of '>' or '<' characters together, resulting in an indent of the - * appropriate levels. There's a special hack in ex_cmd() so that - * cmdp->argv[0] points to the string of '>' or '<' characters. - * - * Q: What's the difference between the people adding features - * to vi and the Girl Scouts? - * A: The Girl Scouts have mint cookies and adult supervision. - */ - for (p = cmdp->argv[0]->bp, sw = 0; *p == '>' || *p == '<'; ++p) - sw += O_VAL(sp, O_SHIFTWIDTH); - - GET_SPACE_RET(sp, bp, blen, 256); - - curset = 0; - for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) { - if (db_get(sp, from, DBG_FATAL, &p, &len)) - goto err; - if (!len) { - if (sp->lno == from) - curset = 1; - continue; - } - - /* - * Calculate the old indent amount and the number of - * characters it used. - */ - for (oldidx = 0, oldcol = 0; oldidx < len; ++oldidx) - if (p[oldidx] == ' ') - ++oldcol; - else if (p[oldidx] == '\t') - oldcol += O_VAL(sp, O_TABSTOP) - - oldcol % O_VAL(sp, O_TABSTOP); - else - break; - - /* Calculate the new indent amount. */ - if (rl == RIGHT) - newcol = oldcol + sw; - else { - newcol = oldcol < sw ? 0 : oldcol - sw; - if (newcol == oldcol) { - if (sp->lno == from) - curset = 1; - continue; - } - } - - /* Get a buffer that will hold the new line. */ - ADD_SPACE_RET(sp, bp, blen, newcol + len); - - /* - * Build a new indent string and count the number of - * characters it uses. - */ - for (tbp = bp, newidx = 0; - newcol >= O_VAL(sp, O_TABSTOP); ++newidx) { - *tbp++ = '\t'; - newcol -= O_VAL(sp, O_TABSTOP); - } - for (; newcol > 0; --newcol, ++newidx) - *tbp++ = ' '; - - /* Add the original line. */ - memcpy(tbp, p + oldidx, len - oldidx); - - /* Set the replacement line. */ - if (db_set(sp, from, bp, (tbp + (len - oldidx)) - bp)) { -err: FREE_SPACE(sp, bp, blen); - return (1); - } - - /* - * !!! - * The shift command in historic vi had the usual bizarre - * collection of cursor semantics. If called from vi, the - * cursor was repositioned to the first non-blank character - * of the lowest numbered line shifted. If called from ex, - * the cursor was repositioned to the first non-blank of the - * highest numbered line shifted. Here, if the cursor isn't - * part of the set of lines that are moved, move it to the - * first non-blank of the last line shifted. (This makes - * ":3>>" in vi work reasonably.) If the cursor is part of - * the shifted lines, it doesn't get moved at all. This - * permits shifting of marked areas, i.e. ">'a." shifts the - * marked area twice, something that couldn't be done with - * historic vi. - */ - if (sp->lno == from) { - curset = 1; - if (newidx > oldidx) - sp->cno += newidx - oldidx; - else if (sp->cno >= oldidx - newidx) - sp->cno -= oldidx - newidx; - } - } - if (!curset) { - sp->lno = to; - sp->cno = 0; - (void)nonblank(sp, to, &sp->cno); - } - - FREE_SPACE(sp, bp, blen); - - sp->rptlines[L_SHIFT] += cmdp->addr2.lno - cmdp->addr1.lno + 1; - return (0); -} diff --git a/contrib/nvi/ex/ex_source.c b/contrib/nvi/ex/ex_source.c deleted file mode 100644 index b52c527..0000000 --- a/contrib/nvi/ex/ex_source.c +++ /dev/null @@ -1,85 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_source.c 10.12 (Berkeley) 8/10/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/stat.h> - -#include <bitstring.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" - -/* - * ex_source -- :source file - * Execute ex commands from a file. - * - * PUBLIC: int ex_source __P((SCR *, EXCMD *)); - */ -int -ex_source(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - struct stat sb; - int fd, len; - char *bp, *name; - - name = cmdp->argv[0]->bp; - if ((fd = open(name, O_RDONLY, 0)) < 0 || fstat(fd, &sb)) - goto err; - - /* - * XXX - * I'd like to test to see if the file is too large to malloc. Since - * we don't know what size or type off_t's or size_t's are, what the - * largest unsigned integral type is, or what random insanity the local - * C compiler will perpetrate, doing the comparison in a portable way - * is flatly impossible. So, put an fairly unreasonable limit on it, - * I don't want to be dropping core here. - */ -#define MEGABYTE 1048576 - if (sb.st_size > MEGABYTE) { - errno = ENOMEM; - goto err; - } - - MALLOC(sp, bp, char *, (size_t)sb.st_size + 1); - if (bp == NULL) { - (void)close(fd); - return (1); - } - bp[sb.st_size] = '\0'; - - /* Read the file into memory. */ - len = read(fd, bp, (int)sb.st_size); - (void)close(fd); - if (len == -1 || len != sb.st_size) { - if (len != sb.st_size) - errno = EIO; - free(bp); -err: msgq_str(sp, M_SYSERR, name, "%s"); - return (1); - } - - /* Put it on the ex queue. */ - return (ex_run_str(sp, name, bp, (size_t)sb.st_size, 1, 1)); -} diff --git a/contrib/nvi/ex/ex_stop.c b/contrib/nvi/ex/ex_stop.c deleted file mode 100644 index bc55fd2..0000000 --- a/contrib/nvi/ex/ex_stop.c +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * Copyright (c) 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_stop.c 10.10 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" - -/* - * ex_stop -- :stop[!] - * :suspend[!] - * Suspend execution. - * - * PUBLIC: int ex_stop __P((SCR *, EXCMD *)); - */ -int -ex_stop(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - int allowed; - - /* For some strange reason, the force flag turns off autowrite. */ - if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && file_aw(sp, FS_ALL)) - return (1); - - if (sp->gp->scr_suspend(sp, &allowed)) - return (1); - if (!allowed) - ex_emsg(sp, NULL, EXM_NOSUSPEND); - return (0); -} diff --git a/contrib/nvi/ex/ex_subst.c b/contrib/nvi/ex/ex_subst.c deleted file mode 100644 index 0ebb81d..0000000 --- a/contrib/nvi/ex/ex_subst.c +++ /dev/null @@ -1,1459 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_subst.c 10.37 (Berkeley) 9/15/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" -#include "../vi/vi.h" - -#define SUB_FIRST 0x01 /* The 'r' flag isn't reasonable. */ -#define SUB_MUSTSETR 0x02 /* The 'r' flag is required. */ - -static int re_conv __P((SCR *, char **, size_t *, int *)); -static int re_cscope_conv __P((SCR *, char **, size_t *, int *)); -static int re_sub __P((SCR *, - char *, char **, size_t *, size_t *, regmatch_t [10])); -static int re_tag_conv __P((SCR *, char **, size_t *, int *)); -static int s __P((SCR *, EXCMD *, char *, regex_t *, u_int)); - -/* - * ex_s -- - * [line [,line]] s[ubstitute] [[/;]pat[/;]/repl[/;] [cgr] [count] [#lp]] - * - * Substitute on lines matching a pattern. - * - * PUBLIC: int ex_s __P((SCR *, EXCMD *)); - */ -int -ex_s(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - regex_t *re; - size_t blen, len; - u_int flags; - int delim; - char *bp, *ptrn, *rep, *p, *t; - - /* - * Skip leading white space. - * - * !!! - * Historic vi allowed any non-alphanumeric to serve as the - * substitution command delimiter. - * - * !!! - * If the arguments are empty, it's the same as &, i.e. we - * repeat the last substitution. - */ - if (cmdp->argc == 0) - goto subagain; - for (p = cmdp->argv[0]->bp, - len = cmdp->argv[0]->len; len > 0; --len, ++p) { - if (!isblank(*p)) - break; - } - if (len == 0) -subagain: return (ex_subagain(sp, cmdp)); - - delim = *p++; - if (isalnum(delim) || delim == '\\') - return (s(sp, cmdp, p, &sp->subre_c, SUB_MUSTSETR)); - - /* - * !!! - * The full-blown substitute command reset the remembered - * state of the 'c' and 'g' suffices. - */ - sp->c_suffix = sp->g_suffix = 0; - - /* - * Get the pattern string, toss escaping characters. - * - * !!! - * Historic vi accepted any of the following forms: - * - * :s/abc/def/ change "abc" to "def" - * :s/abc/def change "abc" to "def" - * :s/abc/ delete "abc" - * :s/abc delete "abc" - * - * QUOTING NOTE: - * - * Only toss an escaping character if it escapes a delimiter. - * This means that "s/A/\\\\f" replaces "A" with "\\f". It - * would be nice to be more regular, i.e. for each layer of - * escaping a single escaping character is removed, but that's - * not how the historic vi worked. - */ - for (ptrn = t = p;;) { - if (p[0] == '\0' || p[0] == delim) { - if (p[0] == delim) - ++p; - /* - * !!! - * Nul terminate the pattern string -- it's passed - * to regcomp which doesn't understand anything else. - */ - *t = '\0'; - break; - } - if (p[0] == '\\') - if (p[1] == delim) - ++p; - else if (p[1] == '\\') - *t++ = *p++; - *t++ = *p++; - } - - /* - * If the pattern string is empty, use the last RE (not just the - * last substitution RE). - */ - if (*ptrn == '\0') { - if (sp->re == NULL) { - ex_emsg(sp, NULL, EXM_NOPREVRE); - return (1); - } - - /* Re-compile the RE if necessary. */ - if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp, - sp->re, sp->re_len, NULL, NULL, &sp->re_c, RE_C_SEARCH)) - return (1); - flags = 0; - } else { - /* - * !!! - * Compile the RE. Historic practice is that substitutes set - * the search direction as well as both substitute and search - * RE's. We compile the RE twice, as we don't want to bother - * ref counting the pattern string and (opaque) structure. - */ - if (re_compile(sp, ptrn, t - ptrn, - &sp->re, &sp->re_len, &sp->re_c, RE_C_SEARCH)) - return (1); - if (re_compile(sp, ptrn, t - ptrn, - &sp->subre, &sp->subre_len, &sp->subre_c, RE_C_SUBST)) - return (1); - - flags = SUB_FIRST; - sp->searchdir = FORWARD; - } - re = &sp->re_c; - - /* - * Get the replacement string. - * - * The special character & (\& if O_MAGIC not set) matches the - * entire RE. No handling of & is required here, it's done by - * re_sub(). - * - * The special character ~ (\~ if O_MAGIC not set) inserts the - * previous replacement string into this replacement string. - * Count ~'s to figure out how much space we need. We could - * special case nonexistent last patterns or whether or not - * O_MAGIC is set, but it's probably not worth the effort. - * - * QUOTING NOTE: - * - * Only toss an escaping character if it escapes a delimiter or - * if O_MAGIC is set and it escapes a tilde. - * - * !!! - * If the entire replacement pattern is "%", then use the last - * replacement pattern. This semantic was added to vi in System - * V and then percolated elsewhere, presumably around the time - * that it was added to their version of ed(1). - */ - if (p[0] == '\0' || p[0] == delim) { - if (p[0] == delim) - ++p; - if (sp->repl != NULL) - free(sp->repl); - sp->repl = NULL; - sp->repl_len = 0; - } else if (p[0] == '%' && (p[1] == '\0' || p[1] == delim)) - p += p[1] == delim ? 2 : 1; - else { - for (rep = p, len = 0; - p[0] != '\0' && p[0] != delim; ++p, ++len) - if (p[0] == '~') - len += sp->repl_len; - GET_SPACE_RET(sp, bp, blen, len); - for (t = bp, len = 0, p = rep;;) { - if (p[0] == '\0' || p[0] == delim) { - if (p[0] == delim) - ++p; - break; - } - if (p[0] == '\\') { - if (p[1] == delim) - ++p; - else if (p[1] == '\\') { - *t++ = *p++; - ++len; - } else if (p[1] == '~') { - ++p; - if (!O_ISSET(sp, O_MAGIC)) - goto tilde; - } - } else if (p[0] == '~' && O_ISSET(sp, O_MAGIC)) { -tilde: ++p; - memcpy(t, sp->repl, sp->repl_len); - t += sp->repl_len; - len += sp->repl_len; - continue; - } - *t++ = *p++; - ++len; - } - if ((sp->repl_len = len) != 0) { - if (sp->repl != NULL) - free(sp->repl); - if ((sp->repl = malloc(len)) == NULL) { - msgq(sp, M_SYSERR, NULL); - FREE_SPACE(sp, bp, blen); - return (1); - } - memcpy(sp->repl, bp, len); - } - FREE_SPACE(sp, bp, blen); - } - return (s(sp, cmdp, p, re, flags)); -} - -/* - * ex_subagain -- - * [line [,line]] & [cgr] [count] [#lp]] - * - * Substitute using the last substitute RE and replacement pattern. - * - * PUBLIC: int ex_subagain __P((SCR *, EXCMD *)); - */ -int -ex_subagain(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - if (sp->subre == NULL) { - ex_emsg(sp, NULL, EXM_NOPREVRE); - return (1); - } - if (!F_ISSET(sp, SC_RE_SUBST) && re_compile(sp, - sp->subre, sp->subre_len, NULL, NULL, &sp->subre_c, RE_C_SUBST)) - return (1); - return (s(sp, - cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL, &sp->subre_c, 0)); -} - -/* - * ex_subtilde -- - * [line [,line]] ~ [cgr] [count] [#lp]] - * - * Substitute using the last RE and last substitute replacement pattern. - * - * PUBLIC: int ex_subtilde __P((SCR *, EXCMD *)); - */ -int -ex_subtilde(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - if (sp->re == NULL) { - ex_emsg(sp, NULL, EXM_NOPREVRE); - return (1); - } - if (!F_ISSET(sp, SC_RE_SEARCH) && re_compile(sp, - sp->re, sp->re_len, NULL, NULL, &sp->re_c, RE_C_SEARCH)) - return (1); - return (s(sp, - cmdp, cmdp->argc ? cmdp->argv[0]->bp : NULL, &sp->re_c, 0)); -} - -/* - * s -- - * Do the substitution. This stuff is *really* tricky. There are lots of - * special cases, and general nastiness. Don't mess with it unless you're - * pretty confident. - * - * The nasty part of the substitution is what happens when the replacement - * string contains newlines. It's a bit tricky -- consider the information - * that has to be retained for "s/f\(o\)o/^M\1^M\1/". The solution here is - * to build a set of newline offsets which we use to break the line up later, - * when the replacement is done. Don't change it unless you're *damned* - * confident. - */ -#define NEEDNEWLINE(sp) { \ - if (sp->newl_len == sp->newl_cnt) { \ - sp->newl_len += 25; \ - REALLOC(sp, sp->newl, size_t *, \ - sp->newl_len * sizeof(size_t)); \ - if (sp->newl == NULL) { \ - sp->newl_len = 0; \ - return (1); \ - } \ - } \ -} - -#define BUILD(sp, l, len) { \ - if (lbclen + (len) > lblen) { \ - lblen += MAX(lbclen + (len), 256); \ - REALLOC(sp, lb, char *, lblen); \ - if (lb == NULL) { \ - lbclen = 0; \ - return (1); \ - } \ - } \ - memcpy(lb + lbclen, l, len); \ - lbclen += len; \ -} - -#define NEEDSP(sp, len, pnt) { \ - if (lbclen + (len) > lblen) { \ - lblen += MAX(lbclen + (len), 256); \ - REALLOC(sp, lb, char *, lblen); \ - if (lb == NULL) { \ - lbclen = 0; \ - return (1); \ - } \ - pnt = lb + lbclen; \ - } \ -} - -static int -s(sp, cmdp, s, re, flags) - SCR *sp; - EXCMD *cmdp; - char *s; - regex_t *re; - u_int flags; -{ - EVENT ev; - MARK from, to; - TEXTH tiq; - recno_t elno, lno, slno; - regmatch_t match[10]; - size_t blen, cnt, last, lbclen, lblen, len, llen; - size_t offset, saved_offset, scno; - int cflag, lflag, nflag, pflag, rflag; - int didsub, do_eol_match, eflags, empty_ok, eval; - int linechanged, matched, quit, rval; - char *bp, *lb; - - NEEDFILE(sp, cmdp); - - slno = sp->lno; - scno = sp->cno; - - /* - * !!! - * Historically, the 'g' and 'c' suffices were always toggled as flags, - * so ":s/A/B/" was the same as ":s/A/B/ccgg". If O_EDCOMPATIBLE was - * not set, they were initialized to 0 for all substitute commands. If - * O_EDCOMPATIBLE was set, they were initialized to 0 only if the user - * specified substitute/replacement patterns (see ex_s()). - */ - if (!O_ISSET(sp, O_EDCOMPATIBLE)) - sp->c_suffix = sp->g_suffix = 0; - - /* - * Historic vi permitted the '#', 'l' and 'p' options in vi mode, but - * it only displayed the last change. I'd disallow them, but they are - * useful in combination with the [v]global commands. In the current - * model the problem is combining them with the 'c' flag -- the screen - * would have to flip back and forth between the confirm screen and the - * ex print screen, which would be pretty awful. We do display all - * changes, though, for what that's worth. - * - * !!! - * Historic vi was fairly strict about the order of "options", the - * count, and "flags". I'm somewhat fuzzy on the difference between - * options and flags, anyway, so this is a simpler approach, and we - * just take it them in whatever order the user gives them. (The ex - * usage statement doesn't reflect this.) - */ - cflag = lflag = nflag = pflag = rflag = 0; - if (s == NULL) - goto noargs; - for (lno = OOBLNO; *s != '\0'; ++s) - switch (*s) { - case ' ': - case '\t': - continue; - case '+': - ++cmdp->flagoff; - break; - case '-': - --cmdp->flagoff; - break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - if (lno != OOBLNO) - goto usage; - errno = 0; - lno = strtoul(s, &s, 10); - if (*s == '\0') /* Loop increment correction. */ - --s; - if (errno == ERANGE) { - if (lno == LONG_MAX) - msgq(sp, M_ERR, "153|Count overflow"); - else if (lno == LONG_MIN) - msgq(sp, M_ERR, "154|Count underflow"); - else - msgq(sp, M_SYSERR, NULL); - return (1); - } - /* - * In historic vi, the count was inclusive from the - * second address. - */ - cmdp->addr1.lno = cmdp->addr2.lno; - cmdp->addr2.lno += lno - 1; - if (!db_exist(sp, cmdp->addr2.lno) && - db_last(sp, &cmdp->addr2.lno)) - return (1); - break; - case '#': - nflag = 1; - break; - case 'c': - sp->c_suffix = !sp->c_suffix; - - /* Ex text structure initialization. */ - if (F_ISSET(sp, SC_EX)) { - memset(&tiq, 0, sizeof(TEXTH)); - CIRCLEQ_INIT(&tiq); - } - break; - case 'g': - sp->g_suffix = !sp->g_suffix; - break; - case 'l': - lflag = 1; - break; - case 'p': - pflag = 1; - break; - case 'r': - if (LF_ISSET(SUB_FIRST)) { - msgq(sp, M_ERR, - "155|Regular expression specified; r flag meaningless"); - return (1); - } - if (!F_ISSET(sp, SC_RE_SEARCH)) { - ex_emsg(sp, NULL, EXM_NOPREVRE); - return (1); - } - rflag = 1; - re = &sp->re_c; - break; - default: - goto usage; - } - - if (*s != '\0' || !rflag && LF_ISSET(SUB_MUSTSETR)) { -usage: ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); - return (1); - } - -noargs: if (F_ISSET(sp, SC_VI) && sp->c_suffix && (lflag || nflag || pflag)) { - msgq(sp, M_ERR, -"156|The #, l and p flags may not be combined with the c flag in vi mode"); - return (1); - } - - /* - * bp: if interactive, line cache - * blen: if interactive, line cache length - * lb: build buffer pointer. - * lbclen: current length of built buffer. - * lblen; length of build buffer. - */ - bp = lb = NULL; - blen = lbclen = lblen = 0; - - /* For each line... */ - for (matched = quit = 0, lno = cmdp->addr1.lno, - elno = cmdp->addr2.lno; !quit && lno <= elno; ++lno) { - - /* Someone's unhappy, time to stop. */ - if (INTERRUPTED(sp)) - break; - - /* Get the line. */ - if (db_get(sp, lno, DBG_FATAL, &s, &llen)) - goto err; - - /* - * Make a local copy if doing confirmation -- when calling - * the confirm routine we're likely to lose the cached copy. - */ - if (sp->c_suffix) { - if (bp == NULL) { - GET_SPACE_RET(sp, bp, blen, llen); - } else - ADD_SPACE_RET(sp, bp, blen, llen); - memcpy(bp, s, llen); - s = bp; - } - - /* Start searching from the beginning. */ - offset = 0; - len = llen; - - /* Reset the build buffer offset. */ - lbclen = 0; - - /* Reset empty match flag. */ - empty_ok = 1; - - /* - * We don't want to have to do a setline if the line didn't - * change -- keep track of whether or not this line changed. - * If doing confirmations, don't want to keep setting the - * line if change is refused -- keep track of substitutions. - */ - didsub = linechanged = 0; - - /* New line, do an EOL match. */ - do_eol_match = 1; - - /* It's not nul terminated, but we pretend it is. */ - eflags = REG_STARTEND; - - /* - * The search area is from s + offset to the EOL. - * - * Generally, match[0].rm_so is the offset of the start - * of the match from the start of the search, and offset - * is the offset of the start of the last search. - */ -nextmatch: match[0].rm_so = 0; - match[0].rm_eo = len; - - /* Get the next match. */ - eval = regexec(re, (char *)s + offset, 10, match, eflags); - - /* - * There wasn't a match or if there was an error, deal with - * it. If there was a previous match in this line, resolve - * the changes into the database. Otherwise, just move on. - */ - if (eval == REG_NOMATCH) - goto endmatch; - if (eval != 0) { - re_error(sp, eval, re); - goto err; - } - matched = 1; - - /* Only the first search can match an anchored expression. */ - eflags |= REG_NOTBOL; - - /* - * !!! - * It's possible to match 0-length strings -- for example, the - * command s;a*;X;, when matched against the string "aabb" will - * result in "XbXbX", i.e. the matches are "aa", the space - * between the b's and the space between the b's and the end of - * the string. There is a similar space between the beginning - * of the string and the a's. The rule that we use (because vi - * historically used it) is that any 0-length match, occurring - * immediately after a match, is ignored. Otherwise, the above - * example would have resulted in "XXbXbX". Another example is - * incorrectly using " *" to replace groups of spaces with one - * space. - * - * The way we do this is that if we just had a successful match, - * the starting offset does not skip characters, and the match - * is empty, ignore the match and move forward. If there's no - * more characters in the string, we were attempting to match - * after the last character, so quit. - */ - if (!empty_ok && match[0].rm_so == 0 && match[0].rm_eo == 0) { - empty_ok = 1; - if (len == 0) - goto endmatch; - BUILD(sp, s + offset, 1) - ++offset; - --len; - goto nextmatch; - } - - /* Confirm change. */ - if (sp->c_suffix) { - /* - * Set the cursor position for confirmation. Note, - * if we matched on a '$', the cursor may be past - * the end of line. - */ - from.lno = to.lno = lno; - from.cno = match[0].rm_so + offset; - to.cno = match[0].rm_eo + offset; - /* - * Both ex and vi have to correct for a change before - * the first character in the line. - */ - if (llen == 0) - from.cno = to.cno = 0; - if (F_ISSET(sp, SC_VI)) { - /* - * Only vi has to correct for a change after - * the last character in the line. - * - * XXX - * It would be nice to change the vi code so - * that we could display a cursor past EOL. - */ - if (to.cno >= llen) - to.cno = llen - 1; - if (from.cno >= llen) - from.cno = llen - 1; - - sp->lno = from.lno; - sp->cno = from.cno; - if (vs_refresh(sp, 1)) - goto err; - - vs_update(sp, msg_cat(sp, - "169|Confirm change? [n]", NULL), NULL); - - if (v_event_get(sp, &ev, 0, 0)) - goto err; - switch (ev.e_event) { - case E_CHARACTER: - break; - case E_EOF: - case E_ERR: - case E_INTERRUPT: - goto lquit; - default: - v_event_err(sp, &ev); - goto lquit; - } - } else { - if (ex_print(sp, cmdp, &from, &to, 0) || - ex_scprint(sp, &from, &to)) - goto lquit; - if (ex_txt(sp, &tiq, 0, TXT_CR)) - goto err; - ev.e_c = tiq.cqh_first->lb[0]; - } - - switch (ev.e_c) { - case CH_YES: - break; - default: - case CH_NO: - didsub = 0; - BUILD(sp, s +offset, match[0].rm_eo); - goto skip; - case CH_QUIT: - /* Set the quit/interrupted flags. */ -lquit: quit = 1; - F_SET(sp->gp, G_INTERRUPTED); - - /* - * Resolve any changes, then return to (and - * exit from) the main loop. - */ - goto endmatch; - } - } - - /* - * Set the cursor to the last position changed, converting - * from 1-based to 0-based. - */ - sp->lno = lno; - sp->cno = match[0].rm_so; - - /* Copy the bytes before the match into the build buffer. */ - BUILD(sp, s + offset, match[0].rm_so); - - /* Substitute the matching bytes. */ - didsub = 1; - if (re_sub(sp, s + offset, &lb, &lbclen, &lblen, match)) - goto err; - - /* Set the change flag so we know this line was modified. */ - linechanged = 1; - - /* Move past the matched bytes. */ -skip: offset += match[0].rm_eo; - len -= match[0].rm_eo; - - /* A match cannot be followed by an empty pattern. */ - empty_ok = 0; - - /* - * If doing a global change with confirmation, we have to - * update the screen. The basic idea is to store the line - * so the screen update routines can find it, and restart. - */ - if (didsub && sp->c_suffix && sp->g_suffix) { - /* - * The new search offset will be the end of the - * modified line. - */ - saved_offset = lbclen; - - /* Copy the rest of the line. */ - if (len) - BUILD(sp, s + offset, len) - - /* Set the new offset. */ - offset = saved_offset; - - /* Store inserted lines, adjusting the build buffer. */ - last = 0; - if (sp->newl_cnt) { - for (cnt = 0; - cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) { - if (db_insert(sp, lno, - lb + last, sp->newl[cnt] - last)) - goto err; - last = sp->newl[cnt] + 1; - ++sp->rptlines[L_ADDED]; - } - lbclen -= last; - offset -= last; - sp->newl_cnt = 0; - } - - /* Store and retrieve the line. */ - if (db_set(sp, lno, lb + last, lbclen)) - goto err; - if (db_get(sp, lno, DBG_FATAL, &s, &llen)) - goto err; - ADD_SPACE_RET(sp, bp, blen, llen) - memcpy(bp, s, llen); - s = bp; - len = llen - offset; - - /* Restart the build. */ - lbclen = 0; - BUILD(sp, s, offset); - - /* - * If we haven't already done the after-the-string - * match, do one. Set REG_NOTEOL so the '$' pattern - * only matches once. - */ - if (!do_eol_match) - goto endmatch; - if (offset == len) { - do_eol_match = 0; - eflags |= REG_NOTEOL; - } - goto nextmatch; - } - - /* - * If it's a global: - * - * If at the end of the string, do a test for the after - * the string match. Set REG_NOTEOL so the '$' pattern - * only matches once. - */ - if (sp->g_suffix && do_eol_match) { - if (len == 0) { - do_eol_match = 0; - eflags |= REG_NOTEOL; - } - goto nextmatch; - } - -endmatch: if (!linechanged) - continue; - - /* Copy any remaining bytes into the build buffer. */ - if (len) - BUILD(sp, s + offset, len) - - /* Store inserted lines, adjusting the build buffer. */ - last = 0; - if (sp->newl_cnt) { - for (cnt = 0; - cnt < sp->newl_cnt; ++cnt, ++lno, ++elno) { - if (db_insert(sp, - lno, lb + last, sp->newl[cnt] - last)) - goto err; - last = sp->newl[cnt] + 1; - ++sp->rptlines[L_ADDED]; - } - lbclen -= last; - sp->newl_cnt = 0; - } - - /* Store the changed line. */ - if (db_set(sp, lno, lb + last, lbclen)) - goto err; - - /* Update changed line counter. */ - if (sp->rptlchange != lno) { - sp->rptlchange = lno; - ++sp->rptlines[L_CHANGED]; - } - - /* - * !!! - * Display as necessary. Historic practice is to only - * display the last line of a line split into multiple - * lines. - */ - if (lflag || nflag || pflag) { - from.lno = to.lno = lno; - from.cno = to.cno = 0; - if (lflag) - (void)ex_print(sp, cmdp, &from, &to, E_C_LIST); - if (nflag) - (void)ex_print(sp, cmdp, &from, &to, E_C_HASH); - if (pflag) - (void)ex_print(sp, cmdp, &from, &to, E_C_PRINT); - } - } - - /* - * !!! - * Historically, vi attempted to leave the cursor at the same place if - * the substitution was done at the current cursor position. Otherwise - * it moved it to the first non-blank of the last line changed. There - * were some problems: for example, :s/$/foo/ with the cursor on the - * last character of the line left the cursor on the last character, or - * the & command with multiple occurrences of the matching string in the - * line usually left the cursor in a fairly random position. - * - * We try to do the same thing, with the exception that if the user is - * doing substitution with confirmation, we move to the last line about - * which the user was consulted, as opposed to the last line that they - * actually changed. This prevents a screen flash if the user doesn't - * change many of the possible lines. - */ - if (!sp->c_suffix && (sp->lno != slno || sp->cno != scno)) { - sp->cno = 0; - (void)nonblank(sp, sp->lno, &sp->cno); - } - - /* - * If not in a global command, and nothing matched, say so. - * Else, if none of the lines displayed, put something up. - */ - rval = 0; - if (!matched) { - if (!F_ISSET(sp, SC_EX_GLOBAL)) { - msgq(sp, M_ERR, "157|No match found"); - goto err; - } - } else if (!lflag && !nflag && !pflag) - F_SET(cmdp, E_AUTOPRINT); - - if (0) { -err: rval = 1; - } - - if (bp != NULL) - FREE_SPACE(sp, bp, blen); - if (lb != NULL) - free(lb); - return (rval); -} - -/* - * re_compile -- - * Compile the RE. - * - * PUBLIC: int re_compile __P((SCR *, - * PUBLIC: char *, size_t, char **, size_t *, regex_t *, u_int)); - */ -int -re_compile(sp, ptrn, plen, ptrnp, lenp, rep, flags) - SCR *sp; - char *ptrn, **ptrnp; - size_t plen, *lenp; - regex_t *rep; - u_int flags; -{ - size_t len; - int reflags, replaced, rval; - char *p; - - /* Set RE flags. */ - reflags = 0; - if (!LF_ISSET(RE_C_CSCOPE | RE_C_TAG)) { - if (O_ISSET(sp, O_EXTENDED)) - reflags |= REG_EXTENDED; - if (O_ISSET(sp, O_IGNORECASE)) - reflags |= REG_ICASE; - if (O_ISSET(sp, O_ICLOWER)) { - for (p = ptrn, len = plen; len > 0; ++p, --len) - if (isupper(*p)) - break; - if (len == 0) - reflags |= REG_ICASE; - } - } - - /* If we're replacing a saved value, clear the old one. */ - if (LF_ISSET(RE_C_SEARCH) && F_ISSET(sp, SC_RE_SEARCH)) { - regfree(&sp->re_c); - F_CLR(sp, SC_RE_SEARCH); - } - if (LF_ISSET(RE_C_SUBST) && F_ISSET(sp, SC_RE_SUBST)) { - regfree(&sp->subre_c); - F_CLR(sp, SC_RE_SUBST); - } - - /* - * If we're saving the string, it's a pattern we haven't seen before, - * so convert the vi-style RE's to POSIX 1003.2 RE's. Save a copy for - * later recompilation. Free any previously saved value. - */ - if (ptrnp != NULL) { - if (LF_ISSET(RE_C_CSCOPE)) { - if (re_cscope_conv(sp, &ptrn, &plen, &replaced)) - return (1); - /* - * XXX - * Currently, the match-any-<blank> expression used in - * re_cscope_conv() requires extended RE's. This may - * not be right or safe. - */ - reflags |= REG_EXTENDED; - } else if (LF_ISSET(RE_C_TAG)) { - if (re_tag_conv(sp, &ptrn, &plen, &replaced)) - return (1); - } else - if (re_conv(sp, &ptrn, &plen, &replaced)) - return (1); - - /* Discard previous pattern. */ - if (*ptrnp != NULL) { - free(*ptrnp); - *ptrnp = NULL; - } - if (lenp != NULL) - *lenp = plen; - - /* - * Copy the string into allocated memory. - * - * XXX - * Regcomp isn't 8-bit clean, so the pattern is nul-terminated - * for now. There's just no other solution. - */ - MALLOC(sp, *ptrnp, char *, plen + 1); - if (*ptrnp != NULL) { - memcpy(*ptrnp, ptrn, plen); - (*ptrnp)[plen] = '\0'; - } - - /* Free up conversion-routine-allocated memory. */ - if (replaced) - FREE_SPACE(sp, ptrn, 0); - - if (*ptrnp == NULL) - return (1); - - ptrn = *ptrnp; - } - - /* - * XXX - * Regcomp isn't 8-bit clean, so we just lost if the pattern - * contained a nul. Bummer! - */ - if ((rval = regcomp(rep, ptrn, /* plen, */ reflags)) != 0) { - if (!LF_ISSET(RE_C_SILENT)) - re_error(sp, rval, rep); - return (1); - } - - if (LF_ISSET(RE_C_SEARCH)) - F_SET(sp, SC_RE_SEARCH); - if (LF_ISSET(RE_C_SUBST)) - F_SET(sp, SC_RE_SUBST); - - return (0); -} - -/* - * re_conv -- - * Convert vi's regular expressions into something that the - * the POSIX 1003.2 RE functions can handle. - * - * There are three conversions we make to make vi's RE's (specifically - * the global, search, and substitute patterns) work with POSIX RE's. - * - * 1: If O_MAGIC is not set, strip backslashes from the magic character - * set (.[*~) that have them, and add them to the ones that don't. - * 2: If O_MAGIC is not set, the string "\~" is replaced with the text - * from the last substitute command's replacement string. If O_MAGIC - * is set, it's the string "~". - * 3: The pattern \<ptrn\> does "word" searches, convert it to use the - * new RE escapes. - * - * !!!/XXX - * This doesn't exactly match the historic behavior of vi because we do - * the ~ substitution before calling the RE engine, so magic characters - * in the replacement string will be expanded by the RE engine, and they - * weren't historically. It's a bug. - */ -static int -re_conv(sp, ptrnp, plenp, replacedp) - SCR *sp; - char **ptrnp; - size_t *plenp; - int *replacedp; -{ - size_t blen, len, needlen; - int magic; - char *bp, *p, *t; - - /* - * First pass through, we figure out how much space we'll need. - * We do it in two passes, on the grounds that most of the time - * the user is doing a search and won't have magic characters. - * That way we can skip most of the memory allocation and copies. - */ - magic = 0; - for (p = *ptrnp, len = *plenp, needlen = 0; len > 0; ++p, --len) - switch (*p) { - case '\\': - if (len > 1) { - --len; - switch (*++p) { - case '<': - magic = 1; - needlen += sizeof(RE_WSTART); - break; - case '>': - magic = 1; - needlen += sizeof(RE_WSTOP); - break; - case '~': - if (!O_ISSET(sp, O_MAGIC)) { - magic = 1; - needlen += sp->repl_len; - } - break; - case '.': - case '[': - case '*': - if (!O_ISSET(sp, O_MAGIC)) { - magic = 1; - needlen += 1; - } - break; - default: - needlen += 2; - } - } else - needlen += 1; - break; - case '~': - if (O_ISSET(sp, O_MAGIC)) { - magic = 1; - needlen += sp->repl_len; - } - break; - case '.': - case '[': - case '*': - if (!O_ISSET(sp, O_MAGIC)) { - magic = 1; - needlen += 2; - } - break; - default: - needlen += 1; - break; - } - - if (!magic) { - *replacedp = 0; - return (0); - } - - /* Get enough memory to hold the final pattern. */ - *replacedp = 1; - GET_SPACE_RET(sp, bp, blen, needlen); - - for (p = *ptrnp, len = *plenp, t = bp; len > 0; ++p, --len) - switch (*p) { - case '\\': - if (len > 1) { - --len; - switch (*++p) { - case '<': - memcpy(t, - RE_WSTART, sizeof(RE_WSTART) - 1); - t += sizeof(RE_WSTART) - 1; - break; - case '>': - memcpy(t, - RE_WSTOP, sizeof(RE_WSTOP) - 1); - t += sizeof(RE_WSTOP) - 1; - break; - case '~': - if (O_ISSET(sp, O_MAGIC)) - *t++ = '~'; - else { - memcpy(t, - sp->repl, sp->repl_len); - t += sp->repl_len; - } - break; - case '.': - case '[': - case '*': - if (O_ISSET(sp, O_MAGIC)) - *t++ = '\\'; - *t++ = *p; - break; - default: - *t++ = '\\'; - *t++ = *p; - } - } else - *t++ = '\\'; - break; - case '~': - if (O_ISSET(sp, O_MAGIC)) { - memcpy(t, sp->repl, sp->repl_len); - t += sp->repl_len; - } else - *t++ = '~'; - break; - case '.': - case '[': - case '*': - if (!O_ISSET(sp, O_MAGIC)) - *t++ = '\\'; - *t++ = *p; - break; - default: - *t++ = *p; - break; - } - - *ptrnp = bp; - *plenp = t - bp; - return (0); -} - -/* - * re_tag_conv -- - * Convert a tags search path into something that the POSIX - * 1003.2 RE functions can handle. - */ -static int -re_tag_conv(sp, ptrnp, plenp, replacedp) - SCR *sp; - char **ptrnp; - size_t *plenp; - int *replacedp; -{ - size_t blen, len; - int lastdollar; - char *bp, *p, *t; - - len = *plenp; - - /* Max memory usage is 2 times the length of the string. */ - *replacedp = 1; - GET_SPACE_RET(sp, bp, blen, len * 2); - - p = *ptrnp; - t = bp; - - /* If the last character is a '/' or '?', we just strip it. */ - if (len > 0 && (p[len - 1] == '/' || p[len - 1] == '?')) - --len; - - /* If the next-to-last or last character is a '$', it's magic. */ - if (len > 0 && p[len - 1] == '$') { - --len; - lastdollar = 1; - } else - lastdollar = 0; - - /* If the first character is a '/' or '?', we just strip it. */ - if (len > 0 && (p[0] == '/' || p[0] == '?')) { - ++p; - --len; - } - - /* If the first or second character is a '^', it's magic. */ - if (p[0] == '^') { - *t++ = *p++; - --len; - } - - /* - * Escape every other magic character we can find, meanwhile stripping - * the backslashes ctags inserts when escaping the search delimiter - * characters. - */ - for (; len > 0; --len) { - if (p[0] == '\\' && (p[1] == '/' || p[1] == '?')) { - ++p; - --len; - } else if (strchr("^.[]$*", p[0])) - *t++ = '\\'; - *t++ = *p++; - } - if (lastdollar) - *t++ = '$'; - - *ptrnp = bp; - *plenp = t - bp; - return (0); -} - -/* - * re_cscope_conv -- - * Convert a cscope search path into something that the POSIX - * 1003.2 RE functions can handle. - */ -static int -re_cscope_conv(sp, ptrnp, plenp, replacedp) - SCR *sp; - char **ptrnp; - size_t *plenp; - int *replacedp; -{ - size_t blen, len, nspaces; - char *bp, *p, *t; - - /* - * Each space in the source line printed by cscope represents an - * arbitrary sequence of spaces, tabs, and comments. - */ -#define CSCOPE_RE_SPACE "([ \t]|/\\*([^*]|\\*/)*\\*/)*" - for (nspaces = 0, p = *ptrnp, len = *plenp; len > 0; ++p, --len) - if (*p == ' ') - ++nspaces; - - /* - * Allocate plenty of space: - * the string, plus potential escaping characters; - * nspaces + 2 copies of CSCOPE_RE_SPACE; - * ^, $, nul terminator characters. - */ - *replacedp = 1; - len = (p - *ptrnp) * 2 + (nspaces + 2) * sizeof(CSCOPE_RE_SPACE) + 3; - GET_SPACE_RET(sp, bp, blen, len); - - p = *ptrnp; - t = bp; - - *t++ = '^'; - memcpy(t, CSCOPE_RE_SPACE, sizeof(CSCOPE_RE_SPACE) - 1); - t += sizeof(CSCOPE_RE_SPACE) - 1; - - for (len = *plenp; len > 0; ++p, --len) - if (*p == ' ') { - memcpy(t, CSCOPE_RE_SPACE, sizeof(CSCOPE_RE_SPACE) - 1); - t += sizeof(CSCOPE_RE_SPACE) - 1; - } else { - if (strchr("\\^.[]$*+?()|{}", *p)) - *t++ = '\\'; - *t++ = *p; - } - - memcpy(t, CSCOPE_RE_SPACE, sizeof(CSCOPE_RE_SPACE) - 1); - t += sizeof(CSCOPE_RE_SPACE) - 1; - *t++ = '$'; - - *ptrnp = bp; - *plenp = t - bp; - return (0); -} - -/* - * re_error -- - * Report a regular expression error. - * - * PUBLIC: void re_error __P((SCR *, int, regex_t *)); - */ -void -re_error(sp, errcode, preg) - SCR *sp; - int errcode; - regex_t *preg; -{ - size_t s; - char *oe; - - s = regerror(errcode, preg, "", 0); - if ((oe = malloc(s)) == NULL) - msgq(sp, M_SYSERR, NULL); - else { - (void)regerror(errcode, preg, oe, s); - msgq(sp, M_ERR, "RE error: %s", oe); - free(oe); - } -} - -/* - * re_sub -- - * Do the substitution for a regular expression. - */ -static int -re_sub(sp, ip, lbp, lbclenp, lblenp, match) - SCR *sp; - char *ip; /* Input line. */ - char **lbp; - size_t *lbclenp, *lblenp; - regmatch_t match[10]; -{ - enum { C_NOTSET, C_LOWER, C_ONELOWER, C_ONEUPPER, C_UPPER } conv; - size_t lbclen, lblen; /* Local copies. */ - size_t mlen; /* Match length. */ - size_t rpl; /* Remaining replacement length. */ - char *rp; /* Replacement pointer. */ - int ch; - int no; /* Match replacement offset. */ - char *p, *t; /* Buffer pointers. */ - char *lb; /* Local copies. */ - - lb = *lbp; /* Get local copies. */ - lbclen = *lbclenp; - lblen = *lblenp; - - /* - * QUOTING NOTE: - * - * There are some special sequences that vi provides in the - * replacement patterns. - * & string the RE matched (\& if nomagic set) - * \# n-th regular subexpression - * \E end \U, \L conversion - * \e end \U, \L conversion - * \l convert the next character to lower-case - * \L convert to lower-case, until \E, \e, or end of replacement - * \u convert the next character to upper-case - * \U convert to upper-case, until \E, \e, or end of replacement - * - * Otherwise, since this is the lowest level of replacement, discard - * all escaping characters. This (hopefully) matches historic practice. - */ -#define OUTCH(ch, nltrans) { \ - CHAR_T __ch = (ch); \ - u_int __value = KEY_VAL(sp, __ch); \ - if (nltrans && (__value == K_CR || __value == K_NL)) { \ - NEEDNEWLINE(sp); \ - sp->newl[sp->newl_cnt++] = lbclen; \ - } else if (conv != C_NOTSET) { \ - switch (conv) { \ - case C_ONELOWER: \ - conv = C_NOTSET; \ - /* FALLTHROUGH */ \ - case C_LOWER: \ - if (isupper(__ch)) \ - __ch = tolower(__ch); \ - break; \ - case C_ONEUPPER: \ - conv = C_NOTSET; \ - /* FALLTHROUGH */ \ - case C_UPPER: \ - if (islower(__ch)) \ - __ch = toupper(__ch); \ - break; \ - default: \ - abort(); \ - } \ - } \ - NEEDSP(sp, 1, p); \ - *p++ = __ch; \ - ++lbclen; \ -} - conv = C_NOTSET; - for (rp = sp->repl, rpl = sp->repl_len, p = lb + lbclen; rpl--;) { - switch (ch = *rp++) { - case '&': - if (O_ISSET(sp, O_MAGIC)) { - no = 0; - goto subzero; - } - break; - case '\\': - if (rpl == 0) - break; - --rpl; - switch (ch = *rp) { - case '&': - ++rp; - if (!O_ISSET(sp, O_MAGIC)) { - no = 0; - goto subzero; - } - break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - no = *rp++ - '0'; -subzero: if (match[no].rm_so == -1 || - match[no].rm_eo == -1) - break; - mlen = match[no].rm_eo - match[no].rm_so; - for (t = ip + match[no].rm_so; mlen--; ++t) - OUTCH(*t, 0); - continue; - case 'e': - case 'E': - ++rp; - conv = C_NOTSET; - continue; - case 'l': - ++rp; - conv = C_ONELOWER; - continue; - case 'L': - ++rp; - conv = C_LOWER; - continue; - case 'u': - ++rp; - conv = C_ONEUPPER; - continue; - case 'U': - ++rp; - conv = C_UPPER; - continue; - default: - ++rp; - break; - } - } - OUTCH(ch, 1); - } - - *lbp = lb; /* Update caller's information. */ - *lbclenp = lbclen; - *lblenp = lblen; - return (0); -} diff --git a/contrib/nvi/ex/ex_tag.c b/contrib/nvi/ex/ex_tag.c deleted file mode 100644 index 461b152..0000000 --- a/contrib/nvi/ex/ex_tag.c +++ /dev/null @@ -1,1324 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * David Hitz of Auspex Systems, Inc. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_tag.c 10.36 (Berkeley) 9/15/96"; -#endif /* not lint */ - -#include <sys/param.h> -#include <sys/types.h> /* XXX: param.h may not have included types.h */ - -#ifdef HAVE_SYS_MMAN_H -#include <sys/mman.h> -#endif - -#include <sys/queue.h> -#include <sys/stat.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" -#include "../vi/vi.h" -#include "tag.h" - -static char *binary_search __P((char *, char *, char *)); -static int compare __P((char *, char *, char *)); -static void ctag_file __P((SCR *, TAGF *, char *, char **, size_t *)); -static int ctag_search __P((SCR *, char *, size_t, char *)); -static int ctag_sfile __P((SCR *, TAGF *, TAGQ *, char *)); -static TAGQ *ctag_slist __P((SCR *, char *)); -static char *linear_search __P((char *, char *, char *)); -static int tag_copy __P((SCR *, TAG *, TAG **)); -static int tag_pop __P((SCR *, TAGQ *, int)); -static int tagf_copy __P((SCR *, TAGF *, TAGF **)); -static int tagf_free __P((SCR *, TAGF *)); -static int tagq_copy __P((SCR *, TAGQ *, TAGQ **)); - -/* - * ex_tag_first -- - * The tag code can be entered from main, e.g., "vi -t tag". - * - * PUBLIC: int ex_tag_first __P((SCR *, char *)); - */ -int -ex_tag_first(sp, tagarg) - SCR *sp; - char *tagarg; -{ - ARGS *ap[2], a; - EXCMD cmd; - - /* Build an argument for the ex :tag command. */ - ex_cinit(&cmd, C_TAG, 0, OOBLNO, OOBLNO, 0, ap); - ex_cadd(&cmd, &a, tagarg, strlen(tagarg)); - - /* - * XXX - * Historic vi went ahead and created a temporary file when it failed - * to find the tag. We match historic practice, but don't distinguish - * between real error and failure to find the tag. - */ - if (ex_tag_push(sp, &cmd)) - return (0); - - /* Display tags in the center of the screen. */ - F_CLR(sp, SC_SCR_TOP); - F_SET(sp, SC_SCR_CENTER); - - return (0); -} - -/* - * ex_tag_push -- ^] - * :tag[!] [string] - * - * Enter a new TAGQ context based on a ctag string. - * - * PUBLIC: int ex_tag_push __P((SCR *, EXCMD *)); - */ -int -ex_tag_push(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - EX_PRIVATE *exp; - FREF *frp; - TAG *rtp; - TAGQ *rtqp, *tqp; - recno_t lno; - size_t cno; - long tl; - int force, istmp; - - exp = EXP(sp); - switch (cmdp->argc) { - case 1: - if (exp->tag_last != NULL) - free(exp->tag_last); - - if ((exp->tag_last = strdup(cmdp->argv[0]->bp)) == NULL) { - msgq(sp, M_SYSERR, NULL); - return (1); - } - - /* Taglength may limit the number of characters. */ - if ((tl = - O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(exp->tag_last) > tl) - exp->tag_last[tl] = '\0'; - break; - case 0: - if (exp->tag_last == NULL) { - msgq(sp, M_ERR, "158|No previous tag entered"); - return (1); - } - break; - default: - abort(); - } - - /* Get the tag information. */ - if ((tqp = ctag_slist(sp, exp->tag_last)) == NULL) - return (1); - - /* - * Allocate all necessary memory before swapping screens. Initialize - * flags so we know what to free. - */ - rtp = NULL; - rtqp = NULL; - if (exp->tq.cqh_first == (void *)&exp->tq) { - /* Initialize the `local context' tag queue structure. */ - CALLOC_GOTO(sp, rtqp, TAGQ *, 1, sizeof(TAGQ)); - CIRCLEQ_INIT(&rtqp->tagq); - - /* Initialize and link in its tag structure. */ - CALLOC_GOTO(sp, rtp, TAG *, 1, sizeof(TAG)); - CIRCLEQ_INSERT_HEAD(&rtqp->tagq, rtp, q); - rtqp->current = rtp; - } - - /* - * Stick the current context information in a convenient place, we're - * about to lose it. Note, if we're called on editor startup, there - * will be no FREF structure. - */ - frp = sp->frp; - lno = sp->lno; - cno = sp->cno; - istmp = frp == NULL || - F_ISSET(frp, FR_TMPFILE) && !F_ISSET(cmdp, E_NEWSCREEN); - - /* Try to switch to the tag. */ - force = FL_ISSET(cmdp->iflags, E_C_FORCE); - if (F_ISSET(cmdp, E_NEWSCREEN)) { - if (ex_tag_Nswitch(sp, tqp->tagq.cqh_first, force)) - goto err; - - /* Everything else gets done in the new screen. */ - sp = sp->nextdisp; - exp = EXP(sp); - } else - if (ex_tag_nswitch(sp, tqp->tagq.cqh_first, force)) - goto err; - - /* - * If this is the first tag, put a `current location' queue entry - * in place, so we can pop all the way back to the current mark. - * Note, it doesn't point to much of anything, it's a placeholder. - */ - if (exp->tq.cqh_first == (void *)&exp->tq) { - CIRCLEQ_INSERT_HEAD(&exp->tq, rtqp, q); - } else - rtqp = exp->tq.cqh_first; - - /* Link the new TAGQ structure into place. */ - CIRCLEQ_INSERT_HEAD(&exp->tq, tqp, q); - - (void)ctag_search(sp, - tqp->current->search, tqp->current->slen, tqp->tag); - - /* - * Move the current context from the temporary save area into the - * right structure. - * - * If we were in a temporary file, we don't have a context to which - * we can return, so just make it be the same as what we're moving - * to. It will be a little odd that ^T doesn't change anything, but - * I don't think it's a big deal. - */ - if (istmp) { - rtqp->current->frp = sp->frp; - rtqp->current->lno = sp->lno; - rtqp->current->cno = sp->cno; - } else { - rtqp->current->frp = frp; - rtqp->current->lno = lno; - rtqp->current->cno = cno; - } - return (0); - -err: -alloc_err: - if (rtqp != NULL) - free(rtqp); - if (rtp != NULL) - free(rtp); - tagq_free(sp, tqp); - return (1); -} - -/* - * ex_tag_next -- - * Switch context to the next TAG. - * - * PUBLIC: int ex_tag_next __P((SCR *, EXCMD *)); - */ -int -ex_tag_next(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - EX_PRIVATE *exp; - TAG *tp; - TAGQ *tqp; - - exp = EXP(sp); - if ((tqp = exp->tq.cqh_first) == (void *)&exp->tq) { - tag_msg(sp, TAG_EMPTY, NULL); - return (1); - } - if ((tp = tqp->current->q.cqe_next) == (void *)&tqp->tagq) { - msgq(sp, M_ERR, "282|Already at the last tag of this group"); - return (1); - } - if (ex_tag_nswitch(sp, tp, FL_ISSET(cmdp->iflags, E_C_FORCE))) - return (1); - tqp->current = tp; - - if (F_ISSET(tqp, TAG_CSCOPE)) - (void)cscope_search(sp, tqp, tp); - else - (void)ctag_search(sp, tp->search, tp->slen, tqp->tag); - return (0); -} - -/* - * ex_tag_prev -- - * Switch context to the next TAG. - * - * PUBLIC: int ex_tag_prev __P((SCR *, EXCMD *)); - */ -int -ex_tag_prev(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - EX_PRIVATE *exp; - TAG *tp; - TAGQ *tqp; - - exp = EXP(sp); - if ((tqp = exp->tq.cqh_first) == (void *)&exp->tq) { - tag_msg(sp, TAG_EMPTY, NULL); - return (0); - } - if ((tp = tqp->current->q.cqe_prev) == (void *)&tqp->tagq) { - msgq(sp, M_ERR, "255|Already at the first tag of this group"); - return (1); - } - if (ex_tag_nswitch(sp, tp, FL_ISSET(cmdp->iflags, E_C_FORCE))) - return (1); - tqp->current = tp; - - if (F_ISSET(tqp, TAG_CSCOPE)) - (void)cscope_search(sp, tqp, tp); - else - (void)ctag_search(sp, tp->search, tp->slen, tqp->tag); - return (0); -} - -/* - * ex_tag_nswitch -- - * Switch context to the specified TAG. - * - * PUBLIC: int ex_tag_nswitch __P((SCR *, TAG *, int)); - */ -int -ex_tag_nswitch(sp, tp, force) - SCR *sp; - TAG *tp; - int force; -{ - /* Get a file structure. */ - if (tp->frp == NULL && (tp->frp = file_add(sp, tp->fname)) == NULL) - return (1); - - /* If not changing files, return, we're done. */ - if (tp->frp == sp->frp) - return (0); - - /* Check for permission to leave. */ - if (file_m1(sp, force, FS_ALL | FS_POSSIBLE)) - return (1); - - /* Initialize the new file. */ - if (file_init(sp, tp->frp, NULL, FS_SETALT)) - return (1); - - /* Display tags in the center of the screen. */ - F_CLR(sp, SC_SCR_TOP); - F_SET(sp, SC_SCR_CENTER); - - /* Switch. */ - F_SET(sp, SC_FSWITCH); - return (0); -} - -/* - * ex_tag_Nswitch -- - * Switch context to the specified TAG in a new screen. - * - * PUBLIC: int ex_tag_Nswitch __P((SCR *, TAG *, int)); - */ -int -ex_tag_Nswitch(sp, tp, force) - SCR *sp; - TAG *tp; - int force; -{ - SCR *new; - - /* Get a file structure. */ - if (tp->frp == NULL && (tp->frp = file_add(sp, tp->fname)) == NULL) - return (1); - - /* Get a new screen. */ - if (screen_init(sp->gp, sp, &new)) - return (1); - if (vs_split(sp, new, 0)) { - (void)file_end(new, new->ep, 1); - (void)screen_end(new); - return (1); - } - - /* Get a backing file. */ - if (tp->frp == sp->frp) { - /* Copy file state. */ - new->ep = sp->ep; - ++new->ep->refcnt; - - new->frp = tp->frp; - new->frp->flags = sp->frp->flags; - } else if (file_init(new, tp->frp, NULL, force)) { - (void)vs_discard(new, NULL); - (void)screen_end(new); - return (1); - } - - /* Create the argument list. */ - new->cargv = new->argv = ex_buildargv(sp, NULL, tp->frp->name); - - /* Display tags in the center of the screen. */ - F_CLR(new, SC_SCR_TOP); - F_SET(new, SC_SCR_CENTER); - - /* Switch. */ - sp->nextdisp = new; - F_SET(sp, SC_SSWITCH); - - return (0); -} - -/* - * ex_tag_pop -- ^T - * :tagp[op][!] [number | file] - * - * Pop to a previous TAGQ context. - * - * PUBLIC: int ex_tag_pop __P((SCR *, EXCMD *)); - */ -int -ex_tag_pop(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - EX_PRIVATE *exp; - TAGQ *tqp, *dtqp; - size_t arglen; - long off; - char *arg, *p, *t; - - /* Check for an empty stack. */ - exp = EXP(sp); - if (exp->tq.cqh_first == (void *)&exp->tq) { - tag_msg(sp, TAG_EMPTY, NULL); - return (1); - } - - /* Find the last TAG structure that we're going to DISCARD! */ - switch (cmdp->argc) { - case 0: /* Pop one tag. */ - dtqp = exp->tq.cqh_first; - break; - case 1: /* Name or number. */ - arg = cmdp->argv[0]->bp; - off = strtol(arg, &p, 10); - if (*p != '\0') - goto filearg; - - /* Number: pop that many queue entries. */ - if (off < 1) - return (0); - for (tqp = exp->tq.cqh_first; - tqp != (void *)&exp->tq && --off > 1; - tqp = tqp->q.cqe_next); - if (tqp == (void *)&exp->tq) { - msgq(sp, M_ERR, - "159|Less than %s entries on the tags stack; use :display t[ags]", - arg); - return (1); - } - dtqp = tqp; - break; - - /* File argument: pop to that queue entry. */ -filearg: arglen = strlen(arg); - for (tqp = exp->tq.cqh_first; - tqp != (void *)&exp->tq; - dtqp = tqp, tqp = tqp->q.cqe_next) { - /* Don't pop to the current file. */ - if (tqp == exp->tq.cqh_first) - continue; - p = tqp->current->frp->name; - if ((t = strrchr(p, '/')) == NULL) - t = p; - else - ++t; - if (!strncmp(arg, t, arglen)) - break; - } - if (tqp == (void *)&exp->tq) { - msgq_str(sp, M_ERR, arg, - "160|No file %s on the tags stack to return to; use :display t[ags]"); - return (1); - } - if (tqp == exp->tq.cqh_first) - return (0); - break; - default: - abort(); - } - - return (tag_pop(sp, dtqp, FL_ISSET(cmdp->iflags, E_C_FORCE))); -} - -/* - * ex_tag_top -- :tagt[op][!] - * Clear the tag stack. - * - * PUBLIC: int ex_tag_top __P((SCR *, EXCMD *)); - */ -int -ex_tag_top(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - EX_PRIVATE *exp; - - exp = EXP(sp); - - /* Check for an empty stack. */ - if (exp->tq.cqh_first == (void *)&exp->tq) { - tag_msg(sp, TAG_EMPTY, NULL); - return (1); - } - - /* Return to the oldest information. */ - return (tag_pop(sp, - exp->tq.cqh_last->q.cqe_prev, FL_ISSET(cmdp->iflags, E_C_FORCE))); -} - -/* - * tag_pop -- - * Pop up to and including the specified TAGQ context. - */ -static int -tag_pop(sp, dtqp, force) - SCR *sp; - TAGQ *dtqp; - int force; -{ - EX_PRIVATE *exp; - TAG *tp; - TAGQ *tqp; - - exp = EXP(sp); - - /* - * Update the cursor from the saved TAG information of the TAG - * structure we're moving to. - */ - tp = dtqp->q.cqe_next->current; - if (tp->frp == sp->frp) { - sp->lno = tp->lno; - sp->cno = tp->cno; - } else { - if (file_m1(sp, force, FS_ALL | FS_POSSIBLE)) - return (1); - - tp->frp->lno = tp->lno; - tp->frp->cno = tp->cno; - F_SET(sp->frp, FR_CURSORSET); - if (file_init(sp, tp->frp, NULL, FS_SETALT)) - return (1); - - F_SET(sp, SC_FSWITCH); - } - - /* Pop entries off the queue up to and including dtqp. */ - do { - tqp = exp->tq.cqh_first; - if (tagq_free(sp, tqp)) - return (0); - } while (tqp != dtqp); - - /* - * If only a single tag left, we've returned to the first tag point, - * and the stack is now empty. - */ - if (exp->tq.cqh_first->q.cqe_next == (void *)&exp->tq) - tagq_free(sp, exp->tq.cqh_first); - - return (0); -} - -/* - * ex_tag_display -- - * Display the list of tags. - * - * PUBLIC: int ex_tag_display __P((SCR *)); - */ -int -ex_tag_display(sp) - SCR *sp; -{ - EX_PRIVATE *exp; - TAG *tp; - TAGQ *tqp; - int cnt; - size_t len; - char *p, *sep; - - exp = EXP(sp); - if ((tqp = exp->tq.cqh_first) == (void *)&exp->tq) { - tag_msg(sp, TAG_EMPTY, NULL); - return (0); - } - - /* - * We give the file name 20 columns and the search string the rest. - * If there's not enough room, we don't do anything special, it's - * not worth the effort, it just makes the display more confusing. - * - * We also assume that characters in file names map 1-1 to printing - * characters. This might not be true, but I don't think it's worth - * fixing. (The obvious fix is to pass the filenames through the - * msg_print function.) - */ -#define L_NAME 30 /* Name. */ -#define L_SLOP 4 /* Leading number plus trailing *. */ -#define L_SPACE 5 /* Spaces after name, before tag. */ -#define L_TAG 20 /* Tag. */ - if (sp->cols <= L_NAME + L_SLOP) { - msgq(sp, M_ERR, "292|Display too small."); - return (0); - } - - /* - * Display the list of tags for each queue entry. The first entry - * is numbered, and the current tag entry has an asterisk appended. - */ - for (cnt = 1, tqp = exp->tq.cqh_first; !INTERRUPTED(sp) && - tqp != (void *)&exp->tq; ++cnt, tqp = tqp->q.cqe_next) - for (tp = tqp->tagq.cqh_first; - tp != (void *)&tqp->tagq; tp = tp->q.cqe_next) { - if (tp == tqp->tagq.cqh_first) - (void)ex_printf(sp, "%2d ", cnt); - else - (void)ex_printf(sp, " "); - p = tp->frp == NULL ? tp->fname : tp->frp->name; - if ((len = strlen(p)) > L_NAME) { - len = len - (L_NAME - 4); - (void)ex_printf(sp, " ... %*.*s", - L_NAME - 4, L_NAME - 4, p + len); - } else - (void)ex_printf(sp, - " %*.*s", L_NAME, L_NAME, p); - if (tqp->current == tp) - (void)ex_printf(sp, "*"); - - if (tp == tqp->tagq.cqh_first && tqp->tag != NULL && - (sp->cols - L_NAME) >= L_TAG + L_SPACE) { - len = strlen(tqp->tag); - if (len > sp->cols - (L_NAME + L_SPACE)) - len = sp->cols - (L_NAME + L_SPACE); - (void)ex_printf(sp, "%s%.*s", - tqp->current == tp ? " " : " ", - (int)len, tqp->tag); - } - (void)ex_printf(sp, "\n"); - } - return (0); -} - -/* - * ex_tag_copy -- - * Copy a screen's tag structures. - * - * PUBLIC: int ex_tag_copy __P((SCR *, SCR *)); - */ -int -ex_tag_copy(orig, sp) - SCR *orig, *sp; -{ - EX_PRIVATE *oexp, *nexp; - TAGQ *aqp, *tqp; - TAG *ap, *tp; - TAGF *atfp, *tfp; - - oexp = EXP(orig); - nexp = EXP(sp); - - /* Copy tag queue and tags stack. */ - for (aqp = oexp->tq.cqh_first; - aqp != (void *)&oexp->tq; aqp = aqp->q.cqe_next) { - if (tagq_copy(sp, aqp, &tqp)) - return (1); - for (ap = aqp->tagq.cqh_first; - ap != (void *)&aqp->tagq; ap = ap->q.cqe_next) { - if (tag_copy(sp, ap, &tp)) - return (1); - /* Set the current pointer. */ - if (aqp->current == ap) - tqp->current = tp; - CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q); - } - CIRCLEQ_INSERT_TAIL(&nexp->tq, tqp, q); - } - - /* Copy list of tag files. */ - for (atfp = oexp->tagfq.tqh_first; - atfp != NULL; atfp = atfp->q.tqe_next) { - if (tagf_copy(sp, atfp, &tfp)) - return (1); - TAILQ_INSERT_TAIL(&nexp->tagfq, tfp, q); - } - - /* Copy the last tag. */ - if (oexp->tag_last != NULL && - (nexp->tag_last = strdup(oexp->tag_last)) == NULL) { - msgq(sp, M_SYSERR, NULL); - return (1); - } - return (0); -} - -/* - * tagf_copy -- - * Copy a TAGF structure and return it in new memory. - */ -static int -tagf_copy(sp, otfp, tfpp) - SCR *sp; - TAGF *otfp, **tfpp; -{ - TAGF *tfp; - - MALLOC_RET(sp, tfp, TAGF *, sizeof(TAGF)); - *tfp = *otfp; - - /* XXX: Allocate as part of the TAGF structure!!! */ - if ((tfp->name = strdup(otfp->name)) == NULL) - return (1); - - *tfpp = tfp; - return (0); -} - -/* - * tagq_copy -- - * Copy a TAGQ structure and return it in new memory. - */ -static int -tagq_copy(sp, otqp, tqpp) - SCR *sp; - TAGQ *otqp, **tqpp; -{ - TAGQ *tqp; - size_t len; - - len = sizeof(TAGQ); - if (otqp->tag != NULL) - len += otqp->tlen + 1; - MALLOC_RET(sp, tqp, TAGQ *, len); - memcpy(tqp, otqp, len); - - CIRCLEQ_INIT(&tqp->tagq); - tqp->current = NULL; - if (otqp->tag != NULL) - tqp->tag = tqp->buf; - - *tqpp = tqp; - return (0); -} - -/* - * tag_copy -- - * Copy a TAG structure and return it in new memory. - */ -static int -tag_copy(sp, otp, tpp) - SCR *sp; - TAG *otp, **tpp; -{ - TAG *tp; - size_t len; - - len = sizeof(TAG); - if (otp->fname != NULL) - len += otp->fnlen + 1; - if (otp->search != NULL) - len += otp->slen + 1; - MALLOC_RET(sp, tp, TAG *, len); - memcpy(tp, otp, len); - - if (otp->fname != NULL) - tp->fname = tp->buf; - if (otp->search != NULL) - tp->search = tp->fname + otp->fnlen + 1; - - *tpp = tp; - return (0); -} - -/* - * tagf_free -- - * Free a TAGF structure. - */ -static int -tagf_free(sp, tfp) - SCR *sp; - TAGF *tfp; -{ - EX_PRIVATE *exp; - - exp = EXP(sp); - TAILQ_REMOVE(&exp->tagfq, tfp, q); - free(tfp->name); - free(tfp); - return (0); -} - -/* - * tagq_free -- - * Free a TAGQ structure (and associated TAG structures). - * - * PUBLIC: int tagq_free __P((SCR *, TAGQ *)); - */ -int -tagq_free(sp, tqp) - SCR *sp; - TAGQ *tqp; -{ - EX_PRIVATE *exp; - TAG *tp; - - exp = EXP(sp); - while ((tp = tqp->tagq.cqh_first) != (void *)&tqp->tagq) { - CIRCLEQ_REMOVE(&tqp->tagq, tp, q); - free(tp); - } - /* - * !!! - * If allocated and then the user failed to switch files, the TAGQ - * structure was never attached to any list. - */ - if (tqp->q.cqe_next != NULL) - CIRCLEQ_REMOVE(&exp->tq, tqp, q); - free(tqp); - return (0); -} - -/* - * tag_msg - * A few common messages. - * - * PUBLIC: void tag_msg __P((SCR *, tagmsg_t, char *)); - */ -void -tag_msg(sp, msg, tag) - SCR *sp; - tagmsg_t msg; - char *tag; -{ - switch (msg) { - case TAG_BADLNO: - msgq_str(sp, M_ERR, tag, - "164|%s: the tag's line number is past the end of the file"); - break; - case TAG_EMPTY: - msgq(sp, M_INFO, "165|The tags stack is empty"); - break; - case TAG_SEARCH: - msgq_str(sp, M_ERR, tag, "166|%s: search pattern not found"); - break; - default: - abort(); - } -} - -/* - * ex_tagf_alloc -- - * Create a new list of ctag files. - * - * PUBLIC: int ex_tagf_alloc __P((SCR *, char *)); - */ -int -ex_tagf_alloc(sp, str) - SCR *sp; - char *str; -{ - EX_PRIVATE *exp; - TAGF *tfp; - size_t len; - char *p, *t; - - /* Free current queue. */ - exp = EXP(sp); - while ((tfp = exp->tagfq.tqh_first) != NULL) - tagf_free(sp, tfp); - - /* Create new queue. */ - for (p = t = str;; ++p) { - if (*p == '\0' || isblank(*p)) { - if ((len = p - t) > 1) { - MALLOC_RET(sp, tfp, TAGF *, sizeof(TAGF)); - MALLOC(sp, tfp->name, char *, len + 1); - if (tfp->name == NULL) { - free(tfp); - return (1); - } - memcpy(tfp->name, t, len); - tfp->name[len] = '\0'; - tfp->flags = 0; - TAILQ_INSERT_TAIL(&exp->tagfq, tfp, q); - } - t = p + 1; - } - if (*p == '\0') - break; - } - return (0); -} - /* Free previous queue. */ -/* - * ex_tag_free -- - * Free the ex tag information. - * - * PUBLIC: int ex_tag_free __P((SCR *)); - */ -int -ex_tag_free(sp) - SCR *sp; -{ - EX_PRIVATE *exp; - TAGF *tfp; - TAGQ *tqp; - - /* Free up tag information. */ - exp = EXP(sp); - while ((tqp = exp->tq.cqh_first) != (void *)&exp->tq) - tagq_free(sp, tqp); - while ((tfp = exp->tagfq.tqh_first) != NULL) - tagf_free(sp, tfp); - if (exp->tag_last != NULL) - free(exp->tag_last); - return (0); -} - -/* - * ctag_search -- - * Search a file for a tag. - */ -static int -ctag_search(sp, search, slen, tag) - SCR *sp; - char *search, *tag; - size_t slen; -{ - MARK m; - char *p; - - /* - * !!! - * The historic tags file format (from a long, long time ago...) - * used a line number, not a search string. I got complaints, so - * people are still using the format. POSIX 1003.2 permits it. - */ - if (isdigit(search[0])) { - m.lno = atoi(search); - if (!db_exist(sp, m.lno)) { - tag_msg(sp, TAG_BADLNO, tag); - return (1); - } - } else { - /* - * Search for the tag; cheap fallback for C functions - * if the name is the same but the arguments have changed. - */ - m.lno = 1; - m.cno = 0; - if (f_search(sp, &m, &m, - search, slen, NULL, SEARCH_FILE | SEARCH_TAG)) - if ((p = strrchr(search, '(')) != NULL) { - slen = p - search; - if (f_search(sp, &m, &m, search, slen, - NULL, SEARCH_FILE | SEARCH_TAG)) - goto notfound; - } else { -notfound: tag_msg(sp, TAG_SEARCH, tag); - return (1); - } - /* - * !!! - * Historically, tags set the search direction if it wasn't - * already set. - */ - if (sp->searchdir == NOTSET) - sp->searchdir = FORWARD; - } - - /* - * !!! - * Tags move to the first non-blank, NOT the search pattern start. - */ - sp->lno = m.lno; - sp->cno = 0; - (void)nonblank(sp, sp->lno, &sp->cno); - return (0); -} - -/* - * ctag_slist -- - * Search the list of tags files for a tag, and return tag queue. - */ -static TAGQ * -ctag_slist(sp, tag) - SCR *sp; - char *tag; -{ - EX_PRIVATE *exp; - TAGF *tfp; - TAGQ *tqp; - size_t len; - int echk; - - exp = EXP(sp); - - /* Allocate and initialize the tag queue structure. */ - len = strlen(tag); - CALLOC_GOTO(sp, tqp, TAGQ *, 1, sizeof(TAGQ) + len + 1); - CIRCLEQ_INIT(&tqp->tagq); - tqp->tag = tqp->buf; - memcpy(tqp->tag, tag, (tqp->tlen = len) + 1); - - /* - * Find the tag, only display missing file messages once, and - * then only if we didn't find the tag. - */ - for (echk = 0, - tfp = exp->tagfq.tqh_first; tfp != NULL; tfp = tfp->q.tqe_next) - if (ctag_sfile(sp, tfp, tqp, tag)) { - echk = 1; - F_SET(tfp, TAGF_ERR); - } else - F_CLR(tfp, TAGF_ERR | TAGF_ERR_WARN); - - /* Check to see if we found anything. */ - if (tqp->tagq.cqh_first == (void *)&tqp->tagq) { - msgq_str(sp, M_ERR, tag, "162|%s: tag not found"); - if (echk) - for (tfp = exp->tagfq.tqh_first; - tfp != NULL; tfp = tfp->q.tqe_next) - if (F_ISSET(tfp, TAGF_ERR) && - !F_ISSET(tfp, TAGF_ERR_WARN)) { - errno = tfp->errnum; - msgq_str(sp, M_SYSERR, tfp->name, "%s"); - F_SET(tfp, TAGF_ERR_WARN); - } - free(tqp); - return (NULL); - } - - tqp->current = tqp->tagq.cqh_first; - return (tqp); - -alloc_err: - return (NULL); -} - -/* - * ctag_sfile -- - * Search a tags file for a tag, adding any found to the tag queue. - */ -static int -ctag_sfile(sp, tfp, tqp, tname) - SCR *sp; - TAGF *tfp; - TAGQ *tqp; - char *tname; -{ - struct stat sb; - TAG *tp; - size_t dlen, nlen, slen; - int fd, i, nf1, nf2; - char *back, *cname, *dname, *front, *map, *name, *p, *search, *t; - - if ((fd = open(tfp->name, O_RDONLY, 0)) < 0) { - tfp->errnum = errno; - return (1); - } - - /* - * XXX - * Some old BSD systems require MAP_FILE as an argument when mapping - * regular files. - */ -#ifndef MAP_FILE -#define MAP_FILE 0 -#endif - /* - * XXX - * We'd like to test if the file is too big to mmap. Since we don't - * know what size or type off_t's or size_t's are, what the largest - * unsigned integral type is, or what random insanity the local C - * compiler will perpetrate, doing the comparison in a portable way - * is flatly impossible. Hope mmap fails if the file is too large. - */ - if (fstat(fd, &sb) != 0 || - (map = mmap(NULL, (size_t)sb.st_size, PROT_READ | PROT_WRITE, - MAP_FILE | MAP_PRIVATE, fd, (off_t)0)) == (caddr_t)-1) { - tfp->errnum = errno; - (void)close(fd); - return (1); - } - - front = map; - back = front + sb.st_size; - front = binary_search(tname, front, back); - front = linear_search(tname, front, back); - if (front == NULL) - goto done; - - /* - * Initialize and link in the tag structure(s). The historic ctags - * file format only permitted a single tag location per tag. The - * obvious extension to permit multiple tags locations per tag is to - * output multiple records in the standard format. Unfortunately, - * this won't work correctly with historic ex/vi implementations, - * because their binary search assumes that there's only one record - * per tag, and so will use a random tag entry if there si more than - * one. This code handles either format. - * - * The tags file is in the following format: - * - * <tag> <filename> <line number> | <pattern> - * - * Figure out how long everything is so we can allocate in one swell - * foop, but discard anything that looks wrong. - */ - for (;;) { - /* Nul-terminate the end of the line. */ - for (p = front; p < back && *p != '\n'; ++p); - if (p == back || *p != '\n') - break; - *p = '\0'; - - /* Update the pointers for the next time. */ - t = p + 1; - p = front; - front = t; - - /* Break the line into tokens. */ - for (i = 0; i < 2 && (t = strsep(&p, "\t ")) != NULL; ++i) - switch (i) { - case 0: /* Tag. */ - cname = t; - break; - case 1: /* Filename. */ - name = t; - nlen = strlen(name); - break; - } - - /* Check for corruption. */ - if (i != 2 || p == NULL || t == NULL) - goto corrupt; - - /* The rest of the string is the search pattern. */ - search = p; - if ((slen = strlen(p)) == 0) { -corrupt: p = msg_print(sp, tname, &nf1); - t = msg_print(sp, tfp->name, &nf2); - msgq(sp, M_ERR, "163|%s: corrupted tag in %s", p, t); - if (nf1) - FREE_SPACE(sp, p, 0); - if (nf2) - FREE_SPACE(sp, t, 0); - continue; - } - - /* Check for passing the last entry. */ - if (strcmp(tname, cname)) - break; - - /* Resolve the file name. */ - ctag_file(sp, tfp, name, &dname, &dlen); - - CALLOC_GOTO(sp, tp, - TAG *, 1, sizeof(TAG) + dlen + 2 + nlen + 1 + slen + 1); - tp->fname = tp->buf; - if (dlen != 0) { - memcpy(tp->fname, dname, dlen); - tp->fname[dlen] = '/'; - ++dlen; - } - memcpy(tp->fname + dlen, name, nlen + 1); - tp->fnlen = dlen + nlen; - tp->search = tp->fname + tp->fnlen + 1; - memcpy(tp->search, search, (tp->slen = slen) + 1); - CIRCLEQ_INSERT_TAIL(&tqp->tagq, tp, q); - } - -alloc_err: -done: if (munmap(map, (size_t)sb.st_size)) - msgq(sp, M_SYSERR, "munmap"); - if (close(fd)) - msgq(sp, M_SYSERR, "close"); - return (0); -} - -/* - * ctag_file -- - * Search for the right path to this file. - */ -static void -ctag_file(sp, tfp, name, dirp, dlenp) - SCR *sp; - TAGF *tfp; - char *name, **dirp; - size_t *dlenp; -{ - struct stat sb; - size_t len; - char *p, buf[MAXPATHLEN]; - - /* - * !!! - * If the tag file path is a relative path, see if it exists. If it - * doesn't, look relative to the tags file path. It's okay for a tag - * file to not exist, and historically, vi simply displayed a "new" - * file. However, if the path exists relative to the tag file, it's - * pretty clear what's happening, so we may as well get it right. - */ - *dlenp = 0; - if (name[0] != '/' && - stat(name, &sb) && (p = strrchr(tfp->name, '/')) != NULL) { - *p = '\0'; - len = snprintf(buf, sizeof(buf), "%s/%s", tfp->name, name); - *p = '/'; - if (stat(buf, &sb) == 0) { - *dirp = tfp->name; - *dlenp = strlen(*dirp); - } - } -} - -/* - * Binary search for "string" in memory between "front" and "back". - * - * This routine is expected to return a pointer to the start of a line at - * *or before* the first word matching "string". Relaxing the constraint - * this way simplifies the algorithm. - * - * Invariants: - * front points to the beginning of a line at or before the first - * matching string. - * - * back points to the beginning of a line at or after the first - * matching line. - * - * Base of the Invariants. - * front = NULL; - * back = EOF; - * - * Advancing the Invariants: - * - * p = first newline after halfway point from front to back. - * - * If the string at "p" is not greater than the string to match, - * p is the new front. Otherwise it is the new back. - * - * Termination: - * - * The definition of the routine allows it return at any point, - * since front is always at or before the line to print. - * - * In fact, it returns when the chosen "p" equals "back". This - * implies that there exists a string is least half as long as - * (back - front), which in turn implies that a linear search will - * be no more expensive than the cost of simply printing a string or two. - * - * Trying to continue with binary search at this point would be - * more trouble than it's worth. - */ -#define EQUAL 0 -#define GREATER 1 -#define LESS (-1) - -#define SKIP_PAST_NEWLINE(p, back) while (p < back && *p++ != '\n'); - -static char * -binary_search(string, front, back) - register char *string, *front, *back; -{ - register char *p; - - p = front + (back - front) / 2; - SKIP_PAST_NEWLINE(p, back); - - while (p != back) { - if (compare(string, p, back) == GREATER) - front = p; - else - back = p; - p = front + (back - front) / 2; - SKIP_PAST_NEWLINE(p, back); - } - return (front); -} - -/* - * Find the first line that starts with string, linearly searching from front - * to back. - * - * Return NULL for no such line. - * - * This routine assumes: - * - * o front points at the first character in a line. - * o front is before or at the first line to be printed. - */ -static char * -linear_search(string, front, back) - char *string, *front, *back; -{ - while (front < back) { - switch (compare(string, front, back)) { - case EQUAL: /* Found it. */ - return (front); - case LESS: /* No such string. */ - return (NULL); - case GREATER: /* Keep going. */ - break; - } - SKIP_PAST_NEWLINE(front, back); - } - return (NULL); -} - -/* - * Return LESS, GREATER, or EQUAL depending on how the string1 compares - * with string2 (s1 ??? s2). - * - * o Matches up to len(s1) are EQUAL. - * o Matches up to len(s2) are GREATER. - * - * The string "s1" is null terminated. The string s2 is '\t', space, (or - * "back") terminated. - * - * !!! - * Reasonably modern ctags programs use tabs as separators, not spaces. - * However, historic programs did use spaces, and, I got complaints. - */ -static int -compare(s1, s2, back) - register char *s1, *s2, *back; -{ - for (; *s1 && s2 < back && (*s2 != '\t' && *s2 != ' '); ++s1, ++s2) - if (*s1 != *s2) - return (*s1 < *s2 ? LESS : GREATER); - return (*s1 ? GREATER : s2 < back && - (*s2 != '\t' && *s2 != ' ') ? LESS : EQUAL); -} diff --git a/contrib/nvi/ex/ex_tcl.c b/contrib/nvi/ex/ex_tcl.c deleted file mode 100644 index 06736a7..0000000 --- a/contrib/nvi/ex/ex_tcl.c +++ /dev/null @@ -1,80 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * Copyright (c) 1995 - * George V. Neville-Neil. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_tcl.c 8.10 (Berkeley) 9/15/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> -#include <termios.h> -#include <unistd.h> - -#include "../common/common.h" - -#ifdef HAVE_TCL_INTERP -#include <tcl.h> -#endif - -/* - * ex_tcl -- :[line [,line]] tcl [command] - * Run a command through the tcl interpreter. - * - * PUBLIC: int ex_tcl __P((SCR*, EXCMD *)); - */ -int -ex_tcl(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ -#ifdef HAVE_TCL_INTERP - CHAR_T *p; - GS *gp; - size_t len; - char buf[128]; - - /* Initialize the interpreter. */ - gp = sp->gp; - if (gp->tcl_interp == NULL && tcl_init(gp)) - return (1); - - /* Skip leading white space. */ - if (cmdp->argc != 0) - for (p = cmdp->argv[0]->bp, - len = cmdp->argv[0]->len; len > 0; --len, ++p) - if (!isblank(*p)) - break; - if (cmdp->argc == 0 || len == 0) { - ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); - return (1); - } - - (void)snprintf(buf, sizeof(buf), - "set viScreenId %d\nset viStartLine %lu\nset viStopLine %lu", - sp->id, cmdp->addr1.lno, cmdp->addr2.lno); - if (Tcl_Eval(gp->tcl_interp, buf) == TCL_OK && - Tcl_Eval(gp->tcl_interp, cmdp->argv[0]->bp) == TCL_OK) - return (0); - - msgq(sp, M_ERR, "Tcl: %s", ((Tcl_Interp *)gp->tcl_interp)->result); - return (1); -#else - msgq(sp, M_ERR, "302|Vi was not loaded with a Tcl interpreter"); - return (1); -#endif /* HAVE_TCL_INTERP */ -} diff --git a/contrib/nvi/ex/ex_txt.c b/contrib/nvi/ex/ex_txt.c deleted file mode 100644 index 2f62ff5..0000000 --- a/contrib/nvi/ex/ex_txt.c +++ /dev/null @@ -1,430 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_txt.c 10.17 (Berkeley) 10/10/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" - -/* - * !!! - * The backslash characters was special when it preceded a newline as part of - * a substitution replacement pattern. For example, the input ":a\<cr>" would - * failed immediately with an error, as the <cr> wasn't part of a substitution - * replacement pattern. This implies a frightening integration of the editor - * and the parser and/or the RE engine. There's no way I'm going to reproduce - * those semantics. - * - * So, if backslashes are special, this code inserts the backslash and the next - * character into the string, without regard for the character or the command - * being entered. Since "\<cr>" was illegal historically (except for the one - * special case), and the command will fail eventually, no historical scripts - * should break (presuming they didn't depend on the failure mode itself or the - * characters remaining when failure occurred. - */ - -static int txt_dent __P((SCR *, TEXT *)); -static void txt_prompt __P((SCR *, TEXT *, ARG_CHAR_T, u_int32_t)); - -/* - * ex_txt -- - * Get lines from the terminal for ex. - * - * PUBLIC: int ex_txt __P((SCR *, TEXTH *, ARG_CHAR_T, u_int32_t)); - */ -int -ex_txt(sp, tiqh, prompt, flags) - SCR *sp; - TEXTH *tiqh; - ARG_CHAR_T prompt; - u_int32_t flags; -{ - EVENT ev; - GS *gp; - TEXT ait, *ntp, *tp; - carat_t carat_st; - size_t cnt; - int rval; - - rval = 0; - - /* - * Get a TEXT structure with some initial buffer space, reusing the - * last one if it's big enough. (All TEXT bookkeeping fields default - * to 0 -- text_init() handles this.) - */ - if (tiqh->cqh_first != (void *)tiqh) { - tp = tiqh->cqh_first; - if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < 32) { - text_lfree(tiqh); - goto newtp; - } - tp->len = 0; - } else { -newtp: if ((tp = text_init(sp, NULL, 0, 32)) == NULL) - goto err; - CIRCLEQ_INSERT_HEAD(tiqh, tp, q); - } - - /* Set the starting line number. */ - tp->lno = sp->lno + 1; - - /* - * If it's a terminal, set up autoindent, put out the prompt, and - * set it up so we know we were suspended. Otherwise, turn off - * the autoindent flag, as that requires less special casing below. - * - * XXX - * Historic practice is that ^Z suspended command mode (but, because - * it ran in cooked mode, it was unaffected by the autowrite option.) - * On restart, any "current" input was discarded, whether in insert - * mode or not, and ex was in command mode. This code matches historic - * practice, but not 'cause it's easier. - */ - gp = sp->gp; - if (F_ISSET(gp, G_SCRIPTED)) - LF_CLR(TXT_AUTOINDENT); - else { - if (LF_ISSET(TXT_AUTOINDENT)) { - LF_SET(TXT_EOFCHAR); - if (v_txt_auto(sp, sp->lno, NULL, 0, tp)) - goto err; - } - txt_prompt(sp, tp, prompt, flags); - } - - for (carat_st = C_NOTSET;;) { - if (v_event_get(sp, &ev, 0, 0)) - goto err; - - /* Deal with all non-character events. */ - switch (ev.e_event) { - case E_CHARACTER: - break; - case E_ERR: - goto err; - case E_REPAINT: - case E_WRESIZE: - continue; - case E_EOF: - rval = 1; - /* FALLTHROUGH */ - case E_INTERRUPT: - /* - * Handle EOF/SIGINT events by discarding partially - * entered text and returning. EOF returns failure, - * E_INTERRUPT returns success. - */ - goto notlast; - default: - v_event_err(sp, &ev); - goto notlast; - } - - /* - * Deal with character events. - * - * Check to see if the character fits into the input buffer. - * (Use tp->len, ignore overwrite and non-printable chars.) - */ - BINC_GOTO(sp, tp->lb, tp->lb_len, tp->len + 1); - - switch (ev.e_value) { - case K_CR: - /* - * !!! - * Historically, <carriage-return>'s in the command - * weren't special, so the ex parser would return an - * unknown command error message. However, if they - * terminated the command if they were in a map. I'm - * pretty sure this still isn't right, but it handles - * what I've seen so far. - */ - if (!F_ISSET(&ev.e_ch, CH_MAPPED)) - goto ins_ch; - /* FALLTHROUGH */ - case K_NL: - /* - * '\' can escape <carriage-return>/<newline>. We - * don't discard the backslash because we need it - * to get the <newline> through the ex parser. - */ - if (LF_ISSET(TXT_BACKSLASH) && - tp->len != 0 && tp->lb[tp->len - 1] == '\\') - goto ins_ch; - - /* - * CR returns from the ex command line. - * - * XXX - * Terminate with a nul, needed by filter. - */ - if (LF_ISSET(TXT_CR)) { - tp->lb[tp->len] = '\0'; - goto done; - } - - /* - * '.' may terminate text input mode; free the current - * TEXT. - */ - if (LF_ISSET(TXT_DOTTERM) && tp->len == tp->ai + 1 && - tp->lb[tp->len - 1] == '.') { -notlast: CIRCLEQ_REMOVE(tiqh, tp, q); - text_free(tp); - goto done; - } - - /* Set up bookkeeping for the new line. */ - if ((ntp = text_init(sp, NULL, 0, 32)) == NULL) - goto err; - ntp->lno = tp->lno + 1; - - /* - * Reset the autoindent line value. 0^D keeps the ai - * line from changing, ^D changes the level, even if - * there were no characters in the old line. Note, if - * using the current tp structure, use the cursor as - * the length, the autoindent characters may have been - * erased. - */ - if (LF_ISSET(TXT_AUTOINDENT)) { - if (carat_st == C_NOCHANGE) { - if (v_txt_auto(sp, - OOBLNO, &ait, ait.ai, ntp)) - goto err; - free(ait.lb); - } else - if (v_txt_auto(sp, - OOBLNO, tp, tp->len, ntp)) - goto err; - carat_st = C_NOTSET; - } - txt_prompt(sp, ntp, prompt, flags); - - /* - * Swap old and new TEXT's, and insert the new TEXT - * into the queue. - */ - tp = ntp; - CIRCLEQ_INSERT_TAIL(tiqh, tp, q); - break; - case K_CARAT: /* Delete autoindent chars. */ - if (tp->len <= tp->ai && LF_ISSET(TXT_AUTOINDENT)) - carat_st = C_CARATSET; - goto ins_ch; - case K_ZERO: /* Delete autoindent chars. */ - if (tp->len <= tp->ai && LF_ISSET(TXT_AUTOINDENT)) - carat_st = C_ZEROSET; - goto ins_ch; - case K_CNTRLD: /* Delete autoindent char. */ - /* - * !!! - * Historically, the ^D command took (but then ignored) - * a count. For simplicity, we don't return it unless - * it's the first character entered. The check for len - * equal to 0 is okay, TXT_AUTOINDENT won't be set. - */ - if (LF_ISSET(TXT_CNTRLD)) { - for (cnt = 0; cnt < tp->len; ++cnt) - if (!isblank(tp->lb[cnt])) - break; - if (cnt == tp->len) { - tp->len = 1; - tp->lb[0] = ev.e_c; - tp->lb[1] = '\0'; - - /* - * Put out a line separator, in case - * the command fails. - */ - (void)putchar('\n'); - goto done; - } - } - - /* - * POSIX 1003.1b-1993, paragraph 7.1.1.9, states that - * the EOF characters are discarded if there are other - * characters to process in the line, i.e. if the EOF - * is not the first character in the line. For this - * reason, historic ex discarded the EOF characters, - * even if occurring in the middle of the input line. - * We match that historic practice. - * - * !!! - * The test for discarding in the middle of the line is - * done in the switch, because the CARAT forms are N+1, - * not N. - * - * !!! - * There's considerable magic to make the terminal code - * return the EOF character at all. See that code for - * details. - */ - if (!LF_ISSET(TXT_AUTOINDENT) || tp->len == 0) - continue; - switch (carat_st) { - case C_CARATSET: /* ^^D */ - if (tp->len > tp->ai + 1) - continue; - - /* Save the ai string for later. */ - ait.lb = NULL; - ait.lb_len = 0; - BINC_GOTO(sp, ait.lb, ait.lb_len, tp->ai); - memcpy(ait.lb, tp->lb, tp->ai); - ait.ai = ait.len = tp->ai; - - carat_st = C_NOCHANGE; - goto leftmargin; - case C_ZEROSET: /* 0^D */ - if (tp->len > tp->ai + 1) - continue; - - carat_st = C_NOTSET; -leftmargin: (void)gp->scr_ex_adjust(sp, EX_TERM_CE); - tp->ai = tp->len = 0; - break; - case C_NOTSET: /* ^D */ - if (tp->len > tp->ai) - continue; - - if (txt_dent(sp, tp)) - goto err; - break; - default: - abort(); - } - - /* Clear and redisplay the line. */ - (void)gp->scr_ex_adjust(sp, EX_TERM_CE); - txt_prompt(sp, tp, prompt, flags); - break; - default: - /* - * See the TXT_BEAUTIFY comment in vi/v_txt_ev.c. - * - * Silently eliminate any iscntrl() character that was - * not already handled specially, except for <tab> and - * <ff>. - */ -ins_ch: if (LF_ISSET(TXT_BEAUTIFY) && iscntrl(ev.e_c) && - ev.e_value != K_FORMFEED && ev.e_value != K_TAB) - break; - - tp->lb[tp->len++] = ev.e_c; - break; - } - } - /* NOTREACHED */ - -done: return (rval); - -err: -alloc_err: - return (1); -} - -/* - * txt_prompt -- - * Display the ex prompt, line number, ai characters. Characters had - * better be printable by the terminal driver, but that's its problem, - * not ours. - */ -static void -txt_prompt(sp, tp, prompt, flags) - SCR *sp; - TEXT *tp; - ARG_CHAR_T prompt; - u_int32_t flags; -{ - /* Display the prompt. */ - if (LF_ISSET(TXT_PROMPT)) - (void)printf("%c", prompt); - - /* Display the line number. */ - if (LF_ISSET(TXT_NUMBER) && O_ISSET(sp, O_NUMBER)) - (void)printf("%6lu ", (u_long)tp->lno); - - /* Print out autoindent string. */ - if (LF_ISSET(TXT_AUTOINDENT)) - (void)printf("%.*s", (int)tp->ai, tp->lb); - (void)fflush(stdout); -} - -/* - * txt_dent -- - * Handle ^D outdents. - * - * Ex version of vi/v_ntext.c:txt_dent(). See that code for the (usual) - * ranting and raving. This is a fair bit simpler as ^T isn't special. - */ -static int -txt_dent(sp, tp) - SCR *sp; - TEXT *tp; -{ - u_long sw, ts; - size_t cno, off, scno, spaces, tabs; - - ts = O_VAL(sp, O_TABSTOP); - sw = O_VAL(sp, O_SHIFTWIDTH); - - /* Get the current screen column. */ - for (off = scno = 0; off < tp->len; ++off) - if (tp->lb[off] == '\t') - scno += COL_OFF(scno, ts); - else - ++scno; - - /* Get the previous shiftwidth column. */ - cno = scno; - scno -= --scno % sw; - - /* - * Since we don't know what comes before the character(s) being - * deleted, we have to resolve the autoindent characters . The - * example is a <tab>, which doesn't take up a full shiftwidth - * number of columns because it's preceded by <space>s. This is - * easy to get if the user sets shiftwidth to a value less than - * tabstop, and then uses ^T to indent, and ^D to outdent. - * - * Count up spaces/tabs needed to get to the target. - */ - for (cno = 0, tabs = 0; cno + COL_OFF(cno, ts) <= scno; ++tabs) - cno += COL_OFF(cno, ts); - spaces = scno - cno; - - /* Make sure there's enough room. */ - BINC_RET(sp, tp->lb, tp->lb_len, tabs + spaces + 1); - - /* Adjust the final ai character count. */ - tp->ai = tabs + spaces; - - /* Enter the replacement characters. */ - for (tp->len = 0; tabs > 0; --tabs) - tp->lb[tp->len++] = '\t'; - for (; spaces > 0; --spaces) - tp->lb[tp->len++] = ' '; - return (0); -} diff --git a/contrib/nvi/ex/ex_undo.c b/contrib/nvi/ex/ex_undo.c deleted file mode 100644 index 0b0b5b2..0000000 --- a/contrib/nvi/ex/ex_undo.c +++ /dev/null @@ -1,77 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_undo.c 10.6 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> - -#include "../common/common.h" - -/* - * ex_undo -- u - * Undo the last change. - * - * PUBLIC: int ex_undo __P((SCR *, EXCMD *)); - */ -int -ex_undo(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - EXF *ep; - MARK m; - - /* - * !!! - * Historic undo always set the previous context mark. - */ - m.lno = sp->lno; - m.cno = sp->cno; - if (mark_set(sp, ABSMARK1, &m, 1)) - return (1); - - /* - * !!! - * Multiple undo isn't available in ex, as there's no '.' command. - * Whether 'u' is undo or redo is toggled each time, unless there - * was a change since the last undo, in which case it's an undo. - */ - ep = sp->ep; - if (!F_ISSET(ep, F_UNDO)) { - F_SET(ep, F_UNDO); - ep->lundo = FORWARD; - } - switch (ep->lundo) { - case BACKWARD: - if (log_forward(sp, &m)) - return (1); - ep->lundo = FORWARD; - break; - case FORWARD: - if (log_backward(sp, &m)) - return (1); - ep->lundo = BACKWARD; - break; - case NOTSET: - abort(); - } - sp->lno = m.lno; - sp->cno = m.cno; - return (0); -} diff --git a/contrib/nvi/ex/ex_usage.c b/contrib/nvi/ex/ex_usage.c deleted file mode 100644 index cddf7a6..0000000 --- a/contrib/nvi/ex/ex_usage.c +++ /dev/null @@ -1,196 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_usage.c 10.13 (Berkeley) 5/3/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" -#include "../vi/vi.h" - -/* - * ex_help -- :help - * Display help message. - * - * PUBLIC: int ex_help __P((SCR *, EXCMD *)); - */ -int -ex_help(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - (void)ex_puts(sp, - "To see the list of vi commands, enter \":viusage<CR>\"\n"); - (void)ex_puts(sp, - "To see the list of ex commands, enter \":exusage<CR>\"\n"); - (void)ex_puts(sp, - "For an ex command usage statement enter \":exusage [cmd]<CR>\"\n"); - (void)ex_puts(sp, - "For a vi key usage statement enter \":viusage [key]<CR>\"\n"); - (void)ex_puts(sp, "To exit, enter \":q!\"\n"); - return (0); -} - -/* - * ex_usage -- :exusage [cmd] - * Display ex usage strings. - * - * PUBLIC: int ex_usage __P((SCR *, EXCMD *)); - */ -int -ex_usage(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - ARGS *ap; - EXCMDLIST const *cp; - int newscreen; - char *name, *p, nb[MAXCMDNAMELEN + 5]; - - switch (cmdp->argc) { - case 1: - ap = cmdp->argv[0]; - if (isupper(ap->bp[0])) { - newscreen = 1; - ap->bp[0] = tolower(ap->bp[0]); - } else - newscreen = 0; - for (cp = cmds; cp->name != NULL && - memcmp(ap->bp, cp->name, ap->len); ++cp); - if (cp->name == NULL || - newscreen && !F_ISSET(cp, E_NEWSCREEN)) { - if (newscreen) - ap->bp[0] = toupper(ap->bp[0]); - (void)ex_printf(sp, "The %.*s command is unknown\n", - (int)ap->len, ap->bp); - } else { - (void)ex_printf(sp, - "Command: %s\n Usage: %s\n", cp->help, cp->usage); - /* - * !!! - * The "visual" command has two modes, one from ex, - * one from the vi colon line. Don't ask. - */ - if (cp != &cmds[C_VISUAL_EX] && - cp != &cmds[C_VISUAL_VI]) - break; - if (cp == &cmds[C_VISUAL_EX]) - cp = &cmds[C_VISUAL_VI]; - else - cp = &cmds[C_VISUAL_EX]; - (void)ex_printf(sp, - "Command: %s\n Usage: %s\n", cp->help, cp->usage); - } - break; - case 0: - for (cp = cmds; cp->name != NULL && !INTERRUPTED(sp); ++cp) { - /* - * The ^D command has an unprintable name. - * - * XXX - * We display both capital and lower-case versions of - * the appropriate commands -- no need to add in extra - * room, they're all short names. - */ - if (cp == &cmds[C_SCROLL]) - name = "^D"; - else if (F_ISSET(cp, E_NEWSCREEN)) { - nb[0] = '['; - nb[1] = toupper(cp->name[0]); - nb[2] = cp->name[0]; - nb[3] = ']'; - for (name = cp->name + 1, - p = nb + 4; (*p++ = *name++) != '\0';); - name = nb; - } else - name = cp->name; - (void)ex_printf(sp, - "%*s: %s\n", MAXCMDNAMELEN, name, cp->help); - } - break; - default: - abort(); - } - return (0); -} - -/* - * ex_viusage -- :viusage [key] - * Display vi usage strings. - * - * PUBLIC: int ex_viusage __P((SCR *, EXCMD *)); - */ -int -ex_viusage(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - GS *gp; - VIKEYS const *kp; - int key; - - gp = sp->gp; - switch (cmdp->argc) { - case 1: - if (cmdp->argv[0]->len != 1) { - ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); - return (1); - } - key = cmdp->argv[0]->bp[0]; - if (key > MAXVIKEY) - goto nokey; - - /* Special case: '[' and ']' commands. */ - if ((key == '[' || key == ']') && cmdp->argv[0]->bp[1] != key) - goto nokey; - - /* Special case: ~ command. */ - if (key == '~' && O_ISSET(sp, O_TILDEOP)) - kp = &tmotion; - else - kp = &vikeys[key]; - - if (kp->usage == NULL) -nokey: (void)ex_printf(sp, - "The %s key has no current meaning\n", - KEY_NAME(sp, key)); - else - (void)ex_printf(sp, - " Key:%s%s\nUsage: %s\n", - isblank(*kp->help) ? "" : " ", kp->help, kp->usage); - break; - case 0: - for (key = 0; key <= MAXVIKEY && !INTERRUPTED(sp); ++key) { - /* Special case: ~ command. */ - if (key == '~' && O_ISSET(sp, O_TILDEOP)) - kp = &tmotion; - else - kp = &vikeys[key]; - if (kp->help != NULL) - (void)ex_printf(sp, "%s\n", kp->help); - } - break; - default: - abort(); - } - return (0); -} diff --git a/contrib/nvi/ex/ex_util.c b/contrib/nvi/ex/ex_util.c deleted file mode 100644 index 6c4772e..0000000 --- a/contrib/nvi/ex/ex_util.c +++ /dev/null @@ -1,234 +0,0 @@ -/*- - * Copyright (c) 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_util.c 10.23 (Berkeley) 6/19/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/stat.h> - -#include <bitstring.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" - -/* - * ex_cinit -- - * Create an EX command structure. - * - * PUBLIC: void ex_cinit __P((EXCMD *, - * PUBLIC: int, int, recno_t, recno_t, int, ARGS **)); - */ -void -ex_cinit(cmdp, cmd_id, naddr, lno1, lno2, force, ap) - EXCMD *cmdp; - int cmd_id, force, naddr; - recno_t lno1, lno2; - ARGS **ap; -{ - memset(cmdp, 0, sizeof(EXCMD)); - cmdp->cmd = &cmds[cmd_id]; - cmdp->addrcnt = naddr; - cmdp->addr1.lno = lno1; - cmdp->addr2.lno = lno2; - cmdp->addr1.cno = cmdp->addr2.cno = 1; - if (force) - cmdp->iflags |= E_C_FORCE; - cmdp->argc = 0; - if ((cmdp->argv = ap) != NULL) - cmdp->argv[0] = NULL; -} - -/* - * ex_cadd -- - * Add an argument to an EX command structure. - * - * PUBLIC: void ex_cadd __P((EXCMD *, ARGS *, char *, size_t)); - */ -void -ex_cadd(cmdp, ap, arg, len) - EXCMD *cmdp; - ARGS *ap; - char *arg; - size_t len; -{ - cmdp->argv[cmdp->argc] = ap; - ap->bp = arg; - ap->len = len; - cmdp->argv[++cmdp->argc] = NULL; -} - -/* - * ex_getline -- - * Return a line from the file. - * - * PUBLIC: int ex_getline __P((SCR *, FILE *, size_t *)); - */ -int -ex_getline(sp, fp, lenp) - SCR *sp; - FILE *fp; - size_t *lenp; -{ - EX_PRIVATE *exp; - size_t off; - int ch; - char *p; - - exp = EXP(sp); - for (errno = 0, off = 0, p = exp->ibp;;) { - if (off >= exp->ibp_len) { - BINC_RET(sp, exp->ibp, exp->ibp_len, off + 1); - p = exp->ibp + off; - } - if ((ch = getc(fp)) == EOF && !feof(fp)) { - if (errno == EINTR) { - errno = 0; - clearerr(fp); - continue; - } - return (1); - } - if (ch == EOF || ch == '\n') { - if (ch == EOF && !off) - return (1); - *lenp = off; - return (0); - } - *p++ = ch; - ++off; - } - /* NOTREACHED */ -} - -/* - * ex_ncheck -- - * Check for more files to edit. - * - * PUBLIC: int ex_ncheck __P((SCR *, int)); - */ -int -ex_ncheck(sp, force) - SCR *sp; - int force; -{ - char **ap; - - /* - * !!! - * Historic practice: quit! or two quit's done in succession - * (where ZZ counts as a quit) didn't check for other files. - */ - if (!force && sp->ccnt != sp->q_ccnt + 1 && - sp->cargv != NULL && sp->cargv[1] != NULL) { - sp->q_ccnt = sp->ccnt; - - for (ap = sp->cargv + 1; *ap != NULL; ++ap); - msgq(sp, M_ERR, - "167|%d more files to edit", (ap - sp->cargv) - 1); - - return (1); - } - return (0); -} - -/* - * ex_init -- - * Init the screen for ex. - * - * PUBLIC: int ex_init __P((SCR *)); - */ -int -ex_init(sp) - SCR *sp; -{ - GS *gp; - - gp = sp->gp; - - if (gp->scr_screen(sp, SC_EX)) - return (1); - (void)gp->scr_attr(sp, SA_ALTERNATE, 0); - - sp->rows = O_VAL(sp, O_LINES); - sp->cols = O_VAL(sp, O_COLUMNS); - - F_CLR(sp, SC_VI); - F_SET(sp, SC_EX | SC_SCR_EX); - return (0); -} - -/* - * ex_emsg -- - * Display a few common ex and vi error messages. - * - * PUBLIC: void ex_emsg __P((SCR *, char *, exm_t)); - */ -void -ex_emsg(sp, p, which) - SCR *sp; - char *p; - exm_t which; -{ - switch (which) { - case EXM_EMPTYBUF: - msgq(sp, M_ERR, "168|Buffer %s is empty", p); - break; - case EXM_FILECOUNT: - msgq_str(sp, M_ERR, p, - "144|%s: expanded into too many file names"); - break; - case EXM_NOCANON: - msgq(sp, M_ERR, - "283|The %s command requires the ex terminal interface", p); - break; - case EXM_NOCANON_F: - msgq(sp, M_ERR, - "272|That form of %s requires the ex terminal interface", - p); - break; - case EXM_NOFILEYET: - if (p == NULL) - msgq(sp, M_ERR, - "274|Command failed, no file read in yet."); - else - msgq(sp, M_ERR, - "173|The %s command requires that a file have already been read in", p); - break; - case EXM_NOPREVBUF: - msgq(sp, M_ERR, "171|No previous buffer to execute"); - break; - case EXM_NOPREVRE: - msgq(sp, M_ERR, "172|No previous regular expression"); - break; - case EXM_NOSUSPEND: - msgq(sp, M_ERR, "230|This screen may not be suspended"); - break; - case EXM_SECURE: - msgq(sp, M_ERR, -"290|The %s command is not supported when the secure edit option is set", p); - break; - case EXM_SECURE_F: - msgq(sp, M_ERR, -"284|That form of %s is not supported when the secure edit option is set", p); - break; - case EXM_USAGE: - msgq(sp, M_ERR, "174|Usage: %s", p); - break; - } -} diff --git a/contrib/nvi/ex/ex_version.c b/contrib/nvi/ex/ex_version.c deleted file mode 100644 index d7363c8..0000000 --- a/contrib/nvi/ex/ex_version.c +++ /dev/null @@ -1,39 +0,0 @@ -/*- - * Copyright (c) 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1991, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_version.c 10.31 (Berkeley) 8/22/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> - -#include "../common/common.h" -#include "version.h" - -/* - * ex_version -- :version - * Display the program version. - * - * PUBLIC: int ex_version __P((SCR *, EXCMD *)); - */ -int -ex_version(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - msgq(sp, M_INFO, VI_VERSION); - return (0); -} diff --git a/contrib/nvi/ex/ex_visual.c b/contrib/nvi/ex/ex_visual.c deleted file mode 100644 index 82e503d..0000000 --- a/contrib/nvi/ex/ex_visual.c +++ /dev/null @@ -1,161 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_visual.c 10.13 (Berkeley) 6/28/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" -#include "../vi/vi.h" - -/* - * ex_visual -- :[line] vi[sual] [^-.+] [window_size] [flags] - * Switch to visual mode. - * - * PUBLIC: int ex_visual __P((SCR *, EXCMD *)); - */ -int -ex_visual(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - SCR *tsp; - size_t len; - int pos; - char buf[256]; - - /* If open option off, disallow visual command. */ - if (!O_ISSET(sp, O_OPEN)) { - msgq(sp, M_ERR, - "175|The visual command requires that the open option be set"); - return (1); - } - - /* Move to the address. */ - sp->lno = cmdp->addr1.lno == 0 ? 1 : cmdp->addr1.lno; - - /* - * Push a command based on the line position flags. If no - * flag specified, the line goes at the top of the screen. - */ - switch (FL_ISSET(cmdp->iflags, - E_C_CARAT | E_C_DASH | E_C_DOT | E_C_PLUS)) { - case E_C_CARAT: - pos = '^'; - break; - case E_C_DASH: - pos = '-'; - break; - case E_C_DOT: - pos = '.'; - break; - case E_C_PLUS: - pos = '+'; - break; - default: - sp->frp->lno = sp->lno; - sp->frp->cno = 0; - (void)nonblank(sp, sp->lno, &sp->cno); - F_SET(sp->frp, FR_CURSORSET); - goto nopush; - } - - if (FL_ISSET(cmdp->iflags, E_C_COUNT)) - len = snprintf(buf, sizeof(buf), - "%luz%c%lu", sp->lno, pos, cmdp->count); - else - len = snprintf(buf, sizeof(buf), "%luz%c", sp->lno, pos); - (void)v_event_push(sp, NULL, buf, len, CH_NOMAP | CH_QUOTED); - - /* - * !!! - * Historically, if no line address was specified, the [p#l] flags - * caused the cursor to be moved to the last line of the file, which - * was then positioned as described above. This seems useless, so - * I haven't implemented it. - */ - switch (FL_ISSET(cmdp->iflags, E_C_HASH | E_C_LIST | E_C_PRINT)) { - case E_C_HASH: - O_SET(sp, O_NUMBER); - break; - case E_C_LIST: - O_SET(sp, O_LIST); - break; - case E_C_PRINT: - break; - } - -nopush: /* - * !!! - * You can call the visual part of the editor from within an ex - * global command. - * - * XXX - * Historically, undoing a visual session was a single undo command, - * i.e. you could undo all of the changes you made in visual mode. - * We don't get this right; I'm waiting for the new logging code to - * be available. - * - * It's explicit, don't have to wait for the user, unless there's - * already a reason to wait. - */ - if (!F_ISSET(sp, SC_SCR_EXWROTE)) - F_SET(sp, SC_EX_WAIT_NO); - - if (F_ISSET(sp, SC_EX_GLOBAL)) { - /* - * When the vi screen(s) exit, we don't want to lose our hold - * on this screen or this file, otherwise we're going to fail - * fairly spectacularly. - */ - ++sp->refcnt; - ++sp->ep->refcnt; - - /* - * Fake up a screen pointer -- vi doesn't get to change our - * underlying file, regardless. - */ - tsp = sp; - if (vi(&tsp)) - return (1); - - /* - * !!! - * Historically, if the user exited the vi screen(s) using an - * ex quit command (e.g. :wq, :q) ex/vi exited, it was only if - * they exited vi using the Q command that ex continued. Some - * early versions of nvi continued in ex regardless, but users - * didn't like the semantic. - * - * Reset the screen. - */ - if (ex_init(sp)) - return (1); - - /* Move out of the vi screen. */ - (void)ex_puts(sp, "\n"); - } else { - F_CLR(sp, SC_EX | SC_SCR_EX); - F_SET(sp, SC_VI); - } - return (0); -} diff --git a/contrib/nvi/ex/ex_write.c b/contrib/nvi/ex/ex_write.c deleted file mode 100644 index b3122e3..0000000 --- a/contrib/nvi/ex/ex_write.c +++ /dev/null @@ -1,375 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_write.c 10.30 (Berkeley) 7/12/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/stat.h> - -#include <bitstring.h> -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../common/common.h" - -enum which {WN, WQ, WRITE, XIT}; -static int exwr __P((SCR *, EXCMD *, enum which)); - -/* - * ex_wn -- :wn[!] [>>] [file] - * Write to a file and switch to the next one. - * - * PUBLIC: int ex_wn __P((SCR *, EXCMD *)); - */ -int -ex_wn(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - if (exwr(sp, cmdp, WN)) - return (1); - if (file_m3(sp, 0)) - return (1); - - /* The file name isn't a new file to edit. */ - cmdp->argc = 0; - - return (ex_next(sp, cmdp)); -} - -/* - * ex_wq -- :wq[!] [>>] [file] - * Write to a file and quit. - * - * PUBLIC: int ex_wq __P((SCR *, EXCMD *)); - */ -int -ex_wq(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - int force; - - if (exwr(sp, cmdp, WQ)) - return (1); - if (file_m3(sp, 0)) - return (1); - - force = FL_ISSET(cmdp->iflags, E_C_FORCE); - - if (ex_ncheck(sp, force)) - return (1); - - F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT); - return (0); -} - -/* - * ex_write -- :write[!] [>>] [file] - * :write [!] [cmd] - * Write to a file. - * - * PUBLIC: int ex_write __P((SCR *, EXCMD *)); - */ -int -ex_write(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - return (exwr(sp, cmdp, WRITE)); -} - - -/* - * ex_xit -- :x[it]! [file] - * Write out any modifications and quit. - * - * PUBLIC: int ex_xit __P((SCR *, EXCMD *)); - */ -int -ex_xit(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - int force; - - NEEDFILE(sp, cmdp); - - if (F_ISSET(sp->ep, F_MODIFIED) && exwr(sp, cmdp, XIT)) - return (1); - if (file_m3(sp, 0)) - return (1); - - force = FL_ISSET(cmdp->iflags, E_C_FORCE); - - if (ex_ncheck(sp, force)) - return (1); - - F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT); - return (0); -} - -/* - * exwr -- - * The guts of the ex write commands. - */ -static int -exwr(sp, cmdp, cmd) - SCR *sp; - EXCMD *cmdp; - enum which cmd; -{ - MARK rm; - int flags; - char *name, *p; - - NEEDFILE(sp, cmdp); - - /* All write commands can have an associated '!'. */ - LF_INIT(FS_POSSIBLE); - if (FL_ISSET(cmdp->iflags, E_C_FORCE)) - LF_SET(FS_FORCE); - - /* Skip any leading whitespace. */ - if (cmdp->argc != 0) - for (p = cmdp->argv[0]->bp; *p != '\0' && isblank(*p); ++p); - - /* If "write !" it's a pipe to a utility. */ - if (cmdp->argc != 0 && cmd == WRITE && *p == '!') { - /* Secure means no shell access. */ - if (O_ISSET(sp, O_SECURE)) { - ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F); - return (1); - } - - /* Expand the argument. */ - for (++p; *p && isblank(*p); ++p); - if (*p == '\0') { - ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE); - return (1); - } - if (argv_exp1(sp, cmdp, p, strlen(p), 1)) - return (1); - - /* - * Historically, vi waited after a write filter even if there - * wasn't any output from the command. People complained when - * nvi waited only if there was output, wanting the visual cue - * that the program hadn't written anything. - */ - F_SET(sp, SC_EX_WAIT_YES); - - /* - * !!! - * Ignore the return cursor position, the cursor doesn't - * move. - */ - if (ex_filter(sp, cmdp, &cmdp->addr1, - &cmdp->addr2, &rm, cmdp->argv[1]->bp, FILTER_WRITE)) - return (1); - - /* Ex terminates with a bang, even if the command fails. */ - if (!F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_EX_SILENT)) - (void)ex_puts(sp, "!\n"); - - return (0); - } - - /* Set the FS_ALL flag if we're writing the entire file. */ - if (cmdp->addr1.lno <= 1 && !db_exist(sp, cmdp->addr2.lno + 1)) - LF_SET(FS_ALL); - - /* If "write >>" it's an append to a file. */ - if (cmdp->argc != 0 && cmd != XIT && p[0] == '>' && p[1] == '>') { - LF_SET(FS_APPEND); - - /* Skip ">>" and whitespace. */ - for (p += 2; *p && isblank(*p); ++p); - } - - /* If no other arguments, just write the file back. */ - if (cmdp->argc == 0 || *p == '\0') - return (file_write(sp, - &cmdp->addr1, &cmdp->addr2, NULL, flags)); - - /* Build an argv so we get an argument count and file expansion. */ - if (argv_exp2(sp, cmdp, p, strlen(p))) - return (1); - - /* - * 0 args: impossible. - * 1 args: impossible (I hope). - * 2 args: read it. - * >2 args: object, too many args. - * - * The 1 args case depends on the argv_sexp() function refusing - * to return success without at least one non-blank character. - */ - switch (cmdp->argc) { - case 0: - case 1: - abort(); - /* NOTREACHED */ - case 2: - name = cmdp->argv[1]->bp; - - /* - * !!! - * Historically, the read and write commands renamed - * "unnamed" files, or, if the file had a name, set - * the alternate file name. - */ - if (F_ISSET(sp->frp, FR_TMPFILE) && - !F_ISSET(sp->frp, FR_EXNAMED)) { - if ((p = v_strdup(sp, - cmdp->argv[1]->bp, cmdp->argv[1]->len)) != NULL) { - free(sp->frp->name); - sp->frp->name = p; - } - /* - * The file has a real name, it's no longer a - * temporary, clear the temporary file flags. - * - * !!! - * If we're writing the whole file, FR_NAMECHANGE - * will be cleared by the write routine -- this is - * historic practice. - */ - F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE); - F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED); - - /* Notify the screen. */ - (void)sp->gp->scr_rename(sp, sp->frp->name, 1); - } else - set_alt_name(sp, name); - break; - default: - ex_emsg(sp, p, EXM_FILECOUNT); - return (1); - } - - return (file_write(sp, &cmdp->addr1, &cmdp->addr2, name, flags)); -} - -/* - * ex_writefp -- - * Write a range of lines to a FILE *. - * - * PUBLIC: int ex_writefp __P((SCR *, - * PUBLIC: char *, FILE *, MARK *, MARK *, u_long *, u_long *, int)); - */ -int -ex_writefp(sp, name, fp, fm, tm, nlno, nch, silent) - SCR *sp; - char *name; - FILE *fp; - MARK *fm, *tm; - u_long *nlno, *nch; - int silent; -{ - struct stat sb; - GS *gp; - u_long ccnt; /* XXX: can't print off_t portably. */ - recno_t fline, tline, lcnt; - size_t len; - int rval; - char *msg, *p; - - gp = sp->gp; - fline = fm->lno; - tline = tm->lno; - - if (nlno != NULL) { - *nch = 0; - *nlno = 0; - } - - /* - * The vi filter code has multiple processes running simultaneously, - * and one of them calls ex_writefp(). The "unsafe" function calls - * in this code are to db_get() and msgq(). Db_get() is safe, see - * the comment in ex_filter.c:ex_filter() for details. We don't call - * msgq if the multiple process bit in the EXF is set. - * - * !!! - * Historic vi permitted files of 0 length to be written. However, - * since the way vi got around dealing with "empty" files was to - * always have a line in the file no matter what, it wrote them as - * files of a single, empty line. We write empty files. - * - * "Alex, I'll take vi trivia for $1000." - */ - ccnt = 0; - lcnt = 0; - msg = "253|Writing..."; - if (tline != 0) - for (; fline <= tline; ++fline, ++lcnt) { - /* Caller has to provide any interrupt message. */ - if ((lcnt + 1) % INTERRUPT_CHECK == 0) { - if (INTERRUPTED(sp)) - break; - if (!silent) { - gp->scr_busy(sp, msg, msg == NULL ? - BUSY_UPDATE : BUSY_ON); - msg = NULL; - } - } - if (db_get(sp, fline, DBG_FATAL, &p, &len)) - goto err; - if (fwrite(p, 1, len, fp) != len) - goto err; - ccnt += len; - if (putc('\n', fp) != '\n') - break; - ++ccnt; - } - - if (fflush(fp)) - goto err; - /* - * XXX - * I don't trust NFS -- check to make sure that we're talking to - * a regular file and sync so that NFS is forced to flush. - */ - if (!fstat(fileno(fp), &sb) && - S_ISREG(sb.st_mode) && fsync(fileno(fp))) - goto err; - - if (fclose(fp)) - goto err; - - rval = 0; - if (0) { -err: if (!F_ISSET(sp->ep, F_MULTILOCK)) - msgq_str(sp, M_SYSERR, name, "%s"); - (void)fclose(fp); - rval = 1; - } - - if (!silent) - gp->scr_busy(sp, NULL, BUSY_OFF); - - /* Report the possibly partial transfer. */ - if (nlno != NULL) { - *nch = ccnt; - *nlno = lcnt; - } - return (rval); -} diff --git a/contrib/nvi/ex/ex_yank.c b/contrib/nvi/ex/ex_yank.c deleted file mode 100644 index 778dc7d..0000000 --- a/contrib/nvi/ex/ex_yank.c +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_yank.c 10.7 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> - -#include "../common/common.h" - -/* - * ex_yank -- :[line [,line]] ya[nk] [buffer] [count] - * Yank the lines into a buffer. - * - * PUBLIC: int ex_yank __P((SCR *, EXCMD *)); - */ -int -ex_yank(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - NEEDFILE(sp, cmdp); - - /* - * !!! - * Historically, yanking lines in ex didn't count toward the - * number-of-lines-yanked report. - */ - return (cut(sp, - FL_ISSET(cmdp->iflags, E_C_BUFFER) ? &cmdp->buffer : NULL, - &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE)); -} diff --git a/contrib/nvi/ex/ex_z.c b/contrib/nvi/ex/ex_z.c deleted file mode 100644 index 41b72ad..0000000 --- a/contrib/nvi/ex/ex_z.c +++ /dev/null @@ -1,150 +0,0 @@ -/*- - * Copyright (c) 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)ex_z.c 10.10 (Berkeley) 3/6/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../common/common.h" - -/* - * ex_z -- :[line] z [^-.+=] [count] [flags] - * Adjust window. - * - * PUBLIC: int ex_z __P((SCR *, EXCMD *)); - */ -int -ex_z(sp, cmdp) - SCR *sp; - EXCMD *cmdp; -{ - MARK abs; - recno_t cnt, equals, lno; - int eofcheck; - - NEEDFILE(sp, cmdp); - - /* - * !!! - * If no count specified, use either two times the size of the - * scrolling region, or the size of the window option. POSIX - * 1003.2 claims that the latter is correct, but historic ex/vi - * documentation and practice appear to use the scrolling region. - * I'm using the window size as it means that the entire screen - * is used instead of losing a line to roundoff. Note, we drop - * a line from the cnt if using the window size to leave room for - * the next ex prompt. - */ - if (FL_ISSET(cmdp->iflags, E_C_COUNT)) - cnt = cmdp->count; - else -#ifdef HISTORIC_PRACTICE - cnt = O_VAL(sp, O_SCROLL) * 2; -#else - cnt = O_VAL(sp, O_WINDOW) - 1; -#endif - - equals = 0; - eofcheck = 0; - lno = cmdp->addr1.lno; - - switch (FL_ISSET(cmdp->iflags, - E_C_CARAT | E_C_DASH | E_C_DOT | E_C_EQUAL | E_C_PLUS)) { - case E_C_CARAT: /* Display cnt * 2 before the line. */ - eofcheck = 1; - if (lno > cnt * 2) - cmdp->addr1.lno = (lno - cnt * 2) + 1; - else - cmdp->addr1.lno = 1; - cmdp->addr2.lno = (cmdp->addr1.lno + cnt) - 1; - break; - case E_C_DASH: /* Line goes at the bottom of the screen. */ - cmdp->addr1.lno = lno > cnt ? (lno - cnt) + 1 : 1; - cmdp->addr2.lno = lno; - break; - case E_C_DOT: /* Line goes in the middle of the screen. */ - /* - * !!! - * Historically, the "middleness" of the line overrode the - * count, so that "3z.19" or "3z.20" would display the first - * 12 lines of the file, i.e. (N - 1) / 2 lines before and - * after the specified line. - */ - eofcheck = 1; - cnt = (cnt - 1) / 2; - cmdp->addr1.lno = lno > cnt ? lno - cnt : 1; - cmdp->addr2.lno = lno + cnt; - - /* - * !!! - * Historically, z. set the absolute cursor mark. - */ - abs.lno = sp->lno; - abs.cno = sp->cno; - (void)mark_set(sp, ABSMARK1, &abs, 1); - break; - case E_C_EQUAL: /* Center with hyphens. */ - /* - * !!! - * Strangeness. The '=' flag is like the '.' flag (see the - * above comment, it applies here as well) but with a special - * little hack. Print out lines of hyphens before and after - * the specified line. Additionally, the cursor remains set - * on that line. - */ - eofcheck = 1; - cnt = (cnt - 1) / 2; - cmdp->addr1.lno = lno > cnt ? lno - cnt : 1; - cmdp->addr2.lno = lno - 1; - if (ex_pr(sp, cmdp)) - return (1); - (void)ex_puts(sp, "----------------------------------------\n"); - cmdp->addr2.lno = cmdp->addr1.lno = equals = lno; - if (ex_pr(sp, cmdp)) - return (1); - (void)ex_puts(sp, "----------------------------------------\n"); - cmdp->addr1.lno = lno + 1; - cmdp->addr2.lno = (lno + cnt) - 1; - break; - default: - /* If no line specified, move to the next one. */ - if (F_ISSET(cmdp, E_ADDR_DEF)) - ++lno; - /* FALLTHROUGH */ - case E_C_PLUS: /* Line goes at the top of the screen. */ - eofcheck = 1; - cmdp->addr1.lno = lno; - cmdp->addr2.lno = (lno + cnt) - 1; - break; - } - - if (eofcheck) { - if (db_last(sp, &lno)) - return (1); - if (cmdp->addr2.lno > lno) - cmdp->addr2.lno = lno; - } - - if (ex_pr(sp, cmdp)) - return (1); - if (equals) - sp->lno = equals; - return (0); -} diff --git a/contrib/nvi/ex/script.h b/contrib/nvi/ex/script.h deleted file mode 100644 index e29f633..0000000 --- a/contrib/nvi/ex/script.h +++ /dev/null @@ -1,23 +0,0 @@ -/*- - * Copyright (c) 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * - * See the LICENSE file for redistribution information. - * - * @(#)script.h 10.2 (Berkeley) 3/6/96 - */ - -struct _script { - pid_t sh_pid; /* Shell pid. */ - int sh_master; /* Master pty fd. */ - int sh_slave; /* Slave pty fd. */ - char *sh_prompt; /* Prompt. */ - size_t sh_prompt_len; /* Prompt length. */ - char sh_name[64]; /* Pty name */ -#ifdef TIOCGWINSZ - struct winsize sh_win; /* Window size. */ -#endif - struct termios sh_term; /* Terminal information. */ -}; diff --git a/contrib/nvi/ex/tag.h b/contrib/nvi/ex/tag.h deleted file mode 100644 index aee3dd2..0000000 --- a/contrib/nvi/ex/tag.h +++ /dev/null @@ -1,107 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * Copyright (c) 1994, 1996 - * Rob Mayoff. All rights reserved. - * - * See the LICENSE file for redistribution information. - * - * @(#)tag.h 10.5 (Berkeley) 5/15/96 - */ - -/* - * Cscope connection information. One of these is maintained per cscope - * connection, linked from the EX_PRIVATE structure. - */ -struct _csc { - LIST_ENTRY(_csc) q; /* Linked list of cscope connections. */ - - char *dname; /* Base directory of this cscope connection. */ - size_t dlen; /* Length of base directory. */ - pid_t pid; /* PID of the connected cscope process. */ - time_t mtime; /* Last modification time of cscope database. */ - - FILE *from_fp; /* from cscope: FILE. */ - int from_fd; /* from cscope: file descriptor. */ - FILE *to_fp; /* to cscope: FILE. */ - int to_fd; /* to cscope: file descriptor. */ - - char **paths; /* Array of search paths for this cscope. */ - char *pbuf; /* Search path buffer. */ - size_t pblen; /* Search path buffer length. */ - - char buf[1]; /* Variable length buffer. */ -}; - -/* - * Tag file information. One of these is maintained per tag file, linked - * from the EXPRIVATE structure. - */ -struct _tagf { /* Tag files. */ - TAILQ_ENTRY(_tagf) q; /* Linked list of tag files. */ - char *name; /* Tag file name. */ - int errnum; /* Errno. */ - -#define TAGF_ERR 0x01 /* Error occurred. */ -#define TAGF_ERR_WARN 0x02 /* Error reported. */ - u_int8_t flags; -}; - -/* - * Tags are structured internally as follows: - * - * +----+ +----+ +----+ +----+ - * | EP | -> | Q1 | <-- | T1 | <-- | T2 | - * +----+ +----+ --> +----+ --> +----+ - * | - * +----+ +----+ - * | Q2 | <-- | T1 | - * +----+ --> +----+ - * | - * +----+ +----+ - * | Q3 | <-- | T1 | - * +----+ --> +----+ - * - * Each Q is a TAGQ, or tag "query", which is the result of one tag or cscope - * command. Each Q references one or more TAG's, or tagged file locations. - * - * tag: put a new Q at the head (^]) - * tagnext: T1 -> T2 inside Q (^N) - * tagprev: T2 -> T1 inside Q (^P) - * tagpop: discard Q (^T) - * tagtop: discard all Q - */ -struct _tag { /* Tag list. */ - CIRCLEQ_ENTRY(_tag) q; /* Linked list of tags. */ - - /* Tag pop/return information. */ - FREF *frp; /* Saved file. */ - recno_t lno; /* Saved line number. */ - size_t cno; /* Saved column number. */ - - char *fname; /* Filename. */ - size_t fnlen; /* Filename length. */ - recno_t slno; /* Search line number. */ - char *search; /* Search string. */ - size_t slen; /* Search string length. */ - - char buf[1]; /* Variable length buffer. */ -}; - -struct _tagq { /* Tag queue. */ - CIRCLEQ_ENTRY(_tagq) q; /* Linked list of tag queues. */ - /* This queue's tag list. */ - CIRCLEQ_HEAD(_tagqh, _tag) tagq; - - TAG *current; /* Current TAG within the queue. */ - - char *tag; /* Tag string. */ - size_t tlen; /* Tag string length. */ - -#define TAG_CSCOPE 0x01 /* Cscope tag. */ - u_int8_t flags; - - char buf[1]; /* Variable length buffer. */ -}; diff --git a/contrib/nvi/ex/version.h b/contrib/nvi/ex/version.h deleted file mode 100644 index 7d657b6..0000000 --- a/contrib/nvi/ex/version.h +++ /dev/null @@ -1,2 +0,0 @@ -#define VI_VERSION \ - "Version 1.79 (10/23/96) The CSRG, University of California, Berkeley." |