diff options
author | Mike Frysinger <vapier@gentoo.org> | 2005-04-23 01:50:55 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2005-04-23 01:50:55 +0000 |
commit | 84ab267e226407ee402eff10aaf8239ed684de77 (patch) | |
tree | 24d9d109c14b18b36e4f007973f7ea28b52a4c91 | |
parent | 6b05b0ce9345895bbd8ae3e553699613d6d2bc98 (diff) | |
download | busybox-w32-84ab267e226407ee402eff10aaf8239ed684de77.tar.gz busybox-w32-84ab267e226407ee402eff10aaf8239ed684de77.tar.bz2 busybox-w32-84ab267e226407ee402eff10aaf8239ed684de77.zip |
patch for a very alpha busybox ed
-rw-r--r-- | patches/ed.patch | 3443 |
1 files changed, 3443 insertions, 0 deletions
diff --git a/patches/ed.patch b/patches/ed.patch new file mode 100644 index 000000000..fc261b88d --- /dev/null +++ b/patches/ed.patch | |||
@@ -0,0 +1,3443 @@ | |||
1 | Index: editors/Makefile.in | ||
2 | =================================================================== | ||
3 | --- editors/Makefile.in (revision 10144) | ||
4 | +++ editors/Makefile.in (working copy) | ||
5 | @@ -24,8 +24,9 @@ | ||
6 | srcdir=$(top_srcdir)/editors | ||
7 | |||
8 | EDITOR-y:= | ||
9 | -EDITOR-$(CONFIG_AWK) += awk.o | ||
10 | -EDITOR-$(CONFIG_PATCH) += patch.o | ||
11 | +EDITOR-$(CONFIG_AWK) += awk.o | ||
12 | +EDITOR-$(CONFIG_ED) += ed.o | ||
13 | +EDITOR-$(CONFIG_PATCH) += patch.o | ||
14 | EDITOR-$(CONFIG_SED) += sed.o | ||
15 | EDITOR-$(CONFIG_VI) += vi.o | ||
16 | EDITOR_SRC:= $(EDITOR-y) | ||
17 | Index: editors/Config.in | ||
18 | =================================================================== | ||
19 | --- editors/Config.in (revision 10144) | ||
20 | +++ editors/Config.in (working copy) | ||
21 | @@ -20,6 +20,12 @@ | ||
22 | Enable math functions of the Awk programming language. | ||
23 | NOTE: This will require libm to be present for linking. | ||
24 | |||
25 | +config CONFIG_ED | ||
26 | + bool "ed" | ||
27 | + default n | ||
28 | + help | ||
29 | + ed | ||
30 | + | ||
31 | config CONFIG_PATCH | ||
32 | bool "patch" | ||
33 | default n | ||
34 | Index: include/usage.h | ||
35 | =================================================================== | ||
36 | --- include/usage.h (revision 10151) | ||
37 | +++ include/usage.h (working copy) | ||
38 | @@ -556,6 +561,9 @@ | ||
39 | "$ echo \"Erik\\nis\\ncool\"\n" \ | ||
40 | "Erik\\nis\\ncool\n") | ||
41 | |||
42 | +#define ed_trivial_usage "" | ||
43 | +#define ed_full_usage "" | ||
44 | + | ||
45 | #define env_trivial_usage \ | ||
46 | "[-iu] [-] [name=value]... [command]" | ||
47 | #define env_full_usage \ | ||
48 | Index: include/applets.h | ||
49 | =================================================================== | ||
50 | --- include/applets.h (revision 10151) | ||
51 | +++ include/applets.h (working copy) | ||
52 | @@ -179,6 +179,9 @@ | ||
53 | #ifdef CONFIG_ECHO | ||
54 | APPLET(echo, echo_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||
55 | #endif | ||
56 | +#ifdef CONFIG_ED | ||
57 | + APPLET(ed, ed_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||
58 | +#endif | ||
59 | #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS) | ||
60 | APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||
61 | #endif | ||
62 | --- /dev/null 2005-04-22 11:15:01.120978184 -0400 | ||
63 | +++ editors/ed.c 2005-04-22 11:16:00.000000000 -0400 | ||
64 | @@ -0,0 +1,3120 @@ | ||
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 | +/* | ||
87 | + * CREDITS | ||
88 | + * | ||
89 | + * This program is based on the editor algorithm described in | ||
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 | + * | ||
96 | + */ | ||
97 | + | ||
98 | +#include <errno.h> | ||
99 | +#include <limits.h> | ||
100 | +#include <signal.h> | ||
101 | +#include <stdlib.h> | ||
102 | +#include <stdio.h> | ||
103 | +#include <string.h> | ||
104 | +#include <ctype.h> | ||
105 | +#include <setjmp.h> | ||
106 | +#include <pwd.h> | ||
107 | +#include <unistd.h> | ||
108 | +#include <sys/types.h> | ||
109 | +#include <sys/stat.h> | ||
110 | +#include <sys/file.h> | ||
111 | +#include <sys/ioctl.h> | ||
112 | + | ||
113 | +#include "busybox.h" | ||
114 | +#include "ed.h" | ||
115 | +#include "getopt.h" | ||
116 | + | ||
117 | +jmp_buf env; | ||
118 | + | ||
119 | +/* static buffers */ | ||
120 | +char *errmsg; /* error message buffer */ | ||
121 | +char stdinbuf[1]; /* stdin buffer */ | ||
122 | +char *shcmd; /* shell command buffer */ | ||
123 | +int shcmdsz; /* shell command buffer size */ | ||
124 | +int shcmdi; /* shell command buffer index */ | ||
125 | +char *ibuf; /* ed command-line buffer */ | ||
126 | +int ibufsz; /* ed command-line buffer size */ | ||
127 | +char *ibufp; /* pointer to ed command-line buffer */ | ||
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 | +{ | ||
161 | + {"help", no_argument, &show_help, 1}, | ||
162 | + {"prompt", required_argument, NULL, 'p'}, | ||
163 | + {"quiet", no_argument, NULL, 's'}, | ||
164 | + {"silent", no_argument, NULL, 's'}, | ||
165 | + {"traditional", no_argument, NULL, 'G'}, | ||
166 | + {"version", no_argument, &show_version, 1}, | ||
167 | + {0, 0, 0, 0}, | ||
168 | +}; | ||
169 | + | ||
170 | +extern int optind; | ||
171 | +extern char *optarg; | ||
172 | + | ||
173 | +/* usage: explain usage */ | ||
174 | + | ||
175 | +#if 0 | ||
176 | +void | ||
177 | +usage (status) | ||
178 | + int status; | ||
179 | +{ | ||
180 | + if (status != 0) | ||
181 | + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); | ||
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 | + | ||
203 | +/* ed: line editor */ | ||
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 | + { | ||
291 | + status = ERR; | ||
292 | + continue; | ||
293 | + } | ||
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 | + { | ||
302 | + fprintf (stderr, garrulous ? | ||
303 | + "script, line %d: %s\n" : | ||
304 | + "", lineno, errmsg); | ||
305 | + quit (2); | ||
306 | + } | ||
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 | + | ||
370 | +long first_addr, second_addr, addr_cnt; | ||
371 | + | ||
372 | +/* extract_addr_range: get line addresses from the command buffer until an | ||
373 | + illegal address is seen; return status */ | ||
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 | + | ||
396 | + | ||
397 | +#define SKIP_BLANKS() \ | ||
398 | + while (isspace (*ibufp) && *ibufp != '\n') \ | ||
399 | + ibufp++ | ||
400 | + | ||
401 | +#define MUST_BE_FIRST() \ | ||
402 | + do \ | ||
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 | +} | ||
500 | + | ||
501 | + | ||
502 | +/* GET_THIRD_ADDR: get a legal address from the command buffer */ | ||
503 | +#define GET_THIRD_ADDR(addr) \ | ||
504 | + do \ | ||
505 | + { \ | ||
506 | + long ol1, ol2; \ | ||
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 | +{ | ||
571 | + extern long u_current_addr; | ||
572 | + extern long u_addr_last; | ||
573 | + | ||
574 | + static pattern_t *pat = NULL; | ||
575 | + static int sgflag = 0; | ||
576 | + static int sgnum = 0; | ||
577 | + | ||
578 | + pattern_t *tpat; | ||
579 | + char *fnp; | ||
580 | + int gflag = 0; | ||
581 | + int sflags = 0; | ||
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 | + { | ||
837 | + switch (*ibufp) | ||
838 | + { | ||
839 | + case '\n': | ||
840 | + sflags |= SGF; | ||
841 | + break; | ||
842 | + case 'g': | ||
843 | + sflags |= SGG; | ||
844 | + ibufp++; | ||
845 | + break; | ||
846 | + case 'p': | ||
847 | + sflags |= SGP; | ||
848 | + ibufp++; | ||
849 | + break; | ||
850 | + case 'r': | ||
851 | + sflags |= SGR; | ||
852 | + ibufp++; | ||
853 | + break; | ||
854 | + case '0': | ||
855 | + case '1': | ||
856 | + case '2': | ||
857 | + case '3': | ||
858 | + case '4': | ||
859 | + case '5': | ||
860 | + case '6': | ||
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 | + } | ||
871 | + default: | ||
872 | + if (sflags) | ||
873 | + { | ||
874 | + sprintf (errmsg, "Invalid command suffix"); | ||
875 | + return ERR; | ||
876 | + } | ||
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 | + | ||
1068 | + | ||
1069 | +/* check_addr_range: return status of address range check */ | ||
1070 | +int | ||
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 | + | ||
1088 | + | ||
1089 | +/* get_matching_node_addr: return the address of the next line matching a | ||
1090 | + pattern in a given direction. wrap around begin/end of editor buffer if | ||
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 | + | ||
1121 | + | ||
1122 | +/* get_filename: return pointer to copy of filename in the command buffer */ | ||
1123 | +char * | ||
1124 | +get_filename () | ||
1125 | +{ | ||
1126 | + static char *file = NULL; | ||
1127 | + static int filesz = 0; | ||
1128 | + | ||
1129 | + int n; | ||
1130 | + | ||
1131 | + if (*ibufp != '\n') | ||
1132 | + { | ||
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 | + | ||
1168 | + | ||
1169 | +/* get_shell_command: read a shell command from stdin; return substitution | ||
1170 | + status */ | ||
1171 | +int | ||
1172 | +get_shell_command () | ||
1173 | +{ | ||
1174 | + static char *buf = NULL; | ||
1175 | + static int n = 0; | ||
1176 | + | ||
1177 | + char *s; /* substitution char pointer */ | ||
1178 | + int i = 0; | ||
1179 | + int j = 0; | ||
1180 | + | ||
1181 | + if (red) | ||
1182 | + { | ||
1183 | + sprintf (errmsg, "Shell access restricted"); | ||
1184 | + return ERR; | ||
1185 | + } | ||
1186 | + else if ((s = ibufp = get_extended_line (&j, 1)) == NULL) | ||
1187 | + return ERR; | ||
1188 | + REALLOC (buf, n, j + 1, ERR); | ||
1189 | + buf[i++] = '!'; /* prefix command w/ bang */ | ||
1190 | + while (*ibufp != '\n') | ||
1191 | + switch (*ibufp) | ||
1192 | + { | ||
1193 | + default: | ||
1194 | + REALLOC (buf, n, i + 2, ERR); | ||
1195 | + buf[i++] = *ibufp; | ||
1196 | + if (*ibufp++ == '\\') | ||
1197 | + buf[i++] = *ibufp++; | ||
1198 | + break; | ||
1199 | + case '!': | ||
1200 | + if (s != ibufp) | ||
1201 | + { | ||
1202 | + REALLOC (buf, n, i + 1, ERR); | ||
1203 | + buf[i++] = *ibufp++; | ||
1204 | + } | ||
1205 | + else if (shcmd == NULL || (traditional && *(shcmd + 1) == '\0')) | ||
1206 | + { | ||
1207 | + sprintf (errmsg, "No previous command"); | ||
1208 | + return ERR; | ||
1209 | + } | ||
1210 | + else | ||
1211 | + { | ||
1212 | + REALLOC (buf, n, i + shcmdi, ERR); | ||
1213 | + for (s = shcmd + 1; s < shcmd + shcmdi;) | ||
1214 | + buf[i++] = *s++; | ||
1215 | + s = ibufp++; | ||
1216 | + } | ||
1217 | + break; | ||
1218 | + case '%': | ||
1219 | + if (*old_filename == '\0') | ||
1220 | + { | ||
1221 | + sprintf (errmsg, "No current filename"); | ||
1222 | + return ERR; | ||
1223 | + } | ||
1224 | + j = strlen (s = strip_escapes (old_filename)); | ||
1225 | + REALLOC (buf, n, i + j, ERR); | ||
1226 | + while (j--) | ||
1227 | + buf[i++] = *s++; | ||
1228 | + s = ibufp++; | ||
1229 | + break; | ||
1230 | + } | ||
1231 | + REALLOC (shcmd, shcmdsz, i + 1, ERR); | ||
1232 | + memcpy (shcmd, buf, i); | ||
1233 | + shcmd[shcmdi = i] = '\0'; | ||
1234 | + return *s == '!' || *s == '%'; | ||
1235 | +} | ||
1236 | + | ||
1237 | + | ||
1238 | +/* append_lines: insert text from stdin to after line n; stop when either a | ||
1239 | + single period is read or EOF; return status */ | ||
1240 | +int | ||
1241 | +append_lines (n) | ||
1242 | + long n; | ||
1243 | +{ | ||
1244 | + int l; | ||
1245 | + char *lp = ibuf; | ||
1246 | + char *eot; | ||
1247 | + undo_t *up = NULL; | ||
1248 | + | ||
1249 | + for (current_addr = n;;) | ||
1250 | + { | ||
1251 | + if (!isglobal) | ||
1252 | + { | ||
1253 | + if ((l = get_tty_line ()) < 0) | ||
1254 | + return ERR; | ||
1255 | + else if (l == 0 || ibuf[l - 1] != '\n') | ||
1256 | + { | ||
1257 | + clearerr (stdin); | ||
1258 | + return l ? EOF : 0; | ||
1259 | + } | ||
1260 | + lp = ibuf; | ||
1261 | + } | ||
1262 | + else if (*(lp = ibufp) == '\0') | ||
1263 | + return 0; | ||
1264 | + else | ||
1265 | + { | ||
1266 | + while (*ibufp++ != '\n') | ||
1267 | + ; | ||
1268 | + l = ibufp - lp; | ||
1269 | + } | ||
1270 | + if (l == 2 && lp[0] == '.' && lp[1] == '\n') | ||
1271 | + { | ||
1272 | + return 0; | ||
1273 | + } | ||
1274 | + eot = lp + l; | ||
1275 | + SPL1 (); | ||
1276 | + do | ||
1277 | + { | ||
1278 | + if ((lp = put_sbuf_line (lp)) == NULL) | ||
1279 | + { | ||
1280 | + SPL0 (); | ||
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 | + } | ||
1292 | + while (lp != eot); | ||
1293 | + modified = 1; | ||
1294 | + SPL0 (); | ||
1295 | + } | ||
1296 | + /* NOTREACHED */ | ||
1297 | +} | ||
1298 | + | ||
1299 | + | ||
1300 | +/* join_lines: replace a range of lines with the joined text of those lines */ | ||
1301 | +int | ||
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 | + | ||
1340 | + | ||
1341 | +/* move_lines: move a range of lines */ | ||
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 | + { | ||
1369 | + b1 = get_addressed_line_node (p); | ||
1370 | + b2 = get_addressed_line_node (addr); | ||
1371 | + /* this get_addressed_line_node last! */ | ||
1372 | + } | ||
1373 | + else | ||
1374 | + { | ||
1375 | + b2 = get_addressed_line_node (addr); | ||
1376 | + b1 = get_addressed_line_node (p); | ||
1377 | + /* this get_addressed_line_node last! */ | ||
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 | + | ||
1393 | + | ||
1394 | +/* copy_lines: copy a range of lines; return status */ | ||
1395 | +int | ||
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 | + | ||
1434 | + | ||
1435 | +/* delete_lines: delete a range of lines */ | ||
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 | + | ||
1463 | + | ||
1464 | +int dlcnt = 0; /* # of lines displayed */ | ||
1465 | + | ||
1466 | +/* display_lines: print a range of lines to stdout */ | ||
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 | + { | ||
1493 | + dlcnt = 0; | ||
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 | + | ||
1503 | + | ||
1504 | +line_t yank_buffer_head; /* head of yank buffer */ | ||
1505 | + | ||
1506 | +/* yank_lines: copy a range of lines to the cut buffer */ | ||
1507 | +int | ||
1508 | +yank_lines (from, to) | ||
1509 | + long from; | ||
1510 | + long to; | ||
1511 | +{ | ||
1512 | + line_t *bp, *cp, *ep, *lp; | ||
1513 | + | ||
1514 | + | ||
1515 | + delete_yank_lines (); | ||
1516 | + ep = get_addressed_line_node (INC_MOD (to, addr_last)); | ||
1517 | + bp = get_addressed_line_node (from); | ||
1518 | + for (lp = &yank_buffer_head; bp != ep; bp = bp->q_forw, lp = cp) | ||
1519 | + { | ||
1520 | + SPL1 (); | ||
1521 | + if ((cp = dup_line_node (bp)) == NULL) | ||
1522 | + { | ||
1523 | + SPL0 (); | ||
1524 | + return ERR; | ||
1525 | + } | ||
1526 | + INSQUE (cp, lp); | ||
1527 | + SPL0 (); | ||
1528 | + } | ||
1529 | + return 0; | ||
1530 | +} | ||
1531 | + | ||
1532 | + | ||
1533 | +/* delete_yank_lines: delete lines from the yank buffer */ | ||
1534 | +void | ||
1535 | +delete_yank_lines () | ||
1536 | +{ | ||
1537 | + line_t *cp, *lp; | ||
1538 | + | ||
1539 | + | ||
1540 | + for (lp = yank_buffer_head.q_forw; lp != &yank_buffer_head; lp = cp) | ||
1541 | + { | ||
1542 | + SPL1 (); | ||
1543 | + cp = lp->q_forw; | ||
1544 | + REQUE (lp->q_back, lp->q_forw); | ||
1545 | + free (lp); | ||
1546 | + SPL0 (); | ||
1547 | + } | ||
1548 | +} | ||
1549 | + | ||
1550 | + | ||
1551 | +/* put_lines: append lines from the yank buffer */ | ||
1552 | +int | ||
1553 | +put_lines (addr) | ||
1554 | + long addr; | ||
1555 | +{ | ||
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 | + | ||
1588 | + | ||
1589 | +#define MAXMARK 26 /* max number of marks */ | ||
1590 | + | ||
1591 | +line_t *mark[MAXMARK]; /* line markers */ | ||
1592 | +int markno; /* line marker count */ | ||
1593 | + | ||
1594 | +/* mark_line_node: set a line node mark */ | ||
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 | + | ||
1611 | + | ||
1612 | +/* get_marked_node_addr: return address of a marked line */ | ||
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 | + | ||
1625 | + | ||
1626 | +/* unmark_line_node: clear line node mark */ | ||
1627 | +void | ||
1628 | +unmark_line_node (lp) | ||
1629 | + line_t *lp; | ||
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 | + | ||
1641 | + | ||
1642 | +/* dup_line_node: return a pointer to a copy of a line node */ | ||
1643 | +line_t * | ||
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 | + | ||
1660 | + | ||
1661 | +/* has_trailing_escape: return the parity of escapes preceding a character | ||
1662 | + in a string */ | ||
1663 | +int | ||
1664 | +has_trailing_escape (s, t) | ||
1665 | + char *s; | ||
1666 | + char *t; | ||
1667 | +{ | ||
1668 | + return (s == t || *(t - 1) != '\\') ? 0 : !has_trailing_escape (s, t - 1); | ||
1669 | +} | ||
1670 | + | ||
1671 | + | ||
1672 | +/* strip_escapes: return copy of escaped string of at most length PATH_MAX */ | ||
1673 | +char * | ||
1674 | +strip_escapes (s) | ||
1675 | + char *s; | ||
1676 | +{ | ||
1677 | + static char *file = NULL; | ||
1678 | + static int filesz = 0; | ||
1679 | + | ||
1680 | + int i = 0; | ||
1681 | + | ||
1682 | + REALLOC (file, filesz, PATH_MAX + 1, NULL); | ||
1683 | + /* assert: no trailing escape */ | ||
1684 | + while ((file[i++] = (*s == '\\') ? *++s : *s)) | ||
1685 | + s++; | ||
1686 | + return file; | ||
1687 | +} | ||
1688 | + | ||
1689 | + | ||
1690 | +#ifndef S_ISREG | ||
1691 | +#define S_ISREG(m) ((m & S_IFMT) == S_IFREG) | ||
1692 | +#endif | ||
1693 | + | ||
1694 | +/* is_regular_file: if file descriptor of a regular file, then return true; | ||
1695 | + otherwise return false */ | ||
1696 | +int | ||
1697 | +is_regular_file (fd) | ||
1698 | + int fd; | ||
1699 | +{ | ||
1700 | + struct stat sb; | ||
1701 | + | ||
1702 | + return fstat (fd, &sb) < 0 || S_ISREG (sb.st_mode); | ||
1703 | +} | ||
1704 | + | ||
1705 | + | ||
1706 | +/* is_legal_filename: return a legal filename */ | ||
1707 | +int | ||
1708 | +is_legal_filename (s) | ||
1709 | + char *s; | ||
1710 | +{ | ||
1711 | + if (red && (*s == '!' || !strcmp (s, "..") || strchr (s, '/'))) | ||
1712 | + { | ||
1713 | + sprintf (errmsg, "Shell access restricted"); | ||
1714 | + return 0; | ||
1715 | + } | ||
1716 | + return 1; | ||
1717 | +} | ||
1718 | + | ||
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 | + | ||
1724 | +/* get_sbuf_line: get a line of text from the scratch file; return pointer | ||
1725 | + to the text */ | ||
1726 | +char * | ||
1727 | +get_sbuf_line (lp) | ||
1728 | + line_t *lp; | ||
1729 | +{ | ||
1730 | + static char *sfbuf = NULL; /* buffer */ | ||
1731 | + static int sfbufsz = 0; /* buffer size */ | ||
1732 | + | ||
1733 | + int len, ct; | ||
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 | + { | ||
1744 | + fprintf (stderr, "%s\n", strerror (errno)); | ||
1745 | + sprintf (errmsg, "Cannot seek temp file"); | ||
1746 | + return NULL; | ||
1747 | + } | ||
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 | +} | ||
1761 | + | ||
1762 | + | ||
1763 | +/* put_sbuf_line: write a line of text to the scratch file and add a line node | ||
1764 | + to the editor buffer; return a pointer to the end of the text */ | ||
1765 | +char * | ||
1766 | +put_sbuf_line (cs) | ||
1767 | + char *cs; | ||
1768 | +{ | ||
1769 | + line_t *lp; | ||
1770 | + int len, ct; | ||
1771 | + char *s; | ||
1772 | + | ||
1773 | + if ((lp = (line_t *) malloc (sizeof (line_t))) == NULL) | ||
1774 | + { | ||
1775 | + fprintf (stderr, "%s\n", strerror (errno)); | ||
1776 | + sprintf (errmsg, "Out of memory"); | ||
1777 | + return NULL; | ||
1778 | + } | ||
1779 | + /* assert: cs is '\n' terminated */ | ||
1780 | + for (s = cs; *s != '\n'; s++) | ||
1781 | + ; | ||
1782 | + if (s - cs >= LINECHARS) | ||
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 | + { | ||
1793 | + fprintf (stderr, "%s\n", strerror (errno)); | ||
1794 | + sprintf (errmsg, "Cannot seek temp file"); | ||
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 | + | ||
1815 | + | ||
1816 | +/* add_line_node: add a line node in the editor buffer after the current line */ | ||
1817 | +void | ||
1818 | +add_line_node (lp) | ||
1819 | + line_t *lp; | ||
1820 | +{ | ||
1821 | + line_t *cp; | ||
1822 | + | ||
1823 | + cp = get_addressed_line_node (current_addr); /* this get_addressed_line_node last! */ | ||
1824 | + INSQUE (lp, cp); | ||
1825 | + addr_last++; | ||
1826 | + current_addr++; | ||
1827 | +} | ||
1828 | + | ||
1829 | + | ||
1830 | +/* get_line_node_addr: return line number of pointer */ | ||
1831 | +long | ||
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 | + | ||
1848 | + | ||
1849 | +/* get_addressed_line_node: return pointer to a line node in the editor buffer */ | ||
1850 | +line_t * | ||
1851 | +get_addressed_line_node (n) | ||
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 | + | ||
1881 | + | ||
1882 | +extern int newline_added; | ||
1883 | + | ||
1884 | +/* open_sbuf: open scratch file */ | ||
1885 | +int | ||
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 | + | ||
1904 | + | ||
1905 | +/* close_sbuf: close scratch file */ | ||
1906 | +int | ||
1907 | +close_sbuf () | ||
1908 | +{ | ||
1909 | + if (sfp) | ||
1910 | + { | ||
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 | + | ||
1921 | + return 0; | ||
1922 | +} | ||
1923 | + | ||
1924 | + | ||
1925 | +/* quit: remove_lines scratch file and exit */ | ||
1926 | +void | ||
1927 | +quit (n) | ||
1928 | + int n; | ||
1929 | +{ | ||
1930 | + if (sfp) | ||
1931 | + { | ||
1932 | + fclose (sfp); | ||
1933 | + } | ||
1934 | + exit (n); | ||
1935 | +} | ||
1936 | + | ||
1937 | + | ||
1938 | +extern line_t yank_buffer_head; | ||
1939 | +extern char *old_filename; | ||
1940 | +unsigned char ctab[256]; /* character translation table */ | ||
1941 | + | ||
1942 | +/* init_buffers: open scratch buffer; initialize line queue */ | ||
1943 | +void | ||
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 | + | ||
1973 | +} | ||
1974 | + | ||
1975 | + | ||
1976 | +/* translit_text: translate characters in a string */ | ||
1977 | +char * | ||
1978 | +translit_text (s, len, from, to) | ||
1979 | + char *s; | ||
1980 | + int len; | ||
1981 | + int from; | ||
1982 | + int to; | ||
1983 | +{ | ||
1984 | + static int i = 0; | ||
1985 | + | ||
1986 | + unsigned char *us; | ||
1987 | + | ||
1988 | + ctab[i] = i; /* restore table to initial state */ | ||
1989 | + ctab[i = from] = to; | ||
1990 | + for (us = (unsigned char *) s; len-- > 0; us++) | ||
1991 | + *us = ctab[*us]; | ||
1992 | + return s; | ||
1993 | +} | ||
1994 | + | ||
1995 | + | ||
1996 | +#ifndef SIG_ERR | ||
1997 | +# define SIG_ERR ((void (*)()) -1) | ||
1998 | +#endif /* !SIG_ERR */ | ||
1999 | + | ||
2000 | +void | ||
2001 | +(*reliable_signal (sno, hndlr)) () | ||
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 | + | ||
2020 | + | ||
2021 | +void | ||
2022 | +signal_hup (signo) | ||
2023 | + int signo; | ||
2024 | +{ | ||
2025 | + if (mutex) | ||
2026 | + sigflags |= (1 << (signo - 1)); | ||
2027 | + else | ||
2028 | + handle_hup (signo); | ||
2029 | +} | ||
2030 | + | ||
2031 | + | ||
2032 | +void | ||
2033 | +signal_int (signo) | ||
2034 | + int signo; | ||
2035 | +{ | ||
2036 | + if (mutex) | ||
2037 | + sigflags |= (1 << (signo - 1)); | ||
2038 | + else | ||
2039 | + handle_int (signo); | ||
2040 | +} | ||
2041 | + | ||
2042 | + | ||
2043 | +#ifdef HAVE_SIGSETJMP | ||
2044 | +extern sigjmp_buf env; | ||
2045 | +#else | ||
2046 | +extern jmp_buf env; | ||
2047 | +#endif | ||
2048 | +extern int sigactive; | ||
2049 | + | ||
2050 | +void | ||
2051 | +handle_hup (signo) | ||
2052 | + int signo; | ||
2053 | +{ | ||
2054 | + char *hup = NULL; /* hup filename */ | ||
2055 | + char *s; | ||
2056 | + int n; | ||
2057 | + | ||
2058 | + if (!sigactive) | ||
2059 | + quit (1); | ||
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 | +} | ||
2074 | + | ||
2075 | + | ||
2076 | +void | ||
2077 | +handle_int (signo) | ||
2078 | + int signo; | ||
2079 | +{ | ||
2080 | + if (!sigactive) | ||
2081 | + quit (1); | ||
2082 | + sigflags &= ~(1 << (signo - 1)); | ||
2083 | +#ifdef HAVE_SIGSETJMP | ||
2084 | + siglongjmp (env, -1); | ||
2085 | +#else | ||
2086 | + longjmp (env, -1); | ||
2087 | +#endif | ||
2088 | +} | ||
2089 | + | ||
2090 | + | ||
2091 | +extern long rows; | ||
2092 | +int cols = 72; /* wrap column */ | ||
2093 | + | ||
2094 | +void | ||
2095 | +handle_winch (signo) | ||
2096 | + int signo; | ||
2097 | +{ | ||
2098 | +#ifdef TIOCGWINSZ | ||
2099 | + struct winsize ws; /* window size structure */ | ||
2100 | +#endif | ||
2101 | + | ||
2102 | + sigflags &= ~(1 << (signo - 1)); | ||
2103 | +#ifdef TIOCGWINSZ | ||
2104 | + if (ioctl (0, TIOCGWINSZ, (char *) &ws) >= 0) | ||
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 | + | ||
2114 | +/* read_file: read a named file/pipe into the buffer; return line count */ | ||
2115 | +long | ||
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 | + | ||
2143 | + | ||
2144 | +char *sbuf; /* file i/o buffer */ | ||
2145 | +int sbufsz; /* file i/o buffer size */ | ||
2146 | +int newline_added; /* if set, newline appended to input file */ | ||
2147 | + | ||
2148 | +/* read_stream: read a stream into the editor buffer; return status */ | ||
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 | + { | ||
2169 | + SPL0 (); | ||
2170 | + return ERR; | ||
2171 | + } | ||
2172 | + lp = lp->q_forw; | ||
2173 | + if (up) | ||
2174 | + up->t = lp; | ||
2175 | + else if ((up = push_undo_stack (UADD, current_addr, | ||
2176 | + current_addr)) == NULL) | ||
2177 | + { | ||
2178 | + SPL0 (); | ||
2179 | + return ERR; | ||
2180 | + } | ||
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 | + | ||
2198 | + | ||
2199 | +/* get_stream_line: read a line of text from a stream; return line length */ | ||
2200 | +int | ||
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 | + | ||
2232 | + | ||
2233 | +/* write_file: write a range of lines to a named file/pipe; return line count */ | ||
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 | + | ||
2263 | + | ||
2264 | +/* write_stream: write a range of lines to a stream; return status */ | ||
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 | +} | ||
2289 | + | ||
2290 | + | ||
2291 | +/* put_stream_line: write a line of text to a stream; return status */ | ||
2292 | +int | ||
2293 | +put_stream_line (fp, s, len) | ||
2294 | + FILE *fp; | ||
2295 | + char *s; | ||
2296 | + int len; | ||
2297 | +{ | ||
2298 | + while (len--) | ||
2299 | + if (fputc (*s++, fp) < 0) | ||
2300 | + { | ||
2301 | + fprintf (stderr, "%s\n", strerror (errno)); | ||
2302 | + sprintf (errmsg, "Cannot write file"); | ||
2303 | + return ERR; | ||
2304 | + } | ||
2305 | + return 0; | ||
2306 | +} | ||
2307 | + | ||
2308 | +/* get_extended_line: get an extended line from stdin */ | ||
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 | + { | ||
2339 | + sprintf (errmsg, "Unexpected end-of-file"); | ||
2340 | + return NULL; | ||
2341 | + } | ||
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 | + | ||
2357 | + | ||
2358 | +/* get_tty_line: read a line of text from stdin; return line length */ | ||
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 | + | ||
2411 | + | ||
2412 | + | ||
2413 | +#define ESCAPES "\a\b\f\n\r\t\v\\" | ||
2414 | +#define ESCCHARS "abfnrtv\\" | ||
2415 | + | ||
2416 | +extern long rows; | ||
2417 | +extern int cols; | ||
2418 | +extern int dlcnt; | ||
2419 | + | ||
2420 | +/* put_tty_line: print text to stdout */ | ||
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 | + { | ||
2440 | + fputs ("\\\n", stdout); | ||
2441 | + col = 1; | ||
2442 | + if (!traditional && !scripted && !isglobal && ++dlcnt > rows) | ||
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 | + } | ||
2451 | + if (gflag & GLS) | ||
2452 | + { | ||
2453 | + if (31 < *s && *s < 127 && *s != '\\') | ||
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 | + { | ||
2463 | + putchar ((((unsigned char) *s & 0300) >> 6) + '0'); | ||
2464 | + putchar ((((unsigned char) *s & 070) >> 3) + '0'); | ||
2465 | + putchar (((unsigned char) *s & 07) + '0'); | ||
2466 | + col += 2; | ||
2467 | + } | ||
2468 | + } | ||
2469 | + | ||
2470 | + } | ||
2471 | + else | ||
2472 | + putchar (*s); | ||
2473 | + } | ||
2474 | + if (!traditional && (gflag & GLS)) | ||
2475 | + putchar ('$'); | ||
2476 | + putchar ('\n'); | ||
2477 | + return 0; | ||
2478 | +} | ||
2479 | + | ||
2480 | + | ||
2481 | + | ||
2482 | + | ||
2483 | +char *rhbuf; /* rhs substitution buffer */ | ||
2484 | +int rhbufsz; /* rhs substitution buffer size */ | ||
2485 | +int rhbufi; /* rhs substitution buffer index */ | ||
2486 | + | ||
2487 | +/* extract_subst_tail: extract substitution tail from the command buffer */ | ||
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 | +} | ||
2524 | + | ||
2525 | + | ||
2526 | +/* extract_subst_template: return pointer to copy of substitution template | ||
2527 | + in the command buffer */ | ||
2528 | +char * | ||
2529 | +extract_subst_template () | ||
2530 | +{ | ||
2531 | + int n = 0; | ||
2532 | + int i = 0; | ||
2533 | + char c; | ||
2534 | + char delimiter = *ibufp++; | ||
2535 | + | ||
2536 | + if (*ibufp == '%' && *(ibufp + 1) == delimiter) | ||
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 | + { | ||
2557 | + while ((n = get_tty_line ()) == 0 || | ||
2558 | + (n > 0 && ibuf[n - 1] != '\n')) | ||
2559 | + clearerr (stdin); | ||
2560 | + if (n < 0) | ||
2561 | + return NULL; | ||
2562 | + } | ||
2563 | + } | ||
2564 | + REALLOC (rhbuf, rhbufsz, i + 1, NULL); | ||
2565 | + rhbuf[rhbufi = i] = '\0'; | ||
2566 | + return rhbuf; | ||
2567 | +} | ||
2568 | + | ||
2569 | + | ||
2570 | +char *rbuf; /* substitute_matching_text buffer */ | ||
2571 | +int rbufsz; /* substitute_matching_text buffer size */ | ||
2572 | + | ||
2573 | +/* search_and_replace: for each line in a range, change text matching a pattern | ||
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 | + { | ||
2597 | + up = NULL; | ||
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 | + { | ||
2607 | + SPL0 (); | ||
2608 | + return ERR; | ||
2609 | + } | ||
2610 | + else if (up) | ||
2611 | + up->t = get_addressed_line_node (current_addr); | ||
2612 | + else if ((up = push_undo_stack (UADD, | ||
2613 | + current_addr, current_addr)) == NULL) | ||
2614 | + { | ||
2615 | + SPL0 (); | ||
2616 | + return ERR; | ||
2617 | + } | ||
2618 | + } | ||
2619 | + while (txt != eot); | ||
2620 | + SPL0 (); | ||
2621 | + nsubs++; | ||
2622 | + } | ||
2623 | + } | ||
2624 | + if (nsubs == 0 && !(gflag & GLB)) | ||
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 | +} | ||
2634 | + | ||
2635 | + | ||
2636 | +/* substitute_matching_text: replace text matched by a pattern according to | ||
2637 | + a substitution template; return pointer to the modified text */ | ||
2638 | +int | ||
2639 | +substitute_matching_text (pat, lp, gflag, kth) | ||
2640 | + pattern_t *pat; | ||
2641 | + line_t *lp; | ||
2642 | + int gflag; | ||
2643 | + int kth; | ||
2644 | +{ | ||
2645 | + int off = 0; | ||
2646 | + int changed = 0; | ||
2647 | + int matchno = 0; | ||
2648 | + int i = 0; | ||
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 | + { | ||
2662 | + if (!kth || kth == ++matchno) | ||
2663 | + { | ||
2664 | + changed++; | ||
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 | + } | ||
2686 | + while (*txt && (!changed || ((gflag & GSG) && rm[0].rm_eo)) && | ||
2687 | + !regexec (pat, txt, SE_MAX, rm, REG_NOTBOL)); | ||
2688 | + i = eot - txt; | ||
2689 | + REALLOC (rbuf, rbufsz, off + i + 2, ERR); | ||
2690 | + if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) | ||
2691 | + { | ||
2692 | + sprintf (errmsg, "Infinite substitution loop"); | ||
2693 | + return ERR; | ||
2694 | + } | ||
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 | + | ||
2703 | + | ||
2704 | +/* apply_subst_template: modify text according to a substitution template; | ||
2705 | + return offset to end of modified text */ | ||
2706 | +int | ||
2707 | +apply_subst_template (boln, rm, off, re_nsub) | ||
2708 | + char *boln; | ||
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 | + | ||
2746 | + | ||
2747 | + | ||
2748 | +#define USIZE 100 /* undo stack size */ | ||
2749 | +undo_t *ustack = NULL; /* undo stack */ | ||
2750 | +long usize = 0; /* stack size variable */ | ||
2751 | +long u_p = 0; /* undo stack pointer */ | ||
2752 | + | ||
2753 | +/* push_undo_stack: return pointer to intialized undo node */ | ||
2754 | +undo_t * | ||
2755 | +push_undo_stack (type, from, to) | ||
2756 | + int type; | ||
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 | +} | ||
2787 | + | ||
2788 | + | ||
2789 | +/* USWAP: swap undo nodes */ | ||
2790 | +#define USWAP(x, y) \ | ||
2791 | + do \ | ||
2792 | + { \ | ||
2793 | + undo_t utmp; \ | ||
2794 | + utmp = (x), (x) = (y), (y) = utmp; \ | ||
2795 | + } \ | ||
2796 | + while (0) | ||
2797 | + | ||
2798 | + | ||
2799 | +long u_current_addr = -1; /* if >= 0, undo enabled */ | ||
2800 | +long u_addr_last = -1; /* if >= 0, undo enabled */ | ||
2801 | + | ||
2802 | +/* pop_undo_stack: undo last change to the editor buffer */ | ||
2803 | +int | ||
2804 | +pop_undo_stack () | ||
2805 | +{ | ||
2806 | + long n; | ||
2807 | + long o_current_addr = current_addr; | ||
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 | + { | ||
2823 | + case UADD: | ||
2824 | + REQUE (ustack[n].h->q_back, ustack[n].t->q_forw); | ||
2825 | + break; | ||
2826 | + case UDEL: | ||
2827 | + REQUE (ustack[n].h->q_back, ustack[n].h); | ||
2828 | + REQUE (ustack[n].t, ustack[n].t->q_forw); | ||
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 | + } | ||
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 | + | ||
2854 | + | ||
2855 | +/* clear_undo_stack: clear the undo stack */ | ||
2856 | +void | ||
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 | + | ||
2877 | + | ||
2878 | + | ||
2879 | + | ||
2880 | +/* build_active_list: add line matching a pattern to the global-active list */ | ||
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 | +} | ||
2914 | + | ||
2915 | + | ||
2916 | +/* exec_global: apply command list in the command buffer to the active | ||
2917 | + lines in a range; return command status */ | ||
2918 | +long | ||
2919 | +exec_global (interact, gflag) | ||
2920 | + int interact; | ||
2921 | + int gflag; | ||
2922 | +{ | ||
2923 | + static char *ocmd = NULL; | ||
2924 | + static int ocmdsz = 0; | ||
2925 | + | ||
2926 | + line_t *lp = NULL; | ||
2927 | + int status; | ||
2928 | + int n; | ||
2929 | + char *cmd = NULL; | ||
2930 | + | ||
2931 | + if (!interact) | ||
2932 | + if (traditional && !strcmp (ibufp, "\n")) | ||
2933 | + cmd = "p\n"; /* null cmd-list == `p' */ | ||
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 | + { | ||
2943 | + /* print current_addr; get a command in global syntax */ | ||
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 | + { | ||
2962 | + sprintf (errmsg, "No previous command"); | ||
2963 | + return ERR; | ||
2964 | + } | ||
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 | + | ||
2977 | + } | ||
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 | + | ||
2989 | + | ||
2990 | +line_t **active_list; /* list of lines active in a global command */ | ||
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 | + | ||
2996 | +/* set_active_node: add a line node to the global-active list */ | ||
2997 | +int | ||
2998 | +set_active_node (lp) | ||
2999 | + line_t *lp; | ||
3000 | +{ | ||
3001 | + if (active_last + 1 > active_size) | ||
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 | + { | ||
3019 | + if ((ts = (line_t **) malloc ((ti += MINBUFSZ) * | ||
3020 | + sizeof (line_t **))) == NULL) | ||
3021 | + { | ||
3022 | + fprintf (stderr, "%s\n", strerror (errno)); | ||
3023 | + sprintf (errmsg, "Out of memory"); | ||
3024 | + SPL0 (); | ||
3025 | + return ERR; | ||
3026 | + } | ||
3027 | + } | ||
3028 | + active_size = ti; | ||
3029 | + active_list = ts; | ||
3030 | + SPL0 (); | ||
3031 | + } | ||
3032 | + active_list[active_last++] = lp; | ||
3033 | + return 0; | ||
3034 | +} | ||
3035 | + | ||
3036 | + | ||
3037 | +/* unset_active_nodes: remove a range of lines from the global-active list */ | ||
3038 | +void | ||
3039 | +unset_active_nodes (np, mp) | ||
3040 | + line_t *np, *mp; | ||
3041 | +{ | ||
3042 | + line_t *lp; | ||
3043 | + long i; | ||
3044 | + | ||
3045 | + for (lp = np; lp != mp; lp = lp->q_forw) | ||
3046 | + for (i = 0; i < active_last; i++) | ||
3047 | + if (active_list[active_ndx] == lp) | ||
3048 | + { | ||
3049 | + active_list[active_ndx] = NULL; | ||
3050 | + active_ndx = INC_MOD (active_ndx, active_last - 1); | ||
3051 | + break; | ||
3052 | + } | ||
3053 | + else | ||
3054 | + active_ndx = INC_MOD (active_ndx, active_last - 1); | ||
3055 | +} | ||
3056 | + | ||
3057 | + | ||
3058 | +/* next_active_node: return the next global-active line node */ | ||
3059 | +line_t * | ||
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 | + | ||
3067 | + | ||
3068 | +/* clear_active_list: clear the global-active list */ | ||
3069 | +void | ||
3070 | +clear_active_list () | ||
3071 | +{ | ||
3072 | + SPL1 (); | ||
3073 | + active_size = active_last = active_ptr = active_ndx = 0; | ||
3074 | + if (active_list != NULL) | ||
3075 | + free (active_list); | ||
3076 | + active_list = NULL; | ||
3077 | + SPL0 (); | ||
3078 | +} | ||
3079 | + | ||
3080 | + | ||
3081 | + | ||
3082 | +/* get_compiled_pattern: return pointer to compiled pattern from command | ||
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 | +} | ||
3124 | + | ||
3125 | + | ||
3126 | +/* extract_pattern: copy a pattern string from the command buffer; return | ||
3127 | + pointer to the copy */ | ||
3128 | +char * | ||
3129 | +extract_pattern (delimiter) | ||
3130 | + int delimiter; | ||
3131 | +{ | ||
3132 | + static char *lhbuf = NULL; /* buffer */ | ||
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 | + | ||
3166 | + | ||
3167 | +/* parse_char_class: expand a POSIX character class */ | ||
3168 | +char * | ||
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 | + | ||
3210 | +#include <stdio.h> | ||
3211 | + | ||
3212 | +#define ERR (-2) | ||
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; | ||