xref: /plan9/sys/src/ape/cmd/sed/sed1.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <stdlib.h>
2 #include <sys/types.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include	<stdio.h>
6 #include "sed.h"
7 
8 #define Read(f, buf, n)	(fflush(stdout), read(f, buf, n))
9 
10 void
execute(uchar * file)11 execute(uchar *file)
12 {
13 	uchar *p1, *p2;
14 	union reptr	*ipc;
15 	int	c;
16 	long	l;
17 	uchar	*execp;
18 
19 	if (file) {
20 		if ((f = open((char*)file, O_RDONLY)) < 0) {
21 			fprintf(stderr, "sed: Can't open %s\n", file);
22 		}
23 	} else
24 		f = 0;
25 
26 	ebp = ibuf;
27 	cbp = ibuf;
28 
29 	if(pending) {
30 		ipc = pending;
31 		pending = 0;
32 		goto yes;
33 	}
34 
35 	for(;;) {
36 		if((execp = gline(linebuf)) == badp) {
37 			close(f);
38 			return;
39 		}
40 		spend = execp;
41 
42 		for(ipc = ptrspace; ipc->r1.command; ) {
43 
44 			p1 = ipc->r1.ad1;
45 			p2 = ipc->r1.ad2;
46 
47 			if(p1) {
48 
49 				if(ipc->r1.inar) {
50 					if(*p2 == CEND) {
51 						p1 = 0;
52 					} else if(*p2 == CLNUM) {
53 						l = p2[1]&0377
54 							| ((p2[2]&0377)<<8)
55 							| ((p2[3]&0377)<<16)
56 							| ((p2[4]&0377)<<24);
57 						if(lnum > l) {
58 							ipc->r1.inar = 0;
59 							if(ipc->r1.negfl)
60 								goto yes;
61 							ipc++;
62 							continue;
63 						}
64 						if(lnum == l) {
65 							ipc->r1.inar = 0;
66 						}
67 					} else if(match(p2, 0)) {
68 						ipc->r1.inar = 0;
69 					}
70 				} else if(*p1 == CEND) {
71 					if(!dolflag) {
72 						if(ipc->r1.negfl)
73 							goto yes;
74 						ipc++;
75 						continue;
76 					}
77 
78 				} else if(*p1 == CLNUM) {
79 					l = p1[1]&0377
80 						| ((p1[2]&0377)<<8)
81 						| ((p1[3]&0377)<<16)
82 						| ((p1[4]&0377)<<24);
83 					if(lnum != l) {
84 						if(ipc->r1.negfl)
85 							goto yes;
86 						ipc++;
87 						continue;
88 					}
89 					if(p2)
90 						ipc->r1.inar = 1;
91 				} else if(match(p1, 0)) {
92 					if(p2)
93 						ipc->r1.inar = 1;
94 				} else {
95 					if(ipc->r1.negfl)
96 						goto yes;
97 					ipc++;
98 					continue;
99 				}
100 			}
101 
102 			if(ipc->r1.negfl) {
103 				ipc++;
104 				continue;
105 			}
106 	yes:
107 			command(ipc);
108 
109 			if(delflag)
110 				break;
111 
112 			if(jflag) {
113 				jflag = 0;
114 				if((ipc = ipc->r2.lb1) == 0) {
115 					ipc = ptrspace;
116 					break;
117 				}
118 			} else
119 				ipc++;
120 
121 		}
122 		if(!nflag && !delflag) {
123 			for(p1 = linebuf; p1 < spend; p1++)
124 				putc(*p1, stdout);
125 			putc('\n', stdout);
126 		}
127 
128 		if(aptr > abuf) {
129 			arout();
130 		}
131 
132 		delflag = 0;
133 
134 	}
135 }
136 int
match(uchar * expbuf,int gf)137 match(uchar *expbuf, int gf)
138 {
139 	uchar	*p1, *p2;
140 	int c;
141 
142 	if(gf) {
143 		if(*expbuf)	return(0);
144 		p1 = linebuf;
145 		p2 = genbuf;
146 		while(*p1++ = *p2++);
147 		locs = p1 = loc2;
148 	} else {
149 		p1 = linebuf;
150 		locs = 0;
151 	}
152 
153 	p2 = expbuf;
154 	if(*p2++) {
155 		loc1 = p1;
156 		if(*p2 == CCHR && p2[1] != *p1)
157 			return(0);
158 		return(advance(p1, p2));
159 	}
160 
161 	/* fast check for first character */
162 
163 	if(*p2 == CCHR) {
164 		c = p2[1];
165 		do {
166 			if(*p1 != c)
167 				continue;
168 			if(advance(p1, p2)) {
169 				loc1 = p1;
170 				return(1);
171 			}
172 		} while(*p1++);
173 		return(0);
174 	}
175 
176 	do {
177 		if(advance(p1, p2)) {
178 			loc1 = p1;
179 			return(1);
180 		}
181 	} while(*p1++);
182 	return(0);
183 }
184 int
advance(uchar * alp,uchar * aep)185 advance(uchar *alp, uchar *aep)
186 {
187 	uchar *lp, *ep, *curlp;
188 	uchar	c;
189 	uchar *bbeg;
190 	int	ct;
191 
192 /*fprintf(stderr, "*lp = %c, %o\n*ep = %c, %o\n", *lp, *lp, *ep, *ep);	/*DEBUG*/
193 
194 	lp = alp;
195 	ep = aep;
196 	for (;;) switch (*ep++) {
197 
198 	case CCHR:
199 		if (*ep++ == *lp++)
200 			continue;
201 		return(0);
202 
203 	case CDOT:
204 		if (*lp++)
205 			continue;
206 		return(0);
207 
208 	case CNL:
209 	case CDOL:
210 		if (*lp == 0)
211 			continue;
212 		return(0);
213 
214 	case CEOF:
215 		loc2 = lp;
216 		return(1);
217 
218 	case CCL:
219 		c = *lp++;
220 		if(ep[c>>3] & bittab[c & 07]) {
221 			ep += 32;
222 			continue;
223 		}
224 		return(0);
225 
226 	case CBRA:
227 		braslist[*ep++] = lp;
228 		continue;
229 
230 	case CKET:
231 		braelist[*ep++] = lp;
232 		continue;
233 
234 	case CBACK:
235 		bbeg = braslist[*ep];
236 		ct = braelist[*ep++] - bbeg;
237 
238 		if(ecmp(bbeg, lp, ct)) {
239 			lp += ct;
240 			continue;
241 		}
242 		return(0);
243 
244 	case CBACK|STAR:
245 		bbeg = braslist[*ep];
246 		ct = braelist[*ep++] - bbeg;
247 		curlp = lp;
248 		while(ecmp(bbeg, lp, ct))
249 			lp += ct;
250 
251 		while(lp >= curlp) {
252 			if(advance(lp, ep))	return(1);
253 			lp -= ct;
254 		}
255 		return(0);
256 
257 
258 	case CDOT|STAR:
259 		curlp = lp;
260 		while (*lp++);
261 		goto star;
262 
263 	case CCHR|STAR:
264 		curlp = lp;
265 		while (*lp++ == *ep);
266 		ep++;
267 		goto star;
268 
269 	case CCL|STAR:
270 		curlp = lp;
271 		do {
272 			c = *lp++;
273 		} while(ep[c>>3] & bittab[c & 07]);
274 		ep += 32;
275 		goto star;
276 
277 	star:
278 		if(--lp == curlp) {
279 			continue;
280 		}
281 
282 		if(*ep == CCHR) {
283 			c = ep[1];
284 			do {
285 				if(*lp != c)
286 					continue;
287 				if(advance(lp, ep))
288 					return(1);
289 			} while(lp-- > curlp);
290 			return(0);
291 		}
292 
293 		if(*ep == CBACK) {
294 			c = *(braslist[ep[1]]);
295 			do {
296 				if(*lp != c)
297 					continue;
298 				if(advance(lp, ep))
299 					return(1);
300 			} while(lp-- > curlp);
301 			return(0);
302 		}
303 
304 		do {
305 			if(lp == locs)	break;
306 			if (advance(lp, ep))
307 				return(1);
308 		} while (lp-- > curlp);
309 		return(0);
310 
311 	default:
312 		fprintf(stderr, "sed:  RE botch, %o\n", *--ep);
313 		exit(1);
314 	}
315 }
316 int
substitute(union reptr * ipc)317 substitute(union reptr *ipc)
318 {
319 	uchar	*oloc2;
320 
321 	if(match(ipc->r1.re1, 0)) {
322 
323 		sflag = 1;
324 		if(!ipc->r1.gfl) {
325 			dosub(ipc->r1.rhs);
326 			return(1);
327 		}
328 
329 		oloc2 = NULL;
330 		do {
331 			if(oloc2 == loc2) {
332 				loc2++;
333 				continue;
334 			} else {
335 				dosub(ipc->r1.rhs);
336 				if(*loc2 == 0)
337 					break;
338 				oloc2 = loc2;
339 			}
340 		} while(match(ipc->r1.re1, 1));
341 		return(1);
342 	}
343 	return(0);
344 }
345 
346 void
dosub(uchar * rhsbuf)347 dosub(uchar *rhsbuf)
348 {
349 	uchar *lp, *sp, *rp;
350 	int c;
351 
352 	lp = linebuf;
353 	sp = genbuf;
354 	rp = rhsbuf;
355 	while (lp < loc1)
356 		*sp++ = *lp++;
357 	while(c = *rp++) {
358 		if (c == '\\') {
359 			c = *rp++;
360 			if (c >= '1' && c < NBRA+'1') {
361 				sp = place(sp, braslist[c-'1'], braelist[c-'1']);
362 				continue;
363 			}
364 		} else if(c == '&') {
365 				sp = place(sp, loc1, loc2);
366 				continue;
367 		}
368 		*sp++ = c;
369 		if (sp >= &genbuf[LBSIZE])
370 			fprintf(stderr, "sed: Output line too long.\n");
371 	}
372 	lp = loc2;
373 	loc2 = sp - genbuf + linebuf;
374 	while (*sp++ = *lp++)
375 		if (sp >= &genbuf[LBSIZE]) {
376 			fprintf(stderr, "sed: Output line too long.\n");
377 		}
378 	lp = linebuf;
379 	sp = genbuf;
380 	while (*lp++ = *sp++);
381 	spend = lp-1;
382 }
383 uchar *
place(uchar * asp,uchar * al1,uchar * al2)384 place(uchar *asp, uchar *al1, uchar *al2)
385 {
386 	uchar *sp, *l1, *l2;
387 
388 	sp = asp;
389 	l1 = al1;
390 	l2 = al2;
391 	while (l1 < l2) {
392 		*sp++ = *l1++;
393 		if (sp >= &genbuf[LBSIZE])
394 			fprintf(stderr, "sed: Output line too long.\n");
395 	}
396 	return(sp);
397 }
398 
399 void
command(union reptr * ipc)400 command(union reptr *ipc)
401 {
402 	int	i;
403 	uchar	*p1, *p2;
404 	uchar	*execp;
405 
406 
407 	switch(ipc->r1.command) {
408 
409 		case ACOM:
410 			*aptr++ = ipc;
411 			if(aptr >= &abuf[ABUFSIZE]) {
412 				fprintf(stderr, "sed: Too many appends after line %ld\n",
413 					lnum);
414 			}
415 			*aptr = 0;
416 			break;
417 
418 		case CCOM:
419 			delflag = 1;
420 			if(!ipc->r1.inar || dolflag) {
421 				for(p1 = ipc->r1.re1; *p1; )
422 					putc(*p1++, stdout);
423 				putc('\n', stdout);
424 			}
425 			break;
426 		case DCOM:
427 			delflag++;
428 			break;
429 		case CDCOM:
430 			p1 = p2 = linebuf;
431 
432 			while(*p1 != '\n') {
433 				if(*p1++ == 0) {
434 					delflag++;
435 					return;
436 				}
437 			}
438 
439 			p1++;
440 			while(*p2++ = *p1++);
441 			spend = p2-1;
442 			jflag++;
443 			break;
444 
445 		case EQCOM:
446 			fprintf(stdout, "%ld\n", lnum);
447 			break;
448 
449 		case GCOM:
450 			p1 = linebuf;
451 			p2 = holdsp;
452 			while(*p1++ = *p2++);
453 			spend = p1-1;
454 			break;
455 
456 		case CGCOM:
457 			*spend++ = '\n';
458 			p1 = spend;
459 			p2 = holdsp;
460 			while(*p1++ = *p2++)
461 				if(p1 >= lbend)
462 					break;
463 			spend = p1-1;
464 			break;
465 
466 		case HCOM:
467 			p1 = holdsp;
468 			p2 = linebuf;
469 			while(*p1++ = *p2++);
470 			hspend = p1-1;
471 			break;
472 
473 		case CHCOM:
474 			*hspend++ = '\n';
475 			p1 = hspend;
476 			p2 = linebuf;
477 			while(*p1++ = *p2++)
478 				if(p1 >= hend)
479 					break;
480 			hspend = p1-1;
481 			break;
482 
483 		case ICOM:
484 			for(p1 = ipc->r1.re1; *p1; )
485 				putc(*p1++, stdout);
486 			putc('\n', stdout);
487 			break;
488 
489 		case BCOM:
490 			jflag = 1;
491 			break;
492 
493 		case LCOM:
494 			p1 = linebuf;
495 			p2 = genbuf;
496 			while(*p1) {
497 				p2 = lformat(*p1++ & 0377, p2);
498 				if(p2>lcomend && *p1) {
499 					*p2 = 0;
500 					fprintf(stdout, "%s\\\n", genbuf);
501 					p2 = genbuf;
502 				}
503 			}
504 			if(p2>genbuf && (p1[-1]==' '||p1[-1]=='\n'))
505 					p2 = lformat('\n', p2);
506 			*p2 = 0;
507 			fprintf(stdout, "%s\n", genbuf);
508 			break;
509 
510 		case NCOM:
511 			if(!nflag) {
512 				for(p1 = linebuf; p1 < spend; p1++)
513 					putc(*p1, stdout);
514 				putc('\n', stdout);
515 			}
516 
517 			if(aptr > abuf)
518 				arout();
519 			if((execp = gline(linebuf)) == badp) {
520 				pending = ipc;
521 				delflag = 1;
522 				break;
523 			}
524 			spend = execp;
525 
526 			break;
527 		case CNCOM:
528 			if(aptr > abuf)
529 				arout();
530 			*spend++ = '\n';
531 			if((execp = gline(spend)) == badp) {
532 				pending = ipc;
533 				delflag = 1;
534 				break;
535 			}
536 			spend = execp;
537 			break;
538 
539 		case PCOM:
540 			for(p1 = linebuf; p1 < spend; p1++)
541 				putc(*p1, stdout);
542 			putc('\n', stdout);
543 			break;
544 		case CPCOM:
545 	cpcom:
546 			for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; )
547 				putc(*p1++, stdout);
548 			putc('\n', stdout);
549 			break;
550 
551 		case QCOM:
552 			if(!nflag) {
553 				for(p1 = linebuf; p1 < spend; p1++)
554 					putc(*p1, stdout);
555 				putc('\n', stdout);
556 			}
557 			if(aptr > abuf)	arout();
558 			fclose(stdout);
559 			lseek(f,(long)(cbp-ebp),2);
560 			exit(0);
561 		case RCOM:
562 
563 			*aptr++ = ipc;
564 			if(aptr >= &abuf[ABUFSIZE])
565 				fprintf(stderr, "sed: Too many reads after line%ld\n",
566 					lnum);
567 
568 			*aptr = 0;
569 
570 			break;
571 
572 		case SCOM:
573 			i = substitute(ipc);
574 			if(ipc->r1.pfl && i)
575 				if(ipc->r1.pfl == 1) {
576 					for(p1 = linebuf; p1 < spend; p1++)
577 						putc(*p1, stdout);
578 					putc('\n', stdout);
579 				}
580 				else
581 					goto cpcom;
582 			if(i && ipc->r1.fcode)
583 				goto wcom;
584 			break;
585 
586 		case TCOM:
587 			if(sflag == 0)	break;
588 			sflag = 0;
589 			jflag = 1;
590 			break;
591 
592 		wcom:
593 		case WCOM:
594 			fprintf(ipc->r1.fcode, "%s\n", linebuf);
595 			fflush(ipc->r1.fcode);
596 			break;
597 		case XCOM:
598 			p1 = linebuf;
599 			p2 = genbuf;
600 			while(*p2++ = *p1++);
601 			p1 = holdsp;
602 			p2 = linebuf;
603 			while(*p2++ = *p1++);
604 			spend = p2 - 1;
605 			p1 = genbuf;
606 			p2 = holdsp;
607 			while(*p2++ = *p1++);
608 			hspend = p2 - 1;
609 			break;
610 
611 		case YCOM:
612 			p1 = linebuf;
613 			p2 = ipc->r1.re1;
614 			while(*p1 = p2[*p1])	p1++;
615 			break;
616 	}
617 
618 }
619 
620 uchar *
gline(uchar * addr)621 gline(uchar *addr)
622 {
623 	uchar	*p1, *p2;
624 	int	c;
625 	sflag = 0;
626 	p1 = addr;
627 	p2 = cbp;
628 	for (;;) {
629 		if (p2 >= ebp) {
630 			if ((c = Read(f, ibuf, 512)) <= 0) {
631 				return(badp);
632 			}
633 			p2 = ibuf;
634 			ebp = ibuf+c;
635 		}
636 		if ((c = *p2++) == '\n') {
637 			if(p2 >=  ebp) {
638 				if((c = Read(f, ibuf, 512)) <= 0) {
639 					close(f);
640 					if(eargc == 0)
641 							dolflag = 1;
642 				}
643 
644 				p2 = ibuf;
645 				ebp = ibuf + c;
646 			}
647 			break;
648 		}
649 		if(c)
650 		if(p1 < lbend)
651 			*p1++ = c;
652 	}
653 	lnum++;
654 	*p1 = 0;
655 	cbp = p2;
656 
657 	return(p1);
658 }
659 int
ecmp(uchar * a,uchar * b,int count)660 ecmp(uchar *a, uchar *b, int count)
661 {
662 	while(count--)
663 		if(*a++ != *b++)	return(0);
664 	return(1);
665 }
666 
667 void
arout(void)668 arout(void)
669 {
670 	uchar	*p1;
671 	FILE	*fi;
672 	uchar	c;
673 	int	t;
674 
675 	aptr = abuf - 1;
676 	while(*++aptr) {
677 		if((*aptr)->r1.command == ACOM) {
678 			for(p1 = (*aptr)->r1.re1; *p1; )
679 				putc(*p1++, stdout);
680 			putc('\n', stdout);
681 		} else {
682 			if((fi = fopen((char*)((*aptr)->r1.re1), "r")) == NULL)
683 				continue;
684 			while((t = getc(fi)) != EOF) {
685 				c = t;
686 				putc(c, stdout);
687 			}
688 			fclose(fi);
689 		}
690 	}
691 	aptr = abuf;
692 	*aptr = 0;
693 }
694 
695 uchar *
lformat(int c,uchar * p)696 lformat(int c, uchar *p)
697 {
698 	int trans =
699 		c=='\b'? 'b':
700 		c=='\t'? 't':
701 		c=='\n'? 'n':
702 		c=='\v'? 'v':
703 		c=='\f'? 'f':
704 		c=='\r'? 'r':
705 		c=='\\'? '\\':
706 		0;
707 	if(trans) {
708 		*p++ = '\\';
709 		*p++ = trans;
710 	} else if(c<040 || c>=0177) {
711 		*p++ = '\\';
712 		*p++ = ((c>>6)&07) + '0';
713 		*p++ = ((c>>3)&07) + '0';
714 		*p++ = (c&07) + '0';
715 	} else
716 		*p++ = c;
717 	return p;
718 }
719 
720