1*4db99f40SSevan Janiyan /* $NetBSD: main.c,v 1.28.8.2 2018/06/22 10:08:22 martin Exp $ */
27e81b07cSAndy Kosela
37e81b07cSAndy Kosela /* main.c: This file contains the main control and user-interface routines
47e81b07cSAndy Kosela for the ed line editor. */
57e81b07cSAndy Kosela /*-
67e81b07cSAndy Kosela * Copyright (c) 1993 Andrew Moore, Talke Studio.
77e81b07cSAndy Kosela * All rights reserved.
87e81b07cSAndy Kosela *
97e81b07cSAndy Kosela * Redistribution and use in source and binary forms, with or without
107e81b07cSAndy Kosela * modification, are permitted provided that the following conditions
117e81b07cSAndy Kosela * are met:
127e81b07cSAndy Kosela * 1. Redistributions of source code must retain the above copyright
137e81b07cSAndy Kosela * notice, this list of conditions and the following disclaimer.
147e81b07cSAndy Kosela * 2. Redistributions in binary form must reproduce the above copyright
157e81b07cSAndy Kosela * notice, this list of conditions and the following disclaimer in the
167e81b07cSAndy Kosela * documentation and/or other materials provided with the distribution.
177e81b07cSAndy Kosela *
187e81b07cSAndy Kosela * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
197e81b07cSAndy Kosela * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
207e81b07cSAndy Kosela * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
217e81b07cSAndy Kosela * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
227e81b07cSAndy Kosela * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
237e81b07cSAndy Kosela * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
247e81b07cSAndy Kosela * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
257e81b07cSAndy Kosela * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
267e81b07cSAndy Kosela * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
277e81b07cSAndy Kosela * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
287e81b07cSAndy Kosela * SUCH DAMAGE.
297e81b07cSAndy Kosela */
307e81b07cSAndy Kosela
317e81b07cSAndy Kosela #include <sys/cdefs.h>
327e81b07cSAndy Kosela #ifndef lint
337e81b07cSAndy Kosela __COPYRIGHT(
347e81b07cSAndy Kosela "@(#) Copyright (c) 1993 Andrew Moore, Talke Studio.\
357e81b07cSAndy Kosela All rights reserved.");
367e81b07cSAndy Kosela #endif /* not lint */
377e81b07cSAndy Kosela
387e81b07cSAndy Kosela #ifndef lint
397e81b07cSAndy Kosela #if 0
407e81b07cSAndy Kosela static char *rcsid = "@(#)main.c,v 1.1 1994/02/01 00:34:42 alm Exp";
417e81b07cSAndy Kosela #else
42*4db99f40SSevan Janiyan __RCSID("$NetBSD: main.c,v 1.28.8.2 2018/06/22 10:08:22 martin Exp $");
437e81b07cSAndy Kosela #endif
447e81b07cSAndy Kosela #endif /* not lint */
457e81b07cSAndy Kosela
467e81b07cSAndy Kosela /*
477e81b07cSAndy Kosela * CREDITS
487e81b07cSAndy Kosela *
497e81b07cSAndy Kosela * This program is based on the editor algorithm described in
507e81b07cSAndy Kosela * Brian W. Kernighan and P. J. Plauger's book "Software Tools
517e81b07cSAndy Kosela * in Pascal," Addison-Wesley, 1981.
527e81b07cSAndy Kosela *
537e81b07cSAndy Kosela * The buffering algorithm is attributed to Rodney Ruddock of
547e81b07cSAndy Kosela * the University of Guelph, Guelph, Ontario.
557e81b07cSAndy Kosela *
567e81b07cSAndy Kosela * The cbc.c encryption code is adapted from
577e81b07cSAndy Kosela * the bdes program by Matt Bishop of Dartmouth College,
587e81b07cSAndy Kosela * Hanover, NH.
597e81b07cSAndy Kosela *
607e81b07cSAndy Kosela */
617e81b07cSAndy Kosela
627e81b07cSAndy Kosela #include <sys/ioctl.h>
637e81b07cSAndy Kosela #include <sys/wait.h>
647e81b07cSAndy Kosela #include <termios.h>
657e81b07cSAndy Kosela #include <ctype.h>
667e81b07cSAndy Kosela #include <setjmp.h>
677e81b07cSAndy Kosela #include <pwd.h>
687e81b07cSAndy Kosela
697e81b07cSAndy Kosela #include "ed.h"
707e81b07cSAndy Kosela
717e81b07cSAndy Kosela
727e81b07cSAndy Kosela #ifdef _POSIX_SOURCE
737e81b07cSAndy Kosela sigjmp_buf env;
747e81b07cSAndy Kosela #else
757e81b07cSAndy Kosela jmp_buf env;
767e81b07cSAndy Kosela #endif
777e81b07cSAndy Kosela
787e81b07cSAndy Kosela /* static buffers */
797e81b07cSAndy Kosela char stdinbuf[1]; /* stdin buffer */
807e81b07cSAndy Kosela char *shcmd; /* shell command buffer */
817e81b07cSAndy Kosela int shcmdsz; /* shell command buffer size */
827e81b07cSAndy Kosela int shcmdi; /* shell command buffer index */
837e81b07cSAndy Kosela char *ibuf; /* ed command-line buffer */
847e81b07cSAndy Kosela int ibufsz; /* ed command-line buffer size */
857e81b07cSAndy Kosela char *ibufp; /* pointer to ed command-line buffer */
867e81b07cSAndy Kosela
877e81b07cSAndy Kosela /* global flags */
887e81b07cSAndy Kosela int des = 0; /* if set, use crypt(3) for i/o */
897e81b07cSAndy Kosela int garrulous = 0; /* if set, print all error messages */
907e81b07cSAndy Kosela int isbinary; /* if set, buffer contains ASCII NULs */
917e81b07cSAndy Kosela int isglobal; /* if set, doing a global command */
927e81b07cSAndy Kosela int modified; /* if set, buffer modified since last write */
937e81b07cSAndy Kosela int mutex = 0; /* if set, signals set "sigflags" */
947e81b07cSAndy Kosela int red = 0; /* if set, restrict shell/directory access */
957e81b07cSAndy Kosela int ere = 0; /* if set, use extended regexes */
967e81b07cSAndy Kosela int scripted = 0; /* if set, suppress diagnostics */
97*4db99f40SSevan Janiyan int secure = 0; /* is set, ! is not allowed */
987e81b07cSAndy Kosela int sigflags = 0; /* if set, signals received while mutex set */
997e81b07cSAndy Kosela int sigactive = 0; /* if set, signal handlers are enabled */
1007e81b07cSAndy Kosela
1017e81b07cSAndy Kosela char old_filename[MAXPATHLEN + 1] = ""; /* default filename */
1027e81b07cSAndy Kosela long current_addr; /* current address in editor buffer */
1037e81b07cSAndy Kosela long addr_last; /* last address in editor buffer */
1047e81b07cSAndy Kosela int lineno; /* script line number */
1057e81b07cSAndy Kosela const char *prompt; /* command-line prompt */
1067e81b07cSAndy Kosela const char *dps = "*"; /* default command-line prompt */
1077e81b07cSAndy Kosela
1087e81b07cSAndy Kosela
109*4db99f40SSevan Janiyan static const char usage[] = "Usage: %s [-] [-ESsx] [-p string] [name]\n";
1107e81b07cSAndy Kosela
1117e81b07cSAndy Kosela /* ed: line editor */
1127e81b07cSAndy Kosela int
main(int ac,char * av[])1137e81b07cSAndy Kosela main(int ac, char *av[])
1147e81b07cSAndy Kosela {
1157e81b07cSAndy Kosela int c, n;
1167e81b07cSAndy Kosela long status = 0;
1177e81b07cSAndy Kosela volatile int argc = ac;
1187e81b07cSAndy Kosela char ** volatile argv = av;
1197e81b07cSAndy Kosela
1207e81b07cSAndy Kosela red = (n = strlen(argv[0])) > 2 && argv[0][n - 3] == 'r';
1217e81b07cSAndy Kosela top:
122*4db99f40SSevan Janiyan while ((c = getopt(argc, argv, "p:sxES")) != -1)
1237e81b07cSAndy Kosela switch(c) {
1247e81b07cSAndy Kosela case 'p': /* set prompt */
1257e81b07cSAndy Kosela prompt = optarg;
1267e81b07cSAndy Kosela break;
1277e81b07cSAndy Kosela case 's': /* run script */
1287e81b07cSAndy Kosela scripted = 1;
1297e81b07cSAndy Kosela break;
1307e81b07cSAndy Kosela case 'x': /* use crypt */
1317e81b07cSAndy Kosela #ifdef DES
1327e81b07cSAndy Kosela des = get_keyword();
1337e81b07cSAndy Kosela #else
1347e81b07cSAndy Kosela fprintf(stderr, "crypt unavailable\n?\n");
1357e81b07cSAndy Kosela #endif
1367e81b07cSAndy Kosela break;
1377e81b07cSAndy Kosela
1387e81b07cSAndy Kosela case 'E':
1397e81b07cSAndy Kosela ere = REG_EXTENDED;
1407e81b07cSAndy Kosela break;
141*4db99f40SSevan Janiyan case 'S': /* ! is not allowed */
142*4db99f40SSevan Janiyan secure = 1;
143*4db99f40SSevan Janiyan break;
1447e81b07cSAndy Kosela default:
1457e81b07cSAndy Kosela fprintf(stderr, usage, getprogname());
1467e81b07cSAndy Kosela exit(1);
1477e81b07cSAndy Kosela /* NOTREACHED */
1487e81b07cSAndy Kosela }
1497e81b07cSAndy Kosela argv += optind;
1507e81b07cSAndy Kosela argc -= optind;
1517e81b07cSAndy Kosela if (argc && **argv == '-') {
1527e81b07cSAndy Kosela scripted = 1;
1537e81b07cSAndy Kosela if (argc > 1) {
1547e81b07cSAndy Kosela optind = 1;
1557e81b07cSAndy Kosela goto top;
1567e81b07cSAndy Kosela }
1577e81b07cSAndy Kosela argv++;
1587e81b07cSAndy Kosela argc--;
1597e81b07cSAndy Kosela }
1607e81b07cSAndy Kosela /* assert: reliable signals! */
1617e81b07cSAndy Kosela #ifdef SIGWINCH
1627e81b07cSAndy Kosela handle_winch(SIGWINCH);
1637e81b07cSAndy Kosela if (isatty(0)) signal(SIGWINCH, handle_winch);
1647e81b07cSAndy Kosela #endif
1657e81b07cSAndy Kosela signal(SIGHUP, signal_hup);
1667e81b07cSAndy Kosela signal(SIGQUIT, SIG_IGN);
1677e81b07cSAndy Kosela signal(SIGINT, signal_int);
1687e81b07cSAndy Kosela #ifdef _POSIX_SOURCE
1697e81b07cSAndy Kosela if ((status = sigsetjmp(env, 1)) != 0)
1707e81b07cSAndy Kosela #else
1717e81b07cSAndy Kosela if ((status = setjmp(env)) != 0)
1727e81b07cSAndy Kosela #endif
1737e81b07cSAndy Kosela {
1747e81b07cSAndy Kosela fputs("\n?\n", stderr);
1750a6a1f1dSLionel Sambuc seterrmsg("interrupt");
1767e81b07cSAndy Kosela } else {
1777e81b07cSAndy Kosela init_buffers();
1787e81b07cSAndy Kosela sigactive = 1; /* enable signal handlers */
1797e81b07cSAndy Kosela if (argc && **argv && is_legal_filename(*argv)) {
1807e81b07cSAndy Kosela if (read_file(*argv, 0) < 0 && !isatty(0))
1817e81b07cSAndy Kosela quit(2);
1827e81b07cSAndy Kosela else if (**argv != '!')
1837e81b07cSAndy Kosela strlcpy(old_filename, *argv,
1847e81b07cSAndy Kosela sizeof(old_filename) - 2);
1857e81b07cSAndy Kosela } else if (argc) {
1867e81b07cSAndy Kosela fputs("?\n", stderr);
1877e81b07cSAndy Kosela if (**argv == '\0')
1880a6a1f1dSLionel Sambuc seterrmsg("invalid filename");
1897e81b07cSAndy Kosela if (!isatty(0))
1907e81b07cSAndy Kosela quit(2);
1917e81b07cSAndy Kosela }
1927e81b07cSAndy Kosela }
1937e81b07cSAndy Kosela for (;;) {
1947e81b07cSAndy Kosela if (status < 0 && garrulous)
1957e81b07cSAndy Kosela fprintf(stderr, "%s\n", errmsg);
1967e81b07cSAndy Kosela if (prompt) {
1977e81b07cSAndy Kosela printf("%s", prompt);
1987e81b07cSAndy Kosela fflush(stdout);
1997e81b07cSAndy Kosela }
2007e81b07cSAndy Kosela if ((n = get_tty_line()) < 0) {
2017e81b07cSAndy Kosela status = ERR;
2027e81b07cSAndy Kosela continue;
2037e81b07cSAndy Kosela } else if (n == 0) {
2047e81b07cSAndy Kosela if (modified && !scripted) {
2057e81b07cSAndy Kosela fputs("?\n", stderr);
2060a6a1f1dSLionel Sambuc seterrmsg("warning: file modified");
2077e81b07cSAndy Kosela if (!isatty(0)) {
2087e81b07cSAndy Kosela if (garrulous) {
2097e81b07cSAndy Kosela fprintf(stderr,
2107e81b07cSAndy Kosela "script, line %d: %s\n",
2117e81b07cSAndy Kosela lineno, errmsg);
2127e81b07cSAndy Kosela }
2137e81b07cSAndy Kosela quit(2);
2147e81b07cSAndy Kosela }
2157e81b07cSAndy Kosela clearerr(stdin);
2167e81b07cSAndy Kosela modified = 0;
2177e81b07cSAndy Kosela status = EMOD;
2187e81b07cSAndy Kosela continue;
2197e81b07cSAndy Kosela } else
2207e81b07cSAndy Kosela quit(0);
2217e81b07cSAndy Kosela } else if (ibuf[n - 1] != '\n') {
2227e81b07cSAndy Kosela /* discard line */
2230a6a1f1dSLionel Sambuc seterrmsg("unexpected end-of-file");
2247e81b07cSAndy Kosela clearerr(stdin);
2257e81b07cSAndy Kosela status = ERR;
2267e81b07cSAndy Kosela continue;
2277e81b07cSAndy Kosela }
2287e81b07cSAndy Kosela isglobal = 0;
2297e81b07cSAndy Kosela if ((status = extract_addr_range()) >= 0 &&
230*4db99f40SSevan Janiyan (status = exec_command()) >= 0) {
231*4db99f40SSevan Janiyan if (status == 0)
2327e81b07cSAndy Kosela continue;
233*4db99f40SSevan Janiyan status = display_lines(current_addr, current_addr,
234*4db99f40SSevan Janiyan status);
235*4db99f40SSevan Janiyan if (status >= 0)
236*4db99f40SSevan Janiyan continue;
237*4db99f40SSevan Janiyan }
2387e81b07cSAndy Kosela switch (status) {
2397e81b07cSAndy Kosela case EOF:
2407e81b07cSAndy Kosela quit(0);
2417e81b07cSAndy Kosela case EMOD:
2427e81b07cSAndy Kosela modified = 0;
2437e81b07cSAndy Kosela fputs("?\n", stderr); /* give warning */
2440a6a1f1dSLionel Sambuc seterrmsg("warning: file modified");
2457e81b07cSAndy Kosela if (!isatty(0)) {
2467e81b07cSAndy Kosela if (garrulous) {
2477e81b07cSAndy Kosela fprintf(stderr,
2487e81b07cSAndy Kosela "script, line %d: %s\n",
2497e81b07cSAndy Kosela lineno, errmsg);
2507e81b07cSAndy Kosela }
2517e81b07cSAndy Kosela quit(2);
2527e81b07cSAndy Kosela }
2537e81b07cSAndy Kosela break;
2547e81b07cSAndy Kosela case FATAL:
2557e81b07cSAndy Kosela if (garrulous) {
2567e81b07cSAndy Kosela if (!isatty(0)) {
2577e81b07cSAndy Kosela fprintf(stderr,
2587e81b07cSAndy Kosela "script, line %d: %s\n",
2597e81b07cSAndy Kosela lineno, errmsg);
2607e81b07cSAndy Kosela } else {
2617e81b07cSAndy Kosela fprintf(stderr, "%s\n", errmsg);
2627e81b07cSAndy Kosela }
2637e81b07cSAndy Kosela }
2647e81b07cSAndy Kosela quit(3);
2657e81b07cSAndy Kosela default:
2667e81b07cSAndy Kosela fputs("?\n", stderr);
2677e81b07cSAndy Kosela if (!isatty(0)) {
2687e81b07cSAndy Kosela if (garrulous) {
2697e81b07cSAndy Kosela fprintf(stderr, "script, line %d: %s\n",
2707e81b07cSAndy Kosela lineno, errmsg);
2717e81b07cSAndy Kosela }
2727e81b07cSAndy Kosela quit(2);
2737e81b07cSAndy Kosela }
2747e81b07cSAndy Kosela break;
2757e81b07cSAndy Kosela }
2767e81b07cSAndy Kosela }
2777e81b07cSAndy Kosela /* NOTREACHED */
2787e81b07cSAndy Kosela }
2797e81b07cSAndy Kosela
2807e81b07cSAndy Kosela long first_addr, second_addr, addr_cnt;
2817e81b07cSAndy Kosela
2827e81b07cSAndy Kosela /* extract_addr_range: get line addresses from the command buffer until an
2837e81b07cSAndy Kosela illegal address is seen; return status */
2847e81b07cSAndy Kosela int
extract_addr_range(void)2857e81b07cSAndy Kosela extract_addr_range(void)
2867e81b07cSAndy Kosela {
2877e81b07cSAndy Kosela long addr;
2887e81b07cSAndy Kosela
2897e81b07cSAndy Kosela addr_cnt = 0;
2907e81b07cSAndy Kosela first_addr = second_addr = current_addr;
2917e81b07cSAndy Kosela while ((addr = next_addr()) >= 0) {
2927e81b07cSAndy Kosela addr_cnt++;
2937e81b07cSAndy Kosela first_addr = second_addr;
2947e81b07cSAndy Kosela second_addr = addr;
2957e81b07cSAndy Kosela if (*ibufp != ',' && *ibufp != ';')
2967e81b07cSAndy Kosela break;
2977e81b07cSAndy Kosela else if (*ibufp++ == ';')
2987e81b07cSAndy Kosela current_addr = addr;
2997e81b07cSAndy Kosela }
3007e81b07cSAndy Kosela if ((addr_cnt = min(addr_cnt, 2)) == 1 || second_addr != addr)
3017e81b07cSAndy Kosela first_addr = second_addr;
3027e81b07cSAndy Kosela return (addr == ERR) ? ERR : 0;
3037e81b07cSAndy Kosela }
3047e81b07cSAndy Kosela
3057e81b07cSAndy Kosela
3067e81b07cSAndy Kosela #define SKIP_BLANKS() while (isspace((unsigned char)*ibufp) && *ibufp != '\n') \
3077e81b07cSAndy Kosela ibufp++
3087e81b07cSAndy Kosela
3097e81b07cSAndy Kosela #define MUST_BE_FIRST() \
3100a6a1f1dSLionel Sambuc if (!first) { seterrmsg("invalid address"); return ERR; }
3117e81b07cSAndy Kosela
3127e81b07cSAndy Kosela /* next_addr: return the next line address in the command buffer */
3137e81b07cSAndy Kosela long
next_addr(void)3147e81b07cSAndy Kosela next_addr(void)
3157e81b07cSAndy Kosela {
3167e81b07cSAndy Kosela char *hd;
3177e81b07cSAndy Kosela long addr = current_addr;
3187e81b07cSAndy Kosela long n;
3197e81b07cSAndy Kosela int first = 1;
3207e81b07cSAndy Kosela int c;
3217e81b07cSAndy Kosela
3227e81b07cSAndy Kosela SKIP_BLANKS();
3237e81b07cSAndy Kosela for (hd = ibufp;; first = 0)
3247e81b07cSAndy Kosela switch (c = *ibufp) {
3257e81b07cSAndy Kosela case '+':
3267e81b07cSAndy Kosela case '\t':
3277e81b07cSAndy Kosela case ' ':
3287e81b07cSAndy Kosela case '-':
3297e81b07cSAndy Kosela case '^':
3307e81b07cSAndy Kosela ibufp++;
3317e81b07cSAndy Kosela SKIP_BLANKS();
3327e81b07cSAndy Kosela if (isdigit((unsigned char)*ibufp)) {
3337e81b07cSAndy Kosela STRTOL(n, ibufp);
3347e81b07cSAndy Kosela addr += (c == '-' || c == '^') ? -n : n;
3357e81b07cSAndy Kosela } else if (!isspace((unsigned char)c))
3367e81b07cSAndy Kosela addr += (c == '-' || c == '^') ? -1 : 1;
3377e81b07cSAndy Kosela break;
3387e81b07cSAndy Kosela case '0': case '1': case '2':
3397e81b07cSAndy Kosela case '3': case '4': case '5':
3407e81b07cSAndy Kosela case '6': case '7': case '8': case '9':
3417e81b07cSAndy Kosela MUST_BE_FIRST();
3427e81b07cSAndy Kosela STRTOL(addr, ibufp);
3437e81b07cSAndy Kosela break;
3447e81b07cSAndy Kosela case '.':
3457e81b07cSAndy Kosela case '$':
3467e81b07cSAndy Kosela MUST_BE_FIRST();
3477e81b07cSAndy Kosela ibufp++;
3487e81b07cSAndy Kosela addr = (c == '.') ? current_addr : addr_last;
3497e81b07cSAndy Kosela break;
3507e81b07cSAndy Kosela case '/':
3517e81b07cSAndy Kosela case '?':
3527e81b07cSAndy Kosela MUST_BE_FIRST();
3537e81b07cSAndy Kosela if ((addr = get_matching_node_addr(
3547e81b07cSAndy Kosela get_compiled_pattern(), c == '/')) < 0)
3557e81b07cSAndy Kosela return ERR;
3567e81b07cSAndy Kosela else if (c == *ibufp)
3577e81b07cSAndy Kosela ibufp++;
3587e81b07cSAndy Kosela break;
3597e81b07cSAndy Kosela case '\'':
3607e81b07cSAndy Kosela MUST_BE_FIRST();
3617e81b07cSAndy Kosela ibufp++;
3627e81b07cSAndy Kosela if ((addr = get_marked_node_addr((unsigned char)*ibufp++)) < 0)
3637e81b07cSAndy Kosela return ERR;
3647e81b07cSAndy Kosela break;
3657e81b07cSAndy Kosela case '%':
3667e81b07cSAndy Kosela case ',':
3677e81b07cSAndy Kosela case ';':
3687e81b07cSAndy Kosela if (first) {
3697e81b07cSAndy Kosela ibufp++;
3707e81b07cSAndy Kosela addr_cnt++;
3717e81b07cSAndy Kosela second_addr = (c == ';') ? current_addr : 1;
3727e81b07cSAndy Kosela addr = addr_last;
3737e81b07cSAndy Kosela break;
3747e81b07cSAndy Kosela }
3757e81b07cSAndy Kosela /* FALL THROUGH */
3767e81b07cSAndy Kosela default:
3777e81b07cSAndy Kosela if (ibufp == hd)
3787e81b07cSAndy Kosela return EOF;
3797e81b07cSAndy Kosela else if (addr < 0 || addr_last < addr) {
3800a6a1f1dSLionel Sambuc seterrmsg("invalid address");
3817e81b07cSAndy Kosela return ERR;
3827e81b07cSAndy Kosela } else
3837e81b07cSAndy Kosela return addr;
3847e81b07cSAndy Kosela }
3857e81b07cSAndy Kosela /* NOTREACHED */
3867e81b07cSAndy Kosela }
3877e81b07cSAndy Kosela
3887e81b07cSAndy Kosela
3897e81b07cSAndy Kosela #ifdef BACKWARDS
3907e81b07cSAndy Kosela /* GET_THIRD_ADDR: get a legal address from the command buffer */
3917e81b07cSAndy Kosela #define GET_THIRD_ADDR(addr) \
3927e81b07cSAndy Kosela { \
3937e81b07cSAndy Kosela long ol1, ol2; \
3947e81b07cSAndy Kosela \
3957e81b07cSAndy Kosela ol1 = first_addr, ol2 = second_addr; \
3967e81b07cSAndy Kosela if (extract_addr_range() < 0) \
3977e81b07cSAndy Kosela return ERR; \
3987e81b07cSAndy Kosela else if (addr_cnt == 0) { \
3990a6a1f1dSLionel Sambuc seterrmsg("destination expected"); \
4007e81b07cSAndy Kosela return ERR; \
4017e81b07cSAndy Kosela } else if (second_addr < 0 || addr_last < second_addr) { \
4020a6a1f1dSLionel Sambuc seterrmsg("invalid address"); \
4037e81b07cSAndy Kosela return ERR; \
4047e81b07cSAndy Kosela } \
4057e81b07cSAndy Kosela addr = second_addr; \
4067e81b07cSAndy Kosela first_addr = ol1, second_addr = ol2; \
4077e81b07cSAndy Kosela }
4087e81b07cSAndy Kosela #else /* BACKWARDS */
4097e81b07cSAndy Kosela /* GET_THIRD_ADDR: get a legal address from the command buffer */
4107e81b07cSAndy Kosela #define GET_THIRD_ADDR(addr) \
4117e81b07cSAndy Kosela { \
4127e81b07cSAndy Kosela long ol1, ol2; \
4137e81b07cSAndy Kosela \
4147e81b07cSAndy Kosela ol1 = first_addr, ol2 = second_addr; \
4157e81b07cSAndy Kosela if (extract_addr_range() < 0) \
4167e81b07cSAndy Kosela return ERR; \
4177e81b07cSAndy Kosela if (second_addr < 0 || addr_last < second_addr) { \
4180a6a1f1dSLionel Sambuc seterrmsg("invalid address"); \
4197e81b07cSAndy Kosela return ERR; \
4207e81b07cSAndy Kosela } \
4217e81b07cSAndy Kosela addr = second_addr; \
4227e81b07cSAndy Kosela first_addr = ol1, second_addr = ol2; \
4237e81b07cSAndy Kosela }
4247e81b07cSAndy Kosela #endif
4257e81b07cSAndy Kosela
4267e81b07cSAndy Kosela
4277e81b07cSAndy Kosela /* GET_COMMAND_SUFFIX: verify the command suffix in the command buffer */
4287e81b07cSAndy Kosela #define GET_COMMAND_SUFFIX() { \
4297e81b07cSAndy Kosela int done = 0; \
4307e81b07cSAndy Kosela do { \
4317e81b07cSAndy Kosela switch(*ibufp) { \
4327e81b07cSAndy Kosela case 'p': \
4337e81b07cSAndy Kosela gflag |= GPR, ibufp++; \
4347e81b07cSAndy Kosela break; \
4357e81b07cSAndy Kosela case 'l': \
4367e81b07cSAndy Kosela gflag |= GLS, ibufp++; \
4377e81b07cSAndy Kosela break; \
4387e81b07cSAndy Kosela case 'n': \
4397e81b07cSAndy Kosela gflag |= GNP, ibufp++; \
4407e81b07cSAndy Kosela break; \
4417e81b07cSAndy Kosela default: \
4427e81b07cSAndy Kosela done++; \
4437e81b07cSAndy Kosela } \
4447e81b07cSAndy Kosela } while (!done); \
4457e81b07cSAndy Kosela if (*ibufp++ != '\n') { \
4460a6a1f1dSLionel Sambuc seterrmsg("invalid command suffix"); \
4477e81b07cSAndy Kosela return ERR; \
4487e81b07cSAndy Kosela } \
4497e81b07cSAndy Kosela }
4507e81b07cSAndy Kosela
4517e81b07cSAndy Kosela
4527e81b07cSAndy Kosela /* sflags */
4537e81b07cSAndy Kosela #define SGG 001 /* complement previous global substitute suffix */
4547e81b07cSAndy Kosela #define SGP 002 /* complement previous print suffix */
4557e81b07cSAndy Kosela #define SGR 004 /* use last regex instead of last pat */
4567e81b07cSAndy Kosela #define SGF 010 /* repeat last substitution */
4577e81b07cSAndy Kosela
4587e81b07cSAndy Kosela int patlock = 0; /* if set, pattern not freed by get_compiled_pattern() */
4597e81b07cSAndy Kosela
4607e81b07cSAndy Kosela long rows = 22; /* scroll length: ws_row - 2 */
4617e81b07cSAndy Kosela
4627e81b07cSAndy Kosela /* exec_command: execute the next command in command buffer; return print
4637e81b07cSAndy Kosela request, if any */
4647e81b07cSAndy Kosela int
exec_command(void)4657e81b07cSAndy Kosela exec_command(void)
4667e81b07cSAndy Kosela {
4677e81b07cSAndy Kosela static pattern_t *pat = NULL;
4687e81b07cSAndy Kosela static int sgflag = 0;
4697e81b07cSAndy Kosela static long sgnum = 0;
4707e81b07cSAndy Kosela
4717e81b07cSAndy Kosela pattern_t *tpat;
4727e81b07cSAndy Kosela char *fnp;
4737e81b07cSAndy Kosela int gflag = 0;
4747e81b07cSAndy Kosela int sflags = 0;
4757e81b07cSAndy Kosela long addr = 0;
4767e81b07cSAndy Kosela int n = 0;
4777e81b07cSAndy Kosela int c;
4787e81b07cSAndy Kosela
4797e81b07cSAndy Kosela SKIP_BLANKS();
4807e81b07cSAndy Kosela switch(c = *ibufp++) {
4817e81b07cSAndy Kosela case 'a':
4827e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
4837e81b07cSAndy Kosela if (!isglobal) clear_undo_stack();
4847e81b07cSAndy Kosela if (append_lines(second_addr) < 0)
4857e81b07cSAndy Kosela return ERR;
4867e81b07cSAndy Kosela break;
4877e81b07cSAndy Kosela case 'c':
4887e81b07cSAndy Kosela if (check_addr_range(current_addr, current_addr) < 0)
4897e81b07cSAndy Kosela return ERR;
4907e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
4917e81b07cSAndy Kosela if (!isglobal) clear_undo_stack();
4927e81b07cSAndy Kosela if (delete_lines(first_addr, second_addr) < 0 ||
4937e81b07cSAndy Kosela append_lines(current_addr) < 0)
4947e81b07cSAndy Kosela return ERR;
4957e81b07cSAndy Kosela break;
4967e81b07cSAndy Kosela case 'd':
4977e81b07cSAndy Kosela if (check_addr_range(current_addr, current_addr) < 0)
4987e81b07cSAndy Kosela return ERR;
4997e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
5007e81b07cSAndy Kosela if (!isglobal) clear_undo_stack();
5017e81b07cSAndy Kosela if (delete_lines(first_addr, second_addr) < 0)
5027e81b07cSAndy Kosela return ERR;
5037e81b07cSAndy Kosela else if ((addr = INC_MOD(current_addr, addr_last)) != 0)
5047e81b07cSAndy Kosela current_addr = addr;
5057e81b07cSAndy Kosela break;
5067e81b07cSAndy Kosela case 'e':
5077e81b07cSAndy Kosela if (modified && !scripted)
5087e81b07cSAndy Kosela return EMOD;
5097e81b07cSAndy Kosela /* fall through */
5107e81b07cSAndy Kosela case 'E':
5117e81b07cSAndy Kosela if (addr_cnt > 0) {
5120a6a1f1dSLionel Sambuc seterrmsg("unexpected address");
5137e81b07cSAndy Kosela return ERR;
5147e81b07cSAndy Kosela } else if (!isspace((unsigned char)*ibufp)) {
5150a6a1f1dSLionel Sambuc seterrmsg("unexpected command suffix");
5167e81b07cSAndy Kosela return ERR;
5177e81b07cSAndy Kosela } else if ((fnp = get_filename()) == NULL)
5187e81b07cSAndy Kosela return ERR;
5197e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
5207e81b07cSAndy Kosela if (delete_lines(1, addr_last) < 0)
5217e81b07cSAndy Kosela return ERR;
5227e81b07cSAndy Kosela clear_undo_stack();
5237e81b07cSAndy Kosela if (close_sbuf() < 0)
5247e81b07cSAndy Kosela return ERR;
5257e81b07cSAndy Kosela else if (open_sbuf() < 0)
5267e81b07cSAndy Kosela return FATAL;
5277e81b07cSAndy Kosela if (*fnp && *fnp != '!') strlcpy(old_filename, fnp,
5287e81b07cSAndy Kosela sizeof(old_filename) - 2);
5297e81b07cSAndy Kosela #ifdef BACKWARDS
5307e81b07cSAndy Kosela if (*fnp == '\0' && *old_filename == '\0') {
5310a6a1f1dSLionel Sambuc seterrmsg("no current filename");
5327e81b07cSAndy Kosela return ERR;
5337e81b07cSAndy Kosela }
5347e81b07cSAndy Kosela #endif
5357e81b07cSAndy Kosela if (read_file(*fnp ? fnp : old_filename, 0) < 0)
5367e81b07cSAndy Kosela return ERR;
5377e81b07cSAndy Kosela clear_undo_stack();
5387e81b07cSAndy Kosela modified = 0;
5397e81b07cSAndy Kosela u_current_addr = u_addr_last = -1;
5407e81b07cSAndy Kosela break;
5417e81b07cSAndy Kosela case 'f':
5427e81b07cSAndy Kosela if (addr_cnt > 0) {
5430a6a1f1dSLionel Sambuc seterrmsg("unexpected address");
5447e81b07cSAndy Kosela return ERR;
5457e81b07cSAndy Kosela } else if (!isspace((unsigned char)*ibufp)) {
5460a6a1f1dSLionel Sambuc seterrmsg("unexpected command suffix");
5477e81b07cSAndy Kosela return ERR;
5487e81b07cSAndy Kosela } else if ((fnp = get_filename()) == NULL)
5497e81b07cSAndy Kosela return ERR;
5507e81b07cSAndy Kosela else if (*fnp == '!') {
5510a6a1f1dSLionel Sambuc seterrmsg("invalid redirection");
5527e81b07cSAndy Kosela return ERR;
5537e81b07cSAndy Kosela }
5547e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
5557e81b07cSAndy Kosela if (*fnp) strlcpy(old_filename, fnp, sizeof(old_filename) - 2);
5567e81b07cSAndy Kosela printf("%s\n", strip_escapes(old_filename));
5577e81b07cSAndy Kosela break;
5587e81b07cSAndy Kosela case 'g':
5597e81b07cSAndy Kosela case 'v':
5607e81b07cSAndy Kosela case 'G':
5617e81b07cSAndy Kosela case 'V':
5627e81b07cSAndy Kosela if (isglobal) {
5630a6a1f1dSLionel Sambuc seterrmsg("cannot nest global commands");
5647e81b07cSAndy Kosela return ERR;
5657e81b07cSAndy Kosela } else if (check_addr_range(1, addr_last) < 0)
5667e81b07cSAndy Kosela return ERR;
5677e81b07cSAndy Kosela else if (build_active_list(c == 'g' || c == 'G') < 0)
5687e81b07cSAndy Kosela return ERR;
5697e81b07cSAndy Kosela else if ((n = (c == 'G' || c == 'V')) != 0)
5707e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
5717e81b07cSAndy Kosela isglobal++;
5727e81b07cSAndy Kosela if (exec_global(n, gflag) < 0)
5737e81b07cSAndy Kosela return ERR;
5747e81b07cSAndy Kosela break;
5757e81b07cSAndy Kosela case 'h':
5767e81b07cSAndy Kosela if (addr_cnt > 0) {
5770a6a1f1dSLionel Sambuc seterrmsg("unexpected address");
5787e81b07cSAndy Kosela return ERR;
5797e81b07cSAndy Kosela }
5807e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
5817e81b07cSAndy Kosela if (*errmsg) fprintf(stderr, "%s\n", errmsg);
5827e81b07cSAndy Kosela break;
5837e81b07cSAndy Kosela case 'H':
5847e81b07cSAndy Kosela if (addr_cnt > 0) {
5850a6a1f1dSLionel Sambuc seterrmsg("unexpected address");
5867e81b07cSAndy Kosela return ERR;
5877e81b07cSAndy Kosela }
5887e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
5897e81b07cSAndy Kosela if ((garrulous = 1 - garrulous) && *errmsg)
5907e81b07cSAndy Kosela fprintf(stderr, "%s\n", errmsg);
5917e81b07cSAndy Kosela break;
5927e81b07cSAndy Kosela case 'i':
5937e81b07cSAndy Kosela if (second_addr == 0) {
5940a6a1f1dSLionel Sambuc seterrmsg("invalid address");
5957e81b07cSAndy Kosela return ERR;
5967e81b07cSAndy Kosela }
5977e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
5987e81b07cSAndy Kosela if (!isglobal) clear_undo_stack();
5997e81b07cSAndy Kosela if (append_lines(second_addr - 1) < 0)
6007e81b07cSAndy Kosela return ERR;
6017e81b07cSAndy Kosela break;
6027e81b07cSAndy Kosela case 'j':
6037e81b07cSAndy Kosela if (check_addr_range(current_addr, current_addr + 1) < 0)
6047e81b07cSAndy Kosela return ERR;
6057e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
6067e81b07cSAndy Kosela if (!isglobal) clear_undo_stack();
6077e81b07cSAndy Kosela if (first_addr != second_addr &&
6087e81b07cSAndy Kosela join_lines(first_addr, second_addr) < 0)
6097e81b07cSAndy Kosela return ERR;
6107e81b07cSAndy Kosela break;
6117e81b07cSAndy Kosela case 'k':
6127e81b07cSAndy Kosela c = *ibufp++;
6137e81b07cSAndy Kosela if (second_addr == 0) {
6140a6a1f1dSLionel Sambuc seterrmsg("invalid address");
6157e81b07cSAndy Kosela return ERR;
6167e81b07cSAndy Kosela }
6177e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
6187e81b07cSAndy Kosela if (mark_line_node(get_addressed_line_node(second_addr), (unsigned char)c) < 0)
6197e81b07cSAndy Kosela return ERR;
6207e81b07cSAndy Kosela break;
6217e81b07cSAndy Kosela case 'l':
6227e81b07cSAndy Kosela if (check_addr_range(current_addr, current_addr) < 0)
6237e81b07cSAndy Kosela return ERR;
6247e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
6257e81b07cSAndy Kosela if (display_lines(first_addr, second_addr, gflag | GLS) < 0)
6267e81b07cSAndy Kosela return ERR;
6277e81b07cSAndy Kosela gflag = 0;
6287e81b07cSAndy Kosela break;
6297e81b07cSAndy Kosela case 'm':
6307e81b07cSAndy Kosela if (check_addr_range(current_addr, current_addr) < 0)
6317e81b07cSAndy Kosela return ERR;
6327e81b07cSAndy Kosela GET_THIRD_ADDR(addr);
6337e81b07cSAndy Kosela if (first_addr <= addr && addr < second_addr) {
6340a6a1f1dSLionel Sambuc seterrmsg("invalid destination");
6357e81b07cSAndy Kosela return ERR;
6367e81b07cSAndy Kosela }
6377e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
6387e81b07cSAndy Kosela if (!isglobal) clear_undo_stack();
6397e81b07cSAndy Kosela if (move_lines(addr) < 0)
6407e81b07cSAndy Kosela return ERR;
6417e81b07cSAndy Kosela break;
6427e81b07cSAndy Kosela case 'n':
6437e81b07cSAndy Kosela if (check_addr_range(current_addr, current_addr) < 0)
6447e81b07cSAndy Kosela return ERR;
6457e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
6467e81b07cSAndy Kosela if (display_lines(first_addr, second_addr, gflag | GNP) < 0)
6477e81b07cSAndy Kosela return ERR;
6487e81b07cSAndy Kosela gflag = 0;
6497e81b07cSAndy Kosela break;
6507e81b07cSAndy Kosela case 'p':
6517e81b07cSAndy Kosela if (check_addr_range(current_addr, current_addr) < 0)
6527e81b07cSAndy Kosela return ERR;
6537e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
6547e81b07cSAndy Kosela if (display_lines(first_addr, second_addr, gflag | GPR) < 0)
6557e81b07cSAndy Kosela return ERR;
6567e81b07cSAndy Kosela gflag = 0;
6577e81b07cSAndy Kosela break;
6587e81b07cSAndy Kosela case 'P':
6597e81b07cSAndy Kosela if (addr_cnt > 0) {
6600a6a1f1dSLionel Sambuc seterrmsg("unexpected address");
6617e81b07cSAndy Kosela return ERR;
6627e81b07cSAndy Kosela }
6637e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
6647e81b07cSAndy Kosela prompt = prompt ? NULL : optarg ? optarg : dps;
6657e81b07cSAndy Kosela break;
6667e81b07cSAndy Kosela case 'q':
6677e81b07cSAndy Kosela case 'Q':
6687e81b07cSAndy Kosela if (addr_cnt > 0) {
6690a6a1f1dSLionel Sambuc seterrmsg("unexpected address");
6707e81b07cSAndy Kosela return ERR;
6717e81b07cSAndy Kosela }
6727e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
6737e81b07cSAndy Kosela gflag = (modified && !scripted && c == 'q') ? EMOD : EOF;
6747e81b07cSAndy Kosela break;
6757e81b07cSAndy Kosela case 'r':
6767e81b07cSAndy Kosela if (!isspace((unsigned char)*ibufp)) {
6770a6a1f1dSLionel Sambuc seterrmsg("unexpected command suffix");
6787e81b07cSAndy Kosela return ERR;
6797e81b07cSAndy Kosela } else if (addr_cnt == 0)
6807e81b07cSAndy Kosela second_addr = addr_last;
6817e81b07cSAndy Kosela if ((fnp = get_filename()) == NULL)
6827e81b07cSAndy Kosela return ERR;
6837e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
6847e81b07cSAndy Kosela if (!isglobal) clear_undo_stack();
6857e81b07cSAndy Kosela if (*old_filename == '\0' && *fnp != '!')
6867e81b07cSAndy Kosela strlcpy(old_filename, fnp, sizeof(old_filename) - 2);
6877e81b07cSAndy Kosela #ifdef BACKWARDS
6887e81b07cSAndy Kosela if (*fnp == '\0' && *old_filename == '\0') {
6890a6a1f1dSLionel Sambuc seterrmsg("no current filename");
6907e81b07cSAndy Kosela return ERR;
6917e81b07cSAndy Kosela }
6927e81b07cSAndy Kosela #endif
6937e81b07cSAndy Kosela if ((addr = read_file(*fnp ? fnp : old_filename, second_addr)) < 0)
6947e81b07cSAndy Kosela return ERR;
6957e81b07cSAndy Kosela else if (addr && addr != addr_last)
6967e81b07cSAndy Kosela modified = 1;
6977e81b07cSAndy Kosela break;
6987e81b07cSAndy Kosela case 's':
6997e81b07cSAndy Kosela do {
7007e81b07cSAndy Kosela switch(*ibufp) {
7017e81b07cSAndy Kosela case '\n':
7027e81b07cSAndy Kosela sflags |=SGF;
7037e81b07cSAndy Kosela break;
7047e81b07cSAndy Kosela case 'g':
7057e81b07cSAndy Kosela sflags |= SGG;
7067e81b07cSAndy Kosela ibufp++;
7077e81b07cSAndy Kosela break;
7087e81b07cSAndy Kosela case 'p':
7097e81b07cSAndy Kosela sflags |= SGP;
7107e81b07cSAndy Kosela ibufp++;
7117e81b07cSAndy Kosela break;
7127e81b07cSAndy Kosela case 'r':
7137e81b07cSAndy Kosela sflags |= SGR;
7147e81b07cSAndy Kosela ibufp++;
7157e81b07cSAndy Kosela break;
7167e81b07cSAndy Kosela case '0': case '1': case '2': case '3': case '4':
7177e81b07cSAndy Kosela case '5': case '6': case '7': case '8': case '9':
7187e81b07cSAndy Kosela STRTOL(sgnum, ibufp);
7197e81b07cSAndy Kosela sflags |= SGF;
7207e81b07cSAndy Kosela sgflag &= ~GSG; /* override GSG */
7217e81b07cSAndy Kosela break;
7227e81b07cSAndy Kosela default:
7237e81b07cSAndy Kosela if (sflags) {
7240a6a1f1dSLionel Sambuc seterrmsg("invalid command suffix");
7257e81b07cSAndy Kosela return ERR;
7267e81b07cSAndy Kosela }
7277e81b07cSAndy Kosela }
7287e81b07cSAndy Kosela } while (sflags && *ibufp != '\n');
7297e81b07cSAndy Kosela if (sflags && !pat) {
7300a6a1f1dSLionel Sambuc seterrmsg("no previous substitution");
7317e81b07cSAndy Kosela return ERR;
7327e81b07cSAndy Kosela } else if (sflags & SGG)
7337e81b07cSAndy Kosela sgnum = 0; /* override numeric arg */
7347e81b07cSAndy Kosela if (*ibufp != '\n' && *(ibufp + 1) == '\n') {
7350a6a1f1dSLionel Sambuc seterrmsg("invalid pattern delimiter");
7367e81b07cSAndy Kosela return ERR;
7377e81b07cSAndy Kosela }
7387e81b07cSAndy Kosela tpat = pat;
7397e81b07cSAndy Kosela SPL1();
7407e81b07cSAndy Kosela if ((!sflags || (sflags & SGR)) &&
7417e81b07cSAndy Kosela (tpat = get_compiled_pattern()) == NULL) {
7427e81b07cSAndy Kosela SPL0();
7437e81b07cSAndy Kosela return ERR;
7447e81b07cSAndy Kosela } else if (tpat != pat) {
7457e81b07cSAndy Kosela if (pat) {
7467e81b07cSAndy Kosela regfree(pat);
7477e81b07cSAndy Kosela free(pat);
7487e81b07cSAndy Kosela }
7497e81b07cSAndy Kosela pat = tpat;
7507e81b07cSAndy Kosela patlock = 1; /* reserve pattern */
7517e81b07cSAndy Kosela }
7527e81b07cSAndy Kosela SPL0();
7537e81b07cSAndy Kosela if (!sflags && extract_subst_tail(&sgflag, &sgnum) < 0)
7547e81b07cSAndy Kosela return ERR;
7557e81b07cSAndy Kosela else if (isglobal)
7567e81b07cSAndy Kosela sgflag |= GLB;
7577e81b07cSAndy Kosela else
7587e81b07cSAndy Kosela sgflag &= ~GLB;
7597e81b07cSAndy Kosela if (sflags & SGG)
7607e81b07cSAndy Kosela sgflag ^= GSG;
7617e81b07cSAndy Kosela if (sflags & SGP)
7627e81b07cSAndy Kosela sgflag ^= GPR, sgflag &= ~(GLS | GNP);
7637e81b07cSAndy Kosela do {
7647e81b07cSAndy Kosela switch(*ibufp) {
7657e81b07cSAndy Kosela case 'p':
7667e81b07cSAndy Kosela sgflag |= GPR, ibufp++;
7677e81b07cSAndy Kosela break;
7687e81b07cSAndy Kosela case 'l':
7697e81b07cSAndy Kosela sgflag |= GLS, ibufp++;
7707e81b07cSAndy Kosela break;
7717e81b07cSAndy Kosela case 'n':
7727e81b07cSAndy Kosela sgflag |= GNP, ibufp++;
7737e81b07cSAndy Kosela break;
7747e81b07cSAndy Kosela default:
7757e81b07cSAndy Kosela n++;
7767e81b07cSAndy Kosela }
7777e81b07cSAndy Kosela } while (!n);
7787e81b07cSAndy Kosela if (check_addr_range(current_addr, current_addr) < 0)
7797e81b07cSAndy Kosela return ERR;
7807e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
7817e81b07cSAndy Kosela if (!isglobal) clear_undo_stack();
7827e81b07cSAndy Kosela if (search_and_replace(pat, sgflag, sgnum) < 0)
7837e81b07cSAndy Kosela return ERR;
7847e81b07cSAndy Kosela break;
7857e81b07cSAndy Kosela case 't':
7867e81b07cSAndy Kosela if (check_addr_range(current_addr, current_addr) < 0)
7877e81b07cSAndy Kosela return ERR;
7887e81b07cSAndy Kosela GET_THIRD_ADDR(addr);
7897e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
7907e81b07cSAndy Kosela if (!isglobal) clear_undo_stack();
7917e81b07cSAndy Kosela if (copy_lines(addr) < 0)
7927e81b07cSAndy Kosela return ERR;
7937e81b07cSAndy Kosela break;
7947e81b07cSAndy Kosela case 'u':
7957e81b07cSAndy Kosela if (addr_cnt > 0) {
7960a6a1f1dSLionel Sambuc seterrmsg("unexpected address");
7977e81b07cSAndy Kosela return ERR;
7987e81b07cSAndy Kosela }
7997e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
8007e81b07cSAndy Kosela if (pop_undo_stack() < 0)
8017e81b07cSAndy Kosela return ERR;
8027e81b07cSAndy Kosela break;
8037e81b07cSAndy Kosela case 'w':
8047e81b07cSAndy Kosela case 'W':
8057e81b07cSAndy Kosela if ((n = *ibufp) == 'q' || n == 'Q') {
8067e81b07cSAndy Kosela gflag = EOF;
8077e81b07cSAndy Kosela ibufp++;
8087e81b07cSAndy Kosela }
8097e81b07cSAndy Kosela if (!isspace((unsigned char)*ibufp)) {
8100a6a1f1dSLionel Sambuc seterrmsg("unexpected command suffix");
8117e81b07cSAndy Kosela return ERR;
8127e81b07cSAndy Kosela } else if ((fnp = get_filename()) == NULL)
8137e81b07cSAndy Kosela return ERR;
8147e81b07cSAndy Kosela if (addr_cnt == 0 && !addr_last)
8157e81b07cSAndy Kosela first_addr = second_addr = 0;
8167e81b07cSAndy Kosela else if (check_addr_range(1, addr_last) < 0)
8177e81b07cSAndy Kosela return ERR;
8187e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
8197e81b07cSAndy Kosela if (*old_filename == '\0' && *fnp != '!')
8207e81b07cSAndy Kosela strlcpy(old_filename, fnp, sizeof(old_filename) - 2);
8217e81b07cSAndy Kosela #ifdef BACKWARDS
8227e81b07cSAndy Kosela if (*fnp == '\0' && *old_filename == '\0') {
8230a6a1f1dSLionel Sambuc seterrmsg("no current filename");
8247e81b07cSAndy Kosela return ERR;
8257e81b07cSAndy Kosela }
8267e81b07cSAndy Kosela #endif
8277e81b07cSAndy Kosela if ((addr = write_file(*fnp ? fnp : old_filename,
8287e81b07cSAndy Kosela (c == 'W') ? "a" : "w", first_addr, second_addr)) < 0)
8297e81b07cSAndy Kosela return ERR;
8307e81b07cSAndy Kosela else if (addr == addr_last)
8317e81b07cSAndy Kosela modified = 0;
8327e81b07cSAndy Kosela else if (modified && !scripted && n == 'q')
8337e81b07cSAndy Kosela gflag = EMOD;
8347e81b07cSAndy Kosela break;
8357e81b07cSAndy Kosela case 'x':
8367e81b07cSAndy Kosela if (addr_cnt > 0) {
8370a6a1f1dSLionel Sambuc seterrmsg("unexpected address");
8387e81b07cSAndy Kosela return ERR;
8397e81b07cSAndy Kosela }
8407e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
8417e81b07cSAndy Kosela #ifdef DES
8427e81b07cSAndy Kosela des = get_keyword();
8437e81b07cSAndy Kosela #else
8440a6a1f1dSLionel Sambuc seterrmsg("crypt unavailable");
8457e81b07cSAndy Kosela return ERR;
8467e81b07cSAndy Kosela #endif
8477e81b07cSAndy Kosela break;
8487e81b07cSAndy Kosela case 'z':
8497e81b07cSAndy Kosela #ifdef BACKWARDS
8507e81b07cSAndy Kosela if (check_addr_range(first_addr = 1, current_addr + 1) < 0)
8517e81b07cSAndy Kosela #else
8527e81b07cSAndy Kosela if (check_addr_range(first_addr = 1, current_addr + !isglobal) < 0)
8537e81b07cSAndy Kosela #endif
8547e81b07cSAndy Kosela return ERR;
8557e81b07cSAndy Kosela else if ('0' < *ibufp && *ibufp <= '9')
8567e81b07cSAndy Kosela STRTOL(rows, ibufp);
8577e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
8587e81b07cSAndy Kosela if (display_lines(second_addr, min(addr_last,
8597e81b07cSAndy Kosela second_addr + rows), gflag) < 0)
8607e81b07cSAndy Kosela return ERR;
8617e81b07cSAndy Kosela gflag = 0;
8627e81b07cSAndy Kosela break;
8637e81b07cSAndy Kosela case '=':
8647e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
8657e81b07cSAndy Kosela printf("%ld\n", addr_cnt ? second_addr : addr_last);
8667e81b07cSAndy Kosela break;
8677e81b07cSAndy Kosela case '!':
8687e81b07cSAndy Kosela if (addr_cnt > 0) {
8690a6a1f1dSLionel Sambuc seterrmsg("unexpected address");
8707e81b07cSAndy Kosela return ERR;
871*4db99f40SSevan Janiyan }
872*4db99f40SSevan Janiyan if ((sflags = get_shell_command()) < 0)
8737e81b07cSAndy Kosela return ERR;
8747e81b07cSAndy Kosela GET_COMMAND_SUFFIX();
8757e81b07cSAndy Kosela if (sflags) printf("%s\n", shcmd + 1);
8767e81b07cSAndy Kosela system(shcmd + 1);
8777e81b07cSAndy Kosela if (!scripted) printf("!\n");
8787e81b07cSAndy Kosela break;
8797e81b07cSAndy Kosela case '\n':
8807e81b07cSAndy Kosela #ifdef BACKWARDS
8817e81b07cSAndy Kosela if (check_addr_range(first_addr = 1, current_addr + 1) < 0
8827e81b07cSAndy Kosela #else
8837e81b07cSAndy Kosela if (check_addr_range(first_addr = 1, current_addr + !isglobal) < 0
8847e81b07cSAndy Kosela #endif
8857e81b07cSAndy Kosela || display_lines(second_addr, second_addr, 0) < 0)
8867e81b07cSAndy Kosela return ERR;
8877e81b07cSAndy Kosela break;
8887e81b07cSAndy Kosela default:
8890a6a1f1dSLionel Sambuc seterrmsg("unknown command");
8907e81b07cSAndy Kosela return ERR;
8917e81b07cSAndy Kosela }
8927e81b07cSAndy Kosela return gflag;
8937e81b07cSAndy Kosela }
8947e81b07cSAndy Kosela
8957e81b07cSAndy Kosela
8967e81b07cSAndy Kosela /* check_addr_range: return status of address range check */
8977e81b07cSAndy Kosela int
check_addr_range(long n,long m)8987e81b07cSAndy Kosela check_addr_range(long n, long m)
8997e81b07cSAndy Kosela {
9007e81b07cSAndy Kosela if (addr_cnt == 0) {
9017e81b07cSAndy Kosela first_addr = n;
9027e81b07cSAndy Kosela second_addr = m;
9037e81b07cSAndy Kosela }
9047e81b07cSAndy Kosela if (first_addr > second_addr || 1 > first_addr ||
9057e81b07cSAndy Kosela second_addr > addr_last) {
9060a6a1f1dSLionel Sambuc seterrmsg("invalid address");
9077e81b07cSAndy Kosela return ERR;
9087e81b07cSAndy Kosela }
9097e81b07cSAndy Kosela return 0;
9107e81b07cSAndy Kosela }
9117e81b07cSAndy Kosela
9127e81b07cSAndy Kosela
9137e81b07cSAndy Kosela /* get_matching_node_addr: return the address of the next line matching a
9147e81b07cSAndy Kosela pattern in a given direction. wrap around begin/end of editor buffer if
9157e81b07cSAndy Kosela necessary */
9167e81b07cSAndy Kosela long
get_matching_node_addr(pattern_t * pat,int dir)9177e81b07cSAndy Kosela get_matching_node_addr(pattern_t *pat, int dir)
9187e81b07cSAndy Kosela {
9197e81b07cSAndy Kosela char *s;
9207e81b07cSAndy Kosela long n = current_addr;
9217e81b07cSAndy Kosela line_t *lp;
9227e81b07cSAndy Kosela
9237e81b07cSAndy Kosela if (!pat) return ERR;
9247e81b07cSAndy Kosela do {
9257e81b07cSAndy Kosela if ((n = dir ? INC_MOD(n, addr_last) :
9267e81b07cSAndy Kosela DEC_MOD(n, addr_last)) != 0) {
9277e81b07cSAndy Kosela lp = get_addressed_line_node(n);
9287e81b07cSAndy Kosela if ((s = get_sbuf_line(lp)) == NULL)
9297e81b07cSAndy Kosela return ERR;
9307e81b07cSAndy Kosela if (isbinary)
9317e81b07cSAndy Kosela NUL_TO_NEWLINE(s, lp->len);
9327e81b07cSAndy Kosela if (!regexec(pat, s, 0, NULL, 0))
9337e81b07cSAndy Kosela return n;
9347e81b07cSAndy Kosela }
9357e81b07cSAndy Kosela } while (n != current_addr);
9360a6a1f1dSLionel Sambuc seterrmsg("no match");
9377e81b07cSAndy Kosela return ERR;
9387e81b07cSAndy Kosela }
9397e81b07cSAndy Kosela
9407e81b07cSAndy Kosela
9417e81b07cSAndy Kosela /* get_filename: return pointer to copy of filename in the command buffer */
9427e81b07cSAndy Kosela char *
get_filename(void)9437e81b07cSAndy Kosela get_filename(void)
9447e81b07cSAndy Kosela {
9457e81b07cSAndy Kosela static char *file = NULL;
9467e81b07cSAndy Kosela static int filesz = 0;
9477e81b07cSAndy Kosela
9487e81b07cSAndy Kosela int n;
9497e81b07cSAndy Kosela
9507e81b07cSAndy Kosela if (*ibufp != '\n') {
9517e81b07cSAndy Kosela SKIP_BLANKS();
9527e81b07cSAndy Kosela if (*ibufp == '\n') {
9530a6a1f1dSLionel Sambuc seterrmsg("invalid filename");
9547e81b07cSAndy Kosela return NULL;
9557e81b07cSAndy Kosela } else if ((ibufp = get_extended_line(&n, 1)) == NULL)
9567e81b07cSAndy Kosela return NULL;
9577e81b07cSAndy Kosela else if (*ibufp == '!') {
9587e81b07cSAndy Kosela ibufp++;
9597e81b07cSAndy Kosela if ((n = get_shell_command()) < 0)
9607e81b07cSAndy Kosela return NULL;
9617e81b07cSAndy Kosela if (n) printf("%s\n", shcmd + 1);
9627e81b07cSAndy Kosela return shcmd;
9637e81b07cSAndy Kosela } else if (n - 1 > MAXPATHLEN) {
9640a6a1f1dSLionel Sambuc seterrmsg("filename too long");
9657e81b07cSAndy Kosela return NULL;
9667e81b07cSAndy Kosela }
9677e81b07cSAndy Kosela }
9687e81b07cSAndy Kosela #ifndef BACKWARDS
9697e81b07cSAndy Kosela else if (*old_filename == '\0') {
9700a6a1f1dSLionel Sambuc seterrmsg("no current filename");
9717e81b07cSAndy Kosela return NULL;
9727e81b07cSAndy Kosela }
9737e81b07cSAndy Kosela #endif
9747e81b07cSAndy Kosela REALLOC(file, filesz, MAXPATHLEN + 1, NULL);
9757e81b07cSAndy Kosela for (n = 0; *ibufp != '\n';)
9767e81b07cSAndy Kosela file[n++] = *ibufp++;
9777e81b07cSAndy Kosela file[n] = '\0';
9787e81b07cSAndy Kosela return is_legal_filename(file) ? file : NULL;
9797e81b07cSAndy Kosela }
9807e81b07cSAndy Kosela
9817e81b07cSAndy Kosela
9827e81b07cSAndy Kosela /* get_shell_command: read a shell command from stdin; return substitution
9837e81b07cSAndy Kosela status */
9847e81b07cSAndy Kosela int
get_shell_command(void)9857e81b07cSAndy Kosela get_shell_command(void)
9867e81b07cSAndy Kosela {
9877e81b07cSAndy Kosela static char *buf = NULL;
9887e81b07cSAndy Kosela static int n = 0;
9897e81b07cSAndy Kosela
9907e81b07cSAndy Kosela char *s; /* substitution char pointer */
9917e81b07cSAndy Kosela int i = 0;
9927e81b07cSAndy Kosela int j = 0;
9937e81b07cSAndy Kosela
994*4db99f40SSevan Janiyan if (red || secure) {
9950a6a1f1dSLionel Sambuc seterrmsg("shell access restricted");
9967e81b07cSAndy Kosela return ERR;
9977e81b07cSAndy Kosela } else if ((s = ibufp = get_extended_line(&j, 1)) == NULL)
9987e81b07cSAndy Kosela return ERR;
9997e81b07cSAndy Kosela REALLOC(buf, n, j + 1, ERR);
10007e81b07cSAndy Kosela buf[i++] = '!'; /* prefix command w/ bang */
10017e81b07cSAndy Kosela while (*ibufp != '\n')
10027e81b07cSAndy Kosela switch (*ibufp) {
10037e81b07cSAndy Kosela default:
10047e81b07cSAndy Kosela REALLOC(buf, n, i + 2, ERR);
10057e81b07cSAndy Kosela buf[i++] = *ibufp;
10067e81b07cSAndy Kosela if (*ibufp++ == '\\')
10077e81b07cSAndy Kosela buf[i++] = *ibufp++;
10087e81b07cSAndy Kosela break;
10097e81b07cSAndy Kosela case '!':
10107e81b07cSAndy Kosela if (s != ibufp) {
10117e81b07cSAndy Kosela REALLOC(buf, n, i + 1, ERR);
10127e81b07cSAndy Kosela buf[i++] = *ibufp++;
10137e81b07cSAndy Kosela }
10147e81b07cSAndy Kosela #ifdef BACKWARDS
10157e81b07cSAndy Kosela else if (shcmd == NULL || *(shcmd + 1) == '\0')
10167e81b07cSAndy Kosela #else
10177e81b07cSAndy Kosela else if (shcmd == NULL)
10187e81b07cSAndy Kosela #endif
10197e81b07cSAndy Kosela {
10200a6a1f1dSLionel Sambuc seterrmsg("no previous command");
10217e81b07cSAndy Kosela return ERR;
10227e81b07cSAndy Kosela } else {
10237e81b07cSAndy Kosela REALLOC(buf, n, i + shcmdi, ERR);
10247e81b07cSAndy Kosela for (s = shcmd + 1; s < shcmd + shcmdi;)
10257e81b07cSAndy Kosela buf[i++] = *s++;
10267e81b07cSAndy Kosela s = ibufp++;
10277e81b07cSAndy Kosela }
10287e81b07cSAndy Kosela break;
10297e81b07cSAndy Kosela case '%':
10307e81b07cSAndy Kosela if (*old_filename == '\0') {
10310a6a1f1dSLionel Sambuc seterrmsg("no current filename");
10327e81b07cSAndy Kosela return ERR;
10337e81b07cSAndy Kosela }
10347e81b07cSAndy Kosela j = strlen(s = strip_escapes(old_filename));
10357e81b07cSAndy Kosela REALLOC(buf, n, i + j, ERR);
10367e81b07cSAndy Kosela while (j--)
10377e81b07cSAndy Kosela buf[i++] = *s++;
10387e81b07cSAndy Kosela s = ibufp++;
10397e81b07cSAndy Kosela break;
10407e81b07cSAndy Kosela }
10417e81b07cSAndy Kosela REALLOC(shcmd, shcmdsz, i + 1, ERR);
10427e81b07cSAndy Kosela memcpy(shcmd, buf, i);
10437e81b07cSAndy Kosela shcmd[shcmdi = i] = '\0';
10447e81b07cSAndy Kosela return *s == '!' || *s == '%';
10457e81b07cSAndy Kosela }
10467e81b07cSAndy Kosela
10477e81b07cSAndy Kosela
10487e81b07cSAndy Kosela /* append_lines: insert text from stdin to after line n; stop when either a
10497e81b07cSAndy Kosela single period is read or EOF; return status */
10507e81b07cSAndy Kosela int
append_lines(long n)10517e81b07cSAndy Kosela append_lines(long n)
10527e81b07cSAndy Kosela {
10537e81b07cSAndy Kosela int l;
10547e81b07cSAndy Kosela char *lp = ibuf;
10557e81b07cSAndy Kosela char *eot;
10567e81b07cSAndy Kosela undo_t *up = NULL;
10577e81b07cSAndy Kosela
10587e81b07cSAndy Kosela for (current_addr = n;;) {
10597e81b07cSAndy Kosela if (!isglobal) {
10607e81b07cSAndy Kosela if ((l = get_tty_line()) < 0)
10617e81b07cSAndy Kosela return ERR;
10627e81b07cSAndy Kosela else if (l == 0 || ibuf[l - 1] != '\n') {
10637e81b07cSAndy Kosela clearerr(stdin);
10647e81b07cSAndy Kosela return l ? EOF : 0;
10657e81b07cSAndy Kosela }
10667e81b07cSAndy Kosela lp = ibuf;
10677e81b07cSAndy Kosela } else if (*(lp = ibufp) == '\0')
10687e81b07cSAndy Kosela return 0;
10697e81b07cSAndy Kosela else {
10707e81b07cSAndy Kosela while (*ibufp++ != '\n')
10717e81b07cSAndy Kosela ;
10727e81b07cSAndy Kosela l = ibufp - lp;
10737e81b07cSAndy Kosela }
10747e81b07cSAndy Kosela if (l == 2 && lp[0] == '.' && lp[1] == '\n') {
10757e81b07cSAndy Kosela return 0;
10767e81b07cSAndy Kosela }
10777e81b07cSAndy Kosela eot = lp + l;
10787e81b07cSAndy Kosela SPL1();
10797e81b07cSAndy Kosela do {
10807e81b07cSAndy Kosela if ((lp = put_sbuf_line(lp)) == NULL) {
10817e81b07cSAndy Kosela SPL0();
10827e81b07cSAndy Kosela return ERR;
10837e81b07cSAndy Kosela } else if (up)
10847e81b07cSAndy Kosela up->t = get_addressed_line_node(current_addr);
10857e81b07cSAndy Kosela else if ((up = push_undo_stack(UADD, current_addr,
10867e81b07cSAndy Kosela current_addr)) == NULL) {
10877e81b07cSAndy Kosela SPL0();
10887e81b07cSAndy Kosela return ERR;
10897e81b07cSAndy Kosela }
10907e81b07cSAndy Kosela } while (lp != eot);
10917e81b07cSAndy Kosela modified = 1;
10927e81b07cSAndy Kosela SPL0();
10937e81b07cSAndy Kosela }
10947e81b07cSAndy Kosela /* NOTREACHED */
10957e81b07cSAndy Kosela }
10967e81b07cSAndy Kosela
10977e81b07cSAndy Kosela
10987e81b07cSAndy Kosela /* join_lines: replace a range of lines with the joined text of those lines */
10997e81b07cSAndy Kosela int
join_lines(long from,long to)11007e81b07cSAndy Kosela join_lines(long from, long to)
11017e81b07cSAndy Kosela {
11027e81b07cSAndy Kosela static char *buf = NULL;
11037e81b07cSAndy Kosela static int n;
11047e81b07cSAndy Kosela
11057e81b07cSAndy Kosela char *s;
11067e81b07cSAndy Kosela int size = 0;
11077e81b07cSAndy Kosela line_t *bp, *ep;
11087e81b07cSAndy Kosela
11097e81b07cSAndy Kosela ep = get_addressed_line_node(INC_MOD(to, addr_last));
11107e81b07cSAndy Kosela bp = get_addressed_line_node(from);
11117e81b07cSAndy Kosela for (; bp != ep; bp = bp->q_forw) {
11127e81b07cSAndy Kosela if ((s = get_sbuf_line(bp)) == NULL)
11137e81b07cSAndy Kosela return ERR;
11147e81b07cSAndy Kosela REALLOC(buf, n, size + bp->len, ERR);
11157e81b07cSAndy Kosela memcpy(buf + size, s, bp->len);
11167e81b07cSAndy Kosela size += bp->len;
11177e81b07cSAndy Kosela }
11187e81b07cSAndy Kosela REALLOC(buf, n, size + 2, ERR);
11197e81b07cSAndy Kosela memcpy(buf + size, "\n", 2);
11207e81b07cSAndy Kosela if (delete_lines(from, to) < 0)
11217e81b07cSAndy Kosela return ERR;
11227e81b07cSAndy Kosela current_addr = from - 1;
11237e81b07cSAndy Kosela SPL1();
11247e81b07cSAndy Kosela if (put_sbuf_line(buf) == NULL ||
11257e81b07cSAndy Kosela push_undo_stack(UADD, current_addr, current_addr) == NULL) {
11267e81b07cSAndy Kosela SPL0();
11277e81b07cSAndy Kosela return ERR;
11287e81b07cSAndy Kosela }
11297e81b07cSAndy Kosela modified = 1;
11307e81b07cSAndy Kosela SPL0();
11317e81b07cSAndy Kosela return 0;
11327e81b07cSAndy Kosela }
11337e81b07cSAndy Kosela
11347e81b07cSAndy Kosela
11357e81b07cSAndy Kosela /* move_lines: move a range of lines */
11367e81b07cSAndy Kosela int
move_lines(long addr)11377e81b07cSAndy Kosela move_lines(long addr)
11387e81b07cSAndy Kosela {
11397e81b07cSAndy Kosela line_t *b1, *a1, *b2, *a2;
11407e81b07cSAndy Kosela long n = INC_MOD(second_addr, addr_last);
11417e81b07cSAndy Kosela long p = first_addr - 1;
11427e81b07cSAndy Kosela int done = (addr == first_addr - 1 || addr == second_addr);
11437e81b07cSAndy Kosela
11447e81b07cSAndy Kosela SPL1();
11457e81b07cSAndy Kosela if (done) {
11467e81b07cSAndy Kosela a2 = get_addressed_line_node(n);
11477e81b07cSAndy Kosela b2 = get_addressed_line_node(p);
11487e81b07cSAndy Kosela current_addr = second_addr;
11497e81b07cSAndy Kosela } else if (push_undo_stack(UMOV, p, n) == NULL ||
11507e81b07cSAndy Kosela push_undo_stack(UMOV, addr, INC_MOD(addr, addr_last)) == NULL) {
11517e81b07cSAndy Kosela SPL0();
11527e81b07cSAndy Kosela return ERR;
11537e81b07cSAndy Kosela } else {
11547e81b07cSAndy Kosela a1 = get_addressed_line_node(n);
11557e81b07cSAndy Kosela if (addr < first_addr) {
11567e81b07cSAndy Kosela b1 = get_addressed_line_node(p);
11577e81b07cSAndy Kosela b2 = get_addressed_line_node(addr);
11587e81b07cSAndy Kosela /* this get_addressed_line_node last! */
11597e81b07cSAndy Kosela } else {
11607e81b07cSAndy Kosela b2 = get_addressed_line_node(addr);
11617e81b07cSAndy Kosela b1 = get_addressed_line_node(p);
11627e81b07cSAndy Kosela /* this get_addressed_line_node last! */
11637e81b07cSAndy Kosela }
11647e81b07cSAndy Kosela a2 = b2->q_forw;
11657e81b07cSAndy Kosela REQUE(b2, b1->q_forw);
11667e81b07cSAndy Kosela REQUE(a1->q_back, a2);
11677e81b07cSAndy Kosela REQUE(b1, a1);
11687e81b07cSAndy Kosela current_addr = addr + ((addr < first_addr) ?
11697e81b07cSAndy Kosela second_addr - first_addr + 1 : 0);
11707e81b07cSAndy Kosela }
11717e81b07cSAndy Kosela if (isglobal)
11727e81b07cSAndy Kosela unset_active_nodes(b2->q_forw, a2);
11737e81b07cSAndy Kosela modified = 1;
11747e81b07cSAndy Kosela SPL0();
11757e81b07cSAndy Kosela return 0;
11767e81b07cSAndy Kosela }
11777e81b07cSAndy Kosela
11787e81b07cSAndy Kosela
11797e81b07cSAndy Kosela /* copy_lines: copy a range of lines; return status */
11807e81b07cSAndy Kosela int
copy_lines(long addr)11817e81b07cSAndy Kosela copy_lines(long addr)
11827e81b07cSAndy Kosela {
11837e81b07cSAndy Kosela line_t *lp, *np = get_addressed_line_node(first_addr);
11847e81b07cSAndy Kosela undo_t *up = NULL;
11857e81b07cSAndy Kosela long n = second_addr - first_addr + 1;
11867e81b07cSAndy Kosela long m = 0;
11877e81b07cSAndy Kosela
11887e81b07cSAndy Kosela current_addr = addr;
11897e81b07cSAndy Kosela if (first_addr <= addr && addr < second_addr) {
11907e81b07cSAndy Kosela n = addr - first_addr + 1;
11917e81b07cSAndy Kosela m = second_addr - addr;
11927e81b07cSAndy Kosela }
11937e81b07cSAndy Kosela for (; n > 0; n=m, m=0, np = get_addressed_line_node(current_addr + 1))
11947e81b07cSAndy Kosela for (; n-- > 0; np = np->q_forw) {
11957e81b07cSAndy Kosela SPL1();
11967e81b07cSAndy Kosela if ((lp = dup_line_node(np)) == NULL) {
11977e81b07cSAndy Kosela SPL0();
11987e81b07cSAndy Kosela return ERR;
11997e81b07cSAndy Kosela }
12007e81b07cSAndy Kosela add_line_node(lp);
12017e81b07cSAndy Kosela if (up)
12027e81b07cSAndy Kosela up->t = lp;
12037e81b07cSAndy Kosela else if ((up = push_undo_stack(UADD, current_addr,
12047e81b07cSAndy Kosela current_addr)) == NULL) {
12057e81b07cSAndy Kosela SPL0();
12067e81b07cSAndy Kosela return ERR;
12077e81b07cSAndy Kosela }
12087e81b07cSAndy Kosela modified = 1;
12097e81b07cSAndy Kosela SPL0();
12107e81b07cSAndy Kosela }
12117e81b07cSAndy Kosela return 0;
12127e81b07cSAndy Kosela }
12137e81b07cSAndy Kosela
12147e81b07cSAndy Kosela
12157e81b07cSAndy Kosela /* delete_lines: delete a range of lines */
12167e81b07cSAndy Kosela int
delete_lines(long from,long to)12177e81b07cSAndy Kosela delete_lines(long from, long to)
12187e81b07cSAndy Kosela {
12197e81b07cSAndy Kosela line_t *n, *p;
12207e81b07cSAndy Kosela
12217e81b07cSAndy Kosela SPL1();
12227e81b07cSAndy Kosela if (push_undo_stack(UDEL, from, to) == NULL) {
12237e81b07cSAndy Kosela SPL0();
12247e81b07cSAndy Kosela return ERR;
12257e81b07cSAndy Kosela }
12267e81b07cSAndy Kosela n = get_addressed_line_node(INC_MOD(to, addr_last));
12277e81b07cSAndy Kosela p = get_addressed_line_node(from - 1);
12287e81b07cSAndy Kosela /* this get_addressed_line_node last! */
12297e81b07cSAndy Kosela if (isglobal)
12307e81b07cSAndy Kosela unset_active_nodes(p->q_forw, n);
12317e81b07cSAndy Kosela REQUE(p, n);
12327e81b07cSAndy Kosela addr_last -= to - from + 1;
12337e81b07cSAndy Kosela current_addr = from - 1;
12347e81b07cSAndy Kosela modified = 1;
12357e81b07cSAndy Kosela SPL0();
12367e81b07cSAndy Kosela return 0;
12377e81b07cSAndy Kosela }
12387e81b07cSAndy Kosela
12397e81b07cSAndy Kosela
12407e81b07cSAndy Kosela /* display_lines: print a range of lines to stdout */
12417e81b07cSAndy Kosela int
display_lines(long from,long to,int gflag)12427e81b07cSAndy Kosela display_lines(long from, long to, int gflag)
12437e81b07cSAndy Kosela {
12447e81b07cSAndy Kosela line_t *bp;
12457e81b07cSAndy Kosela line_t *ep;
12467e81b07cSAndy Kosela char *s;
12477e81b07cSAndy Kosela
12487e81b07cSAndy Kosela if (!from) {
12490a6a1f1dSLionel Sambuc seterrmsg("invalid address");
12507e81b07cSAndy Kosela return ERR;
12517e81b07cSAndy Kosela }
12527e81b07cSAndy Kosela ep = get_addressed_line_node(INC_MOD(to, addr_last));
12537e81b07cSAndy Kosela bp = get_addressed_line_node(from);
12547e81b07cSAndy Kosela for (; bp != ep; bp = bp->q_forw) {
12557e81b07cSAndy Kosela if ((s = get_sbuf_line(bp)) == NULL)
12567e81b07cSAndy Kosela return ERR;
12577e81b07cSAndy Kosela if (put_tty_line(s, bp->len, current_addr = from++, gflag) < 0)
12587e81b07cSAndy Kosela return ERR;
12597e81b07cSAndy Kosela }
12607e81b07cSAndy Kosela return 0;
12617e81b07cSAndy Kosela }
12627e81b07cSAndy Kosela
12637e81b07cSAndy Kosela
12647e81b07cSAndy Kosela #define MAXMARK 26 /* max number of marks */
12657e81b07cSAndy Kosela
12667e81b07cSAndy Kosela line_t *mark[MAXMARK]; /* line markers */
12677e81b07cSAndy Kosela int markno; /* line marker count */
12687e81b07cSAndy Kosela
12697e81b07cSAndy Kosela /* mark_line_node: set a line node mark */
12707e81b07cSAndy Kosela int
mark_line_node(line_t * lp,int n)12717e81b07cSAndy Kosela mark_line_node(line_t *lp, int n)
12727e81b07cSAndy Kosela {
12737e81b07cSAndy Kosela if (!islower(n)) {
12740a6a1f1dSLionel Sambuc seterrmsg("invalid mark character");
12757e81b07cSAndy Kosela return ERR;
12767e81b07cSAndy Kosela } else if (mark[n - 'a'] == NULL)
12777e81b07cSAndy Kosela markno++;
12787e81b07cSAndy Kosela mark[n - 'a'] = lp;
12797e81b07cSAndy Kosela return 0;
12807e81b07cSAndy Kosela }
12817e81b07cSAndy Kosela
12827e81b07cSAndy Kosela
12837e81b07cSAndy Kosela /* get_marked_node_addr: return address of a marked line */
12847e81b07cSAndy Kosela long
get_marked_node_addr(int n)12857e81b07cSAndy Kosela get_marked_node_addr(int n)
12867e81b07cSAndy Kosela {
12877e81b07cSAndy Kosela if (!islower(n)) {
12880a6a1f1dSLionel Sambuc seterrmsg("invalid mark character");
12897e81b07cSAndy Kosela return ERR;
12907e81b07cSAndy Kosela }
12917e81b07cSAndy Kosela return get_line_node_addr(mark[n - 'a']);
12927e81b07cSAndy Kosela }
12937e81b07cSAndy Kosela
12947e81b07cSAndy Kosela
12957e81b07cSAndy Kosela /* unmark_line_node: clear line node mark */
12967e81b07cSAndy Kosela void
unmark_line_node(line_t * lp)12977e81b07cSAndy Kosela unmark_line_node(line_t *lp)
12987e81b07cSAndy Kosela {
12997e81b07cSAndy Kosela int i;
13007e81b07cSAndy Kosela
13017e81b07cSAndy Kosela for (i = 0; markno && i < MAXMARK; i++)
13027e81b07cSAndy Kosela if (mark[i] == lp) {
13037e81b07cSAndy Kosela mark[i] = NULL;
13047e81b07cSAndy Kosela markno--;
13057e81b07cSAndy Kosela }
13067e81b07cSAndy Kosela }
13077e81b07cSAndy Kosela
13087e81b07cSAndy Kosela
13097e81b07cSAndy Kosela /* dup_line_node: return a pointer to a copy of a line node */
13107e81b07cSAndy Kosela line_t *
dup_line_node(line_t * lp)13117e81b07cSAndy Kosela dup_line_node(line_t *lp)
13127e81b07cSAndy Kosela {
13137e81b07cSAndy Kosela line_t *np;
13147e81b07cSAndy Kosela
13157e81b07cSAndy Kosela if ((np = (line_t *) malloc(sizeof(line_t))) == NULL) {
13167e81b07cSAndy Kosela fprintf(stderr, "%s\n", strerror(errno));
13170a6a1f1dSLionel Sambuc seterrmsg("out of memory");
13187e81b07cSAndy Kosela return NULL;
13197e81b07cSAndy Kosela }
13207e81b07cSAndy Kosela np->seek = lp->seek;
13217e81b07cSAndy Kosela np->len = lp->len;
13227e81b07cSAndy Kosela return np;
13237e81b07cSAndy Kosela }
13247e81b07cSAndy Kosela
13257e81b07cSAndy Kosela
13267e81b07cSAndy Kosela /* has_trailing_escape: return the parity of escapes preceding a character
13277e81b07cSAndy Kosela in a string */
13287e81b07cSAndy Kosela int
has_trailing_escape(char * s,char * t)13297e81b07cSAndy Kosela has_trailing_escape(char *s, char *t)
13307e81b07cSAndy Kosela {
13317e81b07cSAndy Kosela return (s == t || *(t - 1) != '\\') ? 0 : !has_trailing_escape(s, t - 1);
13327e81b07cSAndy Kosela }
13337e81b07cSAndy Kosela
13347e81b07cSAndy Kosela
13357e81b07cSAndy Kosela /* strip_escapes: return copy of escaped string of at most length MAXPATHLEN */
13367e81b07cSAndy Kosela char *
strip_escapes(const char * s)13377e81b07cSAndy Kosela strip_escapes(const char *s)
13387e81b07cSAndy Kosela {
13397e81b07cSAndy Kosela static char *file = NULL;
13407e81b07cSAndy Kosela static int filesz = 0;
13417e81b07cSAndy Kosela
13427e81b07cSAndy Kosela int i = 0;
13437e81b07cSAndy Kosela
13447e81b07cSAndy Kosela REALLOC(file, filesz, MAXPATHLEN + 1, NULL);
13457e81b07cSAndy Kosela while ((i < (filesz - 1)) &&
13467e81b07cSAndy Kosela (file[i++] = (*s == '\\') != '\0' ? *++s : *s))
13477e81b07cSAndy Kosela s++;
13487e81b07cSAndy Kosela file[filesz - 1] = '\0';
13497e81b07cSAndy Kosela return file;
13507e81b07cSAndy Kosela }
13517e81b07cSAndy Kosela
13527e81b07cSAndy Kosela
13537e81b07cSAndy Kosela void
signal_hup(int signo)13547e81b07cSAndy Kosela signal_hup(int signo)
13557e81b07cSAndy Kosela {
13567e81b07cSAndy Kosela if (mutex)
13577e81b07cSAndy Kosela sigflags |= (1 << (signo - 1));
13587e81b07cSAndy Kosela else handle_hup(signo);
13597e81b07cSAndy Kosela }
13607e81b07cSAndy Kosela
13617e81b07cSAndy Kosela
13627e81b07cSAndy Kosela void
signal_int(int signo)13637e81b07cSAndy Kosela signal_int(int signo)
13647e81b07cSAndy Kosela {
13657e81b07cSAndy Kosela if (mutex)
13667e81b07cSAndy Kosela sigflags |= (1 << (signo - 1));
13677e81b07cSAndy Kosela else handle_int(signo);
13687e81b07cSAndy Kosela }
13697e81b07cSAndy Kosela
13707e81b07cSAndy Kosela
13717e81b07cSAndy Kosela void
handle_hup(int signo)13727e81b07cSAndy Kosela handle_hup(int signo)
13737e81b07cSAndy Kosela {
13747e81b07cSAndy Kosela char *hup = NULL; /* hup filename */
13757e81b07cSAndy Kosela char *s;
13767e81b07cSAndy Kosela int n;
13777e81b07cSAndy Kosela
13787e81b07cSAndy Kosela if (!sigactive)
13797e81b07cSAndy Kosela quit(1);
13807e81b07cSAndy Kosela sigflags &= ~(1 << (signo - 1));
13817e81b07cSAndy Kosela if (addr_last && write_file("ed.hup", "w", 1, addr_last) < 0 &&
13827e81b07cSAndy Kosela (s = getenv("HOME")) != NULL &&
13837e81b07cSAndy Kosela (n = strlen(s)) + 8 <= MAXPATHLEN && /* "ed.hup" + '/' */
13847e81b07cSAndy Kosela (hup = (char *) malloc(n + 10)) != NULL) {
13857e81b07cSAndy Kosela strcpy(hup, s);
13867e81b07cSAndy Kosela if (hup[n - 1] != '/')
13877e81b07cSAndy Kosela hup[n] = '/', hup[n+1] = '\0';
13887e81b07cSAndy Kosela strcat(hup, "ed.hup");
13897e81b07cSAndy Kosela write_file(hup, "w", 1, addr_last);
13907e81b07cSAndy Kosela }
13917e81b07cSAndy Kosela quit(2);
13927e81b07cSAndy Kosela }
13937e81b07cSAndy Kosela
13947e81b07cSAndy Kosela
13957e81b07cSAndy Kosela void
handle_int(int signo)13967e81b07cSAndy Kosela handle_int(int signo)
13977e81b07cSAndy Kosela {
13987e81b07cSAndy Kosela if (!sigactive)
13997e81b07cSAndy Kosela quit(1);
14007e81b07cSAndy Kosela sigflags &= ~(1 << (signo - 1));
14017e81b07cSAndy Kosela #ifdef _POSIX_SOURCE
14027e81b07cSAndy Kosela siglongjmp(env, -1);
14037e81b07cSAndy Kosela #else
14047e81b07cSAndy Kosela longjmp(env, -1);
14057e81b07cSAndy Kosela #endif
14067e81b07cSAndy Kosela }
14077e81b07cSAndy Kosela
14087e81b07cSAndy Kosela
14097e81b07cSAndy Kosela int cols = 72; /* wrap column */
14107e81b07cSAndy Kosela
14117e81b07cSAndy Kosela void
handle_winch(int signo)14127e81b07cSAndy Kosela handle_winch(int signo)
14137e81b07cSAndy Kosela {
14147e81b07cSAndy Kosela struct winsize ws; /* window size structure */
14157e81b07cSAndy Kosela
14167e81b07cSAndy Kosela sigflags &= ~(1 << (signo - 1));
14177e81b07cSAndy Kosela if (ioctl(0, TIOCGWINSZ, (char *) &ws) >= 0) {
14187e81b07cSAndy Kosela if (ws.ws_row > 2) rows = ws.ws_row - 2;
14197e81b07cSAndy Kosela if (ws.ws_col > 8) cols = ws.ws_col - 8;
14207e81b07cSAndy Kosela }
14217e81b07cSAndy Kosela }
14227e81b07cSAndy Kosela
14237e81b07cSAndy Kosela
14247e81b07cSAndy Kosela /* is_legal_filename: return a legal filename */
14257e81b07cSAndy Kosela int
is_legal_filename(char * s)14267e81b07cSAndy Kosela is_legal_filename(char *s)
14277e81b07cSAndy Kosela {
14287e81b07cSAndy Kosela if (red && (*s == '!' || !strcmp(s, "..") || strchr(s, '/'))) {
14290a6a1f1dSLionel Sambuc seterrmsg("shell access restricted");
14307e81b07cSAndy Kosela return 0;
14317e81b07cSAndy Kosela }
14327e81b07cSAndy Kosela return 1;
14337e81b07cSAndy Kosela }
1434