1 # include	"../hdr/defines.h"
2 # include	"../hdr/had.h"
3 
4 SCCSID(@(#)snull.c	4.3);
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 		bzero(newp,n);
194 		if (!Dhead) {
195 			Dhead = newp;
196 			New_ser_ptr = alloc(n = 2 * (dt.d_serial + 1));
197 			bzero(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 		bcopy(&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 			bzero(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 	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 			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