scc

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

ranlib.c (5967B)


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