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