1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may use this file only in accordance with the terms of version
7 * 1.0 of the CDDL.
8 *
9 * A full copy of the text of the CDDL should have accompanied this
10 * source. A copy of the CDDL is also available via the Internet at
11 * http://www.opensource.org/licenses/cddl1.txt
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 */
23 /* Copyright (c) 1988 AT&T */
24 /* All Rights Reserved */
25 /*
26 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29 /*
30 * Copyright 2006-2020 J. Schilling
31 *
32 * @(#)comb.c 1.45 20/08/23 J. Schilling
33 */
34 #if defined(sun)
35 #pragma ident "@(#)comb.c 1.45 20/08/23 J. Schilling"
36 #endif
37 /*
38 * @(#)comb.c 1.15 06/12/12
39 */
40
41 #if defined(sun)
42 #pragma ident "@(#)comb.c"
43 #pragma ident "@(#)sccs:cmd/comb.c"
44 #endif
45 #define SCCS_MAIN /* define global vars */
46 #include <defines.h>
47 #include <version.h>
48 #include <had.h>
49 #include <i18n.h>
50 #include <schily/sysexits.h>
51
52 static struct sid sid;
53
54 static struct packet gpkt;
55 static Nparms N; /* Keep -N parameters */
56 static Xparms X; /* Keep -X parameters */
57 static int num_files;
58 static int Do_prs;
59 static char *clist;
60 static char *Val_ptr;
61 static char Blank[] = " ";
62 static int *Cvec;
63 static int Cnt;
64 static FILE *iop;
65
66 static void clean_up __PR((void));
67 static void enter __PR((struct packet *pkt,
68 int ch, int n, struct sid *sidp));
69
70 int main __PR((int argc, char **argv));
71 static void comb __PR((char *file));
72 static struct sid *prtget __PR((struct idel *idp,
73 int ser, FILE *fptr, char *file));
74 static int getpred __PR((struct idel *idp, int *vec, int i));
75
76 int
main(argc,argv)77 main(argc, argv)
78 int argc;
79 register char *argv[];
80 {
81 register int i;
82 register char *p;
83 int c;
84 int testmore;
85 extern int Fcnt;
86 int current_optind;
87 int no_arg;
88
89 /*
90 * Set locale for all categories.
91 */
92 setlocale(LC_ALL, NOGETTEXT(""));
93
94 sccs_setinsbase(INS_BASE);
95
96 /*
97 * Set directory to search for general l10n SCCS messages.
98 */
99 #ifdef PROTOTYPES
100 (void) bindtextdomain(NOGETTEXT("SUNW_SPRO_SCCS"),
101 NOGETTEXT(INS_BASE "/" SCCS_BIN_PRE "lib/locale/"));
102 #else
103 (void) bindtextdomain(NOGETTEXT("SUNW_SPRO_SCCS"),
104 NOGETTEXT("/usr/ccs/lib/locale/"));
105 #endif
106
107 (void) textdomain(NOGETTEXT("SUNW_SPRO_SCCS"));
108
109 tzset(); /* Set up timezome related vars */
110
111 #ifdef SCHILY_BUILD
112 save_args(argc, argv);
113 #endif
114 set_clean_up(clean_up);
115 Fflags = FTLEXIT | FTLMSG | FTLCLN;
116 #ifdef SCCS_FATALHELP
117 Fflags |= FTLFUNC;
118 Ffunc = sccsfatalhelp;
119 #endif
120
121 current_optind = 1;
122 optind = 1;
123 opterr = 0;
124 no_arg = 0;
125 i = 1;
126 /*CONSTCOND*/
127 while (1) {
128 if (current_optind < optind) {
129 current_optind = optind;
130 argv[i] = 0;
131 if (optind > i+1) {
132 if ((argv[i+1][0] != '-') &&
133 (no_arg == 0)) {
134 argv[i+1] = NULL;
135 } else {
136 optind = i+1;
137 current_optind = optind;
138 }
139 }
140 }
141 no_arg = 0;
142 i = current_optind;
143 c = getopt(argc, argv, "()-p:c:osN:X:V(version)");
144
145 /*
146 * This takes care of options given after
147 * file names.
148 */
149 if (c == EOF) {
150 if (optind < argc) {
151 /* if it's due to -- then break; */
152 if (argv[i][0] == '-' &&
153 argv[i][1] == '-') {
154 argv[i] = 0;
155 break;
156 }
157 optind++;
158 current_optind = optind;
159 continue;
160 } else {
161 break;
162 }
163 }
164 p = optarg;
165 testmore = 0;
166 switch (c) {
167
168 case 'p':
169 if (!p[0]) {
170 argv[i] = 0;
171 continue;
172 }
173 chksid(sid_ab(p, &sid), &sid);
174 break;
175 case 'c':
176 clist = p;
177 break;
178 case 'o':
179 testmore++;
180 break;
181 case 's':
182 testmore++;
183 break;
184
185 case 'N': /* Bulk names */
186 initN(&N);
187 if (optarg == argv[i+1]) {
188 no_arg = 1;
189 break;
190 }
191 N.n_parm = p;
192 break;
193
194 case 'X': /* -Xtended options */
195 X.x_parm = optarg;
196 X.x_flags = XO_NULLPATH;
197 if (!parseX(&X))
198 goto err;
199 had[NLOWER+c-'A'] = 0; /* Allow mult -X */
200 break;
201
202 case 'V': /* version */
203 printf(gettext(
204 "comb %s-SCCS version %s %s (%s-%s-%s)\n"),
205 PROVIDER,
206 VERSION,
207 VDATE,
208 HOST_CPU, HOST_VENDOR, HOST_OS);
209 exit(EX_OK);
210
211 default:
212 err:
213 fatal(gettext(
214 "Usage: comb [ -os ][ -c sid-list ] [ -p SID ][ -N[bulk-spec]][ -Xxopts ] s.filename ..."));
215 }
216
217 if (testmore) {
218 testmore = 0;
219 if (p) {
220 if (*p) {
221 sprintf(SccsError,
222 gettext("value after %c arg (cm7)"),
223 c);
224 fatal(SccsError);
225 }
226 }
227 }
228
229 /*
230 * Make sure that we only collect option letters from
231 * the range 'a'..'z' and 'A'..'Z'.
232 */
233 if (ALPHA(c) &&
234 (had[LOWER(c)? c-'a' : NLOWER+c-'A']++)) {
235 if (c != 'X')
236 fatal(gettext("key letter twice (cm2)"));
237 }
238 }
239
240 for (i = 1; i < argc; i++) {
241 if (argv[i]) {
242 num_files++;
243 }
244 }
245 if (num_files == 0)
246 fatal(gettext("missing file arg (cm3)"));
247 if (HADP && HADC)
248 fatal(gettext("can't have both -p and -c (cb2)"));
249
250 setsig();
251 xsethome(NULL);
252 if (HADUCN) { /* Parse -N args */
253 parseN(&N);
254
255 if (N.n_sdot && (sethomestat & SETHOME_OFFTREE))
256 fatal(gettext("-Ns. not supported in off-tree project mode"));
257 }
258
259 Fflags &= ~FTLEXIT;
260 Fflags |= FTLJMP;
261 iop = stdout;
262 for (i = 1; i < argc; i++)
263 if ((p = argv[i]) != NULL)
264 do_file(p, comb, 1, N.n_sdot, &X);
265 fclose(iop);
266 iop = NULL;
267
268 return (Fcnt ? 1 : 0);
269 }
270
271 static void
comb(file)272 comb(file)
273 char *file;
274 {
275 register int i, n;
276 register struct idel *rdp;
277 char *p;
278 char *dir_name = NULL;
279 char rarg[SID_STRSIZE];
280 int succnt;
281 struct sid *sp;
282 extern char had_dir, had_standinp;
283 struct stats stats;
284 static int idx;
285
286 if (setjmp(Fjmp))
287 return;
288 if (HADUCN) {
289 #ifdef __needed__
290 char *ofile = file;
291 #endif
292
293 file = bulkprepare(&N, file);
294 if (file == NULL) {
295 #ifdef __needed__
296 if (N.n_ifile)
297 ofile = N.n_ifile;
298 #endif
299 /*
300 * The error is typically
301 * "directory specified as s-file (cm14)"
302 */
303 fatal(gettext(bulkerror(&N)));
304 }
305 if (sid.s_rel == 0 && N.n_sid.s_rel != 0) {
306 sid.s_rel = N.n_sid.s_rel;
307 sid.s_lev = N.n_sid.s_lev;
308 sid.s_br = N.n_sid.s_br;
309 sid.s_seq = N.n_sid.s_seq;
310 }
311 dir_name = N.n_dir_name;
312 }
313
314 if (strchr(file, '\'') || strchr(file, '\\'))
315 fatal(gettext("dangerous filename (cb5)"));
316 sinit(&gpkt, file, SI_OPEN);
317 gpkt.p_verbose = -1;
318 gpkt.p_stdout = stderr;
319 gpkt.p_enter = enter;
320 if (gpkt.p_verbose && (num_files > 1 || had_dir || had_standinp))
321 fprintf(gpkt.p_stdout, "\n%s:\n", gpkt.p_file);
322 if (exists(auxf(gpkt.p_file, 'p')))
323 fatal(gettext("p-file exists (cb1)"));
324
325 if (dodelt(&gpkt, &stats, (struct sid *) 0, 0) == 0)
326 fmterr(&gpkt);
327
328 Cvec = (int *)
329 fmalloc((unsigned) (n = ((maxser(&gpkt)+1) * sizeof (*Cvec))));
330 zero((char *) Cvec, n);
331 Cnt = 0;
332
333 if (HADP) {
334 rdp = gpkt.p_idel;
335 if (!(n = sidtoser(&sid, &gpkt)))
336 fatal(gettext("sid doesn't exist (cb3)"));
337 while (n <= maxser(&gpkt)) {
338 if (rdp[n].i_sid.s_rel == 0 &&
339 rdp[n].i_sid.s_lev == 0 &&
340 rdp[n].i_sid.s_br == 0 &&
341 rdp[n].i_sid.s_seq == 0) {
342 n++;
343 continue;
344 }
345 Cvec[Cnt++] = n++;
346 }
347 } else if (HADC) {
348 dolist(&gpkt, clist, 0);
349 } else {
350 rdp = gpkt.p_idel;
351 for (i = 1; i <= maxser(&gpkt); i++) {
352 succnt = 0;
353 if (rdp[i].i_sid.s_rel == 0 &&
354 rdp[i].i_sid.s_lev == 0 &&
355 rdp[i].i_sid.s_br == 0 &&
356 rdp[i].i_sid.s_seq == 0)
357 continue;
358 for (n = i + 1; n <= maxser(&gpkt); n++)
359 if (rdp[n].i_pred == i)
360 succnt++;
361 if (succnt != 1)
362 Cvec[Cnt++] = i;
363 }
364 }
365 finduser(&gpkt);
366 doflags(&gpkt);
367 donamedflags(&gpkt);
368 dometa(&gpkt);
369 sclose(&gpkt);
370 sfree(&gpkt);
371 if (!Cnt)
372 fatal(gettext("nothing to do (cb4)"));
373 rdp = gpkt.p_idel;
374 Do_prs = 0;
375 if (idx++ == 0) {
376 #if defined(INS_BASE)
377 #ifdef PROTOTYPES
378 fprintf(iop, "PATH=%s/" SCCS_BIN_PRE "bin:$PATH\n", INS_BASE);
379 #else
380 fprintf(iop, "PATH=%s/ccs/bin:$PATH\n", INS_BASE);
381 #endif
382 fprintf(iop, "export PATH\n");
383 #endif
384 fprintf(iop, "trap \"rm -f COMB$$ comb$$ s.COMB$$; exit 2\" 1 2 3 15\n");
385 fprintf(iop, "set -e\n");
386 fprintf(iop, "wdir=`pwd`\n");
387 }
388 fprintf(iop, "\n");
389 if (dir_name)
390 fprintf(iop, "cd '%s'\n", dir_name);
391 sp = prtget(rdp, Cvec[0], iop, gpkt.p_file);
392 sid_ba(sp, rarg);
393 if ((Val_ptr = gpkt.p_sflags[VALFLAG - 'a']) == NULL)
394 Val_ptr = Blank;
395 fprintf(iop, "v=`prs -r%s -d:MR: '%s'`\n", rarg, gpkt.p_file);
396 fprintf(iop, "vs=`val -v '%s'`\n", gpkt.p_file);
397 fprintf(iop, "V6=\n");
398 fprintf(iop, "ip=\n");
399 fprintf(iop, "ur=\n");
400 fprintf(iop, "case \"$vs\" in\n");
401 fprintf(iop, "SCCS\\ V6*)\n");
402 fprintf(iop, "\tV6=-V6\n");
403 fprintf(iop, "\tip=-XGp=`prs -d:Gp: '%s'`\n", gpkt.p_file);
404 fprintf(iop, "\tur=-XGr=`prs -d:Gr: '%s'`\n", gpkt.p_file);
405 fprintf(iop, "\t;;\n");
406 fprintf(iop, "esac\n");
407 fprintf(iop, "if test \"$v\"\n");
408 fprintf(iop, "then\n");
409 fprintf(iop,
410 "admin $V6 $ip $ur -iCOMB$$ -r%s -fv%s -m\"$v\" -y'This was COMBined' s.COMB$$\n",
411 rarg, Val_ptr);
412 fprintf(iop, "else\n");
413 fprintf(iop, "admin $V6 $ip $ur -iCOMB$$ -r%s -y'This was COMBined' s.COMB$$\n",
414 rarg);
415 fprintf(iop, "fi\n");
416 Do_prs = 1;
417 fprintf(iop, "rm -f COMB$$\n");
418 #if defined(BUG_1205145) || defined(GMT_TIME)
419 fprintf(iop, "TZ=GMT\n");
420 fprintf(iop, "export TZ\n");
421 #endif
422 for (i = 1; i < Cnt; i++) {
423 n = getpred(rdp, Cvec, i);
424 if (HADO)
425 fprintf(iop, "get -s -r%d -g -e -t s.COMB$$\n",
426 rdp[Cvec[i]].i_sid.s_rel);
427 else
428 fprintf(iop, "get -s -a%d -r%d -g -e s.COMB$$\n",
429 n + 1, rdp[Cvec[i]].i_sid.s_rel);
430 prtget(rdp, Cvec[i], iop, gpkt.p_file);
431 fprintf(iop, "if test \"$b\"\n");
432 fprintf(iop, "then\n");
433 fprintf(iop, "delta -s -m\"$b\" -y\"$a\" s.COMB$$\n");
434 fprintf(iop, "admin -fv s.COMB$$\n");
435 fprintf(iop, "else\n");
436 fprintf(iop, "delta -s -y\"$a\" s.COMB$$ </dev/null\n");
437 fprintf(iop, "fi\n");
438 fprintf(iop, "c1=`prs -d:D: s.COMB$$`\n");
439 fprintf(iop, "d1=`prs -d:T: s.COMB$$`\n");
440 fprintf(iop, "e1=`prs -d:P: s.COMB$$`\n");
441 fprintf(iop, "s=`prs -d:I: s.COMB$$`\n");
442 fprintf(iop, "sed '/d D '$s'/s|'$c1'|'$c'|' s.COMB$$ >comb$$\n");
443 fprintf(iop, "rm -f s.COMB$$\n");
444 fprintf(iop, "sed '/d D '$s'/s|'$d1'|'$d'|' comb$$ >COMB$$\n");
445 fprintf(iop, "sed '/d D '$s'/s|'$e1'|'$e'|' COMB$$ >s.COMB$$\n");
446 fprintf(iop, "if test \"$v\"\n");
447 fprintf(iop, "then\n");
448 fprintf(iop, "admin -z -fv s.COMB$$\n");
449 fprintf(iop, "else\n");
450 fprintf(iop, "admin -z s.COMB$$\n");
451 fprintf(iop, "fi\n");
452 }
453 fprintf(iop, "sed -n '/^%c%c$/,/^%c%c$/p' '%s' >comb$$\n",
454 CTLCHAR, BUSERTXT, CTLCHAR, EUSERTXT, gpkt.p_file);
455 fprintf(iop, "ed - comb$$ <<\\!\n");
456 fprintf(iop, "1d\n");
457 fprintf(iop, "$c\n");
458 fprintf(iop, "*** DELTA TABLE PRIOR TO COMBINE ***\n");
459 fprintf(iop, ".\n");
460 fprintf(iop, "w\n");
461 fprintf(iop, "q\n");
462 fprintf(iop, "!\n");
463 fprintf(iop, "prs -e '%s' >>comb$$\n", gpkt.p_file);
464 fprintf(iop, "admin -tcomb$$ s.COMB$$\\\n");
465 for (i = 0; i < NFLAGS; i++)
466 if ((p = gpkt.p_sflags[i]) != NULL)
467 if (i != (ENCODEFLAG-'a'))
468 fprintf(iop, " -f%c%s\\\n", i + 'a', p);
469 fprintf(iop, "\n");
470 fprintf(iop, "sed -n '/^%c%c$/,/^%c%c$/p' '%s' >comb$$\n",
471 CTLCHAR, BUSERNAM, CTLCHAR, EUSERNAM, gpkt.p_file);
472 fprintf(iop, "ed - comb$$ <<\\!\n");
473 fprintf(iop, "v/^%c/s/.*/ -a& \\\\/\n", CTLCHAR);
474 fprintf(iop, "1c\n");
475 fprintf(iop, "admin s.COMB$$\\\n");
476 fprintf(iop, ".\n");
477 fprintf(iop, "$c\n");
478 fprintf(iop, "\n");
479 fprintf(iop, ".\n");
480 fprintf(iop, "w\n");
481 fprintf(iop, "q\n");
482 fprintf(iop, "!\n");
483 fprintf(iop, ". comb$$\n");
484 fprintf(iop, "rm comb$$\n");
485 if (!HADS) {
486 fprintf(iop, "rm -f '%s'\n", gpkt.p_file);
487 fprintf(iop, "mv s.COMB$$ '%s'\n", gpkt.p_file);
488 if (!gpkt.p_sflags[VALFLAG - 'a'])
489 fprintf(iop, "admin -dv '%s'\n", gpkt.p_file);
490 } else {
491 fprintf(iop, "set `ls -st s.COMB$$ '%s'`\n", gpkt.p_file);
492 fprintf(iop, "c=`expr 100 - 100 '*' $1 / $3`\n");
493 fprintf(iop, "echo '%s\t' ${c}'%%\t' $1/$3\n", gpkt.p_file);
494 fprintf(iop, "rm -f s.COMB$$\n");
495 }
496 if (dir_name)
497 fprintf(iop, "cd \"$wdir\"\n");
498
499 ffreeall();
500 }
501
502 /*ARGSUSED*/
503 static void
enter(pkt,ch,n,sidp)504 enter(pkt, ch, n, sidp)
505 struct packet *pkt;
506 char ch;
507 int n;
508 struct sid *sidp;
509 {
510 Cvec[Cnt++] = n;
511 }
512
513
514 static struct sid *
prtget(idp,ser,fptr,file)515 prtget(idp, ser, fptr, file)
516 struct idel *idp;
517 int ser;
518 FILE *fptr;
519 char *file;
520 {
521 char buf[SID_STRSIZE];
522 struct sid *sp;
523
524 sid_ba(sp = &idp[ser].i_sid, buf);
525 fprintf(fptr, "get -s -k -r%s -p '%s' > COMB$$\n", buf, file);
526 if (Do_prs) {
527 fprintf(fptr, "a=`prs -r%s -d:C: '%s'`\n", buf, file);
528 fprintf(fptr, "b=`prs -r%s -d:MR: '%s'`\n", buf, file);
529 fprintf(fptr, "c=`prs -r%s -d:D: '%s'`\n", buf, file);
530 fprintf(fptr, "d=`prs -r%s -d:T: '%s'`\n", buf, file);
531 fprintf(fptr, "e=`prs -r%s -d:P: '%s'`\n", buf, file);
532 }
533 return (sp);
534 }
535
536
537 static int
getpred(idp,vec,i)538 getpred(idp, vec, i)
539 struct idel *idp;
540 int *vec;
541 int i;
542 {
543 int ser, pred, acpred;
544
545 ser = vec[i];
546 while (--i) {
547 pred = vec[i];
548 for (acpred = idp[ser].i_pred;
549 acpred; acpred = idp[acpred].i_pred)
550 if (pred == acpred)
551 break;
552 if (pred == acpred)
553 break;
554 }
555 return (i);
556 }
557
558 static void
clean_up()559 clean_up()
560 {
561 sclose(&gpkt);
562 sfree(&gpkt);
563 ffreeall();
564 }
565