Commit | Line | Data |
---|---|---|
299f2784 MH |
1 | /* Copyright (c) 1981 Regents of the University of California */ |
2 | static char *sccsid = "@(#)ex_cmds2.c 7.1 %G%"; | |
7df0b7cf MH |
3 | #include "ex.h" |
4 | #include "ex_argv.h" | |
5 | #include "ex_temp.h" | |
6 | #include "ex_tty.h" | |
7 | #include "ex_vis.h" | |
8 | ||
299f2784 MH |
9 | extern bool pflag, nflag; /* mjm: extern; also in ex_cmds.c */ |
10 | extern int poffset; /* mjm: extern; also in ex_cmds.c */ | |
7df0b7cf MH |
11 | |
12 | /* | |
13 | * Subroutines for major command loop. | |
14 | */ | |
15 | ||
16 | /* | |
17 | * Is there a single letter indicating a named buffer next? | |
18 | */ | |
19 | cmdreg() | |
20 | { | |
21 | register int c = 0; | |
22 | register int wh = skipwh(); | |
23 | ||
24 | if (wh && isalpha(peekchar())) | |
25 | c = getchar(); | |
26 | return (c); | |
27 | } | |
28 | ||
29 | /* | |
30 | * Tell whether the character ends a command | |
31 | */ | |
32 | endcmd(ch) | |
33 | int ch; | |
34 | { | |
35 | switch (ch) { | |
36 | ||
37 | case '\n': | |
38 | case EOF: | |
39 | endline = 1; | |
40 | return (1); | |
41 | ||
42 | case '|': | |
d266c416 | 43 | case '"': |
7df0b7cf MH |
44 | endline = 0; |
45 | return (1); | |
46 | } | |
47 | return (0); | |
48 | } | |
49 | ||
50 | /* | |
51 | * Insist on the end of the command. | |
52 | */ | |
53 | eol() | |
54 | { | |
55 | ||
56 | if (!skipend()) | |
57 | error("Extra chars|Extra characters at end of command"); | |
58 | ignnEOF(); | |
59 | } | |
60 | ||
61 | /* | |
62 | * Print out the message in the error message file at str, | |
63 | * with i an integer argument to printf. | |
64 | */ | |
65 | /*VARARGS2*/ | |
66 | error(str, i) | |
67 | #ifdef lint | |
68 | register char *str; | |
69 | #else | |
70 | register int str; | |
71 | #endif | |
72 | int i; | |
73 | { | |
74 | ||
75 | error0(); | |
76 | merror(str, i); | |
04379bab MH |
77 | if (writing) { |
78 | serror(" [Warning - %s is incomplete]", file); | |
79 | writing = 0; | |
80 | } | |
7df0b7cf MH |
81 | error1(str); |
82 | } | |
83 | ||
84 | /* | |
85 | * Rewind the argument list. | |
86 | */ | |
87 | erewind() | |
88 | { | |
89 | ||
90 | argc = argc0; | |
91 | argv = argv0; | |
92 | args = args0; | |
93 | if (argc > 1 && !hush) { | |
94 | printf(mesg("%d files@to edit"), argc); | |
95 | if (inopen) | |
96 | putchar(' '); | |
97 | else | |
98 | putNFL(); | |
99 | } | |
100 | } | |
101 | ||
102 | /* | |
103 | * Guts of the pre-printing error processing. | |
104 | * If in visual and catching errors, then we dont mung up the internals, | |
105 | * just fixing up the echo area for the print. | |
106 | * Otherwise we reset a number of externals, and discard unused input. | |
107 | */ | |
108 | error0() | |
109 | { | |
110 | ||
d266c416 | 111 | if (laste) { |
7c4625ef MH |
112 | #ifdef VMUNIX |
113 | tlaste(); | |
114 | #endif | |
d266c416 MH |
115 | laste = 0; |
116 | sync(); | |
117 | } | |
7df0b7cf MH |
118 | if (vcatch) { |
119 | if (splitw == 0) | |
120 | fixech(); | |
121 | if (!SO || !SE) | |
122 | dingdong(); | |
123 | return; | |
124 | } | |
125 | if (input) { | |
126 | input = strend(input) - 1; | |
127 | if (*input == '\n') | |
128 | setlastchar('\n'); | |
129 | input = 0; | |
130 | } | |
131 | setoutt(); | |
132 | flush(); | |
133 | resetflav(); | |
7df0b7cf MH |
134 | if (!SO || !SE) |
135 | dingdong(); | |
136 | if (inopen) { | |
137 | /* | |
138 | * We are coming out of open/visual ungracefully. | |
139 | * Restore COLUMNS, undo, and fix tty mode. | |
140 | */ | |
141 | COLUMNS = OCOLUMNS; | |
142 | undvis(); | |
143 | ostop(normf); | |
d266c416 | 144 | /* ostop should be doing this |
7df0b7cf MH |
145 | putpad(VE); |
146 | putpad(KE); | |
d266c416 | 147 | */ |
7df0b7cf MH |
148 | putnl(); |
149 | } | |
150 | inopen = 0; | |
151 | holdcm = 0; | |
152 | } | |
153 | ||
154 | /* | |
155 | * Post error printing processing. | |
156 | * Close the i/o file if left open. | |
157 | * If catching in visual then throw to the visual catch, | |
158 | * else if a child after a fork, then exit. | |
159 | * Otherwise, in the normal command mode error case, | |
160 | * finish state reset, and throw to top. | |
161 | */ | |
162 | error1(str) | |
163 | char *str; | |
164 | { | |
165 | bool die; | |
166 | ||
167 | if (io > 0) { | |
168 | close(io); | |
169 | io = -1; | |
170 | } | |
171 | die = (getpid() != ppid); /* Only children die */ | |
d266c416 | 172 | inappend = inglobal = 0; |
887e3e0d | 173 | globp = vglobp = vmacp = 0; |
7df0b7cf | 174 | if (vcatch && !die) { |
7df0b7cf MH |
175 | inopen = 1; |
176 | vcatch = 0; | |
887e3e0d MH |
177 | if (str) |
178 | noonl(); | |
7df0b7cf MH |
179 | fixol(); |
180 | longjmp(vreslab,1); | |
181 | } | |
182 | if (str && !vcatch) | |
183 | putNFL(); | |
184 | if (die) | |
185 | exit(1); | |
186 | lseek(0, 0L, 2); | |
187 | if (inglobal) | |
188 | setlastchar('\n'); | |
7df0b7cf MH |
189 | while (lastchar() != '\n' && lastchar() != EOF) |
190 | ignchar(); | |
191 | ungetchar(0); | |
192 | endline = 1; | |
193 | reset(); | |
194 | } | |
195 | ||
196 | fixol() | |
197 | { | |
198 | if (Outchar != vputchar) { | |
199 | flush(); | |
200 | if (state == ONEOPEN || state == HARDOPEN) | |
201 | outline = destline = 0; | |
202 | Outchar = vputchar; | |
203 | vcontin(1); | |
204 | } else { | |
205 | if (destcol) | |
206 | vclreol(); | |
207 | vclean(); | |
208 | } | |
209 | } | |
210 | ||
211 | /* | |
212 | * Does an ! character follow in the command stream? | |
213 | */ | |
214 | exclam() | |
215 | { | |
216 | ||
217 | if (peekchar() == '!') { | |
218 | ignchar(); | |
219 | return (1); | |
220 | } | |
221 | return (0); | |
222 | } | |
223 | ||
224 | /* | |
225 | * Make an argument list for e.g. next. | |
226 | */ | |
227 | makargs() | |
228 | { | |
229 | ||
230 | glob(&frob); | |
231 | argc0 = frob.argc0; | |
232 | argv0 = frob.argv; | |
233 | args0 = argv0[0]; | |
234 | erewind(); | |
235 | } | |
236 | ||
237 | /* | |
238 | * Advance to next file in argument list. | |
239 | */ | |
240 | next() | |
241 | { | |
d266c416 | 242 | extern short isalt; /* defined in ex_io.c */ |
7df0b7cf MH |
243 | |
244 | if (argc == 0) | |
245 | error("No more files@to edit"); | |
246 | morargc = argc; | |
d266c416 | 247 | isalt = (strcmp(altfile, args)==0) + 1; |
7df0b7cf MH |
248 | if (savedfile[0]) |
249 | CP(altfile, savedfile); | |
250 | CP(savedfile, args); | |
251 | argc--; | |
252 | args = argv ? *++argv : strend(args) + 1; | |
253 | } | |
254 | ||
255 | /* | |
256 | * Eat trailing flags and offsets after a command, | |
257 | * saving for possible later post-command prints. | |
258 | */ | |
259 | newline() | |
260 | { | |
261 | register int c; | |
262 | ||
263 | resetflav(); | |
264 | for (;;) { | |
265 | c = getchar(); | |
266 | switch (c) { | |
267 | ||
268 | case '^': | |
269 | case '-': | |
270 | poffset--; | |
271 | break; | |
272 | ||
273 | case '+': | |
274 | poffset++; | |
275 | break; | |
276 | ||
277 | case 'l': | |
278 | listf++; | |
279 | break; | |
280 | ||
281 | case '#': | |
282 | nflag++; | |
283 | break; | |
284 | ||
285 | case 'p': | |
286 | listf = 0; | |
287 | break; | |
288 | ||
289 | case ' ': | |
290 | case '\t': | |
291 | continue; | |
292 | ||
d266c416 MH |
293 | case '"': |
294 | comment(); | |
295 | setflav(); | |
296 | return; | |
297 | ||
7df0b7cf MH |
298 | default: |
299 | if (!endcmd(c)) | |
300 | serror("Extra chars|Extra characters at end of \"%s\" command", Command); | |
301 | if (c == EOF) | |
302 | ungetchar(c); | |
303 | setflav(); | |
304 | return; | |
305 | } | |
306 | pflag++; | |
307 | } | |
308 | } | |
309 | ||
310 | /* | |
311 | * Before quit or respec of arg list, check that there are | |
312 | * no more files in the arg list. | |
313 | */ | |
314 | nomore() | |
315 | { | |
316 | ||
317 | if (argc == 0 || morargc == argc) | |
318 | return; | |
319 | morargc = argc; | |
320 | merror("%d more file", argc); | |
321 | serror("%s@to edit", plural((long) argc)); | |
322 | } | |
323 | ||
324 | /* | |
325 | * Before edit of new file check that either an ! follows | |
326 | * or the file has not been changed. | |
327 | */ | |
328 | quickly() | |
329 | { | |
330 | ||
331 | if (exclam()) | |
332 | return (1); | |
333 | if (chng && dol > zero) { | |
334 | /* | |
335 | chng = 0; | |
336 | */ | |
337 | xchng = 0; | |
338 | error("No write@since last change (:%s! overrides)", Command); | |
339 | } | |
340 | return (0); | |
341 | } | |
342 | ||
343 | /* | |
344 | * Reset the flavor of the output to print mode with no numbering. | |
345 | */ | |
346 | resetflav() | |
347 | { | |
348 | ||
349 | if (inopen) | |
350 | return; | |
351 | listf = 0; | |
352 | nflag = 0; | |
353 | pflag = 0; | |
354 | poffset = 0; | |
355 | setflav(); | |
356 | } | |
357 | ||
358 | /* | |
359 | * Print an error message with a %s type argument to printf. | |
360 | * Message text comes from error message file. | |
361 | */ | |
362 | serror(str, cp) | |
363 | #ifdef lint | |
364 | register char *str; | |
365 | #else | |
366 | register int str; | |
367 | #endif | |
368 | char *cp; | |
369 | { | |
370 | ||
371 | error0(); | |
372 | smerror(str, cp); | |
373 | error1(str); | |
374 | } | |
375 | ||
376 | /* | |
377 | * Set the flavor of the output based on the flags given | |
378 | * and the number and list options to either number or not number lines | |
379 | * and either use normally decoded (ARPAnet standard) characters or list mode, | |
380 | * where end of lines are marked and tabs print as ^I. | |
381 | */ | |
382 | setflav() | |
383 | { | |
384 | ||
385 | if (inopen) | |
386 | return; | |
387 | setnumb(nflag || value(NUMBER)); | |
388 | setlist(listf || value(LIST)); | |
389 | setoutt(); | |
390 | } | |
391 | ||
392 | /* | |
393 | * Skip white space and tell whether command ends then. | |
394 | */ | |
395 | skipend() | |
396 | { | |
397 | ||
398 | pastwh(); | |
d266c416 | 399 | return (endcmd(peekchar()) && peekchar() != '"'); |
7df0b7cf MH |
400 | } |
401 | ||
402 | /* | |
403 | * Set the command name for non-word commands. | |
404 | */ | |
405 | tailspec(c) | |
406 | int c; | |
407 | { | |
408 | static char foocmd[2]; | |
409 | ||
410 | foocmd[0] = c; | |
411 | Command = foocmd; | |
412 | } | |
413 | ||
414 | /* | |
415 | * Try to read off the rest of the command word. | |
416 | * If alphabetics follow, then this is not the command we seek. | |
417 | */ | |
418 | tail(comm) | |
419 | char *comm; | |
420 | { | |
421 | ||
422 | tailprim(comm, 1, 0); | |
423 | } | |
424 | ||
425 | tail2of(comm) | |
426 | char *comm; | |
427 | { | |
428 | ||
429 | tailprim(comm, 2, 0); | |
430 | } | |
431 | ||
432 | char tcommand[20]; | |
433 | ||
434 | tailprim(comm, i, notinvis) | |
435 | register char *comm; | |
436 | int i; | |
437 | bool notinvis; | |
438 | { | |
439 | register char *cp; | |
440 | register int c; | |
441 | ||
442 | Command = comm; | |
443 | for (cp = tcommand; i > 0; i--) | |
444 | *cp++ = *comm++; | |
445 | while (*comm && peekchar() == *comm) | |
446 | *cp++ = getchar(), comm++; | |
447 | c = peekchar(); | |
448 | if (notinvis || isalpha(c)) { | |
449 | /* | |
450 | * Of the trailing lp funny business, only dl and dp | |
451 | * survive the move from ed to ex. | |
452 | */ | |
453 | if (tcommand[0] == 'd' && any(c, "lp")) | |
454 | goto ret; | |
455 | if (tcommand[0] == 's' && any(c, "gcr")) | |
456 | goto ret; | |
457 | while (cp < &tcommand[19] && isalpha(peekchar())) | |
458 | *cp++ = getchar(); | |
459 | *cp = 0; | |
460 | if (notinvis) | |
461 | serror("What?|%s: No such command from open/visual", tcommand); | |
462 | else | |
463 | serror("What?|%s: Not an editor command", tcommand); | |
464 | } | |
465 | ret: | |
466 | *cp = 0; | |
467 | } | |
468 | ||
469 | /* | |
887e3e0d | 470 | * Continue after a : command from open/visual. |
7df0b7cf MH |
471 | */ |
472 | vcontin(ask) | |
473 | bool ask; | |
474 | { | |
475 | ||
476 | if (vcnt > 0) | |
477 | vcnt = -vcnt; | |
478 | if (inopen) { | |
479 | if (state != VISUAL) { | |
887e3e0d MH |
480 | /* |
481 | * We don't know what a shell command may have left on | |
482 | * the screen, so we move the cursor to the right place | |
483 | * and then put out a newline. But this makes an extra | |
484 | * blank line most of the time so we only do it for :sh | |
485 | * since the prompt gets left on the screen. | |
486 | * | |
487 | * BUG: :!echo longer than current line \\c | |
488 | * will screw it up, but be reasonable! | |
489 | */ | |
490 | if (state == CRTOPEN) { | |
491 | termreset(); | |
492 | vgoto(WECHO, 0); | |
493 | } | |
494 | if (!ask) { | |
495 | putch('\r'); | |
496 | putch('\n'); | |
497 | } | |
7df0b7cf MH |
498 | return; |
499 | } | |
500 | if (ask) { | |
501 | merror("[Hit return to continue] "); | |
502 | flush(); | |
503 | } | |
504 | #ifndef CBREAK | |
505 | vraw(); | |
506 | #endif | |
507 | if (ask) { | |
887e3e0d | 508 | #ifdef EATQS |
7df0b7cf MH |
509 | /* |
510 | * Gobble ^Q/^S since the tty driver should be eating | |
511 | * them (as far as the user can see) | |
512 | */ | |
513 | while (peekkey() == CTRL(Q) || peekkey() == CTRL(S)) | |
514 | ignore(getkey()); | |
887e3e0d MH |
515 | #endif |
516 | if(getkey() == ':') { | |
517 | /* Ugh. Extra newlines, but no other way */ | |
518 | putch('\n'); | |
519 | outline = WECHO; | |
7df0b7cf | 520 | ungetkey(':'); |
887e3e0d MH |
521 | } |
522 | } | |
523 | vclrech(1); | |
d266c416 | 524 | if (Peekkey != ':') { |
887e3e0d | 525 | putpad(TI); |
d266c416 MH |
526 | tostart(); |
527 | /* replaced by ostart. | |
887e3e0d MH |
528 | putpad(VS); |
529 | putpad(KS); | |
d266c416 | 530 | */ |
7df0b7cf | 531 | } |
7df0b7cf MH |
532 | } |
533 | } | |
534 | ||
535 | /* | |
536 | * Put out a newline (before a shell escape) | |
537 | * if in open/visual. | |
538 | */ | |
539 | vnfl() | |
540 | { | |
541 | ||
542 | if (inopen) { | |
543 | if (state != VISUAL && state != CRTOPEN && destline <= WECHO) | |
544 | vclean(); | |
545 | else | |
546 | vmoveitup(1, 0); | |
547 | vgoto(WECHO, 0); | |
548 | vclrbyte(vtube[WECHO], WCOLS); | |
d266c416 MH |
549 | tostop(); |
550 | /* replaced by the ostop above | |
7df0b7cf MH |
551 | putpad(VE); |
552 | putpad(KE); | |
d266c416 | 553 | */ |
7df0b7cf MH |
554 | } |
555 | flush(); | |
556 | } |