Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/planix-v0/sys/src/cmd/ed.c – Rev 2

Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
/*
2
 * Editor
3
 */
4
#include <u.h>
5
#include <libc.h>
6
#include <bio.h>
7
#include <regexp.h>
8
 
9
enum
10
{
11
	FNSIZE	= 128,		/* file name */
12
	LBSIZE	= 4096,		/* max line size */
13
	BLKSIZE	= 4096,		/* block size in temp file */
14
	NBLK	= 8191,		/* max size of temp file */
15
	ESIZE	= 256,		/* max size of reg exp */
16
	GBSIZE	= 256,		/* max size of global command */
17
	MAXSUB	= 9,		/* max number of sub reg exp */
18
	ESCFLG	= Runemax,	/* escape Rune - user defined code */
19
	EOF	= -1,
20
};
21
 
22
void	(*oldhup)(int);
23
void	(*oldquit)(int);
24
int*	addr1;
25
int*	addr2;
26
int	anymarks;
27
Biobuf	bcons;
28
int	col;
29
long	count;
30
int*	dol;
31
int*	dot;
32
int	fchange;
33
char	file[FNSIZE];
34
Rune	genbuf[LBSIZE];
35
int	given;
36
Rune*	globp;
37
int	iblock;
38
int	ichanged;
39
int	io;
40
Biobuf	iobuf;
41
int	lastc;
42
char	line[70];
43
Rune*	linebp;
44
Rune	linebuf[LBSIZE];
45
int	listf;
46
int	listn;
47
Rune*	loc1;
48
Rune*	loc2;
49
int	names[26];
50
int	nleft;
51
int	oblock;
52
int	oflag;
53
Reprog	*pattern;
54
int	peekc;
55
int	pflag;
56
int	rescuing;
57
Rune	rhsbuf[LBSIZE/sizeof(Rune)];
58
char	savedfile[FNSIZE];
59
jmp_buf	savej;
60
int	subnewa;
61
int	subolda;
62
Resub	subexp[MAXSUB];
63
char*	tfname;
64
int	tline;
65
int	waiting;
66
int	wrapp;
67
int*	zero;
68
 
69
char	Q[]	= "";
70
char	T[]	= "TMP";
71
char	WRERR[]	= "WRITE ERROR";
72
int	bpagesize = 20;
73
char	hex[]	= "0123456789abcdef";
74
char*	linp	= line;
75
ulong	nlall = 128;
76
int	tfile	= -1;
77
int	vflag	= 1;
78
 
79
void	add(int);
80
int*	address(void);
81
int	append(int(*)(void), int*);
82
void	browse(void);
83
void	callunix(void);
84
void	commands(void);
85
void	compile(int);
86
int	compsub(void);
87
void	dosub(void);
88
void	error(char*);
89
int	match(int*);
90
void	exfile(int);
91
void	filename(int);
92
Rune*	getblock(int, int);
93
int	getchr(void);
94
int	getcopy(void);
95
int	getfile(void);
96
Rune*	getline(int);
97
int	getnum(void);
98
int	getsub(void);
99
int	gettty(void);
100
void	global(int);
101
void	init(void);
102
void	join(void);
103
void	move(int);
104
void	newline(void);
105
void	nonzero(void);
106
void	notifyf(void*, char*);
107
Rune*	place(Rune*, Rune*, Rune*);
108
void	printcom(void);
109
void	putchr(int);
110
void	putd(void);
111
void	putfile(void);
112
int	putline(void);
113
void	putshst(Rune*);
114
void	putst(char*);
115
void	quit(void);
116
void	rdelete(int*, int*);
117
void	regerror(char *);
118
void	reverse(int*, int*);
119
void	setnoaddr(void);
120
void	setwide(void);
121
void	squeeze(int);
122
void	substitute(int);
123
 
124
void
125
main(int argc, char *argv[])
126
{
127
	char *p1, *p2;
128
 
129
	Binit(&bcons, 0, OREAD);
130
	notify(notifyf);
131
	ARGBEGIN {
132
	case 'o':
133
		oflag = 1;
134
		vflag = 0;
135
		break;
136
	} ARGEND
137
 
138
	USED(argc);
139
	if(*argv && (strcmp(*argv, "-") == 0)) {
140
		argv++;
141
		vflag = 0;
142
	}
143
	if(oflag) {
144
		p1 = "/fd/1";
145
		p2 = savedfile;
146
		while(*p2++ = *p1++)
147
			;
148
		globp = L"a";
149
	} else
150
	if(*argv) {
151
		p1 = *argv;
152
		p2 = savedfile;
153
		while(*p2++ = *p1++)
154
			if(p2 >= &savedfile[sizeof(savedfile)])
155
				p2--;
156
		globp = L"r";
157
	}
158
	zero = malloc((nlall+5)*sizeof(int*));
159
	tfname = mktemp("/tmp/eXXXXX");
160
	init();
161
	setjmp(savej);
162
	commands();
163
	quit();
164
}
165
 
166
void
167
commands(void)
168
{
169
	int *a1, c, temp;
170
	char lastsep;
171
	Dir *d;
172
 
173
	for(;;) {
174
		if(pflag) {
175
			pflag = 0;
176
			addr1 = addr2 = dot;
177
			printcom();
178
		}
179
		c = '\n';
180
		for(addr1 = 0;;) {
181
			lastsep = c;
182
			a1 = address();
183
			c = getchr();
184
			if(c != ',' && c != ';')
185
				break;
186
			if(lastsep == ',')
187
				error(Q);
188
			if(a1 == 0) {
189
				a1 = zero+1;
190
				if(a1 > dol)
191
					a1--;
192
			}
193
			addr1 = a1;
194
			if(c == ';')
195
				dot = a1;
196
		}
197
		if(lastsep != '\n' && a1 == 0)
198
			a1 = dol;
199
		if((addr2=a1) == 0) {
200
			given = 0;
201
			addr2 = dot;	
202
		} else
203
			given = 1;
204
		if(addr1 == 0)
205
			addr1 = addr2;
206
		switch(c) {
207
 
208
		case 'a':
209
			add(0);
210
			continue;
211
 
212
		case 'b':
213
			nonzero();
214
			browse();
215
			continue;
216
 
217
		case 'c':
218
			nonzero();
219
			newline();
220
			rdelete(addr1, addr2);
221
			append(gettty, addr1-1);
222
			continue;
223
 
224
		case 'd':
225
			nonzero();
226
			newline();
227
			rdelete(addr1, addr2);
228
			continue;
229
 
230
		case 'E':
231
			fchange = 0;
232
			c = 'e';
233
		case 'e':
234
			setnoaddr();
235
			if(vflag && fchange) {
236
				fchange = 0;
237
				error(Q);
238
			}
239
			filename(c);
240
			init();
241
			addr2 = zero;
242
			goto caseread;
243
 
244
		case 'f':
245
			setnoaddr();
246
			filename(c);
247
			putst(savedfile);
248
			continue;
249
 
250
		case 'g':
251
			global(1);
252
			continue;
253
 
254
		case 'i':
255
			add(-1);
256
			continue;
257
 
258
 
259
		case 'j':
260
			if(!given)
261
				addr2++;
262
			newline();
263
			join();
264
			continue;
265
 
266
		case 'k':
267
			nonzero();
268
			c = getchr();
269
			if(c < 'a' || c > 'z')
270
				error(Q);
271
			newline();
272
			names[c-'a'] = *addr2 & ~01;
273
			anymarks |= 01;
274
			continue;
275
 
276
		case 'm':
277
			move(0);
278
			continue;
279
 
280
		case 'n':
281
			listn++;
282
			newline();
283
			printcom();
284
			continue;
285
 
286
		case '\n':
287
			if(a1==0) {
288
				a1 = dot+1;
289
				addr2 = a1;
290
				addr1 = a1;
291
			}
292
			if(lastsep==';')
293
				addr1 = a1;
294
			printcom();
295
			continue;
296
 
297
		case 'l':
298
			listf++;
299
		case 'p':
300
		case 'P':
301
			newline();
302
			printcom();
303
			continue;
304
 
305
		case 'Q':
306
			fchange = 0;
307
		case 'q':
308
			setnoaddr();
309
			newline();
310
			quit();
311
 
312
		case 'r':
313
			filename(c);
314
		caseread:
315
			if((io=open(file, OREAD)) < 0) {
316
				lastc = '\n';
317
				error(file);
318
			}
319
			if((d = dirfstat(io)) != nil){
320
				if(d->mode & DMAPPEND)
321
					print("warning: %s is append only\n", file);
322
				free(d);
323
			}
324
			Binit(&iobuf, io, OREAD);
325
			setwide();
326
			squeeze(0);
327
			c = zero != dol;
328
			append(getfile, addr2);
329
			exfile(OREAD);
330
 
331
			fchange = c;
332
			continue;
333
 
334
		case 's':
335
			nonzero();
336
			substitute(globp != 0);
337
			continue;
338
 
339
		case 't':
340
			move(1);
341
			continue;
342
 
343
		case 'u':
344
			nonzero();
345
			newline();
346
			if((*addr2&~01) != subnewa)
347
				error(Q);
348
			*addr2 = subolda;
349
			dot = addr2;
350
			continue;
351
 
352
		case 'v':
353
			global(0);
354
			continue;
355
 
356
		case 'W':
357
			wrapp++;
358
		case 'w':
359
			setwide();
360
			squeeze(dol>zero);
361
			temp = getchr();
362
			if(temp != 'q' && temp != 'Q') {
363
				peekc = temp;
364
				temp = 0;
365
			}
366
			filename(c);
367
			if(!wrapp ||
368
			  ((io = open(file, OWRITE)) == -1) ||
369
			  ((seek(io, 0L, 2)) == -1))
370
				if((io = create(file, OWRITE, 0666)) < 0)
371
					error(file);
372
			Binit(&iobuf, io, OWRITE);
373
			wrapp = 0;
374
			if(dol > zero)
375
				putfile();
376
			exfile(OWRITE);
377
			if(addr1<=zero+1 && addr2==dol)
378
				fchange = 0;
379
			if(temp == 'Q')
380
				fchange = 0;
381
			if(temp)
382
				quit();
383
			continue;
384
 
385
		case '=':
386
			setwide();
387
			squeeze(0);
388
			newline();
389
			count = addr2 - zero;
390
			putd();
391
			putchr(L'\n');
392
			continue;
393
 
394
		case '!':
395
			callunix();
396
			continue;
397
 
398
		case EOF:
399
			return;
400
 
401
		}
402
		error(Q);
403
	}
404
}
405
 
406
void
407
printcom(void)
408
{
409
	int *a1;
410
 
411
	nonzero();
412
	a1 = addr1;
413
	do {
414
		if(listn) {
415
			count = a1-zero;
416
			putd();
417
			putchr(L'\t');
418
		}
419
		putshst(getline(*a1++));
420
	} while(a1 <= addr2);
421
	dot = addr2;
422
	listf = 0;
423
	listn = 0;
424
	pflag = 0;
425
}
426
 
427
int*
428
address(void)
429
{
430
	int sign, *a, opcnt, nextopand, *b, c;
431
 
432
	nextopand = -1;
433
	sign = 1;
434
	opcnt = 0;
435
	a = dot;
436
	do {
437
		do {
438
			c = getchr();
439
		} while(c == ' ' || c == '\t');
440
		if(c >= '0' && c <= '9') {
441
			peekc = c;
442
			if(!opcnt)
443
				a = zero;
444
			a += sign*getnum();
445
		} else
446
		switch(c) {
447
		case '$':
448
			a = dol;
449
		case '.':
450
			if(opcnt)
451
				error(Q);
452
			break;
453
		case '\'':
454
			c = getchr();
455
			if(opcnt || c < 'a' || c > 'z')
456
				error(Q);
457
			a = zero;
458
			do {
459
				a++;
460
			} while(a <= dol && names[c-'a'] != (*a & ~01));
461
			break;
462
		case '?':
463
			sign = -sign;
464
		case '/':
465
			compile(c);
466
			b = a;
467
			for(;;) {
468
				a += sign;
469
				if(a <= zero)
470
					a = dol;
471
				if(a > dol)
472
					a = zero;
473
				if(match(a))
474
					break;
475
				if(a == b)
476
					error(Q);
477
			}
478
			break;
479
		default:
480
			if(nextopand == opcnt) {
481
				a += sign;
482
				if(a < zero || dol < a)
483
					continue;       /* error(Q); */
484
			}
485
			if(c != '+' && c != '-' && c != '^') {
486
				peekc = c;
487
				if(opcnt == 0)
488
					a = 0;
489
				return a;
490
			}
491
			sign = 1;
492
			if(c != '+')
493
				sign = -sign;
494
			nextopand = ++opcnt;
495
			continue;
496
		}
497
		sign = 1;
498
		opcnt++;
499
	} while(zero <= a && a <= dol);
500
	error(Q);
501
	return 0;
502
}
503
 
504
int
505
getnum(void)
506
{
507
	int r, c;
508
 
509
	r = 0;
510
	for(;;) {
511
		c = getchr();
512
		if(c < '0' || c > '9')
513
			break;
514
		r = r*10 + (c-'0');
515
	}
516
	peekc = c;
517
	return r;
518
}
519
 
520
void
521
setwide(void)
522
{
523
	if(!given) {
524
		addr1 = zero + (dol>zero);
525
		addr2 = dol;
526
	}
527
}
528
 
529
void
530
setnoaddr(void)
531
{
532
	if(given)
533
		error(Q);
534
}
535
 
536
void
537
nonzero(void)
538
{
539
	squeeze(1);
540
}
541
 
542
void
543
squeeze(int i)
544
{
545
	if(addr1 < zero+i || addr2 > dol || addr1 > addr2)
546
		error(Q);
547
}
548
 
549
void
550
newline(void)
551
{
552
	int c;
553
 
554
	c = getchr();
555
	if(c == '\n' || c == EOF)
556
		return;
557
	if(c == 'p' || c == 'l' || c == 'n') {
558
		pflag++;
559
		if(c == 'l')
560
			listf++;
561
		else
562
		if(c == 'n')
563
			listn++;
564
		c = getchr();
565
		if(c == '\n')
566
			return;
567
	}
568
	error(Q);
569
}
570
 
571
void
572
filename(int comm)
573
{
574
	char *p1, *p2;
575
	Rune rune;
576
	int c;
577
 
578
	count = 0;
579
	c = getchr();
580
	if(c == '\n' || c == EOF) {
581
		p1 = savedfile;
582
		if(*p1 == 0 && comm != 'f')
583
			error(Q);
584
		p2 = file;
585
		while(*p2++ = *p1++)
586
			;
587
		return;
588
	}
589
	if(c != ' ')
590
		error(Q);
591
	while((c=getchr()) == ' ')
592
		;
593
	if(c == '\n')
594
		error(Q);
595
	p1 = file;
596
	do {
597
		if(p1 >= &file[sizeof(file)-6] || c == ' ' || c == EOF)
598
			error(Q);
599
		rune = c;
600
		p1 += runetochar(p1, &rune);
601
	} while((c=getchr()) != '\n');
602
	*p1 = 0;
603
	if(savedfile[0] == 0 || comm == 'e' || comm == 'f') {
604
		p1 = savedfile;
605
		p2 = file;
606
		while(*p1++ = *p2++)
607
			;
608
	}
609
}
610
 
611
void
612
exfile(int om)
613
{
614
 
615
	if(om == OWRITE)
616
		if(Bflush(&iobuf) < 0)
617
			error(Q);
618
	close(io);
619
	io = -1;
620
	if(vflag) {
621
		putd();
622
		putchr(L'\n');
623
	}
624
}
625
 
626
void
627
error1(char *s)
628
{
629
	int c;
630
 
631
	wrapp = 0;
632
	listf = 0;
633
	listn = 0;
634
	count = 0;
635
	seek(0, 0, 2);
636
	pflag = 0;
637
	if(globp)
638
		lastc = '\n';
639
	globp = 0;
640
	peekc = lastc;
641
	if(lastc)
642
		for(;;) {
643
			c = getchr();
644
			if(c == '\n' || c == EOF)
645
				break;
646
		}
647
	if(io > 0) {
648
		close(io);
649
		io = -1;
650
	}
651
	putchr(L'?');
652
	putst(s);
653
}
654
 
655
void
656
error(char *s)
657
{
658
	error1(s);
659
	longjmp(savej, 1);
660
}
661
 
662
void
663
rescue(void)
664
{
665
	rescuing = 1;
666
	if(dol > zero) {
667
		addr1 = zero+1;
668
		addr2 = dol;
669
		io = create("ed.hup", OWRITE, 0666);
670
		if(io > 0){
671
			Binit(&iobuf, io, OWRITE);
672
			putfile();
673
		}
674
	}
675
	fchange = 0;
676
	quit();
677
}
678
 
679
void
680
notifyf(void *a, char *s)
681
{
682
	if(strcmp(s, "interrupt") == 0){
683
		if(rescuing || waiting)
684
			noted(NCONT);
685
		putchr(L'\n');
686
		lastc = '\n';
687
		error1(Q);
688
		notejmp(a, savej, 0);
689
	}
690
	if(strcmp(s, "hangup") == 0){
691
		if(rescuing)
692
			noted(NDFLT);
693
		rescue();
694
	}
695
	fprint(2, "ed: note: %s\n", s);
696
	abort();
697
}
698
 
699
int
700
getchr(void)
701
{
702
	if(lastc = peekc) {
703
		peekc = 0;
704
		return lastc;
705
	}
706
	if(globp) {
707
		if((lastc=*globp++) != 0)
708
			return lastc;
709
		globp = 0;
710
		return EOF;
711
	}
712
	lastc = Bgetrune(&bcons);
713
	return lastc;
714
}
715
 
716
int
717
gety(void)
718
{
719
	int c;
720
	Rune *gf, *p;
721
 
722
	p = linebuf;
723
	gf = globp;
724
	for(;;) {
725
		c = getchr();
726
		if(c == '\n') {
727
			*p = 0;
728
			return 0;
729
		}
730
		if(c == EOF) {
731
			if(gf)
732
				peekc = c;
733
			return c;
734
		}
735
		if(c == 0)
736
			continue;
737
		*p++ = c;
738
		if(p >= &linebuf[LBSIZE-sizeof(Rune)])
739
			error(Q);
740
	}
741
}
742
 
743
int
744
gettty(void)
745
{
746
	int rc;
747
 
748
	rc = gety();
749
	if(rc)
750
		return rc;
751
	if(linebuf[0] == '.' && linebuf[1] == 0)
752
		return EOF;
753
	return 0;
754
}
755
 
756
int
757
getfile(void)
758
{
759
	int c;
760
	Rune *lp;
761
 
762
	lp = linebuf;
763
	do {
764
		c = Bgetrune(&iobuf);
765
		if(c < 0) {
766
			if(lp > linebuf) {
767
				putst("'\\n' appended");
768
				c = '\n';
769
			} else
770
				return EOF;
771
		}
772
		if(lp >= &linebuf[LBSIZE]) {
773
			lastc = '\n';
774
			error(Q);
775
		}
776
		*lp++ = c;
777
		count++;
778
	} while(c != '\n');
779
	lp[-1] = 0;
780
	return 0;
781
}
782
 
783
void
784
putfile(void)
785
{
786
	int *a1;
787
	Rune *lp;
788
	long c;
789
 
790
	a1 = addr1;
791
	do {
792
		lp = getline(*a1++);
793
		for(;;) {
794
			count++;
795
			c = *lp++;
796
			if(c == 0) {
797
				if(Bputrune(&iobuf, '\n') < 0)
798
					error(Q);
799
				break;
800
			}
801
			if(Bputrune(&iobuf, c) < 0)
802
				error(Q);
803
		}
804
	} while(a1 <= addr2);
805
	if(Bflush(&iobuf) < 0)
806
		error(Q);
807
}
808
 
809
int
810
append(int (*f)(void), int *a)
811
{
812
	int *a1, *a2, *rdot, nline, tl;
813
 
814
	nline = 0;
815
	dot = a;
816
	while((*f)() == 0) {
817
		if((dol-zero) >= nlall) {
818
			nlall += 512;
819
			a1 = realloc(zero, (nlall+5)*sizeof(int*));
820
			if(a1 == 0) {
821
				error("MEM?");
822
				rescue();
823
			}
824
			tl = a1 - zero;	/* relocate pointers */
825
			zero += tl;
826
			addr1 += tl;
827
			addr2 += tl;
828
			dol += tl;
829
			dot += tl;
830
		}
831
		tl = putline();
832
		nline++;
833
		a1 = ++dol;
834
		a2 = a1+1;
835
		rdot = ++dot;
836
		while(a1 > rdot)
837
			*--a2 = *--a1;
838
		*rdot = tl;
839
	}
840
	return nline;
841
}
842
 
843
void
844
add(int i)
845
{
846
	if(i && (given || dol > zero)) {
847
		addr1--;
848
		addr2--;
849
	}
850
	squeeze(0);
851
	newline();
852
	append(gettty, addr2);
853
}
854
 
855
void
856
browse(void)
857
{
858
	int forward, n;
859
	static int bformat, bnum; /* 0 */
860
 
861
	forward = 1;
862
	peekc = getchr();
863
	if(peekc != '\n'){
864
		if(peekc == '-' || peekc == '+') {
865
			if(peekc == '-')
866
				forward = 0;
867
			getchr();
868
		}
869
		n = getnum();
870
		if(n > 0)
871
			bpagesize = n;
872
	}
873
	newline();
874
	if(pflag) {
875
		bformat = listf;
876
		bnum = listn;
877
	} else {
878
		listf = bformat;
879
		listn = bnum;
880
	}
881
	if(forward) {
882
		addr1 = addr2;
883
		addr2 += bpagesize;
884
		if(addr2 > dol)
885
			addr2 = dol;
886
	} else {
887
		addr1 = addr2-bpagesize;
888
		if(addr1 <= zero)
889
			addr1 = zero+1;
890
	}
891
	printcom();
892
}
893
 
894
void
895
callunix(void)
896
{
897
	int c, pid;
898
	Rune rune;
899
	char buf[512];
900
	char *p;
901
 
902
	setnoaddr();
903
	p = buf;
904
	while((c=getchr()) != EOF && c != '\n')
905
		if(p < &buf[sizeof(buf) - 6]) {
906
			rune = c;
907
			p += runetochar(p, &rune);
908
		}
909
	*p = 0;
910
	pid = fork();
911
	if(pid == 0) {
912
		execl("/bin/rc", "rc", "-c", buf, nil);
913
		exits("execl failed");
914
	}
915
	waiting = 1;
916
	while(waitpid() != pid)
917
		;
918
	waiting = 0;
919
	if(vflag)
920
		putst("!");
921
}
922
 
923
void
924
quit(void)
925
{
926
	if(vflag && fchange && dol!=zero) {
927
		fchange = 0;
928
		error(Q);
929
	}
930
	remove(tfname);
931
	exits(0);
932
}
933
 
934
void
935
onquit(int sig)
936
{
937
	USED(sig);
938
	quit();
939
}
940
 
941
void
942
rdelete(int *ad1, int *ad2)
943
{
944
	int *a1, *a2, *a3;
945
 
946
	a1 = ad1;
947
	a2 = ad2+1;
948
	a3 = dol;
949
	dol -= a2 - a1;
950
	do {
951
		*a1++ = *a2++;
952
	} while(a2 <= a3);
953
	a1 = ad1;
954
	if(a1 > dol)
955
		a1 = dol;
956
	dot = a1;
957
	fchange = 1;
958
}
959
 
960
void
961
gdelete(void)
962
{
963
	int *a1, *a2, *a3;
964
 
965
	a3 = dol;
966
	for(a1=zero; (*a1&01)==0; a1++)
967
		if(a1>=a3)
968
			return;
969
	for(a2=a1+1; a2<=a3;) {
970
		if(*a2 & 01) {
971
			a2++;
972
			dot = a1;
973
		} else
974
			*a1++ = *a2++;
975
	}
976
	dol = a1-1;
977
	if(dot > dol)
978
		dot = dol;
979
	fchange = 1;
980
}
981
 
982
Rune*
983
getline(int tl)
984
{
985
	Rune *lp, *bp;
986
	int nl;
987
 
988
	lp = linebuf;
989
	bp = getblock(tl, OREAD);
990
	nl = nleft;
991
	tl &= ~((BLKSIZE/sizeof(Rune)) - 1);
992
	while(*lp++ = *bp++) {
993
		nl -= sizeof(Rune);
994
		if(nl == 0) {
995
			tl += BLKSIZE/sizeof(Rune);
996
			bp = getblock(tl, OREAD);
997
			nl = nleft;
998
		}
999
	}
1000
	return linebuf;
1001
}
1002
 
1003
int
1004
putline(void)
1005
{
1006
	Rune *lp, *bp;
1007
	int nl, tl;
1008
 
1009
	fchange = 1;
1010
	lp = linebuf;
1011
	tl = tline;
1012
	bp = getblock(tl, OWRITE);
1013
	nl = nleft;
1014
	tl &= ~((BLKSIZE/sizeof(Rune))-1);
1015
	while(*bp = *lp++) {
1016
		if(*bp++ == '\n') {
1017
			bp[-1] = 0;
1018
			linebp = lp;
1019
			break;
1020
		}
1021
		nl -= sizeof(Rune);
1022
		if(nl == 0) {
1023
			tl += BLKSIZE/sizeof(Rune);
1024
			bp = getblock(tl, OWRITE);
1025
			nl = nleft;
1026
		}
1027
	}
1028
	nl = tline;
1029
	tline += ((lp-linebuf) + 03) & 077776;
1030
	return nl;
1031
}
1032
 
1033
void
1034
blkio(int b, uchar *buf, long (*iofcn)(int, void *, long))
1035
{
1036
	seek(tfile, b*BLKSIZE, 0);
1037
	if((*iofcn)(tfile, buf, BLKSIZE) != BLKSIZE) {
1038
		error(T);
1039
	}
1040
}
1041
 
1042
Rune*
1043
getblock(int atl, int iof)
1044
{
1045
	int bno, off;
1046
 
1047
	static uchar ibuff[BLKSIZE];
1048
	static uchar obuff[BLKSIZE];
1049
 
1050
	bno = atl / (BLKSIZE/sizeof(Rune));
1051
	/* &~3 so the ptr is aligned to 4 (?) */
1052
	off = (atl*sizeof(Rune)) & (BLKSIZE-1) & ~3;
1053
	if(bno >= NBLK) {
1054
		lastc = '\n';
1055
		error(T);
1056
	}
1057
	nleft = BLKSIZE - off;
1058
	if(bno == iblock) {
1059
		ichanged |= iof;
1060
		return (Rune*)(ibuff+off);
1061
	}
1062
	if(bno == oblock)
1063
		return (Rune*)(obuff+off);
1064
	if(iof == OREAD) {
1065
		if(ichanged)
1066
			blkio(iblock, ibuff, write);
1067
		ichanged = 0;
1068
		iblock = bno;
1069
		blkio(bno, ibuff, read);
1070
		return (Rune*)(ibuff+off);
1071
	}
1072
	if(oblock >= 0)
1073
		blkio(oblock, obuff, write);
1074
	oblock = bno;
1075
	return (Rune*)(obuff+off);
1076
}
1077
 
1078
void
1079
init(void)
1080
{
1081
	int *markp;
1082
 
1083
	close(tfile);
1084
	tline = 2;
1085
	for(markp = names; markp < &names[26]; )
1086
		*markp++ = 0;
1087
	subnewa = 0;
1088
	anymarks = 0;
1089
	iblock = -1;
1090
	oblock = -1;
1091
	ichanged = 0;
1092
	if((tfile = create(tfname, ORDWR, 0600)) < 0){
1093
		error1(T);
1094
		exits(0);
1095
	}
1096
	dot = dol = zero;
1097
}
1098
 
1099
void
1100
global(int k)
1101
{
1102
	Rune *gp, globuf[GBSIZE];
1103
	int c, *a1;
1104
 
1105
	if(globp)
1106
		error(Q);
1107
	setwide();
1108
	squeeze(dol > zero);
1109
	c = getchr();
1110
	if(c == '\n')
1111
		error(Q);
1112
	compile(c);
1113
	gp = globuf;
1114
	while((c=getchr()) != '\n') {
1115
		if(c == EOF)
1116
			error(Q);
1117
		if(c == '\\') {
1118
			c = getchr();
1119
			if(c != '\n')
1120
				*gp++ = '\\';
1121
		}
1122
		*gp++ = c;
1123
		if(gp >= &globuf[GBSIZE-2])
1124
			error(Q);
1125
	}
1126
	if(gp == globuf)
1127
		*gp++ = 'p';
1128
	*gp++ = '\n';
1129
	*gp = 0;
1130
	for(a1=zero; a1<=dol; a1++) {
1131
		*a1 &= ~01;
1132
		if(a1 >= addr1 && a1 <= addr2 && match(a1) == k)
1133
			*a1 |= 01;
1134
	}
1135
 
1136
	/*
1137
	 * Special case: g/.../d (avoid n^2 algorithm)
1138
	 */
1139
	if(globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == 0) {
1140
		gdelete();
1141
		return;
1142
	}
1143
	for(a1=zero; a1<=dol; a1++) {
1144
		if(*a1 & 01) {
1145
			*a1 &= ~01;
1146
			dot = a1;
1147
			globp = globuf;
1148
			commands();
1149
			a1 = zero;
1150
		}
1151
	}
1152
}
1153
 
1154
void
1155
join(void)
1156
{
1157
	Rune *gp, *lp;
1158
	int *a1;
1159
 
1160
	nonzero();
1161
	gp = genbuf;
1162
	for(a1=addr1; a1<=addr2; a1++) {
1163
		lp = getline(*a1);
1164
		while(*gp = *lp++)
1165
			if(gp++ >= &genbuf[LBSIZE-sizeof(Rune)])
1166
				error(Q);
1167
	}
1168
	lp = linebuf;
1169
	gp = genbuf;
1170
	while(*lp++ = *gp++)
1171
		;
1172
	*addr1 = putline();
1173
	if(addr1 < addr2)
1174
		rdelete(addr1+1, addr2);
1175
	dot = addr1;
1176
}
1177
 
1178
void
1179
substitute(int inglob)
1180
{
1181
	int *mp, *a1, nl, gsubf, n;
1182
 
1183
	n = getnum();	/* OK even if n==0 */
1184
	gsubf = compsub();
1185
	for(a1 = addr1; a1 <= addr2; a1++) {
1186
		if(match(a1)){
1187
			int *ozero;
1188
			int m = n;
1189
 
1190
			do {
1191
				int span = loc2-loc1;
1192
 
1193
				if(--m <= 0) {
1194
					dosub();
1195
					if(!gsubf)
1196
						break;
1197
					if(span == 0) {	/* null RE match */
1198
						if(*loc2 == 0)
1199
							break;
1200
						loc2++;
1201
					}
1202
				}
1203
			} while(match(0));
1204
			if(m <= 0) {
1205
				inglob |= 01;
1206
				subnewa = putline();
1207
				*a1 &= ~01;
1208
				if(anymarks) {
1209
					for(mp=names; mp<&names[26]; mp++)
1210
						if(*mp == *a1)
1211
							*mp = subnewa;
1212
				}
1213
				subolda = *a1;
1214
				*a1 = subnewa;
1215
				ozero = zero;
1216
				nl = append(getsub, a1);
1217
				addr2 += nl;
1218
				nl += zero-ozero;
1219
				a1 += nl;
1220
			}
1221
		}
1222
	}
1223
	if(inglob == 0)
1224
		error(Q);
1225
}
1226
 
1227
int
1228
compsub(void)
1229
{
1230
	int seof, c;
1231
	Rune *p;
1232
 
1233
	seof = getchr();
1234
	if(seof == '\n' || seof == ' ')
1235
		error(Q);
1236
	compile(seof);
1237
	p = rhsbuf;
1238
	for(;;) {
1239
		c = getchr();
1240
		if(c == '\\') {
1241
			c = getchr();
1242
			*p++ = ESCFLG;
1243
			if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
1244
				error(Q);
1245
		} else
1246
		if(c == '\n' && (!globp || !globp[0])) {
1247
			peekc = c;
1248
			pflag++;
1249
			break;
1250
		} else
1251
		if(c == seof)
1252
			break;
1253
		*p++ = c;
1254
		if(p >= &rhsbuf[LBSIZE/sizeof(Rune)])
1255
			error(Q);
1256
	}
1257
	*p = 0;
1258
	peekc = getchr();
1259
	if(peekc == 'g') {
1260
		peekc = 0;
1261
		newline();
1262
		return 1;
1263
	}
1264
	newline();
1265
	return 0;
1266
}
1267
 
1268
int
1269
getsub(void)
1270
{
1271
	Rune *p1, *p2;
1272
 
1273
	p1 = linebuf;
1274
	if((p2 = linebp) == 0)
1275
		return EOF;
1276
	while(*p1++ = *p2++)
1277
		;
1278
	linebp = 0;
1279
	return 0;
1280
}
1281
 
1282
void
1283
dosub(void)
1284
{
1285
	Rune *lp, *sp, *rp;
1286
	int c, n;
1287
 
1288
	lp = linebuf;
1289
	sp = genbuf;
1290
	rp = rhsbuf;
1291
	while(lp < loc1)
1292
		*sp++ = *lp++;
1293
	while(c = *rp++) {
1294
		if(c == '&'){
1295
			sp = place(sp, loc1, loc2);
1296
			continue;
1297
		}
1298
		if(c == ESCFLG && (c = *rp++) >= '1' && c < MAXSUB+'0') {
1299
			n = c-'0';
1300
			if(subexp[n].rsp && subexp[n].rep) {
1301
				sp = place(sp, subexp[n].rsp, subexp[n].rep);
1302
				continue;
1303
			}
1304
			error(Q);
1305
		}
1306
		*sp++ = c;
1307
		if(sp >= &genbuf[LBSIZE])
1308
			error(Q);
1309
	}
1310
	lp = loc2;
1311
	loc2 = sp - genbuf + linebuf;
1312
	while(*sp++ = *lp++)
1313
		if(sp >= &genbuf[LBSIZE])
1314
			error(Q);
1315
	lp = linebuf;
1316
	sp = genbuf;
1317
	while(*lp++ = *sp++)
1318
		;
1319
}
1320
 
1321
Rune*
1322
place(Rune *sp, Rune *l1, Rune *l2)
1323
{
1324
 
1325
	while(l1 < l2) {
1326
		*sp++ = *l1++;
1327
		if(sp >= &genbuf[LBSIZE])
1328
			error(Q);
1329
	}
1330
	return sp;
1331
}
1332
 
1333
void
1334
move(int cflag)
1335
{
1336
	int *adt, *ad1, *ad2;
1337
 
1338
	nonzero();
1339
	if((adt = address())==0)	/* address() guarantees addr is in range */
1340
		error(Q);
1341
	newline();
1342
	if(cflag) {
1343
		int *ozero, delta;
1344
		ad1 = dol;
1345
		ozero = zero;
1346
		append(getcopy, ad1++);
1347
		ad2 = dol;
1348
		delta = zero - ozero;
1349
		ad1 += delta;
1350
		adt += delta;
1351
	} else {
1352
		ad2 = addr2;
1353
		for(ad1 = addr1; ad1 <= ad2;)
1354
			*ad1++ &= ~01;
1355
		ad1 = addr1;
1356
	}
1357
	ad2++;
1358
	if(adt<ad1) {
1359
		dot = adt + (ad2-ad1);
1360
		if((++adt)==ad1)
1361
			return;
1362
		reverse(adt, ad1);
1363
		reverse(ad1, ad2);
1364
		reverse(adt, ad2);
1365
	} else
1366
	if(adt >= ad2) {
1367
		dot = adt++;
1368
		reverse(ad1, ad2);
1369
		reverse(ad2, adt);
1370
		reverse(ad1, adt);
1371
	} else
1372
		error(Q);
1373
	fchange = 1;
1374
}
1375
 
1376
void
1377
reverse(int *a1, int *a2)
1378
{
1379
	int t;
1380
 
1381
	for(;;) {
1382
		t = *--a2;
1383
		if(a2 <= a1)
1384
			return;
1385
		*a2 = *a1;
1386
		*a1++ = t;
1387
	}
1388
}
1389
 
1390
int
1391
getcopy(void)
1392
{
1393
	if(addr1 > addr2)
1394
		return EOF;
1395
	getline(*addr1++);
1396
	return 0;
1397
}
1398
 
1399
void
1400
compile(int eof)
1401
{
1402
	Rune c;
1403
	char *ep;
1404
	char expbuf[ESIZE];
1405
 
1406
	if((c = getchr()) == '\n') {
1407
		peekc = c;
1408
		c = eof;
1409
	}
1410
	if(c == eof) {
1411
		if(!pattern)
1412
			error(Q);
1413
		return;
1414
	}
1415
	if(pattern) {
1416
		free(pattern);
1417
		pattern = 0;
1418
	}
1419
	ep = expbuf;
1420
	do {
1421
		if(c == '\\') {
1422
			if(ep >= expbuf+sizeof(expbuf)) {
1423
				error(Q);
1424
				return;
1425
			}
1426
			ep += runetochar(ep, &c);
1427
			if((c = getchr()) == '\n') {
1428
				error(Q);
1429
				return;
1430
			}
1431
		}
1432
		if(ep >= expbuf+sizeof(expbuf)) {
1433
			error(Q);
1434
			return;
1435
		}
1436
		ep += runetochar(ep, &c);
1437
	} while((c = getchr()) != eof && c != '\n');
1438
	if(c == '\n')
1439
		peekc = c;
1440
	*ep = 0;
1441
	pattern = regcomp(expbuf);
1442
}
1443
 
1444
int
1445
match(int *addr)
1446
{
1447
	if(!pattern)
1448
		return 0;
1449
	if(addr){
1450
		if(addr == zero)
1451
			return 0;
1452
		subexp[0].rsp = getline(*addr);
1453
	} else
1454
		subexp[0].rsp = loc2;
1455
	subexp[0].rep = 0;
1456
	if(rregexec(pattern, linebuf, subexp, MAXSUB)) {
1457
		loc1 = subexp[0].rsp;
1458
		loc2 = subexp[0].rep;
1459
		return 1;
1460
	}
1461
	loc1 = loc2 = 0;
1462
	return 0;
1463
 
1464
}
1465
 
1466
void
1467
putd(void)
1468
{
1469
	int r;
1470
 
1471
	r = count%10;
1472
	count /= 10;
1473
	if(count)
1474
		putd();
1475
	putchr(r + L'0');
1476
}
1477
 
1478
void
1479
putst(char *sp)
1480
{
1481
	Rune r;
1482
 
1483
	col = 0;
1484
	for(;;) {
1485
		sp += chartorune(&r, sp);
1486
		if(r == 0)
1487
			break;
1488
		putchr(r);
1489
	}
1490
	putchr(L'\n');
1491
}
1492
 
1493
void
1494
putshst(Rune *sp)
1495
{
1496
	col = 0;
1497
	while(*sp)
1498
		putchr(*sp++);
1499
	putchr(L'\n');
1500
}
1501
 
1502
void
1503
putchr(int ac)
1504
{
1505
	char *lp;
1506
	int c;
1507
	Rune rune;
1508
 
1509
	lp = linp;
1510
	c = ac;
1511
	if(listf) {
1512
		if(c == '\n') {
1513
			if(linp != line && linp[-1] == ' ') {
1514
				*lp++ = '\\';
1515
				*lp++ = 'n';
1516
			}
1517
		} else {
1518
			if(col > (72-6-2)) {
1519
				col = 8;
1520
				*lp++ = '\\';
1521
				*lp++ = '\n';
1522
				*lp++ = '\t';
1523
			}
1524
			col++;
1525
			if(c=='\b' || c=='\t' || c=='\\') {
1526
				*lp++ = '\\';
1527
				if(c == '\b')
1528
					c = 'b';
1529
				else
1530
				if(c == '\t')
1531
					c = 't';
1532
				col++;
1533
			} else
1534
			if(c<' ' || c>='\177') {
1535
				*lp++ = '\\';
1536
				*lp++ = 'x';
1537
				*lp++ =  hex[c>>12];
1538
				*lp++ =  hex[c>>8&0xF];
1539
				*lp++ =  hex[c>>4&0xF];
1540
				c     =  hex[c&0xF];
1541
				col += 5;
1542
			}
1543
		}
1544
	}
1545
 
1546
	rune = c;
1547
	lp += runetochar(lp, &rune);
1548
 
1549
	if(c == '\n' || lp >= &line[sizeof(line)-5]) {
1550
		linp = line;
1551
		write(oflag? 2: 1, line, lp-line);
1552
		return;
1553
	}
1554
	linp = lp;
1555
}
1556
 
1557
char*
1558
mktemp(char *as)
1559
{
1560
	char *s;
1561
	unsigned pid;
1562
	int i;
1563
 
1564
	pid = getpid();
1565
	s = as;
1566
	while(*s++)
1567
		;
1568
	s--;
1569
	while(*--s == 'X') {
1570
		*s = pid % 10 + '0';
1571
		pid /= 10;
1572
	}
1573
	s++;
1574
	i = 'a';
1575
	while(access(as, 0) != -1) {
1576
		if(i == 'z')
1577
			return "/";
1578
		*s = i++;
1579
	}
1580
	return as;
1581
}
1582
 
1583
void
1584
regerror(char *s)
1585
{
1586
	USED(s);
1587
	error(Q);
1588
}