URI: 
       scc-ranlib.c - scc - simple c99 compiler
  HTML git clone git://git.simple-cc.org/scc
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       scc-ranlib.c (6276B)
       ---
            1 #include <ctype.h>
            2 #include <errno.h>
            3 #include <limits.h>
            4 #include <stdarg.h>
            5 #include <stdio.h>
            6 #include <stdlib.h>
            7 #include <string.h>
            8 #include <time.h>
            9 
           10 #include <scc/ar.h>
           11 #include <scc/arg.h>
           12 #include <scc/mach.h>
           13 #include <scc/scc.h>
           14 
           15 #define NR_SYMDEF 32
           16 
           17 typedef struct symdef Symdef;
           18 
           19 struct symdef {
           20         char *name;
           21         int type;
           22         long offset;
           23         Symdef *hash, *next;
           24 };
           25 
           26 static char *namidx;
           27 static long nsymbols;
           28 static int status, artype, nolib;
           29 static char *filename, *membname;
           30 static Symdef *htab[NR_SYMDEF], *head;
           31 char *argv0;
           32 
           33 static void
           34 error(char *fmt, ...)
           35 {
           36         va_list va;
           37 
           38         va_start(va, fmt);
           39         fprintf(stderr, "scc-ranlib: %s: ", filename);
           40         if (membname)
           41                 fprintf(stderr, "%s: ", membname);
           42         vfprintf(stderr, fmt, va);
           43         putc('\n', stderr);
           44         va_end(va);
           45 
           46         status = EXIT_FAILURE;
           47 }
           48 
           49 Symdef *
           50 lookup(char *name)
           51 {
           52         unsigned h;
           53         Symdef *dp;
           54         char *s;
           55         size_t len;
           56 
           57         h = genhash(name) % NR_SYMDEF;
           58 
           59         for (dp = htab[h]; dp; dp = dp->next) {
           60                 if (!strcmp(dp->name, name))
           61                         return dp;
           62         }
           63 
           64         len = strlen(name) + 1;
           65         dp = malloc(sizeof(*dp));
           66         s = malloc(len);
           67         if (!dp || !s) {
           68                 free(s);
           69                 free(dp);
           70                 return NULL;
           71         }
           72 
           73         nsymbols++;
           74         dp->name = s;
           75         memcpy(dp->name, name, len);
           76         dp->type = 'U';
           77         dp->offset = -1;
           78         dp->hash = htab[h];
           79         htab[h] = dp;
           80         dp->next = head;
           81         head = dp;
           82 
           83         return dp;
           84 }
           85 
           86 static int
           87 newsymbol(Symbol *sym, long off)
           88 {
           89         Symdef *np;
           90 
           91         if (!isupper(sym->type) || sym->type == 'N' || sym->type == 'U')
           92                 return 1;
           93 
           94         if ((np = lookup(sym->name)) == NULL) {
           95                 error(strerror(errno));
           96                 return 0;
           97         }
           98 
           99         switch (np->type) {
          100         case 'C':
          101                 if (sym->type == 'C')
          102                         break;
          103         case 'U':
          104                 np->type = sym->type;
          105                 np->offset = off;
          106                 break;
          107         default:
          108                 if (sym->type != 'C') {
          109                         error("multiple definitions of '%s'", sym->name);
          110                         return 0;
          111                 }
          112         }
          113 
          114         return 1;
          115 }
          116 
          117 static void
          118 freehash(void)
          119 {
          120         Symdef **npp, *next, *np;
          121 
          122         for (npp = htab; npp < &htab[NR_SYMDEF]; npp++)
          123                 *npp = NULL;
          124 
          125         for (np = head; np; np = next) {
          126                 next = np->next;
          127                 free(np->name);
          128                 free(np);
          129         }
          130 
          131         head = NULL;
          132 }
          133 
          134 static int
          135 newmember(FILE *fp, long off)
          136 {
          137         int i,t, ret = 0;
          138         Obj *obj;
          139         Symbol sym;
          140 
          141         t = objprobe(fp, NULL);
          142         if (t == -1 || artype != -1 && artype != t) {
          143                 nolib = 1;
          144                 return 0;
          145         }
          146         artype = t;
          147 
          148         if ((obj = newobj(t)) == NULL) {
          149                 error(strerror(errno));
          150                 return 0;
          151         }
          152         namidx = obj->index;
          153 
          154         if (readobj(obj, fp) < 0) {
          155                 error(strerror(errno));
          156                 goto error;
          157         }
          158 
          159         for (i = 0; getsym(obj, &i, &sym); i++) {
          160                 if (!newsymbol(&sym, off))
          161                         goto error;
          162         }
          163 
          164         ret = 1;
          165 
          166 error:
          167         delobj(obj);
          168         return ret;
          169 }
          170 
          171 static int
          172 readsyms(FILE *fp)
          173 {
          174         long idxsiz, cur, off;
          175         char memb[SARNAM+1];
          176 
          177         nolib = 0;
          178         artype = -1;
          179         nsymbols = 0;
          180         idxsiz = 0;
          181 
          182         if (!archive(fp)) {
          183                 error("file format not recognized");
          184                 return 0;
          185         }
          186 
          187         cur = ftell(fp);
          188         if ((off = armember(fp, memb, NULL)) < 0)
          189                 goto corrupted;
          190 
          191         if (strcmp(memb, "/") == 0 || strcmp(memb, "__.SYMDEF") == 0) {
          192                 idxsiz = off;
          193                 cur += off;
          194         }
          195 
          196         fseek(fp, cur, SEEK_SET);
          197         for (;;) {
          198                 cur = ftell(fp);
          199                 off = armember(fp, memb, NULL);
          200                 switch (off) {
          201                 case -1:
          202                         goto corrupted;
          203                 case 0:
          204                         return (nolib || nsymbols == 0) ? -1 : 0;
          205                 default:
          206                         membname = memb;
          207                         if (objprobe(fp, NULL) != -1)
          208                                 newmember(fp, cur - idxsiz);
          209                         membname = NULL;
          210                         fseek(fp, cur, SEEK_SET);
          211                         fseek(fp, off, SEEK_CUR);
          212                         break;
          213                 }
          214         }
          215 
          216 corrupted:
          217         error(strerror(errno));
          218         error("library corrupted");
          219         return 0;
          220 }
          221 
          222 static void
          223 merge(FILE *to, struct fprop *prop, FILE *lib, FILE *idx)
          224 {
          225         int c;
          226         struct ar_hdr first;
          227 
          228         rewind(lib);
          229         rewind(idx);
          230         fseek(lib, SARMAG, SEEK_SET);
          231 
          232         if (fread(&first, sizeof(first), 1, lib) != 1)
          233                 return;
          234 
          235         if (!strncmp(first.ar_name, namidx, strlen(namidx))) {
          236                 long siz = atol(first.ar_size);
          237                 fseek(lib, siz + (siz & 1), SEEK_CUR);
          238         } else {
          239                 fseek(lib, SARMAG, SEEK_SET);
          240         }
          241 
          242         fwrite(ARMAG, SARMAG, 1, to);
          243 
          244         fprintf(to,
          245                 "%-16.16s%-12lld%-6u%-6u%-8lo%-10ld`\n",
          246                 namidx,
          247                 fromepoch(prop->time),
          248                 prop->uid,
          249                 prop->gid,
          250                 prop->mode,
          251                 prop->size);
          252 
          253         while ((c = getc(idx)) != EOF)
          254                 putc(c, to);
          255         if (prop->size & 1)
          256                 putc('\n', to);
          257 
          258         while ((c = getc(lib)) != EOF)
          259                 putc(c, to);
          260 
          261         fflush(to);
          262 }
          263 
          264 static void
          265 ranlib(char *fname)
          266 {
          267         size_t r;
          268         long *offs, size, i;
          269         char **names;
          270         FILE *fp, *idx, *out;
          271         Symdef *dp;
          272         struct fprop prop;
          273         char tmpname[FILENAME_MAX];
          274 
          275         filename = fname;
          276         if ((fp = fopen(fname, "rb")) == NULL) {
          277                 error(strerror(errno));
          278                 return;
          279         }
          280 
          281         if (readsyms(fp) <0)
          282                 goto err2;
          283 
          284         if ((idx = tmpfile()) == NULL) {
          285                 error(strerror(errno));
          286                 goto err2;
          287         }
          288 
          289         offs = malloc(sizeof(long) * nsymbols);
          290         names = malloc(sizeof(*names) * nsymbols);
          291         if (!offs || !names) {
          292                 error(strerror(errno));
          293                 goto err3;
          294         }
          295 
          296         for (dp = head, i = 0; i < nsymbols; dp = dp->next, i++) {
          297                 offs[i] = dp->offset;
          298                 names[i] = dp->name;
          299         }
          300 
          301         /* First pass: write index to determine its size */
          302         if (setindex(artype, nsymbols, names, offs, idx) < 0) {
          303                 error(strerror(errno));
          304                 goto err3;
          305         }
          306 
          307         if (getstat(fname, &prop) < 0) {
          308                 error(strerror(errno));
          309                 goto err3;
          310         }
          311         prop.time = time(NULL);
          312         prop.size = ftell(idx);
          313 
          314         size = sizeof(struct ar_hdr) + prop.size + (prop.size & 1);
          315         for (i = 0; i < nsymbols; i++)
          316                 offs[i] += size;
          317 
          318         /* Second pass: rewrite index with corrected offsets */
          319         rewind(idx);
          320         if (setindex(artype, nsymbols, names, offs, idx) < 0) {
          321                 error(strerror(errno));
          322                 goto err3;
          323         }
          324 
          325         r = snprintf(tmpname, sizeof(tmpname), "%s.tmp", fname);
          326         if (r >= sizeof(tmpname)) {
          327                 error("too long temporary name");
          328                 goto err3;
          329         }
          330 
          331         if ((out = fopen(tmpname, "wb")) == NULL) {
          332                 error(strerror(errno));
          333                 goto err3;
          334         }
          335 
          336         merge(out, &prop, fp, idx);
          337         if (ferror(out) || ferror(fp) || ferror(idx)) {
          338                 error(strerror(errno));
          339                 fclose(out);
          340                 goto err4;
          341         }
          342 
          343         fclose(out);
          344         if (rename(tmpname, fname) == EOF) {
          345                 error(strerror(errno));
          346                 goto err4;
          347         }
          348 
          349 err4:
          350         remove(tmpname);
          351 err3:
          352         free(offs);
          353         free(names);
          354         fclose(idx);
          355 err2:
          356         freehash();
          357 err1:
          358         fclose(fp);
          359 }
          360 
          361 static void
          362 usage(void)
          363 {
          364         fputs("usage: scc-ranlib [-t] file...\n", stderr);
          365         exit(EXIT_FAILURE);
          366 }
          367 
          368 int
          369 main(int argc, char *argv[])
          370 {
          371         ARGBEGIN {
          372         case 't':
          373                 break;
          374         default:
          375                 usage();
          376         } ARGEND
          377 
          378         if (argc == 0)
          379                 usage();
          380 
          381         for (; *argv; ++argv)
          382                 ranlib(*argv);
          383 
          384         return status;
          385 }