1 /*************************************************************************/
2 /*									 */
3 /*	prs [-d<dataspec>] [-r<sid>] [-c<cutoff>] [-a]			 */
4 /*	    [-y<reverse-cutoff>] file ...				 */
5 /*									 */
6 /*************************************************************************/
7 
8 /*
9 	Program to print parts or all of an SCCS file
10 	in user supplied format.
11 	Arguments to the program may appear in any order
12 	and consist of keyletters, which begin with '-',
13 	and named files.
14 
15 	If a direcory is given as an argument, each
16 	SCCS file within the directory is processed as if
17 	it had been specifically named. If a name of '-'
18 	is given, the standard input is read for a list
19 	of names of SCCS files to be processed.
20 	Non-SCCS files are ignored.
21 */
22 
23 # include "../hdr/defines.h"
24 # include "../hdr/had.h"
25 # include "pathnames.h"
26 
27 static char Sccsid[] = "@(#)prs.c	4.4	11/11/90";
28 
29 char	had[26];
30 char	Sid[32];
31 char	Mod[16];
32 char	*Type;
33 char	Deltadate[18];
34 char	*Deltatime;
35 char	tempskel[] = "/tmp/prXXXXXX";	/* used to generate temp file names */
36 
37 char	untmp[32], uttmp[32], cmtmp[32];
38 char	mrtmp[32], bdtmp[32];
39 FILE	*UNiop;
40 FILE	*UTiop;
41 FILE	*CMiop;
42 FILE	*MRiop;
43 FILE	*BDiop;
44 char	line[BUFSIZ];
45 int	num_files;
46 long	cutoff;
47 long	revcut;
48 char	*dataspec;
49 char	iline[BUFSIZ], xline[BUFSIZ], gline[BUFSIZ];
50 char	*maket();
51 struct	packet	gpkt;
52 struct	sid	sid;
53 struct	tm	*Dtime;
54 
55 main(argc,argv)
56 int argc;
57 char *argv[];
58 {
59 	register int j;
60 	register char *p;
61 	char c;
62 	extern prs();
63 	extern int Fcnt;
64 
65 	/*
66 	Set flags for 'fatal' to issue message, call clean-up
67 	routine, and terminate processing.
68 	*/
69 	Fflags = FTLMSG | FTLCLN | FTLEXIT;
70 
71 
72 	/*
73 	The following loop processes keyletters and arguments.
74 	Note that these are processed only once for each
75 	invocation of 'main'.
76 	*/
77 	for (j = 1; j < argc; j++)
78 		if (argv[j][0] == '-' && (c = argv[j][1])) {
79 			p = &argv[j][2];
80 			switch (c) {
81 
82 			case 'r':	/* delta cutoff */
83 				if (*p) {
84 					if (invalid(p))
85 						fatal("invalid sid (co8)");
86 					sid_ab(p,&sid);
87 				}
88 				break;
89 
90 			case 'c':	/* time cutoff */
91 				if (*p && date_ab(p,&cutoff))
92 					fatal("bad date/time (cm5)");
93 				break;
94 
95 			case 'y':	/* reverse time cutoff */
96 				if (*p && date_ab(p,&revcut))
97 					fatal ("bad date/time (cm5)");
98 				break;
99 
100 			case 'a':
101 				if (*p)
102 					fatal("value after a arg (cm7)");
103 				break;
104 			case 'd':	/* dataspec line */
105 				dataspec = p;
106 				break;
107 			default:
108 				fatal("unknown key letter (cm1)");
109 			}
110 
111 			if (had[c - 'a']++)
112 				fatal("key letter twice (cm2)");
113 			argv[j] = 0;
114 		}
115 		else
116 			num_files++;
117 
118 	if (num_files == 0)
119 		fatal("missing file arg (cm3)");
120 
121 	if (!HADD)
122 		exit(0);
123 	if (HADC && HADY)
124 		fatal("both 'c' and 'y' keyletters specified (prs2)");
125 
126 	setsig();
127 
128 	/*
129 	Change flags for 'fatal' so that it will return to this
130 	routine (main) instead of terminating processing.
131 	*/
132 	Fflags &= ~FTLEXIT;
133 	Fflags |= FTLJMP;
134 
135 	/*
136 	Call 'prs' routine for each file argument.
137 	*/
138 	for (j = 1; j < argc; j++)
139 		if (p = argv[j])
140 			do_file(p,prs);
141 
142 	exit(Fcnt ? 1 : 0);
143 }
144 
145 
146 prs(file)
147 register	char	*file;
148 {
149 	int	n;
150 	extern	char	had_dir, had_standinp;
151 
152 	if (setjmp(Fjmp))
153 		return;
154 	sinit(&gpkt,file,1);	/* init packet and open SCCS file */
155 
156 	gpkt.p_reqsid.s_rel = sid.s_rel;
157 	gpkt.p_reqsid.s_lev = sid.s_lev;
158 	gpkt.p_reqsid.s_br = sid.s_br;
159 	gpkt.p_reqsid.s_seq = sid.s_seq;
160 	gpkt.p_cutoff = cutoff;
161 	gpkt.p_reopen = 1;
162 
163 	/*
164 	read delta table entries checking only for format error
165 	*/
166 	deltblchk(&gpkt);
167 
168 	/*
169 	create auxiliary file for User Name Section
170 	*/
171 
172 	aux_create(UNiop,untmp,EUSERNAM);
173 
174 	doflags(&gpkt);
175 
176 	/*
177 	create auxiliary file for the User Text section
178 	*/
179 
180 	aux_create(UTiop,uttmp,EUSERTXT);
181 
182 	/*
183 	indicate to 'getline' that EOF is okay
184 	*/
185 	gpkt.p_chkeof = 1;
186 
187 	/*
188 	read body of SCCS file and create temp file for it
189 	*/
190 	while(read_mod(&gpkt))
191 		;
192 
193 	if (num_files > 1 || had_dir || had_standinp)
194 		printf("\n%s:\n",gpkt.p_file);
195 	/*
196 	Here, file has already been re-opened (by 'getline')
197 	*/
198 	getline(&gpkt);		/* skip over header line */
199 
200 	/*
201 	call dodeltbl to read delta table entries
202 	*/
203 
204 	dodeltbl(&gpkt);
205 
206 	clean_up();
207 
208 	return;
209 }
210 
211 
212 dodeltbl(pkt)
213 register struct packet *pkt;
214 {
215 	int	n;
216 	struct	deltab	dt;
217 	struct	stats	stats;
218 
219 	/*
220 	Read entire delta table.
221 	*/
222 	while (getstats(pkt,&stats)) {
223 		if (getadel(pkt,&dt) != BDELTAB)
224 			fmterr(pkt);
225 
226 		/*
227 		Read rest of delta entry.
228 		*/
229 		while ((n = getline(pkt)) != NULL)
230 			if (pkt->p_line[0] != CTLCHAR)
231 				break;
232 			else {
233 				switch (pkt->p_line[1]) {
234 				case EDELTAB:
235 					scanspec(dataspec,&dt,&stats);
236 					break;
237 				case INCLUDE:
238 					getit(iline,n);
239 					continue;
240 				case EXCLUDE:
241 					getit(xline,n);
242 					continue;
243 				case IGNORE:
244 					getit(gline,n);
245 					continue;
246 				case MRNUM:
247 				case COMMENTS:
248 					continue;
249 				default:
250 					fmterr(pkt);
251 				}
252 				break;
253 			}
254 		if (n == NULL || pkt->p_line[0] != CTLCHAR)
255 			fmterr(pkt);
256 	}
257 }
258 
259 
260 /*
261  * The scanspec procedure scans the dataspec searching for ID keywords.
262  * When a keyword is found the value is replaced and printed on the
263  * standard output. Any character that is not an ID keyword is printed
264  * immediately.
265 */
266 
267 static	char	Zkeywd[5] = "@(#)";
268 scanspec(spec,dtp,statp)
269 char spec[];
270 struct	deltab	*dtp;
271 struct	stats	*statp;
272 {
273 
274 	extern	char	*Sflags[];
275 	register char *lp;
276 	register char	*k;
277 	union {
278 		char	str[2];
279 		short	istr;
280 	} u;
281 	register	char	c;
282 
283 	idsetup(&dtp->d_sid,&gpkt,&dtp->d_datetime);
284 	for(lp = spec; *lp != 0; lp++) {
285 		if(lp[0] == ':' && lp[1] != 0 && lp[2] == ':') {
286 			c = *++lp;
287 			switch (c) {
288 			case 'I':	/* SID */
289 				printf("%s",Sid);
290 				break;
291 			case 'R':	/* Release number */
292 				printf("%u",dtp->d_sid.s_rel);
293 				break;
294 			case 'L':	/* Level number */
295 				printf("%u",dtp->d_sid.s_lev);
296 				break;
297 			case 'B':	/* Branch number */
298 				if (dtp->d_sid.s_br != 0)
299 					printf("%u",dtp->d_sid.s_br);
300 				break;
301 			case 'S':	/* Sequence number */
302 				if (dtp->d_sid.s_seq != 0)
303 					printf("%u",dtp->d_sid.s_seq);
304 				break;
305 			case 'D':	/* Date delta created */
306 				printf("%s",Deltadate);
307 				break;
308 			case 'T':	/* Time delta created */
309 				printf("%s",Deltatime);
310 				break;
311 			case 'P':	/* Programmer who created delta */
312 				printf("%s",dtp->d_pgmr);
313 				break;
314 			case 'C':	/* Comments */
315 				break;
316 			case 'Y':	/* Type flag */
317 				printf("%s",Type);
318 				break;
319 			case 'M':	/* Module name */
320 				printf("%s",Mod);
321 				break;
322 			case 'W':	/* Form of what string */
323 				printf("%s",Zkeywd);
324 				printf("%s",Mod);
325 				putchar('\t');
326 				printf("%s",Sid);
327 				break;
328 			case 'A':	/* Form of what string */
329 				printf("%s",Zkeywd);
330 				printf("%s ",Type);
331 				printf("%s ",Mod);
332 				printf("%s",Sid);
333 				printf("%s",Zkeywd);
334 				break;
335 			case 'Z':	/* what string constructor */
336 				printf("%s",Zkeywd);
337 				break;
338 			case 'F':	/* File name */
339 				printf("%s",sname(gpkt.p_file));
340 				break;
341 			default:
342 				putchar(':');
343 				putchar(c);
344 				putchar(':');
345 				break;
346 			}
347 			lp++;
348 		}
349 		else if(lp[0] == ':' && lp[1] != 0 && lp[2] !=0 && lp[3] == ':') {
350 			if (lp[1] == ':') {
351 				putchar(':');
352 				*lp += 2;
353 				continue;
354 			}
355 			u.str[1] = *++lp;
356 			u.str[0] = *++lp;
357 			switch (u.istr) {
358 			case 'Dl':	/* Delta line statistics */
359 				printf("%05d",statp->s_ins);
360 				putchar('/');
361 				printf("%05d",statp->s_del);
362 				putchar('/');
363 				printf("%05d",statp->s_unc);
364 				break;
365 			case 'Li':	/* Lines inserted by delta */
366 				printf("%05d",statp->s_ins);
367 				break;
368 			case 'Ld':	/* Lines deleted by delta */
369 				printf("%05d",statp->s_del);
370 				break;
371 			case 'Lu':	/* Lines unchanged by delta */
372 				printf("%05d",statp->s_unc);
373 				break;
374 			case 'DT':	/* Delta type */
375 				printf("%c",dtp->d_type);
376 				break;
377 			case 'Dy':	/* Year delta created */
378 				printf("%02d",Dtime->tm_year);
379 				break;
380 			case 'Dm':	/* Month delta created */
381 				printf("%02d",(Dtime->tm_mon + 1));
382 				break;
383 			case 'Dd':	/* Day delta created */
384 				printf("%02d",Dtime->tm_mday);
385 				break;
386 			case 'Th':	/* Hour delta created */
387 				printf("%02d",Dtime->tm_hour);
388 				break;
389 			case 'Tm':	/* Minutes delta created */
390 				printf("%02d",Dtime->tm_min);
391 				break;
392 			case 'Ts':	/* Seconds delta created */
393 				printf("%02d",Dtime->tm_sec);
394 				break;
395 			case 'DS':	/* Delta sequence number */
396 				printf("%d",dtp->d_serial);
397 				break;
398 			case 'DP':	/* Predecessor delta sequence number */
399 				printf("%d",dtp->d_pred);
400 				break;
401 			case 'DI':	/* Deltas included,excluded,ignored */
402 				printf("%s",iline);
403 				putchar('/');
404 				printf("%s",xline);
405 				putchar('/');
406 				printf("%s",gline);
407 				break;
408 			case 'Di':	/* Deltas included */
409 				printf("%s",iline);
410 				break;
411 			case 'Dx':	/* Deltas excluded */
412 				printf("%s",xline);
413 				break;
414 			case 'Dg':	/* Deltas ignored */
415 				printf("%s",gline);
416 				break;
417 			case 'MR':	/* MR numbers */
418 				break;
419 			case 'UN':	/* User names */
420 				printfile(untmp);
421 				break;
422 			case 'MF':	/* MR validation flag */
423 				if (Sflags[VALFLAG - 'a'])
424 					printf("yes");
425 				else printf("no");
426 				break;
427 			case 'MP':	/* MR validation program */
428 				if (!(k = Sflags[VALFLAG - 'a']))
429 					printf("none");
430 				else printf("%s",k);
431 				break;
432 			case 'KF':	/* Keyword err/warn flag */
433 				if (Sflags[IDFLAG - 'a'])
434 					printf("yes");
435 				else printf("no");
436 				break;
437 			case 'BF':	/* Branch flag */
438 				if (Sflags[BRCHFLAG - 'a'])
439 					printf("yes");
440 				else printf("no");
441 				break;
442 			case 'FB':	/* Floor Boundry */
443 				if (k = Sflags[FLORFLAG - 'a'])
444 					printf("%s",k);
445 				else printf("none");
446 				break;
447 			case 'CB':	/* Ceiling Boundry */
448 				if (k = Sflags[CEILFLAG - 'a'])
449 					printf("%s",k);
450 				else printf("none");
451 				break;
452 			case 'Ds':	/* Default SID */
453 				if (k = Sflags[DEFTFLAG - 'a'])
454 					printf("%s",k);
455 				else printf("none");
456 				break;
457 			case 'ND':	/* Null delta */
458 				if (Sflags[NULLFLAG - 'a'])
459 					printf("yes");
460 				else printf("no");
461 				break;
462 			case 'FD':	/* File descriptive text */
463 				printfile(uttmp);
464 				break;
465 			case 'BD':	/* Entire file body */
466 				printfile(bdtmp);
467 				break;
468 			case 'GB':	/* Gotten body from 'get' */
469 				getbody(&dtp->d_sid,&gpkt);
470 				break;
471 			default:
472 				putchar(':');
473 				printf("%c",u.istr);
474 				putchar(':');
475 				break;
476 			}
477 			lp++;
478 		}
479 		else {
480 			c = *lp;
481 			if (c == '\\') {
482 				switch(*++lp) {
483 				case 'n':	/* for newline */
484 					putchar('\n');
485 					break;
486 				case ':':	/* for wanted colon */
487 					putchar(':');
488 					break;
489 				case 't':	/* for tab */
490 					putchar('\t');
491 					break;
492 				case 'b':	/* for backspace */
493 					putchar('\b');
494 					break;
495 				case 'r':	/* for carriage return */
496 					putchar('\r');
497 					break;
498 				case 'f':	/* for form feed */
499 					putchar('\f');
500 					break;
501 				case '\\':	/* for backslash */
502 					putchar('\\');
503 					break;
504 				case '\'':	/* for single quote */
505 					putchar('\'');
506 					break;
507 				default:	/* unknown case */
508 					putchar('\\');
509 					putchar(*lp);
510 					break;
511 				}
512 			}
513 			else putchar(*lp);
514 		}
515 	}
516 	/*
517 	zero out first char of global string lines in case
518 	a value is not gotten in next delta table entry
519 	*/
520 	iline[0] = xline[0] = gline[0] = 0;
521 	putchar('\n');
522 	return;
523 }
524 
525 
526 clean_up()
527 {
528 	unlink(untmp);
529 	unlink(uttmp);
530 	unlink(bdtmp);
531 	if (gpkt.p_iop)
532 		fclose(gpkt.p_iop);
533 }
534 
535 
536 /* This function takes as it's argument the SID inputed and determines
537  * whether or not it is valid (e. g. not ambiguous or illegal).
538 */
539 invalid(i_sid)
540 register char	*i_sid;
541 {
542 	register int count;
543 	register int digits;
544 	count = digits = 0;
545 	if (*i_sid == '0' || *i_sid == '.')
546 		return (1);
547 	i_sid++;
548 	digits++;
549 	while (*i_sid != '\0') {
550 		if (*i_sid++ == '.') {
551 			digits = 0;
552 			count++;
553 			if (*i_sid == '0' || *i_sid == '.')
554 				return (1);
555 		}
556 		digits++;
557 		if (digits > 5)
558 			return (1);
559 	}
560 	if (*(--i_sid) == '.' )
561 		return (1);
562 	if (count == 1 || count == 3)
563 		return (0);
564 	return (1);
565 }
566 
567 
568 deltblchk(pkt)
569 register struct packet *pkt;
570 {
571 	int	n;
572 	struct	deltab	dt;
573 	struct	stats	stats;
574 
575 	/*
576 	Read entire delta table.
577 	*/
578 	while (getstats(pkt,&stats)) {
579 		if (getadel(pkt,&dt) != BDELTAB)
580 			fmterr(pkt);
581 
582 		/*
583 		Read rest of delta entry.
584 		*/
585 		while ((n = getline(pkt)) != NULL)
586 			if (pkt->p_line[0] != CTLCHAR)
587 				break;
588 			else {
589 				switch (pkt->p_line[1]) {
590 				case EDELTAB:
591 					break;
592 				case INCLUDE:
593 				case EXCLUDE:
594 				case IGNORE:
595 				case MRNUM:
596 				case COMMENTS:
597 					continue;
598 				default:
599 					fmterr(pkt);
600 				}
601 				break;
602 			}
603 		if (n == NULL || pkt->p_line[0] != CTLCHAR)
604 			fmterr(pkt);
605 	}
606 	if (pkt->p_line[1] != BUSERNAM)
607 		fmterr(pkt);
608 }
609 
610 
611 getstats(pkt,statp)
612 register struct packet *pkt;
613 register struct stats *statp;
614 {
615 	register char *p;
616 
617 	p = pkt->p_line;
618 	if (getline(pkt) == NULL || *p++ != CTLCHAR || *p++ != STATS)
619 		return(0);
620 	NONBLANK(p);
621 	p = satoi(p,&statp->s_ins);
622 	p = satoi(++p,&statp->s_del);
623 	satoi(++p,&statp->s_unc);
624 	return(1);
625 }
626 
627 
628 getadel(pkt,dt)
629 register struct packet *pkt;
630 register struct deltab *dt;
631 {
632 	if (getline(pkt) == NULL)
633 		fmterr(pkt);
634 	return(del_ab(pkt->p_line,dt,pkt));
635 }
636 
637 
638 
639 char	*maket(file)
640 char	*file;
641 {
642 	FILE *iop;
643 
644 	copy(tempskel,file);
645 	iop = xfcreat(mktemp(file),0644);
646 
647 	return(iop);
648 }
649 
650 
651 printfile(file)
652 register	char	*file;
653 {
654 	register	char	*p;
655 	FILE	*iop;
656 
657 	iop = xfopen(file,0);
658 	while ((p = fgets(line,sizeof(line),iop)) != NULL)
659 		printf("%s",p);
660 	fclose(iop);
661 }
662 
663 
664 read_mod(pkt)
665 register struct packet *pkt;
666 {
667 	register char *p;
668 	int ser;
669 	int iord;
670 	register struct apply *ap;
671 
672 	BDiop = maket(bdtmp);
673 	while (getline(pkt) != NULL) {
674 		p = pkt->p_line;
675 		fputs(p,BDiop);
676 		if (*p++ != CTLCHAR)
677 			continue;
678 		else {
679 			if (!((iord = *p++) == INS || iord == DEL || iord == END))
680 				fmterr(pkt);
681 			NONBLANK(p);
682 			satoi(p,&ser);
683 			if (iord == END)
684 				remq(pkt,ser);
685 			else if ((ap = &pkt->p_apply[ser])->a_code == APPLY)
686 				addq(pkt,ser,iord == INS ? YES : NO,iord,ap->a_reason & USER);
687 			else
688 				addq(pkt,ser,iord == INS ? NO : NULL,iord,ap->a_reason & USER);
689 		}
690 	}
691 	fclose(BDiop);
692 	if (pkt->p_q)
693 		fatal("premature eof (co5)");
694 	return(0);
695 }
696 
697 
698 getbody(gsid,pkt)
699 struct	sid	*gsid;
700 struct packet *pkt;
701 {
702 	int	i;
703 	int	status;
704 	char	str[128];
705 	char	rarg[20];
706 	char	filearg[80];
707 
708 	sid_ba(gsid,str);
709 	sprintf(rarg,"%s",str);
710 	sprintf(filearg,"%s",pkt->p_file);
711 	/*
712 	fork here so 'getbody' can execute 'get' to
713 	print out gotten body :GB:
714 	*/
715 	if ((i = fork()) < 0)
716 		fatal("cannot fork, try again");
717 	if (i = 0) {
718 		/*
719 		perform 'get' and redirect output
720 		to standard output
721 		*/
722 		execl(_PATH_GET,"get","-s","-p","-r",rarg,filearg,0);
723 		sprintf(Error,"cannot execute '%s'",_PATH_GET);
724 		fatal(Error);
725 	}
726 	else {
727 		wait(&status);
728 		return;
729 	}
730 }
731 
732 
733 getit(str,cp)
734 register	char	*str, *cp;
735 {
736 	cp += 2;
737 	NONBLANK(cp);
738 	cp[length(cp) - 1] = '\0';
739 	sprintf(str,"%s",cp);
740 }
741 
742 
743 aux_create(iop,file,delchar)
744 FILE	*iop;
745 char	*file;
746 char	delchar;
747 {
748 
749 	int	n;
750 	int	text;
751 	/*
752 	create auxiliary file for the named section
753 	*/
754 
755 	text = 0;
756 	iop = maket(file);
757 	while ((n = getline(&gpkt)) != NULL && gpkt.p_line[0] != CTLCHAR) {
758 		text = 1;
759 		fputs(n,iop);
760 	}
761 	/*
762 	check to see that delimiter found is correct
763 	*/
764 	if (n == NULL || gpkt.p_line[0] != CTLCHAR || gpkt.p_line[1] != delchar)
765 		fmterr(&gpkt);
766 	if (!text)
767 		fprintf(iop,"No entries\n");
768 	fclose(iop);
769 }
770 
771 
772 idsetup(gsid,pkt,bdate)
773 struct	sid	*gsid;
774 struct	packet	*pkt;
775 long	*bdate;
776 {
777 
778 	register	char	*p;
779 	extern	struct	tm	*localtime();
780 
781 	date_ba(bdate,Deltadate);
782 
783 	Deltatime = &Deltadate[9];
784 	Deltadate[8] = 0;
785 
786 	sid_ba(gsid,Sid);
787 
788 	Dtime = localtime(bdate);
789 
790 	if (p = Sflags[MODFLAG - 'a'])
791 		copy(p,Mod);
792 	else sprintf(Mod,"%s",sname(pkt->p_file));
793 
794 	if (!(Type = Sflags[TYPEFLAG - 'a']))
795 		Type = "none";
796 }
797