X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=as%2Fasranlib%2Fasranlib.c;h=dde9f787a24beafdac75ff1f1607070418072b89;hb=1edc7c1316ae901d7dc6aeaae8117c6af4089c89;hp=01977beb8aa04b1d5de487c72511b34af5dd5280;hpb=1f5eb81a621295b45fa5ca82aaf94449abb27098;p=fw%2Fsdcc diff --git a/as/asranlib/asranlib.c b/as/asranlib/asranlib.c index 01977beb..dde9f787 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,19 +207,40 @@ 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; }; struct symbol_s *symlist, *lastsym; -off_t offset, first_member_offset; +unsigned int offset, first_member_offset; int add_symbol (const char *sym, void *param) @@ -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); + + 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) - ARHDR_LEN; + 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,36 @@ 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"; + struct stat stat_buf; + int can_stat; - if (NULL == mktemp (tmpfile) || NULL == (outfp = fopen (tmpfile, "wb"))) + /* TODO: create tmpfile in temporery directory (TMP, TMPDIR, /usr/tmp, /tmp) */ +#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 +611,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; } @@ -322,7 +649,6 @@ do_ranlib (const char *archive) fwrite (buf, 1, sizeof (buf), outfp); } - for (symp = symlist; symp; symp = symp->next) { fputs (symp->name, outfp); @@ -338,6 +664,17 @@ do_ranlib (const char *archive) putc (pad, outfp); fclose (outfp); + + if (0 != fstat(fileno(infp), &stat_buf)) + { + fprintf (stderr, "asranlib: can't stat %s: ", infp); + perror (NULL); + fclose (infp); + can_stat = 0; + } + else + can_stat = 1; + fclose (infp); if (0 != remove (archive)) @@ -350,11 +687,21 @@ do_ranlib (const char *archive) fprintf (stderr, "asranlib: can't rename %s to %s: ", tmpfile, archive); perror (NULL); } + else if (!can_stat || 0 != chmod (archive, stat_buf.st_mode)) + { + fprintf (stderr, "asranlib: can't chmod %s: ", archive); + perror (NULL); + } } else fclose (infp); } +void +do_verbose (void) +{ + verbose = 1; +} void print_version (void) @@ -363,80 +710,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) + { + if (*optp == opts[i].short_opt) + { + if (NULL != opts[i].optfnc) + { + (*opts[i].optfnc) (); + break; + } + } + } + if (i >= NELEM (opts)) { - (*opts[i].optfnc) (); - continue; + 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; }