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.2 02/15/87"; 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 fatal(sprintf(Error,"cannot execute '%s'",Getpgm)); 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