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"
29 #define mktemp _mktemp
32 #define NELEM(x) (sizeof (x) / sizeof (*x))
45 if (!(ret = fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, ARMAG, SARMAG) == 0))
52 static int sym_tab_size;
55 get_member_name (char *name, size_t *p_size, int allocate, FILE * libfp)
59 if (0 == memcmp (name, "#1/", 3))
62 size_t len = strtoul (&name [3], &p, 10);
65 /* BSD appends real file name to the file header */
71 char *n = (char *) malloc (len);
72 if (fread (n, 1, len, libfp) != len)
74 /* not an ar archive or broken ar archive */
82 /* just advance the file pointer */
83 fseek (libfp, len, SEEK_CUR);
89 /* not an ar archive or broken ar archive */
101 int name_offset = strtol (++name, &p, 0);
102 if (p != name && name_offset < sym_tab_size)
104 int len = p - name + 1;
105 while (len < AR_NAME_LEN && name[len++] == ' ')
107 if (len == AR_NAME_LEN)
111 /* long name: get it from the symbol table */
112 name = &sym_tab[name_offset];
113 for (p = name; *p != '/' && *p != '\n'; ++p)
114 assert (p < &sym_tab[sym_tab_size]);
116 if (p[0] != '/' || p[1] != '\n')
118 assert (p < &sym_tab[sym_tab_size]);
120 n = (char *) malloc (p - name + 1);
121 memcpy (n, name, p - name);
130 char *p = strrchr (name, '/');
135 while (name[++len] == ' ')
137 if (len == AR_NAME_LEN)
139 char *n = (char *) malloc (p - name + 1);
140 memcpy (n, name, p - name);
147 /* BSD formed member name:
148 trim trailing spaces */
151 p = name + AR_NAME_LEN;
152 while (*--p == ' ' && p >= name)
155 n = (char *) malloc (p - name + 1);
156 memcpy (n, name, p - name);
162 /* bad formed member name:
165 return strdup (name);
172 ar_get_header (struct ar_hdr *hdr, FILE * libfp, char **p_obj_name)
174 char header[ARHDR_LEN];
175 char buf[AR_DATE_LEN + 1];
179 if (fread (header, 1, sizeof (header), libfp) != sizeof (header)
180 || memcmp (header + AR_FMAG_OFFSET, ARFMAG, AR_FMAG_LEN) != 0)
182 /* not an ar archive */
186 memcpy (hdr->ar_name, &header[AR_NAME_OFFSET], AR_NAME_LEN);
187 hdr->ar_name[AR_NAME_LEN] = '\0';
189 memcpy (buf, &header[AR_DATE_OFFSET], AR_DATE_LEN);
190 buf[AR_DATE_LEN] = '\0';
191 hdr->ar_date = strtol (buf, NULL, 0);
193 memcpy (buf, &header[AR_UID_OFFSET], AR_GID_LEN);
194 buf[AR_GID_LEN] = '\0';
195 hdr->ar_uid = (uid_t) strtol (buf, NULL, 0);
197 memcpy (buf, &header[AR_GID_OFFSET], AR_DATE_LEN);
198 buf[AR_DATE_LEN] = '\0';
199 hdr->ar_gid = (gid_t) strtol (buf, NULL, 0);
201 memcpy (buf, &header[AR_MODE_OFFSET], AR_MODE_LEN);
202 buf[AR_MODE_LEN] = '\0';
203 hdr->ar_mode = (mode_t) strtoul (buf, NULL, 0);
205 memcpy (buf, &header[AR_SIZE_OFFSET], AR_SIZE_LEN);
206 buf[AR_SIZE_LEN] = '\0';
207 hdr->ar_size = strtol (buf, NULL, 0);
209 obj_name = get_member_name (hdr->ar_name, &size, p_obj_name != NULL, libfp);
211 if (p_obj_name != NULL)
212 *p_obj_name = obj_name;
214 /* treat BSD appended real file name as a part of the header */
215 hdr->ar_size -= size;
217 return size + ARHDR_LEN;
221 get_member_name_by_offset (FILE * fp, long offset)
226 fseek (fp, offset, SEEK_SET);
227 return (ar_get_header (&hdr, fp, &name) != 0) ? name : NULL;
234 struct symbol_s *next;
237 struct symbol_s *symlist, *lastsym;
238 unsigned int offset, first_member_offset;
241 add_symbol (const char *sym, void *param)
245 if ((s = (struct symbol_s *) malloc (sizeof (struct symbol_s))) == NULL)
249 printf ("%s\n", sym);
251 s->name = strdup (sym);
252 s->offset = offset - first_member_offset;
257 lastsym = symlist = s;
270 is_rel (FILE * libfp)
273 long pos = ftell (libfp);
277 if (((c = getc (libfp)) == 'X' || c == 'D' || c == 'Q') && ((c = getc (libfp)) == 'H' || c == 'L'))
279 switch (getc (libfp))
282 if (getc (libfp) == '\n')
294 if (fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, "!FILE ", 6) == 0)
297 fseek (libfp, pos, SEEK_SET);
302 enum_symbols (FILE * fp, long size, int (*func) (const char *sym, void *param), void *param)
306 struct dbuf_s symname;
308 assert (func != NULL);
310 dbuf_init (&buf, 512);
311 dbuf_init (&symname, 32);
313 end = (size >= 0) ? ftell (fp) + size : -1;
316 * Read in the object file. Look for lines that
317 * begin with "S" and end with "D". These are
318 * symbol table definitions. If we find one, see
319 * if it is our symbol. Make sure we only read in
320 * our object file and don't go into the next one.
323 while (end < 0 || ftell (fp) < end)
327 dbuf_set_length (&buf, 0);
328 if (dbuf_getline (&buf, fp) == 0)
331 p = dbuf_c_str (&buf);
337 * Skip everything that's not a symbol record.
339 if ('S' == p[0] && ' ' == p[1])
341 dbuf_set_length (&symname, 0);
343 for (p += 2; *p && ' ' != *p; ++p)
344 dbuf_append_char (&symname, *p);
346 /* If it's an actual symbol, record it */
347 if (' ' == p[0] && 'D' == p[1])
349 if ((*func) (dbuf_c_str (&symname), NULL))
355 dbuf_destroy (&symname);
362 process_symbol_table (struct ar_hdr *hdr, FILE *fp)
371 printf ("Archive index:\n");
373 buf = (char *) malloc (hdr->ar_size);
375 if (fread (buf, 1, hdr->ar_size, fp) != hdr->ar_size)
388 for (i = 0; i < nsym; ++i)
395 printf ("%s in ", ps);
396 ps += strlen(ps) + 1;
398 obj = get_member_name_by_offset (fp, offset); /* member name */
399 printf ("%s\n", obj);
405 fseek (fp, pos, SEEK_SET);
411 /* skip the symbol table */
412 fseek (fp, hdr->ar_size + (hdr->ar_size & 1), SEEK_CUR);
419 process_bsd_symbol_table (struct ar_hdr *hdr, FILE *fp)
429 printf ("Archive index:\n");
431 buf = (char *) malloc (hdr->ar_size);
433 if (fread (buf, 1, hdr->ar_size, fp) != hdr->ar_size)
441 tablesize = sgetl (buf);
442 nsym = tablesize / 8;
446 ps = po + tablesize + 4;
448 for (i = 0; i < nsym; ++i)
458 printf ("%s in ", ps + sym);
460 obj = get_member_name_by_offset (fp, offset); /* member name */
461 printf ("%s\n", obj);
466 fseek (fp, pos, SEEK_SET);
472 /* skip the symbol table */
473 fseek (fp, hdr->ar_size + (hdr->ar_size & 1), SEEK_CUR);
480 get_symbols (FILE * fp, const char *archive)
485 if (!is_ar (fp) || !ar_get_header (&hdr, fp, &name))
487 fprintf (stderr, "asranlib: %s: File format not recognized\n", archive);
491 if (AR_IS_SYMBOL_TABLE (name))
495 process_symbol_table (&hdr, fp);
496 if (!ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL))
499 else if (AR_IS_BSD_SYMBOL_TABLE (name))
503 process_bsd_symbol_table (&hdr, fp);
504 if (!ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL))
508 first_member_offset = ftell (fp) - ARHDR_LEN;
510 /* walk trough all archive members */
517 printf ("%s%s\n", name, verbose ? ":" : "");
523 long mdule_offset = ftell (fp);
525 offset = mdule_offset - ARHDR_LEN;
527 enum_symbols (fp, hdr.ar_size, add_symbol, NULL);
529 fseek (fp, mdule_offset + hdr.ar_size, SEEK_SET);
534 assert (c == EOF || c == '\n');
545 fprintf (stderr, "asranlib: %s: File format not recognized\n", name);
549 /* skip if the member is not a .REL format */
550 fseek (fp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
553 while (ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL));
559 do_ranlib (const char *archive)
563 if (NULL == (infp = fopen (archive, "rb")))
565 fprintf (stderr, "asranlib: %s: ", archive);
570 if (get_symbols (infp, archive))
573 struct symbol_s *symp;
579 char tmpfile[] = "arXXXXXX";
582 if (NULL == _mktemp (tmpfile) || NULL == (outfp = fopen (tmpfile, "wb")))
585 fprintf (stderr, "asranlib: %s: ", tmpfile);
590 if ((pad = mkstemp (tmpfile)) < 0)
593 fprintf (stderr, "asranlib: %s: ", tmpfile);
598 if (NULL == (outfp = fdopen (pad, "wb")))
607 /* calculate the size of symbol table */
608 for (str_length = 0, nsym = 0, symp = symlist; symp; ++nsym, symp = symp->next)
610 str_length += strlen (symp->name) + 1;
613 symtab_size = 4 + 4 * nsym + str_length;
615 fprintf (outfp, ARMAG AR_SYMBOL_TABLE_NAME "%-12d%-6d%-6d%-8d%-10d" ARFMAG, (int) time (NULL), 0, 0, 0, symtab_size);
625 symtab_size += SARMAG + ARHDR_LEN;
628 fwrite (buf, 1, sizeof (buf), outfp);
630 for (symp = symlist; symp; symp = symp->next)
632 sputl (symp->offset + symtab_size, buf);
633 fwrite (buf, 1, sizeof (buf), outfp);
637 for (symp = symlist; symp; symp = symp->next)
639 fputs (symp->name, outfp);
646 fseek (infp, first_member_offset, SEEK_SET);
648 while (EOF != (pad = getc (infp)))
654 if (0 != remove (archive))
656 fprintf (stderr, "asranlib: can't remove %s to %s: ", tmpfile, archive);
659 else if (0 != rename (tmpfile, archive))
661 fprintf (stderr, "asranlib: can't rename %s to %s: ", tmpfile, archive);
678 printf ("SDCC asxxxx ranlib 1.0.0 $Revision$\n");
698 const char *short_opt;
699 const char *long_opt;
700 void (*optfnc) (void);
705 { "-v", "--verbose", &do_verbose, "Be more verbose about the operation" },
706 { "-V", "--version", &print_version, "Print this help message" },
707 { "-h", "--help", &usage, "Print version information" },
708 { "-t", "--list", &do_list, "List the contents of an archive" },
709 { "-s", "--print-armap", &print_armap, "Print the archive index" },
717 printf ("Usage: asranlib [options] archive\n"
718 " Generate an index to speed access to archives\n"
719 " The options are:\n");
721 for (i = 0; i < NELEM (opts); ++i)
724 printf (" %s ", (NULL != opts[i].short_opt) ? opts[i].short_opt : " ");
725 if (NULL != opts[i].long_opt)
727 printf ("%s ", opts[i].long_opt);
728 len += strlen (opts[i].long_opt);
733 printf ("%s\n", opts[i].comment);
736 printf ("asranlib: supported targets: asxxxx\n");
742 process_options (int argc, char *argv[])
747 for (argp = argv + 1; *argp; ++argp)
749 if (!noopts && (*argp)[0] == '-')
753 if ((*argp)[1] == '-' && (*argp)[2] == '\0')
759 for (i = 0; i < NELEM (opts); ++i)
761 if (0 == strcmp (*argp, opts[i].short_opt) || 0 == strcmp (*argp, opts[i].long_opt))
763 if (NULL != opts[i].optfnc)
765 (*opts[i].optfnc) ();
784 main (int argc, char *argv[])
786 process_options (argc, argv);