1 # include "../hdr/defines.h" 2 # include "../hdr/had.h" 3 4 SCCSID(@(#)snull.c 4.2); 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 putline(&gpkt,sprintf(line,"%c%c00000\n",CTLCHAR,HEAD)); 151 mkdelt(); /* insert 'null' deltas */ 152 wrtdeltbl(&gpkt); /* write out new delta table */ 153 154 flushto(&gpkt,EUSERNAM,0); 155 /* 156 If file does not have the 'n' flag, put one in. 157 */ 158 if (!Sflags[NULLFLAG - 'a']) 159 putline(&gpkt,sprintf(line,"%c%c %c\n",CTLCHAR, 160 FLAG,NULLFLAG)); 161 162 flushto(&gpkt,EUSERTXT,0); 163 164 /* 165 Process body, changing control-line serial numbers 166 appropriately. 167 */ 168 fixbody(&gpkt); 169 170 flushline(&gpkt,0); /* flush buffer, fix header, and close */ 171 rename(auxf(gpkt.p_file,'x'),gpkt.p_file); 172 clean_up(0); 173 } 174 175 176 dodeltbl(pkt) 177 register struct packet *pkt; 178 { 179 struct deltab dt; 180 struct stats stats; 181 struct deltalist *newp; 182 int n; 183 184 Dhead = Dtail = newp = 0; 185 186 /* 187 Read entire delta table. 188 */ 189 while (getstats(pkt,&stats)) { 190 if (getadel(pkt,&dt) != BDELTAB) 191 fmterr(pkt); 192 newp = alloc(n = sizeof(*Dhead)); 193 zero(newp,n); 194 if (!Dhead) { 195 Dhead = newp; 196 New_ser_ptr = alloc(n = 2 * (dt.d_serial + 1)); 197 zero(New_ser_ptr,n); 198 Max_old_ser = dt.d_serial; 199 } 200 else { 201 Dtail->ds_olderdel = newp; 202 newp->ds_youngerdel = Dtail; 203 } 204 newp->ds_sid.s_rel = dt.d_sid.s_rel; 205 newp->ds_sid.s_lev = dt.d_sid.s_lev; 206 newp->ds_sid.s_br = dt.d_sid.s_br; 207 newp->ds_sid.s_seq = dt.d_sid.s_seq; 208 newp->ds_origser = dt.d_serial; 209 newp->ds_ser = dt.d_serial; 210 newp->ds_pred = dt.d_pred; 211 newp->ds_datetime = dt.d_datetime; 212 move(&dt.d_pgmr,newp->ds_pgmr,sizeof(dt.d_pgmr)); 213 newp->ds_type = dt.d_type; 214 newp->ds_stats.s_ins = stats.s_ins; 215 newp->ds_stats.s_del = stats.s_del; 216 newp->ds_stats.s_unc = stats.s_unc; 217 Dtail = newp; 218 219 /* 220 Skip over rest of delta entry. 221 */ 222 while ((n = getline(pkt)) != NULL) 223 if (pkt->p_line[0] != CTLCHAR) 224 break; 225 else { 226 switch (pkt->p_line[1]) { 227 case EDELTAB: 228 break; 229 case INCLUDE: 230 case EXCLUDE: 231 case IGNORE: 232 case MRNUM: 233 case COMMENTS: 234 continue; 235 default: 236 fmterr(pkt); 237 } 238 break; 239 } 240 if (n == NULL || pkt->p_line[0] != CTLCHAR) 241 fmterr(pkt); 242 } 243 } 244 245 246 getadel(pkt,dt) 247 register struct packet *pkt; 248 register struct deltab *dt; 249 { 250 if (getline(pkt) == NULL) 251 fmterr(pkt); 252 return(del_ab(pkt->p_line,dt,pkt)); 253 } 254 255 256 getstats(pkt,statp) 257 register struct packet *pkt; 258 register struct stats *statp; 259 { 260 register char *p; 261 262 p = pkt->p_line; 263 if (getline(pkt) == NULL || *p++ != CTLCHAR || *p++ != STATS) 264 return(0); 265 NONBLANK(p); 266 p = satoi(p,&statp->s_ins); 267 p = satoi(++p,&statp->s_del); 268 satoi(++p,&statp->s_unc); 269 return(1); 270 } 271 272 273 mkdelt() 274 { 275 struct deltalist *ptr; 276 struct deltalist *nulldel; 277 struct deltalist *oldp; 278 struct deltalist *ptrtemp; 279 int n; 280 int currel; 281 int reldiff, numnull; 282 int serhold; 283 284 /* 285 Set current release to that of oldest (first) delta. 286 */ 287 currel = Dtail->ds_sid.s_rel; 288 289 /* 290 The following loop processes each delta, starting with the 291 oldest one in the file (the last one read). 292 */ 293 ptr = Dtail; 294 while (ptr) { 295 reldiff = ptr->ds_sid.s_rel - currel; 296 297 /* 298 Skip removed deltas, branch deltas, or any delta whose 299 release number is the same as the current release number. 300 */ 301 if (ptr->ds_type == 'R' || ptr->ds_sid.s_br || 302 ptr->ds_sid.s_seq || reldiff == 0) { 303 ptr = ptr->ds_youngerdel; 304 continue; 305 } 306 307 /* 308 Check if delta is the next trunk delta in sequence, and if so 309 bump up current release number and continue. 310 */ 311 if (reldiff == 1) { 312 currel++; 313 ptr = ptr->ds_youngerdel; 314 continue; 315 } 316 317 /* 318 Here, a trunk delta has been found, and its release 319 number is greater (by at least 2) than the current 320 release number. 321 This requires insertion of 'null' deltas. 322 First, check that this trunk delta's release 323 number is greater than currel. 324 (This catches deltas whose SIDs have been changed 325 by the user to make them look like trunk deltas.) 326 */ 327 if (reldiff < 0) 328 fatal("file has invalid trunk delta (sn1)"); 329 330 currel =+ reldiff; /* update currel */ 331 332 /* 333 Find pointer to ancestor delta. 334 */ 335 oldp = ser_to_ptr(ptr->ds_pred); 336 337 /* 338 Retain serial number for later use in fixing 339 other deltas' serial numbers. 340 */ 341 serhold = ptr->ds_ser; 342 343 ptrtemp = ptr; 344 numnull = reldiff; /* number of null deltas needed */ 345 while (--numnull) { /* insert null deltas */ 346 nulldel = alloc(n = sizeof(*Dhead)); 347 zero(nulldel,n); 348 nulldel->ds_youngerdel = ptrtemp; 349 nulldel->ds_olderdel = ptrtemp->ds_olderdel; 350 ptrtemp->ds_olderdel = nulldel; 351 (nulldel->ds_olderdel)->ds_youngerdel = nulldel; 352 nulldel->ds_sid.s_rel = ptrtemp->ds_sid.s_rel - 1; 353 nulldel->ds_sid.s_lev = 1; 354 nulldel->ds_sid.s_br = 0; 355 nulldel->ds_sid.s_seq = 0; 356 nulldel->ds_ser = serhold + numnull - 1; 357 if (numnull != 1) 358 nulldel->ds_pred = nulldel->ds_ser - 1; 359 else 360 nulldel->ds_pred = oldp->ds_ser; 361 nulldel->ds_datetime = ptr->ds_datetime; 362 substr(logname(),nulldel->ds_pgmr,0,LNLNAM); 363 nulldel->ds_type = 'D'; 364 nulldel->ds_stats.s_ins = 0; 365 nulldel->ds_stats.s_del = 0; 366 nulldel->ds_stats.s_unc = oldp->ds_stats.s_unc + 367 oldp->ds_stats.s_ins; 368 nulldel->ds_insnull = 1; /* null delta indicator */ 369 ptrtemp = nulldel; 370 } 371 372 /* 373 Fix up sequence and predecessor numbers of those deltas 374 which are younger than the ones just processed. 375 */ 376 ptrtemp = ptr; 377 reldiff--; 378 while (ptrtemp) { 379 if (ptrtemp->ds_ser >= serhold) 380 ptrtemp->ds_ser =+ reldiff; 381 if (ptrtemp->ds_pred >= serhold) 382 ptrtemp->ds_pred =+ reldiff; 383 384 ptrtemp = ptrtemp->ds_youngerdel; 385 } 386 387 /* 388 Fix predecessor of current delta. 389 */ 390 ptr->ds_pred = serhold + reldiff - 1; 391 392 /* 393 Point to next (non-null) delta. 394 */ 395 ptr = ptr->ds_youngerdel; 396 } 397 398 /* 399 Create array of original values of serial numbers of 400 the original deltas. 401 */ 402 ptr = Dtail; 403 while (ptr) { 404 if (ptr->ds_insnull != 1) 405 New_ser_ptr[ptr->ds_origser] = ptr->ds_ser; 406 ptr = ptr->ds_youngerdel; 407 } 408 } 409 410 411 ser_to_ptr(ser) 412 int ser; 413 { 414 struct deltalist *ptr; 415 416 ptr = Dtail; 417 while (ptr) { 418 if (ptr->ds_ser == ser) 419 return(ptr); 420 ptr = ptr->ds_youngerdel; 421 } 422 fatal("internal error -- ser_to_ptr (sn2)"); 423 } 424 425 426 wrtdeltbl(pkt) 427 register struct packet *pkt; 428 { 429 struct deltalist *ptr; 430 char *p; 431 int ser; 432 433 /* 434 The following loop writes out the new delta table. 435 */ 436 ptr = Dhead; 437 while (ptr) { 438 if (ptr->ds_insnull) { /* 'null' delta */ 439 /* 440 Write out statistics line. 441 */ 442 putline(pkt,sprintf(line,"%c%c %05u/%05u/%05u\n", 443 CTLCHAR,STATS,ptr->ds_stats.s_ins, 444 ptr->ds_stats.s_del, 445 ptr->ds_stats.s_unc)); 446 447 /* 448 Write 'delta' line, taken from 449 in-core list. 450 */ 451 putdel(pkt,ptr); 452 453 putline(pkt,sprintf(line,"%c%c %s\n",CTLCHAR,COMMENTS, 454 "INSERTED BY SNULL")); 455 putline(pkt,sprintf(line,CTLSTR,CTLCHAR,EDELTAB)); 456 } 457 else { 458 getline(pkt); /* statistics line */ 459 getline(pkt); /* 'delta' line */ 460 461 /* 462 Indicate not to output previously read line. 463 */ 464 pkt->p_wrttn = 1; 465 466 /* 467 Write 'delta' line from in-core list. 468 */ 469 putdel(pkt,ptr); 470 471 /* 472 Process rest of entry, changeing serial 473 numbers of deltas included, excluded, 474 or ignored. 475 */ 476 while (getline(pkt)) 477 if (pkt->p_line[0] != CTLCHAR) 478 break; 479 else { 480 switch (*(p = &pkt->p_line[1])) { 481 case EDELTAB: 482 putline(pkt,0); 483 break; 484 case INCLUDE: 485 case EXCLUDE: 486 case IGNORE: 487 pkt->p_wrttn = 1; 488 putline(pkt,sprintf(line, 489 "%c%c",CTLCHAR,*p++)); 490 NONBLANK(p); 491 while (numeric(*p)) { 492 p = satoi(p,&ser); 493 494 if (!(ser > 0 && 495 ser <= Max_old_ser)) 496 fmterr(pkt); 497 498 putline(pkt,sprintf( 499 line," %u", 500 New_ser_ptr[ser])); 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 move(&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 move(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 putline(pkt,sprintf(line,"%c%c %u\n",CTLCHAR,type, 567 New_ser_ptr[ser])); 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