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