File: | src/bin/ed/main.c |
Warning: | line 1026, column 8 Value stored to 'lp' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: main.c,v 1.66 2019/06/28 13:34:59 deraadt Exp $ */ |
2 | /* $NetBSD: main.c,v 1.3 1995/03/21 09:04:44 cgd Exp $ */ |
3 | |
4 | /* main.c: This file contains the main control and user-interface routines |
5 | for the ed line editor. */ |
6 | /*- |
7 | * Copyright (c) 1993 Andrew Moore, Talke Studio. |
8 | * All rights reserved. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * CREDITS |
34 | * |
35 | * This program is based on the editor algorithm described in |
36 | * Brian W. Kernighan and P. J. Plauger's book "Software Tools |
37 | * in Pascal," Addison-Wesley, 1981. |
38 | * |
39 | * The buffering algorithm is attributed to Rodney Ruddock of |
40 | * the University of Guelph, Guelph, Ontario. |
41 | * |
42 | */ |
43 | |
44 | #include <sys/ioctl.h> |
45 | #include <sys/stat.h> |
46 | #include <sys/wait.h> |
47 | |
48 | #include <ctype.h> |
49 | #include <err.h> |
50 | #include <errno(*__errno()).h> |
51 | #include <limits.h> |
52 | #include <pwd.h> |
53 | #include <regex.h> |
54 | #include <setjmp.h> |
55 | #include <signal.h> |
56 | #include <stdio.h> |
57 | #include <stdlib.h> |
58 | #include <string.h> |
59 | #include <unistd.h> |
60 | |
61 | #include "ed.h" |
62 | |
63 | void signal_hup(int); |
64 | void signal_int(int); |
65 | void handle_winch(int); |
66 | |
67 | static int next_addr(void); |
68 | static int check_addr_range(int, int); |
69 | static int get_matching_node_addr(regex_t *, int); |
70 | static char *get_filename(int); |
71 | static int get_shell_command(void); |
72 | static int append_lines(int); |
73 | static int join_lines(int, int); |
74 | static int move_lines(int); |
75 | static int copy_lines(int); |
76 | static int mark_line_node(line_t *, int); |
77 | static int get_marked_node_addr(int); |
78 | static line_t *dup_line_node(line_t *); |
79 | |
80 | sigjmp_buf env; |
81 | |
82 | /* static buffers */ |
83 | static char errmsg[PATH_MAX1024 + 40]; /* error message buffer */ |
84 | static char *shcmd; /* shell command buffer */ |
85 | static int shcmdsz; /* shell command buffer size */ |
86 | static int shcmdi; /* shell command buffer index */ |
87 | static char old_filename[PATH_MAX1024]; /* default filename */ |
88 | |
89 | /* global buffers */ |
90 | char *ibuf; /* ed command-line buffer */ |
91 | int ibufsz; /* ed command-line buffer size */ |
92 | char *ibufp; /* pointer to ed command-line buffer */ |
93 | |
94 | /* global flags */ |
95 | int garrulous = 0; /* if set, print all error messages */ |
96 | int isbinary; /* if set, buffer contains ASCII NULs */ |
97 | int isglobal; /* if set, doing a global command */ |
98 | int modified; /* if set, buffer modified since last write */ |
99 | int scripted = 0; /* if set, suppress diagnostics */ |
100 | int interactive = 0; /* if set, we are in interactive mode */ |
101 | |
102 | volatile sig_atomic_t mutex = 0; /* if set, signals set flags */ |
103 | volatile sig_atomic_t sighup = 0; /* if set, sighup received while mutex set */ |
104 | volatile sig_atomic_t sigint = 0; /* if set, sigint received while mutex set */ |
105 | |
106 | /* if set, signal handlers are enabled */ |
107 | volatile sig_atomic_t sigactive = 0; |
108 | |
109 | int current_addr; /* current address in editor buffer */ |
110 | int addr_last; /* last address in editor buffer */ |
111 | int lineno; /* script line number */ |
112 | static char *prompt; /* command-line prompt */ |
113 | static char *dps = "*"; /* default command-line prompt */ |
114 | |
115 | static const char usage[] = "usage: %s [-] [-s] [-p string] [file]\n"; |
116 | |
117 | static char *home; /* home directory */ |
118 | |
119 | void |
120 | seterrmsg(char *s) |
121 | { |
122 | strlcpy(errmsg, s, sizeof(errmsg)); |
123 | } |
124 | |
125 | /* ed: line editor */ |
126 | int |
127 | main(volatile int argc, char ** volatile argv) |
128 | { |
129 | int c, n; |
130 | int status = 0; |
131 | |
132 | if (pledge("stdio rpath wpath cpath proc exec tty", NULL((void *)0)) == -1) |
133 | err(1, "pledge"); |
134 | |
135 | home = getenv("HOME"); |
136 | |
137 | top: |
138 | while ((c = getopt(argc, argv, "p:sx")) != -1) |
139 | switch (c) { |
140 | case 'p': /* set prompt */ |
141 | dps = prompt = optarg; |
142 | break; |
143 | case 's': /* run script */ |
144 | scripted = 1; |
145 | break; |
146 | case 'x': /* use crypt */ |
147 | fprintf(stderr(&__sF[2]), "crypt unavailable\n?\n"); |
148 | break; |
149 | default: |
150 | fprintf(stderr(&__sF[2]), usage, argv[0]); |
151 | exit(1); |
152 | } |
153 | argv += optind; |
154 | argc -= optind; |
155 | if (argc && **argv == '-') { |
156 | scripted = 1; |
157 | if (argc > 1) { |
158 | optind = 1; |
159 | goto top; |
160 | } |
161 | argv++; |
162 | argc--; |
163 | } |
164 | |
165 | if (!(interactive = isatty(0))) { |
166 | struct stat sb; |
167 | |
168 | /* assert: pipes show up as fifo's when fstat'd */ |
169 | if (fstat(STDIN_FILENO0, &sb) || !S_ISFIFO(sb.st_mode)((sb.st_mode & 0170000) == 0010000)) { |
170 | if (lseek(STDIN_FILENO0, 0, SEEK_CUR1)) { |
171 | interactive = 1; |
172 | setvbuf(stdout(&__sF[1]), NULL((void *)0), _IOLBF1, 0); |
173 | } |
174 | } |
175 | } |
176 | |
177 | /* assert: reliable signals! */ |
178 | if (isatty(STDIN_FILENO0)) { |
179 | handle_winch(SIGWINCH28); |
180 | signal(SIGWINCH28, handle_winch); |
181 | } |
182 | signal(SIGHUP1, signal_hup); |
183 | signal(SIGQUIT3, SIG_IGN(void (*)(int))1); |
184 | signal(SIGINT2, signal_int); |
185 | if (sigsetjmp(env, 1)) { |
186 | status = -1; |
187 | fputs("\n?\n", stderr(&__sF[2])); |
188 | seterrmsg("interrupt"); |
189 | } else { |
190 | init_buffers(); |
191 | sigactive = 1; /* enable signal handlers */ |
192 | if (argc && **argv) { |
193 | if (read_file(*argv, 0) < 0 && !interactive) |
194 | quit(2); |
195 | else if (**argv != '!') |
196 | strlcpy(old_filename, *argv, |
197 | sizeof old_filename); |
198 | } else if (argc) { |
199 | fputs("?\n", stderr(&__sF[2])); |
200 | if (**argv == '\0') |
201 | seterrmsg("invalid filename"); |
202 | if (!interactive) |
203 | quit(2); |
204 | } |
205 | } |
206 | for (;;) { |
207 | if (status < 0 && garrulous) |
208 | fprintf(stderr(&__sF[2]), "%s\n", errmsg); |
209 | if (prompt) { |
210 | fputs(prompt, stdout(&__sF[1])); |
211 | fflush(stdout(&__sF[1])); |
212 | } |
213 | if ((n = get_tty_line()) < 0) { |
214 | status = ERR(-2); |
215 | continue; |
216 | } else if (n == 0) { |
217 | if (modified && !scripted) { |
218 | fputs("?\n", stderr(&__sF[2])); |
219 | seterrmsg("warning: file modified"); |
220 | if (!interactive) { |
221 | if (garrulous) |
222 | fprintf(stderr(&__sF[2]), |
223 | "script, line %d: %s\n", |
224 | lineno, errmsg); |
225 | quit(2); |
226 | } |
227 | clearerr(stdin)(!__isthreaded ? ((void)(((&__sF[0]))->_flags &= ~ (0x0040|0x0020))) : (clearerr)((&__sF[0]))); |
228 | modified = 0; |
229 | status = EMOD(-3); |
230 | continue; |
231 | } else |
232 | quit(0); |
233 | } else if (ibuf[n - 1] != '\n') { |
234 | /* discard line */ |
235 | seterrmsg("unexpected end-of-file"); |
236 | clearerr(stdin)(!__isthreaded ? ((void)(((&__sF[0]))->_flags &= ~ (0x0040|0x0020))) : (clearerr)((&__sF[0]))); |
237 | status = ERR(-2); |
238 | continue; |
239 | } |
240 | isglobal = 0; |
241 | if ((status = extract_addr_range()) >= 0 && |
242 | (status = exec_command()) >= 0) |
243 | if (!status || (status && |
244 | (status = display_lines(current_addr, current_addr, |
245 | status)) >= 0)) |
246 | continue; |
247 | switch (status) { |
248 | case EOF(-1): |
249 | quit(0); |
250 | break; |
251 | case EMOD(-3): |
252 | modified = 0; |
253 | fputs("?\n", stderr(&__sF[2])); /* give warning */ |
254 | seterrmsg("warning: file modified"); |
255 | if (!interactive) { |
256 | if (garrulous) |
257 | fprintf(stderr(&__sF[2]), |
258 | "script, line %d: %s\n", |
259 | lineno, errmsg); |
260 | quit(2); |
261 | } |
262 | break; |
263 | case FATAL(-4): |
264 | if (!interactive) { |
265 | if (garrulous) |
266 | fprintf(stderr(&__sF[2]), |
267 | "script, line %d: %s\n", |
268 | lineno, errmsg); |
269 | } else if (garrulous) |
270 | fprintf(stderr(&__sF[2]), "%s\n", errmsg); |
271 | quit(3); |
272 | break; |
273 | default: |
274 | fputs("?\n", stderr(&__sF[2])); |
275 | if (!interactive) { |
276 | if (garrulous) |
277 | fprintf(stderr(&__sF[2]), |
278 | "script, line %d: %s\n", |
279 | lineno, errmsg); |
280 | quit(2); |
281 | } |
282 | break; |
283 | } |
284 | } |
285 | /*NOTREACHED*/ |
286 | } |
287 | |
288 | int first_addr, second_addr, addr_cnt; |
289 | |
290 | /* extract_addr_range: get line addresses from the command buffer until an |
291 | illegal address is seen; return status */ |
292 | int |
293 | extract_addr_range(void) |
294 | { |
295 | int addr; |
296 | |
297 | addr_cnt = 0; |
298 | first_addr = second_addr = current_addr; |
299 | while ((addr = next_addr()) >= 0) { |
300 | addr_cnt++; |
301 | first_addr = second_addr; |
302 | second_addr = addr; |
303 | if (*ibufp != ',' && *ibufp != ';') |
304 | break; |
305 | else if (*ibufp++ == ';') |
306 | current_addr = addr; |
307 | } |
308 | if ((addr_cnt = min(addr_cnt, 2)((addr_cnt) < (2) ? (addr_cnt) : (2))) == 1 || second_addr != addr) |
309 | first_addr = second_addr; |
310 | return (addr == ERR(-2)) ? ERR(-2) : 0; |
311 | } |
312 | |
313 | |
314 | #define SKIP_BLANKS()do { while (isspace((unsigned char)*ibufp) && *ibufp != '\n') ibufp++; } while (0) \ |
315 | do { \ |
316 | while (isspace((unsigned char)*ibufp) && *ibufp != '\n') \ |
317 | ibufp++; \ |
318 | } while (0) |
319 | |
320 | #define MUST_BE_FIRST()do { if (!first) { seterrmsg("invalid address"); return (-2); } } while (0) \ |
321 | do { \ |
322 | if (!first) { \ |
323 | seterrmsg("invalid address"); \ |
324 | return ERR(-2); \ |
325 | } \ |
326 | } while (0) |
327 | |
328 | |
329 | /* next_addr: return the next line address in the command buffer */ |
330 | static int |
331 | next_addr(void) |
332 | { |
333 | char *hd; |
334 | int addr = current_addr; |
335 | int n; |
336 | int first = 1; |
337 | int c; |
338 | |
339 | SKIP_BLANKS()do { while (isspace((unsigned char)*ibufp) && *ibufp != '\n') ibufp++; } while (0); |
340 | for (hd = ibufp;; first = 0) |
341 | switch ((c = (unsigned char)*ibufp)) { |
342 | case '+': |
343 | case '\t': |
344 | case ' ': |
345 | case '-': |
346 | case '^': |
347 | ibufp++; |
348 | SKIP_BLANKS()do { while (isspace((unsigned char)*ibufp) && *ibufp != '\n') ibufp++; } while (0); |
349 | if (isdigit((unsigned char)*ibufp)) { |
350 | STRTOI(n, ibufp){ long l = strtol(ibufp, &ibufp, 10); if (l <= (-2147483647 -1) || l >= 2147483647) { seterrmsg("number out of range" ); n = 0; return (-2); } else n = (int)l; }; |
351 | addr += (c == '-' || c == '^') ? -n : n; |
352 | } else if (!isspace(c)) |
353 | addr += (c == '-' || c == '^') ? -1 : 1; |
354 | break; |
355 | case '0': case '1': case '2': |
356 | case '3': case '4': case '5': |
357 | case '6': case '7': case '8': case '9': |
358 | MUST_BE_FIRST()do { if (!first) { seterrmsg("invalid address"); return (-2); } } while (0); |
359 | STRTOI(addr, ibufp){ long l = strtol(ibufp, &ibufp, 10); if (l <= (-2147483647 -1) || l >= 2147483647) { seterrmsg("number out of range" ); addr = 0; return (-2); } else addr = (int)l; }; |
360 | break; |
361 | case '.': |
362 | case '$': |
363 | MUST_BE_FIRST()do { if (!first) { seterrmsg("invalid address"); return (-2); } } while (0); |
364 | ibufp++; |
365 | addr = (c == '.') ? current_addr : addr_last; |
366 | break; |
367 | case '/': |
368 | case '?': |
369 | MUST_BE_FIRST()do { if (!first) { seterrmsg("invalid address"); return (-2); } } while (0); |
370 | if ((addr = get_matching_node_addr( |
371 | get_compiled_pattern(), c == '/')) < 0) |
372 | return ERR(-2); |
373 | else if (c == *ibufp) |
374 | ibufp++; |
375 | break; |
376 | case '\'': |
377 | MUST_BE_FIRST()do { if (!first) { seterrmsg("invalid address"); return (-2); } } while (0); |
378 | ibufp++; |
379 | if ((addr = get_marked_node_addr((unsigned char)*ibufp++)) < 0) |
380 | return ERR(-2); |
381 | break; |
382 | case '%': |
383 | case ',': |
384 | case ';': |
385 | if (first) { |
386 | ibufp++; |
387 | addr_cnt++; |
388 | second_addr = (c == ';') ? current_addr : 1; |
389 | if ((addr = next_addr()) < 0) |
390 | addr = addr_last; |
391 | break; |
392 | } |
393 | /* FALLTHROUGH */ |
394 | default: |
395 | if (ibufp == hd) |
396 | return EOF(-1); |
397 | else if (addr < 0 || addr_last < addr) { |
398 | seterrmsg("invalid address"); |
399 | return ERR(-2); |
400 | } else |
401 | return addr; |
402 | } |
403 | /* NOTREACHED */ |
404 | } |
405 | |
406 | |
407 | /* GET_THIRD_ADDR: get a legal address from the command buffer */ |
408 | #define GET_THIRD_ADDR(addr)do { int ol1, ol2; ol1 = first_addr; ol2 = second_addr; if (extract_addr_range () < 0) return (-2); else if (addr_cnt == 0) { seterrmsg("destination expected" ); return (-2); } else if (second_addr < 0 || addr_last < second_addr) { seterrmsg("invalid address"); return (-2); } addr = second_addr; first_addr = ol1; second_addr = ol2; } while ( 0) \ |
409 | do { \ |
410 | int ol1, ol2; \ |
411 | \ |
412 | ol1 = first_addr; \ |
413 | ol2 = second_addr; \ |
414 | if (extract_addr_range() < 0) \ |
415 | return ERR(-2); \ |
416 | else if (addr_cnt == 0) { \ |
417 | seterrmsg("destination expected"); \ |
418 | return ERR(-2); \ |
419 | } else if (second_addr < 0 || addr_last < second_addr) { \ |
420 | seterrmsg("invalid address"); \ |
421 | return ERR(-2); \ |
422 | } \ |
423 | addr = second_addr; \ |
424 | first_addr = ol1; \ |
425 | second_addr = ol2; \ |
426 | } while (0) |
427 | |
428 | |
429 | /* GET_COMMAND_SUFFIX: verify the command suffix in the command buffer */ |
430 | #define GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0) \ |
431 | do { \ |
432 | int done = 0; \ |
433 | do { \ |
434 | switch (*ibufp) { \ |
435 | case 'p': \ |
436 | gflag |= GPR002; \ |
437 | ibufp++; \ |
438 | break; \ |
439 | case 'l': \ |
440 | gflag |= GLS004; \ |
441 | ibufp++; \ |
442 | break; \ |
443 | case 'n': \ |
444 | gflag |= GNP010; \ |
445 | ibufp++; \ |
446 | break; \ |
447 | default: \ |
448 | done++; \ |
449 | } \ |
450 | } while (!done); \ |
451 | if (*ibufp++ != '\n') { \ |
452 | seterrmsg("invalid command suffix"); \ |
453 | return ERR(-2); \ |
454 | } \ |
455 | } while (0) |
456 | |
457 | /* sflags */ |
458 | #define SGG001 001 /* complement previous global substitute suffix */ |
459 | #define SGP002 002 /* complement previous print suffix */ |
460 | #define SGR004 004 /* use last regex instead of last pat */ |
461 | #define SGF010 010 /* repeat last substitution */ |
462 | |
463 | int patlock = 0; /* if set, pattern not freed by get_compiled_pattern() */ |
464 | |
465 | volatile sig_atomic_t rows = 22; /* scroll length: ws_row - 2 */ |
466 | volatile sig_atomic_t cols = 72; /* wrap column */ |
467 | |
468 | /* exec_command: execute the next command in command buffer; return print |
469 | request, if any */ |
470 | int |
471 | exec_command(void) |
472 | { |
473 | extern int u_current_addr; |
474 | extern int u_addr_last; |
475 | |
476 | static regex_t *pat = NULL((void *)0); |
477 | static int sgflag = 0; |
478 | static int sgnum = 0; |
479 | |
480 | regex_t *tpat; |
481 | char *fnp; |
482 | int gflag = 0; |
483 | int sflags = 0; |
484 | int addr = 0; |
485 | int n = 0; |
486 | int c; |
487 | |
488 | SKIP_BLANKS()do { while (isspace((unsigned char)*ibufp) && *ibufp != '\n') ibufp++; } while (0); |
489 | switch ((c = (unsigned char)*ibufp++)) { |
490 | case 'a': |
491 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
492 | if (!isglobal) clear_undo_stack(); |
493 | if (append_lines(second_addr) < 0) |
494 | return ERR(-2); |
495 | break; |
496 | case 'c': |
497 | if (check_addr_range(current_addr, current_addr) < 0) |
498 | return ERR(-2); |
499 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
500 | if (!isglobal) clear_undo_stack(); |
501 | if (delete_lines(first_addr, second_addr) < 0 || |
502 | append_lines(current_addr) < 0) |
503 | return ERR(-2); |
504 | break; |
505 | case 'd': |
506 | if (check_addr_range(current_addr, current_addr) < 0) |
507 | return ERR(-2); |
508 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
509 | if (!isglobal) clear_undo_stack(); |
510 | if (delete_lines(first_addr, second_addr) < 0) |
511 | return ERR(-2); |
512 | else if ((addr = INC_MOD(current_addr, addr_last)((current_addr) + 1 > (addr_last) ? 0 : (current_addr) + 1 )) != 0) |
513 | current_addr = addr; |
514 | break; |
515 | case 'e': |
516 | if (modified && !scripted) |
517 | return EMOD(-3); |
518 | /* FALLTHROUGH */ |
519 | case 'E': |
520 | if (addr_cnt > 0) { |
521 | seterrmsg("unexpected address"); |
522 | return ERR(-2); |
523 | } else if (!isspace((unsigned char)*ibufp)) { |
524 | seterrmsg("unexpected command suffix"); |
525 | return ERR(-2); |
526 | } else if ((fnp = get_filename(1)) == NULL((void *)0)) |
527 | return ERR(-2); |
528 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
529 | if (delete_lines(1, addr_last) < 0) |
530 | return ERR(-2); |
531 | clear_undo_stack(); |
532 | if (close_sbuf() < 0) |
533 | return ERR(-2); |
534 | else if (open_sbuf() < 0) |
535 | return FATAL(-4); |
536 | if (read_file(fnp, 0) < 0) |
537 | return ERR(-2); |
538 | clear_undo_stack(); |
539 | modified = 0; |
540 | u_current_addr = u_addr_last = -1; |
541 | break; |
542 | case 'f': |
543 | if (addr_cnt > 0) { |
544 | seterrmsg("unexpected address"); |
545 | return ERR(-2); |
546 | } else if (!isspace((unsigned char)*ibufp)) { |
547 | seterrmsg("unexpected command suffix"); |
548 | return ERR(-2); |
549 | } else if ((fnp = get_filename(1)) == NULL((void *)0)) |
550 | return ERR(-2); |
551 | else if (*fnp == '!') { |
552 | seterrmsg("invalid redirection"); |
553 | return ERR(-2); |
554 | } |
555 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
556 | puts(strip_escapes(fnp)); |
557 | break; |
558 | case 'g': |
559 | case 'v': |
560 | case 'G': |
561 | case 'V': |
562 | if (isglobal) { |
563 | seterrmsg("cannot nest global commands"); |
564 | return ERR(-2); |
565 | } else if (check_addr_range(1, addr_last) < 0) |
566 | return ERR(-2); |
567 | else if (build_active_list(c == 'g' || c == 'G') < 0) |
568 | return ERR(-2); |
569 | else if ((n = (c == 'G' || c == 'V'))) |
570 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
571 | isglobal++; |
572 | if (exec_global(n, gflag) < 0) |
573 | return ERR(-2); |
574 | break; |
575 | case 'h': |
576 | if (addr_cnt > 0) { |
577 | seterrmsg("unexpected address"); |
578 | return ERR(-2); |
579 | } |
580 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
581 | if (*errmsg) fprintf(stderr(&__sF[2]), "%s\n", errmsg); |
582 | break; |
583 | case 'H': |
584 | if (addr_cnt > 0) { |
585 | seterrmsg("unexpected address"); |
586 | return ERR(-2); |
587 | } |
588 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
589 | if ((garrulous = 1 - garrulous) && *errmsg) |
590 | fprintf(stderr(&__sF[2]), "%s\n", errmsg); |
591 | break; |
592 | case 'i': |
593 | if (second_addr == 0) { |
594 | second_addr = 1; |
595 | } |
596 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
597 | if (!isglobal) clear_undo_stack(); |
598 | if (append_lines(second_addr - 1) < 0) |
599 | return ERR(-2); |
600 | break; |
601 | case 'j': |
602 | if (check_addr_range(current_addr, current_addr + 1) < 0) |
603 | return ERR(-2); |
604 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
605 | if (!isglobal) clear_undo_stack(); |
606 | if (first_addr != second_addr && |
607 | join_lines(first_addr, second_addr) < 0) |
608 | return ERR(-2); |
609 | break; |
610 | case 'k': |
611 | c = (unsigned char)*ibufp++; |
612 | if (second_addr == 0) { |
613 | seterrmsg("invalid address"); |
614 | return ERR(-2); |
615 | } |
616 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
617 | if (mark_line_node(get_addressed_line_node(second_addr), c) < 0) |
618 | return ERR(-2); |
619 | break; |
620 | case 'l': |
621 | if (check_addr_range(current_addr, current_addr) < 0) |
622 | return ERR(-2); |
623 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
624 | if (display_lines(first_addr, second_addr, gflag | GLS004) < 0) |
625 | return ERR(-2); |
626 | gflag = 0; |
627 | break; |
628 | case 'm': |
629 | if (check_addr_range(current_addr, current_addr) < 0) |
630 | return ERR(-2); |
631 | GET_THIRD_ADDR(addr)do { int ol1, ol2; ol1 = first_addr; ol2 = second_addr; if (extract_addr_range () < 0) return (-2); else if (addr_cnt == 0) { seterrmsg("destination expected" ); return (-2); } else if (second_addr < 0 || addr_last < second_addr) { seterrmsg("invalid address"); return (-2); } addr = second_addr; first_addr = ol1; second_addr = ol2; } while ( 0); |
632 | if (first_addr <= addr && addr < second_addr) { |
633 | seterrmsg("invalid destination"); |
634 | return ERR(-2); |
635 | } |
636 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
637 | if (!isglobal) clear_undo_stack(); |
638 | if (move_lines(addr) < 0) |
639 | return ERR(-2); |
640 | break; |
641 | case 'n': |
642 | if (check_addr_range(current_addr, current_addr) < 0) |
643 | return ERR(-2); |
644 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
645 | if (display_lines(first_addr, second_addr, gflag | GNP010) < 0) |
646 | return ERR(-2); |
647 | gflag = 0; |
648 | break; |
649 | case 'p': |
650 | if (check_addr_range(current_addr, current_addr) < 0) |
651 | return ERR(-2); |
652 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
653 | if (display_lines(first_addr, second_addr, gflag | GPR002) < 0) |
654 | return ERR(-2); |
655 | gflag = 0; |
656 | break; |
657 | case 'P': |
658 | if (addr_cnt > 0) { |
659 | seterrmsg("unexpected address"); |
660 | return ERR(-2); |
661 | } |
662 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
663 | prompt = prompt ? NULL((void *)0) : optarg ? optarg : dps; |
664 | break; |
665 | case 'q': |
666 | case 'Q': |
667 | if (addr_cnt > 0) { |
668 | seterrmsg("unexpected address"); |
669 | return ERR(-2); |
670 | } |
671 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
672 | gflag = (modified && !scripted && c == 'q') ? EMOD(-3) : EOF(-1); |
673 | break; |
674 | case 'r': |
675 | if (!isspace((unsigned char)*ibufp)) { |
676 | seterrmsg("unexpected command suffix"); |
677 | return ERR(-2); |
678 | } else if (addr_cnt == 0) |
679 | second_addr = addr_last; |
680 | if ((fnp = get_filename(0)) == NULL((void *)0)) |
681 | return ERR(-2); |
682 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
683 | if (!isglobal) clear_undo_stack(); |
684 | if ((addr = read_file(fnp, second_addr)) < 0) |
685 | return ERR(-2); |
686 | else if (addr) |
687 | modified = 1; |
688 | break; |
689 | case 's': |
690 | do { |
691 | switch (*ibufp) { |
692 | case '\n': |
693 | sflags |=SGF010; |
694 | break; |
695 | case 'g': |
696 | sflags |= SGG001; |
697 | ibufp++; |
698 | break; |
699 | case 'p': |
700 | sflags |= SGP002; |
701 | ibufp++; |
702 | break; |
703 | case 'r': |
704 | sflags |= SGR004; |
705 | ibufp++; |
706 | break; |
707 | case '0': case '1': case '2': case '3': case '4': |
708 | case '5': case '6': case '7': case '8': case '9': |
709 | STRTOI(sgnum, ibufp){ long l = strtol(ibufp, &ibufp, 10); if (l <= (-2147483647 -1) || l >= 2147483647) { seterrmsg("number out of range" ); sgnum = 0; return (-2); } else sgnum = (int)l; }; |
710 | sflags |= SGF010; |
711 | sgflag &= ~GSG020; /* override GSG */ |
712 | break; |
713 | default: |
714 | if (sflags) { |
715 | seterrmsg("invalid command suffix"); |
716 | return ERR(-2); |
717 | } |
718 | } |
719 | } while (sflags && *ibufp != '\n'); |
720 | if (sflags && !pat) { |
721 | seterrmsg("no previous substitution"); |
722 | return ERR(-2); |
723 | } else if (sflags & SGG001) |
724 | sgnum = 0; /* override numeric arg */ |
725 | if (*ibufp != '\n' && *(ibufp + 1) == '\n') { |
726 | seterrmsg("invalid pattern delimiter"); |
727 | return ERR(-2); |
728 | } |
729 | tpat = pat; |
730 | SPL1()mutex++; |
731 | if ((!sflags || (sflags & SGR004)) && |
732 | (tpat = get_compiled_pattern()) == NULL((void *)0)) { |
733 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
734 | return ERR(-2); |
735 | } else if (tpat != pat) { |
736 | if (pat) { |
737 | regfree(pat); |
738 | free(pat); |
739 | } |
740 | pat = tpat; |
741 | patlock = 1; /* reserve pattern */ |
742 | } |
743 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
744 | if (!sflags && extract_subst_tail(&sgflag, &sgnum) < 0) |
745 | return ERR(-2); |
746 | else if (isglobal) |
747 | sgflag |= GLB001; |
748 | else |
749 | sgflag &= ~GLB001; |
750 | if (sflags & SGG001) |
751 | sgflag ^= GSG020; |
752 | if (sflags & SGP002) { |
753 | sgflag ^= GPR002; |
754 | sgflag &= ~(GLS004 | GNP010); |
755 | } |
756 | do { |
757 | switch (*ibufp) { |
758 | case 'p': |
759 | sgflag |= GPR002; |
760 | ibufp++; |
761 | break; |
762 | case 'l': |
763 | sgflag |= GLS004; |
764 | ibufp++; |
765 | break; |
766 | case 'n': |
767 | sgflag |= GNP010; |
768 | ibufp++; |
769 | break; |
770 | default: |
771 | n++; |
772 | } |
773 | } while (!n); |
774 | if (check_addr_range(current_addr, current_addr) < 0) |
775 | return ERR(-2); |
776 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
777 | if (!isglobal) clear_undo_stack(); |
778 | if (search_and_replace(pat, sgflag, sgnum) < 0) |
779 | return ERR(-2); |
780 | break; |
781 | case 't': |
782 | if (check_addr_range(current_addr, current_addr) < 0) |
783 | return ERR(-2); |
784 | GET_THIRD_ADDR(addr)do { int ol1, ol2; ol1 = first_addr; ol2 = second_addr; if (extract_addr_range () < 0) return (-2); else if (addr_cnt == 0) { seterrmsg("destination expected" ); return (-2); } else if (second_addr < 0 || addr_last < second_addr) { seterrmsg("invalid address"); return (-2); } addr = second_addr; first_addr = ol1; second_addr = ol2; } while ( 0); |
785 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
786 | if (!isglobal) clear_undo_stack(); |
787 | if (copy_lines(addr) < 0) |
788 | return ERR(-2); |
789 | break; |
790 | case 'u': |
791 | if (addr_cnt > 0) { |
792 | seterrmsg("unexpected address"); |
793 | return ERR(-2); |
794 | } |
795 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
796 | if (pop_undo_stack() < 0) |
797 | return ERR(-2); |
798 | break; |
799 | case 'w': |
800 | case 'W': |
801 | if ((n = *ibufp) == 'q' || n == 'Q') { |
802 | gflag = EOF(-1); |
803 | ibufp++; |
804 | } |
805 | if (!isspace((unsigned char)*ibufp)) { |
806 | seterrmsg("unexpected command suffix"); |
807 | return ERR(-2); |
808 | } else if ((fnp = get_filename(0)) == NULL((void *)0)) |
809 | return ERR(-2); |
810 | if (addr_cnt == 0 && !addr_last) |
811 | first_addr = second_addr = 0; |
812 | else if (check_addr_range(1, addr_last) < 0) |
813 | return ERR(-2); |
814 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
815 | if ((addr = write_file(fnp, (c == 'W') ? "a" : "w", |
816 | first_addr, second_addr)) < 0) |
817 | return ERR(-2); |
818 | else if (addr == addr_last && *fnp != '!') |
819 | modified = 0; |
820 | else if (modified && !scripted && n == 'q') |
821 | gflag = EMOD(-3); |
822 | break; |
823 | case 'x': |
824 | if (addr_cnt > 0) { |
825 | seterrmsg("unexpected address"); |
826 | return ERR(-2); |
827 | } |
828 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
829 | seterrmsg("crypt unavailable"); |
830 | return ERR(-2); |
831 | case 'z': |
832 | first_addr = 1; |
833 | if (check_addr_range(first_addr, current_addr + 1) < 0) |
834 | return ERR(-2); |
835 | else if ('0' < *ibufp && *ibufp <= '9') |
836 | STRTOI(rows, ibufp){ long l = strtol(ibufp, &ibufp, 10); if (l <= (-2147483647 -1) || l >= 2147483647) { seterrmsg("number out of range" ); rows = 0; return (-2); } else rows = (int)l; }; |
837 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
838 | if (display_lines(second_addr, min(addr_last,((addr_last) < (second_addr + rows) ? (addr_last) : (second_addr + rows)) |
839 | second_addr + rows)((addr_last) < (second_addr + rows) ? (addr_last) : (second_addr + rows)), gflag) < 0) |
840 | return ERR(-2); |
841 | gflag = 0; |
842 | break; |
843 | case '=': |
844 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
845 | printf("%d\n", addr_cnt ? second_addr : addr_last); |
846 | break; |
847 | case '!': |
848 | if (addr_cnt > 0) { |
849 | seterrmsg("unexpected address"); |
850 | return ERR(-2); |
851 | } else if ((sflags = get_shell_command()) < 0) |
852 | return ERR(-2); |
853 | GET_COMMAND_SUFFIX()do { int done = 0; do { switch (*ibufp) { case 'p': gflag |= 002 ; ibufp++; break; case 'l': gflag |= 004; ibufp++; break; case 'n': gflag |= 010; ibufp++; break; default: done++; } } while (!done); if (*ibufp++ != '\n') { seterrmsg("invalid command suffix" ); return (-2); } } while (0); |
854 | if (sflags) printf("%s\n", shcmd + 1); |
855 | system(shcmd + 1); |
856 | if (!scripted) printf("!\n"); |
857 | break; |
858 | case '\n': |
859 | first_addr = 1; |
860 | if (check_addr_range(first_addr, current_addr + 1) < 0 |
861 | || display_lines(second_addr, second_addr, 0) < 0) |
862 | return ERR(-2); |
863 | break; |
864 | default: |
865 | seterrmsg("unknown command"); |
866 | return ERR(-2); |
867 | } |
868 | return gflag; |
869 | } |
870 | |
871 | |
872 | /* check_addr_range: return status of address range check */ |
873 | static int |
874 | check_addr_range(int n, int m) |
875 | { |
876 | if (addr_cnt == 0) { |
877 | first_addr = n; |
878 | second_addr = m; |
879 | } |
880 | if (first_addr > second_addr || 1 > first_addr || |
881 | second_addr > addr_last) { |
882 | seterrmsg("invalid address"); |
883 | return ERR(-2); |
884 | } |
885 | return 0; |
886 | } |
887 | |
888 | |
889 | /* get_matching_node_addr: return the address of the next line matching a |
890 | pattern in a given direction. wrap around begin/end of editor buffer if |
891 | necessary */ |
892 | static int |
893 | get_matching_node_addr(regex_t *pat, int dir) |
894 | { |
895 | char *s; |
896 | int n = current_addr; |
897 | line_t *lp; |
898 | |
899 | if (!pat) return ERR(-2); |
900 | do { |
901 | if ((n = dir ? INC_MOD(n, addr_last)((n) + 1 > (addr_last) ? 0 : (n) + 1) : DEC_MOD(n, addr_last)((n) - 1 < 0 ? (addr_last) : (n) - 1))) { |
902 | lp = get_addressed_line_node(n); |
903 | if ((s = get_sbuf_line(lp)) == NULL((void *)0)) |
904 | return ERR(-2); |
905 | if (isbinary) |
906 | NUL_TO_NEWLINE(s, lp->len)translit_text(s, lp->len, '\0', '\n'); |
907 | if (!regexec(pat, s, 0, NULL((void *)0), 0)) |
908 | return n; |
909 | } |
910 | } while (n != current_addr); |
911 | seterrmsg("no match"); |
912 | return ERR(-2); |
913 | } |
914 | |
915 | |
916 | /* get_filename: return pointer to copy of filename in the command buffer */ |
917 | static char * |
918 | get_filename(int save) |
919 | { |
920 | static char filename[PATH_MAX1024]; |
921 | char *p; |
922 | int n; |
923 | |
924 | if (*ibufp != '\n') { |
925 | SKIP_BLANKS()do { while (isspace((unsigned char)*ibufp) && *ibufp != '\n') ibufp++; } while (0); |
926 | if (*ibufp == '\n') { |
927 | seterrmsg("invalid filename"); |
928 | return NULL((void *)0); |
929 | } else if ((ibufp = get_extended_line(&n, 1)) == NULL((void *)0)) |
930 | return NULL((void *)0); |
931 | else if (*ibufp == '!') { |
932 | ibufp++; |
933 | if ((n = get_shell_command()) < 0) |
934 | return NULL((void *)0); |
935 | if (n) printf("%s\n", shcmd + 1); |
936 | return shcmd; |
937 | } else if (n >= PATH_MAX1024 - 1) { |
938 | seterrmsg("filename too long"); |
939 | return NULL((void *)0); |
940 | } |
941 | } else { |
942 | if (*old_filename == '\0') { |
943 | seterrmsg("no current filename"); |
944 | return NULL((void *)0); |
945 | } |
946 | return old_filename; |
947 | } |
948 | |
949 | p = save ? old_filename : *old_filename ? filename : old_filename; |
950 | for (n = 0; *ibufp != '\n';) |
951 | p[n++] = *ibufp++; |
952 | p[n] = '\0'; |
953 | return p; |
954 | } |
955 | |
956 | |
957 | /* get_shell_command: read a shell command from stdin; return substitution |
958 | status */ |
959 | static int |
960 | get_shell_command(void) |
961 | { |
962 | static char *buf = NULL((void *)0); |
963 | static int n = 0; |
964 | |
965 | char *s; /* substitution char pointer */ |
966 | int i = 0; |
967 | int j = 0; |
968 | |
969 | if ((s = ibufp = get_extended_line(&j, 1)) == NULL((void *)0)) |
970 | return ERR(-2); |
971 | REALLOC(buf, n, j + 1, ERR)if ((j + 1) > (n)) { int ti = (n); char *ts; mutex++; if ( (ts = realloc((buf), ti += (((j + 1)) > (512) ? ((j + 1)) : (512)))) == ((void *)0)) { perror(((void *)0)); seterrmsg("out of memory" ); do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); return (-2); } (n) = ti; (buf ) = ts; do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint) handle_int(2); } } while (0); }; |
972 | buf[i++] = '!'; /* prefix command w/ bang */ |
973 | while (*ibufp != '\n') |
974 | switch (*ibufp) { |
975 | default: |
976 | REALLOC(buf, n, i + 2, ERR)if ((i + 2) > (n)) { int ti = (n); char *ts; mutex++; if ( (ts = realloc((buf), ti += (((i + 2)) > (512) ? ((i + 2)) : (512)))) == ((void *)0)) { perror(((void *)0)); seterrmsg("out of memory" ); do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); return (-2); } (n) = ti; (buf ) = ts; do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint) handle_int(2); } } while (0); }; |
977 | buf[i++] = *ibufp; |
978 | if (*ibufp++ == '\\') |
979 | buf[i++] = *ibufp++; |
980 | break; |
981 | case '!': |
982 | if (s != ibufp) { |
983 | REALLOC(buf, n, i + 1, ERR)if ((i + 1) > (n)) { int ti = (n); char *ts; mutex++; if ( (ts = realloc((buf), ti += (((i + 1)) > (512) ? ((i + 1)) : (512)))) == ((void *)0)) { perror(((void *)0)); seterrmsg("out of memory" ); do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); return (-2); } (n) = ti; (buf ) = ts; do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint) handle_int(2); } } while (0); }; |
984 | buf[i++] = *ibufp++; |
985 | } |
986 | else if (shcmd == NULL((void *)0)) |
987 | { |
988 | seterrmsg("no previous command"); |
989 | return ERR(-2); |
990 | } else { |
991 | REALLOC(buf, n, i + shcmdi, ERR)if ((i + shcmdi) > (n)) { int ti = (n); char *ts; mutex++; if ((ts = realloc((buf), ti += (((i + shcmdi)) > (512) ? ( (i + shcmdi)) : (512)))) == ((void *)0)) { perror(((void *)0) ); seterrmsg("out of memory"); do { if (--mutex == 0) { if (sighup ) handle_hup(1); if (sigint) handle_int(2); } } while (0); return (-2); } (n) = ti; (buf) = ts; do { if (--mutex == 0) { if (sighup ) handle_hup(1); if (sigint) handle_int(2); } } while (0); }; |
992 | for (s = shcmd + 1; s < shcmd + shcmdi;) |
993 | buf[i++] = *s++; |
994 | s = ibufp++; |
995 | } |
996 | break; |
997 | case '%': |
998 | if (*old_filename == '\0') { |
999 | seterrmsg("no current filename"); |
1000 | return ERR(-2); |
1001 | } |
1002 | j = strlen(s = strip_escapes(old_filename)); |
1003 | REALLOC(buf, n, i + j, ERR)if ((i + j) > (n)) { int ti = (n); char *ts; mutex++; if ( (ts = realloc((buf), ti += (((i + j)) > (512) ? ((i + j)) : (512)))) == ((void *)0)) { perror(((void *)0)); seterrmsg("out of memory" ); do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); return (-2); } (n) = ti; (buf ) = ts; do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint) handle_int(2); } } while (0); }; |
1004 | while (j--) |
1005 | buf[i++] = *s++; |
1006 | s = ibufp++; |
1007 | break; |
1008 | } |
1009 | if (i == 1) { |
1010 | seterrmsg("no command"); |
1011 | return ERR(-2); |
1012 | } |
1013 | REALLOC(shcmd, shcmdsz, i + 1, ERR)if ((i + 1) > (shcmdsz)) { int ti = (shcmdsz); char *ts; mutex ++; if ((ts = realloc((shcmd), ti += (((i + 1)) > (512) ? ( (i + 1)) : (512)))) == ((void *)0)) { perror(((void *)0)); seterrmsg ("out of memory"); do { if (--mutex == 0) { if (sighup) handle_hup (1); if (sigint) handle_int(2); } } while (0); return (-2); } (shcmdsz) = ti; (shcmd) = ts; do { if (--mutex == 0) { if (sighup ) handle_hup(1); if (sigint) handle_int(2); } } while (0); }; |
1014 | memcpy(shcmd, buf, i); |
1015 | shcmd[shcmdi = i] = '\0'; |
1016 | return *s == '!' || *s == '%'; |
1017 | } |
1018 | |
1019 | |
1020 | /* append_lines: insert text from stdin to after line n; stop when either a |
1021 | single period is read or EOF; return status */ |
1022 | static int |
1023 | append_lines(int n) |
1024 | { |
1025 | int l; |
1026 | char *lp = ibuf; |
Value stored to 'lp' during its initialization is never read | |
1027 | char *eot; |
1028 | undo_t *up = NULL((void *)0); |
1029 | |
1030 | for (current_addr = n;;) { |
1031 | if (!isglobal) { |
1032 | if ((l = get_tty_line()) < 0) |
1033 | return ERR(-2); |
1034 | else if (l == 0 || ibuf[l - 1] != '\n') { |
1035 | clearerr(stdin)(!__isthreaded ? ((void)(((&__sF[0]))->_flags &= ~ (0x0040|0x0020))) : (clearerr)((&__sF[0]))); |
1036 | return l ? EOF(-1) : 0; |
1037 | } |
1038 | lp = ibuf; |
1039 | } else if (*(lp = ibufp) == '\0') |
1040 | return 0; |
1041 | else { |
1042 | while (*ibufp++ != '\n') |
1043 | ; |
1044 | l = ibufp - lp; |
1045 | } |
1046 | if (l == 2 && lp[0] == '.' && lp[1] == '\n') { |
1047 | return 0; |
1048 | } |
1049 | eot = lp + l; |
1050 | SPL1()mutex++; |
1051 | do { |
1052 | if ((lp = put_sbuf_line(lp)) == NULL((void *)0)) { |
1053 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1054 | return ERR(-2); |
1055 | } else if (up) |
1056 | up->t = get_addressed_line_node(current_addr); |
1057 | else if ((up = push_undo_stack(UADD0, current_addr, |
1058 | current_addr)) == NULL((void *)0)) { |
1059 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1060 | return ERR(-2); |
1061 | } |
1062 | } while (lp != eot); |
1063 | modified = 1; |
1064 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1065 | } |
1066 | /* NOTREACHED */ |
1067 | } |
1068 | |
1069 | |
1070 | /* join_lines: replace a range of lines with the joined text of those lines */ |
1071 | static int |
1072 | join_lines(int from, int to) |
1073 | { |
1074 | static char *buf = NULL((void *)0); |
1075 | static int n; |
1076 | |
1077 | char *s; |
1078 | int size = 0; |
1079 | line_t *bp, *ep; |
1080 | |
1081 | ep = get_addressed_line_node(INC_MOD(to, addr_last)((to) + 1 > (addr_last) ? 0 : (to) + 1)); |
1082 | bp = get_addressed_line_node(from); |
1083 | for (; bp != ep; bp = bp->q_forw) { |
1084 | if ((s = get_sbuf_line(bp)) == NULL((void *)0)) |
1085 | return ERR(-2); |
1086 | REALLOC(buf, n, size + bp->len, ERR)if ((size + bp->len) > (n)) { int ti = (n); char *ts; mutex ++; if ((ts = realloc((buf), ti += (((size + bp->len)) > (512) ? ((size + bp->len)) : (512)))) == ((void *)0)) { perror (((void *)0)); seterrmsg("out of memory"); do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint) handle_int(2); } } while (0); return (-2); } (n) = ti; (buf) = ts; do { if (-- mutex == 0) { if (sighup) handle_hup(1); if (sigint) handle_int (2); } } while (0); }; |
1087 | memcpy(buf + size, s, bp->len); |
1088 | size += bp->len; |
1089 | } |
1090 | REALLOC(buf, n, size + 2, ERR)if ((size + 2) > (n)) { int ti = (n); char *ts; mutex++; if ((ts = realloc((buf), ti += (((size + 2)) > (512) ? ((size + 2)) : (512)))) == ((void *)0)) { perror(((void *)0)); seterrmsg ("out of memory"); do { if (--mutex == 0) { if (sighup) handle_hup (1); if (sigint) handle_int(2); } } while (0); return (-2); } (n) = ti; (buf) = ts; do { if (--mutex == 0) { if (sighup) handle_hup (1); if (sigint) handle_int(2); } } while (0); }; |
1091 | memcpy(buf + size, "\n", 2); |
1092 | if (delete_lines(from, to) < 0) |
1093 | return ERR(-2); |
1094 | current_addr = from - 1; |
1095 | SPL1()mutex++; |
1096 | if (put_sbuf_line(buf) == NULL((void *)0) || |
1097 | push_undo_stack(UADD0, current_addr, current_addr) == NULL((void *)0)) { |
1098 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1099 | return ERR(-2); |
1100 | } |
1101 | modified = 1; |
1102 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1103 | return 0; |
1104 | } |
1105 | |
1106 | |
1107 | /* move_lines: move a range of lines */ |
1108 | static int |
1109 | move_lines(int addr) |
1110 | { |
1111 | line_t *b1, *a1, *b2, *a2; |
1112 | int n = INC_MOD(second_addr, addr_last)((second_addr) + 1 > (addr_last) ? 0 : (second_addr) + 1); |
1113 | int p = first_addr - 1; |
1114 | int done = (addr == first_addr - 1 || addr == second_addr); |
1115 | |
1116 | SPL1()mutex++; |
1117 | if (done) { |
1118 | a2 = get_addressed_line_node(n); |
1119 | b2 = get_addressed_line_node(p); |
1120 | current_addr = second_addr; |
1121 | } else if (push_undo_stack(UMOV2, p, n) == NULL((void *)0) || |
1122 | push_undo_stack(UMOV2, addr, INC_MOD(addr, addr_last)((addr) + 1 > (addr_last) ? 0 : (addr) + 1)) == NULL((void *)0)) { |
1123 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1124 | return ERR(-2); |
1125 | } else { |
1126 | a1 = get_addressed_line_node(n); |
1127 | if (addr < first_addr) { |
1128 | b1 = get_addressed_line_node(p); |
1129 | b2 = get_addressed_line_node(addr); |
1130 | /* this get_addressed_line_node last! */ |
1131 | } else { |
1132 | b2 = get_addressed_line_node(addr); |
1133 | b1 = get_addressed_line_node(p); |
1134 | /* this get_addressed_line_node last! */ |
1135 | } |
1136 | a2 = b2->q_forw; |
1137 | REQUE(b2, b1->q_forw)(b2)->q_forw = (b1->q_forw), (b1->q_forw)->q_back = (b2); |
1138 | REQUE(a1->q_back, a2)(a1->q_back)->q_forw = (a2), (a2)->q_back = (a1-> q_back); |
1139 | REQUE(b1, a1)(b1)->q_forw = (a1), (a1)->q_back = (b1); |
1140 | current_addr = addr + ((addr < first_addr) ? |
1141 | second_addr - first_addr + 1 : 0); |
1142 | } |
1143 | if (isglobal) |
1144 | unset_active_nodes(b2->q_forw, a2); |
1145 | modified = 1; |
1146 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1147 | return 0; |
1148 | } |
1149 | |
1150 | |
1151 | /* copy_lines: copy a range of lines; return status */ |
1152 | static int |
1153 | copy_lines(int addr) |
1154 | { |
1155 | line_t *lp, *np = get_addressed_line_node(first_addr); |
1156 | undo_t *up = NULL((void *)0); |
1157 | int n = second_addr - first_addr + 1; |
1158 | int m = 0; |
1159 | |
1160 | current_addr = addr; |
1161 | if (first_addr <= addr && addr < second_addr) { |
1162 | n = addr - first_addr + 1; |
1163 | m = second_addr - addr; |
1164 | } |
1165 | for (; n > 0; n=m, m=0, np = get_addressed_line_node(current_addr + 1)) |
1166 | for (; n-- > 0; np = np->q_forw) { |
1167 | SPL1()mutex++; |
1168 | if ((lp = dup_line_node(np)) == NULL((void *)0)) { |
1169 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1170 | return ERR(-2); |
1171 | } |
1172 | add_line_node(lp); |
1173 | if (up) |
1174 | up->t = lp; |
1175 | else if ((up = push_undo_stack(UADD0, current_addr, |
1176 | current_addr)) == NULL((void *)0)) { |
1177 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1178 | return ERR(-2); |
1179 | } |
1180 | modified = 1; |
1181 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1182 | } |
1183 | return 0; |
1184 | } |
1185 | |
1186 | |
1187 | /* delete_lines: delete a range of lines */ |
1188 | int |
1189 | delete_lines(int from, int to) |
1190 | { |
1191 | line_t *n, *p; |
1192 | |
1193 | SPL1()mutex++; |
1194 | if (push_undo_stack(UDEL1, from, to) == NULL((void *)0)) { |
1195 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1196 | return ERR(-2); |
1197 | } |
1198 | n = get_addressed_line_node(INC_MOD(to, addr_last)((to) + 1 > (addr_last) ? 0 : (to) + 1)); |
1199 | p = get_addressed_line_node(from - 1); |
1200 | /* this get_addressed_line_node last! */ |
1201 | if (isglobal) |
1202 | unset_active_nodes(p->q_forw, n); |
1203 | REQUE(p, n)(p)->q_forw = (n), (n)->q_back = (p); |
1204 | addr_last -= to - from + 1; |
1205 | current_addr = from - 1; |
1206 | modified = 1; |
1207 | SPL0()do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint ) handle_int(2); } } while (0); |
1208 | return 0; |
1209 | } |
1210 | |
1211 | |
1212 | /* display_lines: print a range of lines to stdout */ |
1213 | int |
1214 | display_lines(int from, int to, int gflag) |
1215 | { |
1216 | line_t *bp; |
1217 | line_t *ep; |
1218 | char *s; |
1219 | |
1220 | if (!from) { |
1221 | seterrmsg("invalid address"); |
1222 | return ERR(-2); |
1223 | } |
1224 | ep = get_addressed_line_node(INC_MOD(to, addr_last)((to) + 1 > (addr_last) ? 0 : (to) + 1)); |
1225 | bp = get_addressed_line_node(from); |
1226 | for (; bp != ep; bp = bp->q_forw) { |
1227 | if ((s = get_sbuf_line(bp)) == NULL((void *)0)) |
1228 | return ERR(-2); |
1229 | if (put_tty_line(s, bp->len, current_addr = from++, gflag) < 0) |
1230 | return ERR(-2); |
1231 | } |
1232 | return 0; |
1233 | } |
1234 | |
1235 | |
1236 | #define MAXMARK26 26 /* max number of marks */ |
1237 | |
1238 | static line_t *mark[MAXMARK26]; /* line markers */ |
1239 | static int markno; /* line marker count */ |
1240 | |
1241 | /* mark_line_node: set a line node mark */ |
1242 | static int |
1243 | mark_line_node(line_t *lp, int n) |
1244 | { |
1245 | if (!islower(n)) { |
1246 | seterrmsg("invalid mark character"); |
1247 | return ERR(-2); |
1248 | } else if (mark[n - 'a'] == NULL((void *)0)) |
1249 | markno++; |
1250 | mark[n - 'a'] = lp; |
1251 | return 0; |
1252 | } |
1253 | |
1254 | |
1255 | /* get_marked_node_addr: return address of a marked line */ |
1256 | static int |
1257 | get_marked_node_addr(int n) |
1258 | { |
1259 | if (!islower(n)) { |
1260 | seterrmsg("invalid mark character"); |
1261 | return ERR(-2); |
1262 | } |
1263 | return get_line_node_addr(mark[n - 'a']); |
1264 | } |
1265 | |
1266 | |
1267 | /* unmark_line_node: clear line node mark */ |
1268 | void |
1269 | unmark_line_node(line_t *lp) |
1270 | { |
1271 | int i; |
1272 | |
1273 | for (i = 0; markno && i < MAXMARK26; i++) |
1274 | if (mark[i] == lp) { |
1275 | mark[i] = NULL((void *)0); |
1276 | markno--; |
1277 | } |
1278 | } |
1279 | |
1280 | |
1281 | /* dup_line_node: return a pointer to a copy of a line node */ |
1282 | static line_t * |
1283 | dup_line_node(line_t *lp) |
1284 | { |
1285 | line_t *np; |
1286 | |
1287 | if ((np = malloc(sizeof(line_t))) == NULL((void *)0)) { |
1288 | perror(NULL((void *)0)); |
1289 | seterrmsg("out of memory"); |
1290 | return NULL((void *)0); |
1291 | } |
1292 | np->seek = lp->seek; |
1293 | np->len = lp->len; |
1294 | return np; |
1295 | } |
1296 | |
1297 | |
1298 | /* has_trailing_escape: return the parity of escapes preceding a character |
1299 | in a string */ |
1300 | int |
1301 | has_trailing_escape(char *s, char *t) |
1302 | { |
1303 | return (s == t || *(t - 1) != '\\') ? 0 : !has_trailing_escape(s, t - 1); |
1304 | } |
1305 | |
1306 | |
1307 | /* strip_escapes: return copy of escaped string of at most length PATH_MAX */ |
1308 | char * |
1309 | strip_escapes(char *s) |
1310 | { |
1311 | static char *file = NULL((void *)0); |
1312 | static int filesz = 0; |
1313 | |
1314 | int i = 0; |
1315 | |
1316 | REALLOC(file, filesz, PATH_MAX, NULL)if ((1024) > (filesz)) { int ti = (filesz); char *ts; mutex ++; if ((ts = realloc((file), ti += (((1024)) > (512) ? (( 1024)) : (512)))) == ((void *)0)) { perror(((void *)0)); seterrmsg ("out of memory"); do { if (--mutex == 0) { if (sighup) handle_hup (1); if (sigint) handle_int(2); } } while (0); return ((void * )0); } (filesz) = ti; (file) = ts; do { if (--mutex == 0) { if (sighup) handle_hup(1); if (sigint) handle_int(2); } } while (0); }; |
1317 | /* assert: no trailing escape */ |
1318 | while ((file[i++] = (*s == '\\') ? *++s : *s) != '\0' && |
1319 | i < PATH_MAX1024-1) |
1320 | s++; |
1321 | file[PATH_MAX1024-1] = '\0'; |
1322 | return file; |
1323 | } |
1324 | |
1325 | |
1326 | void |
1327 | signal_hup(int signo) |
1328 | { |
1329 | int save_errno = errno(*__errno()); |
1330 | |
1331 | if (mutex) |
1332 | sighup = 1; |
1333 | else |
1334 | handle_hup(signo); |
1335 | errno(*__errno()) = save_errno; |
1336 | } |
1337 | |
1338 | |
1339 | void |
1340 | signal_int(int signo) |
1341 | { |
1342 | int save_errno = errno(*__errno()); |
1343 | |
1344 | if (mutex) |
1345 | sigint = 1; |
1346 | else |
1347 | handle_int(signo); |
1348 | errno(*__errno()) = save_errno; |
1349 | } |
1350 | |
1351 | |
1352 | void |
1353 | handle_hup(int signo) |
1354 | { |
1355 | char hup[PATH_MAX1024]; |
1356 | |
1357 | if (!sigactive) |
1358 | quit(1); /* XXX signal race */ |
1359 | sighup = 0; |
1360 | /* XXX signal race */ |
1361 | if (addr_last && write_file("ed.hup", "w", 1, addr_last) < 0 && |
1362 | home != NULL((void *)0) && home[0] == '/') { |
1363 | if (strlcpy(hup, home, sizeof(hup)) < sizeof(hup) && |
1364 | strlcat(hup, "/ed.hup", sizeof(hup)) < sizeof(hup)) |
1365 | write_file(hup, "w", 1, addr_last); |
1366 | } |
1367 | _exit(2); |
1368 | } |
1369 | |
1370 | |
1371 | void |
1372 | handle_int(int signo) |
1373 | { |
1374 | if (!sigactive) |
1375 | _exit(1); |
1376 | sigint = 0; |
1377 | siglongjmp(env, -1); |
1378 | } |
1379 | |
1380 | |
1381 | void |
1382 | handle_winch(int signo) |
1383 | { |
1384 | int save_errno = errno(*__errno()); |
1385 | struct winsize ws; /* window size structure */ |
1386 | |
1387 | if (ioctl(STDIN_FILENO0, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff ) << 16) | ((('t')) << 8) | ((104))), &ws) == 0) { |
1388 | if (ws.ws_row > 2) |
1389 | rows = ws.ws_row - 2; |
1390 | if (ws.ws_col > 8) |
1391 | cols = ws.ws_col - 8; |
1392 | } |
1393 | errno(*__errno()) = save_errno; |
1394 | } |