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 
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 	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 
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 
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 
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 
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 
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 
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 
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 
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