Commit | Line | Data |
---|---|---|
5a89b91c EA |
1 | # include "../hdr/defines.h" |
2 | # include "../hdr/had.h" | |
3 | ||
38c01699 | 4 | static char Sccsid[] = "@(#)admin.c 4.2 %G%"; |
5a89b91c EA |
5 | |
6 | /* | |
7 | Program to create new SCCS files and change parameters | |
8 | of existing ones. Arguments to the program may appear in | |
9 | any order and consist of keyletters, which begin with '-', | |
10 | and named files. Named files which do not exist are created | |
11 | and their parameters are initialized according to the given | |
12 | keyletter arguments, or are given default values if the | |
13 | corresponding keyletters were not supplied. Named files which | |
14 | do exist have those parameters corresponding to given key-letter | |
15 | arguments changed and other parameters are left as is. | |
16 | ||
17 | If a directory is given as an argument, each SCCS file within | |
18 | the directory is processed as if it had been specifically named. | |
19 | If a name of '-' is given, the standard input is read for a list | |
20 | of names of SCCS files to be processed. | |
21 | Non-SCCS files are ignored. | |
22 | ||
23 | Files created are given mode 444. | |
24 | */ | |
25 | ||
26 | # define MINR 1 /* minimum release number */ | |
27 | # define MAXR 9999 /* maximum release number */ | |
28 | # define MAXNAMES 9 | |
29 | # define COPY 0 | |
30 | # define NOCOPY 1 | |
31 | ||
32 | char *ifile, *tfile; | |
33 | char *z; /* for validation program name */ | |
34 | char had[26], had_flag[26], rm_flag[26]; | |
35 | char *Comments, *Mrs; | |
38c01699 | 36 | char Valpgm[] = "/usr/local/val"; |
5a89b91c | 37 | int irel, fexists, num_files; |
38c01699 | 38 | int VFLAG = 0; |
5a89b91c EA |
39 | int Domrs; |
40 | char *Sflags[]; | |
41 | char *anames[MAXNAMES], *enames[MAXNAMES]; | |
42 | char *flag_p[26]; | |
43 | int asub, esub; | |
44 | int check_id; | |
45 | int Did_id; | |
46 | ||
47 | main(argc,argv) | |
48 | int argc; | |
49 | char *argv[]; | |
50 | { | |
51 | register int j; | |
52 | register char *p; | |
53 | char c, f; | |
54 | int i, testklt; | |
55 | extern admin(); | |
56 | extern int Fcnt; | |
57 | struct sid sid; | |
58 | ||
59 | /* | |
60 | Set flags for 'fatal' to issue message, call clean-up | |
61 | routine and terminate processing. | |
62 | */ | |
63 | Fflags = FTLMSG | FTLCLN | FTLEXIT; | |
64 | ||
65 | testklt = 1; | |
66 | ||
67 | /* | |
68 | The following loop processes keyletters and arguments. | |
69 | Note that these are processed only once for each | |
70 | invocation of 'main'. | |
71 | */ | |
72 | for(j=1; j<argc; j++) | |
73 | if(argv[j][0] == '-' && (c = argv[j][1])) { | |
74 | p = &argv[j][2]; | |
75 | switch (c) { | |
76 | ||
77 | case 'i': /* name of file of body */ | |
78 | ifile = p; | |
79 | break; | |
80 | ||
81 | case 't': /* name of file of descriptive text */ | |
82 | tfile = p; | |
83 | break; | |
84 | case 'm': /* mr flag */ | |
85 | Mrs = p; | |
86 | break; | |
87 | case 'y': /* comments flag for entry */ | |
88 | Comments = p; | |
89 | break; | |
90 | ||
91 | case 'd': /* flags to be deleted */ | |
92 | testklt = 0; | |
93 | if (!(f = *p)) | |
94 | fatal("d has no argument (ad1)"); | |
95 | p = &argv[j][3]; | |
96 | ||
97 | switch (f) { | |
98 | ||
99 | case IDFLAG: /* see 'f' keyletter */ | |
100 | case BRCHFLAG: /* for meanings of flags */ | |
101 | case VALFLAG: | |
102 | case TYPEFLAG: | |
103 | case MODFLAG: | |
104 | case NULLFLAG: | |
105 | case FLORFLAG: | |
106 | case CEILFLAG: | |
107 | case DEFTFLAG: | |
108 | if (*p) | |
109 | fatal(sprintf(Error, | |
110 | "value after %c flag (ad12)",f)); | |
111 | break; | |
112 | ||
113 | default: | |
114 | fatal("unknown flag (ad3)"); | |
115 | } | |
116 | ||
117 | if (rm_flag[f - 'a']++) | |
118 | fatal("flag twice (ad4)"); | |
119 | break; | |
120 | ||
121 | case 'f': /* flags to be added */ | |
122 | testklt = 0; | |
123 | if (!(f = *p)) | |
124 | fatal("f has no argument (ad5)"); | |
125 | p = &argv[j][3]; | |
126 | ||
127 | switch (f) { | |
128 | ||
129 | case IDFLAG: /* id-kwd message (err/warn) */ | |
130 | case BRCHFLAG: /* branch */ | |
131 | case NULLFLAG: /* null deltas */ | |
132 | if (*p) | |
133 | fatal(sprintf(Error, | |
134 | "value after %c flag (ad13)",f)); | |
135 | break; | |
136 | ||
137 | case VALFLAG: /* mr validation */ | |
138 | VFLAG++; | |
139 | if (*p) | |
140 | z = p; | |
141 | break; | |
142 | ||
143 | case FLORFLAG: /* floor */ | |
144 | if ((i = patoi(p)) == -1) | |
145 | fatal("floor not numeric (ad22)"); | |
146 | if ((size(p) > 5) || (i < MINR) || | |
147 | (i > MAXR)) | |
148 | fatal("floor out of range (ad23)"); | |
149 | break; | |
150 | ||
151 | case CEILFLAG: /* ceiling */ | |
152 | if ((i = patoi(p)) == -1) | |
153 | fatal("ceiling not numeric (ad24)"); | |
154 | if ((size(p) > 5) || (i < MINR) || | |
155 | (i > MAXR)) | |
156 | fatal("ceiling out of range (ad25)"); | |
157 | break; | |
158 | ||
159 | case DEFTFLAG: /* default sid */ | |
160 | if (!(*p)) | |
161 | fatal("no default sid (ad14)"); | |
162 | chksid(sid_ab(p,&sid),&sid); | |
163 | break; | |
164 | ||
165 | case TYPEFLAG: /* type */ | |
166 | case MODFLAG: /* module name */ | |
167 | if (!(*p)) | |
168 | fatal(sprintf(Error, | |
169 | "flag %c has no value (ad2)",f)); | |
170 | break; | |
171 | ||
172 | default: | |
173 | fatal("unknown flag (ad3)"); | |
174 | } | |
175 | ||
176 | if (had_flag[f - 'a']++) | |
177 | fatal("flag twice (ad4)"); | |
178 | flag_p[f - 'a'] = p; | |
179 | break; | |
180 | ||
181 | case 'r': /* initial release number supplied */ | |
182 | if ((irel = patoi(p)) == -1) | |
183 | fatal("r arg not numeric (ad6)"); | |
184 | if ((size(p) > 5) || (irel < MINR) || | |
185 | (irel > MAXR)) | |
186 | fatal("r out of range (ad7)"); | |
187 | break; | |
188 | ||
189 | case 'n': /* creating new SCCS file */ | |
190 | case 'h': /* only check hash of file */ | |
191 | case 'z': /* zero the input hash */ | |
192 | break; | |
193 | ||
194 | case 'a': /* user-name allowed to make deltas */ | |
195 | testklt = 0; | |
196 | if (!(*p)) | |
197 | fatal("bad a argument (ad8)"); | |
198 | if (asub > MAXNAMES) | |
199 | fatal("too many 'a' keyletters (ad9)"); | |
200 | anames[asub++] = p; | |
201 | break; | |
202 | ||
203 | case 'e': /* user-name to be removed */ | |
204 | testklt = 0; | |
205 | if (!(*p)) | |
206 | fatal("bad e argument (ad10)"); | |
207 | if (esub > MAXNAMES) | |
208 | fatal("too many 'e' keyletters (ad11)"); | |
209 | enames[esub++] = p; | |
210 | break; | |
211 | ||
212 | default: | |
213 | fatal("unknown key letter (cm1)"); | |
214 | } | |
215 | ||
216 | if (had[c - 'a']++ && testklt++) | |
217 | fatal("key letter twice (cm2)"); | |
218 | argv[j] = 0; | |
219 | } | |
220 | else | |
221 | num_files++; | |
222 | ||
223 | if (num_files == 0) | |
224 | fatal("missing file arg (cm3)"); | |
225 | ||
226 | if (HADI && num_files > 1) /* only one file allowed with `i' */ | |
227 | fatal("more than one file (ad15)"); | |
228 | ||
229 | setsig(); | |
230 | ||
231 | /* | |
232 | Change flags for 'fatal' so that it will return to this | |
233 | routine (main) instead of terminating processing. | |
234 | */ | |
38c01699 JL |
235 | Fflags &= ~FTLEXIT; |
236 | Fflags |= FTLJMP; | |
5a89b91c EA |
237 | |
238 | /* | |
239 | Call 'admin' routine for each file argument. | |
240 | */ | |
241 | for (j=1; j<argc; j++) | |
242 | if (p = argv[j]) | |
243 | do_file(p,admin); | |
244 | ||
245 | exit(Fcnt ? 1 : 0); | |
246 | } | |
247 | ||
248 | ||
249 | /* | |
250 | Routine that actually does admin's work on SCCS files. | |
251 | Existing s-files are copied, with changes being made, to a | |
252 | temporary file (x-file). The name of the x-file is the same as the | |
253 | name of the s-file, with the 's.' replaced by 'x.'. | |
254 | s-files which are to be created are processed in a similar | |
255 | manner, except that a dummy s-file is first created with | |
256 | mode 444. | |
257 | At end of processing, the x-file is renamed with the name of s-file | |
258 | and the old s-file is removed. | |
259 | */ | |
260 | ||
261 | struct packet gpkt; /* see file defines.h */ | |
262 | char Zhold[BUFSIZ]; /* temporary z-file name */ | |
263 | ||
264 | USXALLOC(); /* defines alloc() and free() */ | |
265 | ||
266 | admin(afile) | |
267 | char *afile; | |
268 | { | |
269 | struct deltab dt; /* see file defines.h */ | |
270 | struct stats stats; /* see file defines.h */ | |
271 | FILE *iptr; | |
272 | register int k; | |
273 | register char *cp, *q; | |
274 | char command[80]; | |
275 | char line[512]; | |
276 | int i; /* used in forking procedure */ | |
277 | int status; | |
278 | extern nfiles; | |
279 | extern had_dir; | |
280 | ||
281 | if (setjmp(Fjmp)) /* set up to return here from 'fatal' */ | |
282 | return; /* and return to caller of admin */ | |
283 | ||
284 | if (HADI && had_dir) /* directory not allowed with `i' keyletter */ | |
285 | fatal("directory named with `i' keyletter (ad26)"); | |
286 | ||
287 | fexists = exists(afile); | |
288 | ||
289 | if (HADI) | |
290 | HADN = 1; | |
291 | if (HADI || HADN) { | |
292 | if (HADM && !VFLAG) | |
293 | fatal("MRs not allowed (de8)"); | |
294 | ||
295 | if (VFLAG && !HADM) | |
296 | fatal("MRs required (de10)"); | |
297 | ||
298 | } | |
299 | ||
300 | if (!HADI && HADR) | |
301 | fatal("r only allowed with i (ad16)"); | |
302 | ||
303 | if (HADN && HADT && !(*tfile)) | |
304 | fatal("t has no argument (ad17)"); | |
305 | ||
306 | if (HADN && HADD) | |
307 | fatal("d not allowed with n (ad18)"); | |
308 | ||
309 | if (HADN && fexists) | |
310 | fatal(sprintf(Error,"file %s exists (ad19)",afile)); | |
311 | ||
312 | if (!HADN && !fexists) | |
313 | fatal(sprintf(Error,"file %s does not exist (ad20)",afile)); | |
314 | /* | |
315 | Check for '-h' flag. If set, create child process and | |
316 | invoke 'get' to examine format of SCCS file. | |
317 | */ | |
318 | ||
319 | if (HADH) { | |
320 | /* | |
321 | fork here so 'admin' can execute 'val' to | |
322 | check for a corrupted file. | |
323 | */ | |
324 | if ((i = fork()) < 0) | |
325 | fatal("cannot fork, try again"); | |
326 | if (i == 0) { /* child */ | |
327 | /* | |
328 | perform 'val' with appropriate keyletters | |
329 | */ | |
330 | execl("/bin/sh","/bin/sh","-c", | |
331 | sprintf(command, | |
332 | "/usr/local/val -s %s", | |
333 | afile),0); | |
334 | fatal(sprintf(Error,"cannot execute '%s'",Valpgm)); | |
335 | } | |
336 | else { | |
337 | wait(&status); /* wait on status from 'execl' */ | |
338 | if (status) | |
339 | fatal("corrupted file (co6)"); | |
340 | return; /* return to caller of 'admin' */ | |
341 | } | |
342 | } | |
343 | ||
344 | /* | |
345 | Lock out any other user who may be trying to process | |
346 | the same file. | |
347 | */ | |
348 | if (!HADH && lockit(copy(auxf(afile,'z'),Zhold),2,getpid())) | |
349 | fatal("cannot create lock file (cm4)"); | |
350 | ||
351 | if (fexists) | |
352 | sinit(&gpkt,afile,1); /* init pkt & open s-file */ | |
353 | else { | |
354 | xfcreat(afile,0444); /* create dummy s-file */ | |
355 | sinit(&gpkt,afile,0); /* and init pkt */ | |
356 | } | |
357 | ||
358 | if (!HADH) | |
359 | /* | |
360 | set the flag for 'putline' routine to open | |
361 | the 'x-file' and allow writing on it. | |
362 | */ | |
363 | gpkt.p_upd = 1; | |
364 | ||
365 | if (HADZ) { | |
366 | gpkt.do_chksum = 0; /* ignore checksum processing */ | |
367 | gpkt.p_ihash = 0; | |
368 | } | |
369 | ||
370 | /* | |
371 | Get statistics of latest delta in old file. | |
372 | */ | |
373 | if (!HADN) { | |
374 | stats_ab(&gpkt,&stats); | |
375 | gpkt.p_wrttn++; | |
376 | newstats(&gpkt,line,"0"); | |
377 | } | |
378 | ||
379 | if (HADN) { /* N E W F I L E */ | |
380 | ||
381 | /* | |
382 | Beginning of SCCS file. | |
383 | */ | |
384 | putline(&gpkt,sprintf(line,"%c%c%s\n",CTLCHAR,HEAD,"00000")); | |
385 | ||
386 | /* | |
387 | Statistics. | |
388 | */ | |
389 | newstats(&gpkt,line,"0"); | |
390 | ||
391 | dt.d_type = 'D'; /* type of delta */ | |
392 | ||
393 | /* | |
394 | Set initial release, level, branch and | |
395 | sequence values. | |
396 | */ | |
397 | if (HADR) | |
398 | dt.d_sid.s_rel = irel; | |
399 | else | |
400 | dt.d_sid.s_rel = 1; | |
401 | dt.d_sid.s_lev = 1; | |
402 | dt.d_sid.s_br = dt.d_sid.s_seq = 0; | |
403 | ||
404 | time(&dt.d_datetime); /* get time and date */ | |
405 | ||
406 | copy(logname(),dt.d_pgmr); /* get user's name */ | |
407 | ||
408 | dt.d_serial = 1; | |
409 | dt.d_pred = 0; | |
410 | ||
411 | del_ba(&dt,line); /* form and write */ | |
412 | putline(&gpkt,line); /* delta-table entry */ | |
413 | ||
414 | /* | |
415 | If -m flag, enter MR numbers | |
416 | */ | |
417 | ||
418 | if (Mrs) { | |
419 | mrfixup(); | |
420 | if (z && valmrs(&gpkt,z)) | |
421 | fatal("invalid MRs (de9)"); | |
422 | putmrs(&gpkt); | |
423 | } | |
424 | ||
425 | /* | |
426 | Enter comment line for `chghist' | |
427 | */ | |
428 | ||
429 | if (HADY) { | |
430 | putline(&gpkt,sprintf(line,"%c%c ",CTLCHAR,COMMENTS)); | |
431 | putline(&gpkt,Comments); | |
432 | putline(&gpkt,"\n"); | |
433 | } | |
434 | else { | |
435 | /* | |
436 | insert date/time and pgmr into comment line | |
437 | */ | |
438 | cmt_ba(&dt,line); | |
439 | putline(&gpkt,line); | |
440 | } | |
441 | /* | |
442 | End of delta-table. | |
443 | */ | |
444 | putline(&gpkt,sprintf(line,CTLSTR,CTLCHAR,EDELTAB)); | |
445 | ||
446 | /* | |
447 | Beginning of user-name section. | |
448 | */ | |
449 | putline(&gpkt,sprintf(line,CTLSTR,CTLCHAR,BUSERNAM)); | |
450 | } | |
451 | else | |
452 | /* | |
453 | For old file, copy to x-file until user-name section | |
454 | is found. | |
455 | */ | |
456 | flushto(&gpkt,BUSERNAM,COPY); | |
457 | ||
458 | /* | |
459 | Write user-names to be added to list of those | |
460 | allowed to make deltas. | |
461 | */ | |
462 | if (HADA) | |
463 | for (k = 0; k < asub; k++) | |
464 | putline(&gpkt,sprintf(line,"%s\n",anames[k])); | |
465 | ||
466 | /* | |
467 | Do not copy those user-names which are to be erased. | |
468 | */ | |
469 | if (HADE && !HADN) | |
470 | while ((cp = getline(&gpkt)) && | |
471 | !(*cp++ == CTLCHAR && *cp == EUSERNAM)) { | |
472 | for (k = 0; k < esub; k++) { | |
473 | cp = &gpkt.p_line; | |
474 | while (*cp) /* find and */ | |
475 | cp++; /* zero newline */ | |
476 | *--cp = '\0'; /* character */ | |
477 | ||
478 | if (equal(enames[k],&gpkt.p_line)) { | |
479 | /* | |
480 | Tell getline not to output | |
481 | previously read line. | |
482 | */ | |
483 | gpkt.p_wrttn = 1; | |
484 | break; | |
485 | } | |
486 | else | |
487 | *cp = '\n'; /* restore newline */ | |
488 | } | |
489 | } | |
490 | ||
491 | if (HADN) { /* N E W F I L E */ | |
492 | ||
493 | /* | |
494 | End of user-name section. | |
495 | */ | |
496 | putline(&gpkt,sprintf(line,CTLSTR,CTLCHAR,EUSERNAM)); | |
497 | } | |
498 | else | |
499 | /* | |
500 | For old file, copy to x-file until end of | |
501 | user-names section is found. | |
502 | */ | |
503 | if (!HADE) | |
504 | flushto(&gpkt,EUSERNAM,COPY); | |
505 | ||
506 | /* | |
507 | For old file, read flags and their values (if any), and | |
508 | store them. Check to see if the flag read is one that | |
509 | should be deleted. | |
510 | */ | |
511 | if (!HADN) | |
512 | while ((cp = getline(&gpkt)) && | |
513 | (*cp++ == CTLCHAR && *cp == FLAG)) { | |
514 | ||
515 | gpkt.p_wrttn = 1; /* don't write previous line */ | |
516 | ||
38c01699 | 517 | cp += 2; /* point to flag character */ |
5a89b91c EA |
518 | k = *cp - 'a'; |
519 | ||
520 | if (!had_flag[k] && !rm_flag[k]) { | |
521 | had_flag[k] = 2; /* indicate flag is */ | |
522 | /* from file, not */ | |
523 | /* from arg list */ | |
524 | ||
525 | if (*++cp != '\n') { /* get flag value */ | |
526 | q = alloc(size(gpkt.p_line)-5); | |
527 | copy(++cp,q); | |
528 | flag_p[k] = q; | |
529 | while (*q) /* find and */ | |
530 | q++; /* zero newline */ | |
531 | *--q = '\0'; /* character */ | |
532 | } | |
533 | } | |
534 | else | |
535 | if (rm_flag[k]) | |
536 | had_flag[k] = 0; | |
537 | } | |
538 | ||
539 | ||
540 | /* | |
541 | Write out flags. | |
542 | */ | |
543 | for (k = 0; k < 26; k++) | |
544 | if (had_flag[k]) { | |
545 | if (flag_p[k]) | |
546 | sprintf(line,"%c%c %c %s\n", | |
547 | CTLCHAR,FLAG,'a'+k,flag_p[k]); | |
548 | else | |
549 | sprintf(line,"%c%c %c\n", | |
550 | CTLCHAR,FLAG,'a'+k); | |
551 | ||
552 | putline(&gpkt,line); | |
553 | ||
554 | if (had_flag[k] == 2) { /* flag was taken from file */ | |
555 | had_flag[k] = 0; | |
556 | if (flag_p[k]) { | |
557 | free(flag_p[k]); | |
558 | flag_p[k] = 0; | |
559 | } | |
560 | } | |
561 | } | |
562 | ||
563 | if (HADN) | |
564 | /* | |
565 | Beginning of descriptive (user) text. | |
566 | */ | |
567 | putline(&gpkt,sprintf(line,CTLSTR,CTLCHAR,BUSERTXT)); | |
568 | else | |
569 | /* | |
570 | Write out BUSERTXT record which was read in | |
571 | above loop that processes flags. | |
572 | */ | |
573 | gpkt.p_wrttn = 0; | |
574 | putline(&gpkt,0); | |
575 | ||
576 | /* | |
577 | Get user description, copy to x-file. | |
578 | */ | |
579 | if (HADT) { | |
580 | if (*tfile) { | |
581 | iptr = xfopen(tfile,0); | |
582 | fgetchk(line,512,iptr,tfile,&gpkt); | |
583 | fclose(iptr); | |
584 | } | |
585 | ||
586 | /* | |
587 | If old file, ignore any previously supplied | |
588 | commentary. (i.e., don't copy it to x-file.) | |
589 | */ | |
590 | if (!HADN) | |
591 | flushto(&gpkt,EUSERTXT,NOCOPY); | |
592 | } | |
593 | ||
594 | if (HADN) { /* N E W F I L E */ | |
595 | ||
596 | /* | |
597 | End of user description. | |
598 | */ | |
599 | putline(&gpkt,sprintf(line,CTLSTR,CTLCHAR,EUSERTXT)); | |
600 | ||
601 | /* | |
602 | Beginning of body (text) of first delta. | |
603 | */ | |
604 | putline(&gpkt,sprintf(line,"%c%c %u\n",CTLCHAR,INS,1)); | |
605 | ||
606 | if (HADI) { /* get body */ | |
607 | ||
608 | /* | |
609 | Set indicator to check lines of body of file for | |
610 | keyword definitions. | |
611 | If no keywords are found, a warning | |
612 | will be produced. | |
613 | */ | |
614 | check_id = 1; | |
615 | /* | |
616 | Set indicator that tells whether there | |
617 | were any keywords to 'no'. | |
618 | */ | |
619 | Did_id = 0; | |
620 | if (*ifile) | |
621 | iptr = xfopen(ifile,0); /* from a file */ | |
622 | else | |
623 | iptr = stdin; /* from standard input */ | |
624 | ||
625 | /* | |
626 | Read and copy to x-file, while checking | |
627 | first character of each line to see that it | |
628 | is not the control character (octal 1). | |
629 | Also, count lines read, and set statistics' | |
630 | structure appropriately. | |
631 | The 'fgetchk' routine will check for keywords. | |
632 | */ | |
633 | stats.s_ins = fgetchk(line,512,iptr,ifile,&gpkt); | |
634 | stats.s_del = stats.s_unc = 0; | |
635 | ||
636 | /* | |
637 | If no keywords were found, issue warning. | |
638 | */ | |
639 | if (!Did_id) { | |
640 | if (had_flag[IDFLAG - 'a']) | |
641 | fatal("no id keywords (cm6)"); | |
642 | else | |
643 | fprintf(stderr,"%s\n","No id keywords (cm7)"); | |
644 | } | |
645 | ||
646 | check_id = 0; | |
647 | Did_id = 0; | |
648 | } | |
649 | ||
650 | /* | |
651 | End of body of first delta. | |
652 | */ | |
653 | putline(&gpkt,sprintf(line,"%c%c %u\n",CTLCHAR,END,1)); | |
654 | } | |
655 | else { | |
656 | /* | |
657 | Indicate that EOF at this point is ok, and | |
658 | flush rest of (old) s-file to x-file. | |
659 | */ | |
660 | gpkt.p_chkeof = 1; | |
661 | while (getline(&gpkt)) ; | |
662 | } | |
663 | ||
664 | /* | |
665 | Flush the buffer, take care of rewinding to insert | |
666 | checksum and statistics in file, and close. | |
667 | */ | |
668 | flushline(&gpkt,&stats); | |
669 | ||
670 | /* | |
671 | Change x-file name to s-file, and delete old file. | |
672 | Unlock file before returning. | |
673 | */ | |
674 | if (!HADH) { | |
675 | rename(auxf(&gpkt,'x'),&gpkt); | |
676 | xrm(&gpkt); | |
677 | unlockit(auxf(afile,'z'),getpid()); | |
678 | } | |
679 | } | |
680 | ||
681 | ||
682 | fgetchk(strp,len,inptr,file,pkt) | |
683 | register char *strp; | |
684 | register int len; | |
685 | FILE *inptr; | |
686 | register char *file; | |
687 | register struct packet *pkt; | |
688 | { | |
689 | register int k; | |
690 | ||
691 | for (k = 1; fgets(strp,len,inptr); k++) { | |
692 | if (*strp == CTLCHAR) fatal( | |
693 | sprintf(Error,"%s illegal data on line %d (ad21)", | |
694 | file,k)); | |
695 | ||
696 | if (check_id) | |
697 | chkid(strp); | |
698 | ||
699 | putline(pkt,strp); | |
700 | } | |
701 | return(k - 1); | |
702 | } | |
703 | ||
704 | ||
705 | clean_up() | |
706 | { | |
707 | xrm(&gpkt); | |
708 | if (!HADH) | |
709 | unlockit(Zhold,getpid()); | |
710 | if (HADN) | |
711 | unlink(&gpkt); | |
712 | } | |
713 | ||
714 | ||
715 | cmt_ba(dt,str) | |
716 | register struct deltab *dt; | |
717 | char *str; | |
718 | { | |
719 | register char *p; | |
720 | ||
721 | p = str; | |
722 | *p++ = CTLCHAR; | |
723 | *p++ = COMMENTS; | |
724 | *p++ = ' '; | |
725 | copy("date and time created",p); | |
726 | while (*p++) | |
727 | ; | |
728 | --p; | |
729 | *p++ = ' '; | |
730 | date_ba(&dt->d_datetime,p); | |
731 | while (*p++) | |
732 | ; | |
733 | --p; | |
734 | *p++ = ' '; | |
735 | copy("by",p); | |
736 | while (*p++) | |
737 | ; | |
738 | --p; | |
739 | *p++ = ' '; | |
740 | copy(dt->d_pgmr,p); | |
741 | while (*p++) | |
742 | ; | |
743 | --p; | |
744 | *p++ = '\n'; | |
745 | *p = 0; | |
746 | return(str); | |
747 | } | |
748 | ||
749 | ||
750 | putmrs(pkt) | |
751 | struct packet *pkt; | |
752 | { | |
753 | register char **argv; | |
754 | char str[64]; | |
755 | extern char *Varg[]; | |
756 | ||
757 | for (argv = &Varg[VSTART]; *argv; argv++) | |
758 | putline(pkt,sprintf(str,"%c%c %s\n",CTLCHAR,MRNUM,*argv)); | |
759 | } |