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