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 static char Sccsid[] = "@(#)prs.c	4.3	02/02/88";
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 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 	extern	char	Getpgm[];
705 	char	str[128];
706 	char	rarg[20];
707 	char	filearg[80];
708 
709 	sid_ba(gsid,str);
710 	sprintf(rarg,"%s",str);
711 	sprintf(filearg,"%s",pkt->p_file);
712 	/*
713 	fork here so 'getbody' can execute 'get' to
714 	print out gotten body :GB:
715 	*/
716 	if ((i = fork()) < 0)
717 		fatal("cannot fork, try again");
718 	if (i = 0) {
719 		/*
720 		perform 'get' and redirect output
721 		to standard output
722 		*/
723 		execl(Getpgm,Getpgm,"-s","-p","-r",rarg,filearg,0);
724 		sprintf(Error,"cannot execute '%s'",Getpgm);
725 		fatal(Error);
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