|
|
1.1 root 1: /*
2: * Archive manager.
3: * Also manages libraries for the
4: * link editor,
5: * including ranlib header updates.
6: */
7: #define RUNRSX 0
8: #define FMTRSX 0 /* Achives in COHERENT format */
9:
10: #include <stdio.h>
11: #include <ar.h>
12: #include <canon.h>
13: #include <sys/types.h>
14: #if !RUNRSX
15: #include <sys/stat.h>
16: #endif
17:
18: #define RO 0
19: #define RW 1
20:
21: #define NONE 0
22: #define BEFORE 1
23: #define AFTER 2
24:
25: #define ALLOK 0
26: #define NOTALL 1
27: #define ERROR 2
28:
29: #define aechk() { if(ferror(afp)) ioerr(anp); }
30: #define techk() { if(ferror(tfp)) ioerr(tnp); }
31:
32: char nwork[] = "No work";
33: char found[] = "found";
34: char copen[] = "%s: cannot open";
35: char ccrea[] = "%s: cannot create";
36: char creop[] = "%s: cannot reopen";
37:
38: FILE *afp;
39: FILE *tfp;
40: FILE *rfp;
41: struct ar_hdr ahb;
42: int nname;
43: char **namep;
44: char *ctime();
45: int usage();
46: long fsize();
47: long ftell();
48: int cflag;
49: int kflag;
50: int lflag;
51: int sflag;
52: int uflag;
53: int vflag;
54: char *pnp;
55: char *anp;
56: char *tnp;
57: char rnp[] = HDRNAME;
58: int xstat = ALLOK;
59: int pos = NONE;
60: int (*ffp)() = usage;
61:
62: #if RUNRSX
63: struct header fhb;
64: time_t fmdate();
65: time_t getmdate();
66: #else
67: char state[] = "%s: stat error";
68: #endif
69:
70: main(argc, argv)
71: char *argv[];
72: {
73: register char *p;
74: register i;
75: int usage(), rfunc();
76:
77: if (argc < 2)
78: usage();
79: key(argv[1]);
80: nname = argc-2;
81: namep = &argv[2];
82: for (i=2; i<argc; ++i) {
83: p = argv[i];
84: if (pos!=NONE && pnp==NULL) {
85: pnp = p;
86: ++namep;
87: --nname;
88: } else if (anp == NULL) {
89: anp = p;
90: ++namep;
91: --nname;
92: }
93: }
94: if (anp == NULL)
95: usage();
96: if (pos != NONE) {
97: if (pnp == NULL)
98: usage();
99: if (ffp == usage)
100: ffp = rfunc;
101: }
102: (*ffp)();
103: delexit(xstat);
104: }
105:
106: /*
107: * Decode key.
108: * Save function name in 'ffp'.
109: * Set 'c', 'l', 'k' and 'v' flags.
110: */
111: key(p)
112: register char *p;
113: {
114: register c;
115: int dfunc(), rfunc(), qfunc(), tfunc();
116: int mfunc(), xfunc(), pfunc();
117:
118: while (c = *p++) {
119: switch (c) {
120:
121: case 'd': /* Delete */
122: ffp = dfunc;
123: break;
124:
125: case 'r': /* Replace */
126: ffp = rfunc;
127: break;
128:
129: case 'q': /* Quick append */
130: ffp = qfunc;
131: break;
132:
133: case 't': /* Tabulate */
134: ffp = tfunc;
135: break;
136:
137: case 'p': /* Print */
138: ffp = pfunc;
139: break;
140:
141: case 'm': /* Move */
142: ffp = mfunc;
143: break;
144:
145: case 'x': /* Extract */
146: ffp = xfunc;
147: break;
148:
149: case 'c': /* no create message */
150: ++cflag;
151: break;
152:
153: case 'k': /* keep dates */
154: ++kflag;
155: break;
156:
157: case 'l': /* local temp file */
158: ++lflag;
159: break;
160:
161: case 's': /* ranlib symbol table */
162: ++sflag;
163: break;
164:
165: case 'u': /* update replace */
166: ++uflag;
167: break;
168:
169: case 'v': /* verbose */
170: ++vflag;
171: break;
172:
173: case 'a': /* after position or append */
174: pos = AFTER;
175: break;
176:
177: case 'b': /* before position */
178: case 'i': /* insert */
179: pos = BEFORE;
180: break;
181:
182: default:
183: usage();
184: }
185: }
186: }
187:
188: /*
189: * Replace.
190: * Eliminate dead stuff if 'u'.
191: * Copy up to insert point.
192: * Copy in new files.
193: * Copy the rest of the file.
194: * Copy back.
195: */
196: rfunc()
197: {
198: register char *qfn;
199: register i, nef;
200: FILE *qfp;
201:
202: if (nname == 0)
203: diag(1, nwork);
204: aopen(RW);
205: ropen();
206: if (uflag) {
207: update();
208: fseek(afp, (long)sizeof(int), 0);
209: if (rfp != NULL) {
210: geth();
211: if (eqh(rnp))
212: fseek(afp, (long)ahb.ar_size, 1);
213: else
214: fseek(afp, (long)sizeof(int), 0);
215: }
216: }
217: topen();
218: while (nef = geth()) {
219: if (pos==BEFORE && eqh(pnp)) {
220: fseek(afp, (long)-sizeof(struct ar_hdr), 1);
221: break;
222: }
223: if (pos == NONE) {
224: for (i=0; i<nname; ++i) {
225: if ((qfn=namep[i])!=NULL && eqh(qfn))
226: break;
227: }
228: if (i != nname) {
229: fseek(afp, ahb.ar_size, 1);
230: namep[i] = NULL;
231: remove(i, qfn);
232: if ((qfp = fopen(qfn, "rb")) == NULL)
233: diag(1, copen, qfn);
234: makeh(qfn, qfp);
235: if (vflag)
236: printf("%s: in place replace.\n", qfn);
237: puth();
238: ffcopy(tfp, tnp, qfp, qfn, fsize(qfp, qfn));
239: fclose(qfp);
240: continue;
241: }
242: }
243: mmove(0);
244: if (pos==AFTER && eqh(pnp))
245: break;
246: }
247: if (nef==0 && pos!=NONE)
248: diag(1, "%s: not in archive", pnp);
249: for (i=0; i<nname; ++i) {
250: if ((qfn=namep[i]) == NULL)
251: continue;
252: remove(i, qfn);
253: if ((qfp=fopen(qfn, "rb")) == NULL)
254: diag(1, copen, qfn);
255: makeh(qfn, qfp);
256: if (vflag)
257: printf("%s: replaced.\n", qfn);
258: puth();
259: ffcopy(tfp, tnp, qfp, qfn, fsize(qfp, qfn));
260: fclose(qfp);
261: }
262: while (geth())
263: mmove(0);
264: tacopy();
265: }
266:
267: /*
268: * Handle the 'u' option.
269: * Read through the archive, comparing
270: * the dates in the headers to the last
271: * modification dates of the files in
272: * the command line. Make some files
273: * go away.
274: */
275: update()
276: {
277: register char *p;
278: register i;
279: #if !RUNRSX
280: struct stat sb;
281: #endif
282:
283: while (geth()) {
284: for (i=0; i<nname; ++i) {
285: p = namep[i];
286: if (p!=NULL && eqh(p)) {
287: #if RUNRSX
288: if (ahb.ar_date >= fmdate(p)) {
289: #else
290: if (stat(p, &sb) < 0)
291: diag(1, state, p);
292: if (ahb.ar_date >= sb.st_mtime) {
293: #endif
294: if (vflag)
295: printf("%s: no update.\n", p);
296: namep[i] = NULL;
297: remove(i, p);
298: }
299: }
300: }
301: fseek(afp, ahb.ar_size, 1);
302: }
303: for (i=0; i<nname && namep[i]==NULL; ++i)
304: ;
305: if (i >= nname) {
306: if (vflag)
307: fprintf(stderr, "%s.\n", nwork);
308: delexit(ALLOK);
309: }
310: }
311:
312: /*
313: * Move.
314: * Copy stuff before insert.
315: * Copy moved stuff.
316: * Copy remainder.
317: * Copy back to archive.
318: */
319: mfunc()
320: {
321: register nef;
322: long s;
323:
324: aopen(RW);
325: ropen();
326: topen();
327: while (nef = geth()) {
328: if (pos==BEFORE && eqh(pnp))
329: break;
330: mmove(0);
331: if (pos==AFTER && eqh(pnp))
332: break;
333: }
334: if (nef==0 && pos!=NONE)
335: diag(1, "%s: not in archive", pnp);
336: s = ftell(afp);
337: if (pos == BEFORE)
338: s -= sizeof(struct ar_hdr);
339: fseek(afp, (long)sizeof(int), 0);
340: while (geth())
341: mmove(1);
342: if (nef) {
343: fseek(afp, s, 0);
344: while (geth())
345: mmove(0);
346: }
347: tacopy();
348: }
349:
350: /*
351: * Conditional move to the
352: * temp file from the archive
353: * file. Used by move and replace
354: */
355: mmove(f1)
356: register f1;
357: {
358: register f2, i;
359: register long size;
360:
361: f2 = 0;
362: for (i=0; i<nname; ++i) {
363: if (eqh(namep[i])) {
364: ++f2;
365: break;
366: }
367: }
368: if (f1 == f2) {
369: if (vflag)
370: amsg("copied");
371: size = ahb.ar_size;
372: puth();
373: ffcopy(tfp, tnp, afp, anp, size);
374: } else {
375: if (vflag)
376: amsg("skipped");
377: fseek(afp, ahb.ar_size, 1);
378: }
379: }
380:
381: /*
382: * Print.
383: */
384: pfunc()
385: {
386: aopen(RO);
387: while (geth()) {
388: if (nname==0 || match())
389: pfile();
390: else
391: fseek(afp, ahb.ar_size, 1);
392: }
393: if (nname != 0)
394: notdone(found);
395: }
396:
397: pfile()
398: {
399: #if FMTRSX
400: register char *rb;
401: register i;
402: long s;
403: int n;
404:
405: if (vflag)
406: amsg(NULL);
407: if ((rb = malloc(ahb.ar_ufat.f_rsiz)) == NULL)
408: diag(1, "Out of space");
409: s = ahb.ar_size;
410: while (s != 0) {
411: if (ahb.ar_ufat.f_rtyp == R_FIX)
412: n = ahb.ar_ufat.f_rsiz;
413: else {
414: fread(&n, sizeof(int), 1, afp);
415: s -= sizeof(int);
416: }
417: fread(rb, sizeof(char), n, afp);
418: for (i=0; i<n; ++i)
419: putchar(rb[i]);
420: if ((ahb.ar_ufat.f_ratt&FD_CR) != 0)
421: putchar('\n');
422: if ((n&01) != 0) {
423: ++n;
424: fseek(afp, (long)1, 1);
425: }
426: s -= n;
427: }
428: free(rb);
429: #else
430: if (vflag)
431: amsg(NULL);
432: ffcopy(stdout, "Stdout", afp, anp, ahb.ar_size);
433: #endif
434: }
435:
436: /*
437: * Delete.
438: * Copy archive to temp, deleting
439: * members along the way. If all of
440: * the files have been deleted then
441: * copy back.
442: */
443: dfunc()
444: {
445: register long size;
446:
447: if (nname == 0)
448: diag(1, nwork);
449: aopen(RW);
450: ropen();
451: topen();
452: while (geth()) {
453: if (match()) {
454: if (vflag)
455: amsg("deleted");
456: fseek(afp, ahb.ar_size, 1);
457: continue;
458: }
459: if (vflag)
460: amsg("copied");
461: size = ahb.ar_size;
462: puth();
463: ffcopy(tfp, tnp, afp, anp, size);
464: }
465: if (notdone("deleted"))
466: delexit(ERROR);
467: tacopy();
468: }
469:
470: /*
471: * Quick insert.
472: * Copy archive to temp file.
473: * Tack new files onto the end.
474: * If no errors, copy back.
475: */
476: qfunc()
477: {
478: register char *qfn;
479: register FILE *qfp;
480: register i;
481:
482: if (nname == 0)
483: diag(1, nwork);
484: aopen(RW);
485: if (geth() != 0 && eqh(rnp)) {
486: fseek(afp, (long)-sizeof(ahb), 1);
487: ahb.ar_date = 0;
488: aputh();
489: }
490: fseek(afp, (long)0, 2);
491: for (i=0; i<nname; ++i) {
492: if ((qfn=namep[i]) == NULL)
493: continue;
494: remove(i, qfn);
495: if ((qfp=fopen(qfn, "rb")) == NULL)
496: diag(1, copen, qfn);
497: makeh(qfn, qfp);
498: if (vflag)
499: printf("%s: quick insert.\n", qfn);
500: aputh();
501: ffcopy(afp, anp, qfp, qfn, fsize(qfp, qfn));
502: fclose(qfp);
503: }
504: }
505:
506: /*
507: * Table.
508: * Read through archive.
509: * If good member print its name.
510: * If verbose, print extra stuff.
511: */
512: tfunc()
513: {
514: register char *p;
515: register c, n;
516:
517: aopen(RO);
518: while (geth()) {
519: if (nname==0 || match()) {
520: n = 0;
521: p = ahb.ar_name;
522: while (n<DIRSIZ && (c=*p++)) {
523: putchar(c);
524: ++n;
525: }
526: if (vflag) {
527: while (n++ < DIRSIZ+1)
528: putchar(' ');
529: #if FMTRSX
530: printf("[%03o,%03o] ", ahb.ar_gid, ahb.ar_uid);
531: printf("%06o ", ahb.ar_mode);
532: #else
533: printf("%5d %5d ", ahb.ar_gid, ahb.ar_uid);
534: printf("%03o ", ahb.ar_mode);
535: #endif
536: printf("%10ld ", ahb.ar_size);
537: printf("%s", ctime(&ahb.ar_date));
538: } else
539: putchar('\n');
540: }
541: fseek(afp, ahb.ar_size, 1);
542: }
543: if (nname != 0)
544: notdone(found);
545: }
546:
547: /*
548: * Extract.
549: * Read through archive.
550: * Extract any files you find.
551: * At end, mutter about files
552: * that were not there.
553: */
554: xfunc()
555: {
556: register char *p1, *p2;
557: register c;
558: char fnb[DIRSIZ+1];
559: FILE *xfp;
560:
561: aopen(RO);
562: while (geth()) {
563: if (nname==0 || match()) {
564: p1 = ahb.ar_name;
565: p2 = fnb;
566: while (p1<&ahb.ar_name[DIRSIZ] && (c=*p1++))
567: *p2++ = c;
568: *p2 = 0;
569: if ((xfp=fopen(fnb, "wb")) == NULL) {
570: diag(0, ccrea, fnb);
571: fseek(afp, ahb.ar_size, 1);
572: continue;
573: }
574: if (vflag)
575: amsg("extracting");
576: ffcopy(xfp, fnb, afp, anp, ahb.ar_size);
577: #if RUNRSX && FMTRSX
578: fseek(xfp, (long)0, 0);
579: xfp->v_rtyp = ahb.ar_ufat.f_rtyp;
580: xfp->v_ratt = ahb.ar_ufat.f_ratt;
581: xfp->v_rsiz = ahb.ar_ufat.f_rsiz;
582: xfp->v_hibk = ahb.ar_ufat.f_hibk;
583: xfp->v_efbk = ahb.ar_ufat.f_efbk;
584: xfp->v_ffby = ahb.ar_ufat.f_ffby;
585: #endif
586: #if !RUNRSX && !FMTRSX
587: chmod(fnb, ahb.ar_mode);
588: #endif
589: fclose(xfp);
590: if (kflag) {
591: #if !RUNRSX && !FMTRSX
592: time_t times[2];
593: time_t time();
594:
595: time(times+0);
596: times[1] = ahb.ar_date;
597: if (utime(fnb, times) < 0)
598: diag(0, "Unable to set time for %s",
599: fnb);
600: #endif
601: }
602: } else
603: fseek(afp, ahb.ar_size, 1);
604: }
605: if (nname != 0)
606: notdone(found);
607: }
608:
609: /*
610: * Make an archive header.
611: * Put it in the external archive
612: * header buffer 'ahb'. The arg.
613: * 'fn' is the file name. The file
614: * is open on 'fp'.
615: */
616: makeh(fn, fp)
617: char *fn;
618: FILE *fp;
619: {
620: register char *p1, *p2;
621: register c;
622: #if !RUNRSX
623: struct stat sb;
624: #endif
625:
626: for (p1=fn; *p1++; )
627: ;
628: while (p1 > fn) {
629: c = p1[-1];
630: #if RUNRSX
631: if (c==':' || c==']')
632: break;
633: #endif
634: #if COHERENT
635: if (c == '/')
636: break;
637: #endif
638: #if GEMDOS
639: if (c == '\\')
640: break;
641: #endif
642: --p1;
643: }
644: p2 = ahb.ar_name;
645: while (c = *p1++) {
646: if (p2 < &ahb.ar_name[DIRSIZ])
647: *p2++ = c;
648: }
649: while (p2 < &ahb.ar_name[DIRSIZ])
650: *p2++ = 0;
651: #if RUNRSX
652: if (ratt(fp, &fhb) == 0)
653: diag(1, "%s: ratt failed", fn);
654: ahb.ar_date = getmdate(&fhb);
655: ahb.ar_size = fsize(fp, fn);
656: #if FMTRSX
657: ahb.ar_uid = fhb.h_prog;
658: ahb.ar_gid = fhb.h_proj;
659: ahb.ar_mode = fhb.h_fpro;
660: ahb.ar_ufat.f_rtyp = fp->v_rtyp;
661: ahb.ar_ufat.f_ratt = fp->v_ratt;
662: ahb.ar_ufat.f_rsiz = fp->v_rsiz;
663: ahb.ar_ufat.f_hibk = fp->v_hibk;
664: ahb.ar_ufat.f_efbk = fp->v_efbk;
665: ahb.ar_ufat.f_ffby = fp->v_ffby;
666: #else
667: ahb.ar_uid = 0;
668: ahb.ar_gid = 0;
669: ahb.ar_mode = 0644;
670: #endif
671: #else
672: #if GEMDOS
673: if (stat(fn, &sb) < 0)
674: #else
675: if (fstat(fileno(fp), &sb) < 0)
676: #endif
677: diag(1, state, fn);
678: if (kflag)
679: ahb.ar_date = sb.st_mtime;
680: else
681: time(&ahb.ar_date);
682: ahb.ar_uid = sb.st_uid;
683: ahb.ar_gid = sb.st_gid;
684: ahb.ar_mode = sb.st_mode&0777;
685: ahb.ar_size = sb.st_size;
686: #endif
687: }
688:
689: /*
690: * Test if the member whose
691: * header is held in the archive
692: * header buffer is mentioned in
693: * the user's list of members.
694: * Return the number of matches.
695: * All matches are NULLed.
696: */
697: match()
698: {
699: register char *p;
700: register i, n;
701:
702: n = 0;
703: for (i=0; i<nname; ++i) {
704: if ((p=namep[i]) == NULL)
705: continue;
706: if (eqh(p)) {
707: ++n;
708: namep[i] = NULL;
709: }
710: }
711: return (n);
712: }
713:
714: /*
715: * Remove all instances of name
716: * 'fn' from the list of names that
717: * is described by 'namep' and
718: * 'nname'.
719: * Start at index 'i+1'.
720: */
721: remove(i, fn)
722: register i;
723: register char *fn;
724: {
725: register char *p;
726:
727: for (++i; i<nname; ++i) {
728: if ((p=namep[i]) == NULL)
729: continue;
730: if (strcmp(fn, p) == 0)
731: namep[i] = NULL;
732: }
733: }
734:
735: /*
736: * This routine digs through the
737: * list of names described by 'namep'
738: * and 'nname' looking for names that
739: * have not been NULLed out. If any
740: * are found it prints a title and
741: * the names. The number of names that
742: * were found is returned.
743: */
744: notdone(s)
745: char *s;
746: {
747: register char *p;
748: register i, n;
749:
750: n = 0;
751: for (i=0; i<nname; ++i) {
752: p = namep[i];
753: if (p != NULL) {
754: if (n++ == 0)
755: fprintf(stderr, "Not %s:\n", s);
756: fprintf(stderr, "%s\n", p);
757: }
758: }
759: return (n);
760: }
761:
762: /*
763: * File to file copy.
764: * With ranlib construction.
765: */
766: ffcopy(tfp, tfn, ffp, ffn, s)
767: FILE *tfp, *ffp;
768: char *tfn, *ffn;
769: long s;
770: {
771: register n;
772: static char fb[BUFSIZ];
773:
774: if (rfp != NULL) raddmod(tfp, ffp);
775: while (s != 0) {
776: n = (s>BUFSIZ) ? BUFSIZ : s;
777: if (fread (fb, sizeof(char), n, ffp) != n)
778: ioerr(ffn);
779: if (fwrite(fb, sizeof(char), n, tfp) != n)
780: ioerr(tfn);
781: s -= n;
782: }
783: }
784:
785: /*
786: * Get the next archive header
787: * into 'ahb'. Check for any I/O
788: * errors. Return true if a header
789: * was read and false on EOF.
790: */
791: geth()
792: {
793: if (fread(&ahb, sizeof(ahb), 1, afp) != 1) {
794: aechk();
795: return (0);
796: }
797: cantime(ahb.ar_date);
798: canshort(ahb.ar_gid);
799: canshort(ahb.ar_uid);
800: canshort(ahb.ar_mode);
801: cansize(ahb.ar_size);
802: return (1);
803: }
804:
805: /*
806: * Write the header in 'ahb' to
807: * the temp file.
808: */
809: puth()
810: {
811: cantime(ahb.ar_date);
812: canshort(ahb.ar_gid);
813: canshort(ahb.ar_uid);
814: canshort(ahb.ar_mode);
815: cansize(ahb.ar_size);
816: fwrite(&ahb, sizeof(ahb), 1, tfp);
817: techk();
818: }
819:
820: /*
821: * Write the header in 'ahb' to
822: * the archive file. from qfunc.
823: */
824: aputh()
825: {
826: cantime(ahb.ar_date);
827: canshort(ahb.ar_gid);
828: canshort(ahb.ar_uid);
829: canshort(ahb.ar_mode);
830: cansize(ahb.ar_size);
831: fwrite(&ahb, sizeof(ahb), 1, afp);
832: aechk();
833: }
834:
835: /*
836: * Compare a string to the name
837: * of the member in the archive header
838: * buffer. True return if same.
839: */
840: eqh(p)
841: char *p;
842: {
843: register char *p1, *p2;
844: register c;
845:
846: if ((p1 = p) == NULL)
847: return (0);
848: while (*p1++)
849: ;
850: while (p1 > p) {
851: c = p1[-1];
852: #if RUNRSX
853: if (c==':' || c==']')
854: break;
855: #endif
856: #if COHERENT
857: if (c == '/')
858: break;
859: #endif
860: #if GEMDOS
861: if (c == '\\')
862: break;
863: #endif
864: --p1;
865: }
866: p2 = ahb.ar_name;
867: c = DIRSIZ;
868: while (c && *p1 == *p2++) {
869: if (*p1++ == 0)
870: return (1);
871: --c;
872: }
873: if (c == 0)
874: return (1);
875: return (0);
876: }
877:
878: /*
879: * Open archive.
880: * The argument 'aam' is the
881: * access mode (RO or RW).
882: */
883: aopen(aam)
884: {
885: int i;
886:
887: if ((afp=fopen(anp, "rb")) == NULL) {
888: if (aam == RO)
889: diag(1, copen, anp);
890: if ((afp=fopen(anp, "wb"))==NULL
891: || (afp=freopen(anp, "wrb", afp))==NULL)
892: diag(1, ccrea, anp);
893: if (cflag == 0)
894: printf("%s: new archive.\n", anp);
895: i = ARMAG;
896: canint(i);
897: fwrite(&i, sizeof(i), 1, afp);
898: aechk();
899: return;
900: }
901: if (aam != RO) {
902: fclose(afp);
903: if ((afp=fopen(anp, "rwb"))==NULL)
904: diag(1, copen, anp);
905: }
906: fread(&i, sizeof(i), 1, afp);
907: aechk();
908: canint(i);
909: if (i != ARMAG)
910: diag(1, "%s: not an archive", anp);
911: }
912:
913: /*
914: * Open tempfile.
915: * Stash the name in 'tnp' for
916: * the benefit of 'delexit'.
917: * Honour the 'l' option w.r.t.
918: * file placement.
919: */
920: topen()
921: {
922: int i;
923:
924: #if COHERENT || GEMDOS
925: extern char *tempnam();
926: tnp = tempnam((lflag ? "." : NULL), "v");
927: #endif
928: #if RUNRSX
929: tnp = "ar.tmp";
930: #endif
931: if ((tfp=fopen(tnp, "wb")) == NULL)
932: diag(1, ccrea, tnp);
933: i = ARMAG;
934: canint(i);
935: fwrite(&i, sizeof(i), 1, tfp);
936: techk();
937: }
938:
939: /*
940: * Copy tempfile back to the
941: * archive.
942: */
943: tacopy()
944: {
945: register FILE *xtp;
946: int i;
947:
948: fclose(tfp);
949: tfp = NULL; /* Scare off delexit */
950: fclose(afp);
951: if ((xtp=fopen(tnp, "rb")) == NULL)
952: diag(1, creop, tnp);
953: if ((afp=fopen(anp, "wb")) == NULL)
954: diag(1, creop, anp);
955: if (vflag)
956: printf("%s: copy back.\n", anp);
957: if (fread(&i, sizeof(i), 1, xtp) != 1)
958: ioerr(tnp);
959: if (fwrite(&i, sizeof(i), 1, afp) != 1)
960: ioerr(anp);
961: if (rfp != NULL) rcopy();
962: ffcopy(afp, anp, xtp, tnp, fsize(xtp, tnp)-sizeof(int));
963: tfp = xtp; /* Delete */
964: }
965:
966: /*
967: * Write diagnostic.
968: * The flag 'f' marks fatal errors.
969: */
970: diag(f, a)
971: {
972: fprintf(stderr, "%r", &a);
973: fprintf(stderr, ".\n");
974: if (f)
975: delexit(ERROR);
976: xstat = NOTALL;
977: }
978:
979: /*
980: * Print a message for a
981: * given archive member. The header
982: * is in the header buffer.
983: */
984: amsg(s)
985: char *s;
986: {
987: register char *p;
988: register c;
989:
990: p = ahb.ar_name;
991: while (p<&ahb.ar_name[DIRSIZ] && (c=*p++)!=0)
992: putchar(c);
993: putchar(':');
994: if (s != NULL)
995: printf(" %s.", s);
996: putchar('\n');
997: }
998:
999: /*
1000: * Exit.
1001: * Delete the tempfile if
1002: * present.
1003: */
1004: delexit(s)
1005: {
1006: #if RUNRSX
1007: if (tfp != NULL)
1008: fmkdl(tfp);
1009: #else
1010: if (tfp != NULL)
1011: unlink(tnp);
1012: #endif
1013: #ifdef DEBUG
1014: if (s)
1015: abort();
1016: #endif
1017: exit(s);
1018: }
1019:
1020: /*
1021: * Mutter about an I/O error
1022: * on file 's'.
1023: */
1024: ioerr(s)
1025: char *s;
1026: {
1027: diag(1, "%s: I/O error", s);
1028: }
1029:
1030: /*
1031: * Print usage message.
1032: */
1033: usage()
1034: {
1035: fprintf(stderr, "Usage: ar options [posname] afile [name ...].\n");
1036: delexit(ERROR);
1037: }
1038:
1039: /*
1040: * Compute the size of a file.
1041: * In bytes.
1042: * The file must not be seeked.
1043: */
1044: long
1045: fsize(fp, fn)
1046: register FILE *fp;
1047: char *fn;
1048: {
1049: #if RUNRSX
1050: return (((fp->v_efbk-1)<<9) + fp->v_ffby);
1051: #else
1052: struct stat sb;
1053:
1054: #if GEMDOS
1055: if (stat(fn, &sb) < 0)
1056: #endif
1057: #if COHERENT
1058: if (fstat(fileno(fp), &sb) < 0)
1059: #endif
1060: diag(1, state, fn);
1061: return (sb.st_size);
1062: #endif
1063: }
1064:
1065: #if RUNRSX
1066: /*
1067: * The following routines simulate
1068: * some aspects of Coherent under the
1069: * dreaded RSX.
1070: */
1071: #define DAY (24L*60L*60L)
1072:
1073: time_t
1074: fmdate(fn)
1075: char *fn;
1076: {
1077: register FILE *fp;
1078: register s;
1079:
1080: if ((fp=fopen(fn, "rb")) == NULL)
1081: diag(1, copen, fn);
1082: s = ratt(fp, &fhb);
1083: fclose(fp);
1084: if (s == 0)
1085: diag(1, "%s: ratt failed", fn);
1086: return (getmdate(&fhb));
1087: }
1088:
1089: time_t
1090: getmdate(fhp)
1091: register struct header *fhp;
1092: {
1093: register i;
1094: time_t date;
1095: int rsxdate[8];
1096: static char *mtab[] = {
1097: "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
1098: "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
1099: };
1100:
1101: rsxdate[0] = (fhp->i_rvdt[5]-'0')*10+fhp->i_rvdt[6]-'0';
1102: for (i=0; i<12; ++i) {
1103: if (cmp3(&fhp->i_rvdt[2], mtab[i])) {
1104: rsxdate[1] = i+1;
1105: break;
1106: }
1107: }
1108: rsxdate[2] = (fhp->i_rvdt[0]-'0')*10+fhp->i_rvdt[1]-'0';
1109: rsxdate[3] = (fhp->i_rvti[0]-'0')*10+fhp->i_rvti[1]-'0';
1110: rsxdate[4] = (fhp->i_rvti[2]-'0')*10+fhp->i_rvti[3]-'0';
1111: rsxdate[5] = (fhp->i_rvti[4]-'0')*10+fhp->i_rvti[5]-'0';
1112: cvttime(&date, rsxdate);
1113: return (date);
1114: }
1115:
1116: cmp3(p1, p2)
1117: register char *p1, *p2;
1118: {
1119: if (*p1++==*p2++ && *p1++==*p2++ && *p1++==*p2++)
1120: return (1);
1121: return (0);
1122: }
1123:
1124: /*
1125: * Convert rsx date to Coherent
1126: * format. This routine assumes that
1127: * the timezone is CST.
1128: * Courtesy of Tom Duff.
1129: */
1130: cvttime(date, rsxdate)
1131: register long *date;
1132: int rsxdate[8];
1133: {
1134: register i;
1135:
1136: *date = 0;
1137: for (i=70; i!=rsxdate[0]; i++) {
1138: if (i%4==0)
1139: *date += 366L*DAY; else
1140: *date += 365L*DAY;
1141: }
1142: for (i=1; i!=rsxdate[1]; i++)
1143: switch (i){
1144: case 9: /* Sep */
1145: case 4: /* Apr */
1146: case 6: /* Jun */
1147: case 11: /* Nov */
1148: *date += 30L*DAY;
1149: break;
1150:
1151: case 2: /* Feb */
1152: if (rsxdate[0]%4 == 0)
1153: *date += 29L*DAY; else
1154: *date += 28L*DAY;
1155: break;
1156:
1157: default:
1158: *date += 31L*DAY;
1159: }
1160: *date += (rsxdate[2]-1)*DAY;
1161: *date += rsxdate[3]*60L*60L;
1162: *date += rsxdate[4]*60L;
1163: *date += rsxdate[5];
1164: *date += 6L*60L*60L; /* adjust cst to gmt */
1165: }
1166: #endif
1167:
1168: /*
1169: * Ranlib stuff.
1170: * If the current archive has HDRNAME as first module,
1171: * then skip it and open rfp for creation of new ranlib header,
1172: * otherwise backup and make a vanilla archive.
1173: * Unless sflag was set as an option,
1174: * in which case make rfp anyway.
1175: * Unless HDRNAME matches the name list and ffp == dfunc,
1176: * in which case make rfp only if sflag was set.
1177: */
1178: ropen()
1179: {
1180: extern int dfunc();
1181:
1182: if (geth() != 0) { /* Must not be end of file */
1183: if (eqh(rnp)) {
1184: fseek(afp, (long)ahb.ar_size, 1);
1185: if (ffp == dfunc && match()) {
1186: if (vflag)
1187: amsg("deleted");
1188: } else
1189: ++sflag;
1190: } else {
1191: fseek(afp, (long)-sizeof(ahb), 1);
1192: if (sflag && ffp == dfunc) {
1193: strcpy(ahb.ar_name, rnp);
1194: match();
1195: }
1196: }
1197: }
1198: if (sflag && (rfp = fopen(rnp, "wb")) == NULL)
1199: diag(1, ccrea, rnp);
1200: }
1201:
1202: /*
1203: * Add the symbols in mfp to the ranlib header,
1204: * and seek mfp back to where it began.
1205: * The postion of this module in the archive
1206: * is -sizeof(arhdr) from current position of afp.
1207: */
1208: struct ldheader ldh;
1209: struct ldsym lds;
1210: struct ar_sym ars;
1211:
1212: xwrite()
1213: {
1214: if (fwrite(lds.ls_id, sizeof(lds.ls_id), 1, rfp) != 1
1215: || fwrite(&ars.ar_off, sizeof(ars.ar_off), 1, rfp) != 1)
1216: ioerr(rnp);
1217: }
1218:
1219: xread(fp) register FILE *fp;
1220: {
1221: register int r;
1222: union { long l; unsigned u[2]; } u;
1223:
1224: if ((ldh.l_flag & LF_32) == 0) {
1225: r = fread(&lds, sizeof(lds)-sizeof(short), 1, fp);
1226: u.l = lds.ls_addr;
1227: canshort(u.u[0]);
1228: lds.ls_addr = u.u[0];
1229: } else {
1230: r = fread(&lds, sizeof(lds), 1, fp);
1231: canlong(lds.ls_addr);
1232: }
1233: canshort(lds.ls_type);
1234: return (r);
1235: }
1236:
1237: raddmod(afp, mfp) FILE *afp, *mfp;
1238: {
1239: fsize_t off, offset;
1240: int seg, nsym;
1241:
1242: ars.ar_off = ftell(afp) - sizeof(ahb) - sizeof(int);
1243: cansize(ars.ar_off);
1244: off = ftell(mfp);
1245: ldh.l_magic = 0; /* in case fread fails */
1246: if (fread(&ldh, sizeof ldh, 1, mfp) != 1)
1247: goto done;
1248: canshort(ldh.l_magic);
1249: if (ldh.l_magic != L_MAGIC)
1250: goto done;
1251: canshort(ldh.l_flag);
1252: if ((ldh.l_flag & LF_32) == 0)
1253: ldh.l_tbase = sizeof(ldh) - 2*sizeof(short);
1254: else
1255: canshort(ldh.l_tbase);
1256: offset = ldh.l_tbase - (fsize_t)sizeof(ldh);
1257: for (seg=0; seg<L_SYM; seg++) {
1258: if (seg==L_BSSI || seg==L_BSSD)
1259: continue;
1260: cansize(ldh.l_ssize[seg]);
1261: offset += ldh.l_ssize[seg];
1262: }
1263: fseek(mfp, offset, 1);
1264: cansize(ldh.l_ssize[L_SYM]);
1265: if ((ldh.l_flag & LF_32) == 0)
1266: nsym = ldh.l_ssize[L_SYM]
1267: / (sizeof(struct ldsym) - sizeof(short));
1268: else
1269: nsym = ldh.l_ssize[L_SYM]/sizeof(struct ldsym);
1270: while (nsym--) {
1271: if (xread(mfp) == 0)
1272: diag(1, "truncated module %.*s", DIRSIZ, ahb.ar_name);
1273: if ((lds.ls_type&L_GLOBAL) == 0)
1274: continue;
1275: if ((lds.ls_type&LR_SEG) != L_REF)
1276: xwrite();
1277: }
1278: done:
1279: fseek(mfp, off, 0); /* back to beginning of module */
1280: }
1281:
1282: /*
1283: * Copy the ranlib header to the output archive
1284: * close and null the ranlib file pointer.
1285: */
1286: rcopy()
1287: {
1288: register FILE *fp;
1289: fclose(rfp);
1290: rfp = NULL;
1291: if ((fp = fopen(rnp, "rb")) == NULL)
1292: diag(1, creop, rnp);
1293: makeh(rnp, fp);
1294: time(&ahb.ar_date);
1295: ahb.ar_date += (long)(10*365+3)*24*60*60;
1296: tfp = afp;
1297: puth();
1298: tfp = NULL;
1299: ffcopy(afp, anp, fp, rnp, fsize(fp, rnp));
1300: fclose(fp);
1301: unlink(rnp);
1302: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.