1 /* asranlib.c - ranlib for asxxxx arvhives
2 version 1.0.0, April 27th, 2008
4 Copyright (C) 2008-2009 Borut Razem, borut dot razem at siol dot net
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25 #include "dbuf_string.h"
30 #define mktemp _mktemp
33 #define NELEM(x) (sizeof (x) / sizeof (*x))
42 if (!(ret = fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, ARMAG, SARMAG) == 0))
48 static struct ar_hdr *
49 ar_get_header (struct ar_hdr *hdr, FILE * libfp)
51 char header[ARHDR_LEN];
52 char buf[AR_DATE_LEN + 1];
54 if (fread (header, 1, sizeof (header), libfp) != sizeof (header) ||
55 memcmp (header + AR_FMAG_OFFSET, ARFMAG, AR_FMAG_LEN) != 0)
57 /* not an ar archive */
61 memcpy (hdr->ar_name, &header[AR_NAME_OFFSET], AR_NAME_LEN);
62 hdr->ar_name[AR_NAME_LEN] = '\0';
64 memcpy (buf, &header[AR_DATE_OFFSET], AR_DATE_LEN);
65 buf[AR_DATE_LEN] = '\0';
66 hdr->ar_date = strtol (buf, NULL, 0);
68 memcpy (buf, &header[AR_UID_OFFSET], AR_GID_LEN);
69 buf[AR_GID_LEN] = '\0';
70 hdr->ar_uid = (uid_t) strtol (buf, NULL, 0);
72 memcpy (buf, &header[AR_GID_OFFSET], AR_DATE_LEN);
73 buf[AR_DATE_LEN] = '\0';
74 hdr->ar_gid = (gid_t) strtol (buf, NULL, 0);
76 memcpy (buf, &header[AR_MODE_OFFSET], AR_MODE_LEN);
77 buf[AR_MODE_LEN] = '\0';
78 hdr->ar_mode = (mode_t) strtoul (buf, NULL, 0);
80 memcpy (buf, &header[AR_SIZE_OFFSET], AR_SIZE_LEN);
81 buf[AR_SIZE_LEN] = '\0';
82 hdr->ar_size = strtol (buf, NULL, 0);
92 struct symbol_s *next;
95 struct symbol_s *symlist, *lastsym;
96 off_t offset, first_member_offset;
99 add_symbol (const char *sym, void *param)
103 if ((s = (struct symbol_s *) malloc (sizeof (struct symbol_s))) == NULL)
106 s->name = strdup (sym);
107 s->offset = offset - first_member_offset;
112 lastsym = symlist = s;
125 is_rel (FILE * libfp)
128 long pos = ftell (libfp);
132 if (((c = getc (libfp)) == 'X' || c == 'D' || c == 'Q') && ((c = getc (libfp)) == 'H' || c == 'L'))
134 switch (getc (libfp))
137 if (getc (libfp) == '\n')
149 if (fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, "!FILE ", 6) == 0)
152 fseek (libfp, pos, SEEK_SET);
157 enum_symbols (FILE * fp, long size, int (*func) (const char *sym, void *param), void *param)
161 struct dbuf_s symname;
163 assert (func != NULL);
165 dbuf_init (&buf, 512);
166 dbuf_init (&symname, 32);
168 end = (size >= 0) ? ftell (fp) + size : -1;
171 * Read in the object file. Look for lines that
172 * begin with "S" and end with "D". These are
173 * symbol table definitions. If we find one, see
174 * if it is our symbol. Make sure we only read in
175 * our object file and don't go into the next one.
178 while (end < 0 || ftell (fp) < end)
182 dbuf_set_length (&buf, 0);
183 if (dbuf_getline (&buf, fp) == 0)
186 p = dbuf_c_str (&buf);
192 * Skip everything that's not a symbol record.
194 if ('S' == p[0] && ' ' == p[1])
196 dbuf_set_length (&symname, 0);
198 for (p += 2; *p && ' ' != *p; ++p)
199 dbuf_append_char (&symname, *p);
201 /* If it's an actual symbol, record it */
202 if (' ' == p[0] && 'D' == p[1])
204 if ((*func) (dbuf_c_str (&symname), NULL))
210 dbuf_destroy (&symname);
216 get_symbols (FILE * fp, const char *archive)
220 if (!is_ar (fp) || !ar_get_header (&hdr, fp))
222 fprintf (stderr, "asranlib: %s: File format not recognized\n", archive);
226 if (AR_IS_SYMBOL_TABLE (hdr))
228 /* skip the symbol table */
229 fseek (fp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
232 first_member_offset = ftell (fp) - ARHDR_LEN;
234 /* walk trough all archive members */
239 long mdule_offset = ftell (fp);
241 offset = mdule_offset - ARHDR_LEN;
243 enum_symbols (fp, hdr.ar_size, add_symbol, NULL);
245 fseek (fp, mdule_offset + hdr.ar_size, SEEK_SET);
250 assert (c == EOF || c == '\n');
255 /* skip if the member is not a .REL format */
256 fseek (fp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
259 while (ar_get_header (&hdr, fp));
266 do_ranlib (const char *archive)
270 if (NULL == (infp = fopen (archive, "rb")))
272 fprintf (stderr, "asranlib: %s: ", archive);
277 if (get_symbols (infp, archive))
280 struct symbol_s *symp;
286 char tmpfile[] = "arXXXXXX";
288 if (NULL == mktemp (tmpfile) || NULL == (outfp = fopen (tmpfile, "wb")))
291 fprintf (stderr, "asranlib: %s: ", tmpfile);
296 /* calculate the size of symbol table */
297 for (nsym = 0, symp = symlist; symp; ++nsym, symp = symp->next)
299 str_length += strlen (symp->name) + 1;
302 symtab_size = 4 + 4 * nsym + str_length;
304 fprintf (outfp, ARMAG AR_SYMBOL_TABLE_NAME "%-12d%-6d%-6d%-8d%-10d" ARFMAG, (int) time (NULL), 0, 0, 0, symtab_size);
314 symtab_size += SARMAG + ARHDR_LEN;
317 fwrite (buf, 1, sizeof (buf), outfp);
319 for (symp = symlist; symp; symp = symp->next)
321 sputl (symp->offset + symtab_size, buf);
322 fwrite (buf, 1, sizeof (buf), outfp);
326 for (symp = symlist; symp; symp = symp->next)
328 fputs (symp->name, outfp);
335 fseek (infp, first_member_offset, SEEK_SET);
337 while (EOF != (pad = getc (infp)))
343 if (0 != remove (archive))
345 fprintf (stderr, "asranlib: can't remove %s to %s: ", tmpfile, archive);
348 else if (0 != rename (tmpfile, archive))
350 fprintf (stderr, "asranlib: can't rename %s to %s: ", tmpfile, archive);
362 printf ("SDCC asxxxx ranlib 1.0.0 $Revision$\n");
370 printf ("Usage: asranlib [options] archive\n"
371 " Generate an index to speed access to archives\n"
372 " The options are:\n"
373 " -h --help Print this help message\n"
374 " -V --version Print version information\n"
375 "asranlib: supported targets: asxxxx\n");
384 void (*optfnc) (void);
388 { "-v", &print_version, },
389 { "-V", &print_version, },
390 { "--version", &print_version, },
392 { "--help", &usage, },
397 process_options (int argc, char *argv[])
402 for (argp = argv + 1; *argp; ++argp)
404 if (!noopts && (*argp)[0] == '-')
408 if ((*argp)[1] == '-' && (*argp)[2] == '\0')
414 for (i = 0; i < NELEM (opts); ++i)
416 if (0 == strcmp (*argp, opts[i].opt))
418 if (NULL != opts[i].optfnc)
420 (*opts[i].optfnc) ();
437 main (int argc, char *argv[])
439 process_options (argc, argv);