scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | 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 }