new version of ed taken from sash
No binary (build failed)
—
(log yok)
| @@ -59,3385 +59,1453 @@ Index: include/applets.h | |
| #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS) | |
| APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER) | |
| #endif | |
| - | --- /dev/null 2005-04-22 11:15:01.120978184 -0400 |
| - | +++ editors/ed.c 2005-04-22 11:16:00.000000000 -0400 |
| - | @@ -0,0 +1,3120 @@ |
| - | +/* main.c: This file contains the main control and user-interface routines |
| - | + for the ed line editor. */ |
| - | +/* ed line editor. |
| - | + Copyright (C) 1993, 1994 Andrew Moore, Talke Studio |
| - | + All Rights Reserved |
| - | + |
| - | + This program is free software; you can redistribute it and/or modify |
| - | + it under the terms of the GNU General Public License as published by |
| - | + the Free Software Foundation; either version 2, or (at your option) |
| - | + any later version. |
| - | + |
| - | + This program is distributed in the hope that it will be useful, but |
| - | + WITHOUT ANY WARRANTY; without even the implied warranty of |
| - | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| - | + General Public License for more details. |
| - | + |
| - | + You should have received a copy of the GNU General Public License |
| - | + along with this program; if not, write to the Free Software |
| - | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| - | +*/ |
| - | + |
| + | --- /dev/null 2005-04-24 01:00:01.350003056 -0400 |
| + | +++ editors/ed.c 2005-04-24 01:15:09.000000000 -0400 |
| + | @@ -0,0 +1,1447 @@ |
| +/* | |
| - | + * CREDITS |
| - | + * |
| - | + * This program is based on the editor algorithm described in |
| - | + * Brian W. Kernighan and P. J. Plauger's book "Software Tools |
| - | + * in Pascal," Addison-Wesley, 1981. |
| - | + * |
| - | + * The buffering algorithm is attributed to Rodney Ruddock of |
| - | + * the University of Guelph, Guelph, Ontario. |
| + | + * Copyright (c) 2002 by David I. Bell |
| + | + * Permission is granted to use, distribute, or modify this source, |
| + | + * provided that this copyright notice remains intact. |
| + * | |
| + | + * The "ed" built-in command (much simplified) |
| + */ | |
| + | |
| - | +#include <errno.h> |
| - | +#include <limits.h> |
| - | +#include <signal.h> |
| - | +#include <stdlib.h> |
| +#include <stdio.h> | |
| + | +#include <stdlib.h> |
| + | +#include <unistd.h> |
| + | +#include <fcntl.h> |
| +#include <string.h> | |
| + | +#include <memory.h> |
| + | +#include <time.h> |
| +#include <ctype.h> | |
| - | +#include <setjmp.h> |
| - | +#include <pwd.h> |
| - | +#include <unistd.h> |
| - | +#include <sys/types.h> |
| - | +#include <sys/stat.h> |
| - | +#include <sys/file.h> |
| - | +#include <sys/ioctl.h> |
| - | + |
| - | +#include "busybox.h" |
| - | +#include "ed.h" |
| - | +#include "getopt.h" |
| - | + |
| - | +jmp_buf env; |
| - | + |
| - | +/* static buffers */ |
| - | +char *errmsg; /* error message buffer */ |
| - | +char stdinbuf[1]; /* stdin buffer */ |
| - | +char *shcmd; /* shell command buffer */ |
| - | +int shcmdsz; /* shell command buffer size */ |
| - | +int shcmdi; /* shell command buffer index */ |
| - | +char *ibuf; /* ed command-line buffer */ |
| - | +int ibufsz; /* ed command-line buffer size */ |
| - | +char *ibufp; /* pointer to ed command-line buffer */ |
| - | + |
| - | +/* global flags */ |
| - | +int traditional = 0; /* if set, be backwards compatible */ |
| - | +int garrulous = 0; /* if set, print all error messages */ |
| - | +int isbinary; /* if set, buffer contains ASCII NULs */ |
| - | +int isglobal; /* if set, doing a global command */ |
| - | +int modified; /* if set, buffer modified since last write */ |
| - | +int mutex = 0; /* if set, signals set "sigflags" */ |
| - | +int red = 0; /* if set, restrict shell/directory access */ |
| - | +int scripted = 0; /* if set, suppress diagnostics */ |
| - | +int sigactive = 0; /* if set, signal handlers are enabled */ |
| - | +int sigflags = 0; /* if set, signals received while mutex set */ |
| - | + |
| - | +char *old_filename; /* default filename */ |
| - | +long current_addr; /* current address in editor buffer */ |
| - | +long addr_last; /* last address in editor buffer */ |
| - | +int lineno; /* script line number */ |
| - | +char *prompt; /* command-line prompt */ |
| - | +char *dps = "*"; /* default command-line prompt */ |
| - | +long err_status = 0; /* program exit status */ |
| - | + |
| - | +/* The name this program was run with. */ |
| - | +char *program_name; |
| - | + |
| - | +/* If non-zero, display usage information and exit. */ |
| - | +int show_help = 0; |
| - | + |
| - | +/* If non-zero, print the version on standard output and exit. */ |
| - | +int show_version = 0; |
| - | + |
| - | +/* Long options equivalences. */ |
| - | +struct option long_options[] = |
| + | +#include <sys/param.h> |
| + | +#include <malloc.h> |
| + | +//#include "sash.h" |
| + | + |
| + | +#define USERSIZE 1024 /* max line length typed in by user */ |
| + | +#define INITBUF_SIZE 1024 /* initial buffer size */ |
| + | + |
| + | +typedef int BOOL; |
| + | + |
| + | +#define FALSE ((BOOL) 0) |
| + | +#define TRUE ((BOOL) 1) |
| + | + |
| + | +#define isBlank(ch) (((ch) == ' ') || ((ch) == '\t')) |
| + | +#define isDecimal(ch) (((ch) >= '0') && ((ch) <= '9')) |
| + | + |
| + | +#define STDOUT 1 |
| + | + |
| + | +typedef int NUM; |
| + | +typedef int LEN; |
| + | + |
| + | +typedef struct LINE LINE; |
| + | + |
| + | +struct LINE |
| +{ | |
| - | + {"help", no_argument, &show_help, 1}, |
| - | + {"prompt", required_argument, NULL, 'p'}, |
| - | + {"quiet", no_argument, NULL, 's'}, |
| - | + {"silent", no_argument, NULL, 's'}, |
| - | + {"traditional", no_argument, NULL, 'G'}, |
| - | + {"version", no_argument, &show_version, 1}, |
| - | + {0, 0, 0, 0}, |
| + | + LINE * next; |
| + | + LINE * prev; |
| + | + LEN len; |
| + | + char data[1]; |
| +}; | |
| + | |
| - | +extern int optind; |
| - | +extern char *optarg; |
| + | |
| - | +/* usage: explain usage */ |
| + | +static LINE lines; |
| + | +static LINE * curLine; |
| + | +static NUM curNum; |
| + | +static NUM lastNum; |
| + | +static NUM marks[26]; |
| + | +static BOOL dirty; |
| + | +static char * fileName; |
| + | +static char searchString[USERSIZE]; |
| + | + |
| + | +static char * bufBase; |
| + | +static char * bufPtr; |
| + | +static LEN bufUsed; |
| + | +static LEN bufSize; |
| + | + |
| + | + |
| + | +static void doCommands(void); |
| + | +static void subCommand(const char * cmd, NUM num1, NUM num2); |
| + | +static BOOL getNum(const char ** retcp, BOOL * retHaveNum, NUM * retNum); |
| + | +static BOOL setCurNum(NUM num); |
| + | +static BOOL initEdit(void); |
| + | +static void termEdit(void); |
| + | +static void addLines(NUM num); |
| + | +static BOOL insertLine(NUM num, const char * data, LEN len); |
| + | +static BOOL deleteLines(NUM num1, NUM num2); |
| + | +static BOOL printLines(NUM num1, NUM num2, BOOL expandFlag); |
| + | +static BOOL writeLines(const char * file, NUM num1, NUM num2); |
| + | +static BOOL readLines(const char * file, NUM num); |
| + | +static NUM searchLines(const char * str, NUM num1, NUM num2); |
| + | +static LINE * findLine(NUM num); |
| + | + |
| + | +static LEN findString |
| + | + (const LINE * lp, const char * str, LEN len, LEN offset); |
| + | + |
| + | |
| - | +#if 0 |
| +void | |
| - | +usage (status) |
| - | + int status; |
| + | +ed_main(int argc, const char ** argv) |
| +{ | |
| - | + if (status != 0) |
| - | + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); |
| - | + else |
| - | + { |
| - | + printf ("Usage: %s [OPTION]... [FILE]\n", program_name); |
| - | + printf ("\ |
| - | +\n\ |
| - | + -G, --traditional use a few backward compatible features\n\ |
| - | + -p, --prompt=STRING use STRING as an interactive prompt\n\ |
| - | + -s, -, --quiet, --silent suppress diagnostics\n"); |
| - | + printf ("\ |
| - | + --help display this help\n\ |
| - | + --version output version information\n\ |
| - | +\n\ |
| - | +Start edit by reading in FILE if given. Read output of shell command\n\ |
| - | +if FILE begins with a `!'.\n"); |
| - | + } |
| - | + exit (status); |
| - | +} |
| - | +#endif |
| - | +#define usage(x) bb_show_usage() |
| - | + |
| + | + if (!initEdit()) |
| + | + return; |
| + | |
| - | +/* ed: line editor */ |
| - | +int |
| - | +ed_main (int argc, char **argv) |
| - | +{ |
| - | + int c, n; |
| - | + long status = 0; |
| - | + |
| - | + program_name = argv[0]; |
| - | + red = (n = strlen (argv[0])) > 2 && argv[0][n - 3] == 'r'; |
| - | +top: |
| - | + while ((c = getopt_long (argc, argv, "Gp:s", long_options, NULL)) != EOF) |
| - | + switch (c) |
| - | + { |
| - | + default: |
| - | + usage (1); |
| - | + case 0: |
| - | + break; |
| - | + case 'G': /* backward compatibility */ |
| - | + traditional = 1; |
| - | + break; |
| - | + case 'p': /* set prompt */ |
| - | + prompt = optarg; |
| - | + break; |
| - | + case 's': /* run script */ |
| - | + scripted = 1; |
| - | + break; |
| - | + } |
| - | + if (show_help) |
| - | + usage (0); |
| - | + argv += optind; |
| - | + argc -= optind; |
| - | + if (argc && **argv == '-') |
| - | + { |
| - | + scripted = 1; |
| - | + if (argc > 1) |
| - | + { |
| - | + optind = 0; |
| - | + goto top; |
| - | + } |
| - | + argv++; |
| - | + argc--; |
| - | + } |
| - | + init_buffers (); |
| - | + |
| - | + /* assert: reliable signals! */ |
| - | +#ifdef SIGWINCH |
| - | + handle_winch (SIGWINCH); |
| - | + if (isatty (0)) |
| - | + reliable_signal (SIGWINCH, handle_winch); |
| - | +#endif |
| - | + reliable_signal (SIGHUP, signal_hup); |
| - | + reliable_signal (SIGQUIT, SIG_IGN); |
| - | + reliable_signal (SIGINT, signal_int); |
| - | + if ((status = setjmp (env))) |
| - | + { |
| - | + fputs ("\n?\n", stderr); |
| - | + sprintf (errmsg, "Interrupt"); |
| - | + } |
| - | + else |
| - | + { |
| - | + sigactive = 1; /* enable signal handlers */ |
| - | + if (argc && **argv && is_legal_filename (*argv)) |
| - | + { |
| - | + if (read_file (*argv, 0) < 0 && is_regular_file (0)) |
| - | + quit (2); |
| - | + else if (**argv != '!') |
| - | + strcpy (old_filename, *argv); |
| - | + } |
| - | + else if (argc) |
| - | + { |
| - | + fputs ("?\n", stderr); |
| - | + if (**argv == '\0') |
| - | + sprintf (errmsg, "Invalid filename"); |
| - | + if (is_regular_file (0)) |
| - | + quit (2); |
| - | + } |
| - | + } |
| - | + for (;;) |
| - | + { |
| - | + if (status < 0 && garrulous) |
| - | + fprintf (stderr, "%s\n", errmsg); |
| - | + if (prompt) |
| - | + { |
| - | + printf ("%s", prompt); |
| - | + fflush (stdout); |
| - | + } |
| - | + if ((n = get_tty_line ()) < 0) |
| + | + if (argc > 1) |
| + { | |
| - | + status = ERR; |
| - | + continue; |
| - | + } |
| - | + else if (n == 0) |
| - | + { |
| - | + if (modified && !scripted) |
| - | + { |
| - | + fputs ("?\n", stderr); |
| - | + sprintf (errmsg, "Warning: file modified"); |
| - | + if (is_regular_file (0)) |
| + | + fileName = strdup(argv[1]); |
| + | + |
| + | + if (fileName == NULL) |
| + { | |
| - | + fprintf (stderr, garrulous ? |
| - | + "script, line %d: %s\n" : |
| - | + "", lineno, errmsg); |
| - | + quit (2); |
| + | + fprintf(stderr, "No memory\n"); |
| + | + termEdit(); |
| + | + |
| + | + return; |
| + } | |
| - | + clearerr (stdin); |
| - | + modified = 0; |
| - | + status = EMOD; |
| - | + continue; |
| - | + } |
| - | + else |
| - | + quit (err_status); |
| - | + } |
| - | + else if (ibuf[n - 1] != '\n') |
| - | + { |
| - | + /* discard line */ |
| - | + sprintf (errmsg, "Unexpected end-of-file"); |
| - | + clearerr (stdin); |
| - | + status = ERR; |
| - | + continue; |
| - | + } |
| - | + isglobal = 0; |
| - | + if ((status = extract_addr_range ()) >= 0 && |
| - | + (status = exec_command ()) >= 0) |
| - | + if (!status || (status = display_lines (current_addr, current_addr, |
| - | + status)) >= 0) |
| - | + continue; |
| - | + switch (status) |
| - | + { |
| - | + case EOF: |
| - | + quit (err_status); |
| - | + case EMOD: |
| - | + modified = 0; |
| - | + fputs ("?\n", stderr); /* give warning */ |
| - | + sprintf (errmsg, "Warning: file modified"); |
| - | + if (is_regular_file (0)) |
| - | + { |
| - | + fprintf (stderr, garrulous ? |
| - | + "script, line %d: %s\n" : |
| - | + "", lineno, errmsg); |
| - | + quit (2); |
| - | + } |
| - | + break; |
| - | + case FATAL: |
| - | + if (is_regular_file (0)) |
| - | + fprintf (stderr, garrulous ? |
| - | + "script, line %d: %s\n" : "", |
| - | + lineno, errmsg); |
| - | + else |
| - | + fprintf (stderr, garrulous ? "%s\n" : "", |
| - | + errmsg); |
| - | + quit (3); |
| - | + default: |
| - | + fputs ("?\n", stderr); |
| - | + if (is_regular_file (0)) |
| - | + { |
| - | + fprintf (stderr, garrulous ? |
| - | + "script, line %d: %s\n" : "", |
| - | + lineno, errmsg); |
| - | + quit (4); |
| - | + } |
| - | + break; |
| - | + } |
| - | + err_status = -status; |
| - | + } |
| - | + /*NOTREACHED */ |
| - | +} |
| + | |
| - | +long first_addr, second_addr, addr_cnt; |
| + | + if (!readLines(fileName, 1)) |
| + | + { |
| + | + termEdit(); |
| + | |
| - | +/* extract_addr_range: get line addresses from the command buffer until an |
| - | + illegal address is seen; return status */ |
| - | +int |
| - | +extract_addr_range () |
| - | +{ |
| - | + long addr; |
| - | + |
| - | + addr_cnt = 0; |
| - | + first_addr = second_addr = current_addr; |
| - | + while ((addr = next_addr ()) >= 0) |
| - | + { |
| - | + addr_cnt++; |
| - | + first_addr = second_addr; |
| - | + second_addr = addr; |
| - | + if (*ibufp != ',' && *ibufp != ';') |
| - | + break; |
| - | + else if (*ibufp++ == ';') |
| - | + current_addr = addr; |
| - | + } |
| - | + if ((addr_cnt = min (addr_cnt, 2)) == 1 || second_addr != addr) |
| - | + first_addr = second_addr; |
| - | + return (addr == ERR) ? ERR : 0; |
| - | +} |
| + | + return; |
| + | + } |
| + | |
| + | + if (lastNum) |
| + | + setCurNum(1); |
| + | |
| - | +#define SKIP_BLANKS() \ |
| - | + while (isspace (*ibufp) && *ibufp != '\n') \ |
| - | + ibufp++ |
| - | + |
| - | +#define MUST_BE_FIRST() \ |
| - | + do \ |
| - | + { \ |
| - | + if (!first) \ |
| - | + { \ |
| - | + sprintf (errmsg, "Invalid address"); \ |
| - | + return ERR; \ |
| - | + } \ |
| - | + } \ |
| - | + while (0) |
| - | + |
| - | +/* next_addr: return the next line address in the command buffer */ |
| - | +long |
| - | +next_addr () |
| - | +{ |
| - | + char *hd; |
| - | + long addr = current_addr; |
| - | + long n; |
| - | + int first = 1; |
| - | + int c; |
| - | + |
| - | + SKIP_BLANKS (); |
| - | + for (hd = ibufp;; first = 0) |
| - | + switch (c = *ibufp) |
| - | + { |
| - | + case '+': |
| - | + case '\t': |
| - | + case ' ': |
| - | + case '-': |
| - | + case '^': |
| - | + ibufp++; |
| - | + SKIP_BLANKS (); |
| - | + if (isdigit (*ibufp)) |
| - | + { |
| - | + STRTOL (n, ibufp); |
| - | + addr += (c == '-' || c == '^') ? -n : n; |
| - | + } |
| - | + else if (!isspace (c)) |
| - | + addr += (c == '-' || c == '^') ? -1 : 1; |
| - | + break; |
| - | + case '0': |
| - | + case '1': |
| - | + case '2': |
| - | + case '3': |
| - | + case '4': |
| - | + case '5': |
| - | + case '6': |
| - | + case '7': |
| - | + case '8': |
| - | + case '9': |
| - | + MUST_BE_FIRST (); |
| - | + STRTOL (addr, ibufp); |
| - | + break; |
| - | + case '.': |
| - | + case '$': |
| - | + MUST_BE_FIRST (); |
| - | + ibufp++; |
| - | + addr = (c == '.') ? current_addr : addr_last; |
| - | + break; |
| - | + case '/': |
| - | + case '?': |
| - | + MUST_BE_FIRST (); |
| - | + if ((addr = get_matching_node_addr ( |
| - | + get_compiled_pattern (), c == '/')) < 0) |
| - | + return ERR; |
| - | + else if (c == *ibufp) |
| - | + ibufp++; |
| - | + break; |
| - | + case '\'': |
| - | + MUST_BE_FIRST (); |
| - | + ibufp++; |
| - | + if ((addr = get_marked_node_addr (*ibufp++)) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case '%': |
| - | + case ',': |
| - | + case ';': |
| - | + if (first) |
| - | + { |
| - | + ibufp++; |
| - | + addr_cnt++; |
| - | + second_addr = (c == ';') ? current_addr : 1; |
| - | + addr = addr_last; |
| - | + break; |
| - | + } |
| - | + /* FALL THROUGH */ |
| - | + default: |
| - | + if (ibufp == hd) |
| - | + return EOF; |
| - | + else if (addr < 0 || addr_last < addr) |
| - | + { |
| - | + sprintf (errmsg, "Invalid address"); |
| - | + return ERR; |
| - | + } |
| - | + else |
| - | + return addr; |
| - | + } |
| - | + /* NOTREACHED */ |
| + | + dirty = FALSE; |
| + | + } |
| + | + |
| + | + doCommands(); |
| + | + |
| + | + termEdit(); |
| +} | |
| + | |
| + | |
| - | +/* GET_THIRD_ADDR: get a legal address from the command buffer */ |
| - | +#define GET_THIRD_ADDR(addr) \ |
| - | + do \ |
| - | + { \ |
| - | + long ol1, ol2; \ |
| - | + ol1 = first_addr, ol2 = second_addr; \ |
| - | + if (extract_addr_range () < 0) \ |
| - | + return ERR; \ |
| - | + else if (traditional && addr_cnt == 0) \ |
| - | + { \ |
| - | + sprintf (errmsg, "Destination expected"); \ |
| - | + return ERR; \ |
| - | + } \ |
| - | + else if (second_addr < 0 || addr_last < second_addr) \ |
| - | + { \ |
| - | + sprintf (errmsg, "Invalid address"); \ |
| - | + return ERR; \ |
| - | + } \ |
| - | + (addr) = second_addr; \ |
| - | + first_addr = ol1, second_addr = ol2; \ |
| - | + } \ |
| - | + while (0) |
| - | + |
| - | +/* GET_COMMAND_SUFFIX: verify the command suffix in the command buffer */ |
| - | +#define GET_COMMAND_SUFFIX() \ |
| - | + do \ |
| - | + { \ |
| - | + int done = 0; \ |
| - | + do \ |
| - | + { \ |
| - | + switch (*ibufp) \ |
| - | + { \ |
| - | + case 'p': \ |
| - | + gflag |= GPR, ibufp++; \ |
| - | + break; \ |
| - | + case 'l': \ |
| - | + gflag |= GLS, ibufp++; \ |
| - | + break; \ |
| - | + case 'n': \ |
| - | + gflag |= GNP, ibufp++; \ |
| - | + break; \ |
| - | + default: \ |
| - | + done++; \ |
| - | + } \ |
| - | + } \ |
| - | + while (!done); \ |
| - | + if (*ibufp++ != '\n') \ |
| - | + { \ |
| - | + sprintf (errmsg, "Invalid command suffix"); \ |
| - | + return ERR; \ |
| - | + } \ |
| - | + } \ |
| - | + while (0) |
| - | + |
| - | +/* sflags */ |
| - | +#define SGG 001 /* complement previous global substitute suffix */ |
| - | +#define SGP 002 /* complement previous print suffix */ |
| - | +#define SGR 004 /* use last regex instead of last pat */ |
| - | +#define SGF 010 /* repeat last substitution */ |
| - | + |
| - | +int patlock = 0; /* if set, pattern not freed by get_compiled_pattern() */ |
| - | + |
| - | +long rows = 22; /* scroll length: ws_row - 2 */ |
| - | + |
| - | +/* exec_command: execute the next command in command buffer; return print |
| - | + request, if any */ |
| - | +int |
| - | +exec_command () |
| + | +/* |
| + | + * Read commands until we are told to stop. |
| + | + */ |
| + | +static void |
| + | +doCommands(void) |
| +{ | |
| - | + extern long u_current_addr; |
| - | + extern long u_addr_last; |
| - | + |
| - | + static pattern_t *pat = NULL; |
| - | + static int sgflag = 0; |
| - | + static int sgnum = 0; |
| - | + |
| - | + pattern_t *tpat; |
| - | + char *fnp; |
| - | + int gflag = 0; |
| - | + int sflags = 0; |
| - | + long addr = 0; |
| - | + int n = 0; |
| - | + int c; |
| - | + |
| - | + SKIP_BLANKS (); |
| - | + switch (c = *ibufp++) |
| - | + { |
| - | + case 'a': |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (!isglobal) |
| - | + clear_undo_stack (); |
| - | + if (append_lines (second_addr) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 'c': |
| - | + if (check_addr_range (current_addr, current_addr) < 0) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (!isglobal) |
| - | + clear_undo_stack (); |
| - | + if (delete_lines (first_addr, second_addr) < 0 || |
| - | + append_lines (current_addr) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 'd': |
| - | + if (check_addr_range (current_addr, current_addr) < 0) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (!isglobal) |
| - | + clear_undo_stack (); |
| - | + if (delete_lines (first_addr, second_addr) < 0) |
| - | + return ERR; |
| - | + else if ((addr = INC_MOD (current_addr, addr_last)) != 0) |
| - | + current_addr = addr; |
| - | + break; |
| - | + case 'e': |
| - | + if (modified && !scripted) |
| - | + return EMOD; |
| - | + /* fall through */ |
| - | + case 'E': |
| - | + if (addr_cnt > 0) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected address"); |
| - | + return ERR; |
| - | + } |
| - | + else if (!isspace (*ibufp)) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected command suffix"); |
| - | + return ERR; |
| - | + } |
| - | + else if ((fnp = get_filename ()) == NULL) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (delete_lines (1, addr_last) < 0) |
| - | + return ERR; |
| - | + delete_yank_lines (); |
| - | + clear_undo_stack (); |
| - | + if (close_sbuf () < 0) |
| - | + return ERR; |
| - | + else if (open_sbuf () < 0) |
| - | + return FATAL; |
| - | + if (*fnp && *fnp != '!') |
| - | + strcpy (old_filename, fnp); |
| - | + if (traditional && *fnp == '\0' && *old_filename == '\0') |
| - | + { |
| - | + sprintf (errmsg, "No current filename"); |
| - | + return ERR; |
| - | + } |
| - | + else if (read_file (*fnp ? fnp : old_filename, 0) < 0) |
| - | + return ERR; |
| - | + clear_undo_stack (); |
| - | + modified = 0; |
| - | + u_current_addr = u_addr_last = -1; |
| - | + break; |
| - | + case 'f': |
| - | + if (addr_cnt > 0) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected address"); |
| - | + return ERR; |
| - | + } |
| - | + else if (!isspace (*ibufp)) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected command suffix"); |
| - | + return ERR; |
| - | + } |
| - | + else if ((fnp = get_filename ()) == NULL) |
| - | + return ERR; |
| - | + else if (*fnp == '!') |
| - | + { |
| - | + sprintf (errmsg, "Invalid redirection"); |
| - | + return ERR; |
| - | + } |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (*fnp) |
| - | + strcpy (old_filename, fnp); |
| - | + printf ("%s\n", strip_escapes (old_filename)); |
| - | + break; |
| - | + case 'g': |
| - | + case 'v': |
| - | + case 'G': |
| - | + case 'V': |
| - | + if (isglobal) |
| - | + { |
| - | + sprintf (errmsg, "Cannot nest global commands"); |
| - | + return ERR; |
| - | + } |
| - | + else if (check_addr_range (1, addr_last) < 0) |
| - | + return ERR; |
| - | + else if (build_active_list (c == 'g' || c == 'G') < 0) |
| - | + return ERR; |
| - | + else if ((n = (c == 'G' || c == 'V'))) |
| - | + GET_COMMAND_SUFFIX (); |
| - | + isglobal++; |
| - | + if (exec_global (n, gflag) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 'h': |
| - | + if (addr_cnt > 0) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected address"); |
| - | + return ERR; |
| - | + } |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (*errmsg) |
| - | + fprintf (stderr, "%s\n", errmsg); |
| - | + break; |
| - | + case 'H': |
| - | + if (addr_cnt > 0) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected address"); |
| - | + return ERR; |
| - | + } |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if ((garrulous = 1 - garrulous) && *errmsg) |
| - | + fprintf (stderr, "%s\n", errmsg); |
| - | + break; |
| - | + case 'i': |
| - | + if (second_addr == 0) |
| - | + { |
| - | + sprintf (errmsg, "Invalid address"); |
| - | + return ERR; |
| - | + } |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (!isglobal) |
| - | + clear_undo_stack (); |
| - | + if (append_lines (second_addr - 1) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 'j': |
| - | + if (check_addr_range (current_addr, current_addr + 1) < 0) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (!isglobal) |
| - | + clear_undo_stack (); |
| - | + if (first_addr != second_addr && |
| - | + join_lines (first_addr, second_addr) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 'k': |
| - | + c = *ibufp++; |
| - | + if (second_addr == 0) |
| - | + { |
| - | + sprintf (errmsg, "Invalid address"); |
| - | + return ERR; |
| - | + } |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (mark_line_node (get_addressed_line_node (second_addr), c) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 'l': |
| - | + if (check_addr_range (current_addr, current_addr) < 0) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (display_lines (first_addr, second_addr, gflag | GLS) < 0) |
| - | + return ERR; |
| - | + gflag = 0; |
| - | + break; |
| - | + case 'm': |
| - | + if (check_addr_range (current_addr, current_addr) < 0) |
| - | + return ERR; |
| - | + GET_THIRD_ADDR (addr); |
| - | + if (first_addr <= addr && addr < second_addr) |
| - | + { |
| - | + sprintf (errmsg, "Invalid destination"); |
| - | + return ERR; |
| - | + } |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (!isglobal) |
| - | + clear_undo_stack (); |
| - | + if (move_lines (addr) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 'n': |
| - | + if (check_addr_range (current_addr, current_addr) < 0) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (display_lines (first_addr, second_addr, gflag | GNP) < 0) |
| - | + return ERR; |
| - | + gflag = 0; |
| - | + break; |
| - | + case 'p': |
| - | + if (check_addr_range (current_addr, current_addr) < 0) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (display_lines (first_addr, second_addr, gflag | GPR) < 0) |
| - | + return ERR; |
| - | + gflag = 0; |
| - | + break; |
| - | + case 'P': |
| - | + if (addr_cnt > 0) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected address"); |
| - | + return ERR; |
| - | + } |
| - | + GET_COMMAND_SUFFIX (); |
| - | + prompt = prompt ? NULL : optarg ? optarg : dps; |
| - | + break; |
| - | + case 'q': |
| - | + case 'Q': |
| - | + if (addr_cnt > 0) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected address"); |
| - | + return ERR; |
| - | + } |
| - | + GET_COMMAND_SUFFIX (); |
| - | + gflag = (modified && !scripted && c == 'q') ? EMOD : EOF; |
| - | + break; |
| - | + case 'r': |
| - | + if (!isspace (*ibufp)) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected command suffix"); |
| - | + return ERR; |
| - | + } |
| - | + else if (addr_cnt == 0) |
| - | + second_addr = addr_last; |
| - | + if ((fnp = get_filename ()) == NULL) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (!isglobal) |
| - | + clear_undo_stack (); |
| - | + if (*old_filename == '\0' && *fnp != '!') |
| - | + strcpy (old_filename, fnp); |
| - | + if (traditional && *fnp == '\0' && *old_filename == '\0') |
| - | + { |
| - | + sprintf (errmsg, "No current filename"); |
| - | + return ERR; |
| - | + } |
| - | + if ((addr = read_file (*fnp ? fnp : old_filename, second_addr)) < 0) |
| - | + return ERR; |
| - | + else if (addr && addr != addr_last) |
| - | + modified = 1; |
| - | + break; |
| - | + case 's': |
| - | + do |
| + | + const char * cp; |
| + | + char * endbuf; |
| + | + char * newname; |
| + | + int len; |
| + | + NUM num1; |
| + | + NUM num2; |
| + | + BOOL have1; |
| + | + BOOL have2; |
| + | + char buf[USERSIZE]; |
| + | + |
| + | + while (TRUE) |
| + { | |
| - | + switch (*ibufp) |
| - | + { |
| - | + case '\n': |
| - | + sflags |= SGF; |
| - | + break; |
| - | + case 'g': |
| - | + sflags |= SGG; |
| - | + ibufp++; |
| - | + break; |
| - | + case 'p': |
| - | + sflags |= SGP; |
| - | + ibufp++; |
| - | + break; |
| - | + case 'r': |
| - | + sflags |= SGR; |
| - | + ibufp++; |
| - | + break; |
| - | + case '0': |
| - | + case '1': |
| - | + case '2': |
| - | + case '3': |
| - | + case '4': |
| - | + case '5': |
| - | + case '6': |
| - | + case '7': |
| - | + case '8': |
| - | + case '9': { |
| - | + long sgnum_long; |
| - | + STRTOL (sgnum_long, ibufp); |
| - | + sgnum = sgnum_long; |
| - | + sflags |= SGF; |
| - | + sgflag &= ~GSG; /* override GSG */ |
| - | + break; |
| + | + printf(": "); |
| + | + fflush(stdout); |
| + | + |
| + | + if (fgets(buf, sizeof(buf), stdin) == NULL) |
| + | + return; |
| + | + |
| + | + len = strlen(buf); |
| + | + |
| + | + if (len == 0) |
| + | + return; |
| + | + |
| + | + endbuf = &buf[len - 1]; |
| + | + |
| + | + if (*endbuf != '\n') |
| + | + { |
| + | + fprintf(stderr, "Command line too long\n"); |
| + | + |
| + | + do |
| + | + { |
| + | + len = fgetc(stdin); |
| + | + } |
| + | + while ((len != EOF) && (len != '\n')); |
| + | + |
| + | + continue; |
| + } | |
| - | + default: |
| - | + if (sflags) |
| + | + |
| + | + while ((endbuf > buf) && isBlank(endbuf[-1])) |
| + | + endbuf--; |
| + | + |
| + | + *endbuf = '\0'; |
| + | + |
| + | + cp = buf; |
| + | + |
| + | + while (isBlank(*cp)) |
| + | + cp++; |
| + | + |
| + | + have1 = FALSE; |
| + | + have2 = FALSE; |
| + | + |
| + | + if ((curNum == 0) && (lastNum > 0)) |
| + { | |
| - | + sprintf (errmsg, "Invalid command suffix"); |
| - | + return ERR; |
| + | + curNum = 1; |
| + | + curLine = lines.next; |
| + } | |
| - | + } |
| - | + } |
| - | + while (sflags && *ibufp != '\n'); |
| - | + if (sflags && !pat) |
| - | + { |
| - | + sprintf (errmsg, "No previous substitution"); |
| - | + return ERR; |
| - | + } |
| - | + else if (sflags & SGG) |
| - | + sgnum = 0; /* override numeric arg */ |
| - | + if (*ibufp != '\n' && *(ibufp + 1) == '\n') |
| - | + { |
| - | + sprintf (errmsg, "Invalid pattern delimiter"); |
| - | + return ERR; |
| - | + } |
| - | + tpat = pat; |
| - | + SPL1 (); |
| - | + if ((!sflags || (sflags & SGR)) && |
| - | + (tpat = get_compiled_pattern ()) == NULL) |
| - | + { |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| - | + else if (tpat != pat) |
| - | + { |
| - | + if (pat) |
| - | + { |
| - | + regfree (pat); |
| - | + free (pat); |
| - | + } |
| - | + pat = tpat; |
| - | + patlock = 1; /* reserve pattern */ |
| - | + } |
| - | + SPL0 (); |
| - | + if (!sflags && extract_subst_tail (&sgflag, &sgnum) < 0) |
| - | + return ERR; |
| - | + else if (isglobal) |
| - | + sgflag |= GLB; |
| - | + else |
| - | + sgflag &= ~GLB; |
| - | + if (sflags & SGG) |
| - | + sgflag ^= GSG; |
| - | + if (sflags & SGP) |
| - | + sgflag ^= GPR, sgflag &= ~(GLS | GNP); |
| - | + do |
| - | + { |
| - | + switch (*ibufp) |
| - | + { |
| - | + case 'p': |
| - | + sgflag |= GPR, ibufp++; |
| - | + break; |
| - | + case 'l': |
| - | + sgflag |= GLS, ibufp++; |
| - | + break; |
| - | + case 'n': |
| - | + sgflag |= GNP, ibufp++; |
| - | + break; |
| - | + default: |
| - | + n++; |
| - | + } |
| - | + } |
| - | + while (!n); |
| - | + if (check_addr_range (current_addr, current_addr) < 0) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (!isglobal) |
| - | + clear_undo_stack (); |
| - | + if (search_and_replace (pat, sgflag, sgnum) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 't': |
| - | + if (check_addr_range (current_addr, current_addr) < 0) |
| - | + return ERR; |
| - | + GET_THIRD_ADDR (addr); |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (!isglobal) |
| - | + clear_undo_stack (); |
| - | + if (copy_lines (addr) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 'u': |
| - | + if (addr_cnt > 0) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected address"); |
| - | + return ERR; |
| - | + } |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (pop_undo_stack () < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 'w': |
| - | + case 'W': |
| - | + if ((n = *ibufp) == 'q' || n == 'Q') |
| - | + { |
| - | + gflag = EOF; |
| - | + ibufp++; |
| - | + } |
| - | + if (!isspace (*ibufp)) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected command suffix"); |
| - | + return ERR; |
| - | + } |
| - | + else if ((fnp = get_filename ()) == NULL) |
| - | + return ERR; |
| - | + if (addr_cnt == 0 && !addr_last) |
| - | + first_addr = second_addr = 0; |
| - | + else if (check_addr_range (1, addr_last) < 0) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (*old_filename == '\0' && *fnp != '!') |
| - | + strcpy (old_filename, fnp); |
| - | + if (traditional && *fnp == '\0' && *old_filename == '\0') |
| - | + { |
| - | + sprintf (errmsg, "No current filename"); |
| - | + return ERR; |
| - | + } |
| - | + if ((addr = write_file (*fnp ? fnp : old_filename, |
| - | + (c == 'W') ? "a" : "w", first_addr, second_addr)) < 0) |
| - | + return ERR; |
| - | + else if (addr == addr_last) |
| - | + modified = 0; |
| - | + else if (modified && !scripted && n == 'q') |
| - | + gflag = EMOD; |
| - | + break; |
| - | + case 'x': |
| - | + if (second_addr < 0 || addr_last < second_addr) |
| - | + { |
| - | + sprintf (errmsg, "Invalid address"); |
| - | + return ERR; |
| - | + } |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (!isglobal) |
| - | + clear_undo_stack (); |
| - | + if (put_lines (second_addr) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 'y': |
| - | + if (check_addr_range (current_addr, current_addr) < 0) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (yank_lines (first_addr, second_addr) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case 'z': |
| - | + if (check_addr_range |
| - | + (first_addr = 1, current_addr + (traditional ? 1 : !isglobal)) < 0) |
| - | + return ERR; |
| - | + else if ('0' < *ibufp && *ibufp <= '9') |
| - | + STRTOL (rows, ibufp); |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (display_lines (second_addr, min (addr_last, |
| - | + second_addr + rows), gflag) < 0) |
| - | + return ERR; |
| - | + gflag = 0; |
| - | + break; |
| - | + case '=': |
| - | + GET_COMMAND_SUFFIX (); |
| - | + printf ("%ld\n", addr_cnt ? second_addr : addr_last); |
| - | + break; |
| - | + case '!': |
| - | + if (addr_cnt > 0) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected address"); |
| - | + return ERR; |
| - | + } |
| - | + else if ((sflags = get_shell_command ()) < 0) |
| - | + return ERR; |
| - | + GET_COMMAND_SUFFIX (); |
| - | + if (sflags) |
| - | + printf ("%s\n", shcmd + 1); |
| - | + system (shcmd + 1); |
| - | + if (!scripted) |
| - | + printf ("!\n"); |
| - | + break; |
| - | + case '\n': |
| - | + if (check_addr_range |
| - | + (first_addr = 1, current_addr + (traditional ? 1 : !isglobal)) < 0 || |
| - | + display_lines (second_addr, second_addr, 0) < 0) |
| - | + return ERR; |
| - | + break; |
| - | + case '#': |
| - | + while (*ibufp++ != '\n') |
| - | + ; |
| - | + break; |
| - | + default: |
| - | + sprintf (errmsg, "Unknown command"); |
| - | + return ERR; |
| - | + } |
| - | + return gflag; |
| - | +} |
| + | |
| + | + if (!getNum(&cp, &have1, &num1)) |
| + | + continue; |
| + | |
| - | +/* check_addr_range: return status of address range check */ |
| - | +int |
| - | +check_addr_range (n, m) |
| - | + long n, m; |
| - | +{ |
| - | + if (addr_cnt == 0) |
| - | + { |
| - | + first_addr = n; |
| - | + second_addr = m; |
| - | + } |
| - | + if (first_addr > second_addr || 1 > first_addr || |
| - | + second_addr > addr_last) |
| - | + { |
| - | + sprintf (errmsg, "Invalid address"); |
| - | + return ERR; |
| - | + } |
| - | + return 0; |
| - | +} |
| + | + while (isBlank(*cp)) |
| + | + cp++; |
| + | |
| + | + if (*cp == ',') |
| + | + { |
| + | + cp++; |
| + | |
| - | +/* get_matching_node_addr: return the address of the next line matching a |
| - | + pattern in a given direction. wrap around begin/end of editor buffer if |
| - | + necessary */ |
| - | +long |
| - | +get_matching_node_addr (pat, dir) |
| - | + pattern_t *pat; |
| - | + int dir; |
| - | +{ |
| - | + char *s; |
| - | + long n = current_addr; |
| - | + line_t *lp; |
| - | + |
| - | + if (!pat) |
| - | + return ERR; |
| - | + do |
| - | + { |
| - | + if ((n = dir ? INC_MOD (n, addr_last) : DEC_MOD (n, addr_last))) |
| - | + { |
| - | + lp = get_addressed_line_node (n); |
| - | + if ((s = get_sbuf_line (lp)) == NULL) |
| - | + return ERR; |
| - | + if (isbinary) |
| - | + NUL_TO_NEWLINE (s, lp->len); |
| - | + if (!regexec (pat, s, 0, NULL, 0)) |
| - | + return n; |
| - | + } |
| - | + } |
| - | + while (n != current_addr); |
| - | + sprintf (errmsg, "No match"); |
| - | + return ERR; |
| - | +} |
| + | + if (!getNum(&cp, &have2, &num2)) |
| + | + continue; |
| + | |
| + | + if (!have1) |
| + | + num1 = 1; |
| + | |
| - | +/* get_filename: return pointer to copy of filename in the command buffer */ |
| - | +char * |
| - | +get_filename () |
| - | +{ |
| - | + static char *file = NULL; |
| - | + static int filesz = 0; |
| + | + if (!have2) |
| + | + num2 = lastNum; |
| + | |
| - | + int n; |
| + | + have1 = TRUE; |
| + | + have2 = TRUE; |
| + | + } |
| + | |
| - | + if (*ibufp != '\n') |
| - | + { |
| - | + SKIP_BLANKS (); |
| - | + if (*ibufp == '\n') |
| - | + { |
| - | + sprintf (errmsg, "Invalid filename"); |
| - | + return NULL; |
| - | + } |
| - | + else if ((ibufp = get_extended_line (&n, 1)) == NULL) |
| - | + return NULL; |
| - | + else if (*ibufp == '!') |
| - | + { |
| - | + ibufp++; |
| - | + if ((n = get_shell_command ()) < 0) |
| - | + return NULL; |
| - | + if (n) |
| - | + printf ("%s\n", shcmd + 1); |
| - | + return shcmd; |
| - | + } |
| - | + else if (n > PATH_MAX) |
| - | + { |
| - | + sprintf (errmsg, "Filename too long"); |
| - | + return NULL; |
| - | + } |
| - | + } |
| - | + else if (!traditional && *old_filename == '\0') |
| - | + { |
| - | + sprintf (errmsg, "No current filename"); |
| - | + return NULL; |
| - | + } |
| - | + REALLOC (file, filesz, PATH_MAX + 1, NULL); |
| - | + for (n = 0; *ibufp != '\n';) |
| - | + file[n++] = *ibufp++; |
| - | + file[n] = '\0'; |
| - | + return is_legal_filename (file) ? file : NULL; |
| - | +} |
| + | + if (!have1) |
| + | + num1 = curNum; |
| + | |
| + | + if (!have2) |
| + | + num2 = num1; |
| + | |
| - | +/* get_shell_command: read a shell command from stdin; return substitution |
| - | + status */ |
| - | +int |
| - | +get_shell_command () |
| - | +{ |
| - | + static char *buf = NULL; |
| - | + static int n = 0; |
| - | + |
| - | + char *s; /* substitution char pointer */ |
| - | + int i = 0; |
| - | + int j = 0; |
| - | + |
| - | + if (red) |
| - | + { |
| - | + sprintf (errmsg, "Shell access restricted"); |
| - | + return ERR; |
| - | + } |
| - | + else if ((s = ibufp = get_extended_line (&j, 1)) == NULL) |
| - | + return ERR; |
| - | + REALLOC (buf, n, j + 1, ERR); |
| - | + buf[i++] = '!'; /* prefix command w/ bang */ |
| - | + while (*ibufp != '\n') |
| - | + switch (*ibufp) |
| - | + { |
| - | + default: |
| - | + REALLOC (buf, n, i + 2, ERR); |
| - | + buf[i++] = *ibufp; |
| - | + if (*ibufp++ == '\\') |
| - | + buf[i++] = *ibufp++; |
| - | + break; |
| - | + case '!': |
| - | + if (s != ibufp) |
| - | + { |
| - | + REALLOC (buf, n, i + 1, ERR); |
| - | + buf[i++] = *ibufp++; |
| - | + } |
| - | + else if (shcmd == NULL || (traditional && *(shcmd + 1) == '\0')) |
| - | + { |
| - | + sprintf (errmsg, "No previous command"); |
| - | + return ERR; |
| - | + } |
| - | + else |
| - | + { |
| - | + REALLOC (buf, n, i + shcmdi, ERR); |
| - | + for (s = shcmd + 1; s < shcmd + shcmdi;) |
| - | + buf[i++] = *s++; |
| - | + s = ibufp++; |
| - | + } |
| - | + break; |
| - | + case '%': |
| - | + if (*old_filename == '\0') |
| - | + { |
| - | + sprintf (errmsg, "No current filename"); |
| - | + return ERR; |
| - | + } |
| - | + j = strlen (s = strip_escapes (old_filename)); |
| - | + REALLOC (buf, n, i + j, ERR); |
| - | + while (j--) |
| - | + buf[i++] = *s++; |
| - | + s = ibufp++; |
| - | + break; |
| - | + } |
| - | + REALLOC (shcmd, shcmdsz, i + 1, ERR); |
| - | + memcpy (shcmd, buf, i); |
| - | + shcmd[shcmdi = i] = '\0'; |
| - | + return *s == '!' || *s == '%'; |
| + | + switch (*cp++) |
| + | + { |
| + | + case 'a': |
| + | + addLines(num1 + 1); |
| + | + break; |
| + | + |
| + | + case 'c': |
| + | + deleteLines(num1, num2); |
| + | + addLines(num1); |
| + | + break; |
| + | + |
| + | + case 'd': |
| + | + deleteLines(num1, num2); |
| + | + break; |
| + | + |
| + | + case 'f': |
| + | + if (*cp && !isBlank(*cp)) |
| + | + { |
| + | + fprintf(stderr, "Bad file command\n"); |
| + | + break; |
| + | + } |
| + | + |
| + | + while (isBlank(*cp)) |
| + | + cp++; |
| + | + |
| + | + if (*cp == '\0') |
| + | + { |
| + | + if (fileName) |
| + | + printf("\"%s\"\n", fileName); |
| + | + else |
| + | + printf("No file name\n"); |
| + | + |
| + | + break; |
| + | + } |
| + | + |
| + | + newname = strdup(cp); |
| + | + |
| + | + if (newname == NULL) |
| + | + { |
| + | + fprintf(stderr, "No memory for file name\n"); |
| + | + break; |
| + | + } |
| + | + |
| + | + if (fileName) |
| + | + free(fileName); |
| + | + |
| + | + fileName = newname; |
| + | + break; |
| + | + |
| + | + case 'i': |
| + | + addLines(num1); |
| + | + break; |
| + | + |
| + | + case 'k': |
| + | + while (isBlank(*cp)) |
| + | + cp++; |
| + | + |
| + | + if ((*cp < 'a') || (*cp > 'a') || cp[1]) |
| + | + { |
| + | + fprintf(stderr, "Bad mark name\n"); |
| + | + break; |
| + | + } |
| + | + |
| + | + marks[*cp - 'a'] = num2; |
| + | + break; |
| + | + |
| + | + case 'l': |
| + | + printLines(num1, num2, TRUE); |
| + | + break; |
| + | + |
| + | + case 'p': |
| + | + printLines(num1, num2, FALSE); |
| + | + break; |
| + | + |
| + | + case 'q': |
| + | + while (isBlank(*cp)) |
| + | + cp++; |
| + | + |
| + | + if (have1 || *cp) |
| + | + { |
| + | + fprintf(stderr, "Bad quit command\n"); |
| + | + break; |
| + | + } |
| + | + |
| + | + if (!dirty) |
| + | + return; |
| + | + |
| + | + printf("Really quit? "); |
| + | + fflush(stdout); |
| + | + |
| + | + buf[0] = '\0'; |
| + | + fgets(buf, sizeof(buf), stdin); |
| + | + cp = buf; |
| + | + |
| + | + while (isBlank(*cp)) |
| + | + cp++; |
| + | + |
| + | + if ((*cp == 'y') || (*cp == 'Y')) |
| + | + return; |
| + | + |
| + | + break; |
| + | + |
| + | + case 'r': |
| + | + if (*cp && !isBlank(*cp)) |
| + | + { |
| + | + fprintf(stderr, "Bad read command\n"); |
| + | + break; |
| + | + } |
| + | + |
| + | + while (isBlank(*cp)) |
| + | + cp++; |
| + | + |
| + | + if (*cp == '\0') |
| + | + { |
| + | + fprintf(stderr, "No file name\n"); |
| + | + break; |
| + | + } |
| + | + |
| + | + if (!have1) |
| + | + num1 = lastNum; |
| + | + |
| + | + if (readLines(cp, num1 + 1)) |
| + | + break; |
| + | + |
| + | + if (fileName == NULL) |
| + | + fileName = strdup(cp); |
| + | + |
| + | + break; |
| + | + |
| + | + case 's': |
| + | + subCommand(cp, num1, num2); |
| + | + break; |
| + | + |
| + | + case 'w': |
| + | + if (*cp && !isBlank(*cp)) |
| + | + { |
| + | + fprintf(stderr, "Bad write command\n"); |
| + | + break; |
| + | + } |
| + | + |
| + | + while (isBlank(*cp)) |
| + | + cp++; |
| + | + |
| + | + if (!have1) { |
| + | + num1 = 1; |
| + | + num2 = lastNum; |
| + | + } |
| + | + |
| + | + if (*cp == '\0') |
| + | + cp = fileName; |
| + | + |
| + | + if (cp == NULL) |
| + | + { |
| + | + fprintf(stderr, "No file name specified\n"); |
| + | + break; |
| + | + } |
| + | + |
| + | + writeLines(cp, num1, num2); |
| + | + break; |
| + | + |
| + | + case 'z': |
| + | + switch (*cp) |
| + | + { |
| + | + case '-': |
| + | + printLines(curNum-21, curNum, FALSE); |
| + | + break; |
| + | + case '.': |
| + | + printLines(curNum-11, curNum+10, FALSE); |
| + | + break; |
| + | + default: |
| + | + printLines(curNum, curNum+21, FALSE); |
| + | + break; |
| + | + } |
| + | + break; |
| + | + |
| + | + case '.': |
| + | + if (have1) |
| + | + { |
| + | + fprintf(stderr, "No arguments allowed\n"); |
| + | + break; |
| + | + } |
| + | + |
| + | + printLines(curNum, curNum, FALSE); |
| + | + break; |
| + | + |
| + | + case '-': |
| + | + if (setCurNum(curNum - 1)) |
| + | + printLines(curNum, curNum, FALSE); |
| + | + |
| + | + break; |
| + | + |
| + | + case '=': |
| + | + printf("%d\n", num1); |
| + | + break; |
| + | + |
| + | + case '\0': |
| + | + if (have1) |
| + | + { |
| + | + printLines(num2, num2, FALSE); |
| + | + break; |
| + | + } |
| + | + |
| + | + if (setCurNum(curNum + 1)) |
| + | + printLines(curNum, curNum, FALSE); |
| + | + |
| + | + break; |
| + | + |
| + | + default: |
| + | + fprintf(stderr, "Unimplemented command\n"); |
| + | + break; |
| + | + } |
| + | + } |
| +} | |
| + | |
| + | |
| - | +/* append_lines: insert text from stdin to after line n; stop when either a |
| - | + single period is read or EOF; return status */ |
| - | +int |
| - | +append_lines (n) |
| - | + long n; |
| + | +/* |
| + | + * Do the substitute command. |
| + | + * The current line is set to the last substitution done. |
| + | + */ |
| + | +static void |
| + | +subCommand(const char * cmd, NUM num1, NUM num2) |
| +{ | |
| - | + int l; |
| - | + char *lp = ibuf; |
| - | + char *eot; |
| - | + undo_t *up = NULL; |
| - | + |
| - | + for (current_addr = n;;) |
| - | + { |
| - | + if (!isglobal) |
| - | + { |
| - | + if ((l = get_tty_line ()) < 0) |
| - | + return ERR; |
| - | + else if (l == 0 || ibuf[l - 1] != '\n') |
| - | + { |
| - | + clearerr (stdin); |
| - | + return l ? EOF : 0; |
| - | + } |
| - | + lp = ibuf; |
| - | + } |
| - | + else if (*(lp = ibufp) == '\0') |
| - | + return 0; |
| - | + else |
| + | + int delim; |
| + | + char * cp; |
| + | + char * oldStr; |
| + | + char * newStr; |
| + | + LEN oldLen; |
| + | + LEN newLen; |
| + | + LEN deltaLen; |
| + | + LEN offset; |
| + | + LINE * lp; |
| + | + LINE * nlp; |
| + | + BOOL globalFlag; |
| + | + BOOL printFlag; |
| + | + BOOL didSub; |
| + | + BOOL needPrint; |
| + | + char buf[USERSIZE]; |
| + | + |
| + | + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) |
| + { | |
| - | + while (*ibufp++ != '\n') |
| - | + ; |
| - | + l = ibufp - lp; |
| + | + fprintf(stderr, "Bad line range for substitute\n"); |
| + | + |
| + | + return; |
| + } | |
| - | + if (l == 2 && lp[0] == '.' && lp[1] == '\n') |
| + | + |
| + | + globalFlag = FALSE; |
| + | + printFlag = FALSE; |
| + | + didSub = FALSE; |
| + | + needPrint = FALSE; |
| + | + |
| + | + /* |
| + | + * Copy the command so we can modify it. |
| + | + */ |
| + | + strcpy(buf, cmd); |
| + | + cp = buf; |
| + | + |
| + | + if (isBlank(*cp) || (*cp == '\0')) |
| + { | |
| - | + return 0; |
| + | + fprintf(stderr, "Bad delimiter for substitute\n"); |
| + | + |
| + | + return; |
| + } | |
| - | + eot = lp + l; |
| - | + SPL1 (); |
| - | + do |
| + | + |
| + | + delim = *cp++; |
| + | + oldStr = cp; |
| + | + |
| + | + cp = strchr(cp, delim); |
| + | + |
| + | + if (cp == NULL) |
| + { | |
| - | + if ((lp = put_sbuf_line (lp)) == NULL) |
| - | + { |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| - | + else if (up) |
| - | + up->t = get_addressed_line_node (current_addr); |
| - | + else if ((up = push_undo_stack (UADD, current_addr, |
| - | + current_addr)) == NULL) |
| - | + { |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| + | + fprintf(stderr, "Missing 2nd delimiter for substitute\n"); |
| + | + |
| + | + return; |
| + } | |
| - | + while (lp != eot); |
| - | + modified = 1; |
| - | + SPL0 (); |
| - | + } |
| - | + /* NOTREACHED */ |
| - | +} |
| + | |
| + | + *cp++ = '\0'; |
| + | |
| - | +/* join_lines: replace a range of lines with the joined text of those lines */ |
| - | +int |
| - | +join_lines (from, to) |
| - | + long from; |
| - | + long to; |
| - | +{ |
| - | + static char *buf = NULL; |
| - | + static int n; |
| - | + |
| - | + char *s; |
| - | + int size = 0; |
| - | + line_t *bp, *ep; |
| - | + |
| - | + ep = get_addressed_line_node (INC_MOD (to, addr_last)); |
| - | + bp = get_addressed_line_node (from); |
| - | + for (; bp != ep; bp = bp->q_forw) |
| - | + { |
| - | + if ((s = get_sbuf_line (bp)) == NULL) |
| - | + return ERR; |
| - | + REALLOC (buf, n, size + bp->len, ERR); |
| - | + memcpy (buf + size, s, bp->len); |
| - | + size += bp->len; |
| - | + } |
| - | + REALLOC (buf, n, size + 2, ERR); |
| - | + memcpy (buf + size, "\n", 2); |
| - | + if (delete_lines (from, to) < 0) |
| - | + return ERR; |
| - | + current_addr = from - 1; |
| - | + SPL1 (); |
| - | + if (put_sbuf_line (buf) == NULL || |
| - | + push_undo_stack (UADD, current_addr, current_addr) == NULL) |
| - | + { |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| - | + modified = 1; |
| - | + SPL0 (); |
| - | + return 0; |
| - | +} |
| + | + newStr = cp; |
| + | + cp = strchr(cp, delim); |
| + | |
| + | + if (cp) |
| + | + *cp++ = '\0'; |
| + | + else |
| + | + cp = ""; |
| + | |
| - | +/* move_lines: move a range of lines */ |
| - | +int |
| - | +move_lines (addr) |
| - | + long addr; |
| - | +{ |
| - | + line_t *b1, *a1, *b2, *a2; |
| - | + long n = INC_MOD (second_addr, addr_last); |
| - | + long p = first_addr - 1; |
| - | + int done = (addr == first_addr - 1 || addr == second_addr); |
| - | + |
| - | + SPL1 (); |
| - | + if (done) |
| - | + { |
| - | + a2 = get_addressed_line_node (n); |
| - | + b2 = get_addressed_line_node (p); |
| - | + current_addr = second_addr; |
| - | + } |
| - | + else if (push_undo_stack (UMOV, p, n) == NULL || |
| - | + push_undo_stack (UMOV, addr, INC_MOD (addr, addr_last)) == NULL) |
| - | + { |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| - | + else |
| - | + { |
| - | + a1 = get_addressed_line_node (n); |
| - | + if (addr < first_addr) |
| + | + while (*cp) switch (*cp++) |
| + { | |
| - | + b1 = get_addressed_line_node (p); |
| - | + b2 = get_addressed_line_node (addr); |
| - | + /* this get_addressed_line_node last! */ |
| + | + case 'g': |
| + | + globalFlag = TRUE; |
| + | + break; |
| + | + |
| + | + case 'p': |
| + | + printFlag = TRUE; |
| + | + break; |
| + | + |
| + | + default: |
| + | + fprintf(stderr, "Unknown option for substitute\n"); |
| + | + |
| + | + return; |
| + } | |
| - | + else |
| + | + |
| + | + if (*oldStr == '\0') |
| + { | |
| - | + b2 = get_addressed_line_node (addr); |
| - | + b1 = get_addressed_line_node (p); |
| - | + /* this get_addressed_line_node last! */ |
| - | + } |
| - | + a2 = b2->q_forw; |
| - | + REQUE (b2, b1->q_forw); |
| - | + REQUE (a1->q_back, a2); |
| - | + REQUE (b1, a1); |
| - | + current_addr = addr + ((addr < first_addr) ? |
| - | + second_addr - first_addr + 1 : 0); |
| - | + } |
| - | + if (isglobal) |
| - | + unset_active_nodes (b2->q_forw, a2); |
| - | + modified = 1; |
| - | + SPL0 (); |
| - | + return 0; |
| - | +} |
| + | + if (searchString[0] == '\0') |
| + | + { |
| + | + fprintf(stderr, "No previous search string\n"); |
| + | |
| + | + return; |
| + | + } |
| + | |
| - | +/* copy_lines: copy a range of lines; return status */ |
| - | +int |
| - | +copy_lines (addr) |
| - | + long addr; |
| - | +{ |
| - | + line_t *lp, *np = get_addressed_line_node (first_addr); |
| - | + undo_t *up = NULL; |
| - | + long n = second_addr - first_addr + 1; |
| - | + long m = 0; |
| - | + |
| - | + current_addr = addr; |
| - | + if (first_addr <= addr && addr < second_addr) |
| - | + { |
| - | + n = addr - first_addr + 1; |
| - | + m = second_addr - addr; |
| - | + } |
| - | + for (; n > 0; n = m, m = 0, np = get_addressed_line_node (current_addr + 1)) |
| - | + for (; n-- > 0; np = np->q_forw) |
| - | + { |
| - | + SPL1 (); |
| - | + if ((lp = dup_line_node (np)) == NULL) |
| - | + { |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| - | + add_line_node (lp); |
| - | + if (up) |
| - | + up->t = lp; |
| - | + else if ((up = push_undo_stack (UADD, current_addr, |
| - | + current_addr)) == NULL) |
| - | + { |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| - | + modified = 1; |
| - | + SPL0 (); |
| - | + } |
| - | + return 0; |
| - | +} |
| + | + oldStr = searchString; |
| + | + } |
| + | |
| + | + if (oldStr != searchString) |
| + | + strcpy(searchString, oldStr); |
| + | |
| - | +/* delete_lines: delete a range of lines */ |
| - | +int |
| - | +delete_lines (from, to) |
| - | + long from, to; |
| - | +{ |
| - | + line_t *n, *p; |
| - | + |
| - | + if (yank_lines (from, to) < 0) |
| - | + return ERR; |
| - | + SPL1 (); |
| - | + if (push_undo_stack (UDEL, from, to) == NULL) |
| - | + { |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| - | + n = get_addressed_line_node (INC_MOD (to, addr_last)); |
| - | + p = get_addressed_line_node (from - 1); |
| - | + /* this get_addressed_line_node last! */ |
| - | + if (isglobal) |
| - | + unset_active_nodes (p->q_forw, n); |
| - | + REQUE (p, n); |
| - | + addr_last -= to - from + 1; |
| - | + current_addr = from - 1; |
| - | + modified = 1; |
| - | + SPL0 (); |
| - | + return 0; |
| - | +} |
| + | + lp = findLine(num1); |
| + | |
| + | + if (lp == NULL) |
| + | + return; |
| + | |
| - | +int dlcnt = 0; /* # of lines displayed */ |
| + | + oldLen = strlen(oldStr); |
| + | + newLen = strlen(newStr); |
| + | + deltaLen = newLen - oldLen; |
| + | + offset = 0; |
| + | + nlp = NULL; |
| + | |
| - | +/* display_lines: print a range of lines to stdout */ |
| - | +int |
| - | +display_lines (from, to, gflag) |
| - | + long from; |
| - | + long to; |
| - | + int gflag; |
| - | +{ |
| - | + line_t *bp; |
| - | + line_t *ep; |
| - | + char *s; |
| - | + |
| - | + if (!from) |
| - | + { |
| - | + sprintf (errmsg, "Invalid address"); |
| - | + return ERR; |
| - | + } |
| - | + ep = get_addressed_line_node (INC_MOD (to, addr_last)); |
| - | + bp = get_addressed_line_node (from); |
| - | + for (dlcnt = 0; bp != ep; bp = bp->q_forw) |
| - | + { |
| - | + if ((s = get_sbuf_line (bp)) == NULL) |
| - | + return ERR; |
| - | + else if (put_tty_line (s, bp->len, current_addr = from++, gflag) < 0) |
| - | + return ERR; |
| - | + else if (!traditional && !scripted && !isglobal && |
| - | + bp->q_forw != ep && ++dlcnt > rows) |
| + | + while (num1 <= num2) |
| + { | |
| - | + dlcnt = 0; |
| - | + fputs ("Press <RETURN> to continue... ", stdout); |
| - | + fflush (stdout); |
| - | + if (get_tty_line () < 0) |
| - | + return ERR; |
| - | + } |
| - | + } |
| - | + return 0; |
| - | +} |
| + | + offset = findString(lp, oldStr, oldLen, offset); |
| + | |
| + | + if (offset < 0) |
| + | + { |
| + | + if (needPrint) |
| + | + { |
| + | + printLines(num1, num1, FALSE); |
| + | + needPrint = FALSE; |
| + | + } |
| + | |
| - | +line_t yank_buffer_head; /* head of yank buffer */ |
| + | + offset = 0; |
| + | + lp = lp->next; |
| + | + num1++; |
| + | |
| - | +/* yank_lines: copy a range of lines to the cut buffer */ |
| - | +int |
| - | +yank_lines (from, to) |
| - | + long from; |
| - | + long to; |
| - | +{ |
| - | + line_t *bp, *cp, *ep, *lp; |
| + | + continue; |
| + | + } |
| + | |
| + | + needPrint = printFlag; |
| + | + didSub = TRUE; |
| + | + dirty = TRUE; |
| + | |
| - | + delete_yank_lines (); |
| - | + ep = get_addressed_line_node (INC_MOD (to, addr_last)); |
| - | + bp = get_addressed_line_node (from); |
| - | + for (lp = &yank_buffer_head; bp != ep; bp = bp->q_forw, lp = cp) |
| - | + { |
| - | + SPL1 (); |
| - | + if ((cp = dup_line_node (bp)) == NULL) |
| - | + { |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| - | + INSQUE (cp, lp); |
| - | + SPL0 (); |
| - | + } |
| - | + return 0; |
| - | +} |
| + | + /* |
| + | + * If the replacement string is the same size or shorter |
| + | + * than the old string, then the substitution is easy. |
| + | + */ |
| + | + if (deltaLen <= 0) |
| + | + { |
| + | + memcpy(&lp->data[offset], newStr, newLen); |
| + | |
| + | + if (deltaLen) |
| + | + { |
| + | + memcpy(&lp->data[offset + newLen], |
| + | + &lp->data[offset + oldLen], |
| + | + lp->len - offset - oldLen); |
| + | |
| - | +/* delete_yank_lines: delete lines from the yank buffer */ |
| - | +void |
| - | +delete_yank_lines () |
| - | +{ |
| - | + line_t *cp, *lp; |
| + | + lp->len += deltaLen; |
| + | + } |
| + | |
| + | + offset += newLen; |
| + | |
| - | + for (lp = yank_buffer_head.q_forw; lp != &yank_buffer_head; lp = cp) |
| - | + { |
| - | + SPL1 (); |
| - | + cp = lp->q_forw; |
| - | + REQUE (lp->q_back, lp->q_forw); |
| - | + free (lp); |
| - | + SPL0 (); |
| - | + } |
| - | +} |
| + | + if (globalFlag) |
| + | + continue; |
| + | |
| + | + if (needPrint) |
| + | + { |
| + | + printLines(num1, num1, FALSE); |
| + | + needPrint = FALSE; |
| + | + } |
| + | |
| - | +/* put_lines: append lines from the yank buffer */ |
| - | +int |
| - | +put_lines (addr) |
| - | + long addr; |
| - | +{ |
| - | + undo_t *up = NULL; |
| - | + line_t *lp, *cp; |
| - | + |
| - | + if ((lp = yank_buffer_head.q_forw) == &yank_buffer_head) |
| - | + { |
| - | + sprintf (errmsg, "Nothing to put"); |
| - | + return ERR; |
| - | + } |
| - | + current_addr = addr; |
| - | + for (; lp != &yank_buffer_head; lp = lp->q_forw) |
| - | + { |
| - | + SPL1 (); |
| - | + if ((cp = dup_line_node (lp)) == NULL) |
| - | + { |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| - | + add_line_node (cp); |
| - | + if (up) |
| - | + up->t = cp; |
| - | + else if ((up = push_undo_stack (UADD, current_addr, |
| - | + current_addr)) == NULL) |
| - | + { |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| - | + modified = 1; |
| - | + SPL0 (); |
| - | + } |
| - | + return 0; |
| - | +} |
| + | + lp = lp->next; |
| + | + num1++; |
| + | + |
| + | + continue; |
| + | + } |
| + | |
| + | + /* |
| + | + * The new string is larger, so allocate a new line |
| + | + * structure and use that. Link it in in place of |
| + | + * the old line structure. |
| + | + */ |
| + | + nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltaLen); |
| + | |
| - | +#define MAXMARK 26 /* max number of marks */ |
| + | + if (nlp == NULL) |
| + | + { |
| + | + fprintf(stderr, "Cannot get memory for line\n"); |
| + | |
| - | +line_t *mark[MAXMARK]; /* line markers */ |
| - | +int markno; /* line marker count */ |
| + | + return; |
| + | + } |
| + | |
| - | +/* mark_line_node: set a line node mark */ |
| - | +int |
| - | +mark_line_node (lp, n) |
| - | + line_t *lp; |
| - | + int n; |
| - | +{ |
| - | + if (!islower (n)) |
| - | + { |
| - | + sprintf (errmsg, "Invalid mark character"); |
| - | + return ERR; |
| - | + } |
| - | + else if (mark[n - 'a'] == NULL) |
| - | + markno++; |
| - | + mark[n - 'a'] = lp; |
| - | + return 0; |
| - | +} |
| + | + nlp->len = lp->len + deltaLen; |
| + | |
| + | + memcpy(nlp->data, lp->data, offset); |
| + | |
| - | +/* get_marked_node_addr: return address of a marked line */ |
| - | +long |
| - | +get_marked_node_addr (n) |
| - | + int n; |
| - | +{ |
| - | + if (!islower (n)) |
| - | + { |
| - | + sprintf (errmsg, "Invalid mark character"); |
| - | + return ERR; |
| - | + } |
| - | + return get_line_node_addr (mark[n - 'a']); |
| - | +} |
| + | + memcpy(&nlp->data[offset], newStr, newLen); |
| + | |
| + | + memcpy(&nlp->data[offset + newLen], |
| + | + &lp->data[offset + oldLen], |
| + | + lp->len - offset - oldLen); |
| + | |
| - | +/* unmark_line_node: clear line node mark */ |
| - | +void |
| - | +unmark_line_node (lp) |
| - | + line_t *lp; |
| - | +{ |
| - | + int i; |
| - | + |
| - | + for (i = 0; markno && i < MAXMARK; i++) |
| - | + if (mark[i] == lp) |
| - | + { |
| - | + mark[i] = NULL; |
| - | + markno--; |
| - | + } |
| - | +} |
| + | + nlp->next = lp->next; |
| + | + nlp->prev = lp->prev; |
| + | + nlp->prev->next = nlp; |
| + | + nlp->next->prev = nlp; |
| + | |
| + | + if (curLine == lp) |
| + | + curLine = nlp; |
| + | |
| - | +/* dup_line_node: return a pointer to a copy of a line node */ |
| - | +line_t * |
| - | +dup_line_node (lp) |
| - | + line_t *lp; |
| - | +{ |
| - | + line_t *np; |
| - | + |
| - | + if ((np = (line_t *) malloc (sizeof (line_t))) == NULL) |
| - | + { |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Out of memory"); |
| - | + return NULL; |
| - | + } |
| - | + np->seek = lp->seek; |
| - | + np->len = lp->len; |
| - | + return np; |
| - | +} |
| + | + free(lp); |
| + | + lp = nlp; |
| + | |
| + | + offset += newLen; |
| + | |
| - | +/* has_trailing_escape: return the parity of escapes preceding a character |
| - | + in a string */ |
| - | +int |
| - | +has_trailing_escape (s, t) |
| - | + char *s; |
| - | + char *t; |
| - | +{ |
| - | + return (s == t || *(t - 1) != '\\') ? 0 : !has_trailing_escape (s, t - 1); |
| + | + if (globalFlag) |
| + | + continue; |
| + | + |
| + | + if (needPrint) |
| + | + { |
| + | + printLines(num1, num1, FALSE); |
| + | + needPrint = FALSE; |
| + | + } |
| + | + |
| + | + lp = lp->next; |
| + | + num1++; |
| + | + } |
| + | + |
| + | + if (!didSub) |
| + | + fprintf(stderr, "No substitutions found for \"%s\"\n", oldStr); |
| +} | |
| + | |
| + | |
| - | +/* strip_escapes: return copy of escaped string of at most length PATH_MAX */ |
| - | +char * |
| - | +strip_escapes (s) |
| - | + char *s; |
| + | +/* |
| + | + * Search a line for the specified string starting at the specified |
| + | + * offset in the line. Returns the offset of the found string, or -1. |
| + | + */ |
| + | +static LEN |
| + | +findString( const LINE * lp, const char * str, LEN len, LEN offset) |
| +{ | |
| - | + static char *file = NULL; |
| - | + static int filesz = 0; |
| + | + LEN left; |
| + | + const char * cp; |
| + | + const char * ncp; |
| + | |
| - | + int i = 0; |
| + | + cp = &lp->data[offset]; |
| + | + left = lp->len - offset; |
| + | |
| - | + REALLOC (file, filesz, PATH_MAX + 1, NULL); |
| - | + /* assert: no trailing escape */ |
| - | + while ((file[i++] = (*s == '\\') ? *++s : *s)) |
| - | + s++; |
| - | + return file; |
| - | +} |
| + | + while (left >= len) |
| + | + { |
| + | + ncp = memchr(cp, *str, left); |
| + | |
| + | + if (ncp == NULL) |
| + | + return -1; |
| + | |
| - | +#ifndef S_ISREG |
| - | +#define S_ISREG(m) ((m & S_IFMT) == S_IFREG) |
| - | +#endif |
| + | + left -= (ncp - cp); |
| + | |
| - | +/* is_regular_file: if file descriptor of a regular file, then return true; |
| - | + otherwise return false */ |
| - | +int |
| - | +is_regular_file (fd) |
| - | + int fd; |
| - | +{ |
| - | + struct stat sb; |
| + | + if (left < len) |
| + | + return -1; |
| + | |
| - | + return fstat (fd, &sb) < 0 || S_ISREG (sb.st_mode); |
| - | +} |
| + | + cp = ncp; |
| + | |
| + | + if (memcmp(cp, str, len) == 0) |
| + | + return (cp - lp->data); |
| + | |
| - | +/* is_legal_filename: return a legal filename */ |
| - | +int |
| - | +is_legal_filename (s) |
| - | + char *s; |
| - | +{ |
| - | + if (red && (*s == '!' || !strcmp (s, "..") || strchr (s, '/'))) |
| - | + { |
| - | + sprintf (errmsg, "Shell access restricted"); |
| - | + return 0; |
| - | + } |
| - | + return 1; |
| + | + cp++; |
| + | + left--; |
| + | + } |
| + | + |
| + | + return -1; |
| +} | |
| + | |
| - | +FILE *sfp; /* scratch file pointer */ |
| - | +off_t sfseek; /* scratch file position */ |
| - | +int seek_write; /* seek before writing */ |
| - | +line_t buffer_head; /* incore buffer */ |
| + | |
| - | +/* get_sbuf_line: get a line of text from the scratch file; return pointer |
| - | + to the text */ |
| - | +char * |
| - | +get_sbuf_line (lp) |
| - | + line_t *lp; |
| + | +/* |
| + | + * Add lines which are typed in by the user. |
| + | + * The lines are inserted just before the specified line number. |
| + | + * The lines are terminated by a line containing a single dot (ugly!), |
| + | + * or by an end of file. |
| + | + */ |
| + | +static void |
| + | +addLines(NUM num) |
| +{ | |
| - | + static char *sfbuf = NULL; /* buffer */ |
| - | + static int sfbufsz = 0; /* buffer size */ |
| - | + |
| - | + int len, ct; |
| - | + |
| - | + if (lp == &buffer_head) |
| - | + return NULL; |
| - | + seek_write = 1; /* force seek on write */ |
| - | + /* out of position */ |
| - | + if (sfseek != lp->seek) |
| - | + { |
| - | + sfseek = lp->seek; |
| - | + if (fseek (sfp, sfseek, SEEK_SET) < 0) |
| + | + int len; |
| + | + char buf[USERSIZE + 1]; |
| + | + |
| + | + while (fgets(buf, sizeof(buf), stdin)) |
| + { | |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Cannot seek temp file"); |
| - | + return NULL; |
| + | + if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0')) |
| + | + return; |
| + | + |
| + | + len = strlen(buf); |
| + | + |
| + | + if (len == 0) |
| + | + return; |
| + | + |
| + | + if (buf[len - 1] != '\n') |
| + | + { |
| + | + fprintf(stderr, "Line too long\n"); |
| + | + |
| + | + do |
| + | + { |
| + | + len = fgetc(stdin); |
| + | + } |
| + | + while ((len != EOF) && (len != '\n')); |
| + | + |
| + | + return; |
| + | + } |
| + | + |
| + | + if (!insertLine(num++, buf, len)) |
| + | + return; |
| + } | |
| - | + } |
| - | + len = lp->len; |
| - | + REALLOC (sfbuf, sfbufsz, len + 1, NULL); |
| - | + if ((ct = fread (sfbuf, sizeof (char), len, sfp)) < 0 || ct != len) |
| - | + { |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Cannot read temp file"); |
| - | + return NULL; |
| - | + } |
| - | + sfseek += len; /* update file position */ |
| - | + sfbuf[len] = '\0'; |
| - | + return sfbuf; |
| +} | |
| + | |
| + | |
| - | +/* put_sbuf_line: write a line of text to the scratch file and add a line node |
| - | + to the editor buffer; return a pointer to the end of the text */ |
| - | +char * |
| - | +put_sbuf_line (cs) |
| - | + char *cs; |
| + | +/* |
| + | + * Parse a line number argument if it is present. This is a sum |
| + | + * or difference of numbers, '.', '$', 'x, or a search string. |
| + | + * Returns TRUE if successful (whether or not there was a number). |
| + | + * Returns FALSE if there was a parsing error, with a message output. |
| + | + * Whether there was a number is returned indirectly, as is the number. |
| + | + * The character pointer which stopped the scan is also returned. |
| + | + */ |
| + | +static BOOL |
| + | +getNum(const char ** retcp, BOOL * retHaveNum, NUM * retNum) |
| +{ | |
| - | + line_t *lp; |
| - | + int len, ct; |
| - | + char *s; |
| - | + |
| - | + if ((lp = (line_t *) malloc (sizeof (line_t))) == NULL) |
| - | + { |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Out of memory"); |
| - | + return NULL; |
| - | + } |
| - | + /* assert: cs is '\n' terminated */ |
| - | + for (s = cs; *s != '\n'; s++) |
| - | + ; |
| - | + if (s - cs >= LINECHARS) |
| - | + { |
| - | + sprintf (errmsg, "Line too long"); |
| - | + return NULL; |
| - | + } |
| - | + len = s - cs; |
| - | + /* out of position */ |
| - | + if (seek_write) |
| - | + { |
| - | + if (fseek (sfp, 0L, SEEK_END) < 0) |
| + | + const char * cp; |
| + | + char * endStr; |
| + | + char str[USERSIZE]; |
| + | + BOOL haveNum; |
| + | + NUM value; |
| + | + NUM num; |
| + | + NUM sign; |
| + | + |
| + | + cp = *retcp; |
| + | + haveNum = FALSE; |
| + | + value = 0; |
| + | + sign = 1; |
| + | + |
| + | + while (TRUE) |
| + { | |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Cannot seek temp file"); |
| - | + return NULL; |
| - | + } |
| - | + sfseek = ftell (sfp); |
| - | + seek_write = 0; |
| - | + } |
| - | + /* assert: SPL1() */ |
| - | + if ((ct = fwrite (cs, sizeof (char), len, sfp)) < 0 || ct != len) |
| - | + { |
| - | + sfseek = -1; |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Cannot write temp file"); |
| - | + return NULL; |
| - | + } |
| - | + lp->len = len; |
| - | + lp->seek = sfseek; |
| - | + add_line_node (lp); |
| - | + sfseek += len; /* update file position */ |
| - | + return ++s; |
| - | +} |
| + | + while (isBlank(*cp)) |
| + | + cp++; |
| + | |
| + | + switch (*cp) |
| + | + { |
| + | + case '.': |
| + | + haveNum = TRUE; |
| + | + num = curNum; |
| + | + cp++; |
| + | + break; |
| + | |
| - | +/* add_line_node: add a line node in the editor buffer after the current line */ |
| - | +void |
| - | +add_line_node (lp) |
| - | + line_t *lp; |
| - | +{ |
| - | + line_t *cp; |
| + | + case '$': |
| + | + haveNum = TRUE; |
| + | + num = lastNum; |
| + | + cp++; |
| + | + break; |
| + | |
| - | + cp = get_addressed_line_node (current_addr); /* this get_addressed_line_node last! */ |
| - | + INSQUE (lp, cp); |
| - | + addr_last++; |
| - | + current_addr++; |
| - | +} |
| + | + case '\'': |
| + | + cp++; |
| + | |
| + | + if ((*cp < 'a') || (*cp > 'z')) |
| + | + { |
| + | + fprintf(stderr, "Bad mark name\n"); |
| + | |
| - | +/* get_line_node_addr: return line number of pointer */ |
| - | +long |
| - | +get_line_node_addr (lp) |
| - | + line_t *lp; |
| - | +{ |
| - | + line_t *cp = &buffer_head; |
| - | + long n = 0; |
| - | + |
| - | + while (cp != lp && (cp = cp->q_forw) != &buffer_head) |
| - | + n++; |
| - | + if (n && cp == &buffer_head) |
| - | + { |
| - | + sprintf (errmsg, "Invalid address"); |
| - | + return ERR; |
| - | + } |
| - | + return n; |
| - | +} |
| + | + return FALSE; |
| + | + } |
| + | |
| + | + haveNum = TRUE; |
| + | + num = marks[*cp++ - 'a']; |
| + | + break; |
| + | |
| - | +/* get_addressed_line_node: return pointer to a line node in the editor buffer */ |
| - | +line_t * |
| - | +get_addressed_line_node (n) |
| - | + long n; |
| - | +{ |
| - | + static line_t *lp = &buffer_head; |
| - | + static long on = 0; |
| - | + |
| - | + SPL1 (); |
| - | + if (n > on) |
| - | + if (n <= (on + addr_last) >> 1) |
| - | + for (; on < n; on++) |
| - | + lp = lp->q_forw; |
| - | + else |
| - | + { |
| - | + lp = buffer_head.q_back; |
| - | + for (on = addr_last; on > n; on--) |
| - | + lp = lp->q_back; |
| - | + } |
| - | + else if (n >= on >> 1) |
| - | + for (; on > n; on--) |
| - | + lp = lp->q_back; |
| - | + else |
| - | + { |
| - | + lp = &buffer_head; |
| - | + for (on = 0; on < n; on++) |
| - | + lp = lp->q_forw; |
| - | + } |
| - | + SPL0 (); |
| - | + return lp; |
| - | +} |
| + | + case '/': |
| + | + strcpy(str, ++cp); |
| + | + endStr = strchr(str, '/'); |
| + | |
| + | + if (endStr) |
| + | + { |
| + | + *endStr++ = '\0'; |
| + | + cp += (endStr - str); |
| + | + } |
| + | + else |
| + | + cp = ""; |
| + | |
| - | +extern int newline_added; |
| + | + num = searchLines(str, curNum, lastNum); |
| + | |
| - | +/* open_sbuf: open scratch file */ |
| - | +int |
| - | +open_sbuf () |
| - | +{ |
| - | + char *mktemp (); |
| - | + int u; |
| - | + |
| - | + isbinary = newline_added = 0; |
| - | + u = umask(077); |
| - | + if ((sfp = tmpfile()) == NULL) |
| - | + { |
| - | + fprintf (stderr, "open_sbuf: tmpfile() failed with '%s'\n", strerror (errno)); |
| - | + sprintf (errmsg, "Cannot open temp file"); |
| - | + umask(u); |
| - | + return ERR; |
| - | + } |
| - | + umask(u); |
| - | + return 0; |
| - | +} |
| + | + if (num == 0) |
| + | + return FALSE; |
| + | |
| + | + haveNum = TRUE; |
| + | + break; |
| + | |
| - | +/* close_sbuf: close scratch file */ |
| - | +int |
| - | +close_sbuf () |
| - | +{ |
| - | + if (sfp) |
| - | + { |
| - | + if (fclose (sfp) < 0) |
| - | + { |
| - | + fprintf (stderr, "close_sbuf: fclose on temporary file failed with '%s'.\n", strerror (errno)); |
| - | + sprintf (errmsg, "Cannot close temp file"); |
| - | + return ERR; |
| - | + } |
| - | + sfp = NULL; |
| - | + } |
| - | + sfseek = seek_write = 0; |
| + | + default: |
| + | + if (!isDecimal(*cp)) |
| + | + { |
| + | + *retcp = cp; |
| + | + *retHaveNum = haveNum; |
| + | + *retNum = value; |
| + | |
| - | + return 0; |
| - | +} |
| + | + return TRUE; |
| + | + } |
| + | |
| + | + num = 0; |
| + | |
| - | +/* quit: remove_lines scratch file and exit */ |
| - | +void |
| - | +quit (n) |
| - | + int n; |
| - | +{ |
| - | + if (sfp) |
| - | + { |
| - | + fclose (sfp); |
| - | + } |
| - | + exit (n); |
| - | +} |
| + | + while (isDecimal(*cp)) |
| + | + num = num * 10 + *cp++ - '0'; |
| + | |
| + | + haveNum = TRUE; |
| + | + break; |
| + | + } |
| + | |
| - | +extern line_t yank_buffer_head; |
| - | +extern char *old_filename; |
| - | +unsigned char ctab[256]; /* character translation table */ |
| + | + value += num * sign; |
| + | |
| - | +/* init_buffers: open scratch buffer; initialize line queue */ |
| - | +void |
| - | +init_buffers () |
| - | +{ |
| - | + int i = 0; |
| - | + |
| - | + /* Read stdin one character at a time to avoid i/o contention |
| - | + with shell escapes invoked by nonterminal input, e.g., |
| - | + ed - <<EOF |
| - | + !cat |
| - | + hello, world |
| - | + EOF */ |
| - | +#ifdef HAVE_SETBUFFER |
| - | + setbuffer (stdin, stdinbuf, 1); |
| - | +#else |
| - | + setvbuf (stdin, stdinbuf, _IONBF, 0); |
| - | +#endif |
| - | + if ((errmsg = (char *) malloc (ERRSZ)) == NULL || |
| - | + (old_filename = (char *) malloc (PATH_MAX + 1)) == NULL) |
| - | + { |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + quit (2); |
| - | + } |
| - | + old_filename[0] = '\0'; |
| - | + if (open_sbuf () < 0) |
| - | + quit (2); |
| - | + REQUE (&buffer_head, &buffer_head); |
| - | + REQUE (&yank_buffer_head, &yank_buffer_head); |
| - | + for (i = 0; i < 256; i++) |
| - | + ctab[i] = i; |
| + | + while (isBlank(*cp)) |
| + | + cp++; |
| + | |
| + | + switch (*cp) |
| + | + { |
| + | + case '-': |
| + | + sign = -1; |
| + | + cp++; |
| + | + break; |
| + | + |
| + | + case '+': |
| + | + sign = 1; |
| + | + cp++; |
| + | + break; |
| + | + |
| + | + default: |
| + | + *retcp = cp; |
| + | + *retHaveNum = haveNum; |
| + | + *retNum = value; |
| + | + |
| + | + return TRUE; |
| + | + } |
| + | + } |
| +} | |
| + | |
| + | |
| - | +/* translit_text: translate characters in a string */ |
| - | +char * |
| - | +translit_text (s, len, from, to) |
| - | + char *s; |
| - | + int len; |
| - | + int from; |
| - | + int to; |
| + | +/* |
| + | + * Initialize everything for editing. |
| + | + */ |
| + | +static BOOL |
| + | +initEdit(void) |
| +{ | |
| - | + static int i = 0; |
| + | + int i; |
| + | |
| - | + unsigned char *us; |
| + | + bufSize = INITBUF_SIZE; |
| + | + bufBase = malloc(bufSize); |
| + | |
| - | + ctab[i] = i; /* restore table to initial state */ |
| - | + ctab[i = from] = to; |
| - | + for (us = (unsigned char *) s; len-- > 0; us++) |
| - | + *us = ctab[*us]; |
| - | + return s; |
| - | +} |
| + | + if (bufBase == NULL) |
| + | + { |
| + | + fprintf(stderr, "No memory for buffer\n"); |
| + | |
| + | + return FALSE; |
| + | + } |
| + | |
| - | +#ifndef SIG_ERR |
| - | +# define SIG_ERR ((void (*)()) -1) |
| - | +#endif /* !SIG_ERR */ |
| + | + bufPtr = bufBase; |
| + | + bufUsed = 0; |
| + | |
| - | +void |
| - | +(*reliable_signal (sno, hndlr)) () |
| - | + int sno; |
| - | + void (*hndlr) (); |
| - | +{ |
| - | +#ifndef HAVE_SIGACTION |
| - | + signal (sno, hndlr); |
| - | +#else |
| - | + struct sigaction sa, osa; |
| - | + |
| - | + sa.sa_handler = hndlr; |
| - | + sigemptyset (&sa.sa_mask); |
| - | + sa.sa_flags = 0; |
| - | +#ifdef SA_RESTART |
| - | + sa.sa_flags |= SA_RESTART; |
| - | +#endif |
| - | + return (sigaction (sno, &sa, &osa) < 0) ? SIG_ERR : osa.sa_handler; |
| - | +#endif /* HAVE_SIGACTION */ |
| - | +} |
| + | + lines.next = &lines; |
| + | + lines.prev = &lines; |
| + | |
| + | + curLine = NULL; |
| + | + curNum = 0; |
| + | + lastNum = 0; |
| + | + dirty = FALSE; |
| + | + fileName = NULL; |
| + | + searchString[0] = '\0'; |
| + | |
| - | +void |
| - | +signal_hup (signo) |
| - | + int signo; |
| - | +{ |
| - | + if (mutex) |
| - | + sigflags |= (1 << (signo - 1)); |
| - | + else |
| - | + handle_hup (signo); |
| + | + for (i = 0; i < 26; i++) |
| + | + marks[i] = 0; |
| + | + |
| + | + return TRUE; |
| +} | |
| + | |
| + | |
| - | +void |
| - | +signal_int (signo) |
| - | + int signo; |
| + | +/* |
| + | + * Finish editing. |
| + | + */ |
| + | +static void |
| + | +termEdit(void) |
| +{ | |
| - | + if (mutex) |
| - | + sigflags |= (1 << (signo - 1)); |
| - | + else |
| - | + handle_int (signo); |
| - | +} |
| + | + if (bufBase) |
| + | + free(bufBase); |
| + | |
| + | + bufBase = NULL; |
| + | + bufPtr = NULL; |
| + | + bufSize = 0; |
| + | + bufUsed = 0; |
| + | |
| - | +#ifdef HAVE_SIGSETJMP |
| - | +extern sigjmp_buf env; |
| - | +#else |
| - | +extern jmp_buf env; |
| - | +#endif |
| - | +extern int sigactive; |
| + | + if (fileName) |
| + | + free(fileName); |
| + | |
| - | +void |
| - | +handle_hup (signo) |
| - | + int signo; |
| - | +{ |
| - | + char *hup = NULL; /* hup filename */ |
| - | + char *s; |
| - | + int n; |
| - | + |
| - | + if (!sigactive) |
| - | + quit (1); |
| - | + sigflags &= ~(1 << (signo - 1)); |
| - | + if (addr_last && write_file ("ed.hup", "w", 1, addr_last) < 0 && |
| - | + (s = getenv ("HOME")) != NULL && |
| - | + (n = strlen (s)) + 7 <= PATH_MAX && /* "ed.hup" + '/' */ |
| - | + (hup = (char *) malloc (n + 8)) != NULL) |
| - | + { |
| - | + strcpy (hup, s); |
| - | + if (n && hup[n - 1] != '/') |
| - | + hup[n++] = '/'; |
| - | + strcpy (hup + n, "ed.hup"); |
| - | + write_file (hup, "w", 1, addr_last); |
| - | + } |
| - | + quit (2); |
| + | + fileName = NULL; |
| + | + |
| + | + searchString[0] = '\0'; |
| + | + |
| + | + if (lastNum) |
| + | + deleteLines(1, lastNum); |
| + | + |
| + | + lastNum = 0; |
| + | + curNum = 0; |
| + | + curLine = NULL; |
| +} | |
| + | |
| + | |
| - | +void |
| - | +handle_int (signo) |
| - | + int signo; |
| + | +/* |
| + | + * Read lines from a file at the specified line number. |
| + | + * Returns TRUE if the file was successfully read. |
| + | + */ |
| + | +static BOOL |
| + | +readLines(const char * file, NUM num) |
| +{ | |
| - | + if (!sigactive) |
| - | + quit (1); |
| - | + sigflags &= ~(1 << (signo - 1)); |
| - | +#ifdef HAVE_SIGSETJMP |
| - | + siglongjmp (env, -1); |
| - | +#else |
| - | + longjmp (env, -1); |
| - | +#endif |
| - | +} |
| + | + int fd; |
| + | + int cc; |
| + | + LEN len; |
| + | + LEN lineCount; |
| + | + LEN charCount; |
| + | + char * cp; |
| + | |
| + | + if ((num < 1) || (num > lastNum + 1)) |
| + | + { |
| + | + fprintf(stderr, "Bad line for read\n"); |
| + | |
| - | +extern long rows; |
| - | +int cols = 72; /* wrap column */ |
| + | + return FALSE; |
| + | + } |
| + | |
| - | +void |
| - | +handle_winch (signo) |
| - | + int signo; |
| - | +{ |
| - | +#ifdef TIOCGWINSZ |
| - | + struct winsize ws; /* window size structure */ |
| - | +#endif |
| + | + fd = open(file, 0); |
| + | |
| - | + sigflags &= ~(1 << (signo - 1)); |
| - | +#ifdef TIOCGWINSZ |
| - | + if (ioctl (0, TIOCGWINSZ, (char *) &ws) >= 0) |
| - | + { |
| - | + if (ws.ws_row > 2) |
| - | + rows = ws.ws_row - 2; |
| - | + if (ws.ws_col > 8) |
| - | + cols = ws.ws_col - 8; |
| - | + } |
| - | +#endif |
| - | +} |
| + | + if (fd < 0) |
| + | + { |
| + | + perror(file); |
| + | |
| - | +/* read_file: read a named file/pipe into the buffer; return line count */ |
| - | +long |
| - | +read_file (fn, n) |
| - | + char *fn; |
| - | + long n; |
| - | +{ |
| - | + FILE *fp; |
| - | + long size; |
| - | + |
| - | + |
| - | + fp = (*fn == '!') ? popen (fn + 1, "r") : fopen (strip_escapes (fn), "r"); |
| - | + if (fp == NULL) |
| - | + { |
| - | + fprintf (stderr, "%s: %s\n", fn, strerror (errno)); |
| - | + sprintf (errmsg, "Cannot open input file"); |
| - | + return ERR; |
| - | + } |
| - | + else if ((size = read_stream (fp, n)) < 0) |
| - | + return ERR; |
| - | + else if (((*fn == '!') ? pclose (fp) : fclose (fp)) < 0) |
| - | + { |
| - | + fprintf (stderr, "%s: %s\n", fn, strerror (errno)); |
| - | + sprintf (errmsg, "Cannot close input file"); |
| - | + return ERR; |
| - | + } |
| - | + fprintf (stderr, !scripted ? "%lu\n" : "", size); |
| - | + return current_addr - n; |
| - | +} |
| + | + return FALSE; |
| + | + } |
| + | |
| + | + bufPtr = bufBase; |
| + | + bufUsed = 0; |
| + | + lineCount = 0; |
| + | + charCount = 0; |
| + | + cc = 0; |
| + | |
| - | +char *sbuf; /* file i/o buffer */ |
| - | +int sbufsz; /* file i/o buffer size */ |
| - | +int newline_added; /* if set, newline appended to input file */ |
| + | + printf("\"%s\", ", file); |
| + | + fflush(stdout); |
| + | |
| - | +/* read_stream: read a stream into the editor buffer; return status */ |
| - | +long |
| - | +read_stream (fp, n) |
| - | + FILE *fp; |
| - | + long n; |
| - | +{ |
| - | + line_t *lp = get_addressed_line_node (n); |
| - | + undo_t *up = NULL; |
| - | + unsigned long size = 0; |
| - | + int o_newline_added = newline_added; |
| - | + int o_isbinary = isbinary; |
| - | + int o_n = n; |
| - | + int appended = n == addr_last; |
| - | + int len; |
| - | + |
| - | + isbinary = newline_added = 0; |
| - | + for (current_addr = n; (len = get_stream_line (fp)) > 0; size += len) |
| - | + { |
| - | + SPL1 (); |
| - | + if (put_sbuf_line (sbuf) == NULL) |
| + | + do |
| + { | |
| - | + SPL0 (); |
| - | + return ERR; |
| + | + cp = memchr(bufPtr, '\n', bufUsed); |
| + | + |
| + | + if (cp) |
| + | + { |
| + | + len = (cp - bufPtr) + 1; |
| + | + |
| + | + if (!insertLine(num, bufPtr, len)) |
| + | + { |
| + | + close(fd); |
| + | + |
| + | + return FALSE; |
| + | + } |
| + | + |
| + | + bufPtr += len; |
| + | + bufUsed -= len; |
| + | + charCount += len; |
| + | + lineCount++; |
| + | + num++; |
| + | + |
| + | + continue; |
| + | + } |
| + | + |
| + | + if (bufPtr != bufBase) |
| + | + { |
| + | + memcpy(bufBase, bufPtr, bufUsed); |
| + | + bufPtr = bufBase + bufUsed; |
| + | + } |
| + | + |
| + | + if (bufUsed >= bufSize) |
| + | + { |
| + | + len = (bufSize * 3) / 2; |
| + | + cp = realloc(bufBase, len); |
| + | + |
| + | + if (cp == NULL) |
| + | + { |
| + | + fprintf(stderr, "No memory for buffer\n"); |
| + | + close(fd); |
| + | + |
| + | + return FALSE; |
| + | + } |
| + | + |
| + | + bufBase = cp; |
| + | + bufPtr = bufBase + bufUsed; |
| + | + bufSize = len; |
| + | + } |
| + | + |
| + | + cc = read(fd, bufPtr, bufSize - bufUsed); |
| + | + bufUsed += cc; |
| + | + bufPtr = bufBase; |
| + | + |
| + } | |
| - | + lp = lp->q_forw; |
| - | + if (up) |
| - | + up->t = lp; |
| - | + else if ((up = push_undo_stack (UADD, current_addr, |
| - | + current_addr)) == NULL) |
| + | + while (cc > 0); |
| + | + |
| + | + if (cc < 0) |
| + { | |
| - | + SPL0 (); |
| - | + return ERR; |
| + | + perror(file); |
| + | + close(fd); |
| + | + |
| + | + return FALSE; |
| + } | |
| - | + SPL0 (); |
| - | + } |
| - | + if (len < 0) |
| - | + return ERR; |
| - | + if (o_n && appended && size && o_isbinary && o_newline_added) |
| - | + fputs ("Newline inserted\n", stderr); |
| - | + else if (newline_added && (!appended || (!isbinary && !o_isbinary))) |
| - | + fputs ("Newline appended\n", stderr); |
| - | + if (isbinary && newline_added && !appended) |
| - | + size += 1; |
| - | + if (!size) |
| - | + newline_added = 1; |
| - | + newline_added = appended ? newline_added : o_newline_added; |
| - | + isbinary = isbinary | o_isbinary; |
| - | + return size; |
| - | +} |
| + | |
| + | + if (bufUsed) |
| + | + { |
| + | + if (!insertLine(num, bufPtr, bufUsed)) |
| + | + { |
| + | + close(fd); |
| + | |
| - | +/* get_stream_line: read a line of text from a stream; return line length */ |
| - | +int |
| - | +get_stream_line (fp) |
| - | + FILE *fp; |
| - | +{ |
| - | + register int c; |
| - | + register int i = 0; |
| - | + |
| - | + while (((c = getc (fp)) != EOF || (!feof (fp) && |
| - | + !ferror (fp))) && c != '\n') |
| - | + { |
| - | + REALLOC (sbuf, sbufsz, i + 1, ERR); |
| - | + if (!(sbuf[i++] = c)) |
| - | + isbinary = 1; |
| - | + } |
| - | + REALLOC (sbuf, sbufsz, i + 2, ERR); |
| - | + if (c == '\n') |
| - | + sbuf[i++] = c; |
| - | + else if (ferror (fp)) |
| - | + { |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Cannot read input file"); |
| - | + return ERR; |
| - | + } |
| - | + else if (i) |
| - | + { |
| - | + sbuf[i++] = '\n'; |
| - | + newline_added = 1; |
| - | + } |
| - | + sbuf[i] = '\0'; |
| - | + return (isbinary && newline_added && i) ? --i : i; |
| - | +} |
| + | + return -1; |
| + | + } |
| + | |
| + | + lineCount++; |
| + | + charCount += bufUsed; |
| + | + } |
| + | |
| - | +/* write_file: write a range of lines to a named file/pipe; return line count */ |
| - | +long |
| - | +write_file (fn, mode, n, m) |
| - | + char *fn; |
| - | + char *mode; |
| - | + long n; |
| - | + long m; |
| - | +{ |
| - | + FILE *fp; |
| - | + long size; |
| - | + |
| - | + fp = (*fn == '!') ? popen (fn + 1, "w") : fopen (strip_escapes (fn), mode); |
| - | + if (fp == NULL) |
| - | + { |
| - | + fprintf (stderr, "%s: %s\n", fn, strerror (errno)); |
| - | + sprintf (errmsg, "Cannot open output file"); |
| - | + return ERR; |
| - | + } |
| - | + else if ((size = write_stream (fp, n, m)) < 0) |
| - | + return ERR; |
| - | + else if (((*fn == '!') ? pclose (fp) : fclose (fp)) < 0) |
| - | + { |
| - | + fprintf (stderr, "%s: %s\n", fn, strerror (errno)); |
| - | + sprintf (errmsg, "Cannot close output file"); |
| - | + return ERR; |
| - | + } |
| - | + fprintf (stderr, !scripted ? "%lu\n" : "", size); |
| - | + return n ? m - n + 1 : 0; |
| - | +} |
| + | + close(fd); |
| + | |
| + | + printf("%d lines%s, %d chars\n", lineCount, |
| + | + (bufUsed ? " (incomplete)" : ""), charCount); |
| + | |
| - | +/* write_stream: write a range of lines to a stream; return status */ |
| - | +long |
| - | +write_stream (fp, n, m) |
| - | + FILE *fp; |
| - | + long n; |
| - | + long m; |
| - | +{ |
| - | + line_t *lp = get_addressed_line_node (n); |
| - | + unsigned long size = 0; |
| - | + char *s; |
| - | + int len; |
| - | + |
| - | + for (; n && n <= m; n++, lp = lp->q_forw) |
| - | + { |
| - | + if ((s = get_sbuf_line (lp)) == NULL) |
| - | + return ERR; |
| - | + len = lp->len; |
| - | + if (n != addr_last || !isbinary || !newline_added) |
| - | + s[len++] = '\n'; |
| - | + if (put_stream_line (fp, s, len) < 0) |
| - | + return ERR; |
| - | + size += len; |
| - | + } |
| - | + return size; |
| + | + return TRUE; |
| +} | |
| + | |
| + | |
| - | +/* put_stream_line: write a line of text to a stream; return status */ |
| - | +int |
| - | +put_stream_line (fp, s, len) |
| - | + FILE *fp; |
| - | + char *s; |
| - | + int len; |
| + | +/* |
| + | + * Write the specified lines out to the specified file. |
| + | + * Returns TRUE if successful, or FALSE on an error with a message output. |
| + | + */ |
| + | +static BOOL |
| + | +writeLines(const char * file, NUM num1, NUM num2) |
| +{ | |
| - | + while (len--) |
| - | + if (fputc (*s++, fp) < 0) |
| - | + { |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Cannot write file"); |
| - | + return ERR; |
| - | + } |
| - | + return 0; |
| - | +} |
| + | + int fd; |
| + | + LINE * lp; |
| + | + LEN lineCount; |
| + | + LEN charCount; |
| + | |
| - | +/* get_extended_line: get an extended line from stdin */ |
| - | +char * |
| - | +get_extended_line (sizep, nonl) |
| - | + int *sizep; |
| - | + int nonl; |
| - | +{ |
| - | + static char *cvbuf = NULL; /* buffer */ |
| - | + static int cvbufsz = 0; /* buffer size */ |
| - | + |
| - | + int l, n; |
| - | + char *t = ibufp; |
| - | + |
| - | + while (*t++ != '\n') |
| - | + ; |
| - | + if ((l = t - ibufp) < 2 || !has_trailing_escape (ibufp, ibufp + l - 1)) |
| - | + { |
| - | + *sizep = l; |
| - | + return ibufp; |
| - | + } |
| - | + *sizep = -1; |
| - | + REALLOC (cvbuf, cvbufsz, l, NULL); |
| - | + memcpy (cvbuf, ibufp, l); |
| - | + *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */ |
| - | + if (nonl) |
| - | + l--; /* strip newline */ |
| - | + for (;;) |
| - | + { |
| - | + if ((n = get_tty_line ()) < 0) |
| - | + return NULL; |
| - | + else if (n == 0 || ibuf[n - 1] != '\n') |
| + | + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) |
| + { | |
| - | + sprintf (errmsg, "Unexpected end-of-file"); |
| - | + return NULL; |
| + | + fprintf(stderr, "Bad line range for write\n"); |
| + | + |
| + | + return FALSE; |
| + } | |
| - | + REALLOC (cvbuf, cvbufsz, l + n, NULL); |
| - | + memcpy (cvbuf + l, ibuf, n); |
| - | + l += n; |
| - | + if (n < 2 || !has_trailing_escape (cvbuf, cvbuf + l - 1)) |
| - | + break; |
| - | + *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */ |
| - | + if (nonl) |
| - | + l--; /* strip newline */ |
| - | + } |
| - | + REALLOC (cvbuf, cvbufsz, l + 1, NULL); |
| - | + cvbuf[l] = '\0'; |
| - | + *sizep = l; |
| - | + return cvbuf; |
| - | +} |
| + | |
| + | + lineCount = 0; |
| + | + charCount = 0; |
| + | |
| - | +/* get_tty_line: read a line of text from stdin; return line length */ |
| - | +int |
| - | +get_tty_line () |
| - | +{ |
| - | + register int oi = 0; |
| - | + register int i = 0; |
| - | + int c; |
| - | + |
| - | + /* Read stdin one character at a time to avoid i/o contention |
| - | + with shell escapes invoked by nonterminal input, e.g., |
| - | + ed - <<EOF |
| - | + !cat |
| - | + hello, world |
| - | + EOF */ |
| - | + for (;;) |
| - | + switch (c = getchar ()) |
| - | + { |
| - | + default: |
| - | + oi = 0; |
| - | + REALLOC (ibuf, ibufsz, i + 2, ERR); |
| - | + if (!(ibuf[i++] = c)) |
| - | + isbinary = 1; |
| - | + if (c != '\n') |
| - | + continue; |
| - | + lineno++; |
| - | + ibuf[i] = '\0'; |
| - | + ibufp = ibuf; |
| - | + return i; |
| - | + case EOF: |
| - | + if (ferror (stdin)) |
| - | + { |
| - | + fprintf (stderr, "stdin: %s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Cannot read stdin"); |
| - | + clearerr (stdin); |
| - | + ibufp = NULL; |
| - | + return ERR; |
| - | + } |
| - | + else |
| - | + { |
| - | + clearerr (stdin); |
| - | + if (i != oi) |
| - | + { |
| - | + oi = i; |
| - | + continue; |
| - | + } |
| - | + else if (i) |
| - | + ibuf[i] = '\0'; |
| - | + ibufp = ibuf; |
| - | + return i; |
| - | + } |
| - | + } |
| - | +} |
| + | + fd = creat(file, 0666); |
| + | |
| + | + if (fd < 0) { |
| + | + perror(file); |
| + | |
| + | + return FALSE; |
| + | + } |
| + | |
| - | +#define ESCAPES "\a\b\f\n\r\t\v\\" |
| - | +#define ESCCHARS "abfnrtv\\" |
| + | + printf("\"%s\", ", file); |
| + | + fflush(stdout); |
| + | |
| - | +extern long rows; |
| - | +extern int cols; |
| - | +extern int dlcnt; |
| + | + lp = findLine(num1); |
| + | |
| - | +/* put_tty_line: print text to stdout */ |
| - | +int |
| - | +put_tty_line (s, l, n, gflag) |
| - | + char *s; |
| - | + int l; |
| - | + long n; |
| - | + int gflag; |
| - | +{ |
| - | + int col = 0; |
| - | + char *cp; |
| - | + |
| - | + if (gflag & GNP) |
| - | + { |
| - | + printf ("%ld\t", n); |
| - | + col = 8; |
| - | + } |
| - | + for (; l--; s++) |
| - | + { |
| - | + if ((gflag & GLS) && ++col > cols) |
| + | + if (lp == NULL) |
| + { | |
| - | + fputs ("\\\n", stdout); |
| - | + col = 1; |
| - | + if (!traditional && !scripted && !isglobal && ++dlcnt > rows) |
| - | + { |
| - | + dlcnt = 0; |
| - | + fputs ("Press <RETURN> to continue... ", stdout); |
| - | + fflush (stdout); |
| - | + if (get_tty_line () < 0) |
| - | + return ERR; |
| - | + } |
| + | + close(fd); |
| + | + |
| + | + return FALSE; |
| + } | |
| - | + if (gflag & GLS) |
| + | + |
| + | + while (num1++ <= num2) |
| + { | |
| - | + if (31 < *s && *s < 127 && *s != '\\') |
| - | + putchar (*s); |
| - | + else |
| - | + { |
| - | + putchar ('\\'); |
| - | + col++; |
| - | + if (*s && (cp = strchr (ESCAPES, *s)) != NULL) |
| - | + putchar (ESCCHARS[cp - ESCAPES]); |
| - | + else |
| + | + if (write(fd, lp->data, lp->len) != lp->len) |
| + { | |
| - | + putchar ((((unsigned char) *s & 0300) >> 6) + '0'); |
| - | + putchar ((((unsigned char) *s & 070) >> 3) + '0'); |
| - | + putchar (((unsigned char) *s & 07) + '0'); |
| - | + col += 2; |
| + | + perror(file); |
| + | + close(fd); |
| + | + |
| + | + return FALSE; |
| + } | |
| - | + } |
| + | |
| + | + charCount += lp->len; |
| + | + lineCount++; |
| + | + lp = lp->next; |
| + } | |
| - | + else |
| - | + putchar (*s); |
| - | + } |
| - | + if (!traditional && (gflag & GLS)) |
| - | + putchar ('$'); |
| - | + putchar ('\n'); |
| - | + return 0; |
| - | +} |
| - | + |
| + | |
| + | + if (close(fd) < 0) |
| + | + { |
| + | + perror(file); |
| + | |
| + | + return FALSE; |
| + | + } |
| + | |
| - | +char *rhbuf; /* rhs substitution buffer */ |
| - | +int rhbufsz; /* rhs substitution buffer size */ |
| - | +int rhbufi; /* rhs substitution buffer index */ |
| + | + printf("%d lines, %d chars\n", lineCount, charCount); |
| + | |
| - | +/* extract_subst_tail: extract substitution tail from the command buffer */ |
| - | +int |
| - | +extract_subst_tail (flagp, np) |
| - | + int *flagp; |
| - | + int *np; |
| - | +{ |
| - | + char delimiter; |
| - | + |
| - | + *flagp = *np = 0; |
| - | + if ((delimiter = *ibufp) == '\n') |
| - | + { |
| - | + rhbufi = 0; |
| - | + *flagp = GPR; |
| - | + return 0; |
| - | + } |
| - | + else if (extract_subst_template () == NULL) |
| - | + return ERR; |
| - | + else if (*ibufp == '\n') |
| - | + { |
| - | + *flagp = GPR; |
| - | + return 0; |
| - | + } |
| - | + else if (*ibufp == delimiter) |
| - | + ibufp++; |
| - | + if ('1' <= *ibufp && *ibufp <= '9') |
| - | + { |
| - | + STRTOL (*np, ibufp); |
| - | + return 0; |
| - | + } |
| - | + else if (*ibufp == 'g') |
| - | + { |
| - | + ibufp++; |
| - | + *flagp = GSG; |
| - | + return 0; |
| - | + } |
| - | + return 0; |
| + | + return TRUE; |
| +} | |
| + | |
| + | |
| - | +/* extract_subst_template: return pointer to copy of substitution template |
| - | + in the command buffer */ |
| - | +char * |
| - | +extract_subst_template () |
| + | +/* |
| + | + * Print lines in a specified range. |
| + | + * The last line printed becomes the current line. |
| + | + * If expandFlag is TRUE, then the line is printed specially to |
| + | + * show magic characters. |
| + | + */ |
| + | +static BOOL |
| + | +printLines(NUM num1, NUM num2, BOOL expandFlag) |
| +{ | |
| - | + int n = 0; |
| - | + int i = 0; |
| - | + char c; |
| - | + char delimiter = *ibufp++; |
| - | + |
| - | + if (*ibufp == '%' && *(ibufp + 1) == delimiter) |
| - | + { |
| - | + ibufp++; |
| - | + if (!rhbuf) |
| - | + sprintf (errmsg, "No previous substitution"); |
| - | + return rhbuf; |
| - | + } |
| - | + while (*ibufp != delimiter) |
| - | + { |
| - | + REALLOC (rhbuf, rhbufsz, i + 2, NULL); |
| - | + if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') |
| - | + { |
| - | + i--, ibufp--; |
| - | + break; |
| - | + } |
| - | + else if (c != '\\') |
| - | + ; |
| - | + else if ((rhbuf[i++] = *ibufp++) != '\n') |
| - | + ; |
| - | + else if (!isglobal) |
| + | + const LINE * lp; |
| + | + const unsigned char * cp; |
| + | + int ch; |
| + | + LEN count; |
| + | + |
| + | + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) |
| + { | |
| - | + while ((n = get_tty_line ()) == 0 || |
| - | + (n > 0 && ibuf[n - 1] != '\n')) |
| - | + clearerr (stdin); |
| - | + if (n < 0) |
| - | + return NULL; |
| + | + fprintf(stderr, "Bad line range for print\n"); |
| + | + |
| + | + return FALSE; |
| + } | |
| - | + } |
| - | + REALLOC (rhbuf, rhbufsz, i + 1, NULL); |
| - | + rhbuf[rhbufi = i] = '\0'; |
| - | + return rhbuf; |
| - | +} |
| + | |
| + | + lp = findLine(num1); |
| + | |
| - | +char *rbuf; /* substitute_matching_text buffer */ |
| - | +int rbufsz; /* substitute_matching_text buffer size */ |
| + | + if (lp == NULL) |
| + | + return FALSE; |
| + | |
| - | +/* search_and_replace: for each line in a range, change text matching a pattern |
| - | + according to a substitution template; return status */ |
| - | +int |
| - | +search_and_replace (pat, gflag, kth) |
| - | + pattern_t *pat; |
| - | + int gflag; |
| - | + int kth; |
| - | +{ |
| - | + undo_t *up; |
| - | + char *txt; |
| - | + char *eot; |
| - | + long lc; |
| - | + int nsubs = 0; |
| - | + line_t *lp; |
| - | + int len; |
| - | + |
| - | + current_addr = first_addr - 1; |
| - | + for (lc = 0; lc <= second_addr - first_addr; lc++) |
| - | + { |
| - | + lp = get_addressed_line_node (++current_addr); |
| - | + if ((len = substitute_matching_text (pat, lp, gflag, kth)) < 0) |
| - | + return ERR; |
| - | + else if (len) |
| + | + while (num1 <= num2) |
| + { | |
| - | + up = NULL; |
| - | + if (delete_lines (current_addr, current_addr) < 0) |
| - | + return ERR; |
| - | + txt = rbuf; |
| - | + eot = rbuf + len; |
| - | + SPL1 (); |
| - | + do |
| - | + { |
| - | + if ((txt = put_sbuf_line (txt)) == NULL) |
| + | + if (!expandFlag) |
| + { | |
| - | + SPL0 (); |
| - | + return ERR; |
| + | + write(STDOUT, lp->data, lp->len); |
| + | + setCurNum(num1++); |
| + | + lp = lp->next; |
| + | + |
| + | + continue; |
| + } | |
| - | + else if (up) |
| - | + up->t = get_addressed_line_node (current_addr); |
| - | + else if ((up = push_undo_stack (UADD, |
| - | + current_addr, current_addr)) == NULL) |
| + | + |
| + | + /* |
| + | + * Show control characters and characters with the |
| + | + * high bit set specially. |
| + | + */ |
| + | + cp = lp->data; |
| + | + count = lp->len; |
| + | + |
| + | + if ((count > 0) && (cp[count - 1] == '\n')) |
| + | + count--; |
| + | + |
| + | + while (count-- > 0) |
| + { | |
| - | + SPL0 (); |
| - | + return ERR; |
| + | + ch = *cp++; |
| + | + |
| + | + if (ch & 0x80) |
| + | + { |
| + | + fputs("M-", stdout); |
| + | + ch &= 0x7f; |
| + | + } |
| + | + |
| + | + if (ch < ' ') |
| + | + { |
| + | + fputc('^', stdout); |
| + | + ch += '@'; |
| + | + } |
| + | + |
| + | + if (ch == 0x7f) |
| + | + { |
| + | + fputc('^', stdout); |
| + | + ch = '?'; |
| + | + } |
| + | + |
| + | + fputc(ch, stdout); |
| + } | |
| - | + } |
| - | + while (txt != eot); |
| - | + SPL0 (); |
| - | + nsubs++; |
| + | + |
| + | + fputs("$\n", stdout); |
| + | + |
| + | + setCurNum(num1++); |
| + | + lp = lp->next; |
| + } | |
| - | + } |
| - | + if (nsubs == 0 && !(gflag & GLB)) |
| - | + { |
| - | + sprintf (errmsg, "No match"); |
| - | + return ERR; |
| - | + } |
| - | + else if ((gflag & (GPR | GLS | GNP)) && |
| - | + display_lines (current_addr, current_addr, gflag) < 0) |
| - | + return ERR; |
| - | + return 0; |
| + | + |
| + | + return TRUE; |
| +} | |
| + | |
| + | |
| - | +/* substitute_matching_text: replace text matched by a pattern according to |
| - | + a substitution template; return pointer to the modified text */ |
| - | +int |
| - | +substitute_matching_text (pat, lp, gflag, kth) |
| - | + pattern_t *pat; |
| - | + line_t *lp; |
| - | + int gflag; |
| - | + int kth; |
| + | +/* |
| + | + * Insert a new line with the specified text. |
| + | + * The line is inserted so as to become the specified line, |
| + | + * thus pushing any existing and further lines down one. |
| + | + * The inserted line is also set to become the current line. |
| + | + * Returns TRUE if successful. |
| + | + */ |
| + | +static BOOL |
| + | +insertLine(NUM num, const char * data, LEN len) |
| +{ | |
| - | + int off = 0; |
| - | + int changed = 0; |
| - | + int matchno = 0; |
| - | + int i = 0; |
| - | + regmatch_t rm[SE_MAX]; |
| - | + char *txt; |
| - | + char *eot; |
| - | + |
| - | + if ((txt = get_sbuf_line (lp)) == NULL) |
| - | + return ERR; |
| - | + if (isbinary) |
| - | + NUL_TO_NEWLINE (txt, lp->len); |
| - | + eot = txt + lp->len; |
| - | + if (!regexec (pat, txt, SE_MAX, rm, 0)) |
| - | + { |
| - | + do |
| + | + LINE * newLp; |
| + | + LINE * lp; |
| + | + |
| + | + if ((num < 1) || (num > lastNum + 1)) |
| + { | |
| - | + if (!kth || kth == ++matchno) |
| - | + { |
| - | + changed++; |
| - | + i = rm[0].rm_so; |
| - | + REALLOC (rbuf, rbufsz, off + i, ERR); |
| - | + if (isbinary) |
| - | + NEWLINE_TO_NUL (txt, rm[0].rm_eo); |
| - | + memcpy (rbuf + off, txt, i); |
| - | + off += i; |
| - | + if ((off = apply_subst_template (txt, rm, off, |
| - | + pat->re_nsub)) < 0) |
| - | + return ERR; |
| - | + } |
| - | + else |
| - | + { |
| - | + i = rm[0].rm_eo; |
| - | + REALLOC (rbuf, rbufsz, off + i, ERR); |
| - | + if (isbinary) |
| - | + NEWLINE_TO_NUL (txt, i); |
| - | + memcpy (rbuf + off, txt, i); |
| - | + off += i; |
| - | + } |
| - | + txt += rm[0].rm_eo; |
| + | + fprintf(stderr, "Inserting at bad line number\n"); |
| + | + |
| + | + return FALSE; |
| + } | |
| - | + while (*txt && (!changed || ((gflag & GSG) && rm[0].rm_eo)) && |
| - | + !regexec (pat, txt, SE_MAX, rm, REG_NOTBOL)); |
| - | + i = eot - txt; |
| - | + REALLOC (rbuf, rbufsz, off + i + 2, ERR); |
| - | + if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) |
| + | + |
| + | + newLp = (LINE *) malloc(sizeof(LINE) + len - 1); |
| + | + |
| + | + if (newLp == NULL) |
| + { | |
| - | + sprintf (errmsg, "Infinite substitution loop"); |
| - | + return ERR; |
| + | + fprintf(stderr, "Failed to allocate memory for line\n"); |
| + | + |
| + | + return FALSE; |
| + } | |
| - | + if (isbinary) |
| - | + NEWLINE_TO_NUL (txt, i); |
| - | + memcpy (rbuf + off, txt, i); |
| - | + memcpy (rbuf + off + i, "\n", 2); |
| - | + } |
| - | + return changed ? off + i + 1 : 0; |
| - | +} |
| + | |
| + | + memcpy(newLp->data, data, len); |
| + | + newLp->len = len; |
| + | |
| - | +/* apply_subst_template: modify text according to a substitution template; |
| - | + return offset to end of modified text */ |
| - | +int |
| - | +apply_subst_template (boln, rm, off, re_nsub) |
| - | + char *boln; |
| - | + regmatch_t *rm; |
| - | + int off; |
| - | + int re_nsub; |
| - | +{ |
| - | + int j = 0; |
| - | + int k = 0; |
| - | + int n; |
| - | + char *sub = rhbuf; |
| - | + |
| - | + for (; sub - rhbuf < rhbufi; sub++) |
| - | + if (*sub == '&') |
| - | + { |
| - | + j = rm[0].rm_so; |
| - | + k = rm[0].rm_eo; |
| - | + REALLOC (rbuf, rbufsz, off + k - j, ERR); |
| - | + while (j < k) |
| - | + rbuf[off++] = boln[j++]; |
| - | + } |
| - | + else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' && |
| - | + (n = *sub - '0') <= re_nsub) |
| - | + { |
| - | + j = rm[n].rm_so; |
| - | + k = rm[n].rm_eo; |
| - | + REALLOC (rbuf, rbufsz, off + k - j, ERR); |
| - | + while (j < k) |
| - | + rbuf[off++] = boln[j++]; |
| - | + } |
| - | + else |
| - | + { |
| - | + REALLOC (rbuf, rbufsz, off + 1, ERR); |
| - | + rbuf[off++] = *sub; |
| - | + } |
| - | + REALLOC (rbuf, rbufsz, off + 1, ERR); |
| - | + rbuf[off] = '\0'; |
| - | + return off; |
| - | +} |
| + | + if (num > lastNum) |
| + | + lp = &lines; |
| + | + else |
| + | + { |
| + | + lp = findLine(num); |
| + | |
| + | + if (lp == NULL) |
| + | + { |
| + | + free((char *) newLp); |
| + | |
| + | + return FALSE; |
| + | + } |
| + | + } |
| + | |
| - | +#define USIZE 100 /* undo stack size */ |
| - | +undo_t *ustack = NULL; /* undo stack */ |
| - | +long usize = 0; /* stack size variable */ |
| - | +long u_p = 0; /* undo stack pointer */ |
| + | + newLp->next = lp; |
| + | + newLp->prev = lp->prev; |
| + | + lp->prev->next = newLp; |
| + | + lp->prev = newLp; |
| + | |
| - | +/* push_undo_stack: return pointer to intialized undo node */ |
| - | +undo_t * |
| - | +push_undo_stack (type, from, to) |
| - | + int type; |
| - | + long from; |
| - | + long to; |
| - | +{ |
| - | + undo_t *t; |
| - | + |
| - | + if ((t = ustack) == NULL && |
| - | + (t = ustack = (undo_t *) malloc ((usize = USIZE) * sizeof (undo_t))) == NULL) |
| - | + { |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Out of memory"); |
| - | + return NULL; |
| - | + } |
| - | + else if (u_p >= usize && |
| - | + (t = (undo_t *) realloc (ustack, (usize += USIZE) * sizeof (undo_t))) == NULL) |
| - | + { |
| - | + /* out of memory - release undo stack */ |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Out of memory"); |
| - | + clear_undo_stack (); |
| - | + free (ustack); |
| - | + ustack = NULL; |
| - | + usize = 0; |
| - | + return NULL; |
| - | + } |
| - | + ustack = t; |
| - | + ustack[u_p].type = type; |
| - | + ustack[u_p].t = get_addressed_line_node (to); |
| - | + ustack[u_p].h = get_addressed_line_node (from); |
| - | + return ustack + u_p++; |
| + | + lastNum++; |
| + | + dirty = TRUE; |
| + | + |
| + | + return setCurNum(num); |
| +} | |
| + | |
| + | |
| - | +/* USWAP: swap undo nodes */ |
| - | +#define USWAP(x, y) \ |
| - | + do \ |
| - | + { \ |
| - | + undo_t utmp; \ |
| - | + utmp = (x), (x) = (y), (y) = utmp; \ |
| - | + } \ |
| - | + while (0) |
| + | +/* |
| + | + * Delete lines from the given range. |
| + | + */ |
| + | +static BOOL |
| + | +deleteLines(NUM num1, NUM num2) |
| + | +{ |
| + | + LINE * lp; |
| + | + LINE * nlp; |
| + | + LINE * plp; |
| + | + NUM count; |
| + | |
| + | + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) |
| + | + { |
| + | + fprintf(stderr, "Bad line numbers for delete\n"); |
| + | |
| - | +long u_current_addr = -1; /* if >= 0, undo enabled */ |
| - | +long u_addr_last = -1; /* if >= 0, undo enabled */ |
| + | + return FALSE; |
| + | + } |
| + | |
| - | +/* pop_undo_stack: undo last change to the editor buffer */ |
| - | +int |
| - | +pop_undo_stack () |
| - | +{ |
| - | + long n; |
| - | + long o_current_addr = current_addr; |
| - | + long o_addr_last = addr_last; |
| - | + |
| - | + if (u_current_addr == -1 || u_addr_last == -1) |
| - | + { |
| - | + sprintf (errmsg, "Nothing to undo"); |
| - | + return ERR; |
| - | + } |
| - | + else if (u_p) |
| - | + modified = 1; |
| - | + get_addressed_line_node (0); /* this get_addressed_line_node last! */ |
| - | + SPL1 (); |
| - | + for (n = u_p; n-- > 0;) |
| - | + { |
| - | + switch (ustack[n].type) |
| + | + lp = findLine(num1); |
| + | + |
| + | + if (lp == NULL) |
| + | + return FALSE; |
| + | + |
| + | + if ((curNum >= num1) && (curNum <= num2)) |
| + { | |
| - | + case UADD: |
| - | + REQUE (ustack[n].h->q_back, ustack[n].t->q_forw); |
| - | + break; |
| - | + case UDEL: |
| - | + REQUE (ustack[n].h->q_back, ustack[n].h); |
| - | + REQUE (ustack[n].t, ustack[n].t->q_forw); |
| - | + break; |
| - | + case UMOV: |
| - | + case VMOV: |
| - | + REQUE (ustack[n - 1].h, ustack[n].h->q_forw); |
| - | + REQUE (ustack[n].t->q_back, ustack[n - 1].t); |
| - | + REQUE (ustack[n].h, ustack[n].t); |
| - | + n--; |
| - | + break; |
| - | + default: |
| - | + /*NOTREACHED */ |
| - | + ; |
| + | + if (num2 < lastNum) |
| + | + setCurNum(num2 + 1); |
| + | + else if (num1 > 1) |
| + | + setCurNum(num1 - 1); |
| + | + else |
| + | + curNum = 0; |
| + } | |
| - | + ustack[n].type ^= 1; |
| - | + } |
| - | + /* reverse undo stack order */ |
| - | + for (n = u_p; n-- > (u_p + 1) / 2;) |
| - | + USWAP (ustack[n], ustack[u_p - 1 - n]); |
| - | + if (isglobal) |
| - | + clear_active_list (); |
| - | + current_addr = u_current_addr, u_current_addr = o_current_addr; |
| - | + addr_last = u_addr_last, u_addr_last = o_addr_last; |
| - | + SPL0 (); |
| - | + return 0; |
| - | +} |
| + | |
| + | + count = num2 - num1 + 1; |
| + | |
| - | +/* clear_undo_stack: clear the undo stack */ |
| - | +void |
| - | +clear_undo_stack () |
| - | +{ |
| - | + line_t *lp, *ep, *tl; |
| - | + |
| - | + while (u_p--) |
| - | + if (ustack[u_p].type == UDEL) |
| - | + { |
| - | + ep = ustack[u_p].t->q_forw; |
| - | + for (lp = ustack[u_p].h; lp != ep; lp = tl) |
| - | + { |
| - | + unmark_line_node (lp); |
| - | + tl = lp->q_forw; |
| - | + free (lp); |
| - | + } |
| - | + } |
| - | + u_p = 0; |
| - | + u_current_addr = current_addr; |
| - | + u_addr_last = addr_last; |
| - | +} |
| + | + if (curNum > num2) |
| + | + curNum -= count; |
| + | |
| + | + lastNum -= count; |
| + | |
| + | + while (count-- > 0) |
| + | + { |
| + | + nlp = lp->next; |
| + | + plp = lp->prev; |
| + | + plp->next = nlp; |
| + | + nlp->prev = plp; |
| + | + lp->next = NULL; |
| + | + lp->prev = NULL; |
| + | + lp->len = 0; |
| + | + free(lp); |
| + | + lp = nlp; |
| + | + } |
| + | |
| + | + dirty = TRUE; |
| + | |
| - | +/* build_active_list: add line matching a pattern to the global-active list */ |
| - | +int |
| - | +build_active_list (isgcmd) |
| - | + int isgcmd; |
| - | +{ |
| - | + pattern_t *pat; |
| - | + line_t *lp; |
| - | + long n; |
| - | + char *s; |
| - | + char delimiter; |
| - | + |
| - | + if ((delimiter = *ibufp) == ' ' || delimiter == '\n') |
| - | + { |
| - | + sprintf (errmsg, "Invalid pattern delimiter"); |
| - | + return ERR; |
| - | + } |
| - | + else if ((pat = get_compiled_pattern ()) == NULL) |
| - | + return ERR; |
| - | + else if (*ibufp == delimiter) |
| - | + ibufp++; |
| - | + clear_active_list (); |
| - | + lp = get_addressed_line_node (first_addr); |
| - | + for (n = first_addr; n <= second_addr; n++, lp = lp->q_forw) |
| - | + { |
| - | + if ((s = get_sbuf_line (lp)) == NULL) |
| - | + return ERR; |
| - | + if (isbinary) |
| - | + NUL_TO_NEWLINE (s, lp->len); |
| - | + if (!regexec (pat, s, 0, NULL, 0) == isgcmd && |
| - | + set_active_node (lp) < 0) |
| - | + return ERR; |
| - | + } |
| - | + return 0; |
| + | + return TRUE; |
| +} | |
| + | |
| + | |
| - | +/* exec_global: apply command list in the command buffer to the active |
| - | + lines in a range; return command status */ |
| - | +long |
| - | +exec_global (interact, gflag) |
| - | + int interact; |
| - | + int gflag; |
| + | +/* |
| + | + * Search for a line which contains the specified string. |
| + | + * If the string is NULL, then the previously searched for string |
| + | + * is used. The currently searched for string is saved for future use. |
| + | + * Returns the line number which matches, or 0 if there was no match |
| + | + * with an error printed. |
| + | + */ |
| + | +static NUM |
| + | +searchLines(const char * str, NUM num1, NUM num2) |
| +{ | |
| - | + static char *ocmd = NULL; |
| - | + static int ocmdsz = 0; |
| - | + |
| - | + line_t *lp = NULL; |
| - | + int status; |
| - | + int n; |
| - | + char *cmd = NULL; |
| - | + |
| - | + if (!interact) |
| - | + if (traditional && !strcmp (ibufp, "\n")) |
| - | + cmd = "p\n"; /* null cmd-list == `p' */ |
| - | + else if ((cmd = get_extended_line (&n, 0)) == NULL) |
| - | + return ERR; |
| - | + clear_undo_stack (); |
| - | + while ((lp = next_active_node ()) != NULL) |
| - | + { |
| - | + if ((current_addr = get_line_node_addr (lp)) < 0) |
| - | + return ERR; |
| - | + if (interact) |
| + | + const LINE * lp; |
| + | + int len; |
| + | + |
| + | + if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) |
| + | + { |
| + | + fprintf(stderr, "Bad line numbers for search\n"); |
| + | + |
| + | + return 0; |
| + | + } |
| + | + |
| + | + if (*str == '\0') |
| + { | |
| - | + /* print current_addr; get a command in global syntax */ |
| - | + if (display_lines (current_addr, current_addr, gflag) < 0) |
| - | + return ERR; |
| - | + while ((n = get_tty_line ()) > 0 && |
| - | + ibuf[n - 1] != '\n') |
| - | + clearerr (stdin); |
| - | + if (n < 0) |
| - | + return ERR; |
| - | + else if (n == 0) |
| - | + { |
| - | + sprintf (errmsg, "Unexpected end-of-file"); |
| - | + return ERR; |
| - | + } |
| - | + else if (n == 1 && !strcmp (ibuf, "\n")) |
| - | + continue; |
| - | + else if (n == 2 && !strcmp (ibuf, "&\n")) |
| - | + { |
| - | + if (cmd == NULL) |
| + | + if (searchString[0] == '\0') |
| + { | |
| - | + sprintf (errmsg, "No previous command"); |
| - | + return ERR; |
| + | + fprintf(stderr, "No previous search string\n"); |
| + | + |
| + | + return 0; |
| + } | |
| - | + else |
| - | + cmd = ocmd; |
| - | + } |
| - | + else if ((cmd = get_extended_line (&n, 0)) == NULL) |
| - | + return ERR; |
| - | + else |
| - | + { |
| - | + REALLOC (ocmd, ocmdsz, n + 1, ERR); |
| - | + memcpy (ocmd, cmd, n + 1); |
| - | + cmd = ocmd; |
| - | + } |
| + | |
| + | + str = searchString; |
| + } | |
| - | + ibufp = cmd; |
| - | + for (; *ibufp;) |
| - | + if ((status = extract_addr_range ()) < 0 || |
| - | + (status = exec_command ()) < 0 || |
| - | + (status > 0 && (status = display_lines ( |
| - | + current_addr, current_addr, status)) < 0)) |
| - | + return status; |
| - | + } |
| - | + return 0; |
| - | +} |
| + | |
| + | + if (str != searchString) |
| + | + strcpy(searchString, str); |
| + | |
| - | +line_t **active_list; /* list of lines active in a global command */ |
| - | +long active_last; /* index of last active line in active_list */ |
| - | +long active_size; /* size of active_list */ |
| - | +long active_ptr; /* active_list index (non-decreasing) */ |
| - | +long active_ndx; /* active_list index (modulo active_last) */ |
| + | + len = strlen(str); |
| + | |
| - | +/* set_active_node: add a line node to the global-active list */ |
| - | +int |
| - | +set_active_node (lp) |
| - | + line_t *lp; |
| - | +{ |
| - | + if (active_last + 1 > active_size) |
| - | + { |
| - | + int ti = active_size; |
| - | + line_t **ts; |
| - | + SPL1 (); |
| - | + if (active_list != NULL) |
| - | + { |
| - | + if ((ts = (line_t **) realloc (active_list, |
| - | + (ti += MINBUFSZ) * sizeof (line_t **))) == NULL) |
| - | + { |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Out of memory"); |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| - | + } |
| - | + else |
| + | + lp = findLine(num1); |
| + | + |
| + | + if (lp == NULL) |
| + | + return 0; |
| + | + |
| + | + while (num1 <= num2) |
| + { | |
| - | + if ((ts = (line_t **) malloc ((ti += MINBUFSZ) * |
| - | + sizeof (line_t **))) == NULL) |
| - | + { |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Out of memory"); |
| - | + SPL0 (); |
| - | + return ERR; |
| - | + } |
| + | + if (findString(lp, str, len, 0) >= 0) |
| + | + return num1; |
| + | + |
| + | + num1++; |
| + | + lp = lp->next; |
| + } | |
| - | + active_size = ti; |
| - | + active_list = ts; |
| - | + SPL0 (); |
| - | + } |
| - | + active_list[active_last++] = lp; |
| - | + return 0; |
| + | + |
| + | + fprintf(stderr, "Cannot find string \"%s\"\n", str); |
| + | + |
| + | + return 0; |
| +} | |
| + | |
| + | |
| - | +/* unset_active_nodes: remove a range of lines from the global-active list */ |
| - | +void |
| - | +unset_active_nodes (np, mp) |
| - | + line_t *np, *mp; |
| + | +/* |
| + | + * Return a pointer to the specified line number. |
| + | + */ |
| + | +static LINE * |
| + | +findLine(NUM num) |
| +{ | |
| - | + line_t *lp; |
| - | + long i; |
| + | + LINE * lp; |
| + | + NUM lnum; |
| + | |
| - | + for (lp = np; lp != mp; lp = lp->q_forw) |
| - | + for (i = 0; i < active_last; i++) |
| - | + if (active_list[active_ndx] == lp) |
| + | + if ((num < 1) || (num > lastNum)) |
| + { | |
| - | + active_list[active_ndx] = NULL; |
| - | + active_ndx = INC_MOD (active_ndx, active_last - 1); |
| - | + break; |
| + | + fprintf(stderr, "Line number %d does not exist\n", num); |
| + | + |
| + | + return NULL; |
| + } | |
| - | + else |
| - | + active_ndx = INC_MOD (active_ndx, active_last - 1); |
| - | +} |
| + | |
| + | + if (curNum <= 0) |
| + | + { |
| + | + curNum = 1; |
| + | + curLine = lines.next; |
| + | + } |
| + | |
| - | +/* next_active_node: return the next global-active line node */ |
| - | +line_t * |
| - | +next_active_node () |
| - | +{ |
| - | + while (active_ptr < active_last && active_list[active_ptr] == NULL) |
| - | + active_ptr++; |
| - | + return (active_ptr < active_last) ? active_list[active_ptr++] : NULL; |
| - | +} |
| + | + if (num == curNum) |
| + | + return curLine; |
| + | |
| + | + lp = curLine; |
| + | + lnum = curNum; |
| + | |
| - | +/* clear_active_list: clear the global-active list */ |
| - | +void |
| - | +clear_active_list () |
| - | +{ |
| - | + SPL1 (); |
| - | + active_size = active_last = active_ptr = active_ndx = 0; |
| - | + if (active_list != NULL) |
| - | + free (active_list); |
| - | + active_list = NULL; |
| - | + SPL0 (); |
| - | +} |
| + | + if (num < (curNum / 2)) |
| + | + { |
| + | + lp = lines.next; |
| + | + lnum = 1; |
| + | + } |
| + | + else if (num > ((curNum + lastNum) / 2)) |
| + | + { |
| + | + lp = lines.prev; |
| + | + lnum = lastNum; |
| + | + } |
| + | |
| + | + while (lnum < num) |
| + | + { |
| + | + lp = lp->next; |
| + | + lnum++; |
| + | + } |
| + | |
| + | + while (lnum > num) |
| + | + { |
| + | + lp = lp->prev; |
| + | + lnum--; |
| + | + } |
| + | |
| - | +/* get_compiled_pattern: return pointer to compiled pattern from command |
| - | + buffer */ |
| - | +pattern_t * |
| - | +get_compiled_pattern () |
| - | +{ |
| - | + static pattern_t *exp = NULL; |
| - | + |
| - | + char *exps; |
| - | + char delimiter; |
| - | + int n; |
| - | + |
| - | + if ((delimiter = *ibufp) == ' ') |
| - | + { |
| - | + sprintf (errmsg, "Invalid pattern delimiter"); |
| - | + return NULL; |
| - | + } |
| - | + else if (delimiter == '\n' || *++ibufp == '\n' || *ibufp == delimiter) |
| - | + { |
| - | + if (!exp) |
| - | + sprintf (errmsg, "No previous pattern"); |
| - | + return exp; |
| - | + } |
| - | + else if ((exps = extract_pattern (delimiter)) == NULL) |
| - | + return NULL; |
| - | + /* buffer alloc'd && not reserved */ |
| - | + if (exp && !patlock) |
| - | + regfree (exp); |
| - | + else if ((exp = (pattern_t *) malloc (sizeof (pattern_t))) == NULL) |
| - | + { |
| - | + fprintf (stderr, "%s\n", strerror (errno)); |
| - | + sprintf (errmsg, "Out of memory"); |
| - | + return NULL; |
| - | + } |
| - | + patlock = 0; |
| - | + if ((n = regcomp (exp, exps, 0))) |
| - | + { |
| - | + regerror (n, exp, errmsg, ERRSZ); |
| - | + free (exp); |
| - | + return exp = NULL; |
| - | + } |
| - | + return exp; |
| + | + return lp; |
| +} | |
| + | |
| + | |
| - | +/* extract_pattern: copy a pattern string from the command buffer; return |
| - | + pointer to the copy */ |
| - | +char * |
| - | +extract_pattern (delimiter) |
| - | + int delimiter; |
| + | +/* |
| + | + * Set the current line number. |
| + | + * Returns TRUE if successful. |
| + | + */ |
| + | +static BOOL |
| + | +setCurNum(NUM num) |
| +{ | |
| - | + static char *lhbuf = NULL; /* buffer */ |
| - | + static int lhbufsz = 0; /* buffer size */ |
| - | + |
| - | + char *nd; |
| - | + int len; |
| - | + |
| - | + for (nd = ibufp; *nd != delimiter && *nd != '\n'; nd++) |
| - | + switch (*nd) |
| - | + { |
| - | + default: |
| - | + break; |
| - | + case '[': |
| - | + if ((nd = parse_char_class (++nd)) == NULL) |
| - | + { |
| - | + sprintf (errmsg, "Unbalanced brackets ([])"); |
| - | + return NULL; |
| - | + } |
| - | + break; |
| - | + case '\\': |
| - | + if (*++nd == '\n') |
| - | + { |
| - | + sprintf (errmsg, "Trailing backslash (\\)"); |
| - | + return NULL; |
| - | + } |
| - | + break; |
| - | + } |
| - | + len = nd - ibufp; |
| - | + REALLOC (lhbuf, lhbufsz, len + 1, NULL); |
| - | + memcpy (lhbuf, ibufp, len); |
| - | + lhbuf[len] = '\0'; |
| - | + ibufp = nd; |
| - | + return (isbinary) ? NUL_TO_NEWLINE (lhbuf, len) : lhbuf; |
| - | +} |
| + | + LINE * lp; |
| + | |
| + | + lp = findLine(num); |
| + | |
| - | +/* parse_char_class: expand a POSIX character class */ |
| - | +char * |
| - | +parse_char_class (s) |
| - | + char *s; |
| - | +{ |
| - | + int c, d; |
| - | + |
| - | + if (*s == '^') |
| - | + s++; |
| - | + if (*s == ']') |
| - | + s++; |
| - | + for (; *s != ']' && *s != '\n'; s++) |
| - | + if (*s == '[' && ((d = *(s + 1)) == '.' || d == ':' || d == '=')) |
| - | + for (s++, c = *++s; *s != ']' || c != d; s++) |
| - | + if ((c = *s) == '\n') |
| - | + return NULL; |
| - | + return (*s == ']') ? s : NULL; |
| - | +} |
| - | --- /dev/null 2005-04-22 11:15:01.120978184 -0400 |
| - | +++ editors/ed.h 2005-04-22 11:15:09.000000000 -0400 |
| - | @@ -0,0 +1,256 @@ |
| - | +/* ed.h: type and constant definitions for the ed editor. */ |
| - | +/* ed line editor. |
| - | + Copyright (C) 1993, 1994 Andrew Moore, Talke Studio |
| - | + All Rights Reserved |
| - | + |
| - | + This program is free software; you can redistribute it and/or modify |
| - | + it under the terms of the GNU General Public License as published by |
| - | + the Free Software Foundation; either version 2, or (at your option) |
| - | + any later version. |
| - | + |
| - | + This program is distributed in the hope that it will be useful, but |
| - | + WITHOUT ANY WARRANTY; without even the implied warranty of |
| - | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| - | + General Public License for more details. |
| - | + |
| - | + You should have received a copy of the GNU General Public License |
| - | + along with this program; if not, write to the Free Software |
| - | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| - | + |
| - | + @(#)$Id: ed.h,v 1.14 1994/11/13 04:25:44 alm Exp $ |
| - | +*/ |
| + | + if (lp == NULL) |
| + | + return FALSE; |
| + | |
| - | +#include <stdio.h> |
| + | + curNum = num; |
| + | + curLine = lp; |
| + | + |
| + | + return TRUE; |
| + | +} |
| + | |
| - | +#define ERR (-2) |
| - | +#define EMOD (-3) |
| - | +#define FATAL (-4) |
| - | + |
| - | +#define ERRSZ (PATH_MAX + 40) /* size of error message buffer */ |
| - | +#define MINBUFSZ 512 /* minimum buffer size: must be > 0 */ |
| - | +#define SE_MAX 30 /* max subexpressions in a regular expression */ |
| - | + |
| - | +#define LINECHARS INT_MAX /* max chars per line */ |
| - | + |
| - | +/* gflags */ |
| - | +#define GLB 001 /* global command */ |
| - | +#define GPR 002 /* print after command */ |
| - | +#define GLS 004 /* list after command */ |
| - | +#define GNP 010 /* enumerate after command */ |
| - | +#define GSG 020 /* global substitute */ |
| - | + |
| - | +typedef regex_t pattern_t; |
| - | + |
| - | +/* Line node */ |
| - | +typedef struct line |
| - | + { |
| - | + struct line *q_forw; |
| - | + struct line *q_back; |
| - | + off_t seek; /* address of line in scratch buffer */ |
| - | + int len; /* length of line */ |
| - | + } |
| - | +line_t; |
| - | + |
| - | + |
| - | +typedef struct undo |
| - | + { |
| - | + |
| - | +/* type of undo nodes */ |
| - | +#define UADD 0 |
| - | +#define UDEL 1 |
| - | +#define UMOV 2 |
| - | +#define VMOV 3 |
| - | + |
| - | + int type; /* command type */ |
| - | + line_t *h; /* head of list */ |
| - | + line_t *t; /* tail of list */ |
| - | + } |
| - | +undo_t; |
| - | + |
| - | +#define INC_MOD(l, k) ((l) + 1 > (k) ? 0 : (l) + 1) |
| - | +#define DEC_MOD(l, k) ((l) - 1 < 0 ? (k) : (l) - 1) |
| - | + |
| - | +/* SPL1: disable some interrupts (requires reliable signals) */ |
| - | +#define SPL1() mutex++ |
| - | + |
| - | +/* SPL0: enable all interrupts; check sigflags (requires reliable signals) */ |
| - | +#define SPL0() \ |
| - | + do \ |
| - | + { \ |
| - | + if (--mutex == 0) \ |
| - | + { \ |
| - | + if (sigflags & (1 << (SIGHUP - 1))) handle_hup (SIGHUP); \ |
| - | + if (sigflags & (1 << (SIGINT - 1))) handle_int (SIGINT); \ |
| - | + } \ |
| - | + } \ |
| - | + while (0) |
| - | + |
| - | +/* STRTOL: convert a string to long */ |
| - | +#define STRTOL(i, p) \ |
| - | + do \ |
| - | + { \ |
| - | + if ((((i) = strtol ((p), &(p), 10)) == LONG_MIN \ |
| - | + || (i) == LONG_MAX) && errno == ERANGE) \ |
| - | + { \ |
| - | + sprintf (errmsg, "Number out of range"); \ |
| - | + (i) = 0; \ |
| - | + return ERR; \ |
| - | + } \ |
| - | + } \ |
| - | + while (0) |
| - | + |
| - | +/* REALLOC: assure at least a minimum size for buffer b */ |
| - | +#define REALLOC(b, n, i, err) \ |
| - | + do \ |
| - | + { \ |
| - | + if ((i) > (n)) \ |
| - | + { \ |
| - | + int ti = (n); \ |
| - | + char *ts; \ |
| - | + SPL1 (); \ |
| - | + if ((b) != NULL) \ |
| - | + { \ |
| - | + if ((ts = (char *) realloc ((b), ti += max ((i), MINBUFSZ))) \ |
| - | + == NULL) \ |
| - | + { \ |
| - | + fprintf (stderr, "%s\n", strerror (errno)); \ |
| - | + sprintf (errmsg, "Out of memory"); \ |
| - | + SPL0 (); \ |
| - | + return err; \ |
| - | + } \ |
| - | + } \ |
| - | + else \ |
| - | + { \ |
| - | + if ((ts = (char *) malloc (ti += max ((i), MINBUFSZ))) \ |
| - | + == NULL) \ |
| - | + { \ |
| - | + fprintf (stderr, "%s\n", strerror (errno)); \ |
| - | + sprintf (errmsg, "Out of memory"); \ |
| - | + SPL0 (); \ |
| - | + return err; \ |
| - | + } \ |
| - | + } \ |
| - | + (n) = ti; \ |
| - | + (b) = ts; \ |
| - | + SPL0 (); \ |
| - | + } \ |
| - | + } \ |
| - | + while (0) |
| - | + |
| - | +/* REQUE: link pred before succ */ |
| - | +#define REQUE(pred, succ) \ |
| - | + ((pred)->q_forw = (succ), (succ)->q_back = (pred)) |
| - | + |
| - | +/* INSQUE: insert elem in circular queue after pred */ |
| - | +#define INSQUE(elem, pred) \ |
| - | + do \ |
| - | + { \ |
| - | + REQUE ((elem), (pred)->q_forw); \ |
| - | + REQUE ((pred), (elem)); \ |
| - | + } \ |
| - | + while (0) |
| - | + |
| - | +/* REMQUE: remove elem from circular queue */ |
| - | +#define REMQUE(elem) \ |
| - | + REQUE ((elem)->q_back, (elem)->q_forw) |
| - | + |
| - | +/* NUL_TO_NEWLINE: overwrite ASCII NULs with newlines */ |
| - | +#define NUL_TO_NEWLINE(s, l) translit_text(s, l, '\0', '\n') |
| - | + |
| - | +/* NEWLINE_TO_NUL: overwrite newlines with ASCII NULs */ |
| - | +#define NEWLINE_TO_NUL(s, l) translit_text(s, l, '\n', '\0') |
| - | + |
| - | +/* Local Function Declarations */ |
| - | +void add_line_node __P ((line_t *)); |
| - | +int append_lines __P ((long)); |
| - | +int apply_subst_template __P ((char *, regmatch_t *, int, int)); |
| - | +int build_active_list __P ((int)); |
| - | +int cbc_decode __P ((char *, FILE *)); |
| - | +int cbc_encode __P ((char *, int, FILE *)); |
| - | +int check_addr_range __P ((long, long)); |
| - | +void clear_active_list __P ((void)); |
| - | +void clear_undo_stack __P ((void)); |
| - | +int close_sbuf __P ((void)); |
| - | +int copy_lines __P ((long)); |
| - | +int delete_lines __P ((long, long)); |
| - | +void delete_yank_lines __P ((void)); |
| - | +int display_lines __P ((long, long, int)); |
| - | +line_t *dup_line_node __P ((line_t *)); |
| - | +int exec_command __P ((void)); |
| - | +long exec_global __P ((int, int)); |
| - | +int extract_addr_range __P ((void)); |
| - | +char *extract_pattern __P ((int)); |
| - | +int extract_subst_tail __P ((int *, int *)); |
| - | +char *extract_subst_template __P ((void)); |
| - | +int filter_lines __P ((long, long, char *)); |
| - | +line_t *get_addressed_line_node __P ((long)); |
| - | +pattern_t *get_compiled_pattern __P ((void)); |
| - | +char *get_extended_line __P ((int *, int)); |
| - | +char *get_filename __P ((void)); |
| - | +int get_keyword __P ((void)); |
| - | +long get_line_node_addr __P ((line_t *)); |
| - | +long get_matching_node_addr __P ((pattern_t *, int)); |
| - | +long get_marked_node_addr __P ((int)); |
| - | +char *get_sbuf_line __P ((line_t *)); |
| - | +int get_shell_command __P ((void)); |
| - | +int get_stream_line __P ((FILE *)); |
| - | +int get_tty_line __P ((void)); |
| - | +void handle_hup __P ((int)); |
| - | +void handle_int __P ((int)); |
| - | +void handle_winch __P ((int)); |
| - | +int has_trailing_escape __P ((char *, char *)); |
| - | +int hex_to_binary __P ((int, int)); |
| - | +void init_buffers __P ((void)); |
| - | +int is_legal_filename __P ((char *)); |
| - | +int is_regular_file __P ((int)); |
| - | +int join_lines __P ((long, long)); |
| - | +int mark_line_node __P ((line_t *, int)); |
| - | +int move_lines __P ((long)); |
| - | +line_t *next_active_node (); |
| - | +long next_addr __P ((void)); |
| - | +int open_sbuf __P ((void)); |
| - | +char *parse_char_class __P ((char *)); |
| - | +int pop_undo_stack __P ((void)); |
| - | +undo_t *push_undo_stack __P ((int, long, long)); |
| - | +int put_lines __P ((long)); |
| - | +char *put_sbuf_line __P ((char *)); |
| - | +int put_stream_line __P ((FILE *, char *, int)); |
| - | +int put_tty_line __P ((char *, int, long, int)); |
| - | +void quit __P ((int)); |
| - | +long read_file __P ((char *, long)); |
| - | +long read_stream __P ((FILE *, long)); |
| - | +void (*reliable_signal __P ((int, void (*) ()))) (); |
| - | +int search_and_replace __P ((pattern_t *, int, int)); |
| - | +int set_active_node __P ((line_t *)); |
| - | +void signal_hup __P ((int)); |
| - | +void signal_int __P ((int)); |
| - | +char *strip_escapes __P ((char *)); |
| - | +int substitute_matching_text __P ((pattern_t *, line_t *, int, int)); |
| - | +char *translit_text __P ((char *, int, int, int)); |
| - | +void unmark_line_node __P ((line_t *)); |
| - | +void unset_active_nodes __P ((line_t *, line_t *)); |
| - | +long write_file __P ((char *, char *, long, long)); |
| - | +long write_stream __P ((FILE *, long, long)); |
| - | +int yank_lines __P ((long, long)); |
| - | + |
| - | +/* global buffers */ |
| - | +extern char stdinbuf[]; |
| - | +extern char *errmsg; |
| - | +extern char *ibuf; |
| - | +extern char *ibufp; |
| - | +extern int ibufsz; |
| - | + |
| - | +/* global flags */ |
| - | +extern int isbinary; |
| - | +extern int isglobal; |
| - | +extern int modified; |
| - | +extern int mutex; |
| - | +extern int sigflags; |
| - | +extern int traditional; |
| - | + |
| - | +/* global vars */ |
| - | +extern long addr_last; |
| - | +extern long current_addr; |
| - | +extern long first_addr; |
| - | +extern int lineno; |
| - | +extern long second_addr; |
| + | +/* END CODE */ |