12152Seric # include "../hdr/defines.h" 22152Seric # include "../hdr/had.h" 32152Seric 4*6174Seric SCCSID(@(#)snull.c 4.2); 52152Seric USXALLOC(); 62152Seric 72152Seric int Debug 0; 82152Seric struct packet gpkt; 92152Seric struct sid sid; 102152Seric int num_files; 112152Seric char had[26]; 122152Seric FILE *Xiop; 132152Seric int Xcreate; 142152Seric struct deltalist { 152152Seric struct deltalist *ds_olderdel; 162152Seric struct deltalist *ds_youngerdel; 172152Seric struct sid ds_sid; 182152Seric int ds_origser; 192152Seric int ds_ser; 202152Seric int ds_pred; 212152Seric long ds_datetime; 22*6174Seric char ds_pgmr[SZLNAM]; 232152Seric char ds_type; 242152Seric struct stats ds_stats; 252152Seric int ds_insnull; 262152Seric }; 272152Seric struct deltalist *Dhead; 282152Seric struct deltalist *Dtail; 292152Seric char line[512]; 302152Seric int *New_ser_ptr; 312152Seric int Max_old_ser; 322152Seric 332152Seric main(argc,argv) 342152Seric int argc; 352152Seric register char *argv[]; 362152Seric { 372152Seric register int i; 382152Seric register char *p; 392152Seric char c; 402152Seric extern snull(); 412152Seric extern int Fcnt; 422152Seric 432152Seric /* 442152Seric Flags for 'fatal'. 452152Seric */ 462152Seric Fflags = FTLEXIT | FTLMSG | FTLCLN; 472152Seric 482152Seric /* 492152Seric Process arguments. 502152Seric */ 512152Seric for (i = 1; i < argc; i++) 522152Seric if (argv[i][0] == '-' && (c = argv[i][1])) { 532152Seric p = &argv[i][2]; 542152Seric switch (c) { 552152Seric default: 562152Seric fatal("unknown key letter (cm1)"); 572152Seric } 582152Seric if (had[c - 'a']++) 592152Seric fatal("key letter twice (cm2)"); 602152Seric argv[i] = 0; 612152Seric } 622152Seric else num_files++; 632152Seric 642152Seric if(num_files == 0) 652152Seric fatal("missing file arg (cm3)"); 662152Seric 672152Seric setsig(); 682152Seric /* 692152Seric Reset flags for 'fatal' so that it will return to 'main' 702152Seric rather than exiting. 712152Seric */ 722152Seric Fflags =& ~FTLEXIT; 732152Seric Fflags =| FTLJMP; 742152Seric 752152Seric /* 762152Seric Invoke 'snull' for each file argument. 772152Seric */ 782152Seric for (i = 1; i < argc; i++) 792152Seric if (p = argv[i]) 802152Seric do_file(p,snull); 812152Seric 822152Seric exit(Fcnt ? 1 : 0); 832152Seric } 842152Seric 852152Seric 862152Seric snull(file) 872152Seric { 882152Seric register char *p; 892152Seric register int ser; 902152Seric extern char had_dir, had_standinp; 912152Seric extern char *Sflags[]; 922152Seric struct stats stats; 932152Seric int newser; 942152Seric 952152Seric /* 962152Seric Set up to return to caller ('main') from 'fatal'. 972152Seric */ 982152Seric if (setjmp(Fjmp)) 992152Seric return; 1002152Seric 1012152Seric sinit(&gpkt,file,1); /* init packet and open file */ 1022152Seric 1032152Seric if (exists(auxf(gpkt.p_file,'p'))) 1042152Seric fatal("p-file exists (sn3)"); 1052152Seric 1062152Seric if (lockit(auxf(gpkt.p_file,'z'),2,getpid())) 1072152Seric fatal("cannot create lock file (cm4)"); 1082152Seric 1092152Seric /* 1102152Seric Indicate that file is to be re-opened (from beginning) 1112152Seric after it reaches EOF. 1122152Seric The file is read once to get the delta table 1132152Seric (without copying to x-file) and then again to make 1142152Seric required modifications to it (using x-file). 1152152Seric */ 1162152Seric gpkt.p_reopen = 1; 1172152Seric 1182152Seric dodeltbl(&gpkt); /* get delta table */ 1192152Seric flushto(&gpkt,EUSERNAM,1); 1202152Seric doflags(&gpkt); /* get flags */ 1212152Seric 1222152Seric /* 1232152Seric Indicate to 'getline' that EOF is allowable. 1242152Seric */ 1252152Seric gpkt.p_chkeof = 1; 1262152Seric 1272152Seric /* 1282152Seric Flush through rest of file. 1292152Seric This checks for corruptions. 1302152Seric */ 1312152Seric while (getline(&gpkt)) 1322152Seric ; 1332152Seric 1342152Seric if (num_files > 1 || had_dir || had_standinp) 1352152Seric printf("\n%s:\n",gpkt.p_file); 1362152Seric 1372152Seric /* 1382152Seric Here, file has already been re-opened (by 'getline'). 1392152Seric Indicate that x-file is to be used. 1402152Seric */ 1412152Seric gpkt.p_upd = 1; 1422152Seric 1432152Seric gpkt.p_wrttn = 1; 1442152Seric getline(&gpkt); /* skip over old */ 1452152Seric gpkt.p_wrttn = 1; /* header record */ 1462152Seric 1472152Seric /* 1482152Seric Write new header. 1492152Seric */ 1502152Seric putline(&gpkt,sprintf(line,"%c%c00000\n",CTLCHAR,HEAD)); 1512152Seric mkdelt(); /* insert 'null' deltas */ 1522152Seric wrtdeltbl(&gpkt); /* write out new delta table */ 1532152Seric 1542152Seric flushto(&gpkt,EUSERNAM,0); 1552152Seric /* 1562152Seric If file does not have the 'n' flag, put one in. 1572152Seric */ 1582152Seric if (!Sflags[NULLFLAG - 'a']) 1592152Seric putline(&gpkt,sprintf(line,"%c%c %c\n",CTLCHAR, 1602152Seric FLAG,NULLFLAG)); 1612152Seric 1622152Seric flushto(&gpkt,EUSERTXT,0); 1632152Seric 1642152Seric /* 1652152Seric Process body, changing control-line serial numbers 1662152Seric appropriately. 1672152Seric */ 1682152Seric fixbody(&gpkt); 1692152Seric 1702152Seric flushline(&gpkt,0); /* flush buffer, fix header, and close */ 1712152Seric rename(auxf(gpkt.p_file,'x'),gpkt.p_file); 1722152Seric clean_up(0); 1732152Seric } 1742152Seric 1752152Seric 1762152Seric dodeltbl(pkt) 1772152Seric register struct packet *pkt; 1782152Seric { 1792152Seric struct deltab dt; 1802152Seric struct stats stats; 1812152Seric struct deltalist *newp; 1822152Seric int n; 1832152Seric 1842152Seric Dhead = Dtail = newp = 0; 1852152Seric 1862152Seric /* 1872152Seric Read entire delta table. 1882152Seric */ 1892152Seric while (getstats(pkt,&stats)) { 1902152Seric if (getadel(pkt,&dt) != BDELTAB) 1912152Seric fmterr(pkt); 1922152Seric newp = alloc(n = sizeof(*Dhead)); 1932152Seric zero(newp,n); 1942152Seric if (!Dhead) { 1952152Seric Dhead = newp; 1962152Seric New_ser_ptr = alloc(n = 2 * (dt.d_serial + 1)); 1972152Seric zero(New_ser_ptr,n); 1982152Seric Max_old_ser = dt.d_serial; 1992152Seric } 2002152Seric else { 2012152Seric Dtail->ds_olderdel = newp; 2022152Seric newp->ds_youngerdel = Dtail; 2032152Seric } 2042152Seric newp->ds_sid.s_rel = dt.d_sid.s_rel; 2052152Seric newp->ds_sid.s_lev = dt.d_sid.s_lev; 2062152Seric newp->ds_sid.s_br = dt.d_sid.s_br; 2072152Seric newp->ds_sid.s_seq = dt.d_sid.s_seq; 2082152Seric newp->ds_origser = dt.d_serial; 2092152Seric newp->ds_ser = dt.d_serial; 2102152Seric newp->ds_pred = dt.d_pred; 2112152Seric newp->ds_datetime = dt.d_datetime; 2122152Seric move(&dt.d_pgmr,newp->ds_pgmr,sizeof(dt.d_pgmr)); 2132152Seric newp->ds_type = dt.d_type; 2142152Seric newp->ds_stats.s_ins = stats.s_ins; 2152152Seric newp->ds_stats.s_del = stats.s_del; 2162152Seric newp->ds_stats.s_unc = stats.s_unc; 2172152Seric Dtail = newp; 2182152Seric 2192152Seric /* 2202152Seric Skip over rest of delta entry. 2212152Seric */ 2222152Seric while ((n = getline(pkt)) != NULL) 2232152Seric if (pkt->p_line[0] != CTLCHAR) 2242152Seric break; 2252152Seric else { 2262152Seric switch (pkt->p_line[1]) { 2272152Seric case EDELTAB: 2282152Seric break; 2292152Seric case INCLUDE: 2302152Seric case EXCLUDE: 2312152Seric case IGNORE: 2322152Seric case MRNUM: 2332152Seric case COMMENTS: 2342152Seric continue; 2352152Seric default: 2362152Seric fmterr(pkt); 2372152Seric } 2382152Seric break; 2392152Seric } 2402152Seric if (n == NULL || pkt->p_line[0] != CTLCHAR) 2412152Seric fmterr(pkt); 2422152Seric } 2432152Seric } 2442152Seric 2452152Seric 2462152Seric getadel(pkt,dt) 2472152Seric register struct packet *pkt; 2482152Seric register struct deltab *dt; 2492152Seric { 2502152Seric if (getline(pkt) == NULL) 2512152Seric fmterr(pkt); 2522152Seric return(del_ab(pkt->p_line,dt,pkt)); 2532152Seric } 2542152Seric 2552152Seric 2562152Seric getstats(pkt,statp) 2572152Seric register struct packet *pkt; 2582152Seric register struct stats *statp; 2592152Seric { 2602152Seric register char *p; 2612152Seric 2622152Seric p = pkt->p_line; 2632152Seric if (getline(pkt) == NULL || *p++ != CTLCHAR || *p++ != STATS) 2642152Seric return(0); 2652152Seric NONBLANK(p); 2662152Seric p = satoi(p,&statp->s_ins); 2672152Seric p = satoi(++p,&statp->s_del); 2682152Seric satoi(++p,&statp->s_unc); 2692152Seric return(1); 2702152Seric } 2712152Seric 2722152Seric 2732152Seric mkdelt() 2742152Seric { 2752152Seric struct deltalist *ptr; 2762152Seric struct deltalist *nulldel; 2772152Seric struct deltalist *oldp; 2782152Seric struct deltalist *ptrtemp; 2792152Seric int n; 2802152Seric int currel; 2812152Seric int reldiff, numnull; 2822152Seric int serhold; 2832152Seric 2842152Seric /* 2852152Seric Set current release to that of oldest (first) delta. 2862152Seric */ 2872152Seric currel = Dtail->ds_sid.s_rel; 2882152Seric 2892152Seric /* 2902152Seric The following loop processes each delta, starting with the 2912152Seric oldest one in the file (the last one read). 2922152Seric */ 2932152Seric ptr = Dtail; 2942152Seric while (ptr) { 2952152Seric reldiff = ptr->ds_sid.s_rel - currel; 2962152Seric 2972152Seric /* 2982152Seric Skip removed deltas, branch deltas, or any delta whose 2992152Seric release number is the same as the current release number. 3002152Seric */ 3012152Seric if (ptr->ds_type == 'R' || ptr->ds_sid.s_br || 3022152Seric ptr->ds_sid.s_seq || reldiff == 0) { 3032152Seric ptr = ptr->ds_youngerdel; 3042152Seric continue; 3052152Seric } 3062152Seric 3072152Seric /* 3082152Seric Check if delta is the next trunk delta in sequence, and if so 3092152Seric bump up current release number and continue. 3102152Seric */ 3112152Seric if (reldiff == 1) { 3122152Seric currel++; 3132152Seric ptr = ptr->ds_youngerdel; 3142152Seric continue; 3152152Seric } 3162152Seric 3172152Seric /* 3182152Seric Here, a trunk delta has been found, and its release 3192152Seric number is greater (by at least 2) than the current 3202152Seric release number. 3212152Seric This requires insertion of 'null' deltas. 3222152Seric First, check that this trunk delta's release 3232152Seric number is greater than currel. 3242152Seric (This catches deltas whose SIDs have been changed 3252152Seric by the user to make them look like trunk deltas.) 3262152Seric */ 3272152Seric if (reldiff < 0) 3282152Seric fatal("file has invalid trunk delta (sn1)"); 3292152Seric 3302152Seric currel =+ reldiff; /* update currel */ 3312152Seric 3322152Seric /* 3332152Seric Find pointer to ancestor delta. 3342152Seric */ 3352152Seric oldp = ser_to_ptr(ptr->ds_pred); 3362152Seric 3372152Seric /* 3382152Seric Retain serial number for later use in fixing 3392152Seric other deltas' serial numbers. 3402152Seric */ 3412152Seric serhold = ptr->ds_ser; 3422152Seric 3432152Seric ptrtemp = ptr; 3442152Seric numnull = reldiff; /* number of null deltas needed */ 3452152Seric while (--numnull) { /* insert null deltas */ 3462152Seric nulldel = alloc(n = sizeof(*Dhead)); 3472152Seric zero(nulldel,n); 3482152Seric nulldel->ds_youngerdel = ptrtemp; 3492152Seric nulldel->ds_olderdel = ptrtemp->ds_olderdel; 3502152Seric ptrtemp->ds_olderdel = nulldel; 3512152Seric (nulldel->ds_olderdel)->ds_youngerdel = nulldel; 3522152Seric nulldel->ds_sid.s_rel = ptrtemp->ds_sid.s_rel - 1; 3532152Seric nulldel->ds_sid.s_lev = 1; 3542152Seric nulldel->ds_sid.s_br = 0; 3552152Seric nulldel->ds_sid.s_seq = 0; 3562152Seric nulldel->ds_ser = serhold + numnull - 1; 3572152Seric if (numnull != 1) 3582152Seric nulldel->ds_pred = nulldel->ds_ser - 1; 3592152Seric else 3602152Seric nulldel->ds_pred = oldp->ds_ser; 3612152Seric nulldel->ds_datetime = ptr->ds_datetime; 362*6174Seric substr(logname(),nulldel->ds_pgmr,0,LNLNAM); 3632152Seric nulldel->ds_type = 'D'; 3642152Seric nulldel->ds_stats.s_ins = 0; 3652152Seric nulldel->ds_stats.s_del = 0; 3662152Seric nulldel->ds_stats.s_unc = oldp->ds_stats.s_unc + 3672152Seric oldp->ds_stats.s_ins; 3682152Seric nulldel->ds_insnull = 1; /* null delta indicator */ 3692152Seric ptrtemp = nulldel; 3702152Seric } 3712152Seric 3722152Seric /* 3732152Seric Fix up sequence and predecessor numbers of those deltas 3742152Seric which are younger than the ones just processed. 3752152Seric */ 3762152Seric ptrtemp = ptr; 3772152Seric reldiff--; 3782152Seric while (ptrtemp) { 3792152Seric if (ptrtemp->ds_ser >= serhold) 3802152Seric ptrtemp->ds_ser =+ reldiff; 3812152Seric if (ptrtemp->ds_pred >= serhold) 3822152Seric ptrtemp->ds_pred =+ reldiff; 3832152Seric 3842152Seric ptrtemp = ptrtemp->ds_youngerdel; 3852152Seric } 3862152Seric 3872152Seric /* 3882152Seric Fix predecessor of current delta. 3892152Seric */ 3902152Seric ptr->ds_pred = serhold + reldiff - 1; 3912152Seric 3922152Seric /* 3932152Seric Point to next (non-null) delta. 3942152Seric */ 3952152Seric ptr = ptr->ds_youngerdel; 3962152Seric } 3972152Seric 3982152Seric /* 3992152Seric Create array of original values of serial numbers of 4002152Seric the original deltas. 4012152Seric */ 4022152Seric ptr = Dtail; 4032152Seric while (ptr) { 4042152Seric if (ptr->ds_insnull != 1) 4052152Seric New_ser_ptr[ptr->ds_origser] = ptr->ds_ser; 4062152Seric ptr = ptr->ds_youngerdel; 4072152Seric } 4082152Seric } 4092152Seric 4102152Seric 4112152Seric ser_to_ptr(ser) 4122152Seric int ser; 4132152Seric { 4142152Seric struct deltalist *ptr; 4152152Seric 4162152Seric ptr = Dtail; 4172152Seric while (ptr) { 4182152Seric if (ptr->ds_ser == ser) 4192152Seric return(ptr); 4202152Seric ptr = ptr->ds_youngerdel; 4212152Seric } 4222152Seric fatal("internal error -- ser_to_ptr (sn2)"); 4232152Seric } 4242152Seric 4252152Seric 4262152Seric wrtdeltbl(pkt) 4272152Seric register struct packet *pkt; 4282152Seric { 4292152Seric struct deltalist *ptr; 4302152Seric char *p; 4312152Seric int ser; 4322152Seric 4332152Seric /* 4342152Seric The following loop writes out the new delta table. 4352152Seric */ 4362152Seric ptr = Dhead; 4372152Seric while (ptr) { 4382152Seric if (ptr->ds_insnull) { /* 'null' delta */ 4392152Seric /* 4402152Seric Write out statistics line. 4412152Seric */ 4422152Seric putline(pkt,sprintf(line,"%c%c %05u/%05u/%05u\n", 4432152Seric CTLCHAR,STATS,ptr->ds_stats.s_ins, 4442152Seric ptr->ds_stats.s_del, 4452152Seric ptr->ds_stats.s_unc)); 4462152Seric 4472152Seric /* 4482152Seric Write 'delta' line, taken from 4492152Seric in-core list. 4502152Seric */ 4512152Seric putdel(pkt,ptr); 4522152Seric 4532152Seric putline(pkt,sprintf(line,"%c%c %s\n",CTLCHAR,COMMENTS, 4542152Seric "INSERTED BY SNULL")); 4552152Seric putline(pkt,sprintf(line,CTLSTR,CTLCHAR,EDELTAB)); 4562152Seric } 4572152Seric else { 4582152Seric getline(pkt); /* statistics line */ 4592152Seric getline(pkt); /* 'delta' line */ 4602152Seric 4612152Seric /* 4622152Seric Indicate not to output previously read line. 4632152Seric */ 4642152Seric pkt->p_wrttn = 1; 4652152Seric 4662152Seric /* 4672152Seric Write 'delta' line from in-core list. 4682152Seric */ 4692152Seric putdel(pkt,ptr); 4702152Seric 4712152Seric /* 4722152Seric Process rest of entry, changeing serial 4732152Seric numbers of deltas included, excluded, 4742152Seric or ignored. 4752152Seric */ 4762152Seric while (getline(pkt)) 4772152Seric if (pkt->p_line[0] != CTLCHAR) 4782152Seric break; 4792152Seric else { 4802152Seric switch (*(p = &pkt->p_line[1])) { 4812152Seric case EDELTAB: 4822152Seric putline(pkt,0); 4832152Seric break; 4842152Seric case INCLUDE: 4852152Seric case EXCLUDE: 4862152Seric case IGNORE: 4872152Seric pkt->p_wrttn = 1; 4882152Seric putline(pkt,sprintf(line, 4892152Seric "%c%c",CTLCHAR,*p++)); 4902152Seric NONBLANK(p); 4912152Seric while (numeric(*p)) { 4922152Seric p = satoi(p,&ser); 4932152Seric 4942152Seric if (!(ser > 0 && 4952152Seric ser <= Max_old_ser)) 4962152Seric fmterr(pkt); 4972152Seric 4982152Seric putline(pkt,sprintf( 4992152Seric line," %u", 5002152Seric New_ser_ptr[ser])); 5012152Seric 5022152Seric NONBLANK(p); 5032152Seric } 5042152Seric putline(pkt,"\n"); 5052152Seric continue; 5062152Seric default: 5072152Seric putline(pkt,0); 5082152Seric continue; 5092152Seric } 5102152Seric break; 5112152Seric } 5122152Seric } 5132152Seric 5142152Seric /* 5152152Seric Point to next delta to be output. 5162152Seric */ 5172152Seric ptr = ptr->ds_olderdel; 5182152Seric } 5192152Seric } 5202152Seric 5212152Seric 5222152Seric putdel(pkt,ptr) 5232152Seric struct packet *pkt; 5242152Seric struct deltalist *ptr; 5252152Seric { 5262152Seric struct deltab dt; 5272152Seric 5282152Seric move(&ptr->ds_sid,&dt.d_sid,sizeof(dt.d_sid)); 5292152Seric dt.d_serial = ptr->ds_ser; 5302152Seric dt.d_pred = ptr->ds_pred; 5312152Seric dt.d_datetime = ptr->ds_datetime; 5322152Seric move(ptr->ds_pgmr,&dt.d_pgmr,sizeof(dt.d_pgmr)); 5332152Seric dt.d_type = ptr->ds_type; 5342152Seric 5352152Seric del_ba(&dt,line); 5362152Seric putline(pkt,line); 5372152Seric } 5382152Seric 5392152Seric 5402152Seric fixbody(pkt) 5412152Seric register struct packet *pkt; 5422152Seric { 5432152Seric int ser; 5442152Seric char *p, type; 5452152Seric 5462152Seric while (getline(pkt)) { 5472152Seric p = pkt->p_line; 5482152Seric 5492152Seric if (*p++ == CTLCHAR) { 5502152Seric if (!((type = *p++) == INS || type == DEL || 5512152Seric type == END)) 5522152Seric fmterr(pkt); 5532152Seric NONBLANK(p); 5542152Seric satoi(p,&ser); 5552152Seric if (!(ser > 0 && ser <= Max_old_ser)) 5562152Seric fmterr(pkt); 5572152Seric 5582152Seric /* 5592152Seric Indicate not to output line just read. 5602152Seric */ 5612152Seric pkt->p_wrttn = 1; 5622152Seric 5632152Seric /* 5642152Seric Output new value of sequence number. 5652152Seric */ 5662152Seric putline(pkt,sprintf(line,"%c%c %u\n",CTLCHAR,type, 5672152Seric New_ser_ptr[ser])); 5682152Seric } 5692152Seric } 5702152Seric } 5712152Seric 5722152Seric 5732152Seric clean_up(n) 5742152Seric { 5752152Seric if (gpkt.p_file[0]) 5762152Seric unlockit(auxf(gpkt.p_file,'z'),getpid()); 5772152Seric if (gpkt.p_iop) 5782152Seric fclose(gpkt.p_iop); 5792152Seric xrm(&gpkt); 5802152Seric xfreeall(); 5812152Seric } 582