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