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
main(argc,argv)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
snull(file)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
dodeltbl(pkt)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
getadel(pkt,dt)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
getstats(pkt,statp)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
mkdelt()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
ser_to_ptr(ser)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
wrtdeltbl(pkt)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
fixbody(pkt)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
clean_up(n)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