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 }