Subversion Repositories planix.SVN

Rev

Rev 108 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
105 7u83 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
#if	!defined(lint) && defined(DOSCCS)
8
static char *sccsid = "@(#)ex_cmds.c	7.10.1 (2.11BSD) 1996/11/19";
9
#endif
10
 
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
 
17
bool	pflag, nflag;
18
int	poffset;
19
const char *versionstring =
20
	"@(#) Version 3.7, 6/7/85. Changes by Gunnar Ritter 31/05/00." + 5;
21
 
22
#define	nochng()	lchng = chng
23
 
24
/*
25
 * Main loop for command mode command decoding.
26
 * A few commands are executed here, but main function
27
 * is to strip command addresses, do a little address oriented
28
 * processing and call command routines to do the real work.
29
 */
30
commands(noprompt, exitoneof)
31
	bool noprompt, exitoneof;
32
{
33
	register line *addr;
34
	register int c;
35
	register int lchng;
36
	int given;
37
	int seensemi;
38
	int cnt;
39
	bool hadpr;
40
 
41
	resetflav();
42
	nochng();
43
	for (;;) {
44
		/*
45
		 * If dot at last command
46
		 * ended up at zero, advance to one if there is a such.
47
		 */
48
		if (dot <= zero) {
49
			dot = zero;
50
			if (dol > zero)
51
				dot = one;
52
		}
53
		shudclob = 0;
54
 
55
		/*
56
		 * If autoprint or trailing print flags,
57
		 * print the line at the specified offset
58
		 * before the next command.
59
		 */
60
		if (pflag ||
61
		    lchng != chng && value(AUTOPRINT) && !inglobal && !inopen && endline) {
62
			pflag = 0;
63
			nochng();
64
			if (dol != zero) {
65
				addr1 = addr2 = dot + poffset;
66
				if (addr1 < one || addr1 > dol)
67
error("Offset out-of-bounds|Offset after command too large");
68
				setdot1();
69
				goto print;
70
			}
71
		}
72
		nochng();
73
 
74
		/*
75
		 * Print prompt if appropriate.
76
		 * If not in global flush output first to prevent
77
		 * going into pfast mode unreasonably.
78
		 */
79
		if (inglobal == 0) {
80
			flush();
81
			if (!hush && value(PROMPT) && !globp && !noprompt && endline) {
82
				putchar(':');
83
				hadpr = 1;
84
			}
85
			TSYNC();
86
		}
87
 
88
		/*
89
		 * Gobble up the address.
90
		 * Degenerate addresses yield ".".
91
		 */
92
		addr2 = 0;
93
		given = seensemi = 0;
94
		do {
95
			addr1 = addr2;
96
			addr = address(0);
97
			c = getcd();
98
			if (addr == 0)
99
				if (c == ',')
100
					addr = dot;
101
				else if (addr1 != 0) {
102
					addr2 = dot;
103
					break;
104
				} else
105
					break;
106
			addr2 = addr;
107
			given++;
108
			if (c == ';') {
109
				c = ',';
110
				dot = addr;
111
				seensemi = 1;
112
			}
113
		} while (c == ',');
114
		if (c == '%') {
115
			/* %: same as 1,$ */
116
			addr1 = one;
117
			addr2 = dol;
118
			given = 2;
119
			c = getchar();
120
		}
121
		if (addr1 == 0)
122
			addr1 = addr2;
123
		if (c == ':')
124
			c = getchar();
125
 
126
		/*
127
		 * Set command name for special character commands.
128
		 */
129
		tailspec(c);
130
 
131
		/*
132
		 * If called via : escape from open or visual, limit
133
		 * the set of available commands here to save work below.
134
		 */
135
		if (inopen) {
136
			if (c=='\n' || c=='\r' || c==CTRL('d') || c==EOF) {
137
				if (addr2)
138
					dot = addr2;
139
				if (c == EOF)
140
					return;
141
				continue;
142
			}
143
			if (any(c, "o"))
144
notinvis:
145
				tailprim(Command, 1, 1);
146
		}
147
choice:
148
		switch (c) {
149
 
150
		case 'a':
151
 
152
			switch(peekchar()) {
153
			case 'b':
154
/* abbreviate */
155
				tail("abbreviate");
156
				setnoaddr();
157
				mapcmd(0, 1);
158
				anyabbrs = 1;
159
				continue;
160
			case 'r':
161
/* args */
162
				tail("args");
163
				setnoaddr();
164
				eol();
165
				pargs();
166
				continue;
167
			}
168
 
169
/* append */
170
			if (inopen)
171
				goto notinvis;
172
			tail("append");
173
			setdot();
174
			aiflag = exclam();
175
			newline();
176
			vmacchng(0);
177
			deletenone();
178
			setin(addr2);
179
			inappend = 1;
180
			ignore(append(gettty, addr2));
181
			inappend = 0;
182
			nochng();
183
			continue;
184
 
185
		case 'c':
186
			switch (peekchar()) {
187
 
188
/* copy */
189
			case 'o':
190
				tail("copy");
191
				vmacchng(0);
192
				move();
193
				continue;
194
 
195
#ifdef CHDIR
196
/* cd */
197
			case 'd':
198
				tail("cd");
199
				goto changdir;
200
 
201
/* chdir */
202
			case 'h':
203
				ignchar();
204
				if (peekchar() == 'd') {
205
					register char *p;
206
					tail2of("chdir");
207
changdir:
208
					if (savedfile[0] == '/' || !value(WARN))
209
						ignore(exclam());
210
					else
211
						ignore(quickly());
212
					if (skipend()) {
213
						p = getenv("HOME");
214
						if (p == NULL)
215
							error("Home directory unknown");
216
					} else
217
						getone(), p = file;
218
					eol();
219
					if (chdir(p) < 0)
220
						filioerr(p);
221
					if (savedfile[0] != '/')
222
						edited = 0;
223
					continue;
224
				}
225
				if (inopen)
226
					tailprim("change", 2, 1);
227
				tail2of("change");
228
				break;
229
 
230
#endif
231
			default:
232
				if (inopen)
233
					goto notinvis;
234
				tail("change");
235
				break;
236
			}
237
/* change */
238
			aiflag = exclam();
239
			setCNL();
240
			vmacchng(0);
241
			setin(addr1);
242
			delete(0);
243
			inappend = 1;
244
			ignore(append(gettty, addr1 - 1));
245
			inappend = 0;
246
			nochng();
247
			continue;
248
 
249
/* delete */
250
		case 'd':
251
			/*
252
			 * Caution: dp and dl have special meaning already.
253
			 */
254
			tail("delete");
255
			c = cmdreg();
256
			setCNL();
257
			vmacchng(0);
258
			if (c)
259
				YANKreg(c);
260
			delete(0);
261
			appendnone();
262
			continue;
263
 
264
/* edit */
265
/* ex */
266
		case 'e':
267
			tail(peekchar() == 'x' ? "ex" : "edit");
268
editcmd:
269
			if (!exclam() && chng)
270
				c = 'E';
271
			filename(c);
272
			if (c == 'E') {
273
				ungetchar(lastchar());
274
				ignore(quickly());
275
			}
276
			setnoaddr();
277
doecmd:
278
			init();
279
			addr2 = zero;
280
			laste++;
281
			sync();
282
			rop(c);
283
#ifdef VMUNIX
284
			tlaste();
285
#endif
286
			laste = 0;
287
			sync();
288
			nochng();
289
			continue;
290
 
291
/* file */
292
		case 'f':
293
			tail("file");
294
			setnoaddr();
295
			filename(c);
296
			noonl();
297
/*
298
			synctmp();
299
*/
300
			continue;
301
 
302
/* global */
303
		case 'g':
304
			tail("global");
305
			global(!exclam());
306
			nochng();
307
			continue;
308
 
309
/* insert */
310
		case 'i':
311
			if (inopen)
312
				goto notinvis;
313
			tail("insert");
314
			setdot();
315
			nonzero();
316
			aiflag = exclam();
317
			newline();
318
			vmacchng(0);
319
			deletenone();
320
			setin(addr2);
321
			inappend = 1;
322
			ignore(append(gettty, addr2 - 1));
323
			inappend = 0;
324
			if (dot == zero && dol > zero)
325
				dot = one;
326
			nochng();
327
			continue;
328
 
329
/* join */
330
		case 'j':
331
			tail("join");
332
			c = exclam();
333
			setcount();
334
			nonzero();
335
			newline();
336
			vmacchng(0);
337
			if (given < 2 && addr2 != dol)
338
				addr2++;
339
			join(c);
340
			continue;
341
 
342
/* k */
343
		case 'k':
344
casek:
345
			pastwh();
346
			c = getchar();
347
			if (endcmd(c))
348
				serror("Mark what?|%s requires following letter", Command);
349
			newline();
350
			if (!islower(c))
351
				error("Bad mark|Mark must specify a letter");
352
			setdot();
353
			nonzero();
354
			names[c - 'a'] = *addr2 &~ 01;
355
			anymarks = 1;
356
			continue;
357
 
358
/* list */
359
		case 'l':
360
			tail("list");
361
			setCNL();
362
			ignorf(setlist(1));
363
			pflag = 0;
364
			goto print;
365
 
366
		case 'm':
367
			if (peekchar() == 'a') {
368
				ignchar();
369
				if (peekchar() == 'p') {
370
/* map */
371
					tail2of("map");
372
					setnoaddr();
373
					mapcmd(0, 0);
374
					continue;
375
				}
376
/* mark */
377
				tail2of("mark");
378
				goto casek;
379
			}
380
/* move */
381
			tail("move");
382
			vmacchng(0);
383
			move();
384
			continue;
385
 
386
		case 'n':
387
			if (peekchar() == 'u') {
388
				tail("number");
389
				goto numberit;
390
			}
391
/* next */
392
			tail("next");
393
			setnoaddr();
394
			ckaw();
395
			ignore(quickly());
396
			if (getargs())
397
				makargs();
398
			next();
399
			c = 'e';
400
			filename(c);
401
			goto doecmd;
402
 
403
/* open */
404
		case 'o':
405
			tail("open");
406
			oop();
407
			pflag = 0;
408
			nochng();
409
			continue;
410
 
411
		case 'p':
412
		case 'P':
413
			switch (peekchar()) {
414
 
415
/* put */
416
			case 'u':
417
				tail("put");
418
				setdot();
419
				c = cmdreg();
420
				eol();
421
				vmacchng(0);
422
				if (c)
423
					putreg(c);
424
				else
425
					put();
426
				continue;
427
 
428
			case 'r':
429
				ignchar();
430
				if (peekchar() == 'e') {
431
/* preserve */
432
					tail2of("preserve");
433
					eol();
434
					if (preserve() == 0)
435
						error("Preserve failed!");
436
					else
437
						error("File preserved.");
438
				}
439
				tail2of("print");
440
				break;
441
 
442
			default:
443
				tail("print");
444
				break;
445
			}
446
/* print */
447
			setCNL();
448
			pflag = 0;
449
print:
450
			nonzero();
451
			if (CL && span() > LINES) {
452
				flush1();
453
				vclear();
454
			}
455
			plines(addr1, addr2, 1);
456
			continue;
457
 
458
/* quit */
459
		case 'q':
460
			tail("quit");
461
			setnoaddr();
462
			c = quickly();
463
			eol();
464
			if (!c)
465
quit:
466
				nomore();
467
			if (inopen) {
468
				vgoto(WECHO, 0);
469
				if (!ateopr())
470
					vnfl();
471
				else {
472
					tostop();
473
				}
474
				flush();
475
				setty(normf);
476
			}
477
			cleanup(1);
478
			exit(0);
479
 
480
		case 'r':
481
			if (peekchar() == 'e') {
482
				ignchar();
483
				switch (peekchar()) {
484
 
485
/* rewind */
486
				case 'w':
487
					tail2of("rewind");
488
					setnoaddr();
489
					if (!exclam()) {
490
						ckaw();
491
						if (chng && dol > zero)
492
							error("No write@since last change (:rewind! overrides)");
493
					}
494
					eol();
495
					erewind();
496
					next();
497
					c = 'e';
498
					ungetchar(lastchar());
499
					filename(c);
500
					goto doecmd;
501
 
502
/* recover */
503
				case 'c':
504
					tail2of("recover");
505
					setnoaddr();
506
					c = 'e';
507
					if (!exclam() && chng)
508
						c = 'E';
509
					filename(c);
510
					if (c == 'E') {
511
						ungetchar(lastchar());
512
						ignore(quickly());
513
					}
514
					init();
515
					addr2 = zero;
516
					laste++;
517
					sync();
518
					recover();
519
					rop2();
520
					revocer();
521
					if (status == 0)
522
						rop3(c);
523
					if (dol != zero)
524
						change();
525
#ifdef VMUNIX
526
					tlaste();
527
#endif
528
					laste = 0;
529
					nochng();
530
					continue;
531
				}
532
				tail2of("read");
533
			} else
534
				tail("read");
535
/* read */
536
			if (savedfile[0] == 0 && dol == zero)
537
				c = 'e';
538
			pastwh();
539
			vmacchng(0);
540
			if (peekchar() == '!') {
541
				setdot();
542
				ignchar();
543
				unix0(0);
544
				filter(0);
545
				continue;
546
			}
547
			filename(c);
548
			rop(c);
549
			nochng();
550
			if (inopen && endline && addr1 > zero && addr1 < dol)
551
				dot = addr1 + 1;
552
			continue;
553
 
554
		case 's':
555
			switch (peekchar()) {
556
			/*
557
			 * Caution: 2nd char cannot be c, g, or r
558
			 * because these have meaning to substitute.
559
			 */
560
 
561
/* set */
562
			case 'e':
563
				tail("set");
564
				setnoaddr();
565
				set();
566
				continue;
567
 
568
/* shell */
569
			case 'h':
570
				tail("shell");
571
				setNAEOL();
572
				vnfl();
573
				putpad(TE);
574
				flush();
575
				unixwt(1, unixex("-i", (char *) 0, 0, 0));
576
				vcontin(0);
577
				continue;
578
 
579
/* source */
580
			case 'o':
581
#ifdef notdef
582
				if (inopen)
583
					goto notinvis;
584
#endif
585
				tail("source");
586
				setnoaddr();
587
				getone();
588
				eol();
589
				source(file, 0);
590
				continue;
591
#ifdef SIGTSTP
592
/* stop, suspend */
593
			case 't':
594
				tail("stop");
595
				goto suspend;
596
			case 'u':
597
				tail("suspend");
598
suspend:
599
				if (!ldisc)
600
					error("Old tty driver|Not using new tty driver/shell");
601
				c = exclam();
602
				eol();
603
				if (!c)
604
					ckaw();
605
				onsusp();
606
				continue;
607
#endif
608
 
609
			}
610
			/* fall into ... */
611
 
612
/* & */
613
/* ~ */
614
/* substitute */
615
		case '&':
616
		case '~':
617
			Command = "substitute";
618
			if (c == 's')
619
				tail(Command);
620
			vmacchng(0);
621
			if (!substitute(c))
622
				pflag = 0;
623
			continue;
624
 
625
/* t */
626
		case 't':
627
			if (peekchar() == 'a') {
628
				tail("tag");
629
				tagfind(exclam());
630
				if (!inopen)
631
					lchng = chng - 1;
632
				else
633
					nochng();
634
				continue;
635
			}
636
			tail("t");
637
			vmacchng(0);
638
			move();
639
			continue;
640
 
641
		case 'u':
642
			if (peekchar() == 'n') {
643
				ignchar();
644
				switch(peekchar()) {
645
/* unmap */
646
				case 'm':
647
					tail2of("unmap");
648
					setnoaddr();
649
					mapcmd(1, 0);
650
					continue;
651
/* unabbreviate */
652
				case 'a':
653
					tail2of("unabbreviate");
654
					setnoaddr();
655
					mapcmd(1, 1);
656
					anyabbrs = 1;
657
					continue;
658
				}
659
/* undo */
660
				tail2of("undo");
661
			} else
662
				tail("undo");
663
			setnoaddr();
664
			markDOT();
665
			c = exclam();
666
			newline();
667
			undo(c);
668
			continue;
669
 
670
		case 'v':
671
			switch (peekchar()) {
672
 
673
			case 'e':
674
/* version */
675
				tail("version");
676
				setNAEOL();
677
				printf(versionstring);
678
				noonl();
679
				continue;
680
 
681
/* visual */
682
			case 'i':
683
				tail("visual");
684
				if (inopen) {
685
					c = 'e';
686
					goto editcmd;
687
				}
688
				vop();
689
				pflag = 0;
690
				nochng();
691
				continue;
692
			}
693
/* v */
694
			tail("v");
695
			global(0);
696
			nochng();
697
			continue;
698
 
699
/* write */
700
		case 'w':
701
			c = peekchar();
702
			tail(c == 'q' ? "wq" : "write");
703
wq:
704
			if (skipwh() && peekchar() == '!') {
705
				pofix();
706
				ignchar();
707
				setall();
708
				unix0(0);
709
				filter(1);
710
			} else {
711
				setall();
712
				wop(1);
713
				nochng();
714
			}
715
			if (c == 'q')
716
				goto quit;
717
			continue;
718
 
719
/* xit */
720
		case 'x':
721
			tail("xit");
722
			if (!chng)
723
				goto quit;
724
			c = 'q';
725
			goto wq;
726
 
727
/* yank */
728
		case 'y':
729
			tail("yank");
730
			c = cmdreg();
731
			setcount();
732
			eol();
733
			vmacchng(0);
734
			if (c)
735
				YANKreg(c);
736
			else
737
				yank();
738
			continue;
739
 
740
/* z */
741
		case 'z':
742
			zop(0);
743
			pflag = 0;
744
			continue;
745
 
746
/* * */
747
/* @ */
748
		case '*':
749
		case '@':
750
			c = getchar();
751
			if (c=='\n' || c=='\r')
752
				ungetchar(c);
753
			if (any(c, "@*\n\r"))
754
				c = lastmac;
755
			if (isupper(c))
756
				c = tolower(c);
757
			if (!islower(c))
758
				error("Bad register");
759
			newline();
760
			setdot();
761
			cmdmac(c);
762
			continue;
763
 
764
/* | */
765
		case '|':
766
			endline = 0;
767
			goto caseline;
768
 
769
/* \n */
770
		case '\n':
771
			endline = 1;
772
caseline:
773
			notempty();
774
			if (addr2 == 0) {
775
				if (UP != NOSTR && c == '\n' && !inglobal)
776
					c = CTRL('k');
777
				if (inglobal)
778
					addr1 = addr2 = dot;
779
				else {
780
					if (dot == dol)
781
						error("At EOF|At end-of-file");
782
					addr1 = addr2 = dot + 1;
783
				}
784
			}
785
			setdot();
786
			nonzero();
787
			if (seensemi)
788
				addr1 = addr2;
789
			getline(*addr1);
790
			if (c == CTRL('k')) {
791
				flush1();
792
				destline--;
793
				if (hadpr)
794
					shudclob = 1;
795
			}
796
			plines(addr1, addr2, 1);
797
			continue;
798
 
799
/* " */
800
		case '"':
801
			comment();
802
			continue;
803
 
804
/* # */
805
		case '#':
806
numberit:
807
			setCNL();
808
			ignorf(setnumb(1));
809
			pflag = 0;
810
			goto print;
811
 
812
/* = */
813
		case '=':
814
			newline();
815
			setall();
816
			if (inglobal == 2)
817
				pofix();
818
			printf("%d", lineno(addr2));
819
			noonl();
820
			continue;
821
 
822
/* ! */
823
		case '!':
824
			if (addr2 != 0) {
825
				vmacchng(0);
826
				unix0(0);
827
				setdot();
828
				filter(2);
829
			} else {
830
				unix0(1);
831
				pofix();
832
				putpad(TE);
833
				flush();
834
				unixwt(1, unixex("-c", uxb, 0, 0));
835
				vclrech(1);	/* vcontin(0); */
836
				nochng();
837
			}
838
			continue;
839
 
840
/* < */
841
/* > */
842
		case '<':
843
		case '>':
844
			for (cnt = 1; peekchar() == c; cnt++)
845
				ignchar();
846
			setCNL();
847
			vmacchng(0);
848
			shift(c, cnt);
849
			continue;
850
 
851
/* ^D */
852
/* EOF */
853
		case CTRL('d'):
854
		case EOF:
855
			if (exitoneof) {
856
				if (addr2 != 0)
857
					dot = addr2;
858
				return;
859
			}
860
			if (!isatty(0)) {
861
				if (intty)
862
					/*
863
					 * Chtty sys call at UCB may cause a
864
					 * input which was a tty to suddenly be
865
					 * turned into /dev/null.
866
					 */
867
					onhup();
868
				return;
869
			}
870
			if (addr2 != 0) {
871
				setlastchar('\n');
872
				putnl();
873
			}
874
			if (dol == zero) {
875
				if (addr2 == 0)
876
					putnl();
877
				notempty();
878
			}
879
			ungetchar(EOF);
880
			zop(hadpr);
881
			continue;
882
 
883
		default:
884
			if (!isalpha(c))
885
				break;
886
			ungetchar(c);
887
			tailprim("", 0, 0);
888
		}
889
		error("What?|Unknown command character '%c'", c);
890
	}
891
}