1*162Sroot # include	"../hdr/defines.h"
2*162Sroot # include	"../hdr/had.h"
3*162Sroot 
4*162Sroot SCCSID(@(#)delta	2.1);
5*162Sroot USXALLOC();
6*162Sroot 
7*162Sroot char	Diffpgm[]	"/usr/local/bdiff";
8*162Sroot FILE	*Diffin;
9*162Sroot int	Debug	0;
10*162Sroot struct packet gpkt;
11*162Sroot struct sid sid;
12*162Sroot int	num_files;
13*162Sroot char	had[26];
14*162Sroot char	*ilist, *elist, *glist;
15*162Sroot char	*Comments, *Mrs;
16*162Sroot int	Domrs;
17*162Sroot int verbosity;
18*162Sroot int	Did_id;
19*162Sroot long	Szqfile;
20*162Sroot char	Pfilename[FILESIZE];
21*162Sroot FILE	*Xiop;
22*162Sroot int	Xcreate;
23*162Sroot 
24*162Sroot main(argc,argv)
25*162Sroot int argc;
26*162Sroot register char *argv[];
27*162Sroot {
28*162Sroot 	register int i;
29*162Sroot 	register char *p;
30*162Sroot 	char c;
31*162Sroot 	int testmore;
32*162Sroot 	extern delta();
33*162Sroot 	extern int Fcnt;
34*162Sroot 
35*162Sroot 	Fflags = FTLEXIT | FTLMSG | FTLCLN;
36*162Sroot 	for(i=1; i<argc; i++)
37*162Sroot 		if(argv[i][0] == '-' && (c=argv[i][1])) {
38*162Sroot 			p = &argv[i][2];
39*162Sroot 			testmore = 0;
40*162Sroot 			switch (c) {
41*162Sroot 
42*162Sroot 			case 'r':
43*162Sroot 				if (!p[0]) {
44*162Sroot 					argv[i] = 0;
45*162Sroot 					continue;
46*162Sroot 				}
47*162Sroot 				chksid(sid_ab(p,&sid),&sid);
48*162Sroot 				break;
49*162Sroot 			case 'g':
50*162Sroot 				glist = p;
51*162Sroot 				break;
52*162Sroot 			case 'y':
53*162Sroot 				Comments = p;
54*162Sroot 				break;
55*162Sroot 			case 'm':
56*162Sroot 				Mrs = p;
57*162Sroot 				break;
58*162Sroot 			case 'p':
59*162Sroot 			case 'n':
60*162Sroot 			case 's':
61*162Sroot 				testmore++;
62*162Sroot 				break;
63*162Sroot 			default:
64*162Sroot 				fatal("unknown key letter (cm1)");
65*162Sroot 			}
66*162Sroot 
67*162Sroot 			if (testmore) {
68*162Sroot 				testmore = 0;
69*162Sroot 				if (*p)
70*162Sroot 					fatal(sprintf(Error,
71*162Sroot 					  "value after %c arg (cm7)",c));
72*162Sroot 			}
73*162Sroot 			if (had[c - 'a']++)
74*162Sroot 				fatal("key letter twice (cm2)");
75*162Sroot 			argv[i] = 0;
76*162Sroot 		}
77*162Sroot 		else num_files++;
78*162Sroot 
79*162Sroot 	if(num_files == 0)
80*162Sroot 		fatal("missing file arg (cm3)");
81*162Sroot 	if (!HADS)
82*162Sroot 		verbosity = -1;
83*162Sroot 	setsig();
84*162Sroot 	Fflags =& ~FTLEXIT;
85*162Sroot 	Fflags =| FTLJMP;
86*162Sroot 	for (i=1; i<argc; i++)
87*162Sroot 		if (p=argv[i])
88*162Sroot 			do_file(p,delta);
89*162Sroot 	exit(Fcnt ? 1 : 0);
90*162Sroot }
91*162Sroot 
92*162Sroot 
93*162Sroot delta(file)
94*162Sroot {
95*162Sroot 	static int first 1;
96*162Sroot 	register char *p;
97*162Sroot 	int n, linenum;
98*162Sroot 	char type;
99*162Sroot 	register int ser;
100*162Sroot 	extern char had_dir, had_standinp;
101*162Sroot 	extern char *Sflags[];
102*162Sroot 	char dfilename[FILESIZE];
103*162Sroot 	char gfilename[FILESIZE];
104*162Sroot 	char line[512];
105*162Sroot 	FILE *gin;
106*162Sroot 	struct stats stats;
107*162Sroot 	struct pfile *pp;
108*162Sroot 	int inserted, deleted, orig;
109*162Sroot 	int newser;
110*162Sroot 	int status;
111*162Sroot 	int diffloop;
112*162Sroot 	int difflim;
113*162Sroot 
114*162Sroot 	if (setjmp(Fjmp))
115*162Sroot 		return;
116*162Sroot 	if (first) {
117*162Sroot 		first = 0;
118*162Sroot 		dohist(file);
119*162Sroot 	}
120*162Sroot 	sinit(&gpkt,file,1);
121*162Sroot 	if (lockit(auxf(gpkt.p_file,'z'),2,getpid()))
122*162Sroot 		fatal("cannot create lock file (cm4)");
123*162Sroot 	gpkt.p_reopen = 1;
124*162Sroot 	gpkt.p_stdout = stdout;
125*162Sroot 	copy(auxf(gpkt.p_file,'g'),gfilename);
126*162Sroot 	gin = xfopen(gfilename,0);
127*162Sroot 	pp = rdpfile(&gpkt,&sid);
128*162Sroot 	gpkt.p_cutoff = pp->pf_date;
129*162Sroot 	ilist = pp->pf_ilist;
130*162Sroot 	elist = pp->pf_elist;
131*162Sroot 
132*162Sroot 	if (dodelt(&gpkt,&stats,0,0) == 0)
133*162Sroot 		fmterr(&gpkt);
134*162Sroot 	if ((ser = sidtoser(&pp->pf_gsid,&gpkt)) == 0 ||
135*162Sroot 		sidtoser(&pp->pf_nsid,&gpkt))
136*162Sroot 			fatal("invalid sid in p-file (de3)");
137*162Sroot 	doie(&gpkt,ilist,elist,glist);
138*162Sroot 	setup(&gpkt,ser);
139*162Sroot 	finduser(&gpkt);
140*162Sroot 	doflags(&gpkt);
141*162Sroot 	move(&pp->pf_nsid,&gpkt.p_reqsid,sizeof(gpkt.p_reqsid));
142*162Sroot 	permiss(&gpkt);
143*162Sroot 	flushto(&gpkt,EUSERTXT,1);
144*162Sroot 	gpkt.p_chkeof = 1;
145*162Sroot 	copy(auxf(gpkt.p_file,'d'),dfilename);
146*162Sroot 	gpkt.p_gout = xfcreat(dfilename,0444);
147*162Sroot 	while(readmod(&gpkt)) {
148*162Sroot 		chkid(gpkt.p_line);
149*162Sroot 		fputs(gpkt.p_line,gpkt.p_gout);
150*162Sroot 	}
151*162Sroot 	fclose(gpkt.p_gout);
152*162Sroot 	orig = gpkt.p_glnno;
153*162Sroot 	gpkt.p_glnno = 0;
154*162Sroot 	gpkt.p_verbose = verbosity;
155*162Sroot 	Did_id = 0;
156*162Sroot 	while (fgets(line,sizeof(line),gin) != NULL && !chkid(line))
157*162Sroot 		;
158*162Sroot 	fclose(gin);
159*162Sroot 	if (gpkt.p_verbose && (num_files > 1 || had_dir || had_standinp))
160*162Sroot 		fprintf(gpkt.p_stdout,"\n%s:\n",gpkt.p_file);
161*162Sroot 	if (!Did_id)
162*162Sroot 		if (Sflags[IDFLAG - 'a'])
163*162Sroot 			fatal("no id keywords (cm6)");
164*162Sroot 		else if (gpkt.p_verbose)
165*162Sroot 			fprintf(stderr,"No id keywords (cm7)\n");
166*162Sroot 
167*162Sroot 	/*
168*162Sroot 	The following while loop executes 'bdiff' on g-file and
169*162Sroot 	d-file. If 'bdiff' fails (usually because segmentation
170*162Sroot 	limit it is using is too large for 'diff'), it is
171*162Sroot 	invoked again, with a lower segmentation limit.
172*162Sroot 	*/
173*162Sroot 	difflim = 3500;
174*162Sroot 	diffloop = 0;
175*162Sroot 	while (1) {
176*162Sroot 		inserted = deleted = 0;
177*162Sroot 		gpkt.p_glnno = 0;
178*162Sroot 		gpkt.p_upd = 1;
179*162Sroot 		gpkt.p_wrttn = 1;
180*162Sroot 		getline(&gpkt);
181*162Sroot 		gpkt.p_wrttn = 1;
182*162Sroot 		newser = mkdelt(&gpkt,&pp->pf_nsid,&pp->pf_gsid,
183*162Sroot 						diffloop,orig);
184*162Sroot 		diffloop = 1;
185*162Sroot 		flushto(&gpkt,EUSERTXT,0);
186*162Sroot 		Diffin = dodiff(auxf(gpkt.p_file,'g'),dfilename,difflim);
187*162Sroot 		while (n = getdiff(&type,&linenum)) {
188*162Sroot 			if (type == INS) {
189*162Sroot 				inserted =+ n;
190*162Sroot 				insert(&gpkt,linenum,n,newser);
191*162Sroot 			}
192*162Sroot 			else {
193*162Sroot 				deleted =+ n;
194*162Sroot 				delete(&gpkt,linenum,n,newser);
195*162Sroot 			}
196*162Sroot 		}
197*162Sroot 		fclose(Diffin);
198*162Sroot 		if (gpkt.p_iop)
199*162Sroot 			while (readmod(&gpkt))
200*162Sroot 				;
201*162Sroot 		wait(&status);
202*162Sroot 		if (status) {		/* diff failed */
203*162Sroot 			/*
204*162Sroot 			Check top byte (exit code of child).
205*162Sroot 			*/
206*162Sroot 			if (((status >> 8) & 0377) == 32) /* 'execl' failed */
207*162Sroot 				fatal(sprintf(Error,
208*162Sroot 						"cannot execute '%s' (de12)",
209*162Sroot 						Diffpgm));
210*162Sroot 			/*
211*162Sroot 			Re-try.
212*162Sroot 			*/
213*162Sroot 			if (difflim =- 500) {	/* reduce segmentation */
214*162Sroot 				fprintf(stderr,
215*162Sroot 			"'%s' failed, re-trying, segmentation = %d (de13)\n",
216*162Sroot 					Diffpgm,difflim);
217*162Sroot 				fclose(Xiop);	/* set up */
218*162Sroot 				Xiop = 0;	/* for new x-file */
219*162Sroot 				Xcreate = 0;
220*162Sroot 				/*
221*162Sroot 				Re-open s-file.
222*162Sroot 				*/
223*162Sroot 				gpkt.p_iop = xfopen(gpkt.p_file,0);
224*162Sroot 				setbuf(gpkt.p_iop,gpkt.p_buf);
225*162Sroot 				/*
226*162Sroot 				Reset counters.
227*162Sroot 				*/
228*162Sroot 				gpkt.p_slnno = 0;
229*162Sroot 				gpkt.p_ihash = 0;
230*162Sroot 				gpkt.p_chash = 0;
231*162Sroot 				gpkt.p_nhash = 0;
232*162Sroot 				gpkt.p_keep = 0;
233*162Sroot 			}
234*162Sroot 			else
235*162Sroot 				/* tried up to 500 lines, can't go on */
236*162Sroot 				fatal("diff failed (de4)");
237*162Sroot 		}
238*162Sroot 		else {		/* no need to try again, worked */
239*162Sroot 			break;			/* exit while loop */
240*162Sroot 		}
241*162Sroot 	}
242*162Sroot 	unlink(dfilename);
243*162Sroot 	stats.s_ins = inserted;
244*162Sroot 	stats.s_del = deleted;
245*162Sroot 	stats.s_unc = orig - deleted;
246*162Sroot 	if (gpkt.p_verbose) {
247*162Sroot 		fprintf(gpkt.p_stdout,"%u inserted\n",stats.s_ins);
248*162Sroot 		fprintf(gpkt.p_stdout,"%u deleted\n",stats.s_del);
249*162Sroot 		fprintf(gpkt.p_stdout,"%u unchanged\n",stats.s_unc);
250*162Sroot 	}
251*162Sroot 	flushline(&gpkt,&stats);
252*162Sroot 	rename(auxf(gpkt.p_file,'x'),gpkt.p_file);
253*162Sroot 	if (Szqfile)
254*162Sroot 		rename(auxf(&gpkt.p_file,'q'),Pfilename);
255*162Sroot 	else {
256*162Sroot 		xunlink(Pfilename);
257*162Sroot 		xunlink(auxf(&gpkt.p_file,'q'));
258*162Sroot 	}
259*162Sroot 	clean_up(0);
260*162Sroot 	if (!HADN) {
261*162Sroot 		setuid(getuid());
262*162Sroot 		unlink(gfilename);
263*162Sroot 	}
264*162Sroot }
265*162Sroot 
266*162Sroot 
267*162Sroot mkdelt(pkt,sp,osp,diffloop,orig_nlines)
268*162Sroot struct packet *pkt;
269*162Sroot struct sid *sp, *osp;
270*162Sroot int diffloop;
271*162Sroot int orig_nlines;
272*162Sroot {
273*162Sroot 	extern long Timenow;
274*162Sroot 	struct deltab dt;
275*162Sroot 	char str[128];
276*162Sroot 	int newser;
277*162Sroot 	extern char *Sflags[];
278*162Sroot 	register char *p;
279*162Sroot 	int ser_inc, opred, nulldel;
280*162Sroot 
281*162Sroot 	if (!diffloop && pkt->p_verbose) {
282*162Sroot 		sid_ba(sp,str);
283*162Sroot 		fprintf(pkt->p_stdout,"%s\n",str);
284*162Sroot 	}
285*162Sroot 	putline(pkt,sprintf(str,"%c%c00000\n",CTLCHAR,HEAD));
286*162Sroot 	newstats(pkt,str,"0");
287*162Sroot 	move(sp,&dt.d_sid,sizeof(dt.d_sid));
288*162Sroot 
289*162Sroot 	/*
290*162Sroot 	Check if 'null' deltas should be inserted
291*162Sroot 	(only if 'null' flag is in file and
292*162Sroot 	releases are being skipped) and set
293*162Sroot 	'nulldel' indicator appropriately.
294*162Sroot 	*/
295*162Sroot 	if (Sflags[NULLFLAG - 'a'] && (sp->s_rel > osp->s_rel + 1) &&
296*162Sroot 			!sp->s_br && !sp->s_seq &&
297*162Sroot 			!osp->s_br && !osp->s_seq)
298*162Sroot 		nulldel = 1;
299*162Sroot 	else
300*162Sroot 		nulldel = 0;
301*162Sroot 	/*
302*162Sroot 	Calculate how many serial numbers are needed.
303*162Sroot 	*/
304*162Sroot 	if (nulldel)
305*162Sroot 		ser_inc = sp->s_rel - osp->s_rel;
306*162Sroot 	else
307*162Sroot 		ser_inc = 1;
308*162Sroot 	/*
309*162Sroot 	Find serial number of the new delta.
310*162Sroot 	*/
311*162Sroot 	newser = dt.d_serial = maxser(pkt) + ser_inc;
312*162Sroot 	/*
313*162Sroot 	Find old predecessor's serial number.
314*162Sroot 	*/
315*162Sroot 	opred = sidtoser(osp,pkt);
316*162Sroot 	if (nulldel)
317*162Sroot 		dt.d_pred = newser - 1;	/* set predecessor to 'null' delta */
318*162Sroot 	else
319*162Sroot 		dt.d_pred = opred;
320*162Sroot 	dt.d_datetime = Timenow;
321*162Sroot 	substr(logname(),dt.d_pgmr,0,7);
322*162Sroot 	dt.d_type = 'D';
323*162Sroot 	del_ba(&dt,str);
324*162Sroot 	putline(pkt,str);
325*162Sroot 	if (ilist)
326*162Sroot 		mkixg(pkt,INCLUSER,INCLUDE);
327*162Sroot 	if (elist)
328*162Sroot 		mkixg(pkt,EXCLUSER,EXCLUDE);
329*162Sroot 	if (glist)
330*162Sroot 		mkixg(pkt,IGNRUSER,IGNORE);
331*162Sroot 	if (Mrs) {
332*162Sroot 		if (!(p = Sflags[VALFLAG - 'a']))
333*162Sroot 			fatal("MRs not allowed (de8)");
334*162Sroot 		if (*p && !diffloop && valmrs(pkt,p))
335*162Sroot 			fatal("invalid MRs (de9)");
336*162Sroot 		putmrs(pkt);
337*162Sroot 	}
338*162Sroot 	else if (Sflags[VALFLAG - 'a'])
339*162Sroot 		fatal("MRs required (de10)");
340*162Sroot 	putline(pkt,sprintf(str,"%c%c ",CTLCHAR,COMMENTS));
341*162Sroot 	putline(pkt,Comments);
342*162Sroot 	putline(pkt,"\n");
343*162Sroot 	putline(pkt,sprintf(str,CTLSTR,CTLCHAR,EDELTAB));
344*162Sroot 	if (nulldel)			/* insert 'null' deltas */
345*162Sroot 		while (--ser_inc) {
346*162Sroot 			putline(pkt,sprintf(str,"%c%c %s/%s/%05u\n",
347*162Sroot 				CTLCHAR, STATS,
348*162Sroot 				"00000", "00000", orig_nlines));
349*162Sroot 			dt.d_sid.s_rel =- 1;
350*162Sroot 			dt.d_serial =- 1;
351*162Sroot 			if (ser_inc != 1)
352*162Sroot 				dt.d_pred =- 1;
353*162Sroot 			else
354*162Sroot 				dt.d_pred = opred;	/* point to old pred */
355*162Sroot 			del_ba(&dt,str);
356*162Sroot 			putline(pkt,str);
357*162Sroot 			putline(pkt,sprintf(str,"%c%c ",CTLCHAR,COMMENTS));
358*162Sroot 			putline(pkt,"AUTO NULL DELTA\n");
359*162Sroot 			putline(pkt,sprintf(str,CTLSTR,CTLCHAR,EDELTAB));
360*162Sroot 		}
361*162Sroot 	return(newser);
362*162Sroot }
363*162Sroot 
364*162Sroot 
365*162Sroot mkixg(pkt,reason,ch)
366*162Sroot struct packet *pkt;
367*162Sroot int reason;
368*162Sroot char ch;
369*162Sroot {
370*162Sroot 	int n;
371*162Sroot 	char str[512];
372*162Sroot 
373*162Sroot 	putline(pkt,sprintf(str,"%c%c",CTLCHAR,ch));
374*162Sroot 	for (n = maxser(pkt); n; n--) {
375*162Sroot 		if (pkt->p_apply[n].a_reason == reason)
376*162Sroot 			putline(pkt,sprintf(str," %u",n));
377*162Sroot 	}
378*162Sroot 	putline(pkt,"\n");
379*162Sroot }
380*162Sroot 
381*162Sroot 
382*162Sroot putmrs(pkt)
383*162Sroot struct packet *pkt;
384*162Sroot {
385*162Sroot 	register char **argv;
386*162Sroot 	char str[64];
387*162Sroot 	extern char *Varg[];
388*162Sroot 
389*162Sroot 	for (argv = &Varg[VSTART]; *argv; argv++)
390*162Sroot 		putline(pkt,sprintf(str,"%c%c %s\n",CTLCHAR,MRNUM,*argv));
391*162Sroot }
392*162Sroot 
393*162Sroot 
394*162Sroot rdpfile(pkt,sp)
395*162Sroot register struct packet *pkt;
396*162Sroot struct sid *sp;
397*162Sroot {
398*162Sroot 	char *user;
399*162Sroot 	struct pfile pf;
400*162Sroot 	static struct pfile goodpf;
401*162Sroot 	char line[512];
402*162Sroot 	int cnt;
403*162Sroot 	FILE *in, *out;
404*162Sroot 
405*162Sroot 	cnt = -1;
406*162Sroot 	user = logname();
407*162Sroot 	zero(&goodpf,sizeof(goodpf));
408*162Sroot 	in = xfopen(auxf(pkt->p_file,'p'),0);
409*162Sroot 	out = xfcreat(auxf(pkt->p_file,'q'),0644);
410*162Sroot 	while (fgets(line,sizeof(line),in) != NULL) {
411*162Sroot 		pf_ab(line,&pf,1);
412*162Sroot 		if (equal(pf.pf_user,user)) {
413*162Sroot 			if (sp->s_rel == 0) {
414*162Sroot 				if (++cnt) {
415*162Sroot 					fclose(out);
416*162Sroot 					fclose(in);
417*162Sroot 					fatal("missing -r argument (de1)");
418*162Sroot 				}
419*162Sroot 				move(&pf,&goodpf,sizeof(pf));
420*162Sroot 				continue;
421*162Sroot 			}
422*162Sroot 			else if (sp->s_rel == pf.pf_gsid.s_rel &&
423*162Sroot 				sp->s_lev == pf.pf_gsid.s_lev &&
424*162Sroot 				sp->s_br == pf.pf_gsid.s_br &&
425*162Sroot 				sp->s_seq == pf.pf_gsid.s_seq) {
426*162Sroot 					move(&pf,&goodpf,sizeof(pf));
427*162Sroot 					continue;
428*162Sroot 			}
429*162Sroot 		}
430*162Sroot 		fputs(line,out);
431*162Sroot 	}
432*162Sroot 	fflush(out);
433*162Sroot 	fstat(fileno(out),&Statbuf);
434*162Sroot 	Szqfile = Statbuf.st_size;
435*162Sroot 	copy(auxf(pkt->p_file,'p'),Pfilename);
436*162Sroot 	fclose(out);
437*162Sroot 	fclose(in);
438*162Sroot 	if (!goodpf.pf_user[0])
439*162Sroot 		fatal("not in p-file (de2)");
440*162Sroot 	return(&goodpf);
441*162Sroot }
442*162Sroot 
443*162Sroot 
444*162Sroot dodiff(newf,oldf,difflim)
445*162Sroot char *newf, *oldf;
446*162Sroot int difflim;
447*162Sroot {
448*162Sroot 	register int i;
449*162Sroot 	int pfd[2];
450*162Sroot 	FILE *iop;
451*162Sroot 	extern char Diffpgm[];
452*162Sroot 	char num[10];
453*162Sroot 
454*162Sroot 	xpipe(pfd);
455*162Sroot 	if ((i = fork()) < 0) {
456*162Sroot 		close(pfd[0]);
457*162Sroot 		close(pfd[1]);
458*162Sroot 		fatal("cannot fork, try again (de11)");
459*162Sroot 	}
460*162Sroot 	else if (i == 0) {
461*162Sroot 		close(pfd[0]);
462*162Sroot 		close(1);
463*162Sroot 		dup(pfd[1]);
464*162Sroot 		close(pfd[1]);
465*162Sroot 		for (i = 5; i < 15; i++)
466*162Sroot 			close(i);
467*162Sroot 		sprintf(num,"%d",difflim);
468*162Sroot 		execl(Diffpgm,Diffpgm,oldf,newf,num,"-s",0);
469*162Sroot 		close(1);
470*162Sroot 		exit(32);	/* tell parent that 'execl' failed */
471*162Sroot 	}
472*162Sroot 	else {
473*162Sroot 		close(pfd[1]);
474*162Sroot 		iop = fdfopen(pfd[0],0);
475*162Sroot 		return(iop);
476*162Sroot 	}
477*162Sroot }
478*162Sroot 
479*162Sroot 
480*162Sroot getdiff(type,plinenum)
481*162Sroot register char *type;
482*162Sroot register int *plinenum;
483*162Sroot {
484*162Sroot 	char line[512];
485*162Sroot 	register char *p;
486*162Sroot 	int num_lines;
487*162Sroot 	static int chg_num, chg_ln;
488*162Sroot 	int lowline, highline;
489*162Sroot 
490*162Sroot 	if ((p = rddiff(line,512)) == NULL)
491*162Sroot 		return(0);
492*162Sroot 
493*162Sroot 	if (*p == '-') {
494*162Sroot 		*type = INS;
495*162Sroot 		*plinenum = chg_ln;
496*162Sroot 		num_lines = chg_num;
497*162Sroot 	}
498*162Sroot 	else {
499*162Sroot 		p = linerange(p,&lowline,&highline);
500*162Sroot 		*plinenum = lowline;
501*162Sroot 
502*162Sroot 		switch(*p++) {
503*162Sroot 		case 'd':
504*162Sroot 			num_lines = highline - lowline + 1;
505*162Sroot 			*type = DEL;
506*162Sroot 			skipline(line,num_lines);
507*162Sroot 			break;
508*162Sroot 
509*162Sroot 		case 'a':
510*162Sroot 			linerange(p,&lowline,&highline);
511*162Sroot 			num_lines = highline - lowline + 1;
512*162Sroot 			*type = INS;
513*162Sroot 			break;
514*162Sroot 
515*162Sroot 		case 'c':
516*162Sroot 			chg_ln = lowline;
517*162Sroot 			num_lines = highline - lowline + 1;
518*162Sroot 			linerange(p,&lowline,&highline);
519*162Sroot 			chg_num = highline - lowline + 1;
520*162Sroot 			*type = DEL;
521*162Sroot 			skipline(line,num_lines);
522*162Sroot 			break;
523*162Sroot 		}
524*162Sroot 	}
525*162Sroot 
526*162Sroot 	return(num_lines);
527*162Sroot }
528*162Sroot 
529*162Sroot 
530*162Sroot insert(pkt,linenum,n,ser)
531*162Sroot register struct packet *pkt;
532*162Sroot register int linenum;
533*162Sroot register int n;
534*162Sroot int ser;
535*162Sroot {
536*162Sroot 	char str[512];
537*162Sroot 
538*162Sroot 	after(pkt,linenum);
539*162Sroot 	putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,INS,ser));
540*162Sroot 	for (++n; --n; ) {
541*162Sroot 		rddiff(str,sizeof(str));
542*162Sroot 		putline(pkt,&str[2]);
543*162Sroot 	}
544*162Sroot 	putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,END,ser));
545*162Sroot }
546*162Sroot 
547*162Sroot 
548*162Sroot delete(pkt,linenum,n,ser)
549*162Sroot register struct packet *pkt;
550*162Sroot register int linenum;
551*162Sroot int n;
552*162Sroot register int ser;
553*162Sroot {
554*162Sroot 	char str[512];
555*162Sroot 
556*162Sroot 	before(pkt,linenum);
557*162Sroot 	putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,DEL,ser));
558*162Sroot 	after(pkt,linenum + n - 1);
559*162Sroot 	putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,END,ser));
560*162Sroot }
561*162Sroot 
562*162Sroot 
563*162Sroot after(pkt,n)
564*162Sroot register struct packet *pkt;
565*162Sroot register int n;
566*162Sroot {
567*162Sroot 	before(pkt,n);
568*162Sroot 	if (pkt->p_glnno == n)
569*162Sroot 		putline(pkt,0);
570*162Sroot }
571*162Sroot 
572*162Sroot 
573*162Sroot before(pkt,n)
574*162Sroot register struct packet *pkt;
575*162Sroot register int n;
576*162Sroot {
577*162Sroot 	while (pkt->p_glnno < n) {
578*162Sroot 		if (!readmod(pkt))
579*162Sroot 			break;
580*162Sroot 	}
581*162Sroot }
582*162Sroot 
583*162Sroot 
584*162Sroot linerange(cp,low,high)
585*162Sroot register char *cp;
586*162Sroot register int *low, *high;
587*162Sroot {
588*162Sroot 	cp = satoi(cp,low);
589*162Sroot 	if (*cp == ',')
590*162Sroot 		cp = satoi(++cp,high);
591*162Sroot 	else
592*162Sroot 		*high = *low;
593*162Sroot 
594*162Sroot 	return(cp);
595*162Sroot }
596*162Sroot 
597*162Sroot 
598*162Sroot skiplines(lp,num)
599*162Sroot register char *lp;
600*162Sroot register int num;
601*162Sroot {
602*162Sroot 	for (++num;--num;)
603*162Sroot 		rddiff(lp,512);
604*162Sroot }
605*162Sroot 
606*162Sroot 
607*162Sroot rddiff(s,n)
608*162Sroot register char *s;
609*162Sroot register int n;
610*162Sroot {
611*162Sroot 	register int r;
612*162Sroot 
613*162Sroot 	if ((r = fgets(s,n,Diffin)) != NULL && HADP)
614*162Sroot 		fputs(s,gpkt.p_stdout);
615*162Sroot 	return(r);
616*162Sroot }
617*162Sroot 
618*162Sroot 
619*162Sroot enter(pkt,ch,n,sidp)
620*162Sroot struct packet *pkt;
621*162Sroot char ch;
622*162Sroot int n;
623*162Sroot struct sid *sidp;
624*162Sroot {
625*162Sroot 	char str[32];
626*162Sroot 	register struct apply *ap;
627*162Sroot 
628*162Sroot 	sid_ba(sidp,str);
629*162Sroot 	ap = &pkt->p_apply[n];
630*162Sroot 	if (pkt->p_cutoff > pkt->p_idel[n].i_datetime)
631*162Sroot 		switch(ap->a_code) {
632*162Sroot 
633*162Sroot 		case EMPTY:
634*162Sroot 			switch (ch) {
635*162Sroot 			case INCLUDE:
636*162Sroot 				condset(ap,APPLY,INCLUSER);
637*162Sroot 				break;
638*162Sroot 			case EXCLUDE:
639*162Sroot 				condset(ap,NOAPPLY,EXCLUSER);
640*162Sroot 				break;
641*162Sroot 			case IGNORE:
642*162Sroot 				condset(ap,EMPTY,IGNRUSER);
643*162Sroot 				break;
644*162Sroot 			}
645*162Sroot 			break;
646*162Sroot 		case APPLY:
647*162Sroot 			fatal("internal error in delta/enter() (de5)");
648*162Sroot 			break;
649*162Sroot 		case NOAPPLY:
650*162Sroot 			fatal("internal error in delta/enter() (de6)");
651*162Sroot 			break;
652*162Sroot 		default:
653*162Sroot 			fatal("internal error in delta/enter() (de7)");
654*162Sroot 			break;
655*162Sroot 		}
656*162Sroot }
657*162Sroot 
658*162Sroot 
659*162Sroot escdodelt()	/* dummy routine for dodelt() */
660*162Sroot {
661*162Sroot }
662*162Sroot 
663*162Sroot 
664*162Sroot clean_up(n)
665*162Sroot {
666*162Sroot 	if (gpkt.p_file[0])
667*162Sroot 		unlockit(auxf(gpkt.p_file,'z'),getpid());
668*162Sroot 	xrm(&gpkt);
669*162Sroot 	xfreeall();
670*162Sroot }
671