X-Git-Url: https://git.gag.com/?a=blobdiff_plain;ds=sidebyside;f=as%2Fasranlib%2Fasranlib.c;h=69876283d61fc67882827adb622ebaf7e1a8a950;hb=3ad2f4c4dfafbcec6fcf6f76165d0dd714e46393;hp=e5449cfdf7490cb8c2e68b4b68b2169d6f57e3ce;hpb=0781937e2f57dec5475bf968ee54716ed00d6f92;p=fw%2Fsdcc
diff --git a/as/asranlib/asranlib.c b/as/asranlib/asranlib.c
index e5449cfd..69876283 100644
--- a/as/asranlib/asranlib.c
+++ b/as/asranlib/asranlib.c
@@ -5,7 +5,7 @@
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
+Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+along with this program. If not, see . */
#include
#include
@@ -27,12 +26,17 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifdef _WIN32
#include
-#define mktemp _mktemp
+#else
+#include
#endif
#define NELEM(x) (sizeof (x) / sizeof (*x))
+static int verbose = 0;
+static int list = 0;
+static int print_index = 0;
+
int
is_ar (FILE * libfp)
{
@@ -45,17 +49,139 @@ is_ar (FILE * libfp)
return ret;
}
-static struct ar_hdr *
-ar_get_header (struct ar_hdr *hdr, FILE * libfp)
+static char *sym_tab;
+static int sym_tab_size;
+
+char *
+get_member_name (char *name, size_t *p_size, int allocate, FILE * libfp)
+{
+ *p_size = 0;
+
+ if (0 == memcmp (name, "#1/", 3))
+ {
+ char *p;
+ size_t len = strtoul (&name [3], &p, 10);
+ if (p > &name [3])
+ {
+ /* BSD appends real file name to the file header */
+ if (p_size != NULL)
+ *p_size = len;
+
+ if (allocate)
+ {
+ char *n = (char *) malloc (len);
+ if (fread (n, 1, len, libfp) != len)
+ {
+ /* not an ar archive or broken ar archive */
+ return NULL;
+ }
+ else
+ return n;
+ }
+ else
+ {
+ /* just advance the file pointer */
+ fseek (libfp, len, SEEK_CUR);
+ return NULL;
+ }
+ }
+ else
+ {
+ /* not an ar archive or broken ar archive */
+ return NULL;
+ }
+ }
+ else if (allocate)
+ {
+ if (name[0] == '/')
+ {
+ if (NULL != sym_tab)
+ {
+ char *p;
+
+ int name_offset = strtol (++name, &p, 0);
+ if (p != name && name_offset < sym_tab_size)
+ {
+ int len = p - name + 1;
+ while (len < AR_NAME_LEN && name[len++] == ' ')
+ ;
+ if (len == AR_NAME_LEN)
+ {
+ char *n;
+
+ /* long name: get it from the symbol table */
+ name = &sym_tab[name_offset];
+ for (p = name; *p != '/' && *p != '\n'; ++p)
+ assert (p < &sym_tab[sym_tab_size]);
+
+ if (p[0] != '/' || p[1] != '\n')
+ while (*++p != '\n')
+ assert (p < &sym_tab[sym_tab_size]);
+
+ n = (char *) malloc (p - name + 1);
+ memcpy (n, name, p - name);
+ n[p - name] = '\0';
+ return n;
+ }
+ }
+ }
+ }
+ else
+ {
+ char *p = strrchr (name, '/');
+
+ if (NULL != p)
+ {
+ int len = p - name;
+ while (name[++len] == ' ')
+ ;
+ if (len == AR_NAME_LEN)
+ {
+ char *n = (char *) malloc (p - name + 1);
+ memcpy (n, name, p - name);
+ n[p - name] = '\0';
+ return n;
+ }
+ }
+ else
+ {
+ /* BSD formed member name:
+ trim trailing spaces */
+ char *n;
+
+ p = name + AR_NAME_LEN;
+ while (*--p == ' ' && p >= name)
+ ;
+ ++p;
+ n = (char *) malloc (p - name + 1);
+ memcpy (n, name, p - name);
+ n[p - name] = '\0';
+ return n;
+ }
+ }
+
+ /* bad formed member name:
+ just return it */
+
+ return strdup (name);
+ }
+ else
+ return NULL;
+}
+
+size_t
+ar_get_header (struct ar_hdr *hdr, FILE * libfp, char **p_obj_name)
{
char header[ARHDR_LEN];
char buf[AR_DATE_LEN + 1];
+ char *obj_name;
+ size_t size;
- if (fread (header, 1, sizeof (header), libfp) != sizeof (header) ||
- memcmp (header + AR_FMAG_OFFSET, ARFMAG, AR_FMAG_LEN) != 0)
+ if (fread (header, 1, sizeof (header), libfp) != sizeof (header)
+ || memcmp (header + AR_FMAG_OFFSET, ARFMAG, AR_FMAG_LEN) != 0)
{
/* not an ar archive */
- return NULL;
+ return 0;
}
memcpy (hdr->ar_name, &header[AR_NAME_OFFSET], AR_NAME_LEN);
@@ -81,14 +207,35 @@ ar_get_header (struct ar_hdr *hdr, FILE * libfp)
buf[AR_SIZE_LEN] = '\0';
hdr->ar_size = strtol (buf, NULL, 0);
- return hdr;
+ if (NULL == (obj_name = get_member_name (hdr->ar_name, &size, p_obj_name != NULL, libfp)) && p_obj_name != NULL)
+ {
+ /* Malformed archive */
+ return 0;
+ }
+
+ if (p_obj_name != NULL)
+ *p_obj_name = obj_name;
+
+ /* treat BSD appended real file name as a part of the header */
+ hdr->ar_size -= size;
+
+ return size + ARHDR_LEN;
}
+static char *
+get_member_name_by_offset (FILE * fp, long offset)
+{
+ struct ar_hdr hdr;
+ char *name;
+
+ fseek (fp, offset, SEEK_SET);
+ return (ar_get_header (&hdr, fp, &name) != 0) ? name : NULL;
+}
struct symbol_s
{
const char *name;
- off_t offset;
+ size_t offset;
struct symbol_s *next;
};
@@ -103,6 +250,9 @@ add_symbol (const char *sym, void *param)
if ((s = (struct symbol_s *) malloc (sizeof (struct symbol_s))) == NULL)
return 0;
+ if (verbose)
+ printf ("%s\n", sym);
+
s->name = strdup (sym);
s->offset = offset - first_member_offset;
s->next = NULL;
@@ -120,7 +270,6 @@ add_symbol (const char *sym, void *param)
return 0;
}
-
int
is_rel (FILE * libfp)
{
@@ -212,56 +361,207 @@ enum_symbols (FILE * fp, long size, int (*func) (const char *sym, void *param),
return 0;
}
+static int
+process_symbol_table (struct ar_hdr *hdr, FILE *fp)
+{
+ long pos = ftell (fp);
+
+ if (print_index)
+ {
+ char *buf, *po, *ps;
+ int i;
+ long nsym;
+
+ printf ("Archive index:\n");
+
+ buf = (char *) malloc (hdr->ar_size);
+
+ if (fread (buf, 1, hdr->ar_size, fp) != hdr->ar_size)
+ {
+ free (buf);
+ return 0;
+ }
+
+ nsym = sgetl (buf);
+
+ po = buf + 4;
+ ps = po + nsym * 4;
+
+ for (i = 0; i < nsym; ++i)
+ {
+ char *obj;
+
+ offset = sgetl (po);
+ po += 4;
+
+ if (NULL == (obj = get_member_name_by_offset (fp, offset))) /* member name */
+ return 0;
+
+ printf ("%s in %s", ps, obj);
+ if (verbose)
+ printf (" at 0x%04x\n", offset);
+ else
+ putchar ('\n');
+ free (obj);
+
+ ps += strlen(ps) + 1;
+
+ }
+ free (buf);
+
+ fseek (fp, pos, SEEK_SET);
+
+ putchar ('\n');
+ }
+
+ /* skip the symbol table */
+ fseek (fp, pos + hdr->ar_size + (hdr->ar_size & 1), SEEK_SET);
+
+ return 1;
+}
+
+static int
+process_bsd_symbol_table (struct ar_hdr *hdr, FILE *fp)
+{
+ long pos = ftell (fp);
+
+ if (print_index)
+ {
+ char *buf, *po, *ps;
+ int i;
+ long tablesize;
+ long nsym;
+
+ printf ("Archive index:\n");
+
+ buf = (char *) malloc (hdr->ar_size);
+
+ if (fread (buf, 1, hdr->ar_size, fp) != hdr->ar_size)
+ {
+ free (buf);
+ return 0;
+ }
+
+ tablesize = sgetl (buf);
+ nsym = tablesize / 8;
+
+ po = buf + 4;
+
+ ps = po + tablesize + 4;
+
+ for (i = 0; i < nsym; ++i)
+ {
+ char *obj;
+ long sym;
+
+ sym = sgetl (po);
+ po += 4;
+ offset = sgetl (po);
+ po += 4;
+
+ printf ("%s in ", ps + sym);
+
+ if (NULL == (obj = get_member_name_by_offset (fp, offset))) /* member name */
+ return 0;
+
+ printf ("%s\n", obj);
+ free (obj);
+ }
+ free (buf);
+ putchar ('\n');
+ }
+
+ /* skip the symbol table */
+ fseek (fp, pos + hdr->ar_size + (hdr->ar_size & 1), SEEK_SET);
+
+ return 1;
+}
+
int
get_symbols (FILE * fp, const char *archive)
{
struct ar_hdr hdr;
+ size_t hdr_len;
+ char *name;
- if (!is_ar (fp) || !ar_get_header (&hdr, fp))
+ if (!is_ar (fp) || !(hdr_len = ar_get_header (&hdr, fp, &name)))
{
- fprintf (stderr, "asranlib: %s: File format not recognized\n", archive);
- exit (1);
+ free (name);
+
+ return 0;
}
- if (AR_IS_SYMBOL_TABLE (hdr))
+ if (AR_IS_SYMBOL_TABLE (name))
{
- /* skip the symbol table */
- fseek (fp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
+ free (name);
+
+ if (!process_symbol_table (&hdr, fp))
+ return 0;
+
+ if (feof (fp))
+ return 1;
+ else if (!(hdr_len = ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL)))
+ return 0;
}
+ else if (AR_IS_BSD_SYMBOL_TABLE (name))
+ {
+ free (name);
- first_member_offset = ftell (fp) - ARHDR_LEN;
+ if (!process_bsd_symbol_table (&hdr, fp))
+ return 0;
+
+ if (feof (fp))
+ return 1;
+ else if (!(hdr_len = ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL)))
+ return 0;
+ }
+ else if (!verbose && !list)
+ free (name);
+
+ first_member_offset = ftell (fp) - hdr_len;
/* walk trough all archive members */
do
{
if (is_rel (fp))
{
- long mdule_offset = ftell (fp);
+ if (verbose || list)
+ {
+ printf ("%s%s\n", name, verbose ? ":" : "");
+ free (name);
+ }
- offset = mdule_offset - ARHDR_LEN;
+ if (!list)
+ {
+ long mdule_offset = ftell (fp);
- enum_symbols (fp, hdr.ar_size, add_symbol, NULL);
+ offset = mdule_offset - hdr_len;
- fseek (fp, mdule_offset + hdr.ar_size, SEEK_SET);
+ enum_symbols (fp, hdr.ar_size, add_symbol, NULL);
- if (hdr.ar_size & 1)
- {
- int c = getc (fp);
- assert (c == EOF || c == '\n');
+ fseek (fp, mdule_offset + hdr.ar_size + (hdr.ar_size & 1), SEEK_SET);
}
+
+ if (verbose)
+ putchar ('\n');
}
else
{
+ if (verbose || list)
+ {
+ fprintf (stderr, "asranlib: %s: File format not recognized\n", name);
+ free (name);
+ }
+
/* skip if the member is not a .REL format */
fseek (fp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
}
}
- while (ar_get_header (&hdr, fp));
+ while ((hdr_len = ar_get_header (&hdr, fp, (verbose || list) ? &name : NULL)));
- return 1;
+ return feof (fp) ? 1 : 0;
}
-
void
do_ranlib (const char *archive)
{
@@ -274,18 +574,33 @@ do_ranlib (const char *archive)
exit (1);
}
- if (get_symbols (infp, archive))
+ if (!get_symbols (infp, archive))
+ {
+ fprintf (stderr, "asranlib: %s: Malformed archive\n", archive);
+ fclose (infp);
+ exit (1);
+ }
+ else if (!list && !print_index)
{
- FILE *outfp = NULL;
+ FILE *outfp;
struct symbol_s *symp;
char buf[4];
- int str_length = 0;
- int pad = 0;
+ int str_length;
+ int pad;
int nsym;
int symtab_size;
char tmpfile[] = "arXXXXXX";
- if (NULL == mktemp (tmpfile) || NULL == (outfp = fopen (tmpfile, "wb")))
+#ifdef _WIN32
+ if (NULL == _mktemp (tmpfile) || NULL == (outfp = fopen (tmpfile, "wb")))
+ {
+ fclose (infp);
+ fprintf (stderr, "asranlib: %s: ", tmpfile);
+ perror (NULL);
+ exit (1);
+ }
+#else
+ if ((pad = mkstemp (tmpfile)) < 0)
{
fclose (infp);
fprintf (stderr, "asranlib: %s: ", tmpfile);
@@ -293,8 +608,17 @@ do_ranlib (const char *archive)
exit (1);
}
+ if (NULL == (outfp = fdopen (pad, "wb")))
+ {
+ close (pad);
+ fclose (infp);
+ perror ("asranlib");
+ exit (1);
+ }
+#endif
+
/* calculate the size of symbol table */
- for (nsym = 0, symp = symlist; symp; ++nsym, symp = symp->next)
+ for (str_length = 0, nsym = 0, symp = symlist; symp; ++nsym, symp = symp->next)
{
str_length += strlen (symp->name) + 1;
}
@@ -355,6 +679,11 @@ do_ranlib (const char *archive)
fclose (infp);
}
+void
+do_verbose (void)
+{
+ verbose = 1;
+}
void
print_version (void)
@@ -363,80 +692,147 @@ print_version (void)
exit (0);
}
-
void
-usage (void)
+do_list (void)
{
- printf ("Usage: asranlib [options] archive\n"
- " Generate an index to speed access to archives\n"
- " The options are:\n"
- " -h --help Print this help message\n"
- " -V --version Print version information\n"
- "asranlib: supported targets: asxxxx\n");
+ list = 1;
+}
- exit (1);
+void
+print_armap (void)
+{
+ print_index = 1;
}
+void usage (void);
struct opt_s
{
- const char *opt;
+ char short_opt;
+ const char *long_opt;
void (*optfnc) (void);
+ const char *comment;
}
opts[] =
{
- { "-v", &print_version, },
- { "-V", &print_version, },
- { "--version", &print_version, },
- { "-h", &usage, },
- { "--help", &usage, },
+ { 'v', "verbose", &do_verbose, "Be more verbose about the operation" },
+ { 'V', "version", &print_version, "Print this help message" },
+ { 'h', "help", &usage, "Print version information" },
+ { 't', "list", &do_list, "List the contents of an archive" },
+ { 's', "print-armap", &print_armap, "Print the archive index" },
};
-
void
-process_options (int argc, char *argv[])
+usage (void)
+{
+ int i;
+
+ printf ("Usage: asranlib [options] archive\n"
+ " Generate an index to speed access to archives\n"
+ " The options are:\n");
+
+ for (i = 0; i < NELEM (opts); ++i)
+ {
+ int len = 5;
+ if ('\0' != opts[i].short_opt)
+ printf (" -%c ", opts[i].short_opt);
+ else
+ printf (" ");
+
+ if (NULL != opts[i].long_opt)
+ {
+ printf ("--%s ", opts[i].long_opt);
+ len += strlen (opts[i].long_opt);
+ }
+
+ while (len++ < 30)
+ putchar (' ');
+ printf ("%s\n", opts[i].comment);
+ }
+
+ printf ("asranlib: supported targets: asxxxx\n");
+
+ exit (1);
+}
+
+int
+main (int argc, char *argv[])
{
char **argp;
int noopts = 0;
int narch = 0;
+
for (argp = argv + 1; *argp; ++argp)
{
if (!noopts && (*argp)[0] == '-')
{
int i;
- if ((*argp)[1] == '-' && (*argp)[2] == '\0')
+ if ((*argp)[1] == '-')
{
- noopts = 1;
- continue;
+ if ((*argp)[2] == '\0')
+ {
+ /* end of options */
+ noopts = 1;
+ continue;
+ }
+ else
+ {
+ /* long option */
+ for (i = 0; i < NELEM (opts); ++i)
+ {
+ if (0 == strcmp (&(*argp)[2], opts[i].long_opt))
+ {
+ if (NULL != opts[i].optfnc)
+ {
+ (*opts[i].optfnc) ();
+ break;
+ }
+ }
+ }
+ if (i >= NELEM (opts))
+ {
+ fprintf (stderr, "asranlib: unrecognized option `%s'\n", *argp);
+ usage ();
+ }
+ }
}
-
- for (i = 0; i < NELEM (opts); ++i)
+ else
{
- if (0 == strcmp (*argp, opts[i].opt))
+ char *optp;
+
+ /* short option */
+ for (optp = &(*argp)[1]; *optp != '\0'; ++optp)
{
- if (NULL != opts[i].optfnc)
+ for (i = 0; i < NELEM (opts); ++i)
{
- (*opts[i].optfnc) ();
- continue;
+ if (*optp == opts[i].short_opt)
+ {
+ if (NULL != opts[i].optfnc)
+ {
+ (*opts[i].optfnc) ();
+ break;
+ }
+ }
+ }
+ if (i >= NELEM (opts))
+ {
+ fprintf (stderr, "asranlib: invalid option -- %c\n", *optp);
+ usage ();
}
}
}
}
-
- do_ranlib (*argp);
- ++narch;
+ else
+ {
+ /* not an option */
+ do_ranlib (*argp);
+ ++narch;
+ }
}
if (!narch)
usage ();
-}
-
-
-int
-main (int argc, char *argv[])
-{
- process_options (argc, argv);
return 0;
}