1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may use this file only in accordance with the terms of version
7 * 1.0 of the CDDL.
8 *
9 * A full copy of the text of the CDDL should have accompanied this
10 * source. A copy of the CDDL is also available via the Internet at
11 * http://www.opensource.org/licenses/cddl1.txt
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 */
23 /* Copyright (c) 1988 AT&T */
24 /* All Rights Reserved */
25 /*
26 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29 /*
30 * Copyright 2006-2020 J. Schilling
31 *
32 * @(#)prs.c 1.68 20/09/11 J. Schilling
33 */
34 #if defined(sun)
35 #pragma ident "@(#)prs.c 1.68 20/09/11 J. Schilling"
36 #endif
37 /*
38 * @(#)prs.c 1.33 06/12/12
39 */
40
41 /*
42 * Copyright 1990-2003 Sun Microsystems, Inc. All rights reserved.
43 * Use is subject to license terms.
44 */
45
46 #if defined(sun)
47 #pragma ident "@(#)prs.c"
48 #pragma ident "@(#)sccs:cmd/prs.c"
49 #endif
50 /*************************************************************************/
51 /* */
52 /* prs [-d<dataspec>] [-r<sid>] [-l] [-e] [-a] file ... */
53 /* */
54 /*************************************************************************/
55
56 /*
57 Program to print parts or all of an SCCS file
58 in user supplied format.
59 Arguments to the program may appear in any order
60 and consist of keyletters, which begin with '-',
61 and named files.
62
63 If a direcory is given as an argument, each
64 SCCS file within the directory is processed as if
65 it had been specifically named. If a name of '-'
66 is given, the standard input is read for a list
67 of names of SCCS files to be processed.
68 Non-SCCS files are ignored.
69 */
70
71 #define SCCS_MAIN /* define global vars */
72 #include <defines.h>
73 #include <version.h>
74 #include <had.h>
75 #include <i18n.h>
76 #include <schily/wait.h>
77 #define VMS_VFORK_OK
78 #include <schily/vfork.h>
79 #include <schily/sysexits.h>
80
81 #if defined(PROTOTYPES) && defined(INS_BASE)
82 static char Getpgmp[] = NOGETTEXT(INS_BASE "/" SCCS_BIN_PRE "bin/" "get");
83 #endif
84 static char Getpgm[] = NOGETTEXT("get");
85 static char defline[] = NOGETTEXT(":Dt:\t:DL:\nMRs:\n:MR:COMMENTS:\n:C:");
86 static char Sid[SID_STRSIZE];
87 static char Mod[FILESIZE];
88 static char Olddir[BUFSIZ];
89 static char Pname[BUFSIZ];
90 static char Dir[BUFSIZ];
91 static char *Type;
92 static char *Qsect;
93 static char Deltadate[DT_ZSTRSIZE];
94 static char Deltadatel[DT_ZSTRSIZE];
95 static char *Deltatime;
96 static char tempskel[] = NOGETTEXT("/tmp/prXXXXXX"); /* used to generate */
97 /* temp file names */
98 static Nparms N; /* Keep -N parameters */
99 static Xparms X; /* Keep -X parameters */
100 static struct sid sid;
101
102 static char untmp[32], uttmp[32], cmtmp[32];
103 static char mrtmp[32], sxtmp[32], bdtmp[32];
104 static FILE *UNiop;
105 static FILE *UTiop;
106 static FILE *CMiop;
107 static FILE *MRiop;
108 static FILE *SXiop;
109 static FILE *BDiop;
110 static char line[BUFSIZ];
111 static int num_files;
112 static int HAD_CM, HAD_MR, HAD_SX, HAD_FD, HAD_BD, HAD_UN;
113 static char dt_line[BUFSIZ];
114 static char *dataspec = &defline[0];
115 static char iline[BUFSIZ], xline[BUFSIZ], gline[BUFSIZ];
116 static struct packet gpkt;
117 static struct tm *Dtime;
118 static struct tm Date_time;
119 static struct tm Del_Date_time;
120
121 static void clean_up __PR((void));
122
123 int main __PR((int argc, char **argv));
124 static void process __PR((char *file));
125 static void dodeltbl __PR((struct packet *pkt));
126 static void scanspec __PR((char *spec, struct deltab *dtp, struct stats *statp));
127 static void deltblchk __PR((struct packet *pkt));
128 static int getstats __PR((struct packet *pkt, struct stats *statp));
129 static int sidcmp __PR((struct sid *sid1, struct sid *sid2));
130 static int getadel __PR((struct packet *pkt, struct deltab *dt));
131 static FILE * maket __PR((char *file));
132 static void printfile __PR((char *file));
133 static int read_mod __PR((struct packet *pkt));
134 static void getbody __PR((struct sid *gsid, struct packet *pkt));
135 static void getit __PR((char *str, char *cp));
136 static void aux_create __PR((FILE *iop, char *file, int delchar));
137 #if defined(BUG_1205145) || defined(GMT_TIME)
138 static void prs_idsetup __PR((struct sid *gsid, struct packet *pkt, struct deltab *dt));
139 #else
140 static void prs_idsetup __PR((struct sid *gsid, struct packet *pkt, time_t *bdate));
141 #endif
142 static void putmr __PR((char *cp));
143 static void putsx __PR((char *cp));
144 static void putcom __PR((char *cp));
145 static void read_to __PR((int ch, struct packet *pkt));
146 static void printflags __PR((void));
147 static void ck_spec __PR((char *p));
148
149 int
main(argc,argv)150 main(argc, argv)
151 int argc;
152 char *argv[];
153 {
154 register int j;
155 register char *p;
156 int c;
157 int strlength = 0;
158 extern int Fcnt;
159 int current_optind;
160 int no_arg;
161 /*
162 * Set locale for all categories.
163 */
164 setlocale(LC_ALL, NOGETTEXT(""));
165
166 sccs_setinsbase(INS_BASE);
167
168 /*
169 * Set directory to search for general l10n SCCS messages.
170 */
171 #ifdef PROTOTYPES
172 (void) bindtextdomain(NOGETTEXT("SUNW_SPRO_SCCS"),
173 NOGETTEXT(INS_BASE "/" SCCS_BIN_PRE "lib/locale/"));
174 #else
175 (void) bindtextdomain(NOGETTEXT("SUNW_SPRO_SCCS"),
176 NOGETTEXT("/usr/ccs/lib/locale/"));
177 #endif
178
179 (void) textdomain(NOGETTEXT("SUNW_SPRO_SCCS"));
180
181 tzset(); /* Set up timezome related vars */
182
183 #ifdef SCHILY_BUILD
184 save_args(argc, argv);
185 #endif
186 /*
187 Set flags for 'fatal' to issue message, call clean-up
188 routine, and terminate processing.
189 */
190 set_clean_up(clean_up);
191 Fflags = FTLMSG | FTLCLN | FTLEXIT;
192 #ifdef SCCS_FATALHELP
193 Fflags |= FTLFUNC;
194 Ffunc = sccsfatalhelp;
195 #endif
196
197 /*
198 The following loop processes keyletters and arguments.
199 Note that these are processed only once for each
200 invocation of 'main'.
201 */
202
203 current_optind = 1;
204 optind = 1;
205 opterr = 0;
206 no_arg = 0;
207 j = 1;
208 /*CONSTCOND*/
209 while (1) {
210 if (current_optind < optind) {
211 current_optind = optind;
212 argv[j] = 0;
213 if (optind > j+1) {
214 if ((argv[j+1][0] != '-') && (no_arg == 0)) {
215 argv[j+1] = NULL;
216 } else {
217 optind = j+1;
218 current_optind = optind;
219 }
220 }
221 }
222 no_arg = 0;
223 j = current_optind;
224 c = getopt(argc, argv, "()-d:r:c:ealqN:X:V(version)");
225
226 /* this takes care of options given after
227 ** file names.
228 */
229 if (c == EOF) {
230 if (optind < argc) {
231 /* if it's due to -- then break; */
232 if (argv[j][0] == '-' &&
233 argv[j][1] == '-') {
234 argv[j] = 0;
235 break;
236 }
237 optind++;
238 current_optind = optind;
239 continue;
240 } else {
241 break;
242 }
243 }
244 p = optarg;
245 switch (c) {
246 case 'r': /* specified SID */
247 if (argv[j][2] == '\0') {
248 if (*(omit_sid(p)) != '\0') {
249 no_arg = 1;
250 continue;
251 }
252 }
253 chksid(sid_ab(p, &sid), &sid);
254 break;
255 case 'c': /* cutoff date[time] */
256 if ((*p) && (mystrptime(p, &Date_time, 0) != -1)) {
257 break;
258 } else {
259 fatal(gettext("invalid cutoff date (prs4)"));
260 }
261 /*FALLTHRU*/
262 case 'l': /* later than specified SID */
263 case 'e': /* earlier than specified SID */
264 case 'a': /* print all delta types (R or D) */
265 if (p) {
266 if (*p) {
267 sprintf(SccsError,
268 gettext("value after %c arg (cm7)"),
269 c);
270 fatal(SccsError);
271 }
272 }
273 break;
274 case 'd': /* dataspec line */
275 if (*p) {
276 strlength = strlen(p);
277 if ((p[strlength-2] == '\\') &&
278 (p[strlength-1] == 'n'))
279 p[strlength-2] = '\0';
280 dataspec = p;
281 }
282 break;
283 case 'q': /* enable NSE mode */
284 if (p) {
285 if (*p) {
286 nsedelim = p;
287 }
288 } else {
289 nsedelim = (char *) 0;
290 }
291 break;
292
293 case 'N': /* Bulk names */
294 initN(&N);
295 if (optarg == argv[j+1]) {
296 no_arg = 1;
297 break;
298 }
299 N.n_parm = p;
300 break;
301
302 case 'X': /* -Xtended options */
303 X.x_parm = optarg;
304 X.x_flags = XO_NULLPATH;
305 if (!parseX(&X))
306 goto err;
307 had[NLOWER+c-'A'] = 0; /* Allow mult -X */
308 break;
309
310 case 'V': /* version */
311 printf(gettext(
312 "prs %s-SCCS version %s %s (%s-%s-%s)\n"),
313 PROVIDER,
314 VERSION,
315 VDATE,
316 HOST_CPU, HOST_VENDOR, HOST_OS);
317 exit(EX_OK);
318
319 default:
320 err:
321 fatal(gettext("Usage: prs [ -ael ][ -c date-time ][ -d dataspec ]\n\t[ -r SID ][ -N[bulk-spec]][ -Xxopts ] s.filename ..."));
322 }
323
324 /*
325 * Make sure that we only collect option letters from
326 * the range 'a'..'z' and 'A'..'Z'.
327 */
328 if (ALPHA(c) &&
329 (had[LOWER(c)? c-'a' : NLOWER+c-'A']++)) {
330 if (c != 'X')
331 fatal(gettext("key letter twice (cm2)"));
332 }
333 }
334
335 for (j = 1; j < argc; j++) {
336 if (argv[j]) {
337 num_files++;
338 }
339 }
340
341 if (num_files == 0)
342 fatal(gettext("missing file arg (cm3)"));
343
344 if (HADR && HADC)
345 fatal(gettext("can't specify cutoff date and SID (prs5)"));
346 if (HADC && (!HADL) && (!HADE))
347 fatal(gettext("must specify -e or -l with -c (prs6)"));
348 /*
349 if (!HADD)
350 HADD = 1;
351 */
352
353 setsig();
354 xsethome(NULL);
355 if (HADUCN) { /* Parse -N args */
356 parseN(&N);
357
358 if (N.n_sdot && (sethomestat & SETHOME_OFFTREE))
359 fatal(gettext("-Ns. not supported in off-tree project mode"));
360 }
361
362 /*
363 check the dataspec line and determine if any tmp files
364 need be created
365 */
366 ck_spec(dataspec);
367
368 /*
369 Change flags for 'fatal' so that it will return to this
370 routine (main) instead of terminating processing.
371 */
372 Fflags &= ~FTLEXIT;
373 Fflags |= FTLJMP;
374
375 /*
376 Call 'process' routine for each file argument.
377 */
378 for (j = 1; j < argc; j++)
379 if ((p = argv[j]) != NULL)
380 do_file(p, process, 1, N.n_sdot, &X);
381
382 return (Fcnt ? 1 : 0);
383 }
384
385
386 /*
387 * This procedure opens the SCCS file and calls all subsequent
388 * modules to perform 'prs'. Once the file is finished, process
389 * returns to 'main' to process any other possible files.
390 */
391
392 static void
process(file)393 process(file)
394 register char *file;
395 {
396 if (setjmp(Fjmp)) /* set up to return here from 'fatal' */
397 return; /* and return to caller of 'process' */
398 if (HADUCN) {
399 #ifdef __needed__
400 char *ofile = file;
401 #endif
402
403 file = bulkprepare(&N, file);
404 if (file == NULL) {
405 #ifdef __needed__
406 if (N.n_ifile)
407 ofile = N.n_ifile;
408 #endif
409 /*
410 * The error is typically
411 * "directory specified as s-file (cm14)"
412 */
413 fatal(gettext(bulkerror(&N)));
414 }
415 if (sid.s_rel == 0 && N.n_sid.s_rel != 0) {
416 sid.s_rel = N.n_sid.s_rel;
417 sid.s_lev = N.n_sid.s_lev;
418 sid.s_br = N.n_sid.s_br;
419 sid.s_seq = N.n_sid.s_seq;
420 }
421 }
422
423 sinit(&gpkt, file, SI_OPEN); /* init packet and open SCCS file */
424
425 /*
426 move value of global sid into gpkt.p_reqsid for
427 later comparision.
428 */
429
430 gpkt.p_reqsid = sid;
431
432 gpkt.p_reopen = 1; /* set reopen flag to 1 for 'getline' */
433
434 /*
435 Read delta table entries checking for format error and
436 setting the value for the SID if none was specified.
437 Also check to see if SID specified does in fact exists.
438 */
439
440 deltblchk(&gpkt);
441 /*
442 create auxiliary file for User Name Section
443 */
444
445 if (HAD_UN)
446 aux_create(UNiop, untmp, EUSERNAM);
447 else read_to(EUSERNAM, &gpkt);
448
449 /*
450 store flags (if any) into array called 'gpkt.p_sflags'
451 */
452
453 doflags(&gpkt);
454
455 /*
456 * If there are SCCS v6 flags or SCCS v6 global meta data,
457 * we need to skip this here.
458 * XXX In order to be able to print this data, we need to
459 * XXX parse this block instead of just skipping it.
460 */
461 donamedflags(&gpkt);
462 dometa(&gpkt);
463 if (gpkt.p_line != NULL &&
464 gpkt.p_line[0] == CTLCHAR && gpkt.p_line[1] != BUSERTXT)
465 read_to(BUSERTXT, &gpkt);
466
467 /*
468 create auxiliary file for the User Text section
469 */
470
471 if (HAD_FD)
472 aux_create(UTiop, uttmp, EUSERTXT);
473 else read_to(EUSERTXT, &gpkt);
474
475 /*
476 indicate to 'getline' that EOF is okay
477 */
478
479 gpkt.p_chkeof = 1;
480
481 /*
482 read body of SCCS file and create temp file for it
483 */
484
485 while (read_mod(&gpkt))
486 ;
487
488 /*
489 Here, file has already been re-opened (by 'getline' after
490 EOF was encountered by 'read_mod' calling 'getline')
491 */
492
493 getline(&gpkt); /* skip over header line */
494
495 if (!HADD && !HADR && !HADE && !HADL)
496 HADE = 1;
497 if (!HADD)
498 printf("%s:\n\n", file);
499
500 /*
501 call 'dodeltbl' to read delta table entries
502 and determine which deltas are to be considered
503 */
504
505 dodeltbl(&gpkt);
506
507 /*
508 call 'clean_up' to remove any temporary file created
509 during processing of the SCCS file passed as an argument from
510 'do_file'
511 */
512
513 clean_up();
514
515 /* return to caller of 'process' */
516 }
517
518
519 /*
520 * This procedure actually reads the delta table entries and
521 * substitutes pre-defined strings and pointers with the information
522 * needed during the scanning of the 'dataspec' line
523 */
524
525 static void
dodeltbl(pkt)526 dodeltbl(pkt)
527 register struct packet *pkt;
528 {
529 char *n;
530 int stopdel;
531 int found;
532 long dcomp;
533 struct deltab dt;
534 struct stats stats;
535
536 /*
537 flags used during determination of deltas to be
538 considered
539 */
540
541 found = stopdel = 0;
542
543 /*
544 Read entire delta table.
545 */
546 while (getstats(pkt, &stats) && !stopdel) {
547 if (getadel(pkt, &dt) != BDELTAB)
548 fmterr(pkt);
549
550 /*
551 ignore 'removed' deltas if !HADA keyletter
552 */
553
554 if (!HADA && (dt.d_type != 'D' && dt.d_type != 'U')) {
555 read_to(EDELTAB, pkt);
556 continue;
557 }
558
559 /*
560 determine whether or not to consider current delta
561 */
562
563 if (HADC) {
564 get_Del_Date_time(pkt->p_line, &dt, pkt, &Del_Date_time);
565 dcomp = cmpdate(&Date_time, &Del_Date_time);
566 if (HADE && !HADL && (dcomp < 0)) {
567 read_to(EDELTAB, pkt);
568 continue;
569 } else if (HADL && !HADE && (dcomp > 0)) {
570 stopdel = 1;
571 continue;
572 }
573 } else if (HADE && HADL)
574 stopdel = 0;
575
576 else if (!(eqsid(&gpkt.p_reqsid, &dt.d_sid)) && !found) {
577 /*
578 if !HADL keyletter skip delta entry
579 */
580 if (!HADL) {
581 read_to(EDELTAB, pkt);
582 continue;
583 }
584 } else {
585 found = 1;
586 stopdel = 1;
587 }
588 /*
589 if HADE keyletter read remainder of delta table entries
590 */
591 if (HADE && stopdel)
592 stopdel = 0;
593 /*
594 create temp file for MRs and comments
595 */
596 if (HAD_MR)
597 MRiop = maket(mrtmp);
598 if (HAD_CM)
599 CMiop = maket(cmtmp);
600 if (HAD_SX)
601 SXiop = maket(sxtmp);
602 /*
603 Read rest of delta entry.
604 */
605 while ((n = getline(pkt)) != NULL)
606 if (pkt->p_line[0] != CTLCHAR)
607 break;
608 else {
609 switch (pkt->p_line[1]) {
610 case INCLUDE:
611 getit(iline, n);
612 continue;
613 case EXCLUDE:
614 getit(xline, n);
615 continue;
616 case IGNORE:
617 getit(gline, n);
618 continue;
619 case MRNUM:
620 if (HAD_MR)
621 putmr(n);
622 continue;
623 case SIDEXTENS:
624 if (HAD_SX)
625 putsx(n);
626 continue;
627 case COMMENTS:
628 if (HAD_CM)
629 putcom(n);
630 continue;
631 case EDELTAB:
632 /*
633 close temp files for MRs and comments
634 */
635 if (HAD_MR) {
636 if (MRiop)
637 fclose(MRiop);
638 MRiop = NULL;
639 }
640 if (HAD_CM) {
641 if (CMiop)
642 fclose(CMiop);
643 CMiop = NULL;
644 }
645 if (HAD_SX) {
646 if (SXiop)
647 fclose(SXiop);
648 SXiop = NULL;
649 }
650 scanspec(dataspec, &dt, &stats);
651 /*
652 remove temp files for MRs and comments
653 */
654 unlink(mrtmp);
655 unlink(cmtmp);
656 unlink(sxtmp);
657 break;
658 default:
659 fmterr(pkt);
660 }
661 break;
662 }
663 if (n == NULL || pkt->p_line[0] != CTLCHAR)
664 fmterr(pkt);
665 }
666 }
667
668
669 /*
670 * The scanspec procedure scans the dataspec searching for ID keywords.
671 * When a keyword is found the value is replaced and printed on the
672 * standard output. Any character that is not an ID keyword is printed
673 * immediately.
674 */
675
676 static char Zkywd[5] = "@(#)";
677
678 static void
scanspec(spec,dtp,statp)679 scanspec(spec, dtp, statp)
680 char spec[];
681 struct deltab *dtp;
682 struct stats *statp;
683 {
684
685 register char *lp;
686 register char *k;
687
688 int istr;
689 register char c;
690
691 istr = 0;
692
693 /*
694 call 'idsetup' to set certain data keywords for
695 'scanspec' substitution
696 */
697 #if defined(BUG_1205145) || defined(GMT_TIME)
698 prs_idsetup(&dtp->d_sid, &gpkt, dtp);
699 #else
700 prs_idsetup(&dtp->d_sid, &gpkt, &dtp->d_dtime.dt_sec);
701 #endif
702
703 /*
704 scan 'dataspec' line
705 */
706 for (lp = spec; *lp != 0; lp++) {
707 if (lp[0] == ':' && lp[1] != 0 && lp[2] == ':') {
708 c = *++lp;
709 switch (c) {
710 case 'I': /* SID */
711 printf("%s", Sid);
712 break;
713 case 'R': /* Release number */
714 printf("%d", dtp->d_sid.s_rel);
715 break;
716 case 'L': /* Level number */
717 printf("%d", dtp->d_sid.s_lev);
718 break;
719 case 'B': /* Branch number */
720 if (dtp->d_sid.s_br != 0)
721 printf("%d", dtp->d_sid.s_br);
722 break;
723 case 'S': /* Sequence number */
724 if (dtp->d_sid.s_seq != 0)
725 printf("%d", dtp->d_sid.s_seq);
726 break;
727 case 'D': /* Date delta created */
728 printf("%s", Deltadate);
729 break;
730 case 'd': /* Date delta created (4 digit year) */
731 printf("%s", Deltadatel);
732 break;
733 case 'T': /* Time delta created */
734 printf("%s", Deltatime);
735 break;
736 case 'P': /* Programmer who created delta */
737 printf("%s", dtp->d_pgmr);
738 break;
739 case 'C': /* Comments */
740 if (exists(cmtmp))
741 printfile(cmtmp);
742 break;
743 case 'Y': /* Type flag */
744 printf("%s", Type);
745 break;
746 case 'Q': /* csect flag */
747 printf("%s", Qsect);
748 break;
749 case 'J': /* joint edit flag */
750 if (gpkt.p_sflags[JOINTFLAG - 'a'])
751 printf(gettext("yes"));
752 else printf(gettext("no"));
753 break;
754 case 'M': /* Module name */
755 printf("%s", Mod);
756 break;
757 case 'W': /* Form of what string */
758 printf("%s%s\t%s", Zkywd, Mod, Sid);
759 break;
760 case 'A': /* Form of what string */
761 printf("%s%s %s %s%s", Zkywd, Type, Mod, Sid, Zkywd);
762 break;
763 case 'Z': /* what string constructor */
764 printf("%s", Zkywd);
765 break;
766 case 'F': /* File name */
767 printf("%s", sname(gpkt.p_file));
768 break;
769 case 'G': /* Basename of g-file */
770 printf("%s", auxf(gpkt.p_file, 'g'));
771 break;
772 default:
773 putchar(':');
774 --lp;
775 continue;
776 }
777 lp++;
778 } else if (lp[0] == ':' && lp[1] != 0 && lp[2] != 0 && lp[3] == ':') {
779 if (lp[1] == ':') {
780 putchar(':');
781 continue;
782 }
783 istr = *++lp;
784 istr += 256 * (*++lp);
785
786 switch (istr) {
787 case 256*'L'+'D': /* :DL: Delta line statistics */
788 printf("%.05d", statp->s_ins);
789 putchar('/');
790 printf("%.05d", statp->s_del);
791 putchar('/');
792 printf("%.05d", statp->s_unc);
793 break;
794 case 256*'i'+'L': /* :Li: Lines inserted by delta */
795 printf("%.05d", statp->s_ins);
796 break;
797 case 256*'d'+'L': /* :Ld: Lines deleted by delta */
798 printf("%.05d", statp->s_del);
799 break;
800 case 256*'u'+'L': /* :Lu: Lines unchanged by delta */
801 printf("%.05d", statp->s_unc);
802 break;
803 case 256*'T'+'D': /* :DT: Delta type */
804 printf("%c", dtp->d_type);
805 break;
806 case 256*'y'+'D': /* :Dy: Year delta created */
807 if (Dtime->tm_year >= 100) {
808 Dtime->tm_year %= 100;
809 }
810 printf("%02d", Dtime->tm_year);
811 break;
812 case 256*'Y'+'D': /* :DY: Year delta created */
813 Dtime->tm_year += 1900;
814 printf("%4d", Dtime->tm_year); /* 4 digits */
815 break;
816 case 256*'_'+'D': /* :D_: Date delta created y-m-d */
817 Deltadatel[4] = '-';
818 Deltadatel[7] = '-';
819 printf("%s", Deltadatel);
820 Deltadatel[4] = '/';
821 Deltadatel[7] = '/';
822 break;
823 case 256*'m'+'D': /* :Dm: Month delta created */
824 printf("%02d", (Dtime->tm_mon + 1));
825 break;
826 case 256*'d'+'D': /* :Dd: Day delta created */
827 printf("%02d", Dtime->tm_mday);
828 break;
829 case 256*'h'+'T': /* :Th: Hour delta created */
830 printf("%02d", Dtime->tm_hour);
831 break;
832 case 256*'m'+'T': /* :Tm: Minutes delta created */
833 printf("%02d", Dtime->tm_min);
834 break;
835 case 256*'s'+'T': /* :Ts: Seconds delta created */
836 printf("%02d", Dtime->tm_sec);
837 break;
838 case 256*'S'+'D': /* :DS: Delta sequence number */
839 printf("%d", dtp->d_serial);
840 break;
841 case 256*'P'+'D': /* :DP: Predecessor delta sequence number */
842 printf("%d", dtp->d_pred);
843 break;
844 case 256*'I'+'D': /* :DI: Deltas included,excluded,ignored */
845 #ifdef ATT_BUG
846 /*
847 * This has been introduced around 1984.
848 */
849 printf("%s", iline);
850 if (length(xline))
851 printf("/%s", xline);
852 if (length(gline))
853 printf("/%s", gline);
854 #else
855 /*
856 * This is the POSIX compliant behavior.
857 */
858 printf("%s", iline);
859 printf("/%s", xline);
860 printf("/%s", gline);
861 #endif
862 break;
863 case 256*'n'+'D': /* :Dn: Deltas included */
864 printf("%s", iline);
865 break;
866 case 256*'x'+'D': /* :Dx: Deltas excluded */
867 printf("%s", xline);
868 break;
869 case 256*'g'+'D': /* :Dg: Deltas ignored */
870 printf("%s", gline);
871 break;
872 case 256*'K'+'L': /* :LK: locked releases */
873 if ((k = gpkt.p_sflags[LOCKFLAG - 'a']) != NULL)
874 printf("%s", k);
875 else printf(gettext("none"));
876 break;
877 case 256*'R'+'M': /* :MR: MR numbers */
878 if (exists(mrtmp))
879 printfile(mrtmp);
880 break;
881 case 256*'C'+'M': /* :MC: cmf flag yes or no */
882 if (gpkt.p_sflags[CMFFLAG - 'a'])
883 printf(gettext("yes"));
884 else
885 printf(gettext("no"));
886 break;
887 case 256*'X'+'S': /* :SX: SID Extensions */
888 if (exists(sxtmp))
889 printfile(sxtmp);
890 break;
891 case 256*'C'+'A': /* :AC: cmf application field */
892 if ((k = gpkt.p_sflags[CMFFLAG - 'a']) == NULL)
893 printf(gettext("none"));
894 else
895 printf("%s", k);
896 break;
897 case 256*'N'+'U': /* :UN: User names */
898 if (exists(untmp))
899 printfile(untmp);
900 break;
901 case 256*'F'+'M': /* :MF: MR validation flag */
902 if (gpkt.p_sflags[VALFLAG - 'a'])
903 printf(gettext("yes"));
904 else printf(gettext("no"));
905 break;
906 case 256*'P'+'M': /* :MP: MR validation program */
907 if ((k = gpkt.p_sflags[VALFLAG - 'a']) == NULL)
908 printf(gettext("none"));
909 else printf("%s", k);
910 break;
911 case 256*'F'+'K': /* :KF: Keyword err/warn flag */
912 if (gpkt.p_sflags[IDFLAG - 'a'])
913 printf(gettext("yes"));
914 else printf(gettext("no"));
915 break;
916 case 256*'F'+'B': /* :BF: Branch flag */
917 if (gpkt.p_sflags[BRCHFLAG - 'a'])
918 printf(gettext("yes"));
919 else printf(gettext("no"));
920 break;
921 case 256*'B'+'F': /* :FB: Floor Boundry */
922 if ((k = gpkt.p_sflags[FLORFLAG - 'a']) != NULL)
923 printf("%s", k);
924 else printf(gettext("none"));
925 break;
926 case 256*'B'+'C': /* :CB: Ceiling Boundry */
927 if ((k = gpkt.p_sflags[CEILFLAG - 'a']) != NULL)
928 printf("%s", k);
929 else printf(gettext("none"));
930 break;
931 case 256*'s'+'D': /* :Ds: Default SID */
932 if ((k = gpkt.p_sflags[DEFTFLAG - 'a']) != NULL)
933 printf("%s", k);
934 else printf(gettext("none"));
935 break;
936 case 256*'D'+'N': /* :ND: Null delta */
937 if (gpkt.p_sflags[NULLFLAG - 'a'])
938 printf(gettext("yes"));
939 else printf(gettext("no"));
940 break;
941 case 256*'D'+'F': /* :FD: File descriptive text */
942 if (exists(uttmp))
943 printfile(uttmp);
944 break;
945 case 256*'D'+'B': /* :BD: Entire file body */
946 if (exists(bdtmp))
947 printfile(bdtmp);
948 break;
949 case 256*'B'+'G': /* :GB: Gotten body from 'get' */
950 getbody(&dtp->d_sid, &gpkt);
951 break;
952 case 256*'N'+'P': /* :PN: Full pathname of File */
953 copy(gpkt.p_file, Dir);
954 dname(Dir);
955 if (getcwd(Olddir, sizeof (Olddir)) == NULL)
956 efatal(gettext("getcwd() failed (prs2)"));
957 if (chdir(Dir) != 0)
958 efatal(gettext("cannot change directory (prs3)"));
959 if (getcwd(Pname, sizeof (Pname)) == NULL)
960 efatal(gettext("getcwd() failed (prs2)"));
961 if (chdir(Olddir) != 0)
962 efatal(gettext("cannot change directory (prs3)"));
963 printf("%s/", Pname);
964 printf("%s", sname(gpkt.p_file));
965 break;
966 case 256*'L'+'F': /* :FL: Flag descriptions (as in 'prt') */
967 printflags();
968 break;
969 case 256*'t'+'D': /* :Dt: Whole delta table line */
970 /*
971 replace newline with null char to make
972 data keyword simple format
973 */
974 repl(dt_line, '\n', '\0');
975 k = dt_line;
976 /*
977 skip control char, line flag, and blank
978 */
979 k += 3;
980 printf("%s", k);
981 break;
982 case 256*'p'+'G': /* :Gp: V6 Initial Path */
983 if (gpkt.p_init_path)
984 printf("%s", gpkt.p_init_path);
985 break;
986 case 256*'r'+'G': { /* :Gr: V6 Unified Random */
987 char rbuf[64];
988 urand_ba(&gpkt.p_rand, rbuf, sizeof (rbuf));
989 printf("%s", rbuf);
990 break;
991 }
992 default:
993 putchar(':');
994 lp -= 2;
995 continue;
996 }
997 lp++;
998 } else {
999 c = *lp;
1000 if (c == '\\') {
1001 switch (*++lp) {
1002 case 'n': /* for newline */
1003 putchar('\n');
1004 break;
1005 case ':': /* for wanted colon */
1006 putchar(':');
1007 break;
1008 case 't': /* for tab */
1009 putchar('\t');
1010 break;
1011 case 'b': /* for backspace */
1012 putchar('\b');
1013 break;
1014 case 'r': /* for carriage return */
1015 putchar('\r');
1016 break;
1017 case 'f': /* for form feed */
1018 putchar('\f');
1019 break;
1020 case '\\': /* for backslash */
1021 putchar('\\');
1022 break;
1023 case '\'': /* for single quote */
1024 putchar('\'');
1025 break;
1026 default: /* unknown case */
1027 putchar('\\');
1028 putchar(*lp);
1029 break;
1030 }
1031 } else
1032 putchar(*lp);
1033 }
1034 }
1035 /*
1036 zero out first char of global string lines in case
1037 a value is not gotten in next delta table entry
1038 */
1039 iline[0] = xline[0] = gline[0] = 0;
1040 putchar('\n');
1041 }
1042
1043
1044 /*
1045 * This procedure cleans up all temporary files created during
1046 * 'process' that are used for data keyword substitution
1047 */
1048
1049 static void
clean_up()1050 clean_up()
1051 {
1052 sclose(&gpkt); /* if SCCS file is open, close it */
1053 sfree(&gpkt); /* free line buffer */
1054 xrm(&gpkt); /* remove the 'packet' used for this SCCS file */
1055 unlink(mrtmp); /* remove all temporary files from /tmp */
1056 unlink(cmtmp); /* " */
1057 unlink(sxtmp); /* " */
1058 unlink(untmp); /* " */
1059 unlink(uttmp); /* " */
1060 unlink(bdtmp); /* " */
1061 ffreeall();
1062 }
1063
1064
1065 /*
1066 * This procedure checks the delta table entries for correct format.
1067 * It also checks to see if the SID specified by the -r keyletter
1068 * is contained in the file. If no SID was specified assumes the top
1069 * delta created (last in time).
1070 */
1071
1072 static void
deltblchk(pkt)1073 deltblchk(pkt)
1074 register struct packet *pkt;
1075 {
1076 char *n;
1077 int found;
1078 struct deltab dt;
1079 struct deltab odt; /* Old delta */
1080 struct stats stats;
1081
1082 odt.d_sid.s_rel = 0;
1083 odt.d_sid.s_lev = 0;
1084 odt.d_sid.s_br = 0;
1085 odt.d_sid.s_seq = 0;
1086 found = 0;
1087 /*
1088 Read entire delta table.
1089 */
1090 while (getstats(pkt, &stats)) {
1091 if (getadel(pkt, &dt) != BDELTAB)
1092 fmterr(pkt);
1093
1094 /*
1095 ignore if "removed" delta
1096 */
1097 if (!HADA && (dt.d_type != 'D' && dt.d_type != 'U')) {
1098 read_to(EDELTAB, pkt);
1099 continue;
1100 }
1101
1102 if (!HADR && (pkt->p_reqsid.s_rel == 0)) {
1103 if (!found)
1104 odt.d_sid = dt.d_sid;
1105 found = 1;
1106 } else if (pkt->p_reqsid.s_rel == 0) {
1107 if (sidcmp(&odt.d_sid, &dt.d_sid) < 0)
1108 odt.d_sid = dt.d_sid;
1109 } else if (pkt->p_reqsid.s_lev == 0) {
1110 if ((pkt->p_reqsid.s_rel >= dt.d_sid.s_rel) &&
1111 (sidcmp(&odt.d_sid, &dt.d_sid) < 0))
1112 odt.d_sid = dt.d_sid;
1113 } else if ((pkt->p_reqsid.s_br == 0) && !found) {
1114 if (!(sidcmp(&pkt->p_reqsid, &dt.d_sid))) {
1115 found = 1;
1116 odt.d_sid = dt.d_sid;
1117 }
1118 } else if (pkt->p_reqsid.s_seq == 0) {
1119 if ((pkt->p_reqsid.s_rel == dt.d_sid.s_rel) &&
1120 (pkt->p_reqsid.s_lev == dt.d_sid.s_lev) &&
1121 (pkt->p_reqsid.s_br == dt.d_sid.s_br) &&
1122 (sidcmp(&odt.d_sid, &dt.d_sid) < 0))
1123 odt.d_sid = dt.d_sid;
1124 } else if (!found) {
1125 if (!(sidcmp(&pkt->p_reqsid, &dt.d_sid))) {
1126 found = 1;
1127 odt.d_sid = dt.d_sid;
1128 }
1129 }
1130
1131 /*
1132 Read rest of delta entry.
1133 */
1134 while ((n = getline(pkt)) != NULL)
1135 if (pkt->p_line[0] != CTLCHAR)
1136 break;
1137 else {
1138 switch (pkt->p_line[1]) {
1139 case EDELTAB:
1140 break;
1141 case INCLUDE:
1142 case EXCLUDE:
1143 case IGNORE:
1144 case MRNUM:
1145 case SIDEXTENS:
1146 case COMMENTS:
1147 continue;
1148 default:
1149 fmterr(pkt);
1150 }
1151 break;
1152 }
1153 if (n == NULL || pkt->p_line[0] != CTLCHAR)
1154 fmterr(pkt);
1155 }
1156 /*
1157 if not at the beginning of the User Name section
1158 there is an internal error
1159 */
1160 if (pkt->p_line[1] != BUSERNAM)
1161 fmterr(pkt);
1162 /*
1163 if SID did not exist (the one specified by -r keyletter)
1164 then there exists an error
1165 */
1166 if (odt.d_sid.s_rel == 0)
1167 fatal(gettext("nonexistent SID (prs1)"));
1168 else
1169 gpkt.p_reqsid = odt.d_sid;
1170 }
1171
1172
1173 /*
1174 * This procedure reads the stats line from the delta table entry
1175 * and places the statisitics into a structure called "stats".
1176 */
1177
1178 static int
getstats(pkt,statp)1179 getstats(pkt, statp)
1180 register struct packet *pkt;
1181 register struct stats *statp;
1182 {
1183 register char *p = getline(pkt);
1184
1185 if (p == NULL || *p++ != CTLCHAR || *p++ != STATS)
1186 return (0);
1187 NONBLANK(p);
1188 p = satoi(p, &statp->s_ins);
1189 p = satoi(++p, &statp->s_del);
1190 satoi(++p, &statp->s_unc);
1191 return (1);
1192 }
1193
1194 /*
1195 * This routine compares to SIDs numerically.
1196 */
1197
1198 static int
sidcmp(sid1,sid2)1199 sidcmp(sid1, sid2)
1200 struct sid *sid1, *sid2;
1201
1202 {
1203 int diff = 0;
1204
1205 if ((diff = (sid1->s_rel - sid2->s_rel)) != 0)
1206 return (diff);
1207 if ((diff = (sid1->s_lev - sid2->s_lev)) != 0)
1208 return (diff);
1209 if ((diff = (sid1->s_br - sid2->s_br)) != 0)
1210 return (diff);
1211
1212 return (sid1->s_seq - sid2->s_seq);
1213 }
1214 /*
1215 * This procedure reads a delta table entry line from the delta
1216 * table entry and places the contents of the line into a structure
1217 * called "deltab".
1218 */
1219
1220 static int
getadel(pkt,dt)1221 getadel(pkt, dt)
1222 register struct packet *pkt;
1223 register struct deltab *dt;
1224 {
1225 if (getline(pkt) == NULL)
1226 fmterr(pkt);
1227 #if !(defined(BUG_1205145) || defined(GMT_TIME))
1228 copy(pkt->p_line, dt_line); /* copy delta table line for :Dt: keywd */
1229 #endif
1230 return (del_ab(pkt->p_line, dt, pkt));
1231 }
1232
1233
1234 /*
1235 * This procedure creates the temporary file used during the
1236 * "process" subroutine. The skeleton defined at the beginning
1237 * of the program is filled in in this function
1238 */
1239 static FILE *
maket(file)1240 maket(file)
1241 char *file;
1242 {
1243 FILE *iop;
1244 mode_t cur_umask;
1245
1246 copy(tempskel, file); /* copy file name into the skeleton */
1247 /* umask 0133 -> create mode 0644 */
1248 cur_umask = umask((mode_t)((S_IRWXU|S_IRWXG|S_IRWXO)&~(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)));
1249 #ifdef HAVE_MKSTEMP
1250 iop = fdfopen(mkstemp(file), O_WRONLY|O_BINARY);
1251 #else
1252 iop = xfcreat(mktemp(file), 0644);
1253 #endif
1254 #ifdef NEED_O_BINARY
1255 if (iop != NULL)
1256 setmode(fileno(iop), O_BINARY);
1257 #endif
1258 (void) umask(cur_umask);
1259
1260 return (iop);
1261 }
1262
1263
1264 /*
1265 * This procedure prints (on the standard output) the contents of any
1266 * temporary file that may have been created during "process".
1267 */
1268
1269 static void
printfile(file)1270 printfile(file)
1271 register char *file;
1272 {
1273 #ifdef __historic__
1274 register char *p;
1275 #else
1276 register size_t amt;
1277 #endif
1278 FILE *iop;
1279
1280 iop = xfopen(file, O_RDONLY|O_BINARY);
1281 #ifdef __historic__
1282 while ((p = fgets(line, sizeof (line), iop)) != NULL)
1283 printf("%s", p);
1284 #else
1285 while ((amt= fread(line, 1, sizeof (line), iop)) > 0)
1286 fwrite(line, 1, amt, stdout);
1287 #endif
1288 fclose(iop);
1289 }
1290
1291
1292 /*
1293 * This procedure reads the body of the SCCS file from beginning to end.
1294 * It also creates the temporary file /tmp/prbdtmp which contains
1295 * the body of the SCCS file for data keyword substitution.
1296 */
1297
1298 static int
read_mod(pkt)1299 read_mod(pkt)
1300 register struct packet *pkt;
1301 {
1302 register char *p;
1303 int ser;
1304 int iod;
1305
1306 if (HAD_BD)
1307 BDiop = maket(bdtmp);
1308 while (getline(pkt) != NULL) {
1309 p = pkt->p_line;
1310 if (HAD_BD) {
1311 #ifdef __historic__
1312 if (fputs(p, BDiop) == EOF) {
1313 xmsg(bdtmp, NOGETTEXT("read_mod"));
1314 #else
1315 if (fwrite(p, 1, pkt->p_line_length, BDiop) == EOF) {
1316 xmsg(bdtmp, NOGETTEXT("read_mod"));
1317 #endif
1318 }
1319 }
1320 if (*p++ != CTLCHAR)
1321 continue;
1322 else {
1323 if (!((iod = *p++) == INS || iod == DEL || iod == END)) {
1324 if (iod == CTLCHAR)
1325 continue;
1326 if (iod == NONL)
1327 continue;
1328 fmterr(pkt);
1329 }
1330 NONBLANK(p);
1331 satoi(p, &ser);
1332 if (iod == END)
1333 remq(pkt, ser);
1334 else
1335 addq(pkt, ser, iod == INS ? NO : 0, iod, USER);
1336 }
1337 }
1338 if (HAD_BD) {
1339 if (BDiop)
1340 fclose(BDiop);
1341 BDiop = NULL;
1342 }
1343 if (pkt->p_q)
1344 fatal(gettext("premature eof (co5)"));
1345 return (0);
1346 }
1347
1348
1349 /*
1350 * This procedure is only called if the :GB: data keyword is specified.
1351 * It forks and creates a child process to invoke 'get' with the '-p'
1352 * and '-s' options for the SID currently being processed. Upon
1353 * completion, control of the program is returned to 'prs'.
1354 */
1355
1356 static void
getbody(gsid,pkt)1357 getbody(gsid, pkt)
1358 struct sid *gsid;
1359 struct packet *pkt;
1360 {
1361 int i;
1362 int status;
1363 char str[SID_STRSIZE];
1364 char rarg[SID_STRSIZE+2];
1365 char filearg[80];
1366
1367 sid_ba(gsid, str);
1368 sprintf(rarg, "-r%s", str);
1369 sprintf(filearg, "%s", pkt->p_file);
1370 /*
1371 fork here so 'getbody' can execute 'get' to
1372 print out gotten body :GB:
1373 */
1374 if ((i = vfork()) < 0)
1375 efatal(gettext("cannot fork, try again"));
1376 if (i == 0) {
1377 /*
1378 perform 'get' and redirect output
1379 to standard output
1380 */
1381 #if defined(PROTOTYPES) && defined(INS_BASE)
1382 execlp(Getpgmp, Getpgm, NOGETTEXT("-s"), NOGETTEXT("-p"), rarg, filearg, (char *)0);
1383 #endif
1384 execlp(Getpgm, Getpgm, NOGETTEXT("-s"), NOGETTEXT("-p"), rarg, filearg, (char *)0);
1385 sprintf(SccsError, gettext("cannot execute '%s'"),
1386 Getpgm);
1387 #ifdef HAVE_VFORK
1388 Fflags |= FTLVFORK;
1389 #endif
1390 efatal(SccsError);
1391 } else {
1392 wait(&status);
1393 return;
1394 }
1395 }
1396
1397
1398 /*
1399 * This procedure places the line read in "dodeltbl" into a global string
1400 * 'str'. This procedure is only called for include, exclude or ignore
1401 * lines.
1402 */
1403
1404 static void
getit(str,cp)1405 getit(str, cp)
1406 register char *str, *cp;
1407 {
1408 cp += 2;
1409 NONBLANK(cp);
1410 cp[length(cp) - 1] = '\0';
1411 sprintf(str, "%s", cp);
1412 }
1413
1414
1415 /*
1416 * This procedure creates an auxiliary file for the iop passed as an argument
1417 * for the file name also passed as an argument. If no text exists for the
1418 * named file, an auxiliary file is still created with the text "(none)".
1419 */
1420
1421 static void
aux_create(iop,file,delchar)1422 aux_create(iop, file, delchar)
1423 FILE *iop;
1424 char *file;
1425 char delchar;
1426 {
1427
1428 char *n;
1429 int text;
1430 /*
1431 create auxiliary file for the named section
1432 */
1433
1434 text = 0;
1435 iop = maket(file);
1436 while ((n = getline(&gpkt)) != NULL && gpkt.p_line[0] != CTLCHAR) {
1437 text = 1;
1438 if (fputs(n, iop) == EOF) {
1439 xmsg(file, NOGETTEXT("aux_create"));
1440 }
1441 }
1442 /*
1443 check to see that delimiter found is correct
1444 */
1445 if (n == NULL || gpkt.p_line[0] != CTLCHAR || gpkt.p_line[1] != delchar)
1446 fmterr(&gpkt);
1447 if (!text)
1448 fprintf(iop, gettext("none\n"));
1449 fclose(iop);
1450 }
1451
1452
1453 /*
1454 * This procedure sets the values for certain data keywords which are
1455 * either shared by more than one data keyword or because substitution
1456 * here would be easier than doing it in "scanspec" (more efficient etc.)
1457 */
1458
1459 static void
1460 #if defined(BUG_1205145) || defined(GMT_TIME)
prs_idsetup(gsid,pkt,dt)1461 prs_idsetup(gsid, pkt, dt)
1462 #else
1463 prs_idsetup(gsid, pkt, bdate)
1464 #endif
1465 struct sid *gsid;
1466 struct packet *pkt;
1467 #if defined(BUG_1205145) || defined(GMT_TIME)
1468 struct deltab *dt;
1469 #else
1470 time_t *bdate;
1471 #endif
1472 {
1473
1474 register char *p;
1475
1476 #if defined(BUG_1205145) || defined(GMT_TIME)
1477 Dtime = localtime(&dt->d_dtime.dt_sec);
1478 /*
1479 * Local time corrections before del_ba() and date_ba() calls.
1480 * Because these functions use gmtime() instead of localtime().
1481 * This allows to print the local time for the :Dt: keywd instead
1482 * of the GMT based time from the s-file.
1483 */
1484 dt->d_dtime.dt_sec = mklgmtime(Dtime);
1485
1486 del_ba(dt, dt_line, pkt->p_flags|PF_GMT); /* create delta table line for :Dt: keywd */
1487 date_ba(&dt->d_dtime.dt_sec, Deltadate, 0);
1488 date_bal(&dt->d_dtime.dt_sec, Deltadatel, 0);
1489 #else
1490 date_ba(bdate, Deltadate, 0);
1491 date_bal(bdate, Deltadatel, 0);
1492 #endif
1493 Deltatime = &Deltadate[9];
1494 Deltadate[8] = 0;
1495 Deltadatel[10] = 0;
1496 sid_ba(gsid, Sid);
1497 #if !(defined(BUG_1205145) || defined(GMT_TIME))
1498 Dtime = localtime(bdate);
1499 #endif
1500 if ((p = pkt->p_sflags[MODFLAG - 'a']) != NULL)
1501 copy(p, Mod);
1502 else sprintf(Mod, "%s", auxf(pkt->p_file, 'g'));
1503 if ((Type = pkt->p_sflags[TYPEFLAG - 'a']) == NULL)
1504 Type = Null;
1505 if ((Qsect = pkt->p_sflags[QSECTFLAG - 'a']) == NULL)
1506 Qsect = Null;
1507 }
1508
1509
1510 /*
1511 * This procedure places any MRs that are found in the delta table entry
1512 * into the temporary file created for that express purpose (/tmp/prXXXXXX).
1513 */
1514
1515 static void
putmr(cp)1516 putmr(cp)
1517 register char *cp;
1518 {
1519
1520 cp += 3;
1521
1522 if (!(*cp) || (*cp == '\n')) {
1523 if (MRiop)
1524 fclose(MRiop);
1525 MRiop = NULL;
1526 return;
1527 }
1528
1529 if (fputs(cp, MRiop) == EOF) {
1530 xmsg(mrtmp, NOGETTEXT("putmr"));
1531 }
1532 }
1533
1534
1535 /*
1536 * This procedure places any SID extensions that are found in the delta table
1537 * entry * into the temporary file created for that express purpose
1538 * (/tmp/prXXXXXX).
1539 */
1540 static void
putsx(cp)1541 putsx(cp)
1542 register char *cp;
1543 {
1544
1545 cp += 3;
1546
1547 if (!(*cp) || (*cp == '\n')) {
1548 if (SXiop)
1549 fclose(SXiop);
1550 SXiop = NULL;
1551 return;
1552 }
1553
1554 if (fputs(cp, SXiop) == EOF) {
1555 xmsg(sxtmp, NOGETTEXT("putsx"));
1556 }
1557 }
1558
1559
1560 /*
1561 * This procedure is the same as "putmr" except it is used for the comment
1562 * section of the delta table entries.
1563 */
1564
1565 static void
putcom(cp)1566 putcom(cp)
1567 register char *cp;
1568 {
1569
1570 cp += 3;
1571
1572 if (fputs(cp, CMiop) == EOF) {
1573 xmsg(cmtmp, NOGETTEXT("putcom"));
1574 }
1575 }
1576
1577
1578 /*
1579 * This procedure reads through the SCCS file until a line is found
1580 * containing the character passed as an argument in the 2nd position
1581 * of the line.
1582 */
1583
1584 static void
read_to(ch,pkt)1585 read_to(ch, pkt)
1586 register char ch;
1587 register struct packet *pkt;
1588 {
1589 register char *p;
1590 while (((p = getline(pkt)) != NULL) &&
1591 !(*p++ == CTLCHAR && *p == ch))
1592 ;
1593 }
1594
1595
1596 /*
1597 * This procedure prints a list of all the flags that are present in the
1598 * SCCS file. The format is the same as 'prt' except the flag description
1599 * is not preceeded by a "tab".
1600 */
1601
1602 static void
printflags()1603 printflags()
1604 {
1605 register char *k;
1606 register char **sflags = gpkt.p_sflags;
1607
1608 if (sflags[BRCHFLAG - 'a']) /* check for 'branch' flag */
1609 printf(gettext("branch\n"));
1610 if ((k = (sflags[CEILFLAG - 'a'])) != NULL) /* check for 'ceiling flag */
1611 printf(gettext("ceiling\t%s\n"), k);
1612 if ((k = (sflags[DEFTFLAG - 'a'])) != NULL) /* check for 'default SID' flag */
1613 printf(gettext("default SID\t%s\n"), k);
1614 if ((k = (sflags[ENCODEFLAG - 'a'])) != NULL) { /* check for 'encoded' flag */
1615 int i;
1616
1617 NONBLANK(k);
1618 k = satoi(k, &i);
1619 /*
1620 * The semantics of this flag are unusual: report its
1621 * existence only if an operand with value '1' is present.
1622 * Yes, the test below is sloppy...
1623 */
1624 if (*k == '\0' && (i & EF_UUENCODE))
1625 printf(gettext("encoded\n"));
1626 }
1627 if ((k = (sflags[FLORFLAG - 'a'])) != NULL) /* check for 'floor' flag */
1628 printf(gettext("floor\t%s\n"), k);
1629 if (sflags[IDFLAG - 'a']) /* check for 'id err/warn' flag */
1630 printf(gettext("id keywd err/warn\n"));
1631 if (sflags[JOINTFLAG - 'a']) /* check for joint edit flag */
1632 printf(gettext("joint edit\n"));
1633 if ((k = (sflags[LOCKFLAG - 'a'])) != NULL) /* check for 'lock' flag */
1634 printf(gettext("locked releases\t%s\n"), k);
1635 if ((k = (sflags[MODFLAG - 'a'])) != NULL) /* check for 'module' flag */
1636 printf(gettext("module\t%s\n"), k);
1637 if (sflags[NULLFLAG - 'a']) /* check for 'null delta' flag */
1638 printf(gettext("null delta\n"));
1639 if ((k = (sflags[QSECTFLAG - 'a'])) != NULL) /* check for 'qsect' flag */
1640 printf(gettext("csect name\t%s\n"), k);
1641 if ((k = (sflags[TYPEFLAG - 'a'])) != NULL) /* check for 'type' flag */
1642 printf(gettext("type\t%s\n"), k);
1643 if (sflags[VALFLAG - 'a']) { /* check for 'MR valid' flag */
1644 printf(gettext("validate MRs\t"));
1645 /*
1646 check for MR validating program
1647 (optional)
1648 */
1649 if ((k = (sflags[VALFLAG - 'a'])) != NULL)
1650 printf("%s\n", k);
1651 else putchar('\n');
1652 }
1653 if ((k = (sflags[SCANFLAG - 'a'])) != NULL) /* check for 'keywd scan lines' flag */
1654 printf(gettext("keywd scan lines\t%s\n"), k);
1655 if ((k = (sflags[EXTENSFLAG - 'a'])) != NULL) /* check for 'extensions' flag */
1656 printf(gettext("extensions\t%s\n"), k);
1657 if ((k = (sflags[EXPANDFLAG - 'a'])) != NULL) /* check for 'expand keywds' flag */
1658 printf(gettext("expand keywds\t%s\n"), k);
1659 }
1660
1661
1662 /*
1663 * This procedure checks the `dataspec' (if user defined) and determines
1664 * if any temporary files need be created for future keyword replacement
1665 */
1666
1667 static void
ck_spec(p)1668 ck_spec(p)
1669 register char *p;
1670 {
1671 if (sccs_index(p, NOGETTEXT(":C:")) != -1) /* check for Comment keyword */
1672 HAD_CM = 1;
1673 if (sccs_index(p, NOGETTEXT(":MR:")) != -1) /* check for MR keyword */
1674 HAD_MR = 1;
1675 if (sccs_index(p, NOGETTEXT(":SX:")) != -1) /* check for SX keyword */
1676 HAD_SX = 1;
1677 if (sccs_index(p, NOGETTEXT(":UN:")) != -1) /* check for User name keyword */
1678 HAD_UN = 1;
1679 if (sccs_index(p, NOGETTEXT(":FD:")) != -1) /* check for descriptive text kyword */
1680 HAD_FD = 1;
1681 if (sccs_index(p, NOGETTEXT(":BD:")) != -1) /* check for body keyword */
1682 HAD_BD = 1;
1683 }
1684