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