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