aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2005-04-24 05:18:00 +0000
committerMike Frysinger <vapier@gentoo.org>2005-04-24 05:18:00 +0000
commitcf131bb3280d555e40808c28366d0cb33c6a4497 (patch)
treeaef075e624c18b92a6e645993a06439093c36bbd
parentd89e5e645030fd28be5adb636191a70004acb750 (diff)
downloadbusybox-w32-cf131bb3280d555e40808c28366d0cb33c6a4497.tar.gz
busybox-w32-cf131bb3280d555e40808c28366d0cb33c6a4497.tar.bz2
busybox-w32-cf131bb3280d555e40808c28366d0cb33c6a4497.zip
new version of ed taken from sash
-rw-r--r--patches/ed.patch4284
1 files changed, 1176 insertions, 3108 deletions
diff --git a/patches/ed.patch b/patches/ed.patch
index fc261b88d..cc3d13853 100644
--- a/patches/ed.patch
+++ b/patches/ed.patch
@@ -59,3385 +59,1453 @@ Index: include/applets.h
59 #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS) 59 #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS)
60 APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER) 60 APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER)
61 #endif 61 #endif
62--- /dev/null 2005-04-22 11:15:01.120978184 -0400 62--- /dev/null 2005-04-24 01:00:01.350003056 -0400
63+++ editors/ed.c 2005-04-22 11:16:00.000000000 -0400 63+++ editors/ed.c 2005-04-24 01:15:09.000000000 -0400
64@@ -0,0 +1,3120 @@ 64@@ -0,0 +1,1447 @@
65+/* main.c: This file contains the main control and user-interface routines
66+ for the ed line editor. */
67+/* ed line editor.
68+ Copyright (C) 1993, 1994 Andrew Moore, Talke Studio
69+ All Rights Reserved
70+
71+ This program is free software; you can redistribute it and/or modify
72+ it under the terms of the GNU General Public License as published by
73+ the Free Software Foundation; either version 2, or (at your option)
74+ any later version.
75+
76+ This program is distributed in the hope that it will be useful, but
77+ WITHOUT ANY WARRANTY; without even the implied warranty of
78+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
79+ General Public License for more details.
80+
81+ You should have received a copy of the GNU General Public License
82+ along with this program; if not, write to the Free Software
83+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
84+*/
85+
86+/* 65+/*
87+ * CREDITS 66+ * Copyright (c) 2002 by David I. Bell
88+ * 67+ * Permission is granted to use, distribute, or modify this source,
89+ * This program is based on the editor algorithm described in 68+ * provided that this copyright notice remains intact.
90+ * Brian W. Kernighan and P. J. Plauger's book "Software Tools
91+ * in Pascal," Addison-Wesley, 1981.
92+ *
93+ * The buffering algorithm is attributed to Rodney Ruddock of
94+ * the University of Guelph, Guelph, Ontario.
95+ * 69+ *
70+ * The "ed" built-in command (much simplified)
96+ */ 71+ */
97+ 72+
98+#include <errno.h>
99+#include <limits.h>
100+#include <signal.h>
101+#include <stdlib.h>
102+#include <stdio.h> 73+#include <stdio.h>
74+#include <stdlib.h>
75+#include <unistd.h>
76+#include <fcntl.h>
103+#include <string.h> 77+#include <string.h>
78+#include <memory.h>
79+#include <time.h>
104+#include <ctype.h> 80+#include <ctype.h>
105+#include <setjmp.h> 81+#include <sys/param.h>
106+#include <pwd.h> 82+#include <malloc.h>
107+#include <unistd.h> 83+//#include "sash.h"
108+#include <sys/types.h> 84+
109+#include <sys/stat.h> 85+#define USERSIZE 1024 /* max line length typed in by user */
110+#include <sys/file.h> 86+#define INITBUF_SIZE 1024 /* initial buffer size */
111+#include <sys/ioctl.h> 87+
112+ 88+typedef int BOOL;
113+#include "busybox.h" 89+
114+#include "ed.h" 90+#define FALSE ((BOOL) 0)
115+#include "getopt.h" 91+#define TRUE ((BOOL) 1)
116+ 92+
117+jmp_buf env; 93+#define isBlank(ch) (((ch) == ' ') || ((ch) == '\t'))
118+ 94+#define isDecimal(ch) (((ch) >= '0') && ((ch) <= '9'))
119+/* static buffers */ 95+
120+char *errmsg; /* error message buffer */ 96+#define STDOUT 1
121+char stdinbuf[1]; /* stdin buffer */ 97+
122+char *shcmd; /* shell command buffer */ 98+typedef int NUM;
123+int shcmdsz; /* shell command buffer size */ 99+typedef int LEN;
124+int shcmdi; /* shell command buffer index */ 100+
125+char *ibuf; /* ed command-line buffer */ 101+typedef struct LINE LINE;
126+int ibufsz; /* ed command-line buffer size */ 102+
127+char *ibufp; /* pointer to ed command-line buffer */ 103+struct LINE
128+
129+/* global flags */
130+int traditional = 0; /* if set, be backwards compatible */
131+int garrulous = 0; /* if set, print all error messages */
132+int isbinary; /* if set, buffer contains ASCII NULs */
133+int isglobal; /* if set, doing a global command */
134+int modified; /* if set, buffer modified since last write */
135+int mutex = 0; /* if set, signals set "sigflags" */
136+int red = 0; /* if set, restrict shell/directory access */
137+int scripted = 0; /* if set, suppress diagnostics */
138+int sigactive = 0; /* if set, signal handlers are enabled */
139+int sigflags = 0; /* if set, signals received while mutex set */
140+
141+char *old_filename; /* default filename */
142+long current_addr; /* current address in editor buffer */
143+long addr_last; /* last address in editor buffer */
144+int lineno; /* script line number */
145+char *prompt; /* command-line prompt */
146+char *dps = "*"; /* default command-line prompt */
147+long err_status = 0; /* program exit status */
148+
149+/* The name this program was run with. */
150+char *program_name;
151+
152+/* If non-zero, display usage information and exit. */
153+int show_help = 0;
154+
155+/* If non-zero, print the version on standard output and exit. */
156+int show_version = 0;
157+
158+/* Long options equivalences. */
159+struct option long_options[] =
160+{ 104+{
161+ {"help", no_argument, &show_help, 1}, 105+ LINE * next;
162+ {"prompt", required_argument, NULL, 'p'}, 106+ LINE * prev;
163+ {"quiet", no_argument, NULL, 's'}, 107+ LEN len;
164+ {"silent", no_argument, NULL, 's'}, 108+ char data[1];
165+ {"traditional", no_argument, NULL, 'G'},
166+ {"version", no_argument, &show_version, 1},
167+ {0, 0, 0, 0},
168+}; 109+};
169+ 110+
170+extern int optind;
171+extern char *optarg;
172+ 111+
173+/* usage: explain usage */ 112+static LINE lines;
113+static LINE * curLine;
114+static NUM curNum;
115+static NUM lastNum;
116+static NUM marks[26];
117+static BOOL dirty;
118+static char * fileName;
119+static char searchString[USERSIZE];
120+
121+static char * bufBase;
122+static char * bufPtr;
123+static LEN bufUsed;
124+static LEN bufSize;
125+
126+
127+static void doCommands(void);
128+static void subCommand(const char * cmd, NUM num1, NUM num2);
129+static BOOL getNum(const char ** retcp, BOOL * retHaveNum, NUM * retNum);
130+static BOOL setCurNum(NUM num);
131+static BOOL initEdit(void);
132+static void termEdit(void);
133+static void addLines(NUM num);
134+static BOOL insertLine(NUM num, const char * data, LEN len);
135+static BOOL deleteLines(NUM num1, NUM num2);
136+static BOOL printLines(NUM num1, NUM num2, BOOL expandFlag);
137+static BOOL writeLines(const char * file, NUM num1, NUM num2);
138+static BOOL readLines(const char * file, NUM num);
139+static NUM searchLines(const char * str, NUM num1, NUM num2);
140+static LINE * findLine(NUM num);
141+
142+static LEN findString
143+ (const LINE * lp, const char * str, LEN len, LEN offset);
144+
174+ 145+
175+#if 0
176+void 146+void
177+usage (status) 147+ed_main(int argc, const char ** argv)
178+ int status;
179+{ 148+{
180+ if (status != 0) 149+ if (!initEdit())
181+ fprintf (stderr, "Try `%s --help' for more information.\n", program_name); 150+ return;
182+ else
183+ {
184+ printf ("Usage: %s [OPTION]... [FILE]\n", program_name);
185+ printf ("\
186+\n\
187+ -G, --traditional use a few backward compatible features\n\
188+ -p, --prompt=STRING use STRING as an interactive prompt\n\
189+ -s, -, --quiet, --silent suppress diagnostics\n");
190+ printf ("\
191+ --help display this help\n\
192+ --version output version information\n\
193+\n\
194+Start edit by reading in FILE if given. Read output of shell command\n\
195+if FILE begins with a `!'.\n");
196+ }
197+ exit (status);
198+}
199+#endif
200+#define usage(x) bb_show_usage()
201+
202+ 151+
203+/* ed: line editor */ 152+ if (argc > 1)
204+int
205+ed_main (int argc, char **argv)
206+{
207+ int c, n;
208+ long status = 0;
209+
210+ program_name = argv[0];
211+ red = (n = strlen (argv[0])) > 2 && argv[0][n - 3] == 'r';
212+top:
213+ while ((c = getopt_long (argc, argv, "Gp:s", long_options, NULL)) != EOF)
214+ switch (c)
215+ {
216+ default:
217+ usage (1);
218+ case 0:
219+ break;
220+ case 'G': /* backward compatibility */
221+ traditional = 1;
222+ break;
223+ case 'p': /* set prompt */
224+ prompt = optarg;
225+ break;
226+ case 's': /* run script */
227+ scripted = 1;
228+ break;
229+ }
230+ if (show_help)
231+ usage (0);
232+ argv += optind;
233+ argc -= optind;
234+ if (argc && **argv == '-')
235+ {
236+ scripted = 1;
237+ if (argc > 1)
238+ {
239+ optind = 0;
240+ goto top;
241+ }
242+ argv++;
243+ argc--;
244+ }
245+ init_buffers ();
246+
247+ /* assert: reliable signals! */
248+#ifdef SIGWINCH
249+ handle_winch (SIGWINCH);
250+ if (isatty (0))
251+ reliable_signal (SIGWINCH, handle_winch);
252+#endif
253+ reliable_signal (SIGHUP, signal_hup);
254+ reliable_signal (SIGQUIT, SIG_IGN);
255+ reliable_signal (SIGINT, signal_int);
256+ if ((status = setjmp (env)))
257+ {
258+ fputs ("\n?\n", stderr);
259+ sprintf (errmsg, "Interrupt");
260+ }
261+ else
262+ {
263+ sigactive = 1; /* enable signal handlers */
264+ if (argc && **argv && is_legal_filename (*argv))
265+ {
266+ if (read_file (*argv, 0) < 0 && is_regular_file (0))
267+ quit (2);
268+ else if (**argv != '!')
269+ strcpy (old_filename, *argv);
270+ }
271+ else if (argc)
272+ {
273+ fputs ("?\n", stderr);
274+ if (**argv == '\0')
275+ sprintf (errmsg, "Invalid filename");
276+ if (is_regular_file (0))
277+ quit (2);
278+ }
279+ }
280+ for (;;)
281+ {
282+ if (status < 0 && garrulous)
283+ fprintf (stderr, "%s\n", errmsg);
284+ if (prompt)
285+ {
286+ printf ("%s", prompt);
287+ fflush (stdout);
288+ }
289+ if ((n = get_tty_line ()) < 0)
290+ { 153+ {
291+ status = ERR; 154+ fileName = strdup(argv[1]);
292+ continue; 155+
293+ } 156+ if (fileName == NULL)
294+ else if (n == 0)
295+ {
296+ if (modified && !scripted)
297+ {
298+ fputs ("?\n", stderr);
299+ sprintf (errmsg, "Warning: file modified");
300+ if (is_regular_file (0))
301+ { 157+ {
302+ fprintf (stderr, garrulous ? 158+ fprintf(stderr, "No memory\n");
303+ "script, line %d: %s\n" : 159+ termEdit();
304+ "", lineno, errmsg); 160+
305+ quit (2); 161+ return;
306+ } 162+ }
307+ clearerr (stdin);
308+ modified = 0;
309+ status = EMOD;
310+ continue;
311+ }
312+ else
313+ quit (err_status);
314+ }
315+ else if (ibuf[n - 1] != '\n')
316+ {
317+ /* discard line */
318+ sprintf (errmsg, "Unexpected end-of-file");
319+ clearerr (stdin);
320+ status = ERR;
321+ continue;
322+ }
323+ isglobal = 0;
324+ if ((status = extract_addr_range ()) >= 0 &&
325+ (status = exec_command ()) >= 0)
326+ if (!status || (status = display_lines (current_addr, current_addr,
327+ status)) >= 0)
328+ continue;
329+ switch (status)
330+ {
331+ case EOF:
332+ quit (err_status);
333+ case EMOD:
334+ modified = 0;
335+ fputs ("?\n", stderr); /* give warning */
336+ sprintf (errmsg, "Warning: file modified");
337+ if (is_regular_file (0))
338+ {
339+ fprintf (stderr, garrulous ?
340+ "script, line %d: %s\n" :
341+ "", lineno, errmsg);
342+ quit (2);
343+ }
344+ break;
345+ case FATAL:
346+ if (is_regular_file (0))
347+ fprintf (stderr, garrulous ?
348+ "script, line %d: %s\n" : "",
349+ lineno, errmsg);
350+ else
351+ fprintf (stderr, garrulous ? "%s\n" : "",
352+ errmsg);
353+ quit (3);
354+ default:
355+ fputs ("?\n", stderr);
356+ if (is_regular_file (0))
357+ {
358+ fprintf (stderr, garrulous ?
359+ "script, line %d: %s\n" : "",
360+ lineno, errmsg);
361+ quit (4);
362+ }
363+ break;
364+ }
365+ err_status = -status;
366+ }
367+ /*NOTREACHED */
368+}
369+ 163+
370+long first_addr, second_addr, addr_cnt; 164+ if (!readLines(fileName, 1))
165+ {
166+ termEdit();
371+ 167+
372+/* extract_addr_range: get line addresses from the command buffer until an 168+ return;
373+ illegal address is seen; return status */ 169+ }
374+int
375+extract_addr_range ()
376+{
377+ long addr;
378+
379+ addr_cnt = 0;
380+ first_addr = second_addr = current_addr;
381+ while ((addr = next_addr ()) >= 0)
382+ {
383+ addr_cnt++;
384+ first_addr = second_addr;
385+ second_addr = addr;
386+ if (*ibufp != ',' && *ibufp != ';')
387+ break;
388+ else if (*ibufp++ == ';')
389+ current_addr = addr;
390+ }
391+ if ((addr_cnt = min (addr_cnt, 2)) == 1 || second_addr != addr)
392+ first_addr = second_addr;
393+ return (addr == ERR) ? ERR : 0;
394+}
395+ 170+
171+ if (lastNum)
172+ setCurNum(1);
396+ 173+
397+#define SKIP_BLANKS() \ 174+ dirty = FALSE;
398+ while (isspace (*ibufp) && *ibufp != '\n') \ 175+ }
399+ ibufp++ 176+
400+ 177+ doCommands();
401+#define MUST_BE_FIRST() \ 178+
402+ do \ 179+ termEdit();
403+ { \
404+ if (!first) \
405+ { \
406+ sprintf (errmsg, "Invalid address"); \
407+ return ERR; \
408+ } \
409+ } \
410+ while (0)
411+
412+/* next_addr: return the next line address in the command buffer */
413+long
414+next_addr ()
415+{
416+ char *hd;
417+ long addr = current_addr;
418+ long n;
419+ int first = 1;
420+ int c;
421+
422+ SKIP_BLANKS ();
423+ for (hd = ibufp;; first = 0)
424+ switch (c = *ibufp)
425+ {
426+ case '+':
427+ case '\t':
428+ case ' ':
429+ case '-':
430+ case '^':
431+ ibufp++;
432+ SKIP_BLANKS ();
433+ if (isdigit (*ibufp))
434+ {
435+ STRTOL (n, ibufp);
436+ addr += (c == '-' || c == '^') ? -n : n;
437+ }
438+ else if (!isspace (c))
439+ addr += (c == '-' || c == '^') ? -1 : 1;
440+ break;
441+ case '0':
442+ case '1':
443+ case '2':
444+ case '3':
445+ case '4':
446+ case '5':
447+ case '6':
448+ case '7':
449+ case '8':
450+ case '9':
451+ MUST_BE_FIRST ();
452+ STRTOL (addr, ibufp);
453+ break;
454+ case '.':
455+ case '$':
456+ MUST_BE_FIRST ();
457+ ibufp++;
458+ addr = (c == '.') ? current_addr : addr_last;
459+ break;
460+ case '/':
461+ case '?':
462+ MUST_BE_FIRST ();
463+ if ((addr = get_matching_node_addr (
464+ get_compiled_pattern (), c == '/')) < 0)
465+ return ERR;
466+ else if (c == *ibufp)
467+ ibufp++;
468+ break;
469+ case '\'':
470+ MUST_BE_FIRST ();
471+ ibufp++;
472+ if ((addr = get_marked_node_addr (*ibufp++)) < 0)
473+ return ERR;
474+ break;
475+ case '%':
476+ case ',':
477+ case ';':
478+ if (first)
479+ {
480+ ibufp++;
481+ addr_cnt++;
482+ second_addr = (c == ';') ? current_addr : 1;
483+ addr = addr_last;
484+ break;
485+ }
486+ /* FALL THROUGH */
487+ default:
488+ if (ibufp == hd)
489+ return EOF;
490+ else if (addr < 0 || addr_last < addr)
491+ {
492+ sprintf (errmsg, "Invalid address");
493+ return ERR;
494+ }
495+ else
496+ return addr;
497+ }
498+ /* NOTREACHED */
499+} 180+}
500+ 181+
501+ 182+
502+/* GET_THIRD_ADDR: get a legal address from the command buffer */ 183+/*
503+#define GET_THIRD_ADDR(addr) \ 184+ * Read commands until we are told to stop.
504+ do \ 185+ */
505+ { \ 186+static void
506+ long ol1, ol2; \ 187+doCommands(void)
507+ ol1 = first_addr, ol2 = second_addr; \
508+ if (extract_addr_range () < 0) \
509+ return ERR; \
510+ else if (traditional && addr_cnt == 0) \
511+ { \
512+ sprintf (errmsg, "Destination expected"); \
513+ return ERR; \
514+ } \
515+ else if (second_addr < 0 || addr_last < second_addr) \
516+ { \
517+ sprintf (errmsg, "Invalid address"); \
518+ return ERR; \
519+ } \
520+ (addr) = second_addr; \
521+ first_addr = ol1, second_addr = ol2; \
522+ } \
523+ while (0)
524+
525+/* GET_COMMAND_SUFFIX: verify the command suffix in the command buffer */
526+#define GET_COMMAND_SUFFIX() \
527+ do \
528+ { \
529+ int done = 0; \
530+ do \
531+ { \
532+ switch (*ibufp) \
533+ { \
534+ case 'p': \
535+ gflag |= GPR, ibufp++; \
536+ break; \
537+ case 'l': \
538+ gflag |= GLS, ibufp++; \
539+ break; \
540+ case 'n': \
541+ gflag |= GNP, ibufp++; \
542+ break; \
543+ default: \
544+ done++; \
545+ } \
546+ } \
547+ while (!done); \
548+ if (*ibufp++ != '\n') \
549+ { \
550+ sprintf (errmsg, "Invalid command suffix"); \
551+ return ERR; \
552+ } \
553+ } \
554+ while (0)
555+
556+/* sflags */
557+#define SGG 001 /* complement previous global substitute suffix */
558+#define SGP 002 /* complement previous print suffix */
559+#define SGR 004 /* use last regex instead of last pat */
560+#define SGF 010 /* repeat last substitution */
561+
562+int patlock = 0; /* if set, pattern not freed by get_compiled_pattern() */
563+
564+long rows = 22; /* scroll length: ws_row - 2 */
565+
566+/* exec_command: execute the next command in command buffer; return print
567+ request, if any */
568+int
569+exec_command ()
570+{ 188+{
571+ extern long u_current_addr; 189+ const char * cp;
572+ extern long u_addr_last; 190+ char * endbuf;
573+ 191+ char * newname;
574+ static pattern_t *pat = NULL; 192+ int len;
575+ static int sgflag = 0; 193+ NUM num1;
576+ static int sgnum = 0; 194+ NUM num2;
577+ 195+ BOOL have1;
578+ pattern_t *tpat; 196+ BOOL have2;
579+ char *fnp; 197+ char buf[USERSIZE];
580+ int gflag = 0; 198+
581+ int sflags = 0; 199+ while (TRUE)
582+ long addr = 0;
583+ int n = 0;
584+ int c;
585+
586+ SKIP_BLANKS ();
587+ switch (c = *ibufp++)
588+ {
589+ case 'a':
590+ GET_COMMAND_SUFFIX ();
591+ if (!isglobal)
592+ clear_undo_stack ();
593+ if (append_lines (second_addr) < 0)
594+ return ERR;
595+ break;
596+ case 'c':
597+ if (check_addr_range (current_addr, current_addr) < 0)
598+ return ERR;
599+ GET_COMMAND_SUFFIX ();
600+ if (!isglobal)
601+ clear_undo_stack ();
602+ if (delete_lines (first_addr, second_addr) < 0 ||
603+ append_lines (current_addr) < 0)
604+ return ERR;
605+ break;
606+ case 'd':
607+ if (check_addr_range (current_addr, current_addr) < 0)
608+ return ERR;
609+ GET_COMMAND_SUFFIX ();
610+ if (!isglobal)
611+ clear_undo_stack ();
612+ if (delete_lines (first_addr, second_addr) < 0)
613+ return ERR;
614+ else if ((addr = INC_MOD (current_addr, addr_last)) != 0)
615+ current_addr = addr;
616+ break;
617+ case 'e':
618+ if (modified && !scripted)
619+ return EMOD;
620+ /* fall through */
621+ case 'E':
622+ if (addr_cnt > 0)
623+ {
624+ sprintf (errmsg, "Unexpected address");
625+ return ERR;
626+ }
627+ else if (!isspace (*ibufp))
628+ {
629+ sprintf (errmsg, "Unexpected command suffix");
630+ return ERR;
631+ }
632+ else if ((fnp = get_filename ()) == NULL)
633+ return ERR;
634+ GET_COMMAND_SUFFIX ();
635+ if (delete_lines (1, addr_last) < 0)
636+ return ERR;
637+ delete_yank_lines ();
638+ clear_undo_stack ();
639+ if (close_sbuf () < 0)
640+ return ERR;
641+ else if (open_sbuf () < 0)
642+ return FATAL;
643+ if (*fnp && *fnp != '!')
644+ strcpy (old_filename, fnp);
645+ if (traditional && *fnp == '\0' && *old_filename == '\0')
646+ {
647+ sprintf (errmsg, "No current filename");
648+ return ERR;
649+ }
650+ else if (read_file (*fnp ? fnp : old_filename, 0) < 0)
651+ return ERR;
652+ clear_undo_stack ();
653+ modified = 0;
654+ u_current_addr = u_addr_last = -1;
655+ break;
656+ case 'f':
657+ if (addr_cnt > 0)
658+ {
659+ sprintf (errmsg, "Unexpected address");
660+ return ERR;
661+ }
662+ else if (!isspace (*ibufp))
663+ {
664+ sprintf (errmsg, "Unexpected command suffix");
665+ return ERR;
666+ }
667+ else if ((fnp = get_filename ()) == NULL)
668+ return ERR;
669+ else if (*fnp == '!')
670+ {
671+ sprintf (errmsg, "Invalid redirection");
672+ return ERR;
673+ }
674+ GET_COMMAND_SUFFIX ();
675+ if (*fnp)
676+ strcpy (old_filename, fnp);
677+ printf ("%s\n", strip_escapes (old_filename));
678+ break;
679+ case 'g':
680+ case 'v':
681+ case 'G':
682+ case 'V':
683+ if (isglobal)
684+ {
685+ sprintf (errmsg, "Cannot nest global commands");
686+ return ERR;
687+ }
688+ else if (check_addr_range (1, addr_last) < 0)
689+ return ERR;
690+ else if (build_active_list (c == 'g' || c == 'G') < 0)
691+ return ERR;
692+ else if ((n = (c == 'G' || c == 'V')))
693+ GET_COMMAND_SUFFIX ();
694+ isglobal++;
695+ if (exec_global (n, gflag) < 0)
696+ return ERR;
697+ break;
698+ case 'h':
699+ if (addr_cnt > 0)
700+ {
701+ sprintf (errmsg, "Unexpected address");
702+ return ERR;
703+ }
704+ GET_COMMAND_SUFFIX ();
705+ if (*errmsg)
706+ fprintf (stderr, "%s\n", errmsg);
707+ break;
708+ case 'H':
709+ if (addr_cnt > 0)
710+ {
711+ sprintf (errmsg, "Unexpected address");
712+ return ERR;
713+ }
714+ GET_COMMAND_SUFFIX ();
715+ if ((garrulous = 1 - garrulous) && *errmsg)
716+ fprintf (stderr, "%s\n", errmsg);
717+ break;
718+ case 'i':
719+ if (second_addr == 0)
720+ {
721+ sprintf (errmsg, "Invalid address");
722+ return ERR;
723+ }
724+ GET_COMMAND_SUFFIX ();
725+ if (!isglobal)
726+ clear_undo_stack ();
727+ if (append_lines (second_addr - 1) < 0)
728+ return ERR;
729+ break;
730+ case 'j':
731+ if (check_addr_range (current_addr, current_addr + 1) < 0)
732+ return ERR;
733+ GET_COMMAND_SUFFIX ();
734+ if (!isglobal)
735+ clear_undo_stack ();
736+ if (first_addr != second_addr &&
737+ join_lines (first_addr, second_addr) < 0)
738+ return ERR;
739+ break;
740+ case 'k':
741+ c = *ibufp++;
742+ if (second_addr == 0)
743+ {
744+ sprintf (errmsg, "Invalid address");
745+ return ERR;
746+ }
747+ GET_COMMAND_SUFFIX ();
748+ if (mark_line_node (get_addressed_line_node (second_addr), c) < 0)
749+ return ERR;
750+ break;
751+ case 'l':
752+ if (check_addr_range (current_addr, current_addr) < 0)
753+ return ERR;
754+ GET_COMMAND_SUFFIX ();
755+ if (display_lines (first_addr, second_addr, gflag | GLS) < 0)
756+ return ERR;
757+ gflag = 0;
758+ break;
759+ case 'm':
760+ if (check_addr_range (current_addr, current_addr) < 0)
761+ return ERR;
762+ GET_THIRD_ADDR (addr);
763+ if (first_addr <= addr && addr < second_addr)
764+ {
765+ sprintf (errmsg, "Invalid destination");
766+ return ERR;
767+ }
768+ GET_COMMAND_SUFFIX ();
769+ if (!isglobal)
770+ clear_undo_stack ();
771+ if (move_lines (addr) < 0)
772+ return ERR;
773+ break;
774+ case 'n':
775+ if (check_addr_range (current_addr, current_addr) < 0)
776+ return ERR;
777+ GET_COMMAND_SUFFIX ();
778+ if (display_lines (first_addr, second_addr, gflag | GNP) < 0)
779+ return ERR;
780+ gflag = 0;
781+ break;
782+ case 'p':
783+ if (check_addr_range (current_addr, current_addr) < 0)
784+ return ERR;
785+ GET_COMMAND_SUFFIX ();
786+ if (display_lines (first_addr, second_addr, gflag | GPR) < 0)
787+ return ERR;
788+ gflag = 0;
789+ break;
790+ case 'P':
791+ if (addr_cnt > 0)
792+ {
793+ sprintf (errmsg, "Unexpected address");
794+ return ERR;
795+ }
796+ GET_COMMAND_SUFFIX ();
797+ prompt = prompt ? NULL : optarg ? optarg : dps;
798+ break;
799+ case 'q':
800+ case 'Q':
801+ if (addr_cnt > 0)
802+ {
803+ sprintf (errmsg, "Unexpected address");
804+ return ERR;
805+ }
806+ GET_COMMAND_SUFFIX ();
807+ gflag = (modified && !scripted && c == 'q') ? EMOD : EOF;
808+ break;
809+ case 'r':
810+ if (!isspace (*ibufp))
811+ {
812+ sprintf (errmsg, "Unexpected command suffix");
813+ return ERR;
814+ }
815+ else if (addr_cnt == 0)
816+ second_addr = addr_last;
817+ if ((fnp = get_filename ()) == NULL)
818+ return ERR;
819+ GET_COMMAND_SUFFIX ();
820+ if (!isglobal)
821+ clear_undo_stack ();
822+ if (*old_filename == '\0' && *fnp != '!')
823+ strcpy (old_filename, fnp);
824+ if (traditional && *fnp == '\0' && *old_filename == '\0')
825+ {
826+ sprintf (errmsg, "No current filename");
827+ return ERR;
828+ }
829+ if ((addr = read_file (*fnp ? fnp : old_filename, second_addr)) < 0)
830+ return ERR;
831+ else if (addr && addr != addr_last)
832+ modified = 1;
833+ break;
834+ case 's':
835+ do
836+ { 200+ {
837+ switch (*ibufp) 201+ printf(": ");
838+ { 202+ fflush(stdout);
839+ case '\n': 203+
840+ sflags |= SGF; 204+ if (fgets(buf, sizeof(buf), stdin) == NULL)
841+ break; 205+ return;
842+ case 'g': 206+
843+ sflags |= SGG; 207+ len = strlen(buf);
844+ ibufp++; 208+
845+ break; 209+ if (len == 0)
846+ case 'p': 210+ return;
847+ sflags |= SGP; 211+
848+ ibufp++; 212+ endbuf = &buf[len - 1];
849+ break; 213+
850+ case 'r': 214+ if (*endbuf != '\n')
851+ sflags |= SGR; 215+ {
852+ ibufp++; 216+ fprintf(stderr, "Command line too long\n");
853+ break; 217+
854+ case '0': 218+ do
855+ case '1': 219+ {
856+ case '2': 220+ len = fgetc(stdin);
857+ case '3': 221+ }
858+ case '4': 222+ while ((len != EOF) && (len != '\n'));
859+ case '5': 223+
860+ case '6': 224+ continue;
861+ case '7':
862+ case '8':
863+ case '9': {
864+ long sgnum_long;
865+ STRTOL (sgnum_long, ibufp);
866+ sgnum = sgnum_long;
867+ sflags |= SGF;
868+ sgflag &= ~GSG; /* override GSG */
869+ break;
870+ } 225+ }
871+ default: 226+
872+ if (sflags) 227+ while ((endbuf > buf) && isBlank(endbuf[-1]))
228+ endbuf--;
229+
230+ *endbuf = '\0';
231+
232+ cp = buf;
233+
234+ while (isBlank(*cp))
235+ cp++;
236+
237+ have1 = FALSE;
238+ have2 = FALSE;
239+
240+ if ((curNum == 0) && (lastNum > 0))
873+ { 241+ {
874+ sprintf (errmsg, "Invalid command suffix"); 242+ curNum = 1;
875+ return ERR; 243+ curLine = lines.next;
876+ } 244+ }
877+ }
878+ }
879+ while (sflags && *ibufp != '\n');
880+ if (sflags && !pat)
881+ {
882+ sprintf (errmsg, "No previous substitution");
883+ return ERR;
884+ }
885+ else if (sflags & SGG)
886+ sgnum = 0; /* override numeric arg */
887+ if (*ibufp != '\n' && *(ibufp + 1) == '\n')
888+ {
889+ sprintf (errmsg, "Invalid pattern delimiter");
890+ return ERR;
891+ }
892+ tpat = pat;
893+ SPL1 ();
894+ if ((!sflags || (sflags & SGR)) &&
895+ (tpat = get_compiled_pattern ()) == NULL)
896+ {
897+ SPL0 ();
898+ return ERR;
899+ }
900+ else if (tpat != pat)
901+ {
902+ if (pat)
903+ {
904+ regfree (pat);
905+ free (pat);
906+ }
907+ pat = tpat;
908+ patlock = 1; /* reserve pattern */
909+ }
910+ SPL0 ();
911+ if (!sflags && extract_subst_tail (&sgflag, &sgnum) < 0)
912+ return ERR;
913+ else if (isglobal)
914+ sgflag |= GLB;
915+ else
916+ sgflag &= ~GLB;
917+ if (sflags & SGG)
918+ sgflag ^= GSG;
919+ if (sflags & SGP)
920+ sgflag ^= GPR, sgflag &= ~(GLS | GNP);
921+ do
922+ {
923+ switch (*ibufp)
924+ {
925+ case 'p':
926+ sgflag |= GPR, ibufp++;
927+ break;
928+ case 'l':
929+ sgflag |= GLS, ibufp++;
930+ break;
931+ case 'n':
932+ sgflag |= GNP, ibufp++;
933+ break;
934+ default:
935+ n++;
936+ }
937+ }
938+ while (!n);
939+ if (check_addr_range (current_addr, current_addr) < 0)
940+ return ERR;
941+ GET_COMMAND_SUFFIX ();
942+ if (!isglobal)
943+ clear_undo_stack ();
944+ if (search_and_replace (pat, sgflag, sgnum) < 0)
945+ return ERR;
946+ break;
947+ case 't':
948+ if (check_addr_range (current_addr, current_addr) < 0)
949+ return ERR;
950+ GET_THIRD_ADDR (addr);
951+ GET_COMMAND_SUFFIX ();
952+ if (!isglobal)
953+ clear_undo_stack ();
954+ if (copy_lines (addr) < 0)
955+ return ERR;
956+ break;
957+ case 'u':
958+ if (addr_cnt > 0)
959+ {
960+ sprintf (errmsg, "Unexpected address");
961+ return ERR;
962+ }
963+ GET_COMMAND_SUFFIX ();
964+ if (pop_undo_stack () < 0)
965+ return ERR;
966+ break;
967+ case 'w':
968+ case 'W':
969+ if ((n = *ibufp) == 'q' || n == 'Q')
970+ {
971+ gflag = EOF;
972+ ibufp++;
973+ }
974+ if (!isspace (*ibufp))
975+ {
976+ sprintf (errmsg, "Unexpected command suffix");
977+ return ERR;
978+ }
979+ else if ((fnp = get_filename ()) == NULL)
980+ return ERR;
981+ if (addr_cnt == 0 && !addr_last)
982+ first_addr = second_addr = 0;
983+ else if (check_addr_range (1, addr_last) < 0)
984+ return ERR;
985+ GET_COMMAND_SUFFIX ();
986+ if (*old_filename == '\0' && *fnp != '!')
987+ strcpy (old_filename, fnp);
988+ if (traditional && *fnp == '\0' && *old_filename == '\0')
989+ {
990+ sprintf (errmsg, "No current filename");
991+ return ERR;
992+ }
993+ if ((addr = write_file (*fnp ? fnp : old_filename,
994+ (c == 'W') ? "a" : "w", first_addr, second_addr)) < 0)
995+ return ERR;
996+ else if (addr == addr_last)
997+ modified = 0;
998+ else if (modified && !scripted && n == 'q')
999+ gflag = EMOD;
1000+ break;
1001+ case 'x':
1002+ if (second_addr < 0 || addr_last < second_addr)
1003+ {
1004+ sprintf (errmsg, "Invalid address");
1005+ return ERR;
1006+ }
1007+ GET_COMMAND_SUFFIX ();
1008+ if (!isglobal)
1009+ clear_undo_stack ();
1010+ if (put_lines (second_addr) < 0)
1011+ return ERR;
1012+ break;
1013+ case 'y':
1014+ if (check_addr_range (current_addr, current_addr) < 0)
1015+ return ERR;
1016+ GET_COMMAND_SUFFIX ();
1017+ if (yank_lines (first_addr, second_addr) < 0)
1018+ return ERR;
1019+ break;
1020+ case 'z':
1021+ if (check_addr_range
1022+ (first_addr = 1, current_addr + (traditional ? 1 : !isglobal)) < 0)
1023+ return ERR;
1024+ else if ('0' < *ibufp && *ibufp <= '9')
1025+ STRTOL (rows, ibufp);
1026+ GET_COMMAND_SUFFIX ();
1027+ if (display_lines (second_addr, min (addr_last,
1028+ second_addr + rows), gflag) < 0)
1029+ return ERR;
1030+ gflag = 0;
1031+ break;
1032+ case '=':
1033+ GET_COMMAND_SUFFIX ();
1034+ printf ("%ld\n", addr_cnt ? second_addr : addr_last);
1035+ break;
1036+ case '!':
1037+ if (addr_cnt > 0)
1038+ {
1039+ sprintf (errmsg, "Unexpected address");
1040+ return ERR;
1041+ }
1042+ else if ((sflags = get_shell_command ()) < 0)
1043+ return ERR;
1044+ GET_COMMAND_SUFFIX ();
1045+ if (sflags)
1046+ printf ("%s\n", shcmd + 1);
1047+ system (shcmd + 1);
1048+ if (!scripted)
1049+ printf ("!\n");
1050+ break;
1051+ case '\n':
1052+ if (check_addr_range
1053+ (first_addr = 1, current_addr + (traditional ? 1 : !isglobal)) < 0 ||
1054+ display_lines (second_addr, second_addr, 0) < 0)
1055+ return ERR;
1056+ break;
1057+ case '#':
1058+ while (*ibufp++ != '\n')
1059+ ;
1060+ break;
1061+ default:
1062+ sprintf (errmsg, "Unknown command");
1063+ return ERR;
1064+ }
1065+ return gflag;
1066+}
1067+ 245+
246+ if (!getNum(&cp, &have1, &num1))
247+ continue;
1068+ 248+
1069+/* check_addr_range: return status of address range check */ 249+ while (isBlank(*cp))
1070+int 250+ cp++;
1071+check_addr_range (n, m)
1072+ long n, m;
1073+{
1074+ if (addr_cnt == 0)
1075+ {
1076+ first_addr = n;
1077+ second_addr = m;
1078+ }
1079+ if (first_addr > second_addr || 1 > first_addr ||
1080+ second_addr > addr_last)
1081+ {
1082+ sprintf (errmsg, "Invalid address");
1083+ return ERR;
1084+ }
1085+ return 0;
1086+}
1087+ 251+
252+ if (*cp == ',')
253+ {
254+ cp++;
1088+ 255+
1089+/* get_matching_node_addr: return the address of the next line matching a 256+ if (!getNum(&cp, &have2, &num2))
1090+ pattern in a given direction. wrap around begin/end of editor buffer if 257+ continue;
1091+ necessary */
1092+long
1093+get_matching_node_addr (pat, dir)
1094+ pattern_t *pat;
1095+ int dir;
1096+{
1097+ char *s;
1098+ long n = current_addr;
1099+ line_t *lp;
1100+
1101+ if (!pat)
1102+ return ERR;
1103+ do
1104+ {
1105+ if ((n = dir ? INC_MOD (n, addr_last) : DEC_MOD (n, addr_last)))
1106+ {
1107+ lp = get_addressed_line_node (n);
1108+ if ((s = get_sbuf_line (lp)) == NULL)
1109+ return ERR;
1110+ if (isbinary)
1111+ NUL_TO_NEWLINE (s, lp->len);
1112+ if (!regexec (pat, s, 0, NULL, 0))
1113+ return n;
1114+ }
1115+ }
1116+ while (n != current_addr);
1117+ sprintf (errmsg, "No match");
1118+ return ERR;
1119+}
1120+ 258+
259+ if (!have1)
260+ num1 = 1;
1121+ 261+
1122+/* get_filename: return pointer to copy of filename in the command buffer */ 262+ if (!have2)
1123+char * 263+ num2 = lastNum;
1124+get_filename ()
1125+{
1126+ static char *file = NULL;
1127+ static int filesz = 0;
1128+ 264+
1129+ int n; 265+ have1 = TRUE;
266+ have2 = TRUE;
267+ }
1130+ 268+
1131+ if (*ibufp != '\n') 269+ if (!have1)
1132+ { 270+ num1 = curNum;
1133+ SKIP_BLANKS ();
1134+ if (*ibufp == '\n')
1135+ {
1136+ sprintf (errmsg, "Invalid filename");
1137+ return NULL;
1138+ }
1139+ else if ((ibufp = get_extended_line (&n, 1)) == NULL)
1140+ return NULL;
1141+ else if (*ibufp == '!')
1142+ {
1143+ ibufp++;
1144+ if ((n = get_shell_command ()) < 0)
1145+ return NULL;
1146+ if (n)
1147+ printf ("%s\n", shcmd + 1);
1148+ return shcmd;
1149+ }
1150+ else if (n > PATH_MAX)
1151+ {
1152+ sprintf (errmsg, "Filename too long");
1153+ return NULL;
1154+ }
1155+ }
1156+ else if (!traditional && *old_filename == '\0')
1157+ {
1158+ sprintf (errmsg, "No current filename");
1159+ return NULL;
1160+ }
1161+ REALLOC (file, filesz, PATH_MAX + 1, NULL);
1162+ for (n = 0; *ibufp != '\n';)
1163+ file[n++] = *ibufp++;
1164+ file[n] = '\0';
1165+ return is_legal_filename (file) ? file : NULL;
1166+}
1167+ 271+
272+ if (!have2)
273+ num2 = num1;
1168+ 274+
1169+/* get_shell_command: read a shell command from stdin; return substitution 275+ switch (*cp++)
1170+ status */ 276+ {
1171+int 277+ case 'a':
1172+get_shell_command () 278+ addLines(num1 + 1);
1173+{ 279+ break;
1174+ static char *buf = NULL; 280+
1175+ static int n = 0; 281+ case 'c':
1176+ 282+ deleteLines(num1, num2);
1177+ char *s; /* substitution char pointer */ 283+ addLines(num1);
1178+ int i = 0; 284+ break;
1179+ int j = 0; 285+
1180+ 286+ case 'd':
1181+ if (red) 287+ deleteLines(num1, num2);
1182+ { 288+ break;
1183+ sprintf (errmsg, "Shell access restricted"); 289+
1184+ return ERR; 290+ case 'f':
1185+ } 291+ if (*cp && !isBlank(*cp))
1186+ else if ((s = ibufp = get_extended_line (&j, 1)) == NULL) 292+ {
1187+ return ERR; 293+ fprintf(stderr, "Bad file command\n");
1188+ REALLOC (buf, n, j + 1, ERR); 294+ break;
1189+ buf[i++] = '!'; /* prefix command w/ bang */ 295+ }
1190+ while (*ibufp != '\n') 296+
1191+ switch (*ibufp) 297+ while (isBlank(*cp))
1192+ { 298+ cp++;
1193+ default: 299+
1194+ REALLOC (buf, n, i + 2, ERR); 300+ if (*cp == '\0')
1195+ buf[i++] = *ibufp; 301+ {
1196+ if (*ibufp++ == '\\') 302+ if (fileName)
1197+ buf[i++] = *ibufp++; 303+ printf("\"%s\"\n", fileName);
1198+ break; 304+ else
1199+ case '!': 305+ printf("No file name\n");
1200+ if (s != ibufp) 306+
1201+ { 307+ break;
1202+ REALLOC (buf, n, i + 1, ERR); 308+ }
1203+ buf[i++] = *ibufp++; 309+
1204+ } 310+ newname = strdup(cp);
1205+ else if (shcmd == NULL || (traditional && *(shcmd + 1) == '\0')) 311+
1206+ { 312+ if (newname == NULL)
1207+ sprintf (errmsg, "No previous command"); 313+ {
1208+ return ERR; 314+ fprintf(stderr, "No memory for file name\n");
1209+ } 315+ break;
1210+ else 316+ }
1211+ { 317+
1212+ REALLOC (buf, n, i + shcmdi, ERR); 318+ if (fileName)
1213+ for (s = shcmd + 1; s < shcmd + shcmdi;) 319+ free(fileName);
1214+ buf[i++] = *s++; 320+
1215+ s = ibufp++; 321+ fileName = newname;
1216+ } 322+ break;
1217+ break; 323+
1218+ case '%': 324+ case 'i':
1219+ if (*old_filename == '\0') 325+ addLines(num1);
1220+ { 326+ break;
1221+ sprintf (errmsg, "No current filename"); 327+
1222+ return ERR; 328+ case 'k':
1223+ } 329+ while (isBlank(*cp))
1224+ j = strlen (s = strip_escapes (old_filename)); 330+ cp++;
1225+ REALLOC (buf, n, i + j, ERR); 331+
1226+ while (j--) 332+ if ((*cp < 'a') || (*cp > 'a') || cp[1])
1227+ buf[i++] = *s++; 333+ {
1228+ s = ibufp++; 334+ fprintf(stderr, "Bad mark name\n");
1229+ break; 335+ break;
1230+ } 336+ }
1231+ REALLOC (shcmd, shcmdsz, i + 1, ERR); 337+
1232+ memcpy (shcmd, buf, i); 338+ marks[*cp - 'a'] = num2;
1233+ shcmd[shcmdi = i] = '\0'; 339+ break;
1234+ return *s == '!' || *s == '%'; 340+
341+ case 'l':
342+ printLines(num1, num2, TRUE);
343+ break;
344+
345+ case 'p':
346+ printLines(num1, num2, FALSE);
347+ break;
348+
349+ case 'q':
350+ while (isBlank(*cp))
351+ cp++;
352+
353+ if (have1 || *cp)
354+ {
355+ fprintf(stderr, "Bad quit command\n");
356+ break;
357+ }
358+
359+ if (!dirty)
360+ return;
361+
362+ printf("Really quit? ");
363+ fflush(stdout);
364+
365+ buf[0] = '\0';
366+ fgets(buf, sizeof(buf), stdin);
367+ cp = buf;
368+
369+ while (isBlank(*cp))
370+ cp++;
371+
372+ if ((*cp == 'y') || (*cp == 'Y'))
373+ return;
374+
375+ break;
376+
377+ case 'r':
378+ if (*cp && !isBlank(*cp))
379+ {
380+ fprintf(stderr, "Bad read command\n");
381+ break;
382+ }
383+
384+ while (isBlank(*cp))
385+ cp++;
386+
387+ if (*cp == '\0')
388+ {
389+ fprintf(stderr, "No file name\n");
390+ break;
391+ }
392+
393+ if (!have1)
394+ num1 = lastNum;
395+
396+ if (readLines(cp, num1 + 1))
397+ break;
398+
399+ if (fileName == NULL)
400+ fileName = strdup(cp);
401+
402+ break;
403+
404+ case 's':
405+ subCommand(cp, num1, num2);
406+ break;
407+
408+ case 'w':
409+ if (*cp && !isBlank(*cp))
410+ {
411+ fprintf(stderr, "Bad write command\n");
412+ break;
413+ }
414+
415+ while (isBlank(*cp))
416+ cp++;
417+
418+ if (!have1) {
419+ num1 = 1;
420+ num2 = lastNum;
421+ }
422+
423+ if (*cp == '\0')
424+ cp = fileName;
425+
426+ if (cp == NULL)
427+ {
428+ fprintf(stderr, "No file name specified\n");
429+ break;
430+ }
431+
432+ writeLines(cp, num1, num2);
433+ break;
434+
435+ case 'z':
436+ switch (*cp)
437+ {
438+ case '-':
439+ printLines(curNum-21, curNum, FALSE);
440+ break;
441+ case '.':
442+ printLines(curNum-11, curNum+10, FALSE);
443+ break;
444+ default:
445+ printLines(curNum, curNum+21, FALSE);
446+ break;
447+ }
448+ break;
449+
450+ case '.':
451+ if (have1)
452+ {
453+ fprintf(stderr, "No arguments allowed\n");
454+ break;
455+ }
456+
457+ printLines(curNum, curNum, FALSE);
458+ break;
459+
460+ case '-':
461+ if (setCurNum(curNum - 1))
462+ printLines(curNum, curNum, FALSE);
463+
464+ break;
465+
466+ case '=':
467+ printf("%d\n", num1);
468+ break;
469+
470+ case '\0':
471+ if (have1)
472+ {
473+ printLines(num2, num2, FALSE);
474+ break;
475+ }
476+
477+ if (setCurNum(curNum + 1))
478+ printLines(curNum, curNum, FALSE);
479+
480+ break;
481+
482+ default:
483+ fprintf(stderr, "Unimplemented command\n");
484+ break;
485+ }
486+ }
1235+} 487+}
1236+ 488+
1237+ 489+
1238+/* append_lines: insert text from stdin to after line n; stop when either a 490+/*
1239+ single period is read or EOF; return status */ 491+ * Do the substitute command.
1240+int 492+ * The current line is set to the last substitution done.
1241+append_lines (n) 493+ */
1242+ long n; 494+static void
495+subCommand(const char * cmd, NUM num1, NUM num2)
1243+{ 496+{
1244+ int l; 497+ int delim;
1245+ char *lp = ibuf; 498+ char * cp;
1246+ char *eot; 499+ char * oldStr;
1247+ undo_t *up = NULL; 500+ char * newStr;
1248+ 501+ LEN oldLen;
1249+ for (current_addr = n;;) 502+ LEN newLen;
1250+ { 503+ LEN deltaLen;
1251+ if (!isglobal) 504+ LEN offset;
1252+ { 505+ LINE * lp;
1253+ if ((l = get_tty_line ()) < 0) 506+ LINE * nlp;
1254+ return ERR; 507+ BOOL globalFlag;
1255+ else if (l == 0 || ibuf[l - 1] != '\n') 508+ BOOL printFlag;
1256+ { 509+ BOOL didSub;
1257+ clearerr (stdin); 510+ BOOL needPrint;
1258+ return l ? EOF : 0; 511+ char buf[USERSIZE];
1259+ } 512+
1260+ lp = ibuf; 513+ if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
1261+ }
1262+ else if (*(lp = ibufp) == '\0')
1263+ return 0;
1264+ else
1265+ { 514+ {
1266+ while (*ibufp++ != '\n') 515+ fprintf(stderr, "Bad line range for substitute\n");
1267+ ; 516+
1268+ l = ibufp - lp; 517+ return;
1269+ } 518+ }
1270+ if (l == 2 && lp[0] == '.' && lp[1] == '\n') 519+
520+ globalFlag = FALSE;
521+ printFlag = FALSE;
522+ didSub = FALSE;
523+ needPrint = FALSE;
524+
525+ /*
526+ * Copy the command so we can modify it.
527+ */
528+ strcpy(buf, cmd);
529+ cp = buf;
530+
531+ if (isBlank(*cp) || (*cp == '\0'))
1271+ { 532+ {
1272+ return 0; 533+ fprintf(stderr, "Bad delimiter for substitute\n");
534+
535+ return;
1273+ } 536+ }
1274+ eot = lp + l; 537+
1275+ SPL1 (); 538+ delim = *cp++;
1276+ do 539+ oldStr = cp;
540+
541+ cp = strchr(cp, delim);
542+
543+ if (cp == NULL)
1277+ { 544+ {
1278+ if ((lp = put_sbuf_line (lp)) == NULL) 545+ fprintf(stderr, "Missing 2nd delimiter for substitute\n");
1279+ { 546+
1280+ SPL0 (); 547+ return;
1281+ return ERR;
1282+ }
1283+ else if (up)
1284+ up->t = get_addressed_line_node (current_addr);
1285+ else if ((up = push_undo_stack (UADD, current_addr,
1286+ current_addr)) == NULL)
1287+ {
1288+ SPL0 ();
1289+ return ERR;
1290+ }
1291+ } 548+ }
1292+ while (lp != eot);
1293+ modified = 1;
1294+ SPL0 ();
1295+ }
1296+ /* NOTREACHED */
1297+}
1298+ 549+
550+ *cp++ = '\0';
1299+ 551+
1300+/* join_lines: replace a range of lines with the joined text of those lines */ 552+ newStr = cp;
1301+int 553+ cp = strchr(cp, delim);
1302+join_lines (from, to)
1303+ long from;
1304+ long to;
1305+{
1306+ static char *buf = NULL;
1307+ static int n;
1308+
1309+ char *s;
1310+ int size = 0;
1311+ line_t *bp, *ep;
1312+
1313+ ep = get_addressed_line_node (INC_MOD (to, addr_last));
1314+ bp = get_addressed_line_node (from);
1315+ for (; bp != ep; bp = bp->q_forw)
1316+ {
1317+ if ((s = get_sbuf_line (bp)) == NULL)
1318+ return ERR;
1319+ REALLOC (buf, n, size + bp->len, ERR);
1320+ memcpy (buf + size, s, bp->len);
1321+ size += bp->len;
1322+ }
1323+ REALLOC (buf, n, size + 2, ERR);
1324+ memcpy (buf + size, "\n", 2);
1325+ if (delete_lines (from, to) < 0)
1326+ return ERR;
1327+ current_addr = from - 1;
1328+ SPL1 ();
1329+ if (put_sbuf_line (buf) == NULL ||
1330+ push_undo_stack (UADD, current_addr, current_addr) == NULL)
1331+ {
1332+ SPL0 ();
1333+ return ERR;
1334+ }
1335+ modified = 1;
1336+ SPL0 ();
1337+ return 0;
1338+}
1339+ 554+
555+ if (cp)
556+ *cp++ = '\0';
557+ else
558+ cp = "";
1340+ 559+
1341+/* move_lines: move a range of lines */ 560+ while (*cp) switch (*cp++)
1342+int
1343+move_lines (addr)
1344+ long addr;
1345+{
1346+ line_t *b1, *a1, *b2, *a2;
1347+ long n = INC_MOD (second_addr, addr_last);
1348+ long p = first_addr - 1;
1349+ int done = (addr == first_addr - 1 || addr == second_addr);
1350+
1351+ SPL1 ();
1352+ if (done)
1353+ {
1354+ a2 = get_addressed_line_node (n);
1355+ b2 = get_addressed_line_node (p);
1356+ current_addr = second_addr;
1357+ }
1358+ else if (push_undo_stack (UMOV, p, n) == NULL ||
1359+ push_undo_stack (UMOV, addr, INC_MOD (addr, addr_last)) == NULL)
1360+ {
1361+ SPL0 ();
1362+ return ERR;
1363+ }
1364+ else
1365+ {
1366+ a1 = get_addressed_line_node (n);
1367+ if (addr < first_addr)
1368+ { 561+ {
1369+ b1 = get_addressed_line_node (p); 562+ case 'g':
1370+ b2 = get_addressed_line_node (addr); 563+ globalFlag = TRUE;
1371+ /* this get_addressed_line_node last! */ 564+ break;
565+
566+ case 'p':
567+ printFlag = TRUE;
568+ break;
569+
570+ default:
571+ fprintf(stderr, "Unknown option for substitute\n");
572+
573+ return;
1372+ } 574+ }
1373+ else 575+
576+ if (*oldStr == '\0')
1374+ { 577+ {
1375+ b2 = get_addressed_line_node (addr); 578+ if (searchString[0] == '\0')
1376+ b1 = get_addressed_line_node (p); 579+ {
1377+ /* this get_addressed_line_node last! */ 580+ fprintf(stderr, "No previous search string\n");
1378+ }
1379+ a2 = b2->q_forw;
1380+ REQUE (b2, b1->q_forw);
1381+ REQUE (a1->q_back, a2);
1382+ REQUE (b1, a1);
1383+ current_addr = addr + ((addr < first_addr) ?
1384+ second_addr - first_addr + 1 : 0);
1385+ }
1386+ if (isglobal)
1387+ unset_active_nodes (b2->q_forw, a2);
1388+ modified = 1;
1389+ SPL0 ();
1390+ return 0;
1391+}
1392+ 581+
582+ return;
583+ }
1393+ 584+
1394+/* copy_lines: copy a range of lines; return status */ 585+ oldStr = searchString;
1395+int 586+ }
1396+copy_lines (addr)
1397+ long addr;
1398+{
1399+ line_t *lp, *np = get_addressed_line_node (first_addr);
1400+ undo_t *up = NULL;
1401+ long n = second_addr - first_addr + 1;
1402+ long m = 0;
1403+
1404+ current_addr = addr;
1405+ if (first_addr <= addr && addr < second_addr)
1406+ {
1407+ n = addr - first_addr + 1;
1408+ m = second_addr - addr;
1409+ }
1410+ for (; n > 0; n = m, m = 0, np = get_addressed_line_node (current_addr + 1))
1411+ for (; n-- > 0; np = np->q_forw)
1412+ {
1413+ SPL1 ();
1414+ if ((lp = dup_line_node (np)) == NULL)
1415+ {
1416+ SPL0 ();
1417+ return ERR;
1418+ }
1419+ add_line_node (lp);
1420+ if (up)
1421+ up->t = lp;
1422+ else if ((up = push_undo_stack (UADD, current_addr,
1423+ current_addr)) == NULL)
1424+ {
1425+ SPL0 ();
1426+ return ERR;
1427+ }
1428+ modified = 1;
1429+ SPL0 ();
1430+ }
1431+ return 0;
1432+}
1433+ 587+
588+ if (oldStr != searchString)
589+ strcpy(searchString, oldStr);
1434+ 590+
1435+/* delete_lines: delete a range of lines */ 591+ lp = findLine(num1);
1436+int
1437+delete_lines (from, to)
1438+ long from, to;
1439+{
1440+ line_t *n, *p;
1441+
1442+ if (yank_lines (from, to) < 0)
1443+ return ERR;
1444+ SPL1 ();
1445+ if (push_undo_stack (UDEL, from, to) == NULL)
1446+ {
1447+ SPL0 ();
1448+ return ERR;
1449+ }
1450+ n = get_addressed_line_node (INC_MOD (to, addr_last));
1451+ p = get_addressed_line_node (from - 1);
1452+ /* this get_addressed_line_node last! */
1453+ if (isglobal)
1454+ unset_active_nodes (p->q_forw, n);
1455+ REQUE (p, n);
1456+ addr_last -= to - from + 1;
1457+ current_addr = from - 1;
1458+ modified = 1;
1459+ SPL0 ();
1460+ return 0;
1461+}
1462+ 592+
593+ if (lp == NULL)
594+ return;
1463+ 595+
1464+int dlcnt = 0; /* # of lines displayed */ 596+ oldLen = strlen(oldStr);
597+ newLen = strlen(newStr);
598+ deltaLen = newLen - oldLen;
599+ offset = 0;
600+ nlp = NULL;
1465+ 601+
1466+/* display_lines: print a range of lines to stdout */ 602+ while (num1 <= num2)
1467+int
1468+display_lines (from, to, gflag)
1469+ long from;
1470+ long to;
1471+ int gflag;
1472+{
1473+ line_t *bp;
1474+ line_t *ep;
1475+ char *s;
1476+
1477+ if (!from)
1478+ {
1479+ sprintf (errmsg, "Invalid address");
1480+ return ERR;
1481+ }
1482+ ep = get_addressed_line_node (INC_MOD (to, addr_last));
1483+ bp = get_addressed_line_node (from);
1484+ for (dlcnt = 0; bp != ep; bp = bp->q_forw)
1485+ {
1486+ if ((s = get_sbuf_line (bp)) == NULL)
1487+ return ERR;
1488+ else if (put_tty_line (s, bp->len, current_addr = from++, gflag) < 0)
1489+ return ERR;
1490+ else if (!traditional && !scripted && !isglobal &&
1491+ bp->q_forw != ep && ++dlcnt > rows)
1492+ { 603+ {
1493+ dlcnt = 0; 604+ offset = findString(lp, oldStr, oldLen, offset);
1494+ fputs ("Press <RETURN> to continue... ", stdout);
1495+ fflush (stdout);
1496+ if (get_tty_line () < 0)
1497+ return ERR;
1498+ }
1499+ }
1500+ return 0;
1501+}
1502+ 605+
606+ if (offset < 0)
607+ {
608+ if (needPrint)
609+ {
610+ printLines(num1, num1, FALSE);
611+ needPrint = FALSE;
612+ }
1503+ 613+
1504+line_t yank_buffer_head; /* head of yank buffer */ 614+ offset = 0;
615+ lp = lp->next;
616+ num1++;
1505+ 617+
1506+/* yank_lines: copy a range of lines to the cut buffer */ 618+ continue;
1507+int 619+ }
1508+yank_lines (from, to)
1509+ long from;
1510+ long to;
1511+{
1512+ line_t *bp, *cp, *ep, *lp;
1513+ 620+
621+ needPrint = printFlag;
622+ didSub = TRUE;
623+ dirty = TRUE;
1514+ 624+
1515+ delete_yank_lines (); 625+ /*
1516+ ep = get_addressed_line_node (INC_MOD (to, addr_last)); 626+ * If the replacement string is the same size or shorter
1517+ bp = get_addressed_line_node (from); 627+ * than the old string, then the substitution is easy.
1518+ for (lp = &yank_buffer_head; bp != ep; bp = bp->q_forw, lp = cp) 628+ */
1519+ { 629+ if (deltaLen <= 0)
1520+ SPL1 (); 630+ {
1521+ if ((cp = dup_line_node (bp)) == NULL) 631+ memcpy(&lp->data[offset], newStr, newLen);
1522+ {
1523+ SPL0 ();
1524+ return ERR;
1525+ }
1526+ INSQUE (cp, lp);
1527+ SPL0 ();
1528+ }
1529+ return 0;
1530+}
1531+ 632+
633+ if (deltaLen)
634+ {
635+ memcpy(&lp->data[offset + newLen],
636+ &lp->data[offset + oldLen],
637+ lp->len - offset - oldLen);
1532+ 638+
1533+/* delete_yank_lines: delete lines from the yank buffer */ 639+ lp->len += deltaLen;
1534+void 640+ }
1535+delete_yank_lines ()
1536+{
1537+ line_t *cp, *lp;
1538+ 641+
642+ offset += newLen;
1539+ 643+
1540+ for (lp = yank_buffer_head.q_forw; lp != &yank_buffer_head; lp = cp) 644+ if (globalFlag)
1541+ { 645+ continue;
1542+ SPL1 ();
1543+ cp = lp->q_forw;
1544+ REQUE (lp->q_back, lp->q_forw);
1545+ free (lp);
1546+ SPL0 ();
1547+ }
1548+}
1549+ 646+
647+ if (needPrint)
648+ {
649+ printLines(num1, num1, FALSE);
650+ needPrint = FALSE;
651+ }
1550+ 652+
1551+/* put_lines: append lines from the yank buffer */ 653+ lp = lp->next;
1552+int 654+ num1++;
1553+put_lines (addr) 655+
1554+ long addr; 656+ continue;
1555+{ 657+ }
1556+ undo_t *up = NULL;
1557+ line_t *lp, *cp;
1558+
1559+ if ((lp = yank_buffer_head.q_forw) == &yank_buffer_head)
1560+ {
1561+ sprintf (errmsg, "Nothing to put");
1562+ return ERR;
1563+ }
1564+ current_addr = addr;
1565+ for (; lp != &yank_buffer_head; lp = lp->q_forw)
1566+ {
1567+ SPL1 ();
1568+ if ((cp = dup_line_node (lp)) == NULL)
1569+ {
1570+ SPL0 ();
1571+ return ERR;
1572+ }
1573+ add_line_node (cp);
1574+ if (up)
1575+ up->t = cp;
1576+ else if ((up = push_undo_stack (UADD, current_addr,
1577+ current_addr)) == NULL)
1578+ {
1579+ SPL0 ();
1580+ return ERR;
1581+ }
1582+ modified = 1;
1583+ SPL0 ();
1584+ }
1585+ return 0;
1586+}
1587+ 658+
659+ /*
660+ * The new string is larger, so allocate a new line
661+ * structure and use that. Link it in in place of
662+ * the old line structure.
663+ */
664+ nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltaLen);
1588+ 665+
1589+#define MAXMARK 26 /* max number of marks */ 666+ if (nlp == NULL)
667+ {
668+ fprintf(stderr, "Cannot get memory for line\n");
1590+ 669+
1591+line_t *mark[MAXMARK]; /* line markers */ 670+ return;
1592+int markno; /* line marker count */ 671+ }
1593+ 672+
1594+/* mark_line_node: set a line node mark */ 673+ nlp->len = lp->len + deltaLen;
1595+int
1596+mark_line_node (lp, n)
1597+ line_t *lp;
1598+ int n;
1599+{
1600+ if (!islower (n))
1601+ {
1602+ sprintf (errmsg, "Invalid mark character");
1603+ return ERR;
1604+ }
1605+ else if (mark[n - 'a'] == NULL)
1606+ markno++;
1607+ mark[n - 'a'] = lp;
1608+ return 0;
1609+}
1610+ 674+
675+ memcpy(nlp->data, lp->data, offset);
1611+ 676+
1612+/* get_marked_node_addr: return address of a marked line */ 677+ memcpy(&nlp->data[offset], newStr, newLen);
1613+long
1614+get_marked_node_addr (n)
1615+ int n;
1616+{
1617+ if (!islower (n))
1618+ {
1619+ sprintf (errmsg, "Invalid mark character");
1620+ return ERR;
1621+ }
1622+ return get_line_node_addr (mark[n - 'a']);
1623+}
1624+ 678+
679+ memcpy(&nlp->data[offset + newLen],
680+ &lp->data[offset + oldLen],
681+ lp->len - offset - oldLen);
1625+ 682+
1626+/* unmark_line_node: clear line node mark */ 683+ nlp->next = lp->next;
1627+void 684+ nlp->prev = lp->prev;
1628+unmark_line_node (lp) 685+ nlp->prev->next = nlp;
1629+ line_t *lp; 686+ nlp->next->prev = nlp;
1630+{
1631+ int i;
1632+
1633+ for (i = 0; markno && i < MAXMARK; i++)
1634+ if (mark[i] == lp)
1635+ {
1636+ mark[i] = NULL;
1637+ markno--;
1638+ }
1639+}
1640+ 687+
688+ if (curLine == lp)
689+ curLine = nlp;
1641+ 690+
1642+/* dup_line_node: return a pointer to a copy of a line node */ 691+ free(lp);
1643+line_t * 692+ lp = nlp;
1644+dup_line_node (lp)
1645+ line_t *lp;
1646+{
1647+ line_t *np;
1648+
1649+ if ((np = (line_t *) malloc (sizeof (line_t))) == NULL)
1650+ {
1651+ fprintf (stderr, "%s\n", strerror (errno));
1652+ sprintf (errmsg, "Out of memory");
1653+ return NULL;
1654+ }
1655+ np->seek = lp->seek;
1656+ np->len = lp->len;
1657+ return np;
1658+}
1659+ 693+
694+ offset += newLen;
1660+ 695+
1661+/* has_trailing_escape: return the parity of escapes preceding a character 696+ if (globalFlag)
1662+ in a string */ 697+ continue;
1663+int 698+
1664+has_trailing_escape (s, t) 699+ if (needPrint)
1665+ char *s; 700+ {
1666+ char *t; 701+ printLines(num1, num1, FALSE);
1667+{ 702+ needPrint = FALSE;
1668+ return (s == t || *(t - 1) != '\\') ? 0 : !has_trailing_escape (s, t - 1); 703+ }
704+
705+ lp = lp->next;
706+ num1++;
707+ }
708+
709+ if (!didSub)
710+ fprintf(stderr, "No substitutions found for \"%s\"\n", oldStr);
1669+} 711+}
1670+ 712+
1671+ 713+
1672+/* strip_escapes: return copy of escaped string of at most length PATH_MAX */ 714+/*
1673+char * 715+ * Search a line for the specified string starting at the specified
1674+strip_escapes (s) 716+ * offset in the line. Returns the offset of the found string, or -1.
1675+ char *s; 717+ */
718+static LEN
719+findString( const LINE * lp, const char * str, LEN len, LEN offset)
1676+{ 720+{
1677+ static char *file = NULL; 721+ LEN left;
1678+ static int filesz = 0; 722+ const char * cp;
723+ const char * ncp;
1679+ 724+
1680+ int i = 0; 725+ cp = &lp->data[offset];
726+ left = lp->len - offset;
1681+ 727+
1682+ REALLOC (file, filesz, PATH_MAX + 1, NULL); 728+ while (left >= len)
1683+ /* assert: no trailing escape */ 729+ {
1684+ while ((file[i++] = (*s == '\\') ? *++s : *s)) 730+ ncp = memchr(cp, *str, left);
1685+ s++;
1686+ return file;
1687+}
1688+ 731+
732+ if (ncp == NULL)
733+ return -1;
1689+ 734+
1690+#ifndef S_ISREG 735+ left -= (ncp - cp);
1691+#define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
1692+#endif
1693+ 736+
1694+/* is_regular_file: if file descriptor of a regular file, then return true; 737+ if (left < len)
1695+ otherwise return false */ 738+ return -1;
1696+int
1697+is_regular_file (fd)
1698+ int fd;
1699+{
1700+ struct stat sb;
1701+ 739+
1702+ return fstat (fd, &sb) < 0 || S_ISREG (sb.st_mode); 740+ cp = ncp;
1703+}
1704+ 741+
742+ if (memcmp(cp, str, len) == 0)
743+ return (cp - lp->data);
1705+ 744+
1706+/* is_legal_filename: return a legal filename */ 745+ cp++;
1707+int 746+ left--;
1708+is_legal_filename (s) 747+ }
1709+ char *s; 748+
1710+{ 749+ return -1;
1711+ if (red && (*s == '!' || !strcmp (s, "..") || strchr (s, '/')))
1712+ {
1713+ sprintf (errmsg, "Shell access restricted");
1714+ return 0;
1715+ }
1716+ return 1;
1717+} 750+}
1718+ 751+
1719+FILE *sfp; /* scratch file pointer */
1720+off_t sfseek; /* scratch file position */
1721+int seek_write; /* seek before writing */
1722+line_t buffer_head; /* incore buffer */
1723+ 752+
1724+/* get_sbuf_line: get a line of text from the scratch file; return pointer 753+/*
1725+ to the text */ 754+ * Add lines which are typed in by the user.
1726+char * 755+ * The lines are inserted just before the specified line number.
1727+get_sbuf_line (lp) 756+ * The lines are terminated by a line containing a single dot (ugly!),
1728+ line_t *lp; 757+ * or by an end of file.
758+ */
759+static void
760+addLines(NUM num)
1729+{ 761+{
1730+ static char *sfbuf = NULL; /* buffer */ 762+ int len;
1731+ static int sfbufsz = 0; /* buffer size */ 763+ char buf[USERSIZE + 1];
1732+ 764+
1733+ int len, ct; 765+ while (fgets(buf, sizeof(buf), stdin))
1734+
1735+ if (lp == &buffer_head)
1736+ return NULL;
1737+ seek_write = 1; /* force seek on write */
1738+ /* out of position */
1739+ if (sfseek != lp->seek)
1740+ {
1741+ sfseek = lp->seek;
1742+ if (fseek (sfp, sfseek, SEEK_SET) < 0)
1743+ { 766+ {
1744+ fprintf (stderr, "%s\n", strerror (errno)); 767+ if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0'))
1745+ sprintf (errmsg, "Cannot seek temp file"); 768+ return;
1746+ return NULL; 769+
770+ len = strlen(buf);
771+
772+ if (len == 0)
773+ return;
774+
775+ if (buf[len - 1] != '\n')
776+ {
777+ fprintf(stderr, "Line too long\n");
778+
779+ do
780+ {
781+ len = fgetc(stdin);
782+ }
783+ while ((len != EOF) && (len != '\n'));
784+
785+ return;
786+ }
787+
788+ if (!insertLine(num++, buf, len))
789+ return;
1747+ } 790+ }
1748+ }
1749+ len = lp->len;
1750+ REALLOC (sfbuf, sfbufsz, len + 1, NULL);
1751+ if ((ct = fread (sfbuf, sizeof (char), len, sfp)) < 0 || ct != len)
1752+ {
1753+ fprintf (stderr, "%s\n", strerror (errno));
1754+ sprintf (errmsg, "Cannot read temp file");
1755+ return NULL;
1756+ }
1757+ sfseek += len; /* update file position */
1758+ sfbuf[len] = '\0';
1759+ return sfbuf;
1760+} 791+}
1761+ 792+
1762+ 793+
1763+/* put_sbuf_line: write a line of text to the scratch file and add a line node 794+/*
1764+ to the editor buffer; return a pointer to the end of the text */ 795+ * Parse a line number argument if it is present. This is a sum
1765+char * 796+ * or difference of numbers, '.', '$', 'x, or a search string.
1766+put_sbuf_line (cs) 797+ * Returns TRUE if successful (whether or not there was a number).
1767+ char *cs; 798+ * Returns FALSE if there was a parsing error, with a message output.
799+ * Whether there was a number is returned indirectly, as is the number.
800+ * The character pointer which stopped the scan is also returned.
801+ */
802+static BOOL
803+getNum(const char ** retcp, BOOL * retHaveNum, NUM * retNum)
1768+{ 804+{
1769+ line_t *lp; 805+ const char * cp;
1770+ int len, ct; 806+ char * endStr;
1771+ char *s; 807+ char str[USERSIZE];
1772+ 808+ BOOL haveNum;
1773+ if ((lp = (line_t *) malloc (sizeof (line_t))) == NULL) 809+ NUM value;
1774+ { 810+ NUM num;
1775+ fprintf (stderr, "%s\n", strerror (errno)); 811+ NUM sign;
1776+ sprintf (errmsg, "Out of memory"); 812+
1777+ return NULL; 813+ cp = *retcp;
1778+ } 814+ haveNum = FALSE;
1779+ /* assert: cs is '\n' terminated */ 815+ value = 0;
1780+ for (s = cs; *s != '\n'; s++) 816+ sign = 1;
1781+ ; 817+
1782+ if (s - cs >= LINECHARS) 818+ while (TRUE)
1783+ {
1784+ sprintf (errmsg, "Line too long");
1785+ return NULL;
1786+ }
1787+ len = s - cs;
1788+ /* out of position */
1789+ if (seek_write)
1790+ {
1791+ if (fseek (sfp, 0L, SEEK_END) < 0)
1792+ { 819+ {
1793+ fprintf (stderr, "%s\n", strerror (errno)); 820+ while (isBlank(*cp))
1794+ sprintf (errmsg, "Cannot seek temp file"); 821+ cp++;
1795+ return NULL;
1796+ }
1797+ sfseek = ftell (sfp);
1798+ seek_write = 0;
1799+ }
1800+ /* assert: SPL1() */
1801+ if ((ct = fwrite (cs, sizeof (char), len, sfp)) < 0 || ct != len)
1802+ {
1803+ sfseek = -1;
1804+ fprintf (stderr, "%s\n", strerror (errno));
1805+ sprintf (errmsg, "Cannot write temp file");
1806+ return NULL;
1807+ }
1808+ lp->len = len;
1809+ lp->seek = sfseek;
1810+ add_line_node (lp);
1811+ sfseek += len; /* update file position */
1812+ return ++s;
1813+}
1814+ 822+
823+ switch (*cp)
824+ {
825+ case '.':
826+ haveNum = TRUE;
827+ num = curNum;
828+ cp++;
829+ break;
1815+ 830+
1816+/* add_line_node: add a line node in the editor buffer after the current line */ 831+ case '$':
1817+void 832+ haveNum = TRUE;
1818+add_line_node (lp) 833+ num = lastNum;
1819+ line_t *lp; 834+ cp++;
1820+{ 835+ break;
1821+ line_t *cp;
1822+ 836+
1823+ cp = get_addressed_line_node (current_addr); /* this get_addressed_line_node last! */ 837+ case '\'':
1824+ INSQUE (lp, cp); 838+ cp++;
1825+ addr_last++;
1826+ current_addr++;
1827+}
1828+ 839+
840+ if ((*cp < 'a') || (*cp > 'z'))
841+ {
842+ fprintf(stderr, "Bad mark name\n");
1829+ 843+
1830+/* get_line_node_addr: return line number of pointer */ 844+ return FALSE;
1831+long 845+ }
1832+get_line_node_addr (lp)
1833+ line_t *lp;
1834+{
1835+ line_t *cp = &buffer_head;
1836+ long n = 0;
1837+
1838+ while (cp != lp && (cp = cp->q_forw) != &buffer_head)
1839+ n++;
1840+ if (n && cp == &buffer_head)
1841+ {
1842+ sprintf (errmsg, "Invalid address");
1843+ return ERR;
1844+ }
1845+ return n;
1846+}
1847+ 846+
847+ haveNum = TRUE;
848+ num = marks[*cp++ - 'a'];
849+ break;
1848+ 850+
1849+/* get_addressed_line_node: return pointer to a line node in the editor buffer */ 851+ case '/':
1850+line_t * 852+ strcpy(str, ++cp);
1851+get_addressed_line_node (n) 853+ endStr = strchr(str, '/');
1852+ long n;
1853+{
1854+ static line_t *lp = &buffer_head;
1855+ static long on = 0;
1856+
1857+ SPL1 ();
1858+ if (n > on)
1859+ if (n <= (on + addr_last) >> 1)
1860+ for (; on < n; on++)
1861+ lp = lp->q_forw;
1862+ else
1863+ {
1864+ lp = buffer_head.q_back;
1865+ for (on = addr_last; on > n; on--)
1866+ lp = lp->q_back;
1867+ }
1868+ else if (n >= on >> 1)
1869+ for (; on > n; on--)
1870+ lp = lp->q_back;
1871+ else
1872+ {
1873+ lp = &buffer_head;
1874+ for (on = 0; on < n; on++)
1875+ lp = lp->q_forw;
1876+ }
1877+ SPL0 ();
1878+ return lp;
1879+}
1880+ 854+
855+ if (endStr)
856+ {
857+ *endStr++ = '\0';
858+ cp += (endStr - str);
859+ }
860+ else
861+ cp = "";
1881+ 862+
1882+extern int newline_added; 863+ num = searchLines(str, curNum, lastNum);
1883+ 864+
1884+/* open_sbuf: open scratch file */ 865+ if (num == 0)
1885+int 866+ return FALSE;
1886+open_sbuf ()
1887+{
1888+ char *mktemp ();
1889+ int u;
1890+
1891+ isbinary = newline_added = 0;
1892+ u = umask(077);
1893+ if ((sfp = tmpfile()) == NULL)
1894+ {
1895+ fprintf (stderr, "open_sbuf: tmpfile() failed with '%s'\n", strerror (errno));
1896+ sprintf (errmsg, "Cannot open temp file");
1897+ umask(u);
1898+ return ERR;
1899+ }
1900+ umask(u);
1901+ return 0;
1902+}
1903+ 867+
868+ haveNum = TRUE;
869+ break;
1904+ 870+
1905+/* close_sbuf: close scratch file */ 871+ default:
1906+int 872+ if (!isDecimal(*cp))
1907+close_sbuf () 873+ {
1908+{ 874+ *retcp = cp;
1909+ if (sfp) 875+ *retHaveNum = haveNum;
1910+ { 876+ *retNum = value;
1911+ if (fclose (sfp) < 0)
1912+ {
1913+ fprintf (stderr, "close_sbuf: fclose on temporary file failed with '%s'.\n", strerror (errno));
1914+ sprintf (errmsg, "Cannot close temp file");
1915+ return ERR;
1916+ }
1917+ sfp = NULL;
1918+ }
1919+ sfseek = seek_write = 0;
1920+ 877+
1921+ return 0; 878+ return TRUE;
1922+} 879+ }
1923+ 880+
881+ num = 0;
1924+ 882+
1925+/* quit: remove_lines scratch file and exit */ 883+ while (isDecimal(*cp))
1926+void 884+ num = num * 10 + *cp++ - '0';
1927+quit (n)
1928+ int n;
1929+{
1930+ if (sfp)
1931+ {
1932+ fclose (sfp);
1933+ }
1934+ exit (n);
1935+}
1936+ 885+
886+ haveNum = TRUE;
887+ break;
888+ }
1937+ 889+
1938+extern line_t yank_buffer_head; 890+ value += num * sign;
1939+extern char *old_filename;
1940+unsigned char ctab[256]; /* character translation table */
1941+ 891+
1942+/* init_buffers: open scratch buffer; initialize line queue */ 892+ while (isBlank(*cp))
1943+void 893+ cp++;
1944+init_buffers ()
1945+{
1946+ int i = 0;
1947+
1948+ /* Read stdin one character at a time to avoid i/o contention
1949+ with shell escapes invoked by nonterminal input, e.g.,
1950+ ed - <<EOF
1951+ !cat
1952+ hello, world
1953+ EOF */
1954+#ifdef HAVE_SETBUFFER
1955+ setbuffer (stdin, stdinbuf, 1);
1956+#else
1957+ setvbuf (stdin, stdinbuf, _IONBF, 0);
1958+#endif
1959+ if ((errmsg = (char *) malloc (ERRSZ)) == NULL ||
1960+ (old_filename = (char *) malloc (PATH_MAX + 1)) == NULL)
1961+ {
1962+ fprintf (stderr, "%s\n", strerror (errno));
1963+ quit (2);
1964+ }
1965+ old_filename[0] = '\0';
1966+ if (open_sbuf () < 0)
1967+ quit (2);
1968+ REQUE (&buffer_head, &buffer_head);
1969+ REQUE (&yank_buffer_head, &yank_buffer_head);
1970+ for (i = 0; i < 256; i++)
1971+ ctab[i] = i;
1972+ 894+
895+ switch (*cp)
896+ {
897+ case '-':
898+ sign = -1;
899+ cp++;
900+ break;
901+
902+ case '+':
903+ sign = 1;
904+ cp++;
905+ break;
906+
907+ default:
908+ *retcp = cp;
909+ *retHaveNum = haveNum;
910+ *retNum = value;
911+
912+ return TRUE;
913+ }
914+ }
1973+} 915+}
1974+ 916+
1975+ 917+
1976+/* translit_text: translate characters in a string */ 918+/*
1977+char * 919+ * Initialize everything for editing.
1978+translit_text (s, len, from, to) 920+ */
1979+ char *s; 921+static BOOL
1980+ int len; 922+initEdit(void)
1981+ int from;
1982+ int to;
1983+{ 923+{
1984+ static int i = 0; 924+ int i;
1985+ 925+
1986+ unsigned char *us; 926+ bufSize = INITBUF_SIZE;
927+ bufBase = malloc(bufSize);
1987+ 928+
1988+ ctab[i] = i; /* restore table to initial state */ 929+ if (bufBase == NULL)
1989+ ctab[i = from] = to; 930+ {
1990+ for (us = (unsigned char *) s; len-- > 0; us++) 931+ fprintf(stderr, "No memory for buffer\n");
1991+ *us = ctab[*us];
1992+ return s;
1993+}
1994+ 932+
933+ return FALSE;
934+ }
1995+ 935+
1996+#ifndef SIG_ERR 936+ bufPtr = bufBase;
1997+# define SIG_ERR ((void (*)()) -1) 937+ bufUsed = 0;
1998+#endif /* !SIG_ERR */
1999+ 938+
2000+void 939+ lines.next = &lines;
2001+(*reliable_signal (sno, hndlr)) () 940+ lines.prev = &lines;
2002+ int sno;
2003+ void (*hndlr) ();
2004+{
2005+#ifndef HAVE_SIGACTION
2006+ signal (sno, hndlr);
2007+#else
2008+ struct sigaction sa, osa;
2009+
2010+ sa.sa_handler = hndlr;
2011+ sigemptyset (&sa.sa_mask);
2012+ sa.sa_flags = 0;
2013+#ifdef SA_RESTART
2014+ sa.sa_flags |= SA_RESTART;
2015+#endif
2016+ return (sigaction (sno, &sa, &osa) < 0) ? SIG_ERR : osa.sa_handler;
2017+#endif /* HAVE_SIGACTION */
2018+}
2019+ 941+
942+ curLine = NULL;
943+ curNum = 0;
944+ lastNum = 0;
945+ dirty = FALSE;
946+ fileName = NULL;
947+ searchString[0] = '\0';
2020+ 948+
2021+void 949+ for (i = 0; i < 26; i++)
2022+signal_hup (signo) 950+ marks[i] = 0;
2023+ int signo; 951+
2024+{ 952+ return TRUE;
2025+ if (mutex)
2026+ sigflags |= (1 << (signo - 1));
2027+ else
2028+ handle_hup (signo);
2029+} 953+}
2030+ 954+
2031+ 955+
2032+void 956+/*
2033+signal_int (signo) 957+ * Finish editing.
2034+ int signo; 958+ */
959+static void
960+termEdit(void)
2035+{ 961+{
2036+ if (mutex) 962+ if (bufBase)
2037+ sigflags |= (1 << (signo - 1)); 963+ free(bufBase);
2038+ else
2039+ handle_int (signo);
2040+}
2041+ 964+
965+ bufBase = NULL;
966+ bufPtr = NULL;
967+ bufSize = 0;
968+ bufUsed = 0;
2042+ 969+
2043+#ifdef HAVE_SIGSETJMP 970+ if (fileName)
2044+extern sigjmp_buf env; 971+ free(fileName);
2045+#else
2046+extern jmp_buf env;
2047+#endif
2048+extern int sigactive;
2049+ 972+
2050+void 973+ fileName = NULL;
2051+handle_hup (signo) 974+
2052+ int signo; 975+ searchString[0] = '\0';
2053+{ 976+
2054+ char *hup = NULL; /* hup filename */ 977+ if (lastNum)
2055+ char *s; 978+ deleteLines(1, lastNum);
2056+ int n; 979+
2057+ 980+ lastNum = 0;
2058+ if (!sigactive) 981+ curNum = 0;
2059+ quit (1); 982+ curLine = NULL;
2060+ sigflags &= ~(1 << (signo - 1));
2061+ if (addr_last && write_file ("ed.hup", "w", 1, addr_last) < 0 &&
2062+ (s = getenv ("HOME")) != NULL &&
2063+ (n = strlen (s)) + 7 <= PATH_MAX && /* "ed.hup" + '/' */
2064+ (hup = (char *) malloc (n + 8)) != NULL)
2065+ {
2066+ strcpy (hup, s);
2067+ if (n && hup[n - 1] != '/')
2068+ hup[n++] = '/';
2069+ strcpy (hup + n, "ed.hup");
2070+ write_file (hup, "w", 1, addr_last);
2071+ }
2072+ quit (2);
2073+} 983+}
2074+ 984+
2075+ 985+
2076+void 986+/*
2077+handle_int (signo) 987+ * Read lines from a file at the specified line number.
2078+ int signo; 988+ * Returns TRUE if the file was successfully read.
989+ */
990+static BOOL
991+readLines(const char * file, NUM num)
2079+{ 992+{
2080+ if (!sigactive) 993+ int fd;
2081+ quit (1); 994+ int cc;
2082+ sigflags &= ~(1 << (signo - 1)); 995+ LEN len;
2083+#ifdef HAVE_SIGSETJMP 996+ LEN lineCount;
2084+ siglongjmp (env, -1); 997+ LEN charCount;
2085+#else 998+ char * cp;
2086+ longjmp (env, -1);
2087+#endif
2088+}
2089+ 999+
1000+ if ((num < 1) || (num > lastNum + 1))
1001+ {
1002+ fprintf(stderr, "Bad line for read\n");
2090+ 1003+
2091+extern long rows; 1004+ return FALSE;
2092+int cols = 72; /* wrap column */ 1005+ }
2093+ 1006+
2094+void 1007+ fd = open(file, 0);
2095+handle_winch (signo)
2096+ int signo;
2097+{
2098+#ifdef TIOCGWINSZ
2099+ struct winsize ws; /* window size structure */
2100+#endif
2101+ 1008+
2102+ sigflags &= ~(1 << (signo - 1)); 1009+ if (fd < 0)
2103+#ifdef TIOCGWINSZ 1010+ {
2104+ if (ioctl (0, TIOCGWINSZ, (char *) &ws) >= 0) 1011+ perror(file);
2105+ {
2106+ if (ws.ws_row > 2)
2107+ rows = ws.ws_row - 2;
2108+ if (ws.ws_col > 8)
2109+ cols = ws.ws_col - 8;
2110+ }
2111+#endif
2112+}
2113+ 1012+
2114+/* read_file: read a named file/pipe into the buffer; return line count */ 1013+ return FALSE;
2115+long 1014+ }
2116+read_file (fn, n)
2117+ char *fn;
2118+ long n;
2119+{
2120+ FILE *fp;
2121+ long size;
2122+
2123+
2124+ fp = (*fn == '!') ? popen (fn + 1, "r") : fopen (strip_escapes (fn), "r");
2125+ if (fp == NULL)
2126+ {
2127+ fprintf (stderr, "%s: %s\n", fn, strerror (errno));
2128+ sprintf (errmsg, "Cannot open input file");
2129+ return ERR;
2130+ }
2131+ else if ((size = read_stream (fp, n)) < 0)
2132+ return ERR;
2133+ else if (((*fn == '!') ? pclose (fp) : fclose (fp)) < 0)
2134+ {
2135+ fprintf (stderr, "%s: %s\n", fn, strerror (errno));
2136+ sprintf (errmsg, "Cannot close input file");
2137+ return ERR;
2138+ }
2139+ fprintf (stderr, !scripted ? "%lu\n" : "", size);
2140+ return current_addr - n;
2141+}
2142+ 1015+
1016+ bufPtr = bufBase;
1017+ bufUsed = 0;
1018+ lineCount = 0;
1019+ charCount = 0;
1020+ cc = 0;
2143+ 1021+
2144+char *sbuf; /* file i/o buffer */ 1022+ printf("\"%s\", ", file);
2145+int sbufsz; /* file i/o buffer size */ 1023+ fflush(stdout);
2146+int newline_added; /* if set, newline appended to input file */
2147+ 1024+
2148+/* read_stream: read a stream into the editor buffer; return status */ 1025+ do
2149+long
2150+read_stream (fp, n)
2151+ FILE *fp;
2152+ long n;
2153+{
2154+ line_t *lp = get_addressed_line_node (n);
2155+ undo_t *up = NULL;
2156+ unsigned long size = 0;
2157+ int o_newline_added = newline_added;
2158+ int o_isbinary = isbinary;
2159+ int o_n = n;
2160+ int appended = n == addr_last;
2161+ int len;
2162+
2163+ isbinary = newline_added = 0;
2164+ for (current_addr = n; (len = get_stream_line (fp)) > 0; size += len)
2165+ {
2166+ SPL1 ();
2167+ if (put_sbuf_line (sbuf) == NULL)
2168+ { 1026+ {
2169+ SPL0 (); 1027+ cp = memchr(bufPtr, '\n', bufUsed);
2170+ return ERR; 1028+
1029+ if (cp)
1030+ {
1031+ len = (cp - bufPtr) + 1;
1032+
1033+ if (!insertLine(num, bufPtr, len))
1034+ {
1035+ close(fd);
1036+
1037+ return FALSE;
1038+ }
1039+
1040+ bufPtr += len;
1041+ bufUsed -= len;
1042+ charCount += len;
1043+ lineCount++;
1044+ num++;
1045+
1046+ continue;
1047+ }
1048+
1049+ if (bufPtr != bufBase)
1050+ {
1051+ memcpy(bufBase, bufPtr, bufUsed);
1052+ bufPtr = bufBase + bufUsed;
1053+ }
1054+
1055+ if (bufUsed >= bufSize)
1056+ {
1057+ len = (bufSize * 3) / 2;
1058+ cp = realloc(bufBase, len);
1059+
1060+ if (cp == NULL)
1061+ {
1062+ fprintf(stderr, "No memory for buffer\n");
1063+ close(fd);
1064+
1065+ return FALSE;
1066+ }
1067+
1068+ bufBase = cp;
1069+ bufPtr = bufBase + bufUsed;
1070+ bufSize = len;
1071+ }
1072+
1073+ cc = read(fd, bufPtr, bufSize - bufUsed);
1074+ bufUsed += cc;
1075+ bufPtr = bufBase;
1076+
2171+ } 1077+ }
2172+ lp = lp->q_forw; 1078+ while (cc > 0);
2173+ if (up) 1079+
2174+ up->t = lp; 1080+ if (cc < 0)
2175+ else if ((up = push_undo_stack (UADD, current_addr,
2176+ current_addr)) == NULL)
2177+ { 1081+ {
2178+ SPL0 (); 1082+ perror(file);
2179+ return ERR; 1083+ close(fd);
1084+
1085+ return FALSE;
2180+ } 1086+ }
2181+ SPL0 ();
2182+ }
2183+ if (len < 0)
2184+ return ERR;
2185+ if (o_n && appended && size && o_isbinary && o_newline_added)
2186+ fputs ("Newline inserted\n", stderr);
2187+ else if (newline_added && (!appended || (!isbinary && !o_isbinary)))
2188+ fputs ("Newline appended\n", stderr);
2189+ if (isbinary && newline_added && !appended)
2190+ size += 1;
2191+ if (!size)
2192+ newline_added = 1;
2193+ newline_added = appended ? newline_added : o_newline_added;
2194+ isbinary = isbinary | o_isbinary;
2195+ return size;
2196+}
2197+ 1087+
1088+ if (bufUsed)
1089+ {
1090+ if (!insertLine(num, bufPtr, bufUsed))
1091+ {
1092+ close(fd);
2198+ 1093+
2199+/* get_stream_line: read a line of text from a stream; return line length */ 1094+ return -1;
2200+int 1095+ }
2201+get_stream_line (fp)
2202+ FILE *fp;
2203+{
2204+ register int c;
2205+ register int i = 0;
2206+
2207+ while (((c = getc (fp)) != EOF || (!feof (fp) &&
2208+ !ferror (fp))) && c != '\n')
2209+ {
2210+ REALLOC (sbuf, sbufsz, i + 1, ERR);
2211+ if (!(sbuf[i++] = c))
2212+ isbinary = 1;
2213+ }
2214+ REALLOC (sbuf, sbufsz, i + 2, ERR);
2215+ if (c == '\n')
2216+ sbuf[i++] = c;
2217+ else if (ferror (fp))
2218+ {
2219+ fprintf (stderr, "%s\n", strerror (errno));
2220+ sprintf (errmsg, "Cannot read input file");
2221+ return ERR;
2222+ }
2223+ else if (i)
2224+ {
2225+ sbuf[i++] = '\n';
2226+ newline_added = 1;
2227+ }
2228+ sbuf[i] = '\0';
2229+ return (isbinary && newline_added && i) ? --i : i;
2230+}
2231+ 1096+
1097+ lineCount++;
1098+ charCount += bufUsed;
1099+ }
2232+ 1100+
2233+/* write_file: write a range of lines to a named file/pipe; return line count */ 1101+ close(fd);
2234+long
2235+write_file (fn, mode, n, m)
2236+ char *fn;
2237+ char *mode;
2238+ long n;
2239+ long m;
2240+{
2241+ FILE *fp;
2242+ long size;
2243+
2244+ fp = (*fn == '!') ? popen (fn + 1, "w") : fopen (strip_escapes (fn), mode);
2245+ if (fp == NULL)
2246+ {
2247+ fprintf (stderr, "%s: %s\n", fn, strerror (errno));
2248+ sprintf (errmsg, "Cannot open output file");
2249+ return ERR;
2250+ }
2251+ else if ((size = write_stream (fp, n, m)) < 0)
2252+ return ERR;
2253+ else if (((*fn == '!') ? pclose (fp) : fclose (fp)) < 0)
2254+ {
2255+ fprintf (stderr, "%s: %s\n", fn, strerror (errno));
2256+ sprintf (errmsg, "Cannot close output file");
2257+ return ERR;
2258+ }
2259+ fprintf (stderr, !scripted ? "%lu\n" : "", size);
2260+ return n ? m - n + 1 : 0;
2261+}
2262+ 1102+
1103+ printf("%d lines%s, %d chars\n", lineCount,
1104+ (bufUsed ? " (incomplete)" : ""), charCount);
2263+ 1105+
2264+/* write_stream: write a range of lines to a stream; return status */ 1106+ return TRUE;
2265+long
2266+write_stream (fp, n, m)
2267+ FILE *fp;
2268+ long n;
2269+ long m;
2270+{
2271+ line_t *lp = get_addressed_line_node (n);
2272+ unsigned long size = 0;
2273+ char *s;
2274+ int len;
2275+
2276+ for (; n && n <= m; n++, lp = lp->q_forw)
2277+ {
2278+ if ((s = get_sbuf_line (lp)) == NULL)
2279+ return ERR;
2280+ len = lp->len;
2281+ if (n != addr_last || !isbinary || !newline_added)
2282+ s[len++] = '\n';
2283+ if (put_stream_line (fp, s, len) < 0)
2284+ return ERR;
2285+ size += len;
2286+ }
2287+ return size;
2288+} 1107+}
2289+ 1108+
2290+ 1109+
2291+/* put_stream_line: write a line of text to a stream; return status */ 1110+/*
2292+int 1111+ * Write the specified lines out to the specified file.
2293+put_stream_line (fp, s, len) 1112+ * Returns TRUE if successful, or FALSE on an error with a message output.
2294+ FILE *fp; 1113+ */
2295+ char *s; 1114+static BOOL
2296+ int len; 1115+writeLines(const char * file, NUM num1, NUM num2)
2297+{ 1116+{
2298+ while (len--) 1117+ int fd;
2299+ if (fputc (*s++, fp) < 0) 1118+ LINE * lp;
2300+ { 1119+ LEN lineCount;
2301+ fprintf (stderr, "%s\n", strerror (errno)); 1120+ LEN charCount;
2302+ sprintf (errmsg, "Cannot write file");
2303+ return ERR;
2304+ }
2305+ return 0;
2306+}
2307+ 1121+
2308+/* get_extended_line: get an extended line from stdin */ 1122+ if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
2309+char *
2310+get_extended_line (sizep, nonl)
2311+ int *sizep;
2312+ int nonl;
2313+{
2314+ static char *cvbuf = NULL; /* buffer */
2315+ static int cvbufsz = 0; /* buffer size */
2316+
2317+ int l, n;
2318+ char *t = ibufp;
2319+
2320+ while (*t++ != '\n')
2321+ ;
2322+ if ((l = t - ibufp) < 2 || !has_trailing_escape (ibufp, ibufp + l - 1))
2323+ {
2324+ *sizep = l;
2325+ return ibufp;
2326+ }
2327+ *sizep = -1;
2328+ REALLOC (cvbuf, cvbufsz, l, NULL);
2329+ memcpy (cvbuf, ibufp, l);
2330+ *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
2331+ if (nonl)
2332+ l--; /* strip newline */
2333+ for (;;)
2334+ {
2335+ if ((n = get_tty_line ()) < 0)
2336+ return NULL;
2337+ else if (n == 0 || ibuf[n - 1] != '\n')
2338+ { 1123+ {
2339+ sprintf (errmsg, "Unexpected end-of-file"); 1124+ fprintf(stderr, "Bad line range for write\n");
2340+ return NULL; 1125+
1126+ return FALSE;
2341+ } 1127+ }
2342+ REALLOC (cvbuf, cvbufsz, l + n, NULL);
2343+ memcpy (cvbuf + l, ibuf, n);
2344+ l += n;
2345+ if (n < 2 || !has_trailing_escape (cvbuf, cvbuf + l - 1))
2346+ break;
2347+ *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
2348+ if (nonl)
2349+ l--; /* strip newline */
2350+ }
2351+ REALLOC (cvbuf, cvbufsz, l + 1, NULL);
2352+ cvbuf[l] = '\0';
2353+ *sizep = l;
2354+ return cvbuf;
2355+}
2356+ 1128+
1129+ lineCount = 0;
1130+ charCount = 0;
2357+ 1131+
2358+/* get_tty_line: read a line of text from stdin; return line length */ 1132+ fd = creat(file, 0666);
2359+int
2360+get_tty_line ()
2361+{
2362+ register int oi = 0;
2363+ register int i = 0;
2364+ int c;
2365+
2366+ /* Read stdin one character at a time to avoid i/o contention
2367+ with shell escapes invoked by nonterminal input, e.g.,
2368+ ed - <<EOF
2369+ !cat
2370+ hello, world
2371+ EOF */
2372+ for (;;)
2373+ switch (c = getchar ())
2374+ {
2375+ default:
2376+ oi = 0;
2377+ REALLOC (ibuf, ibufsz, i + 2, ERR);
2378+ if (!(ibuf[i++] = c))
2379+ isbinary = 1;
2380+ if (c != '\n')
2381+ continue;
2382+ lineno++;
2383+ ibuf[i] = '\0';
2384+ ibufp = ibuf;
2385+ return i;
2386+ case EOF:
2387+ if (ferror (stdin))
2388+ {
2389+ fprintf (stderr, "stdin: %s\n", strerror (errno));
2390+ sprintf (errmsg, "Cannot read stdin");
2391+ clearerr (stdin);
2392+ ibufp = NULL;
2393+ return ERR;
2394+ }
2395+ else
2396+ {
2397+ clearerr (stdin);
2398+ if (i != oi)
2399+ {
2400+ oi = i;
2401+ continue;
2402+ }
2403+ else if (i)
2404+ ibuf[i] = '\0';
2405+ ibufp = ibuf;
2406+ return i;
2407+ }
2408+ }
2409+}
2410+ 1133+
1134+ if (fd < 0) {
1135+ perror(file);
2411+ 1136+
1137+ return FALSE;
1138+ }
2412+ 1139+
2413+#define ESCAPES "\a\b\f\n\r\t\v\\" 1140+ printf("\"%s\", ", file);
2414+#define ESCCHARS "abfnrtv\\" 1141+ fflush(stdout);
2415+ 1142+
2416+extern long rows; 1143+ lp = findLine(num1);
2417+extern int cols;
2418+extern int dlcnt;
2419+ 1144+
2420+/* put_tty_line: print text to stdout */ 1145+ if (lp == NULL)
2421+int
2422+put_tty_line (s, l, n, gflag)
2423+ char *s;
2424+ int l;
2425+ long n;
2426+ int gflag;
2427+{
2428+ int col = 0;
2429+ char *cp;
2430+
2431+ if (gflag & GNP)
2432+ {
2433+ printf ("%ld\t", n);
2434+ col = 8;
2435+ }
2436+ for (; l--; s++)
2437+ {
2438+ if ((gflag & GLS) && ++col > cols)
2439+ { 1146+ {
2440+ fputs ("\\\n", stdout); 1147+ close(fd);
2441+ col = 1; 1148+
2442+ if (!traditional && !scripted && !isglobal && ++dlcnt > rows) 1149+ return FALSE;
2443+ {
2444+ dlcnt = 0;
2445+ fputs ("Press <RETURN> to continue... ", stdout);
2446+ fflush (stdout);
2447+ if (get_tty_line () < 0)
2448+ return ERR;
2449+ }
2450+ } 1150+ }
2451+ if (gflag & GLS) 1151+
1152+ while (num1++ <= num2)
2452+ { 1153+ {
2453+ if (31 < *s && *s < 127 && *s != '\\') 1154+ if (write(fd, lp->data, lp->len) != lp->len)
2454+ putchar (*s);
2455+ else
2456+ {
2457+ putchar ('\\');
2458+ col++;
2459+ if (*s && (cp = strchr (ESCAPES, *s)) != NULL)
2460+ putchar (ESCCHARS[cp - ESCAPES]);
2461+ else
2462+ { 1155+ {
2463+ putchar ((((unsigned char) *s & 0300) >> 6) + '0'); 1156+ perror(file);
2464+ putchar ((((unsigned char) *s & 070) >> 3) + '0'); 1157+ close(fd);
2465+ putchar (((unsigned char) *s & 07) + '0'); 1158+
2466+ col += 2; 1159+ return FALSE;
2467+ } 1160+ }
2468+ }
2469+ 1161+
1162+ charCount += lp->len;
1163+ lineCount++;
1164+ lp = lp->next;
2470+ } 1165+ }
2471+ else
2472+ putchar (*s);
2473+ }
2474+ if (!traditional && (gflag & GLS))
2475+ putchar ('$');
2476+ putchar ('\n');
2477+ return 0;
2478+}
2479+
2480+ 1166+
1167+ if (close(fd) < 0)
1168+ {
1169+ perror(file);
2481+ 1170+
1171+ return FALSE;
1172+ }
2482+ 1173+
2483+char *rhbuf; /* rhs substitution buffer */ 1174+ printf("%d lines, %d chars\n", lineCount, charCount);
2484+int rhbufsz; /* rhs substitution buffer size */
2485+int rhbufi; /* rhs substitution buffer index */
2486+ 1175+
2487+/* extract_subst_tail: extract substitution tail from the command buffer */ 1176+ return TRUE;
2488+int
2489+extract_subst_tail (flagp, np)
2490+ int *flagp;
2491+ int *np;
2492+{
2493+ char delimiter;
2494+
2495+ *flagp = *np = 0;
2496+ if ((delimiter = *ibufp) == '\n')
2497+ {
2498+ rhbufi = 0;
2499+ *flagp = GPR;
2500+ return 0;
2501+ }
2502+ else if (extract_subst_template () == NULL)
2503+ return ERR;
2504+ else if (*ibufp == '\n')
2505+ {
2506+ *flagp = GPR;
2507+ return 0;
2508+ }
2509+ else if (*ibufp == delimiter)
2510+ ibufp++;
2511+ if ('1' <= *ibufp && *ibufp <= '9')
2512+ {
2513+ STRTOL (*np, ibufp);
2514+ return 0;
2515+ }
2516+ else if (*ibufp == 'g')
2517+ {
2518+ ibufp++;
2519+ *flagp = GSG;
2520+ return 0;
2521+ }
2522+ return 0;
2523+} 1177+}
2524+ 1178+
2525+ 1179+
2526+/* extract_subst_template: return pointer to copy of substitution template 1180+/*
2527+ in the command buffer */ 1181+ * Print lines in a specified range.
2528+char * 1182+ * The last line printed becomes the current line.
2529+extract_subst_template () 1183+ * If expandFlag is TRUE, then the line is printed specially to
1184+ * show magic characters.
1185+ */
1186+static BOOL
1187+printLines(NUM num1, NUM num2, BOOL expandFlag)
2530+{ 1188+{
2531+ int n = 0; 1189+ const LINE * lp;
2532+ int i = 0; 1190+ const unsigned char * cp;
2533+ char c; 1191+ int ch;
2534+ char delimiter = *ibufp++; 1192+ LEN count;
2535+ 1193+
2536+ if (*ibufp == '%' && *(ibufp + 1) == delimiter) 1194+ if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
2537+ {
2538+ ibufp++;
2539+ if (!rhbuf)
2540+ sprintf (errmsg, "No previous substitution");
2541+ return rhbuf;
2542+ }
2543+ while (*ibufp != delimiter)
2544+ {
2545+ REALLOC (rhbuf, rhbufsz, i + 2, NULL);
2546+ if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0')
2547+ {
2548+ i--, ibufp--;
2549+ break;
2550+ }
2551+ else if (c != '\\')
2552+ ;
2553+ else if ((rhbuf[i++] = *ibufp++) != '\n')
2554+ ;
2555+ else if (!isglobal)
2556+ { 1195+ {
2557+ while ((n = get_tty_line ()) == 0 || 1196+ fprintf(stderr, "Bad line range for print\n");
2558+ (n > 0 && ibuf[n - 1] != '\n')) 1197+
2559+ clearerr (stdin); 1198+ return FALSE;
2560+ if (n < 0)
2561+ return NULL;
2562+ } 1199+ }
2563+ }
2564+ REALLOC (rhbuf, rhbufsz, i + 1, NULL);
2565+ rhbuf[rhbufi = i] = '\0';
2566+ return rhbuf;
2567+}
2568+ 1200+
1201+ lp = findLine(num1);
2569+ 1202+
2570+char *rbuf; /* substitute_matching_text buffer */ 1203+ if (lp == NULL)
2571+int rbufsz; /* substitute_matching_text buffer size */ 1204+ return FALSE;
2572+ 1205+
2573+/* search_and_replace: for each line in a range, change text matching a pattern 1206+ while (num1 <= num2)
2574+ according to a substitution template; return status */
2575+int
2576+search_and_replace (pat, gflag, kth)
2577+ pattern_t *pat;
2578+ int gflag;
2579+ int kth;
2580+{
2581+ undo_t *up;
2582+ char *txt;
2583+ char *eot;
2584+ long lc;
2585+ int nsubs = 0;
2586+ line_t *lp;
2587+ int len;
2588+
2589+ current_addr = first_addr - 1;
2590+ for (lc = 0; lc <= second_addr - first_addr; lc++)
2591+ {
2592+ lp = get_addressed_line_node (++current_addr);
2593+ if ((len = substitute_matching_text (pat, lp, gflag, kth)) < 0)
2594+ return ERR;
2595+ else if (len)
2596+ { 1207+ {
2597+ up = NULL; 1208+ if (!expandFlag)
2598+ if (delete_lines (current_addr, current_addr) < 0)
2599+ return ERR;
2600+ txt = rbuf;
2601+ eot = rbuf + len;
2602+ SPL1 ();
2603+ do
2604+ {
2605+ if ((txt = put_sbuf_line (txt)) == NULL)
2606+ { 1209+ {
2607+ SPL0 (); 1210+ write(STDOUT, lp->data, lp->len);
2608+ return ERR; 1211+ setCurNum(num1++);
1212+ lp = lp->next;
1213+
1214+ continue;
2609+ } 1215+ }
2610+ else if (up) 1216+
2611+ up->t = get_addressed_line_node (current_addr); 1217+ /*
2612+ else if ((up = push_undo_stack (UADD, 1218+ * Show control characters and characters with the
2613+ current_addr, current_addr)) == NULL) 1219+ * high bit set specially.
1220+ */
1221+ cp = lp->data;
1222+ count = lp->len;
1223+
1224+ if ((count > 0) && (cp[count - 1] == '\n'))
1225+ count--;
1226+
1227+ while (count-- > 0)
2614+ { 1228+ {
2615+ SPL0 (); 1229+ ch = *cp++;
2616+ return ERR; 1230+
1231+ if (ch & 0x80)
1232+ {
1233+ fputs("M-", stdout);
1234+ ch &= 0x7f;
1235+ }
1236+
1237+ if (ch < ' ')
1238+ {
1239+ fputc('^', stdout);
1240+ ch += '@';
1241+ }
1242+
1243+ if (ch == 0x7f)
1244+ {
1245+ fputc('^', stdout);
1246+ ch = '?';
1247+ }
1248+
1249+ fputc(ch, stdout);
2617+ } 1250+ }
2618+ } 1251+
2619+ while (txt != eot); 1252+ fputs("$\n", stdout);
2620+ SPL0 (); 1253+
2621+ nsubs++; 1254+ setCurNum(num1++);
1255+ lp = lp->next;
2622+ } 1256+ }
2623+ } 1257+
2624+ if (nsubs == 0 && !(gflag & GLB)) 1258+ return TRUE;
2625+ {
2626+ sprintf (errmsg, "No match");
2627+ return ERR;
2628+ }
2629+ else if ((gflag & (GPR | GLS | GNP)) &&
2630+ display_lines (current_addr, current_addr, gflag) < 0)
2631+ return ERR;
2632+ return 0;
2633+} 1259+}
2634+ 1260+
2635+ 1261+
2636+/* substitute_matching_text: replace text matched by a pattern according to 1262+/*
2637+ a substitution template; return pointer to the modified text */ 1263+ * Insert a new line with the specified text.
2638+int 1264+ * The line is inserted so as to become the specified line,
2639+substitute_matching_text (pat, lp, gflag, kth) 1265+ * thus pushing any existing and further lines down one.
2640+ pattern_t *pat; 1266+ * The inserted line is also set to become the current line.
2641+ line_t *lp; 1267+ * Returns TRUE if successful.
2642+ int gflag; 1268+ */
2643+ int kth; 1269+static BOOL
1270+insertLine(NUM num, const char * data, LEN len)
2644+{ 1271+{
2645+ int off = 0; 1272+ LINE * newLp;
2646+ int changed = 0; 1273+ LINE * lp;
2647+ int matchno = 0; 1274+
2648+ int i = 0; 1275+ if ((num < 1) || (num > lastNum + 1))
2649+ regmatch_t rm[SE_MAX];
2650+ char *txt;
2651+ char *eot;
2652+
2653+ if ((txt = get_sbuf_line (lp)) == NULL)
2654+ return ERR;
2655+ if (isbinary)
2656+ NUL_TO_NEWLINE (txt, lp->len);
2657+ eot = txt + lp->len;
2658+ if (!regexec (pat, txt, SE_MAX, rm, 0))
2659+ {
2660+ do
2661+ { 1276+ {
2662+ if (!kth || kth == ++matchno) 1277+ fprintf(stderr, "Inserting at bad line number\n");
2663+ { 1278+
2664+ changed++; 1279+ return FALSE;
2665+ i = rm[0].rm_so;
2666+ REALLOC (rbuf, rbufsz, off + i, ERR);
2667+ if (isbinary)
2668+ NEWLINE_TO_NUL (txt, rm[0].rm_eo);
2669+ memcpy (rbuf + off, txt, i);
2670+ off += i;
2671+ if ((off = apply_subst_template (txt, rm, off,
2672+ pat->re_nsub)) < 0)
2673+ return ERR;
2674+ }
2675+ else
2676+ {
2677+ i = rm[0].rm_eo;
2678+ REALLOC (rbuf, rbufsz, off + i, ERR);
2679+ if (isbinary)
2680+ NEWLINE_TO_NUL (txt, i);
2681+ memcpy (rbuf + off, txt, i);
2682+ off += i;
2683+ }
2684+ txt += rm[0].rm_eo;
2685+ } 1280+ }
2686+ while (*txt && (!changed || ((gflag & GSG) && rm[0].rm_eo)) && 1281+
2687+ !regexec (pat, txt, SE_MAX, rm, REG_NOTBOL)); 1282+ newLp = (LINE *) malloc(sizeof(LINE) + len - 1);
2688+ i = eot - txt; 1283+
2689+ REALLOC (rbuf, rbufsz, off + i + 2, ERR); 1284+ if (newLp == NULL)
2690+ if (i > 0 && !rm[0].rm_eo && (gflag & GSG))
2691+ { 1285+ {
2692+ sprintf (errmsg, "Infinite substitution loop"); 1286+ fprintf(stderr, "Failed to allocate memory for line\n");
2693+ return ERR; 1287+
1288+ return FALSE;
2694+ } 1289+ }
2695+ if (isbinary)
2696+ NEWLINE_TO_NUL (txt, i);
2697+ memcpy (rbuf + off, txt, i);
2698+ memcpy (rbuf + off + i, "\n", 2);
2699+ }
2700+ return changed ? off + i + 1 : 0;
2701+}
2702+ 1290+
1291+ memcpy(newLp->data, data, len);
1292+ newLp->len = len;
2703+ 1293+
2704+/* apply_subst_template: modify text according to a substitution template; 1294+ if (num > lastNum)
2705+ return offset to end of modified text */ 1295+ lp = &lines;
2706+int 1296+ else
2707+apply_subst_template (boln, rm, off, re_nsub) 1297+ {
2708+ char *boln; 1298+ lp = findLine(num);
2709+ regmatch_t *rm;
2710+ int off;
2711+ int re_nsub;
2712+{
2713+ int j = 0;
2714+ int k = 0;
2715+ int n;
2716+ char *sub = rhbuf;
2717+
2718+ for (; sub - rhbuf < rhbufi; sub++)
2719+ if (*sub == '&')
2720+ {
2721+ j = rm[0].rm_so;
2722+ k = rm[0].rm_eo;
2723+ REALLOC (rbuf, rbufsz, off + k - j, ERR);
2724+ while (j < k)
2725+ rbuf[off++] = boln[j++];
2726+ }
2727+ else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
2728+ (n = *sub - '0') <= re_nsub)
2729+ {
2730+ j = rm[n].rm_so;
2731+ k = rm[n].rm_eo;
2732+ REALLOC (rbuf, rbufsz, off + k - j, ERR);
2733+ while (j < k)
2734+ rbuf[off++] = boln[j++];
2735+ }
2736+ else
2737+ {
2738+ REALLOC (rbuf, rbufsz, off + 1, ERR);
2739+ rbuf[off++] = *sub;
2740+ }
2741+ REALLOC (rbuf, rbufsz, off + 1, ERR);
2742+ rbuf[off] = '\0';
2743+ return off;
2744+}
2745+ 1299+
1300+ if (lp == NULL)
1301+ {
1302+ free((char *) newLp);
2746+ 1303+
1304+ return FALSE;
1305+ }
1306+ }
2747+ 1307+
2748+#define USIZE 100 /* undo stack size */ 1308+ newLp->next = lp;
2749+undo_t *ustack = NULL; /* undo stack */ 1309+ newLp->prev = lp->prev;
2750+long usize = 0; /* stack size variable */ 1310+ lp->prev->next = newLp;
2751+long u_p = 0; /* undo stack pointer */ 1311+ lp->prev = newLp;
2752+ 1312+
2753+/* push_undo_stack: return pointer to intialized undo node */ 1313+ lastNum++;
2754+undo_t * 1314+ dirty = TRUE;
2755+push_undo_stack (type, from, to) 1315+
2756+ int type; 1316+ return setCurNum(num);
2757+ long from;
2758+ long to;
2759+{
2760+ undo_t *t;
2761+
2762+ if ((t = ustack) == NULL &&
2763+ (t = ustack = (undo_t *) malloc ((usize = USIZE) * sizeof (undo_t))) == NULL)
2764+ {
2765+ fprintf (stderr, "%s\n", strerror (errno));
2766+ sprintf (errmsg, "Out of memory");
2767+ return NULL;
2768+ }
2769+ else if (u_p >= usize &&
2770+ (t = (undo_t *) realloc (ustack, (usize += USIZE) * sizeof (undo_t))) == NULL)
2771+ {
2772+ /* out of memory - release undo stack */
2773+ fprintf (stderr, "%s\n", strerror (errno));
2774+ sprintf (errmsg, "Out of memory");
2775+ clear_undo_stack ();
2776+ free (ustack);
2777+ ustack = NULL;
2778+ usize = 0;
2779+ return NULL;
2780+ }
2781+ ustack = t;
2782+ ustack[u_p].type = type;
2783+ ustack[u_p].t = get_addressed_line_node (to);
2784+ ustack[u_p].h = get_addressed_line_node (from);
2785+ return ustack + u_p++;
2786+} 1317+}
2787+ 1318+
2788+ 1319+
2789+/* USWAP: swap undo nodes */ 1320+/*
2790+#define USWAP(x, y) \ 1321+ * Delete lines from the given range.
2791+ do \ 1322+ */
2792+ { \ 1323+static BOOL
2793+ undo_t utmp; \ 1324+deleteLines(NUM num1, NUM num2)
2794+ utmp = (x), (x) = (y), (y) = utmp; \ 1325+{
2795+ } \ 1326+ LINE * lp;
2796+ while (0) 1327+ LINE * nlp;
1328+ LINE * plp;
1329+ NUM count;
2797+ 1330+
1331+ if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
1332+ {
1333+ fprintf(stderr, "Bad line numbers for delete\n");
2798+ 1334+
2799+long u_current_addr = -1; /* if >= 0, undo enabled */ 1335+ return FALSE;
2800+long u_addr_last = -1; /* if >= 0, undo enabled */ 1336+ }
2801+ 1337+
2802+/* pop_undo_stack: undo last change to the editor buffer */ 1338+ lp = findLine(num1);
2803+int 1339+
2804+pop_undo_stack () 1340+ if (lp == NULL)
2805+{ 1341+ return FALSE;
2806+ long n; 1342+
2807+ long o_current_addr = current_addr; 1343+ if ((curNum >= num1) && (curNum <= num2))
2808+ long o_addr_last = addr_last;
2809+
2810+ if (u_current_addr == -1 || u_addr_last == -1)
2811+ {
2812+ sprintf (errmsg, "Nothing to undo");
2813+ return ERR;
2814+ }
2815+ else if (u_p)
2816+ modified = 1;
2817+ get_addressed_line_node (0); /* this get_addressed_line_node last! */
2818+ SPL1 ();
2819+ for (n = u_p; n-- > 0;)
2820+ {
2821+ switch (ustack[n].type)
2822+ { 1344+ {
2823+ case UADD: 1345+ if (num2 < lastNum)
2824+ REQUE (ustack[n].h->q_back, ustack[n].t->q_forw); 1346+ setCurNum(num2 + 1);
2825+ break; 1347+ else if (num1 > 1)
2826+ case UDEL: 1348+ setCurNum(num1 - 1);
2827+ REQUE (ustack[n].h->q_back, ustack[n].h); 1349+ else
2828+ REQUE (ustack[n].t, ustack[n].t->q_forw); 1350+ curNum = 0;
2829+ break;
2830+ case UMOV:
2831+ case VMOV:
2832+ REQUE (ustack[n - 1].h, ustack[n].h->q_forw);
2833+ REQUE (ustack[n].t->q_back, ustack[n - 1].t);
2834+ REQUE (ustack[n].h, ustack[n].t);
2835+ n--;
2836+ break;
2837+ default:
2838+ /*NOTREACHED */
2839+ ;
2840+ } 1351+ }
2841+ ustack[n].type ^= 1;
2842+ }
2843+ /* reverse undo stack order */
2844+ for (n = u_p; n-- > (u_p + 1) / 2;)
2845+ USWAP (ustack[n], ustack[u_p - 1 - n]);
2846+ if (isglobal)
2847+ clear_active_list ();
2848+ current_addr = u_current_addr, u_current_addr = o_current_addr;
2849+ addr_last = u_addr_last, u_addr_last = o_addr_last;
2850+ SPL0 ();
2851+ return 0;
2852+}
2853+ 1352+
1353+ count = num2 - num1 + 1;
2854+ 1354+
2855+/* clear_undo_stack: clear the undo stack */ 1355+ if (curNum > num2)
2856+void 1356+ curNum -= count;
2857+clear_undo_stack ()
2858+{
2859+ line_t *lp, *ep, *tl;
2860+
2861+ while (u_p--)
2862+ if (ustack[u_p].type == UDEL)
2863+ {
2864+ ep = ustack[u_p].t->q_forw;
2865+ for (lp = ustack[u_p].h; lp != ep; lp = tl)
2866+ {
2867+ unmark_line_node (lp);
2868+ tl = lp->q_forw;
2869+ free (lp);
2870+ }
2871+ }
2872+ u_p = 0;
2873+ u_current_addr = current_addr;
2874+ u_addr_last = addr_last;
2875+}
2876+ 1357+
1358+ lastNum -= count;
2877+ 1359+
1360+ while (count-- > 0)
1361+ {
1362+ nlp = lp->next;
1363+ plp = lp->prev;
1364+ plp->next = nlp;
1365+ nlp->prev = plp;
1366+ lp->next = NULL;
1367+ lp->prev = NULL;
1368+ lp->len = 0;
1369+ free(lp);
1370+ lp = nlp;
1371+ }
2878+ 1372+
1373+ dirty = TRUE;
2879+ 1374+
2880+/* build_active_list: add line matching a pattern to the global-active list */ 1375+ return TRUE;
2881+int
2882+build_active_list (isgcmd)
2883+ int isgcmd;
2884+{
2885+ pattern_t *pat;
2886+ line_t *lp;
2887+ long n;
2888+ char *s;
2889+ char delimiter;
2890+
2891+ if ((delimiter = *ibufp) == ' ' || delimiter == '\n')
2892+ {
2893+ sprintf (errmsg, "Invalid pattern delimiter");
2894+ return ERR;
2895+ }
2896+ else if ((pat = get_compiled_pattern ()) == NULL)
2897+ return ERR;
2898+ else if (*ibufp == delimiter)
2899+ ibufp++;
2900+ clear_active_list ();
2901+ lp = get_addressed_line_node (first_addr);
2902+ for (n = first_addr; n <= second_addr; n++, lp = lp->q_forw)
2903+ {
2904+ if ((s = get_sbuf_line (lp)) == NULL)
2905+ return ERR;
2906+ if (isbinary)
2907+ NUL_TO_NEWLINE (s, lp->len);
2908+ if (!regexec (pat, s, 0, NULL, 0) == isgcmd &&
2909+ set_active_node (lp) < 0)
2910+ return ERR;
2911+ }
2912+ return 0;
2913+} 1376+}
2914+ 1377+
2915+ 1378+
2916+/* exec_global: apply command list in the command buffer to the active 1379+/*
2917+ lines in a range; return command status */ 1380+ * Search for a line which contains the specified string.
2918+long 1381+ * If the string is NULL, then the previously searched for string
2919+exec_global (interact, gflag) 1382+ * is used. The currently searched for string is saved for future use.
2920+ int interact; 1383+ * Returns the line number which matches, or 0 if there was no match
2921+ int gflag; 1384+ * with an error printed.
1385+ */
1386+static NUM
1387+searchLines(const char * str, NUM num1, NUM num2)
2922+{ 1388+{
2923+ static char *ocmd = NULL; 1389+ const LINE * lp;
2924+ static int ocmdsz = 0; 1390+ int len;
2925+ 1391+
2926+ line_t *lp = NULL; 1392+ if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
2927+ int status; 1393+ {
2928+ int n; 1394+ fprintf(stderr, "Bad line numbers for search\n");
2929+ char *cmd = NULL; 1395+
2930+ 1396+ return 0;
2931+ if (!interact) 1397+ }
2932+ if (traditional && !strcmp (ibufp, "\n")) 1398+
2933+ cmd = "p\n"; /* null cmd-list == `p' */ 1399+ if (*str == '\0')
2934+ else if ((cmd = get_extended_line (&n, 0)) == NULL)
2935+ return ERR;
2936+ clear_undo_stack ();
2937+ while ((lp = next_active_node ()) != NULL)
2938+ {
2939+ if ((current_addr = get_line_node_addr (lp)) < 0)
2940+ return ERR;
2941+ if (interact)
2942+ { 1400+ {
2943+ /* print current_addr; get a command in global syntax */ 1401+ if (searchString[0] == '\0')
2944+ if (display_lines (current_addr, current_addr, gflag) < 0)
2945+ return ERR;
2946+ while ((n = get_tty_line ()) > 0 &&
2947+ ibuf[n - 1] != '\n')
2948+ clearerr (stdin);
2949+ if (n < 0)
2950+ return ERR;
2951+ else if (n == 0)
2952+ {
2953+ sprintf (errmsg, "Unexpected end-of-file");
2954+ return ERR;
2955+ }
2956+ else if (n == 1 && !strcmp (ibuf, "\n"))
2957+ continue;
2958+ else if (n == 2 && !strcmp (ibuf, "&\n"))
2959+ {
2960+ if (cmd == NULL)
2961+ { 1402+ {
2962+ sprintf (errmsg, "No previous command"); 1403+ fprintf(stderr, "No previous search string\n");
2963+ return ERR; 1404+
1405+ return 0;
2964+ } 1406+ }
2965+ else
2966+ cmd = ocmd;
2967+ }
2968+ else if ((cmd = get_extended_line (&n, 0)) == NULL)
2969+ return ERR;
2970+ else
2971+ {
2972+ REALLOC (ocmd, ocmdsz, n + 1, ERR);
2973+ memcpy (ocmd, cmd, n + 1);
2974+ cmd = ocmd;
2975+ }
2976+ 1407+
1408+ str = searchString;
2977+ } 1409+ }
2978+ ibufp = cmd;
2979+ for (; *ibufp;)
2980+ if ((status = extract_addr_range ()) < 0 ||
2981+ (status = exec_command ()) < 0 ||
2982+ (status > 0 && (status = display_lines (
2983+ current_addr, current_addr, status)) < 0))
2984+ return status;
2985+ }
2986+ return 0;
2987+}
2988+ 1410+
1411+ if (str != searchString)
1412+ strcpy(searchString, str);
2989+ 1413+
2990+line_t **active_list; /* list of lines active in a global command */ 1414+ len = strlen(str);
2991+long active_last; /* index of last active line in active_list */
2992+long active_size; /* size of active_list */
2993+long active_ptr; /* active_list index (non-decreasing) */
2994+long active_ndx; /* active_list index (modulo active_last) */
2995+ 1415+
2996+/* set_active_node: add a line node to the global-active list */ 1416+ lp = findLine(num1);
2997+int 1417+
2998+set_active_node (lp) 1418+ if (lp == NULL)
2999+ line_t *lp; 1419+ return 0;
3000+{ 1420+
3001+ if (active_last + 1 > active_size) 1421+ while (num1 <= num2)
3002+ {
3003+ int ti = active_size;
3004+ line_t **ts;
3005+ SPL1 ();
3006+ if (active_list != NULL)
3007+ {
3008+ if ((ts = (line_t **) realloc (active_list,
3009+ (ti += MINBUFSZ) * sizeof (line_t **))) == NULL)
3010+ {
3011+ fprintf (stderr, "%s\n", strerror (errno));
3012+ sprintf (errmsg, "Out of memory");
3013+ SPL0 ();
3014+ return ERR;
3015+ }
3016+ }
3017+ else
3018+ { 1422+ {
3019+ if ((ts = (line_t **) malloc ((ti += MINBUFSZ) * 1423+ if (findString(lp, str, len, 0) >= 0)
3020+ sizeof (line_t **))) == NULL) 1424+ return num1;
3021+ { 1425+
3022+ fprintf (stderr, "%s\n", strerror (errno)); 1426+ num1++;
3023+ sprintf (errmsg, "Out of memory"); 1427+ lp = lp->next;
3024+ SPL0 ();
3025+ return ERR;
3026+ }
3027+ } 1428+ }
3028+ active_size = ti; 1429+
3029+ active_list = ts; 1430+ fprintf(stderr, "Cannot find string \"%s\"\n", str);
3030+ SPL0 (); 1431+
3031+ } 1432+ return 0;
3032+ active_list[active_last++] = lp;
3033+ return 0;
3034+} 1433+}
3035+ 1434+
3036+ 1435+
3037+/* unset_active_nodes: remove a range of lines from the global-active list */ 1436+/*
3038+void 1437+ * Return a pointer to the specified line number.
3039+unset_active_nodes (np, mp) 1438+ */
3040+ line_t *np, *mp; 1439+static LINE *
1440+findLine(NUM num)
3041+{ 1441+{
3042+ line_t *lp; 1442+ LINE * lp;
3043+ long i; 1443+ NUM lnum;
3044+ 1444+
3045+ for (lp = np; lp != mp; lp = lp->q_forw) 1445+ if ((num < 1) || (num > lastNum))
3046+ for (i = 0; i < active_last; i++)
3047+ if (active_list[active_ndx] == lp)
3048+ { 1446+ {
3049+ active_list[active_ndx] = NULL; 1447+ fprintf(stderr, "Line number %d does not exist\n", num);
3050+ active_ndx = INC_MOD (active_ndx, active_last - 1); 1448+
3051+ break; 1449+ return NULL;
3052+ } 1450+ }
3053+ else
3054+ active_ndx = INC_MOD (active_ndx, active_last - 1);
3055+}
3056+ 1451+
1452+ if (curNum <= 0)
1453+ {
1454+ curNum = 1;
1455+ curLine = lines.next;
1456+ }
3057+ 1457+
3058+/* next_active_node: return the next global-active line node */ 1458+ if (num == curNum)
3059+line_t * 1459+ return curLine;
3060+next_active_node ()
3061+{
3062+ while (active_ptr < active_last && active_list[active_ptr] == NULL)
3063+ active_ptr++;
3064+ return (active_ptr < active_last) ? active_list[active_ptr++] : NULL;
3065+}
3066+ 1460+
1461+ lp = curLine;
1462+ lnum = curNum;
3067+ 1463+
3068+/* clear_active_list: clear the global-active list */ 1464+ if (num < (curNum / 2))
3069+void 1465+ {
3070+clear_active_list () 1466+ lp = lines.next;
3071+{ 1467+ lnum = 1;
3072+ SPL1 (); 1468+ }
3073+ active_size = active_last = active_ptr = active_ndx = 0; 1469+ else if (num > ((curNum + lastNum) / 2))
3074+ if (active_list != NULL) 1470+ {
3075+ free (active_list); 1471+ lp = lines.prev;
3076+ active_list = NULL; 1472+ lnum = lastNum;
3077+ SPL0 (); 1473+ }
3078+}
3079+ 1474+
1475+ while (lnum < num)
1476+ {
1477+ lp = lp->next;
1478+ lnum++;
1479+ }
3080+ 1480+
1481+ while (lnum > num)
1482+ {
1483+ lp = lp->prev;
1484+ lnum--;
1485+ }
3081+ 1486+
3082+/* get_compiled_pattern: return pointer to compiled pattern from command 1487+ return lp;
3083+ buffer */
3084+pattern_t *
3085+get_compiled_pattern ()
3086+{
3087+ static pattern_t *exp = NULL;
3088+
3089+ char *exps;
3090+ char delimiter;
3091+ int n;
3092+
3093+ if ((delimiter = *ibufp) == ' ')
3094+ {
3095+ sprintf (errmsg, "Invalid pattern delimiter");
3096+ return NULL;
3097+ }
3098+ else if (delimiter == '\n' || *++ibufp == '\n' || *ibufp == delimiter)
3099+ {
3100+ if (!exp)
3101+ sprintf (errmsg, "No previous pattern");
3102+ return exp;
3103+ }
3104+ else if ((exps = extract_pattern (delimiter)) == NULL)
3105+ return NULL;
3106+ /* buffer alloc'd && not reserved */
3107+ if (exp && !patlock)
3108+ regfree (exp);
3109+ else if ((exp = (pattern_t *) malloc (sizeof (pattern_t))) == NULL)
3110+ {
3111+ fprintf (stderr, "%s\n", strerror (errno));
3112+ sprintf (errmsg, "Out of memory");
3113+ return NULL;
3114+ }
3115+ patlock = 0;
3116+ if ((n = regcomp (exp, exps, 0)))
3117+ {
3118+ regerror (n, exp, errmsg, ERRSZ);
3119+ free (exp);
3120+ return exp = NULL;
3121+ }
3122+ return exp;
3123+} 1488+}
3124+ 1489+
3125+ 1490+
3126+/* extract_pattern: copy a pattern string from the command buffer; return 1491+/*
3127+ pointer to the copy */ 1492+ * Set the current line number.
3128+char * 1493+ * Returns TRUE if successful.
3129+extract_pattern (delimiter) 1494+ */
3130+ int delimiter; 1495+static BOOL
1496+setCurNum(NUM num)
3131+{ 1497+{
3132+ static char *lhbuf = NULL; /* buffer */ 1498+ LINE * lp;
3133+ static int lhbufsz = 0; /* buffer size */
3134+
3135+ char *nd;
3136+ int len;
3137+
3138+ for (nd = ibufp; *nd != delimiter && *nd != '\n'; nd++)
3139+ switch (*nd)
3140+ {
3141+ default:
3142+ break;
3143+ case '[':
3144+ if ((nd = parse_char_class (++nd)) == NULL)
3145+ {
3146+ sprintf (errmsg, "Unbalanced brackets ([])");
3147+ return NULL;
3148+ }
3149+ break;
3150+ case '\\':
3151+ if (*++nd == '\n')
3152+ {
3153+ sprintf (errmsg, "Trailing backslash (\\)");
3154+ return NULL;
3155+ }
3156+ break;
3157+ }
3158+ len = nd - ibufp;
3159+ REALLOC (lhbuf, lhbufsz, len + 1, NULL);
3160+ memcpy (lhbuf, ibufp, len);
3161+ lhbuf[len] = '\0';
3162+ ibufp = nd;
3163+ return (isbinary) ? NUL_TO_NEWLINE (lhbuf, len) : lhbuf;
3164+}
3165+ 1499+
1500+ lp = findLine(num);
3166+ 1501+
3167+/* parse_char_class: expand a POSIX character class */ 1502+ if (lp == NULL)
3168+char * 1503+ return FALSE;
3169+parse_char_class (s)
3170+ char *s;
3171+{
3172+ int c, d;
3173+
3174+ if (*s == '^')
3175+ s++;
3176+ if (*s == ']')
3177+ s++;
3178+ for (; *s != ']' && *s != '\n'; s++)
3179+ if (*s == '[' && ((d = *(s + 1)) == '.' || d == ':' || d == '='))
3180+ for (s++, c = *++s; *s != ']' || c != d; s++)
3181+ if ((c = *s) == '\n')
3182+ return NULL;
3183+ return (*s == ']') ? s : NULL;
3184+}
3185--- /dev/null 2005-04-22 11:15:01.120978184 -0400
3186+++ editors/ed.h 2005-04-22 11:15:09.000000000 -0400
3187@@ -0,0 +1,256 @@
3188+/* ed.h: type and constant definitions for the ed editor. */
3189+/* ed line editor.
3190+ Copyright (C) 1993, 1994 Andrew Moore, Talke Studio
3191+ All Rights Reserved
3192+
3193+ This program is free software; you can redistribute it and/or modify
3194+ it under the terms of the GNU General Public License as published by
3195+ the Free Software Foundation; either version 2, or (at your option)
3196+ any later version.
3197+
3198+ This program is distributed in the hope that it will be useful, but
3199+ WITHOUT ANY WARRANTY; without even the implied warranty of
3200+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3201+ General Public License for more details.
3202+
3203+ You should have received a copy of the GNU General Public License
3204+ along with this program; if not, write to the Free Software
3205+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3206+
3207+ @(#)$Id: ed.h,v 1.14 1994/11/13 04:25:44 alm Exp $
3208+*/
3209+ 1504+
3210+#include <stdio.h> 1505+ curNum = num;
1506+ curLine = lp;
1507+
1508+ return TRUE;
1509+}
3211+ 1510+
3212+#define ERR (-2) 1511+/* END CODE */
3213+#define EMOD (-3)
3214+#define FATAL (-4)
3215+
3216+#define ERRSZ (PATH_MAX + 40) /* size of error message buffer */
3217+#define MINBUFSZ 512 /* minimum buffer size: must be > 0 */
3218+#define SE_MAX 30 /* max subexpressions in a regular expression */
3219+
3220+#define LINECHARS INT_MAX /* max chars per line */
3221+
3222+/* gflags */
3223+#define GLB 001 /* global command */
3224+#define GPR 002 /* print after command */
3225+#define GLS 004 /* list after command */
3226+#define GNP 010 /* enumerate after command */
3227+#define GSG 020 /* global substitute */
3228+
3229+typedef regex_t pattern_t;
3230+
3231+/* Line node */
3232+typedef struct line
3233+ {
3234+ struct line *q_forw;
3235+ struct line *q_back;
3236+ off_t seek; /* address of line in scratch buffer */
3237+ int len; /* length of line */
3238+ }
3239+line_t;
3240+
3241+
3242+typedef struct undo
3243+ {
3244+
3245+/* type of undo nodes */
3246+#define UADD 0
3247+#define UDEL 1
3248+#define UMOV 2
3249+#define VMOV 3
3250+
3251+ int type; /* command type */
3252+ line_t *h; /* head of list */
3253+ line_t *t; /* tail of list */
3254+ }
3255+undo_t;
3256+
3257+#define INC_MOD(l, k) ((l) + 1 > (k) ? 0 : (l) + 1)
3258+#define DEC_MOD(l, k) ((l) - 1 < 0 ? (k) : (l) - 1)
3259+
3260+/* SPL1: disable some interrupts (requires reliable signals) */
3261+#define SPL1() mutex++
3262+
3263+/* SPL0: enable all interrupts; check sigflags (requires reliable signals) */
3264+#define SPL0() \
3265+ do \
3266+ { \
3267+ if (--mutex == 0) \
3268+ { \
3269+ if (sigflags & (1 << (SIGHUP - 1))) handle_hup (SIGHUP); \
3270+ if (sigflags & (1 << (SIGINT - 1))) handle_int (SIGINT); \
3271+ } \
3272+ } \
3273+ while (0)
3274+
3275+/* STRTOL: convert a string to long */
3276+#define STRTOL(i, p) \
3277+ do \
3278+ { \
3279+ if ((((i) = strtol ((p), &(p), 10)) == LONG_MIN \
3280+ || (i) == LONG_MAX) && errno == ERANGE) \
3281+ { \
3282+ sprintf (errmsg, "Number out of range"); \
3283+ (i) = 0; \
3284+ return ERR; \
3285+ } \
3286+ } \
3287+ while (0)
3288+
3289+/* REALLOC: assure at least a minimum size for buffer b */
3290+#define REALLOC(b, n, i, err) \
3291+ do \
3292+ { \
3293+ if ((i) > (n)) \
3294+ { \
3295+ int ti = (n); \
3296+ char *ts; \
3297+ SPL1 (); \
3298+ if ((b) != NULL) \
3299+ { \
3300+ if ((ts = (char *) realloc ((b), ti += max ((i), MINBUFSZ))) \
3301+ == NULL) \
3302+ { \
3303+ fprintf (stderr, "%s\n", strerror (errno)); \
3304+ sprintf (errmsg, "Out of memory"); \
3305+ SPL0 (); \
3306+ return err; \
3307+ } \
3308+ } \
3309+ else \
3310+ { \
3311+ if ((ts = (char *) malloc (ti += max ((i), MINBUFSZ))) \
3312+ == NULL) \
3313+ { \
3314+ fprintf (stderr, "%s\n", strerror (errno)); \
3315+ sprintf (errmsg, "Out of memory"); \
3316+ SPL0 (); \
3317+ return err; \
3318+ } \
3319+ } \
3320+ (n) = ti; \
3321+ (b) = ts; \
3322+ SPL0 (); \
3323+ } \
3324+ } \
3325+ while (0)
3326+
3327+/* REQUE: link pred before succ */
3328+#define REQUE(pred, succ) \
3329+ ((pred)->q_forw = (succ), (succ)->q_back = (pred))
3330+
3331+/* INSQUE: insert elem in circular queue after pred */
3332+#define INSQUE(elem, pred) \
3333+ do \
3334+ { \
3335+ REQUE ((elem), (pred)->q_forw); \
3336+ REQUE ((pred), (elem)); \
3337+ } \
3338+ while (0)
3339+
3340+/* REMQUE: remove elem from circular queue */
3341+#define REMQUE(elem) \
3342+ REQUE ((elem)->q_back, (elem)->q_forw)
3343+
3344+/* NUL_TO_NEWLINE: overwrite ASCII NULs with newlines */
3345+#define NUL_TO_NEWLINE(s, l) translit_text(s, l, '\0', '\n')
3346+
3347+/* NEWLINE_TO_NUL: overwrite newlines with ASCII NULs */
3348+#define NEWLINE_TO_NUL(s, l) translit_text(s, l, '\n', '\0')
3349+
3350+/* Local Function Declarations */
3351+void add_line_node __P ((line_t *));
3352+int append_lines __P ((long));
3353+int apply_subst_template __P ((char *, regmatch_t *, int, int));
3354+int build_active_list __P ((int));
3355+int cbc_decode __P ((char *, FILE *));
3356+int cbc_encode __P ((char *, int, FILE *));
3357+int check_addr_range __P ((long, long));
3358+void clear_active_list __P ((void));
3359+void clear_undo_stack __P ((void));
3360+int close_sbuf __P ((void));
3361+int copy_lines __P ((long));
3362+int delete_lines __P ((long, long));
3363+void delete_yank_lines __P ((void));
3364+int display_lines __P ((long, long, int));
3365+line_t *dup_line_node __P ((line_t *));
3366+int exec_command __P ((void));
3367+long exec_global __P ((int, int));
3368+int extract_addr_range __P ((void));
3369+char *extract_pattern __P ((int));
3370+int extract_subst_tail __P ((int *, int *));
3371+char *extract_subst_template __P ((void));
3372+int filter_lines __P ((long, long, char *));
3373+line_t *get_addressed_line_node __P ((long));
3374+pattern_t *get_compiled_pattern __P ((void));
3375+char *get_extended_line __P ((int *, int));
3376+char *get_filename __P ((void));
3377+int get_keyword __P ((void));
3378+long get_line_node_addr __P ((line_t *));
3379+long get_matching_node_addr __P ((pattern_t *, int));
3380+long get_marked_node_addr __P ((int));
3381+char *get_sbuf_line __P ((line_t *));
3382+int get_shell_command __P ((void));
3383+int get_stream_line __P ((FILE *));
3384+int get_tty_line __P ((void));
3385+void handle_hup __P ((int));
3386+void handle_int __P ((int));
3387+void handle_winch __P ((int));
3388+int has_trailing_escape __P ((char *, char *));
3389+int hex_to_binary __P ((int, int));
3390+void init_buffers __P ((void));
3391+int is_legal_filename __P ((char *));
3392+int is_regular_file __P ((int));
3393+int join_lines __P ((long, long));
3394+int mark_line_node __P ((line_t *, int));
3395+int move_lines __P ((long));
3396+line_t *next_active_node ();
3397+long next_addr __P ((void));
3398+int open_sbuf __P ((void));
3399+char *parse_char_class __P ((char *));
3400+int pop_undo_stack __P ((void));
3401+undo_t *push_undo_stack __P ((int, long, long));
3402+int put_lines __P ((long));
3403+char *put_sbuf_line __P ((char *));
3404+int put_stream_line __P ((FILE *, char *, int));
3405+int put_tty_line __P ((char *, int, long, int));
3406+void quit __P ((int));
3407+long read_file __P ((char *, long));
3408+long read_stream __P ((FILE *, long));
3409+void (*reliable_signal __P ((int, void (*) ()))) ();
3410+int search_and_replace __P ((pattern_t *, int, int));
3411+int set_active_node __P ((line_t *));
3412+void signal_hup __P ((int));
3413+void signal_int __P ((int));
3414+char *strip_escapes __P ((char *));
3415+int substitute_matching_text __P ((pattern_t *, line_t *, int, int));
3416+char *translit_text __P ((char *, int, int, int));
3417+void unmark_line_node __P ((line_t *));
3418+void unset_active_nodes __P ((line_t *, line_t *));
3419+long write_file __P ((char *, char *, long, long));
3420+long write_stream __P ((FILE *, long, long));
3421+int yank_lines __P ((long, long));
3422+
3423+/* global buffers */
3424+extern char stdinbuf[];
3425+extern char *errmsg;
3426+extern char *ibuf;
3427+extern char *ibufp;
3428+extern int ibufsz;
3429+
3430+/* global flags */
3431+extern int isbinary;
3432+extern int isglobal;
3433+extern int modified;
3434+extern int mutex;
3435+extern int sigflags;
3436+extern int traditional;
3437+
3438+/* global vars */
3439+extern long addr_last;
3440+extern long current_addr;
3441+extern long first_addr;
3442+extern int lineno;
3443+extern long second_addr;