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