12143Seric # include "../hdr/defines.h"
22143Seric # include "../hdr/had.h"
32143Seric 
4*33423Sbostic static char Sccsid[] = "@(#)admin.c	4.3	02/02/88";
52143Seric 
62143Seric /*
72143Seric 	Program to create new SCCS files and change parameters
82143Seric 	of existing ones. Arguments to the program may appear in
92143Seric 	any order and consist of keyletters, which begin with '-',
102143Seric 	and named files. Named files which do not exist are created
112143Seric 	and their parameters are initialized according to the given
122143Seric 	keyletter arguments, or are given default values if the
132143Seric 	corresponding keyletters were not supplied. Named files which
142143Seric 	do exist have those parameters corresponding to given key-letter
152143Seric 	arguments changed and other parameters are left as is.
162143Seric 
172143Seric 	If a directory is given as an argument, each SCCS file within
182143Seric 	the directory is processed as if it had been specifically named.
192143Seric 	If a name of '-' is given, the standard input is read for a list
202143Seric 	of names of SCCS files to be processed.
212143Seric 	Non-SCCS files are ignored.
222143Seric 
232143Seric 	Files created are given mode 444.
242143Seric */
252143Seric 
262143Seric # define MINR 1		/* minimum release number */
272143Seric # define MAXR 9999	/* maximum release number */
282143Seric # define MAXNAMES 9
292143Seric # define COPY 0
302143Seric # define NOCOPY 1
312143Seric 
322143Seric char *ifile, *tfile;
332143Seric char *z;	/* for validation program name */
342143Seric char had[26], had_flag[26], rm_flag[26];
352143Seric char	*Comments, *Mrs;
3630503Slepreau char Valpgm[] = "/usr/local/val";
372143Seric int irel, fexists, num_files;
3830503Slepreau int	VFLAG = 0;
392143Seric int	Domrs;
402143Seric char *Sflags[];
412143Seric char *anames[MAXNAMES], *enames[MAXNAMES];
422143Seric char *flag_p[26];
432143Seric int asub, esub;
442143Seric int check_id;
452143Seric int Did_id;
462143Seric 
main(argc,argv)472143Seric main(argc,argv)
482143Seric int argc;
492143Seric char *argv[];
502143Seric {
512143Seric 	register int j;
522143Seric 	register char *p;
532143Seric 	char c, f;
542143Seric 	int i, testklt;
552143Seric 	extern admin();
562143Seric 	extern int Fcnt;
572143Seric 	struct sid sid;
582143Seric 
592143Seric 	/*
602143Seric 	Set flags for 'fatal' to issue message, call clean-up
612143Seric 	routine and terminate processing.
622143Seric 	*/
632143Seric 	Fflags = FTLMSG | FTLCLN | FTLEXIT;
642143Seric 
652143Seric 	testklt = 1;
662143Seric 
672143Seric 	/*
682143Seric 	The following loop processes keyletters and arguments.
692143Seric 	Note that these are processed only once for each
702143Seric 	invocation of 'main'.
712143Seric 	*/
722143Seric 	for(j=1; j<argc; j++)
732143Seric 		if(argv[j][0] == '-' && (c = argv[j][1])) {
742143Seric 			p = &argv[j][2];
752143Seric 			switch (c) {
762143Seric 
772143Seric 			case 'i':	/* name of file of body */
782143Seric 				ifile = p;
792143Seric 				break;
802143Seric 
812143Seric 			case 't':	/* name of file of descriptive text */
822143Seric 				tfile = p;
832143Seric 				break;
842143Seric 			case 'm':	/* mr flag */
852143Seric 				Mrs = p;
862143Seric 				break;
872143Seric 			case 'y':	/* comments flag for entry */
882143Seric 				Comments = p;
892143Seric 				break;
902143Seric 
912143Seric 			case 'd':	/* flags to be deleted */
922143Seric 				testklt = 0;
932143Seric 				if (!(f = *p))
942143Seric 					fatal("d has no argument (ad1)");
952143Seric 				p = &argv[j][3];
962143Seric 
972143Seric 				switch (f) {
982143Seric 
992143Seric 				case IDFLAG:	/* see 'f' keyletter */
1002143Seric 				case BRCHFLAG:	/* for meanings of flags */
1012143Seric 				case VALFLAG:
1022143Seric 				case TYPEFLAG:
1032143Seric 				case MODFLAG:
1042143Seric 				case NULLFLAG:
1052143Seric 				case FLORFLAG:
1062143Seric 				case CEILFLAG:
1072143Seric 				case DEFTFLAG:
108*33423Sbostic 					if (*p) {
109*33423Sbostic 						sprintf(Error, "value after %c flag (ad12)",f);
110*33423Sbostic 						fatal(Error);
111*33423Sbostic 					}
1122143Seric 					break;
1132143Seric 
1142143Seric 				default:
1152143Seric 					fatal("unknown flag (ad3)");
1162143Seric 				}
1172143Seric 
1182143Seric 				if (rm_flag[f - 'a']++)
1192143Seric 					fatal("flag twice (ad4)");
1202143Seric 				break;
1212143Seric 
1222143Seric 			case 'f':	/* flags to be added */
1232143Seric 				testklt = 0;
1242143Seric 				if (!(f = *p))
1252143Seric 					fatal("f has no argument (ad5)");
1262143Seric 				p = &argv[j][3];
1272143Seric 
1282143Seric 				switch (f) {
1292143Seric 
1302143Seric 				case IDFLAG:	/* id-kwd message (err/warn) */
1312143Seric 				case BRCHFLAG:	/* branch */
1322143Seric 				case NULLFLAG:	/* null deltas */
133*33423Sbostic 					if (*p) {
134*33423Sbostic 						sprintf(Error, "value after %c flag (ad13)",f);
135*33423Sbostic 						fatal(Error);
136*33423Sbostic 					}
1372143Seric 					break;
1382143Seric 
1392143Seric 				case VALFLAG:	/* mr validation */
1402143Seric 					VFLAG++;
1412143Seric 					if (*p)
1422143Seric 						z = p;
1432143Seric 					break;
1442143Seric 
1452143Seric 				case FLORFLAG:	/* floor */
1462143Seric 					if ((i = patoi(p)) == -1)
1472143Seric 						fatal("floor not numeric (ad22)");
1482143Seric 					if ((size(p) > 5) || (i < MINR) ||
1492143Seric 							(i > MAXR))
1502143Seric 						fatal("floor out of range (ad23)");
1512143Seric 					break;
1522143Seric 
1532143Seric 				case CEILFLAG:	/* ceiling */
1542143Seric 					if ((i = patoi(p)) == -1)
1552143Seric 						fatal("ceiling not numeric (ad24)");
1562143Seric 					if ((size(p) > 5) || (i < MINR) ||
1572143Seric 							(i > MAXR))
1582143Seric 						fatal("ceiling out of range (ad25)");
1592143Seric 					break;
1602143Seric 
1612143Seric 				case DEFTFLAG:	/* default sid */
1622143Seric 					if (!(*p))
1632143Seric 						fatal("no default sid (ad14)");
1642143Seric 					chksid(sid_ab(p,&sid),&sid);
1652143Seric 					break;
1662143Seric 
1672143Seric 				case TYPEFLAG:	/* type */
1682143Seric 				case MODFLAG:	/* module name */
169*33423Sbostic 					if (!(*p)) {
170*33423Sbostic 						sprintf(Error, "flag %c has no value (ad2)",f);
171*33423Sbostic 						fatal(Error);
172*33423Sbostic 					}
1732143Seric 					break;
1742143Seric 
1752143Seric 				default:
1762143Seric 					fatal("unknown flag (ad3)");
1772143Seric 				}
1782143Seric 
1792143Seric 				if (had_flag[f - 'a']++)
1802143Seric 					fatal("flag twice (ad4)");
1812143Seric 				flag_p[f - 'a'] = p;
1822143Seric 				break;
1832143Seric 
1842143Seric 			case 'r':	/* initial release number supplied */
1852143Seric 				if ((irel = patoi(p)) == -1)
1862143Seric 					fatal("r arg not numeric (ad6)");
1872143Seric 				if ((size(p) > 5) || (irel < MINR) ||
1882143Seric 						(irel > MAXR))
1892143Seric 					fatal("r out of range (ad7)");
1902143Seric 				break;
1912143Seric 
1922143Seric 			case 'n':	/* creating new SCCS file */
1932143Seric 			case 'h':	/* only check hash of file */
1942143Seric 			case 'z':	/* zero the input hash */
1952143Seric 				break;
1962143Seric 
1972143Seric 			case 'a':	/* user-name allowed to make deltas */
1982143Seric 				testklt = 0;
1992143Seric 				if (!(*p))
2002143Seric 					fatal("bad a argument (ad8)");
2012143Seric 				if (asub > MAXNAMES)
2022143Seric 					fatal("too many 'a' keyletters (ad9)");
2032143Seric 				anames[asub++] = p;
2042143Seric 				break;
2052143Seric 
2062143Seric 			case 'e':	/* user-name to be removed */
2072143Seric 				testklt = 0;
2082143Seric 				if (!(*p))
2092143Seric 					fatal("bad e argument (ad10)");
2102143Seric 				if (esub > MAXNAMES)
2112143Seric 					fatal("too many 'e' keyletters (ad11)");
2122143Seric 				enames[esub++] = p;
2132143Seric 				break;
2142143Seric 
2152143Seric 			default:
2162143Seric 				fatal("unknown key letter (cm1)");
2172143Seric 			}
2182143Seric 
2192143Seric 			if (had[c - 'a']++ && testklt++)
2202143Seric 				fatal("key letter twice (cm2)");
2212143Seric 			argv[j] = 0;
2222143Seric 		}
2232143Seric 		else
2242143Seric 			num_files++;
2252143Seric 
2262143Seric 	if (num_files == 0)
2272143Seric 		fatal("missing file arg (cm3)");
2282143Seric 
2292143Seric 	if (HADI && num_files > 1) /* only one file allowed with `i' */
2302143Seric 		fatal("more than one file (ad15)");
2312143Seric 
2322143Seric 	setsig();
2332143Seric 
2342143Seric 	/*
2352143Seric 	Change flags for 'fatal' so that it will return to this
2362143Seric 	routine (main) instead of terminating processing.
2372143Seric 	*/
23830503Slepreau 	Fflags &= ~FTLEXIT;
23930503Slepreau 	Fflags |= FTLJMP;
2402143Seric 
2412143Seric 	/*
2422143Seric 	Call 'admin' routine for each file argument.
2432143Seric 	*/
2442143Seric 	for (j=1; j<argc; j++)
2452143Seric 		if (p = argv[j])
2462143Seric 			do_file(p,admin);
2472143Seric 
2482143Seric 	exit(Fcnt ? 1 : 0);
2492143Seric }
2502143Seric 
2512143Seric 
2522143Seric /*
2532143Seric 	Routine that actually does admin's work on SCCS files.
2542143Seric 	Existing s-files are copied, with changes being made, to a
2552143Seric 	temporary file (x-file). The name of the x-file is the same as the
2562143Seric 	name of the s-file, with the 's.' replaced by 'x.'.
2572143Seric 	s-files which are to be created are processed in a similar
2582143Seric 	manner, except that a dummy s-file is first created with
2592143Seric 	mode 444.
2602143Seric 	At end of processing, the x-file is renamed with the name of s-file
2612143Seric 	and the old s-file is removed.
2622143Seric */
2632143Seric 
2642143Seric struct packet gpkt;	/* see file defines.h */
2652143Seric char	Zhold[BUFSIZ];	/* temporary z-file name */
2662143Seric 
2672143Seric USXALLOC();		/* defines alloc() and free() */
2682143Seric 
admin(afile)2692143Seric admin(afile)
2702143Seric char *afile;
2712143Seric {
2722143Seric 	struct deltab dt;	/* see file defines.h */
2732143Seric 	struct stats stats;	/* see file defines.h */
2742143Seric 	FILE *iptr;
2752143Seric 	register int k;
2762143Seric 	register char *cp, *q;
2772143Seric 	char command[80];
2782143Seric 	char line[512];
2792143Seric 	int i;			/* used in forking procedure */
2802143Seric 	int status;
2812143Seric 	extern nfiles;
2822143Seric 	extern had_dir;
2832143Seric 
2842143Seric 	if (setjmp(Fjmp))	/* set up to return here from 'fatal' */
2852143Seric 		return;		/* and return to caller of admin */
2862143Seric 
2872143Seric 	if (HADI && had_dir) /* directory not allowed with `i' keyletter */
2882143Seric 		fatal("directory named with `i' keyletter (ad26)");
2892143Seric 
2902143Seric 	fexists = exists(afile);
2912143Seric 
2922143Seric 	if (HADI)
2932143Seric 		HADN = 1;
2942143Seric 	if (HADI || HADN) {
2952143Seric 		if (HADM && !VFLAG)
2962143Seric 			fatal("MRs not allowed (de8)");
2972143Seric 
2982143Seric 		if (VFLAG && !HADM)
2992143Seric 			fatal("MRs required (de10)");
3002143Seric 
3012143Seric 	}
3022143Seric 
3032143Seric 	if (!HADI && HADR)
3042143Seric 		fatal("r only allowed with i (ad16)");
3052143Seric 
3062143Seric 	if (HADN && HADT && !(*tfile))
3072143Seric 		fatal("t has no argument (ad17)");
3082143Seric 
3092143Seric 	if (HADN && HADD)
3102143Seric 		fatal("d not allowed with n (ad18)");
3112143Seric 
312*33423Sbostic 	if (HADN && fexists) {
313*33423Sbostic 		sprintf(Error,"file %s exists (ad19)",afile);
314*33423Sbostic 		fatal(Error);
315*33423Sbostic 	}
3162143Seric 
317*33423Sbostic 	if (!HADN && !fexists) {
318*33423Sbostic 		sprintf(Error,"file %s does not exist (ad20)",afile);
319*33423Sbostic 		fatal(Error);
320*33423Sbostic 	}
3212143Seric 	/*
3222143Seric 	   Check for '-h' flag.  If set, create child process and
3232143Seric 	   invoke 'get' to examine format of SCCS file.
3242143Seric 	*/
3252143Seric 
3262143Seric 	if (HADH) {
3272143Seric 		/*
3282143Seric 		   fork here so 'admin' can execute 'val' to
3292143Seric 		   check for a corrupted file.
3302143Seric 		*/
3312143Seric 		if ((i = fork()) < 0)
3322143Seric 			fatal("cannot fork, try again");
3332143Seric 		if (i == 0) {		/* child */
3342143Seric 			/*
3352143Seric 			   perform 'val' with appropriate keyletters
3362143Seric 			*/
337*33423Sbostic 			sprintf(command, "/usr/local/val -s %s", afile);
338*33423Sbostic 			execl("/bin/sh","/bin/sh","-c", command, 0);
339*33423Sbostic 			sprintf(Error,"cannot execute '%s'",Valpgm);
340*33423Sbostic 			fatal(Error);
3412143Seric 		}
3422143Seric 		else {
3432143Seric 			wait(&status);	   /* wait on status from 'execl' */
3442143Seric 			if (status)
3452143Seric 				fatal("corrupted file (co6)");
3462143Seric 			return;		/* return to caller of 'admin' */
3472143Seric 		}
3482143Seric 	}
3492143Seric 
3502143Seric 	/*
3512143Seric 	Lock out any other user who may be trying to process
3522143Seric 	the same file.
3532143Seric 	*/
3542143Seric 	if (!HADH && lockit(copy(auxf(afile,'z'),Zhold),2,getpid()))
3552143Seric 		fatal("cannot create lock file (cm4)");
3562143Seric 
3572143Seric 	if (fexists)
3582143Seric 		sinit(&gpkt,afile,1);	/* init pkt & open s-file */
3592143Seric 	else {
3602143Seric 		xfcreat(afile,0444);	/* create dummy s-file */
3612143Seric 		sinit(&gpkt,afile,0);	/* and init pkt */
3622143Seric 	}
3632143Seric 
3642143Seric 	if (!HADH)
3652143Seric 		/*
3662143Seric 		   set the flag for 'putline' routine to open
3672143Seric 		   the 'x-file' and allow writing on it.
3682143Seric 		*/
3692143Seric 		gpkt.p_upd = 1;
3702143Seric 
3712143Seric 	if (HADZ) {
3722143Seric 		gpkt.do_chksum = 0;	/* ignore checksum processing */
3732143Seric 		gpkt.p_ihash = 0;
3742143Seric 	}
3752143Seric 
3762143Seric 	/*
3772143Seric 	Get statistics of latest delta in old file.
3782143Seric 	*/
3792143Seric 	if (!HADN) {
3802143Seric 		stats_ab(&gpkt,&stats);
3812143Seric 		gpkt.p_wrttn++;
3822143Seric 		newstats(&gpkt,line,"0");
3832143Seric 	}
3842143Seric 
3852143Seric 	if (HADN) {		/*   N E W   F I L E   */
3862143Seric 
3872143Seric 		/*
3882143Seric 		Beginning of SCCS file.
3892143Seric 		*/
390*33423Sbostic 		sprintf(line,"%c%c%s\n",CTLCHAR,HEAD,"00000");
391*33423Sbostic 		putline(&gpkt,line);
3922143Seric 
3932143Seric 		/*
3942143Seric 		Statistics.
3952143Seric 		*/
3962143Seric 		newstats(&gpkt,line,"0");
3972143Seric 
3982143Seric 		dt.d_type = 'D';	/* type of delta */
3992143Seric 
4002143Seric 		/*
4012143Seric 		Set initial release, level, branch and
4022143Seric 		sequence values.
4032143Seric 		*/
4042143Seric 		if (HADR)
4052143Seric 			dt.d_sid.s_rel = irel;
4062143Seric 		else
4072143Seric 			dt.d_sid.s_rel = 1;
4082143Seric 		dt.d_sid.s_lev = 1;
4092143Seric 		dt.d_sid.s_br = dt.d_sid.s_seq = 0;
4102143Seric 
4112143Seric 		time(&dt.d_datetime);		/* get time and date */
4122143Seric 
4132143Seric 		copy(logname(),dt.d_pgmr);	/* get user's name */
4142143Seric 
4152143Seric 		dt.d_serial = 1;
4162143Seric 		dt.d_pred = 0;
4172143Seric 
4182143Seric 		del_ba(&dt,line);	/* form and write */
4192143Seric 		putline(&gpkt,line);	/* delta-table entry */
4202143Seric 
4212143Seric 		/*
4222143Seric 		If -m flag, enter MR numbers
4232143Seric 		*/
4242143Seric 
4252143Seric 		if (Mrs) {
4262143Seric 			mrfixup();
4272143Seric 			if (z && valmrs(&gpkt,z))
4282143Seric 				fatal("invalid MRs (de9)");
4292143Seric 			putmrs(&gpkt);
4302143Seric 		}
4312143Seric 
4322143Seric 		/*
4332143Seric 		Enter comment line for `chghist'
4342143Seric 		*/
4352143Seric 
4362143Seric 		if (HADY) {
437*33423Sbostic 			sprintf(line,"%c%c ",CTLCHAR,COMMENTS);
438*33423Sbostic 			putline(&gpkt,line);
4392143Seric 			putline(&gpkt,Comments);
4402143Seric 			putline(&gpkt,"\n");
4412143Seric 		}
4422143Seric 		else {
4432143Seric 			/*
4442143Seric 			insert date/time and pgmr into comment line
4452143Seric 			*/
4462143Seric 			cmt_ba(&dt,line);
4472143Seric 			putline(&gpkt,line);
4482143Seric 		}
4492143Seric 		/*
4502143Seric 		End of delta-table.
4512143Seric 		*/
452*33423Sbostic 		sprintf(line,CTLSTR,CTLCHAR,EDELTAB);
453*33423Sbostic 		putline(&gpkt,line);
4542143Seric 
4552143Seric 		/*
4562143Seric 		Beginning of user-name section.
4572143Seric 		*/
458*33423Sbostic 		sprintf(line,CTLSTR,CTLCHAR,BUSERNAM);
459*33423Sbostic 		putline(&gpkt,line);
4602143Seric 	}
4612143Seric 	else
4622143Seric 		/*
4632143Seric 		For old file, copy to x-file until user-name section
4642143Seric 		is found.
4652143Seric 		*/
4662143Seric 		flushto(&gpkt,BUSERNAM,COPY);
4672143Seric 
4682143Seric 	/*
4692143Seric 	Write user-names to be added to list of those
4702143Seric 	allowed to make deltas.
4712143Seric 	*/
4722143Seric 	if (HADA)
473*33423Sbostic 		for (k = 0; k < asub; k++) {
474*33423Sbostic 			sprintf(line,"%s\n",anames[k]);
475*33423Sbostic 			putline(&gpkt,line);
476*33423Sbostic 		}
4772143Seric 
4782143Seric 	/*
4792143Seric 	Do not copy those user-names which are to be erased.
4802143Seric 	*/
4812143Seric 	if (HADE && !HADN)
4822143Seric 		while ((cp = getline(&gpkt)) &&
4832143Seric 				!(*cp++ == CTLCHAR && *cp == EUSERNAM)) {
4842143Seric 			for (k = 0; k < esub; k++) {
4852143Seric 				cp = &gpkt.p_line;
4862143Seric 				while (*cp)	/* find and */
4872143Seric 					cp++;	/* zero newline */
4882143Seric 				*--cp = '\0';	/* character */
4892143Seric 
4902143Seric 				if (equal(enames[k],&gpkt.p_line)) {
4912143Seric 					/*
4922143Seric 					Tell getline not to output
4932143Seric 					previously read line.
4942143Seric 					*/
4952143Seric 					gpkt.p_wrttn = 1;
4962143Seric 					break;
4972143Seric 				}
4982143Seric 				else
4992143Seric 					*cp = '\n';	/* restore newline */
5002143Seric 			}
5012143Seric 		}
5022143Seric 
5032143Seric 	if (HADN) {		/*   N E W  F I L E   */
5042143Seric 
5052143Seric 		/*
5062143Seric 		End of user-name section.
5072143Seric 		*/
508*33423Sbostic 		sprintf(line,CTLSTR,CTLCHAR,EUSERNAM);
509*33423Sbostic 		putline(&gpkt,line);
5102143Seric 	}
5112143Seric 	else
5122143Seric 		/*
5132143Seric 		For old file, copy to x-file until end of
5142143Seric 		user-names section is found.
5152143Seric 		*/
5162143Seric 		if (!HADE)
5172143Seric 			flushto(&gpkt,EUSERNAM,COPY);
5182143Seric 
5192143Seric 	/*
5202143Seric 	For old file, read flags and their values (if any), and
5212143Seric 	store them. Check to see if the flag read is one that
5222143Seric 	should be deleted.
5232143Seric 	*/
5242143Seric 	if (!HADN)
5252143Seric 		while ((cp = getline(&gpkt)) &&
5262143Seric 				(*cp++ == CTLCHAR && *cp == FLAG)) {
5272143Seric 
5282143Seric 			gpkt.p_wrttn = 1;	/* don't write previous line */
5292143Seric 
53030503Slepreau 			cp += 2;	/* point to flag character */
5312143Seric 			k = *cp - 'a';
5322143Seric 
5332143Seric 			if (!had_flag[k] && !rm_flag[k]) {
5342143Seric 				had_flag[k] = 2;	/* indicate flag is */
5352143Seric 							/* from file, not */
5362143Seric 							/* from arg list */
5372143Seric 
5382143Seric 				if (*++cp != '\n') {	/* get flag value */
5392143Seric 					q = alloc(size(gpkt.p_line)-5);
5402143Seric 					copy(++cp,q);
5412143Seric 					flag_p[k] = q;
5422143Seric 					while (*q)	/* find and */
5432143Seric 						q++;	/* zero newline */
5442143Seric 					*--q = '\0';	/* character */
5452143Seric 				}
5462143Seric 			}
5472143Seric 			else
5482143Seric 				if (rm_flag[k])
5492143Seric 					had_flag[k] = 0;
5502143Seric 		}
5512143Seric 
5522143Seric 
5532143Seric 	/*
5542143Seric 	Write out flags.
5552143Seric 	*/
5562143Seric 	for (k = 0; k < 26; k++)
5572143Seric 		if (had_flag[k]) {
5582143Seric 			if (flag_p[k])
5592143Seric 				sprintf(line,"%c%c %c %s\n",
5602143Seric 					CTLCHAR,FLAG,'a'+k,flag_p[k]);
5612143Seric 			else
5622143Seric 				sprintf(line,"%c%c %c\n",
5632143Seric 					CTLCHAR,FLAG,'a'+k);
5642143Seric 
5652143Seric 			putline(&gpkt,line);
5662143Seric 
5672143Seric 			if (had_flag[k] == 2) {	/* flag was taken from file */
5682143Seric 				had_flag[k] = 0;
5692143Seric 				if (flag_p[k]) {
5702143Seric 					free(flag_p[k]);
5712143Seric 					flag_p[k] = 0;
5722143Seric 				}
5732143Seric 			}
5742143Seric 		}
5752143Seric 
576*33423Sbostic 	if (HADN) {
5772143Seric 		/*
5782143Seric 		Beginning of descriptive (user) text.
5792143Seric 		*/
580*33423Sbostic 		sprintf(line,CTLSTR,CTLCHAR,BUSERTXT);
581*33423Sbostic 		putline(&gpkt,line);
582*33423Sbostic 	}
5832143Seric 	else
5842143Seric 		/*
5852143Seric 		Write out BUSERTXT record which was read in
5862143Seric 		above loop that processes flags.
5872143Seric 		*/
5882143Seric 		gpkt.p_wrttn = 0;
5892143Seric 		putline(&gpkt,0);
5902143Seric 
5912143Seric 	/*
5922143Seric 	Get user description, copy to x-file.
5932143Seric 	*/
5942143Seric 	if (HADT) {
5952143Seric 		if (*tfile) {
5962143Seric 			iptr = xfopen(tfile,0);
5972143Seric 			fgetchk(line,512,iptr,tfile,&gpkt);
5982143Seric 			fclose(iptr);
5992143Seric 		}
6002143Seric 
6012143Seric 		/*
6022143Seric 		If old file, ignore any previously supplied
6032143Seric 		commentary. (i.e., don't copy it to x-file.)
6042143Seric 		*/
6052143Seric 		if (!HADN)
6062143Seric 			flushto(&gpkt,EUSERTXT,NOCOPY);
6072143Seric 	}
6082143Seric 
6092143Seric 	if (HADN) {		/*   N E W  F I L E   */
6102143Seric 
6112143Seric 		/*
6122143Seric 		End of user description.
6132143Seric 		*/
614*33423Sbostic 		sprintf(line,CTLSTR,CTLCHAR,EUSERTXT);
615*33423Sbostic 		putline(&gpkt,line);
6162143Seric 
6172143Seric 		/*
6182143Seric 		Beginning of body (text) of first delta.
6192143Seric 		*/
620*33423Sbostic 		sprintf(line,"%c%c %u\n",CTLCHAR,INS,1);
621*33423Sbostic 		putline(&gpkt,line);
6222143Seric 
6232143Seric 		if (HADI) {		/* get body */
6242143Seric 
6252143Seric 			/*
6262143Seric 			Set indicator to check lines of body of file for
6272143Seric 			keyword definitions.
6282143Seric 			If no keywords are found, a warning
6292143Seric 			will be produced.
6302143Seric 			*/
6312143Seric 			check_id = 1;
6322143Seric 			/*
6332143Seric 			Set indicator that tells whether there
6342143Seric 			were any keywords to 'no'.
6352143Seric 			*/
6362143Seric 			Did_id = 0;
6372143Seric 			if (*ifile)
6382143Seric 				iptr = xfopen(ifile,0);	/* from a file */
6392143Seric 			else
6402143Seric 				iptr = stdin;	/* from standard input */
6412143Seric 
6422143Seric 			/*
6432143Seric 			Read and copy to x-file, while checking
6442143Seric 			first character of each line to see that it
6452143Seric 			is not the control character (octal 1).
6462143Seric 			Also, count lines read, and set statistics'
6472143Seric 			structure appropriately.
6482143Seric 			The 'fgetchk' routine will check for keywords.
6492143Seric 			*/
6502143Seric 			stats.s_ins = fgetchk(line,512,iptr,ifile,&gpkt);
6512143Seric 			stats.s_del = stats.s_unc = 0;
6522143Seric 
6532143Seric 			/*
6542143Seric 			If no keywords were found, issue warning.
6552143Seric 			*/
6562143Seric 			if (!Did_id) {
6572143Seric 				if (had_flag[IDFLAG - 'a'])
6582143Seric 					fatal("no id keywords (cm6)");
6592143Seric 				else
6602143Seric 					fprintf(stderr,"%s\n","No id keywords (cm7)");
6612143Seric 			}
6622143Seric 
6632143Seric 			check_id = 0;
6642143Seric 			Did_id = 0;
6652143Seric 		}
6662143Seric 
6672143Seric 		/*
6682143Seric 		End of body of first delta.
6692143Seric 		*/
670*33423Sbostic 		sprintf(line,"%c%c %u\n",CTLCHAR,END,1);
671*33423Sbostic 		putline(&gpkt,line);
6722143Seric 	}
6732143Seric 	else {
6742143Seric 		/*
6752143Seric 		Indicate that EOF at this point is ok, and
6762143Seric 		flush rest of (old) s-file to x-file.
6772143Seric 		*/
6782143Seric 		gpkt.p_chkeof = 1;
6792143Seric 		while (getline(&gpkt)) ;
6802143Seric 	}
6812143Seric 
6822143Seric 	/*
6832143Seric 	Flush the buffer, take care of rewinding to insert
6842143Seric 	checksum and statistics in file, and close.
6852143Seric 	*/
6862143Seric 	flushline(&gpkt,&stats);
6872143Seric 
6882143Seric 	/*
6892143Seric 	Change x-file name to s-file, and delete old file.
6902143Seric 	Unlock file before returning.
6912143Seric 	*/
6922143Seric 	if (!HADH) {
6932143Seric 		rename(auxf(&gpkt,'x'),&gpkt);
6942143Seric 		xrm(&gpkt);
6952143Seric 		unlockit(auxf(afile,'z'),getpid());
6962143Seric 	}
6972143Seric }
6982143Seric 
6992143Seric 
fgetchk(strp,len,inptr,file,pkt)7002143Seric fgetchk(strp,len,inptr,file,pkt)
7012143Seric register char *strp;
7022143Seric register int len;
7032143Seric FILE *inptr;
7042143Seric register char *file;
7052143Seric register struct packet *pkt;
7062143Seric {
7072143Seric 	register int k;
7082143Seric 
7092143Seric 	for (k = 1; fgets(strp,len,inptr); k++) {
710*33423Sbostic 		if (*strp == CTLCHAR) {
7112143Seric 			sprintf(Error,"%s illegal data on line %d (ad21)",
712*33423Sbostic 				file,k);
713*33423Sbostic 			fatal(Error);
714*33423Sbostic 		}
7152143Seric 
7162143Seric 		if (check_id)
7172143Seric 			chkid(strp);
7182143Seric 
7192143Seric 		putline(pkt,strp);
7202143Seric 	}
7212143Seric 	return(k - 1);
7222143Seric }
7232143Seric 
7242143Seric 
clean_up()7252143Seric clean_up()
7262143Seric {
7272143Seric 	xrm(&gpkt);
7282143Seric 	if (!HADH)
7292143Seric 		unlockit(Zhold,getpid());
7302143Seric 	if (HADN)
7312143Seric 		unlink(&gpkt);
7322143Seric }
7332143Seric 
7342143Seric 
cmt_ba(dt,str)7352143Seric cmt_ba(dt,str)
7362143Seric register struct deltab *dt;
7372143Seric char *str;
7382143Seric {
7392143Seric 	register char *p;
7402143Seric 
7412143Seric 	p = str;
7422143Seric 	*p++ = CTLCHAR;
7432143Seric 	*p++ = COMMENTS;
7442143Seric 	*p++ = ' ';
7452143Seric 	copy("date and time created",p);
7462143Seric 	while (*p++)
7472143Seric 		;
7482143Seric 	--p;
7492143Seric 	*p++ = ' ';
7502143Seric 	date_ba(&dt->d_datetime,p);
7512143Seric 	while (*p++)
7522143Seric 		;
7532143Seric 	--p;
7542143Seric 	*p++ = ' ';
7552143Seric 	copy("by",p);
7562143Seric 	while (*p++)
7572143Seric 		;
7582143Seric 	--p;
7592143Seric 	*p++ = ' ';
7602143Seric 	copy(dt->d_pgmr,p);
7612143Seric 	while (*p++)
7622143Seric 		;
7632143Seric 	--p;
7642143Seric 	*p++ = '\n';
7652143Seric 	*p = 0;
7662143Seric 	return(str);
7672143Seric }
7682143Seric 
7692143Seric 
7702143Seric putmrs(pkt)
7712143Seric struct packet *pkt;
7722143Seric {
7732143Seric 	register char **argv;
7742143Seric 	char str[64];
7752143Seric 	extern char *Varg[];
7762143Seric 
7772143Seric 	for (argv = &Varg[VSTART]; *argv; argv++)
778*33423Sbostic 		sprintf(str,"%c%c %s\n",CTLCHAR,MRNUM,*argv);
779*33423Sbostic 		putline(pkt,str);
7802143Seric }
781