diff options
author | Mike Frysinger <vapier@gentoo.org> | 2005-04-24 05:18:00 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2005-04-24 05:18:00 +0000 |
commit | cf131bb3280d555e40808c28366d0cb33c6a4497 (patch) | |
tree | aef075e624c18b92a6e645993a06439093c36bbd | |
parent | d89e5e645030fd28be5adb636191a70004acb750 (diff) | |
download | busybox-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.patch | 4284 |
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; | ||