scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

ranlib.c (5885B)


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