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)
487 if (!is_ar (fp) || !(hdr_len = ar_get_header (&hdr, fp, &name)))
489 fprintf (stderr, "asranlib: %s: File format not recognized\n", archive);
493 if (AR_IS_SYMBOL_TABLE (name))
497 process_symbol_table (&hdr, fp);
498 if (!(hdr_len = ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL)))
501 else if (AR_IS_BSD_SYMBOL_TABLE (name))
505 process_bsd_symbol_table (&hdr, fp);
506 if (!(hdr_len = ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL)))
510 first_member_offset = ftell (fp) - hdr_len;
512 /* walk trough all archive members */
519 printf ("%s%s\n", name, verbose ? ":" : "");
525 long mdule_offset = ftell (fp);
527 offset = mdule_offset - hdr_len;
529 enum_symbols (fp, hdr.ar_size, add_symbol, NULL);
531 fseek (fp, mdule_offset + hdr.ar_size, SEEK_SET);
536 assert (c == EOF || c == '\n');
547 fprintf (stderr, "asranlib: %s: File format not recognized\n", name);
551 /* skip if the member is not a .REL format */
552 fseek (fp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
555 while (ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL));
561 do_ranlib (const char *archive)
565 if (NULL == (infp = fopen (archive, "rb")))
567 fprintf (stderr, "asranlib: %s: ", archive);
572 if (get_symbols (infp, archive))
575 struct symbol_s *symp;
581 char tmpfile[] = "arXXXXXX";
584 if (NULL == _mktemp (tmpfile) || NULL == (outfp = fopen (tmpfile, "wb")))
587 fprintf (stderr, "asranlib: %s: ", tmpfile);
592 if ((pad = mkstemp (tmpfile)) < 0)
595 fprintf (stderr, "asranlib: %s: ", tmpfile);
600 if (NULL == (outfp = fdopen (pad, "wb")))
609 /* calculate the size of symbol table */
610 for (str_length = 0, nsym = 0, symp = symlist; symp; ++nsym, symp = symp->next)
612 str_length += strlen (symp->name) + 1;
615 symtab_size = 4 + 4 * nsym + str_length;
617 fprintf (outfp, ARMAG AR_SYMBOL_TABLE_NAME "%-12d%-6d%-6d%-8d%-10d" ARFMAG, (int) time (NULL), 0, 0, 0, symtab_size);
627 symtab_size += SARMAG + ARHDR_LEN;
630 fwrite (buf, 1, sizeof (buf), outfp);
632 for (symp = symlist; symp; symp = symp->next)
634 sputl (symp->offset + symtab_size, buf);
635 fwrite (buf, 1, sizeof (buf), outfp);
639 for (symp = symlist; symp; symp = symp->next)
641 fputs (symp->name, outfp);
648 fseek (infp, first_member_offset, SEEK_SET);
650 while (EOF != (pad = getc (infp)))
656 if (0 != remove (archive))
658 fprintf (stderr, "asranlib: can't remove %s to %s: ", tmpfile, archive);
661 else if (0 != rename (tmpfile, archive))
663 fprintf (stderr, "asranlib: can't rename %s to %s: ", tmpfile, archive);
680 printf ("SDCC asxxxx ranlib 1.0.0 $Revision$\n");
700 const char *short_opt;
701 const char *long_opt;
702 void (*optfnc) (void);
707 { "-v", "--verbose", &do_verbose, "Be more verbose about the operation" },
708 { "-V", "--version", &print_version, "Print this help message" },
709 { "-h", "--help", &usage, "Print version information" },
710 { "-t", "--list", &do_list, "List the contents of an archive" },
711 { "-s", "--print-armap", &print_armap, "Print the archive index" },
719 printf ("Usage: asranlib [options] archive\n"
720 " Generate an index to speed access to archives\n"
721 " The options are:\n");
723 for (i = 0; i < NELEM (opts); ++i)
726 printf (" %s ", (NULL != opts[i].short_opt) ? opts[i].short_opt : " ");
727 if (NULL != opts[i].long_opt)
729 printf ("%s ", opts[i].long_opt);
730 len += strlen (opts[i].long_opt);
735 printf ("%s\n", opts[i].comment);
738 printf ("asranlib: supported targets: asxxxx\n");
744 process_options (int argc, char *argv[])
749 for (argp = argv + 1; *argp; ++argp)
751 if (!noopts && (*argp)[0] == '-')
755 if ((*argp)[1] == '-' && (*argp)[2] == '\0')
761 for (i = 0; i < NELEM (opts); ++i)
763 if (0 == strcmp (*argp, opts[i].short_opt) || 0 == strcmp (*argp, opts[i].long_opt))
765 if (NULL != opts[i].optfnc)
767 (*opts[i].optfnc) ();
786 main (int argc, char *argv[])
788 process_options (argc, argv);