1 # include "../hdr/defines.h" 2 # include "../hdr/had.h" 3 4 static char Sccsid[] = "@(#)snull.c 4.5 02/02/88"; 5 USXALLOC(); 6 7 int Debug = 0; 8 struct packet gpkt; 9 struct sid sid; 10 int num_files; 11 char had[26]; 12 FILE *Xiop; 13 int Xcreate; 14 struct deltalist { 15 struct deltalist *ds_olderdel; 16 struct deltalist *ds_youngerdel; 17 struct sid ds_sid; 18 int ds_origser; 19 int ds_ser; 20 int ds_pred; 21 long ds_datetime; 22 char ds_pgmr[SZLNAM]; 23 char ds_type; 24 struct stats ds_stats; 25 int ds_insnull; 26 }; 27 struct deltalist *Dhead; 28 struct deltalist *Dtail; 29 char line[512]; 30 int *New_ser_ptr; 31 int Max_old_ser; 32 33 main(argc,argv) 34 int argc; 35 register char *argv[]; 36 { 37 register int i; 38 register char *p; 39 char c; 40 extern snull(); 41 extern int Fcnt; 42 43 /* 44 Flags for 'fatal'. 45 */ 46 Fflags = FTLEXIT | FTLMSG | FTLCLN; 47 48 /* 49 Process arguments. 50 */ 51 for (i = 1; i < argc; i++) 52 if (argv[i][0] == '-' && (c = argv[i][1])) { 53 p = &argv[i][2]; 54 switch (c) { 55 default: 56 fatal("unknown key letter (cm1)"); 57 } 58 if (had[c - 'a']++) 59 fatal("key letter twice (cm2)"); 60 argv[i] = 0; 61 } 62 else num_files++; 63 64 if(num_files == 0) 65 fatal("missing file arg (cm3)"); 66 67 setsig(); 68 /* 69 Reset flags for 'fatal' so that it will return to 'main' 70 rather than exiting. 71 */ 72 Fflags &= ~FTLEXIT; 73 Fflags |= FTLJMP; 74 75 /* 76 Invoke 'snull' for each file argument. 77 */ 78 for (i = 1; i < argc; i++) 79 if (p = argv[i]) 80 do_file(p,snull); 81 82 exit(Fcnt ? 1 : 0); 83 } 84 85 86 snull(file) 87 { 88 register char *p; 89 register int ser; 90 extern char had_dir, had_standinp; 91 extern char *Sflags[]; 92 struct stats stats; 93 int newser; 94 95 /* 96 Set up to return to caller ('main') from 'fatal'. 97 */ 98 if (setjmp(Fjmp)) 99 return; 100 101 sinit(&gpkt,file,1); /* init packet and open file */ 102 103 if (exists(auxf(gpkt.p_file,'p'))) 104 fatal("p-file exists (sn3)"); 105 106 if (lockit(auxf(gpkt.p_file,'z'),2,getpid())) 107 fatal("cannot create lock file (cm4)"); 108 109 /* 110 Indicate that file is to be re-opened (from beginning) 111 after it reaches EOF. 112 The file is read once to get the delta table 113 (without copying to x-file) and then again to make 114 required modifications to it (using x-file). 115 */ 116 gpkt.p_reopen = 1; 117 118 dodeltbl(&gpkt); /* get delta table */ 119 flushto(&gpkt,EUSERNAM,1); 120 doflags(&gpkt); /* get flags */ 121 122 /* 123 Indicate to 'getline' that EOF is allowable. 124 */ 125 gpkt.p_chkeof = 1; 126 127 /* 128 Flush through rest of file. 129 This checks for corruptions. 130 */ 131 while (getline(&gpkt)) 132 ; 133 134 if (num_files > 1 || had_dir || had_standinp) 135 printf("\n%s:\n",gpkt.p_file); 136 137 /* 138 Here, file has already been re-opened (by 'getline'). 139 Indicate that x-file is to be used. 140 */ 141 gpkt.p_upd = 1; 142 143 gpkt.p_wrttn = 1; 144 getline(&gpkt); /* skip over old */ 145 gpkt.p_wrttn = 1; /* header record */ 146 147 /* 148 Write new header. 149 */ 150 sprintf(line,"%c%c00000\n",CTLCHAR,HEAD); 151 putline(&gpkt,line); 152 mkdelt(); /* insert 'null' deltas */ 153 wrtdeltbl(&gpkt); /* write out new delta table */ 154 155 flushto(&gpkt,EUSERNAM,0); 156 /* 157 If file does not have the 'n' flag, put one in. 158 */ 159 if (!Sflags[NULLFLAG - 'a']) { 160 sprintf(line,"%c%c %c\n",CTLCHAR,FLAG,NULLFLAG); 161 putline(&gpkt,line); 162 } 163 164 flushto(&gpkt,EUSERTXT,0); 165 166 /* 167 Process body, changing control-line serial numbers 168 appropriately. 169 */ 170 fixbody(&gpkt); 171 172 flushline(&gpkt,0); /* flush buffer, fix header, and close */ 173 rename(auxf(gpkt.p_file,'x'),gpkt.p_file); 174 clean_up(0); 175 } 176 177 178 dodeltbl(pkt) 179 register struct packet *pkt; 180 { 181 struct deltab dt; 182 struct stats stats; 183 struct deltalist *newp; 184 int n; 185 186 Dhead = Dtail = newp = 0; 187 188 /* 189 Read entire delta table. 190 */ 191 while (getstats(pkt,&stats)) { 192 if (getadel(pkt,&dt) != BDELTAB) 193 fmterr(pkt); 194 newp = alloc(n = sizeof(*Dhead)); 195 bzero(newp,n); 196 if (!Dhead) { 197 Dhead = newp; 198 New_ser_ptr = alloc(n = 2 * (dt.d_serial + 1)); 199 bzero(New_ser_ptr,n); 200 Max_old_ser = dt.d_serial; 201 } 202 else { 203 Dtail->ds_olderdel = newp; 204 newp->ds_youngerdel = Dtail; 205 } 206 newp->ds_sid.s_rel = dt.d_sid.s_rel; 207 newp->ds_sid.s_lev = dt.d_sid.s_lev; 208 newp->ds_sid.s_br = dt.d_sid.s_br; 209 newp->ds_sid.s_seq = dt.d_sid.s_seq; 210 newp->ds_origser = dt.d_serial; 211 newp->ds_ser = dt.d_serial; 212 newp->ds_pred = dt.d_pred; 213 newp->ds_datetime = dt.d_datetime; 214 bcopy(&dt.d_pgmr,newp->ds_pgmr,sizeof(dt.d_pgmr)); 215 newp->ds_type = dt.d_type; 216 newp->ds_stats.s_ins = stats.s_ins; 217 newp->ds_stats.s_del = stats.s_del; 218 newp->ds_stats.s_unc = stats.s_unc; 219 Dtail = newp; 220 221 /* 222 Skip over rest of delta entry. 223 */ 224 while ((n = getline(pkt)) != NULL) 225 if (pkt->p_line[0] != CTLCHAR) 226 break; 227 else { 228 switch (pkt->p_line[1]) { 229 case EDELTAB: 230 break; 231 case INCLUDE: 232 case EXCLUDE: 233 case IGNORE: 234 case MRNUM: 235 case COMMENTS: 236 continue; 237 default: 238 fmterr(pkt); 239 } 240 break; 241 } 242 if (n == NULL || pkt->p_line[0] != CTLCHAR) 243 fmterr(pkt); 244 } 245 } 246 247 248 getadel(pkt,dt) 249 register struct packet *pkt; 250 register struct deltab *dt; 251 { 252 if (getline(pkt) == NULL) 253 fmterr(pkt); 254 return(del_ab(pkt->p_line,dt,pkt)); 255 } 256 257 258 getstats(pkt,statp) 259 register struct packet *pkt; 260 register struct stats *statp; 261 { 262 register char *p; 263 264 p = pkt->p_line; 265 if (getline(pkt) == NULL || *p++ != CTLCHAR || *p++ != STATS) 266 return(0); 267 NONBLANK(p); 268 p = satoi(p,&statp->s_ins); 269 p = satoi(++p,&statp->s_del); 270 satoi(++p,&statp->s_unc); 271 return(1); 272 } 273 274 275 mkdelt() 276 { 277 struct deltalist *ptr; 278 struct deltalist *nulldel; 279 struct deltalist *oldp; 280 struct deltalist *ptrtemp; 281 int n; 282 int currel; 283 int reldiff, numnull; 284 int serhold; 285 286 /* 287 Set current release to that of oldest (first) delta. 288 */ 289 currel = Dtail->ds_sid.s_rel; 290 291 /* 292 The following loop processes each delta, starting with the 293 oldest one in the file (the last one read). 294 */ 295 ptr = Dtail; 296 while (ptr) { 297 reldiff = ptr->ds_sid.s_rel - currel; 298 299 /* 300 Skip removed deltas, branch deltas, or any delta whose 301 release number is the same as the current release number. 302 */ 303 if (ptr->ds_type == 'R' || ptr->ds_sid.s_br || 304 ptr->ds_sid.s_seq || reldiff == 0) { 305 ptr = ptr->ds_youngerdel; 306 continue; 307 } 308 309 /* 310 Check if delta is the next trunk delta in sequence, and if so 311 bump up current release number and continue. 312 */ 313 if (reldiff == 1) { 314 currel++; 315 ptr = ptr->ds_youngerdel; 316 continue; 317 } 318 319 /* 320 Here, a trunk delta has been found, and its release 321 number is greater (by at least 2) than the current 322 release number. 323 This requires insertion of 'null' deltas. 324 First, check that this trunk delta's release 325 number is greater than currel. 326 (This catches deltas whose SIDs have been changed 327 by the user to make them look like trunk deltas.) 328 */ 329 if (reldiff < 0) 330 fatal("file has invalid trunk delta (sn1)"); 331 332 currel += reldiff; /* update currel */ 333 334 /* 335 Find pointer to ancestor delta. 336 */ 337 oldp = ser_to_ptr(ptr->ds_pred); 338 339 /* 340 Retain serial number for later use in fixing 341 other deltas' serial numbers. 342 */ 343 serhold = ptr->ds_ser; 344 345 ptrtemp = ptr; 346 numnull = reldiff; /* number of null deltas needed */ 347 while (--numnull) { /* insert null deltas */ 348 nulldel = alloc(n = sizeof(*Dhead)); 349 bzero(nulldel,n); 350 nulldel->ds_youngerdel = ptrtemp; 351 nulldel->ds_olderdel = ptrtemp->ds_olderdel; 352 ptrtemp->ds_olderdel = nulldel; 353 (nulldel->ds_olderdel)->ds_youngerdel = nulldel; 354 nulldel->ds_sid.s_rel = ptrtemp->ds_sid.s_rel - 1; 355 nulldel->ds_sid.s_lev = 1; 356 nulldel->ds_sid.s_br = 0; 357 nulldel->ds_sid.s_seq = 0; 358 nulldel->ds_ser = serhold + numnull - 1; 359 if (numnull != 1) 360 nulldel->ds_pred = nulldel->ds_ser - 1; 361 else 362 nulldel->ds_pred = oldp->ds_ser; 363 nulldel->ds_datetime = ptr->ds_datetime; 364 substr(logname(),nulldel->ds_pgmr,0,LNLNAM); 365 nulldel->ds_type = 'D'; 366 nulldel->ds_stats.s_ins = 0; 367 nulldel->ds_stats.s_del = 0; 368 nulldel->ds_stats.s_unc = oldp->ds_stats.s_unc + 369 oldp->ds_stats.s_ins; 370 nulldel->ds_insnull = 1; /* null delta indicator */ 371 ptrtemp = nulldel; 372 } 373 374 /* 375 Fix up sequence and predecessor numbers of those deltas 376 which are younger than the ones just processed. 377 */ 378 ptrtemp = ptr; 379 reldiff--; 380 while (ptrtemp) { 381 if (ptrtemp->ds_ser >= serhold) 382 ptrtemp->ds_ser += reldiff; 383 if (ptrtemp->ds_pred >= serhold) 384 ptrtemp->ds_pred += reldiff; 385 386 ptrtemp = ptrtemp->ds_youngerdel; 387 } 388 389 /* 390 Fix predecessor of current delta. 391 */ 392 ptr->ds_pred = serhold + reldiff - 1; 393 394 /* 395 Point to next (non-null) delta. 396 */ 397 ptr = ptr->ds_youngerdel; 398 } 399 400 /* 401 Create array of original values of serial numbers of 402 the original deltas. 403 */ 404 ptr = Dtail; 405 while (ptr) { 406 if (ptr->ds_insnull != 1) 407 New_ser_ptr[ptr->ds_origser] = ptr->ds_ser; 408 ptr = ptr->ds_youngerdel; 409 } 410 } 411 412 413 ser_to_ptr(ser) 414 int ser; 415 { 416 struct deltalist *ptr; 417 418 ptr = Dtail; 419 while (ptr) { 420 if (ptr->ds_ser == ser) 421 return(ptr); 422 ptr = ptr->ds_youngerdel; 423 } 424 fatal("internal error -- ser_to_ptr (sn2)"); 425 } 426 427 428 wrtdeltbl(pkt) 429 register struct packet *pkt; 430 { 431 struct deltalist *ptr; 432 char *p; 433 int ser; 434 435 /* 436 The following loop writes out the new delta table. 437 */ 438 ptr = Dhead; 439 while (ptr) { 440 if (ptr->ds_insnull) { /* 'null' delta */ 441 /* 442 Write out statistics line. 443 */ 444 sprintf(line,"%c%c %05u/%05u/%05u\n",CTLCHAR,STATS,ptr->ds_stats.s_ins,ptr->ds_stats.s_del,ptr->ds_stats.s_unc); 445 putline(pkt,line); 446 447 /* 448 Write 'delta' line, taken from 449 in-core list. 450 */ 451 putdel(pkt,ptr); 452 453 sprintf(line,"%c%c %s\n",CTLCHAR,COMMENTS,"INSERTED BY SNULL"); 454 putline(pkt,line); 455 sprintf(line,CTLSTR,CTLCHAR,EDELTAB); 456 putline(pkt,line); 457 } 458 else { 459 getline(pkt); /* statistics line */ 460 getline(pkt); /* 'delta' line */ 461 462 /* 463 Indicate not to output previously read line. 464 */ 465 pkt->p_wrttn = 1; 466 467 /* 468 Write 'delta' line from in-core list. 469 */ 470 putdel(pkt,ptr); 471 472 /* 473 Process rest of entry, changeing serial 474 numbers of deltas included, excluded, 475 or ignored. 476 */ 477 while (getline(pkt)) 478 if (pkt->p_line[0] != CTLCHAR) 479 break; 480 else { 481 switch (*(p = &pkt->p_line[1])) { 482 case EDELTAB: 483 putline(pkt,0); 484 break; 485 case INCLUDE: 486 case EXCLUDE: 487 case IGNORE: 488 pkt->p_wrttn = 1; 489 sprintf(line,"%c%c",CTLCHAR,*p++); 490 putline(pkt,line); 491 NONBLANK(p); 492 while (numeric(*p)) { 493 p = satoi(p,&ser); 494 495 if (!(ser > 0 && 496 ser <= Max_old_ser)) 497 fmterr(pkt); 498 499 sprintf(line," %u",New_ser_ptr[ser]); 500 putline(pkt,line); 501 502 NONBLANK(p); 503 } 504 putline(pkt,"\n"); 505 continue; 506 default: 507 putline(pkt,0); 508 continue; 509 } 510 break; 511 } 512 } 513 514 /* 515 Point to next delta to be output. 516 */ 517 ptr = ptr->ds_olderdel; 518 } 519 } 520 521 522 putdel(pkt,ptr) 523 struct packet *pkt; 524 struct deltalist *ptr; 525 { 526 struct deltab dt; 527 528 bcopy(&ptr->ds_sid,&dt.d_sid,sizeof(dt.d_sid)); 529 dt.d_serial = ptr->ds_ser; 530 dt.d_pred = ptr->ds_pred; 531 dt.d_datetime = ptr->ds_datetime; 532 bcopy(ptr->ds_pgmr,&dt.d_pgmr,sizeof(dt.d_pgmr)); 533 dt.d_type = ptr->ds_type; 534 535 del_ba(&dt,line); 536 putline(pkt,line); 537 } 538 539 540 fixbody(pkt) 541 register struct packet *pkt; 542 { 543 int ser; 544 char *p, type; 545 546 while (getline(pkt)) { 547 p = pkt->p_line; 548 549 if (*p++ == CTLCHAR) { 550 if (!((type = *p++) == INS || type == DEL || 551 type == END)) 552 fmterr(pkt); 553 NONBLANK(p); 554 satoi(p,&ser); 555 if (!(ser > 0 && ser <= Max_old_ser)) 556 fmterr(pkt); 557 558 /* 559 Indicate not to output line just read. 560 */ 561 pkt->p_wrttn = 1; 562 563 /* 564 Output new value of sequence number. 565 */ 566 sprintf(line,"%c%c %u\n",CTLCHAR,type,New_ser_ptr[ser]); 567 putline(pkt,line); 568 } 569 } 570 } 571 572 573 clean_up(n) 574 { 575 if (gpkt.p_file[0]) 576 unlockit(auxf(gpkt.p_file,'z'),getpid()); 577 if (gpkt.p_iop) 578 fclose(gpkt.p_iop); 579 xrm(&gpkt); 580 xfreeall(); 581 } 582