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))
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 obj_name = get_member_name (hdr->ar_name, &size, p_obj_name != NULL, libfp);
212 if (p_obj_name != NULL)
213 *p_obj_name = obj_name;
215 /* treat BSD appended real file name as a part of the header */
216 hdr->ar_size -= size;
218 return size + ARHDR_LEN;
222 get_member_name_by_offset (FILE * fp, long offset)
227 fseek (fp, offset, SEEK_SET);
228 return (ar_get_header (&hdr, fp, &name) != 0) ? name : NULL;
235 struct symbol_s *next;
238 struct symbol_s *symlist, *lastsym;
239 unsigned int offset, first_member_offset;
242 add_symbol (const char *sym, void *param)
246 if ((s = (struct symbol_s *) malloc (sizeof (struct symbol_s))) == NULL)
250 printf ("%s\n", sym);
252 s->name = strdup (sym);
253 s->offset = offset - first_member_offset;
258 lastsym = symlist = s;
271 is_rel (FILE * libfp)
274 long pos = ftell (libfp);
278 if (((c = getc (libfp)) == 'X' || c == 'D' || c == 'Q') && ((c = getc (libfp)) == 'H' || c == 'L'))
280 switch (getc (libfp))
283 if (getc (libfp) == '\n')
295 if (fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, "!FILE ", 6) == 0)
298 fseek (libfp, pos, SEEK_SET);
303 enum_symbols (FILE * fp, long size, int (*func) (const char *sym, void *param), void *param)
307 struct dbuf_s symname;
309 assert (func != NULL);
311 dbuf_init (&buf, 512);
312 dbuf_init (&symname, 32);
314 end = (size >= 0) ? ftell (fp) + size : -1;
317 * Read in the object file. Look for lines that
318 * begin with "S" and end with "D". These are
319 * symbol table definitions. If we find one, see
320 * if it is our symbol. Make sure we only read in
321 * our object file and don't go into the next one.
324 while (end < 0 || ftell (fp) < end)
328 dbuf_set_length (&buf, 0);
329 if (dbuf_getline (&buf, fp) == 0)
332 p = dbuf_c_str (&buf);
338 * Skip everything that's not a symbol record.
340 if ('S' == p[0] && ' ' == p[1])
342 dbuf_set_length (&symname, 0);
344 for (p += 2; *p && ' ' != *p; ++p)
345 dbuf_append_char (&symname, *p);
347 /* If it's an actual symbol, record it */
348 if (' ' == p[0] && 'D' == p[1])
350 if ((*func) (dbuf_c_str (&symname), NULL))
356 dbuf_destroy (&symname);
363 process_symbol_table (struct ar_hdr *hdr, FILE *fp)
372 printf ("Archive index:\n");
374 buf = (char *) malloc (hdr->ar_size);
376 if (fread (buf, 1, hdr->ar_size, fp) != hdr->ar_size)
389 for (i = 0; i < nsym; ++i)
396 printf ("%s in ", ps);
397 ps += strlen(ps) + 1;
399 obj = get_member_name_by_offset (fp, offset); /* member name */
400 printf ("%s\n", obj);
406 fseek (fp, pos, SEEK_SET);
412 /* skip the symbol table */
413 fseek (fp, hdr->ar_size + (hdr->ar_size & 1), SEEK_CUR);
420 process_bsd_symbol_table (struct ar_hdr *hdr, FILE *fp)
430 printf ("Archive index:\n");
432 buf = (char *) malloc (hdr->ar_size);
434 if (fread (buf, 1, hdr->ar_size, fp) != hdr->ar_size)
442 tablesize = sgetl (buf);
443 nsym = tablesize / 8;
447 ps = po + tablesize + 4;
449 for (i = 0; i < nsym; ++i)
459 printf ("%s in ", ps + sym);
461 obj = get_member_name_by_offset (fp, offset); /* member name */
462 printf ("%s\n", obj);
467 fseek (fp, pos, SEEK_SET);
473 /* skip the symbol table */
474 fseek (fp, hdr->ar_size + (hdr->ar_size & 1), SEEK_CUR);
481 get_symbols (FILE * fp, const char *archive)
486 if (!is_ar (fp) || !ar_get_header (&hdr, fp, &name))
488 fprintf (stderr, "asranlib: %s: File format not recognized\n", archive);
492 if (AR_IS_SYMBOL_TABLE (name))
496 process_symbol_table (&hdr, fp);
497 if (!ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL))
500 else if (AR_IS_BSD_SYMBOL_TABLE (name))
504 process_bsd_symbol_table (&hdr, fp);
505 if (!ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL))
509 first_member_offset = ftell (fp) - ARHDR_LEN;
511 /* walk trough all archive members */
518 printf ("%s%s\n", name, verbose ? ":" : "");
524 long mdule_offset = ftell (fp);
526 offset = mdule_offset - ARHDR_LEN;
528 enum_symbols (fp, hdr.ar_size, add_symbol, NULL);
530 fseek (fp, mdule_offset + hdr.ar_size, SEEK_SET);
535 assert (c == EOF || c == '\n');
546 fprintf (stderr, "asranlib: %s: File format not recognized\n", name);
550 /* skip if the member is not a .REL format */
551 fseek (fp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
554 while (ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL));
560 do_ranlib (const char *archive)
564 if (NULL == (infp = fopen (archive, "rb")))
566 fprintf (stderr, "asranlib: %s: ", archive);
571 if (get_symbols (infp, archive))
574 struct symbol_s *symp;
580 char tmpfile[] = "arXXXXXX";
583 if (NULL == _mktemp (tmpfile) || NULL == (outfp = fopen (tmpfile, "wb")))
586 fprintf (stderr, "asranlib: %s: ", tmpfile);
591 if ((pad = mkstemp (tmpfile)) < 0)
594 fprintf (stderr, "asranlib: %s: ", tmpfile);
599 if (NULL == (outfp = fdopen (pad, "wb")))
608 /* calculate the size of symbol table */
609 for (str_length = 0, nsym = 0, symp = symlist; symp; ++nsym, symp = symp->next)
611 str_length += strlen (symp->name) + 1;
614 symtab_size = 4 + 4 * nsym + str_length;
616 fprintf (outfp, ARMAG AR_SYMBOL_TABLE_NAME "%-12d%-6d%-6d%-8d%-10d" ARFMAG, (int) time (NULL), 0, 0, 0, symtab_size);
626 symtab_size += SARMAG + ARHDR_LEN;
629 fwrite (buf, 1, sizeof (buf), outfp);
631 for (symp = symlist; symp; symp = symp->next)
633 sputl (symp->offset + symtab_size, buf);
634 fwrite (buf, 1, sizeof (buf), outfp);
638 for (symp = symlist; symp; symp = symp->next)
640 fputs (symp->name, outfp);
647 fseek (infp, first_member_offset, SEEK_SET);
649 while (EOF != (pad = getc (infp)))
655 if (0 != remove (archive))
657 fprintf (stderr, "asranlib: can't remove %s to %s: ", tmpfile, archive);
660 else if (0 != rename (tmpfile, archive))
662 fprintf (stderr, "asranlib: can't rename %s to %s: ", tmpfile, archive);
679 printf ("SDCC asxxxx ranlib 1.0.0 $Revision$\n");
699 const char *short_opt;
700 const char *long_opt;
701 void (*optfnc) (void);
706 { "-v", "--verbose", &do_verbose, "Be more verbose about the operation" },
707 { "-V", "--version", &print_version, "Print this help message" },
708 { "-h", "--help", &usage, "Print version information" },
709 { "-t", "--list", &do_list, "List the contents of an archive" },
710 { "-s", "--print-armap", &print_armap, "Print the archive index" },
718 printf ("Usage: asranlib [options] archive\n"
719 " Generate an index to speed access to archives\n"
720 " The options are:\n");
722 for (i = 0; i < NELEM (opts); ++i)
725 printf (" %s ", (NULL != opts[i].short_opt) ? opts[i].short_opt : " ");
726 if (NULL != opts[i].long_opt)
728 printf ("%s ", opts[i].long_opt);
729 len += strlen (opts[i].long_opt);
734 printf ("%s\n", opts[i].comment);
737 printf ("asranlib: supported targets: asxxxx\n");
743 process_options (int argc, char *argv[])
748 for (argp = argv + 1; *argp; ++argp)
750 if (!noopts && (*argp)[0] == '-')
754 if ((*argp)[1] == '-' && (*argp)[2] == '\0')
760 for (i = 0; i < NELEM (opts); ++i)
762 if (0 == strcmp (*argp, opts[i].short_opt) || 0 == strcmp (*argp, opts[i].long_opt))
764 if (NULL != opts[i].optfnc)
766 (*opts[i].optfnc) ();
785 main (int argc, char *argv[])
787 process_options (argc, argv);