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 3, 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, see <http://www.gnu.org/licenses/>. */
24 #include "dbuf_string.h"
33 #define NELEM(x) (sizeof (x) / sizeof (*x))
36 static int verbose = 0;
38 static int print_index = 0;
46 if (!(ret = fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, ARMAG, SARMAG) == 0))
53 static int sym_tab_size;
56 get_member_name (char *name, size_t *p_size, int allocate, FILE * libfp)
60 if (0 == memcmp (name, "#1/", 3))
63 size_t len = strtoul (&name [3], &p, 10);
66 /* BSD appends real file name to the file header */
72 char *n = (char *) malloc (len);
73 if (fread (n, 1, len, libfp) != len)
75 /* not an ar archive or broken ar archive */
83 /* just advance the file pointer */
84 fseek (libfp, len, SEEK_CUR);
90 /* not an ar archive or broken ar archive */
102 int name_offset = strtol (++name, &p, 0);
103 if (p != name && name_offset < sym_tab_size)
105 int len = p - name + 1;
106 while (len < AR_NAME_LEN && name[len++] == ' ')
108 if (len == AR_NAME_LEN)
112 /* long name: get it from the symbol table */
113 name = &sym_tab[name_offset];
114 for (p = name; *p != '/' && *p != '\n'; ++p)
115 assert (p < &sym_tab[sym_tab_size]);
117 if (p[0] != '/' || p[1] != '\n')
119 assert (p < &sym_tab[sym_tab_size]);
121 n = (char *) malloc (p - name + 1);
122 memcpy (n, name, p - name);
131 char *p = strrchr (name, '/');
136 while (name[++len] == ' ')
138 if (len == AR_NAME_LEN)
140 char *n = (char *) malloc (p - name + 1);
141 memcpy (n, name, p - name);
148 /* BSD formed member name:
149 trim trailing spaces */
152 p = name + AR_NAME_LEN;
153 while (*--p == ' ' && p >= name)
156 n = (char *) malloc (p - name + 1);
157 memcpy (n, name, p - name);
163 /* bad formed member name:
166 return strdup (name);
173 ar_get_header (struct ar_hdr *hdr, FILE * libfp, char **p_obj_name)
175 char header[ARHDR_LEN];
176 char buf[AR_DATE_LEN + 1];
180 if (fread (header, 1, sizeof (header), libfp) != sizeof (header)
181 || memcmp (header + AR_FMAG_OFFSET, ARFMAG, AR_FMAG_LEN) != 0)
183 /* not an ar archive */
187 memcpy (hdr->ar_name, &header[AR_NAME_OFFSET], AR_NAME_LEN);
188 hdr->ar_name[AR_NAME_LEN] = '\0';
190 memcpy (buf, &header[AR_DATE_OFFSET], AR_DATE_LEN);
191 buf[AR_DATE_LEN] = '\0';
192 hdr->ar_date = strtol (buf, NULL, 0);
194 memcpy (buf, &header[AR_UID_OFFSET], AR_GID_LEN);
195 buf[AR_GID_LEN] = '\0';
196 hdr->ar_uid = (uid_t) strtol (buf, NULL, 0);
198 memcpy (buf, &header[AR_GID_OFFSET], AR_DATE_LEN);
199 buf[AR_DATE_LEN] = '\0';
200 hdr->ar_gid = (gid_t) strtol (buf, NULL, 0);
202 memcpy (buf, &header[AR_MODE_OFFSET], AR_MODE_LEN);
203 buf[AR_MODE_LEN] = '\0';
204 hdr->ar_mode = (mode_t) strtoul (buf, NULL, 0);
206 memcpy (buf, &header[AR_SIZE_OFFSET], AR_SIZE_LEN);
207 buf[AR_SIZE_LEN] = '\0';
208 hdr->ar_size = strtol (buf, NULL, 0);
210 if (NULL == (obj_name = get_member_name (hdr->ar_name, &size, p_obj_name != NULL, libfp)) && p_obj_name != NULL)
212 /* Malformed archive */
216 if (p_obj_name != NULL)
217 *p_obj_name = obj_name;
219 /* treat BSD appended real file name as a part of the header */
220 hdr->ar_size -= size;
222 return size + ARHDR_LEN;
226 get_member_name_by_offset (FILE * fp, long offset)
231 fseek (fp, offset, SEEK_SET);
232 return (ar_get_header (&hdr, fp, &name) != 0) ? name : NULL;
239 struct symbol_s *next;
242 struct symbol_s *symlist, *lastsym;
243 unsigned int offset, first_member_offset;
246 add_symbol (const char *sym, void *param)
250 if ((s = (struct symbol_s *) malloc (sizeof (struct symbol_s))) == NULL)
254 printf ("%s\n", sym);
256 s->name = strdup (sym);
257 s->offset = offset - first_member_offset;
262 lastsym = symlist = s;
274 is_rel (FILE * libfp)
277 long pos = ftell (libfp);
281 if (((c = getc (libfp)) == 'X' || c == 'D' || c == 'Q') && ((c = getc (libfp)) == 'H' || c == 'L'))
283 switch (getc (libfp))
286 if (getc (libfp) == '\n')
298 if (fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, "!FILE ", 6) == 0)
301 fseek (libfp, pos, SEEK_SET);
306 enum_symbols (FILE * fp, long size, int (*func) (const char *sym, void *param), void *param)
310 struct dbuf_s symname;
312 assert (func != NULL);
314 dbuf_init (&buf, 512);
315 dbuf_init (&symname, 32);
317 end = (size >= 0) ? ftell (fp) + size : -1;
320 * Read in the object file. Look for lines that
321 * begin with "S" and end with "D". These are
322 * symbol table definitions. If we find one, see
323 * if it is our symbol. Make sure we only read in
324 * our object file and don't go into the next one.
327 while (end < 0 || ftell (fp) < end)
331 dbuf_set_length (&buf, 0);
332 if (dbuf_getline (&buf, fp) == 0)
335 p = dbuf_c_str (&buf);
341 * Skip everything that's not a symbol record.
343 if ('S' == p[0] && ' ' == p[1])
345 dbuf_set_length (&symname, 0);
347 for (p += 2; *p && ' ' != *p; ++p)
348 dbuf_append_char (&symname, *p);
350 /* If it's an actual symbol, record it */
351 if (' ' == p[0] && 'D' == p[1])
353 if ((*func) (dbuf_c_str (&symname), NULL))
359 dbuf_destroy (&symname);
365 process_symbol_table (struct ar_hdr *hdr, FILE *fp)
367 long pos = ftell (fp);
375 printf ("Archive index:\n");
377 buf = (char *) malloc (hdr->ar_size);
379 if (fread (buf, 1, hdr->ar_size, fp) != hdr->ar_size)
390 for (i = 0; i < nsym; ++i)
397 if (NULL == (obj = get_member_name_by_offset (fp, offset))) /* member name */
400 printf ("%s in %s", ps, obj);
402 printf (" at 0x%04x\n", offset);
407 ps += strlen(ps) + 1;
412 fseek (fp, pos, SEEK_SET);
417 /* skip the symbol table */
418 fseek (fp, pos + hdr->ar_size + (hdr->ar_size & 1), SEEK_SET);
424 process_bsd_symbol_table (struct ar_hdr *hdr, FILE *fp)
426 long pos = ftell (fp);
435 printf ("Archive index:\n");
437 buf = (char *) malloc (hdr->ar_size);
439 if (fread (buf, 1, hdr->ar_size, fp) != hdr->ar_size)
445 tablesize = sgetl (buf);
446 nsym = tablesize / 8;
450 ps = po + tablesize + 4;
452 for (i = 0; i < nsym; ++i)
462 printf ("%s in ", ps + sym);
464 if (NULL == (obj = get_member_name_by_offset (fp, offset))) /* member name */
467 printf ("%s\n", obj);
474 /* skip the symbol table */
475 fseek (fp, pos + hdr->ar_size + (hdr->ar_size & 1), SEEK_SET);
481 get_symbols (FILE * fp, const char *archive)
487 if (!is_ar (fp) || !(hdr_len = ar_get_header (&hdr, fp, &name)))
494 if (AR_IS_SYMBOL_TABLE (name))
498 if (!process_symbol_table (&hdr, fp))
503 else if (!(hdr_len = ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL)))
506 else if (AR_IS_BSD_SYMBOL_TABLE (name))
510 if (!process_bsd_symbol_table (&hdr, fp))
515 else if (!(hdr_len = ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL)))
518 else if (!verbose && !list)
521 first_member_offset = ftell (fp) - hdr_len;
523 /* walk trough all archive members */
530 printf ("%s%s\n", name, verbose ? ":" : "");
536 long mdule_offset = ftell (fp);
538 offset = mdule_offset - hdr_len;
540 enum_symbols (fp, hdr.ar_size, add_symbol, NULL);
542 fseek (fp, mdule_offset + hdr.ar_size + (hdr.ar_size & 1), SEEK_SET);
552 fprintf (stderr, "asranlib: %s: File format not recognized\n", name);
556 /* skip if the member is not a .REL format */
557 fseek (fp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
560 while ((hdr_len = ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL)));
562 return feof (fp) ? 1 : 0;
566 do_ranlib (const char *archive)
570 if (NULL == (infp = fopen (archive, "rb")))
572 fprintf (stderr, "asranlib: %s: ", archive);
577 if (!get_symbols (infp, archive))
579 fprintf (stderr, "asranlib: %s: Malformed archive\n", archive);
583 else if (!list && !print_index)
586 struct symbol_s *symp;
592 char tmpfile[] = "arXXXXXX";
595 if (NULL == _mktemp (tmpfile) || NULL == (outfp = fopen (tmpfile, "wb")))
598 fprintf (stderr, "asranlib: %s: ", tmpfile);
603 if ((pad = mkstemp (tmpfile)) < 0)
606 fprintf (stderr, "asranlib: %s: ", tmpfile);
611 if (NULL == (outfp = fdopen (pad, "wb")))
620 /* calculate the size of symbol table */
621 for (str_length = 0, nsym = 0, symp = symlist; symp; ++nsym, symp = symp->next)
623 str_length += strlen (symp->name) + 1;
626 symtab_size = 4 + 4 * nsym + str_length;
628 fprintf (outfp, ARMAG AR_SYMBOL_TABLE_NAME "%-12d%-6d%-6d%-8d%-10d" ARFMAG, (int) time (NULL), 0, 0, 0, symtab_size);
638 symtab_size += SARMAG + ARHDR_LEN;
641 fwrite (buf, 1, sizeof (buf), outfp);
643 for (symp = symlist; symp; symp = symp->next)
645 sputl (symp->offset + symtab_size, buf);
646 fwrite (buf, 1, sizeof (buf), outfp);
650 for (symp = symlist; symp; symp = symp->next)
652 fputs (symp->name, outfp);
659 fseek (infp, first_member_offset, SEEK_SET);
661 while (EOF != (pad = getc (infp)))
667 if (0 != remove (archive))
669 fprintf (stderr, "asranlib: can't remove %s to %s: ", tmpfile, archive);
672 else if (0 != rename (tmpfile, archive))
674 fprintf (stderr, "asranlib: can't rename %s to %s: ", tmpfile, archive);
691 printf ("SDCC asxxxx ranlib 1.0.0 $Revision$\n");
712 const char *long_opt;
713 void (*optfnc) (void);
718 { 'v', "verbose", &do_verbose, "Be more verbose about the operation" },
719 { 'V', "version", &print_version, "Print this help message" },
720 { 'h', "help", &usage, "Print version information" },
721 { 't', "list", &do_list, "List the contents of an archive" },
722 { 's', "print-armap", &print_armap, "Print the archive index" },
730 printf ("Usage: asranlib [options] archive\n"
731 " Generate an index to speed access to archives\n"
732 " The options are:\n");
734 for (i = 0; i < NELEM (opts); ++i)
737 if ('\0' != opts[i].short_opt)
738 printf (" -%c ", opts[i].short_opt);
742 if (NULL != opts[i].long_opt)
744 printf ("--%s ", opts[i].long_opt);
745 len += strlen (opts[i].long_opt);
750 printf ("%s\n", opts[i].comment);
753 printf ("asranlib: supported targets: asxxxx\n");
759 main (int argc, char *argv[])
765 for (argp = argv + 1; *argp; ++argp)
767 if (!noopts && (*argp)[0] == '-')
771 if ((*argp)[1] == '-')
773 if ((*argp)[2] == '\0')
782 for (i = 0; i < NELEM (opts); ++i)
784 if (0 == strcmp (&(*argp)[2], opts[i].long_opt))
786 if (NULL != opts[i].optfnc)
788 (*opts[i].optfnc) ();
793 if (i >= NELEM (opts))
795 fprintf (stderr, "asranlib: unrecognized option `%s'\n", *argp);
805 for (optp = &(*argp)[1]; *optp != '\0'; ++optp)
807 for (i = 0; i < NELEM (opts); ++i)
809 if (*optp == opts[i].short_opt)
811 if (NULL != opts[i].optfnc)
813 (*opts[i].optfnc) ();
818 if (i >= NELEM (opts))
820 fprintf (stderr, "asranlib: invalid option -- %c\n", *optp);