Reorder routines to eliminate static prototypes.
authorjbj <devnull@localhost>
Tue, 1 Oct 2002 17:02:02 +0000 (17:02 +0000)
committerjbj <devnull@localhost>
Tue, 1 Oct 2002 17:02:02 +0000 (17:02 +0000)
CVS patchset: 5742
CVS date: 2002/10/01 17:02:02

file/.lclintrc
file/apprentice.c
file/ascmagic.c
file/compress.c
file/file.c
file/is_tar.c
file/readelf.c
file/softmagic.c

index 172c48c..d1c90c9 100644 (file)
@@ -21,7 +21,7 @@
 -modunconnomods                # 12 ctype.h
 -mustmod               # 1 mman.h
 -noparams              # 3 getopt_long
-#-nullderef            # 4
+-nullderef             # 4
 -nullpass              # 27
 -nullptrarith          # 1
 -redef                 # 4
index d830f98..0fc3a91 100644 (file)
@@ -76,291 +76,230 @@ static int maxmagic = 0;
 /*@unchecked@*/
 struct mlist mlist;
 
-
-static int getvalue(struct magic *m, /*@out@*/ char **p)
-       /*@globals fileSystem @*/
-       /*@modifies m, *p, fileSystem @*/;
-static int hextoint(int c)
-       /*@*/;
-static char *getstr(/*@returned@*/ char *s, char *p, int plen,
-               /*@out@*/ int * slen)
-       /*@globals fileSystem @*/
-       /*@modifies *p, *slen, fileSystem @*/;
-static int parse(/*@out@*/ struct magic **magicp,
-               /*@out@*/ uint32_t *nmagicp, char *l, int action)
-       /*@globals maxmagic, fileSystem @*/
-       /*@modifies *magicp, *nmagicp, maxmagic, fileSystem @*/;
-static void eatsize(/*@out@*/ char **p)
-       /*@modifies *p @*/;
-static int apprentice_1(const char *fn, int action)
-       /*@globals lineno, mlist, fileSystem, internalState @*/
-       /*@modifies lineno, mlist, fileSystem, internalState @*/;
-static int apprentice_file(/*@out@*/ struct magic **magicp,
-               /*@out@*/ uint32_t *nmagicp, const char *fn, int action)
-       /*@globals lineno, maxmagic, fileSystem @*/
-       /*@modifies *magicp, *nmagicp, lineno, maxmagic, fileSystem @*/;
-static void byteswap(struct magic *m, uint32_t nmagic)
-       /*@modifies m @*/;
-static void bs1(struct magic *m)
-       /*@modifies m @*/;
-static uint16_t swap2(uint16_t sv)
-       /*@*/;
-static uint32_t swap4(uint32_t sv)
-       /*@*/;
-/*@null@*/
-static char *mkdbname(const char *fn)
-       /*@globals fileSystem @*/
-       /*@modifies fileSystem @*/;
-static int apprentice_map(/*@out@*/ struct magic **magicp,
-               /*@out@*/ uint32_t *nmagicp, const char *fn, int action)
-       /*@globals fileSystem, internalState @*/
-       /*@modifies *magicp, *nmagicp, fileSystem, internalState @*/;
-static int apprentice_compile(/*@out@*/ struct magic **magicp,
-               /*@out@*/ uint32_t *nmagicp, const char *fn, int action)
-       /*@globals fileSystem, internalState @*/
-       /*@modifies fileSystem, internalState @*/;
-
-#ifdef COMPILE_ONLY
-const char *magicfile;
-char *progname;
-int lineno;
-
-int main(int argc, char *argv[])
-       /*@*/;
-
-int
-main(int argc, char *argv[])
+/*
+ * extend the sign bit if the comparison is to be signed
+ */
+uint32_t
+signextend(struct magic *m, uint32_t v)
 {
-       int ret;
-
-       if ((progname = strrchr(argv[0], '/')) != NULL)
-               progname++;
-       else
-               progname = argv[0];
-
-       if (argc != 2) {
-               (void)fprintf(stderr, "usage: %s file\n", progname);
-               exit(1);
-       }
-       magicfile = argv[1];
-
-       exit(apprentice(magicfile, COMPILE));
+       if (!(m->flag & UNSIGNED))
+               switch(m->type) {
+               /*
+                * Do not remove the casts below.  They are
+                * vital.  When later compared with the data,
+                * the sign extension must have happened.
+                */
+               case BYTE:
+                       v = (char) v;
+                       break;
+               case SHORT:
+               case BESHORT:
+               case LESHORT:
+                       v = (short) v;
+                       break;
+               case DATE:
+               case BEDATE:
+               case LEDATE:
+               case LDATE:
+               case BELDATE:
+               case LELDATE:
+               case LONG:
+               case BELONG:
+               case LELONG:
+                       v = (int32_t) v;
+                       break;
+               case STRING:
+               case PSTRING:
+                       break;
+               case REGEX:
+                       break;
+               default:
+                       magwarn("can't happen: m->type=%d\n", m->type);
+                       return -1;
+               }
+       return v;
 }
-#endif /* COMPILE_ONLY */
-
 
 /*
- * Handle one file.
+ * eatsize(): Eat the size spec from a number [eg. 10UL]
  */
-static int
-apprentice_1(const char *fn, int action)
+static void
+eatsize(/*@out@*/ char **p)
+       /*@modifies *p @*/
 {
-/*@-shadow@*/
-       struct magic *magic = NULL;
-       uint32_t nmagic = 0;
-/*@=shadow@*/
-       struct mlist *ml;
-       int rv = -1;
+       char *l = *p;
 
-       if (action == COMPILE) {
-               rv = apprentice_file(&magic, &nmagic, fn, action);
-               if (rv == 0)
-                       return apprentice_compile(&magic, &nmagic, fn, action);
-               else
-                       return rv;
-       }
-#ifndef COMPILE_ONLY
-       if ((rv = apprentice_map(&magic, &nmagic, fn, action)) != 0)
-               (void)fprintf(stderr, "%s: Using regular magic file `%s'\n",
-                   progname, fn);
-               
-       if (rv != 0)
-               rv = apprentice_file(&magic, &nmagic, fn, action);
+       if (LOWCASE(*l) == 'u') 
+               l++;
 
-       if (rv != 0)
-               return rv;
-            
-       if ((ml = malloc(sizeof(*ml))) == NULL) {
-               (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
-                   strerror(errno));
-               if (action == CHECK)
-                       return -1;
+       switch (LOWCASE(*l)) {
+       case 'l':    /* long */
+       case 's':    /* short */
+       case 'h':    /* short */
+       case 'b':    /* char/byte */
+       case 'c':    /* char/byte */
+               l++;
+               /*@fallthrough@*/
+       default:
+               break;
        }
 
-       if (magic == NULL || nmagic == 0)
-               return rv;
-
-       ml->magic = magic;
-       ml->nmagic = nmagic;
-
-       mlist.prev->next = ml;
-       ml->prev = mlist.prev;
-/*@-immediatetrans@*/
-       ml->next = &mlist;
-/*@=immediatetrans@*/
-/*@-kepttrans@*/
-       mlist.prev = ml;
-/*@=kepttrans@*/
-
-/*@-compdef@*/
-       return rv;
-/*@=compdef@*/
-#endif /* COMPILE_ONLY */
+       *p = l;
 }
 
-
-/* const char *fn: list of magic files */
-int
-apprentice(const char *fn, int action)
+/* Single hex char to int; -1 if not a hex char. */
+static int
+hextoint(int c)
+       /*@*/
 {
-       char *p, *mfn;
-       int file_err, errs = -1;
-
-/*@-immediatetrans@*/
-       mlist.next = &mlist;
-       mlist.prev = &mlist;
-/*@=immediatetrans@*/
-       mfn = malloc(strlen(fn)+1);
-       if (mfn == NULL) {
-               (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
-                   strerror(errno));
-/*@-compmempass@*/
-               if (action == CHECK)
-                       return -1;
-               else
-                       exit(EXIT_FAILURE);
-/*@=compmempass@*/
-       }
-       fn = strcpy(mfn, fn);
-  
-/*@-branchstate@*/
-       while (fn != NULL) {
-               p = strchr(fn, PATHSEP);
-               if (p != NULL)
-                       *p++ = '\0';
-               file_err = apprentice_1(fn, action);
-               if (file_err > errs)
-                       errs = file_err;
-               fn = p;
-       }
-/*@=branchstate@*/
-       if (errs == -1)
-               (void) fprintf(stderr, "%s: couldn't find any magic files!\n",
-                   progname);
-       if (action == CHECK && errs)
-               exit(EXIT_FAILURE);
-
-       free(mfn);
-/*@-compdef -compmempass@*/
-       return errs;
-/*@=compdef =compmempass@*/
+       if (!isascii((unsigned char) c))
+               return -1;
+       if (isdigit((unsigned char) c))
+               return c - '0';
+       if ((c >= 'a')&&(c <= 'f'))
+               return c + 10 - 'a';
+       if (( c>= 'A')&&(c <= 'F'))
+               return c + 10 - 'A';
+       return -1;
 }
 
 /*
- * parse from a file
- * const char *fn: name of magic file
+ * Convert a string containing C character escapes.  Stop at an unescaped
+ * space or tab.
+ * Copy the converted version to "p", returning its length in *slen.
+ * Return updated scan pointer as function result.
  */
-static int
-apprentice_file(struct magic **magicp, uint32_t *nmagicp, const char *fn,
-               int action)
+static char *
+getstr(/*@returned@*/ char *s, char *p, int plen, /*@out@*/ int *slen)
+       /*@globals fileSystem @*/
+       /*@modifies *p, *slen, fileSystem @*/
 {
-       static const char hdr[] =
-               "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
-       FILE *f;
-       char line[BUFSIZ+1];
-       int errs = 0;
+       char    *origs = s, *origp = p;
+       char    *pmax = p + plen - 1;
+       int     c;
+       int     val;
 
-       f = fopen(fn, "r");
-       if (f == NULL) {
-               if (errno != ENOENT)
-                       (void) fprintf(stderr,
-                           "%s: can't read magic file %s (%s)\n", 
-                           progname, fn, strerror(errno));
-               return -1;
-       }
+       while ((c = *s++) != '\0') {
+               if (isspace((unsigned char) c))
+                       break;
+               if (p >= pmax) {
+                       fprintf(stderr, "String too long: %s\n", origs);
+                       break;
+               }
+               if(c == '\\') {
+                       switch(c = *s++) {
 
-        maxmagic = MAXMAGIS;
-       *magicp = (struct magic *) calloc(sizeof(struct magic), maxmagic);
-       if (*magicp == NULL) {
-               (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
-                   strerror(errno));
-               if (action == CHECK)
-                       return -1;
-       }
+                       case '\0':
+                               goto out;
 
-       /* parse it */
-       if (action == CHECK)    /* print silly verbose header for USG compat. */
-               (void) printf("%s\n", hdr);
+                       default:
+                               *p++ = (char) c;
+                               /*@switchbreak@*/ break;
 
-       for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
-               if (line[0]=='#')       /* comment, do not parse */
-                       continue;
-               if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
-                       continue;
-               line[strlen(line)-1] = '\0'; /* delete newline */
-               if (parse(magicp, nmagicp, line, action) != 0)
-                       errs = 1;
-       }
+                       case 'n':
+                               *p++ = '\n';
+                               /*@switchbreak@*/ break;
 
-       (void) fclose(f);
-       if (errs) {
-               free(*magicp);
-               *magicp = NULL;
-               *nmagicp = 0;
+                       case 'r':
+                               *p++ = '\r';
+                               /*@switchbreak@*/ break;
+
+                       case 'b':
+                               *p++ = '\b';
+                               /*@switchbreak@*/ break;
+
+                       case 't':
+                               *p++ = '\t';
+                               /*@switchbreak@*/ break;
+
+                       case 'f':
+                               *p++ = '\f';
+                               /*@switchbreak@*/ break;
+
+                       case 'v':
+                               *p++ = '\v';
+                               /*@switchbreak@*/ break;
+
+                       /* \ and up to 3 octal digits */
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                               val = c - '0';
+                               c = *s++;  /* try for 2 */
+                               if(c >= '0' && c <= '7') {
+                                       val = (val<<3) | (c - '0');
+                                       c = *s++;  /* try for 3 */
+                                       if(c >= '0' && c <= '7')
+                                               val = (val<<3) | (c-'0');
+                                       else
+                                               --s;
+                               }
+                               else
+                                       --s;
+                               *p++ = (char)val;
+                               /*@switchbreak@*/ break;
+
+                       /* \x and up to 2 hex digits */
+                       case 'x':
+                               val = 'x';      /* Default if no digits */
+                               c = hextoint(*s++);     /* Get next char */
+                               if (c >= 0) {
+                                       val = c;
+                                       c = hextoint(*s++);
+                                       if (c >= 0)
+                                               val = (val << 4) + c;
+                                       else
+                                               --s;
+                               } else
+                                       --s;
+                               *p++ = (char)val;
+                               /*@switchbreak@*/ break;
+                       }
+               } else
+                       *p++ = (char)c;
        }
-       return errs;
+out:
+       *p = '\0';
+       *slen = p - origp;
+       return s;
 }
 
-/*
- * extend the sign bit if the comparison is to be signed
+/* 
+ * Read a numeric value from a pointer, into the value union of a magic 
+ * pointer, according to the magic type.  Update the string pointer to point 
+ * just after the number read.  Return 0 for success, non-zero for failure.
  */
-uint32_t
-signextend(struct magic *m, uint32_t v)
+static int
+getvalue(struct magic *m, /*@out@*/ char **p)
+       /*@globals fileSystem @*/
+       /*@modifies m, *p, fileSystem @*/
 {
-       if (!(m->flag & UNSIGNED))
-               switch(m->type) {
-               /*
-                * Do not remove the casts below.  They are
-                * vital.  When later compared with the data,
-                * the sign extension must have happened.
-                */
-               case BYTE:
-                       v = (char) v;
-                       break;
-               case SHORT:
-               case BESHORT:
-               case LESHORT:
-                       v = (short) v;
-                       break;
-               case DATE:
-               case BEDATE:
-               case LEDATE:
-               case LDATE:
-               case BELDATE:
-               case LELDATE:
-               case LONG:
-               case BELONG:
-               case LELONG:
-                       v = (int32_t) v;
-                       break;
-               case STRING:
-               case PSTRING:
-                       break;
-               case REGEX:
-                       break;
-               default:
-                       magwarn("can't happen: m->type=%d\n",
-                               m->type);
-                       return -1;
+       int slen;
+
+       if (m->type == STRING || m->type == PSTRING || m->type == REGEX) {
+               *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
+               m->vallen = slen;
+       } else
+               if (m->reln != 'x') {
+                       m->value.l = signextend(m, strtoul(*p, p, 0));
+                       eatsize(p);
                }
-       return v;
+       return 0;
 }
 
 /*
  * parse one line from magic file, put into magic[index++] if valid
  */
 static int
-parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action)
+parse(/*@out@*/ struct magic **magicp, /*@out@*/ uint32_t *nmagicp,
+               char *l, int action)
+       /*@globals maxmagic, fileSystem @*/
+       /*@modifies *magicp, *nmagicp, maxmagic, fileSystem @*/
 {
        int i = 0;
        struct magic *m;
@@ -640,235 +579,93 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action)
                                case CHAR_IGNORE_LOWERCASE:
                                        m->mask |= STRING_IGNORE_LOWERCASE;
                                        /*@switchbreak@*/ break;
-                               case CHAR_COMPACT_BLANK:
-                                       m->mask |= STRING_COMPACT_BLANK;
-                                       /*@switchbreak@*/ break;
-                               case CHAR_COMPACT_OPTIONAL_BLANK:
-                                       m->mask |=
-                                           STRING_COMPACT_OPTIONAL_BLANK;
-                                       /*@switchbreak@*/ break;
-                               default:
-                                       magwarn("string extension %c invalid",
-                                           *l);
-                                       return -1;
-                               }
-                       }
-               }
-               break;
-       }
-       /* We used to set mask to all 1's here, instead let's just not do anything 
-          if mask = 0 (unless you have a better idea) */
-       EATAB;
-  
-       switch (*l) {
-       case '>':
-       case '<':
-       /* Old-style anding: "0 byte &0x80 dynamically linked" */
-       case '&':
-       case '^':
-       case '=':
-               m->reln = *l;
-               ++l;
-               if (*l == '=') {
-                  /* HP compat: ignore &= etc. */
-                  ++l;
-               }
-               break;
-       case '!':
-               if (m->type != STRING && m->type != PSTRING) {
-                       m->reln = *l;
-                       ++l;
-                       break;
-               }
-               /*@fallthrough@*/
-       default:
-               if (*l == 'x' && isascii((unsigned char)l[1]) && 
-                   isspace((unsigned char)l[1])) {
-                       m->reln = *l;
-                       ++l;
-                       goto GetDesc;   /* Bill The Cat */
-               }
-               m->reln = '=';
-               break;
-       }
-       EATAB;
-  
-       if (getvalue(m, &l))
-               return -1;
-       /*
-        * TODO finish this macro and start using it!
-        * #define offsetcheck {if (offset > HOWMANY-1) 
-        *      magwarn("offset too big"); }
-        */
-
-       /*
-        * now get last part - the description
-        */
-GetDesc:
-       EATAB;
-       if (l[0] == '\b') {
-               ++l;
-               m->nospflag = 1;
-       } else if ((l[0] == '\\') && (l[1] == 'b')) {
-               ++l;
-               ++l;
-               m->nospflag = 1;
-       } else
-               m->nospflag = 0;
-       while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
-               {};
-
-#ifndef COMPILE_ONLY
-       if (action == CHECK) {
-               mdump(m);
-       }
-#endif
-       ++(*nmagicp);           /* make room for next */
-       return 0;
-}
-
-/* 
- * Read a numeric value from a pointer, into the value union of a magic 
- * pointer, according to the magic type.  Update the string pointer to point 
- * just after the number read.  Return 0 for success, non-zero for failure.
- */
-static int
-getvalue(struct magic *m, char **p)
-{
-       int slen;
-
-       if (m->type == STRING || m->type == PSTRING || m->type == REGEX) {
-               *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
-               m->vallen = slen;
-       } else
-               if (m->reln != 'x') {
-                       m->value.l = signextend(m, strtoul(*p, p, 0));
-                       eatsize(p);
-               }
-       return 0;
-}
-
-/*
- * Convert a string containing C character escapes.  Stop at an unescaped
- * space or tab.
- * Copy the converted version to "p", returning its length in *slen.
- * Return updated scan pointer as function result.
- */
-static char *
-getstr(char *s, char *p, int plen, int *slen)
-{
-       char    *origs = s, *origp = p;
-       char    *pmax = p + plen - 1;
-       int     c;
-       int     val;
-
-       while ((c = *s++) != '\0') {
-               if (isspace((unsigned char) c))
-                       break;
-               if (p >= pmax) {
-                       fprintf(stderr, "String too long: %s\n", origs);
-                       break;
-               }
-               if(c == '\\') {
-                       switch(c = *s++) {
-
-                       case '\0':
-                               goto out;
-
-                       default:
-                               *p++ = (char) c;
-                               /*@switchbreak@*/ break;
-
-                       case 'n':
-                               *p++ = '\n';
-                               /*@switchbreak@*/ break;
-
-                       case 'r':
-                               *p++ = '\r';
-                               /*@switchbreak@*/ break;
-
-                       case 'b':
-                               *p++ = '\b';
-                               /*@switchbreak@*/ break;
-
-                       case 't':
-                               *p++ = '\t';
-                               /*@switchbreak@*/ break;
-
-                       case 'f':
-                               *p++ = '\f';
-                               /*@switchbreak@*/ break;
-
-                       case 'v':
-                               *p++ = '\v';
-                               /*@switchbreak@*/ break;
-
-                       /* \ and up to 3 octal digits */
-                       case '0':
-                       case '1':
-                       case '2':
-                       case '3':
-                       case '4':
-                       case '5':
-                       case '6':
-                       case '7':
-                               val = c - '0';
-                               c = *s++;  /* try for 2 */
-                               if(c >= '0' && c <= '7') {
-                                       val = (val<<3) | (c - '0');
-                                       c = *s++;  /* try for 3 */
-                                       if(c >= '0' && c <= '7')
-                                               val = (val<<3) | (c-'0');
-                                       else
-                                               --s;
+                               case CHAR_COMPACT_BLANK:
+                                       m->mask |= STRING_COMPACT_BLANK;
+                                       /*@switchbreak@*/ break;
+                               case CHAR_COMPACT_OPTIONAL_BLANK:
+                                       m->mask |=
+                                           STRING_COMPACT_OPTIONAL_BLANK;
+                                       /*@switchbreak@*/ break;
+                               default:
+                                       magwarn("string extension %c invalid",
+                                           *l);
+                                       return -1;
                                }
-                               else
-                                       --s;
-                               *p++ = (char)val;
-                               /*@switchbreak@*/ break;
-
-                       /* \x and up to 2 hex digits */
-                       case 'x':
-                               val = 'x';      /* Default if no digits */
-                               c = hextoint(*s++);     /* Get next char */
-                               if (c >= 0) {
-                                       val = c;
-                                       c = hextoint(*s++);
-                                       if (c >= 0)
-                                               val = (val << 4) + c;
-                                       else
-                                               --s;
-                               } else
-                                       --s;
-                               *p++ = (char)val;
-                               /*@switchbreak@*/ break;
                        }
-               } else
-                       *p++ = (char)c;
+               }
+               break;
        }
-out:
-       *p = '\0';
-       *slen = p - origp;
-       return s;
-}
+       /* We used to set mask to all 1's here, instead let's just not do anything 
+          if mask = 0 (unless you have a better idea) */
+       EATAB;
+  
+       switch (*l) {
+       case '>':
+       case '<':
+       /* Old-style anding: "0 byte &0x80 dynamically linked" */
+       case '&':
+       case '^':
+       case '=':
+               m->reln = *l;
+               ++l;
+               if (*l == '=') {
+                  /* HP compat: ignore &= etc. */
+                  ++l;
+               }
+               break;
+       case '!':
+               if (m->type != STRING && m->type != PSTRING) {
+                       m->reln = *l;
+                       ++l;
+                       break;
+               }
+               /*@fallthrough@*/
+       default:
+               if (*l == 'x' && isascii((unsigned char)l[1]) && 
+                   isspace((unsigned char)l[1])) {
+                       m->reln = *l;
+                       ++l;
+                       goto GetDesc;   /* Bill The Cat */
+               }
+               m->reln = '=';
+               break;
+       }
+       EATAB;
+  
+       if (getvalue(m, &l))
+               return -1;
+       /*
+        * TODO finish this macro and start using it!
+        * #define offsetcheck {if (offset > HOWMANY-1) 
+        *      magwarn("offset too big"); }
+        */
 
+       /*
+        * now get last part - the description
+        */
+GetDesc:
+       EATAB;
+       if (l[0] == '\b') {
+               ++l;
+               m->nospflag = 1;
+       } else if ((l[0] == '\\') && (l[1] == 'b')) {
+               ++l;
+               ++l;
+               m->nospflag = 1;
+       } else
+               m->nospflag = 0;
+       while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
+               {};
 
-/* Single hex char to int; -1 if not a hex char. */
-static int
-hextoint(int c)
-{
-       if (!isascii((unsigned char) c))
-               return -1;
-       if (isdigit((unsigned char) c))
-               return c - '0';
-       if ((c >= 'a')&&(c <= 'f'))
-               return c + 10 - 'a';
-       if (( c>= 'A')&&(c <= 'F'))
-               return c + 10 - 'A';
-       return -1;
+#ifndef COMPILE_ONLY
+       if (action == CHECK) {
+               mdump(m);
+       }
+#endif
+       ++(*nmagicp);           /* make room for next */
+       return 0;
 }
 
-
 /*
  * Print a string containing C character escapes.
  */
@@ -926,37 +723,204 @@ showstr(FILE *fp, const char *s, int len)
 }
 
 /*
- * eatsize(): Eat the size spec from a number [eg. 10UL]
+ * swap a short
+ */
+static uint16_t
+swap2(uint16_t sv)
+       /*@*/
+{
+       uint16_t rv;
+       uint8_t *s = (uint8_t *) &sv; 
+       uint8_t *d = (uint8_t *) &rv; 
+       d[0] = s[1];
+       d[1] = s[0];
+       return rv;
+}
+
+/*
+ * swap an int
+ */
+static uint32_t
+swap4(uint32_t sv)
+       /*@*/
+{
+       uint32_t rv;
+       uint8_t *s = (uint8_t *) &sv; 
+       uint8_t *d = (uint8_t *) &rv; 
+       d[0] = s[3];
+       d[1] = s[2];
+       d[2] = s[1];
+       d[3] = s[0];
+       return rv;
+}
+
+/*
+ * byteswap a single magic entry
+ */
+static
+void bs1(struct magic *m)
+       /*@modifies m @*/
+{
+       m->cont_level = swap2(m->cont_level);
+       m->offset = swap4(m->offset);
+       m->in_offset = swap4(m->in_offset);
+       if (m->type != STRING)
+               m->value.l = swap4(m->value.l);
+       m->mask = swap4(m->mask);
+}
+
+/*
+ * Byteswap an mmap'ed file if needed
+ */
+static void
+byteswap(struct magic *m, uint32_t nmagic)
+       /*@modifies m @*/
+{
+       uint32_t i;
+       for (i = 0; i < nmagic; i++)
+               bs1(&m[i]);
+}
+
+/*
+ * make a dbname
+ */
+/*@null@*/
+static char *
+mkdbname(const char *fn)
+       /*@globals fileSystem @*/
+       /*@modifies fileSystem @*/
+{
+       static const char ext[] = ".mgc";
+       /*@only@*/
+       static char *buf = NULL;
+       size_t len = strlen(fn) + sizeof(ext) + 1;
+       if (buf == NULL)
+               buf = malloc(len);
+       else
+               buf = realloc(buf, len);
+       if (buf == NULL) {
+               (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
+                   strerror(errno));
+               return NULL;
+       }
+       (void)strcpy(buf, fn);
+       (void)strcat(buf, ext);
+       return buf;
+}
+
+/*
+ * parse from a file
+ * const char *fn: name of magic file
+ */
+static int
+apprentice_file(/*@out@*/ struct magic **magicp, /*@out@*/ uint32_t *nmagicp,
+               const char *fn, int action)
+       /*@globals lineno, maxmagic, fileSystem @*/
+       /*@modifies *magicp, *nmagicp, lineno, maxmagic, fileSystem @*/
+{
+       /*@observer@*/
+       static const char hdr[] =
+               "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
+       FILE *f;
+       char line[BUFSIZ+1];
+       int errs = 0;
+
+       f = fopen(fn, "r");
+       if (f == NULL) {
+               if (errno != ENOENT)
+                       (void) fprintf(stderr,
+                           "%s: can't read magic file %s (%s)\n", 
+                           progname, fn, strerror(errno));
+               return -1;
+       }
+
+        maxmagic = MAXMAGIS;
+       *magicp = (struct magic *) calloc(sizeof(struct magic), maxmagic);
+       if (*magicp == NULL) {
+               (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
+                   strerror(errno));
+               if (action == CHECK)
+                       return -1;
+       }
+
+       /* parse it */
+       if (action == CHECK)    /* print silly verbose header for USG compat. */
+               (void) printf("%s\n", hdr);
+
+       for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
+               if (line[0]=='#')       /* comment, do not parse */
+                       continue;
+               if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
+                       continue;
+               line[strlen(line)-1] = '\0'; /* delete newline */
+               if (parse(magicp, nmagicp, line, action) != 0)
+                       errs = 1;
+       }
+
+       (void) fclose(f);
+       if (errs) {
+               free(*magicp);
+               *magicp = NULL;
+               *nmagicp = 0;
+       }
+       return errs;
+}
+
+/*
+ * handle an mmaped file.
  */
-static void
-eatsize(char **p)
+static int
+apprentice_compile(/*@out@*/ struct magic **magicp, /*@out@*/ uint32_t *nmagicp,
+               const char *fn, /*@unused@*/ int action)
+       /*@globals fileSystem, internalState @*/
+       /*@modifies fileSystem, internalState @*/
 {
-       char *l = *p;
+       int fd;
+       char *dbname = mkdbname(fn);
+       static const uint32_t ar[] = {
+           MAGICNO, VERSIONNO
+       };
 
-       if (LOWCASE(*l) == 'u'
-               l++;
+       if (dbname == NULL
+               return -1;
 
-       switch (LOWCASE(*l)) {
-       case 'l':    /* long */
-       case 's':    /* short */
-       case 'h':    /* short */
-       case 'b':    /* char/byte */
-       case 'c':    /* char/byte */
-               l++;
-               /*@fallthrough@*/
-       default:
-               break;
+       if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
+               (void)fprintf(stderr, "%s: Cannot open `%s' (%s)\n",
+                   progname, dbname, strerror(errno));
+               return -1;
        }
 
-       *p = l;
+       if (write(fd, ar, sizeof(ar)) != sizeof(ar)) {
+               (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
+                   progname, dbname, strerror(errno));
+               return -1;
+       }
+
+       if (lseek(fd, sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) {
+               (void)fprintf(stderr, "%s: error seeking `%s' (%s)\n",
+                   progname, dbname, strerror(errno));
+               return -1;
+       }
+
+       if (write(fd, *magicp,  sizeof(struct magic) * *nmagicp) 
+           != sizeof(struct magic) * *nmagicp) {
+               (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
+                   progname, dbname, strerror(errno));
+               return -1;
+       }
+
+       (void)close(fd);
+       return 0;
 }
 
 /*
  * handle a compiled file.
  */
 static int
-apprentice_map(struct magic **magicp, uint32_t *nmagicp, const char *fn,
-               /*@unused@*/ int action)
+apprentice_map(/*@out@*/ struct magic **magicp, /*@out@*/ uint32_t *nmagicp,
+               const char *fn, /*@unused@*/ int action)
+       /*@globals fileSystem, internalState @*/
+       /*@modifies *magicp, *nmagicp, fileSystem, internalState @*/
 {
        int fd;
        struct stat st;
@@ -1045,125 +1009,135 @@ error:
 }
 
 /*
- * handle an mmaped file.
+ * Handle one file.
  */
 static int
-apprentice_compile(struct magic **magicp, uint32_t *nmagicp, const char *fn,
-               /*@unused@*/ int action)
+apprentice_1(const char *fn, int action)
+       /*@globals lineno, mlist, fileSystem, internalState @*/
+       /*@modifies lineno, mlist, fileSystem, internalState @*/
 {
-       int fd;
-       char *dbname = mkdbname(fn);
-       static const uint32_t ar[] = {
-           MAGICNO, VERSIONNO
-       };
-
-       if (dbname == NULL) 
-               return -1;
+/*@-shadow@*/
+       struct magic *magic = NULL;
+       uint32_t nmagic = 0;
+/*@=shadow@*/
+       struct mlist *ml;
+       int rv = -1;
 
-       if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
-               (void)fprintf(stderr, "%s: Cannot open `%s' (%s)\n",
-                   progname, dbname, strerror(errno));
-               return -1;
+       if (action == COMPILE) {
+               rv = apprentice_file(&magic, &nmagic, fn, action);
+               if (rv == 0)
+                       return apprentice_compile(&magic, &nmagic, fn, action);
+               else
+                       return rv;
        }
+#ifndef COMPILE_ONLY
+       if ((rv = apprentice_map(&magic, &nmagic, fn, action)) != 0)
+               (void)fprintf(stderr, "%s: Using regular magic file `%s'\n",
+                   progname, fn);
+               
+       if (rv != 0)
+               rv = apprentice_file(&magic, &nmagic, fn, action);
 
-       if (write(fd, ar, sizeof(ar)) != sizeof(ar)) {
-               (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
-                   progname, dbname, strerror(errno));
-               return -1;
+       if (rv != 0)
+               return rv;
+            
+       if ((ml = malloc(sizeof(*ml))) == NULL) {
+               (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
+                   strerror(errno));
+               if (action == CHECK)
+                       return -1;
        }
 
-       if (lseek(fd, sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) {
-               (void)fprintf(stderr, "%s: error seeking `%s' (%s)\n",
-                   progname, dbname, strerror(errno));
-               return -1;
-       }
+       if (magic == NULL || nmagic == 0)
+               return rv;
 
-       if (write(fd, *magicp,  sizeof(struct magic) * *nmagicp) 
-           != sizeof(struct magic) * *nmagicp) {
-               (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
-                   progname, dbname, strerror(errno));
-               return -1;
-       }
+       ml->magic = magic;
+       ml->nmagic = nmagic;
 
-       (void)close(fd);
-       return 0;
+       mlist.prev->next = ml;
+       ml->prev = mlist.prev;
+/*@-immediatetrans@*/
+       ml->next = &mlist;
+/*@=immediatetrans@*/
+/*@-kepttrans@*/
+       mlist.prev = ml;
+/*@=kepttrans@*/
+
+/*@-compdef@*/
+       return rv;
+/*@=compdef@*/
+#endif /* COMPILE_ONLY */
 }
 
-/*
- * make a dbname
- */
-static char *
-mkdbname(const char *fn)
+/* const char *fn: list of magic files */
+int
+apprentice(const char *fn, int action)
 {
-       static const char ext[] = ".mgc";
-       /*@only@*/
-       static char *buf = NULL;
-       size_t len = strlen(fn) + sizeof(ext) + 1;
-       if (buf == NULL)
-               buf = malloc(len);
-       else
-               buf = realloc(buf, len);
-       if (buf == NULL) {
+       char *p, *mfn;
+       int file_err, errs = -1;
+
+/*@-immediatetrans@*/
+       mlist.next = &mlist;
+       mlist.prev = &mlist;
+/*@=immediatetrans@*/
+       mfn = malloc(strlen(fn)+1);
+       if (mfn == NULL) {
                (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
                    strerror(errno));
-               return NULL;
+/*@-compmempass@*/
+               if (action == CHECK)
+                       return -1;
+               else
+                       exit(EXIT_FAILURE);
+/*@=compmempass@*/
        }
-       (void)strcpy(buf, fn);
-       (void)strcat(buf, ext);
-       return buf;
-}
+       fn = strcpy(mfn, fn);
+  
+/*@-branchstate@*/
+       while (fn != NULL) {
+               p = strchr(fn, PATHSEP);
+               if (p != NULL)
+                       *p++ = '\0';
+               file_err = apprentice_1(fn, action);
+               if (file_err > errs)
+                       errs = file_err;
+               fn = p;
+       }
+/*@=branchstate@*/
+       if (errs == -1)
+               (void) fprintf(stderr, "%s: couldn't find any magic files!\n",
+                   progname);
+       if (action == CHECK && errs)
+               exit(EXIT_FAILURE);
 
-/*
- * Byteswap an mmap'ed file if needed
- */
-static void
-byteswap(struct magic *m, uint32_t nmagic)
-{
-       uint32_t i;
-       for (i = 0; i < nmagic; i++)
-               bs1(&m[i]);
+       free(mfn);
+/*@-compdef -compmempass@*/
+       return errs;
+/*@=compdef =compmempass@*/
 }
 
-/*
- * swap a short
- */
-static uint16_t
-swap2(uint16_t sv)
-{
-       uint16_t rv;
-       uint8_t *s = (uint8_t *) &sv; 
-       uint8_t *d = (uint8_t *) &rv; 
-       d[0] = s[1];
-       d[1] = s[0];
-       return rv;
-}
+#ifdef COMPILE_ONLY
+const char *magicfile;
+char *progname;
+int lineno;
 
-/*
- * swap an int
- */
-static uint32_t
-swap4(uint32_t sv)
+int
+main(int argc, char *argv[])
+       /*@*/
 {
-       uint32_t rv;
-       uint8_t *s = (uint8_t *) &sv; 
-       uint8_t *d = (uint8_t *) &rv; 
-       d[0] = s[3];
-       d[1] = s[2];
-       d[2] = s[1];
-       d[3] = s[0];
-       return rv;
-}
+       int ret;
 
-/*
- * byteswap a single magic entry
- */
-static
-void bs1(struct magic *m)
-{
-       m->cont_level = swap2(m->cont_level);
-       m->offset = swap4(m->offset);
-       m->in_offset = swap4(m->in_offset);
-       if (m->type != STRING)
-               m->value.l = swap4(m->value.l);
-       m->mask = swap4(m->mask);
+       if ((progname = strrchr(argv[0], '/')) != NULL)
+               progname++;
+       else
+               progname = argv[0];
+
+       if (argc != 2) {
+               (void)fprintf(stderr, "usage: %s file\n", progname);
+               exit(1);
+       }
+       magicfile = argv[1];
+
+       exit(apprentice(magicfile, COMPILE));
 }
+#endif /* COMPILE_ONLY */
index db314ef..2d7b68e 100644 (file)
@@ -54,439 +54,153 @@ typedef unsigned long unichar;
 #define ISSPC(x) ((x) == ' ' || (x) == '\t' || (x) == '\r' || (x) == '\n' \
                  || (x) == 0x85 || (x) == '\f')
 
-static int looks_ascii(const unsigned char *buf, int nbytes,
-               /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
-       /*@modifies *ubuf, *ulen @*/;
-static int looks_utf8(const unsigned char *buf, int nbytes,
-               /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
-       /*@modifies *ubuf, *ulen @*/;
-static int looks_unicode(const unsigned char *buf, int nbytes,
-               /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
-       /*@modifies *ubuf, *ulen @*/;
-static int looks_latin1(const unsigned char *buf, int nbytes,
-               /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
-       /*@modifies *ubuf, *ulen @*/;
-static int looks_extended(const unsigned char *buf, int nbytes,
-               /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
-       /*@modifies *ubuf, *ulen @*/;
-static void from_ebcdic(const unsigned char *buf, int nbytes,
-               /*@out@*/ unsigned char *otp)
-       /*@modifies *otp @*/;
-static int ascmatch(const unsigned char *s, const unichar *us, int ulen)
-       /*@*/;
+/*
+ * This table reflects a particular philosophy about what constitutes
+ * "text," and there is room for disagreement about it.
+ *
+ * Version 3.31 of the file command considered a file to be ASCII if
+ * each of its characters was approved by either the isascii() or
+ * isalpha() function.  On most systems, this would mean that any
+ * file consisting only of characters in the range 0x00 ... 0x7F
+ * would be called ASCII text, but many systems might reasonably
+ * consider some characters outside this range to be alphabetic,
+ * so the file command would call such characters ASCII.  It might
+ * have been more accurate to call this "considered textual on the
+ * local system" than "ASCII."
+ *
+ * It considered a file to be "International language text" if each
+ * of its characters was either an ASCII printing character (according
+ * to the real ASCII standard, not the above test), a character in
+ * the range 0x80 ... 0xFF, or one of the following control characters:
+ * backspace, tab, line feed, vertical tab, form feed, carriage return,
+ * escape.  No attempt was made to determine the language in which files
+ * of this type were written.
+ *
+ *
+ * The table below considers a file to be ASCII if all of its characters
+ * are either ASCII printing characters (again, according to the X3.4
+ * standard, not isascii()) or any of the following controls: bell,
+ * backspace, tab, line feed, form feed, carriage return, esc, nextline.
+ *
+ * I include bell because some programs (particularly shell scripts)
+ * use it literally, even though it is rare in normal text.  I exclude
+ * vertical tab because it never seems to be used in real text.  I also
+ * include, with hesitation, the X3.64/ECMA-43 control nextline (0x85),
+ * because that's what the dd EBCDIC->ASCII table maps the EBCDIC newline
+ * character to.  It might be more appropriate to include it in the 8859
+ * set instead of the ASCII set, but it's got to be included in *something*
+ * we recognize or EBCDIC files aren't going to be considered textual.
+ * Some old Unix source files use SO/SI (^N/^O) to shift between Greek
+ * and Latin characters, so these should possibly be allowed.  But they
+ * make a real mess on VT100-style displays if they're not paired properly,
+ * so we are probably better off not calling them text.
+ *
+ * A file is considered to be ISO-8859 text if its characters are all
+ * either ASCII, according to the above definition, or printing characters
+ * from the ISO-8859 8-bit extension, characters 0xA0 ... 0xFF.
+ *
+ * Finally, a file is considered to be international text from some other
+ * character code if its characters are all either ISO-8859 (according to
+ * the above definition) or characters in the range 0x80 ... 0x9F, which
+ * ISO-8859 considers to be control characters but the IBM PC and Macintosh
+ * consider to be printing characters.
+ */
 
-/* int nbytes: size actually read */
-int
-ascmagic(unsigned char *buf, int nbytes)
+#define F 0   /* character never appears in text */
+#define T 1   /* character appears in plain ASCII text */
+#define I 2   /* character appears in ISO-8859 text */
+#define X 3   /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
+
+/*@unchecked@*/ /*@observer@*/
+static char text_chars[256] = {
+       /*                  BEL BS HT LF    FF CR    */
+       F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F,  /* 0x0X */
+        /*                              ESC          */
+       F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F,  /* 0x1X */
+       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x2X */
+       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x3X */
+       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x4X */
+       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x5X */
+       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x6X */
+       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F,  /* 0x7X */
+       /*            NEL                            */
+       X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X,  /* 0x8X */
+       X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,  /* 0x9X */
+       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xaX */
+       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xbX */
+       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xcX */
+       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xdX */
+       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xeX */
+       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I   /* 0xfX */
+};
+
+static int
+looks_ascii(const unsigned char *buf, int nbytes,
+               /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
+       /*@modifies *ubuf, *ulen @*/
 {
        int i;
-       char nbuf[HOWMANY+1];           /* one extra for terminating '\0' */
-       unichar ubuf[HOWMANY+1];        /* one extra for terminating '\0' */
-       int ulen;
-       struct names *p;
-
-       char *code = NULL;
-       char *code_mime = NULL;
-       char *type = NULL;
-       char *subtype = NULL;
-       char *subtype_mime = NULL;
 
-       int has_escapes = 0;
-       int has_backspace = 0;
+       *ulen = 0;
 
-       int n_crlf = 0;
-       int n_lf = 0;
-       int n_cr = 0;
-       int n_nel = 0;
+       for (i = 0; i < nbytes; i++) {
+               int t = text_chars[buf[i]];
 
-       int last_line_end = -1;
-       int has_long_lines = 0;
+               if (t != T)
+                       return 0;
 
-       /*
-        * Do the tar test first, because if the first file in the tar
-        * archive starts with a dot, we can confuse it with an nroff file.
-        */
-       switch (is_tar(buf, nbytes)) {
-       case 1:
-               ckfputs(iflag ? "application/x-tar" : "tar archive", stdout);
-               return 1;
-       case 2:
-               ckfputs(iflag ? "application/x-tar, POSIX"
-                               : "POSIX tar archive", stdout);
-               return 1;
+               ubuf[(*ulen)++] = buf[i];
        }
 
-       /*
-        * Undo the NUL-termination kindly provided by process()
-        * but leave at least one byte to look at
-        */
-
-       while (nbytes > 1 && buf[nbytes - 1] == '\0')
-               nbytes--;
-
-       /*
-        * Then try to determine whether it's any character code we can
-        * identify.  Each of these tests, if it succeeds, will leave
-        * the text converted into one-unichar-per-character Unicode in
-        * ubuf, and the number of characters converted in ulen.
-        */
-       if (looks_ascii(buf, nbytes, ubuf, &ulen)) {
-               code = "ASCII";
-               code_mime = "us-ascii";
-               type = "text";
-       } else if (looks_utf8(buf, nbytes, ubuf, &ulen)) {
-               code = "UTF-8 Unicode";
-               code_mime = "utf-8";
-               type = "text";
-       } else if ((i = looks_unicode(buf, nbytes, ubuf, &ulen))) {
-               if (i == 1)
-                       code = "Little-endian UTF-16 Unicode";
-               else
-                       code = "Big-endian UTF-16 Unicode";
+       return 1;
+}
 
-               type = "character data";
-               code_mime = "utf-16";    /* is this defined? */
-       } else if (looks_latin1(buf, nbytes, ubuf, &ulen)) {
-               code = "ISO-8859";
-               type = "text";
-               code_mime = "iso-8859-1"; 
-       } else if (looks_extended(buf, nbytes, ubuf, &ulen)) {
-               code = "Non-ISO extended-ASCII";
-               type = "text";
-               code_mime = "unknown";
-       } else {
-               from_ebcdic(buf, nbytes, nbuf);
+static int
+looks_latin1(const unsigned char *buf, int nbytes,
+               /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
+       /*@modifies *ubuf, *ulen @*/
+{
+       int i;
 
-               if (looks_ascii(nbuf, nbytes, ubuf, &ulen)) {
-                       code = "EBCDIC";
-                       type = "character data";
-                       code_mime = "ebcdic";
-               } else if (looks_latin1(nbuf, nbytes, ubuf, &ulen)) {
-                       code = "International EBCDIC";
-                       type = "character data";
-                       code_mime = "ebcdic";
-               } else {
-                       return 0;  /* doesn't look like text at all */
-               }
-       }
+       *ulen = 0;
 
-       /*
-        * for troff, look for . + letter + letter or .\";
-        * this must be done to disambiguate tar archives' ./file
-        * and other trash from real troff input.
-        *
-        * I believe Plan 9 troff allows non-ASCII characters in the names
-        * of macros, so this test might possibly fail on such a file.
-        */
-       if (*ubuf == '.') {
-               unichar *tp = ubuf + 1;
+       for (i = 0; i < nbytes; i++) {
+               int t = text_chars[buf[i]];
 
-               while (ISSPC(*tp))
-                       ++tp;   /* skip leading whitespace */
-               if ((tp[0] == '\\' && tp[1] == '\"') ||
-                   (isascii(tp[0]) && isalnum(tp[0]) &&
-                    isascii(tp[1]) && isalnum(tp[1]) &&
-                    ISSPC(tp[2]))) {
-                       subtype_mime = "text/troff";
-                       subtype = "troff or preprocessor input";
-                       goto subtype_identified;
-               }
-       }
+               if (t != T && t != I)
+                       return 0;
 
-       if ((*buf == 'c' || *buf == 'C') && ISSPC(buf[1])) {
-               subtype_mime = "text/fortran";
-               subtype = "fortran program";
-               goto subtype_identified;
+               ubuf[(*ulen)++] = buf[i];
        }
 
-       /* look for tokens from names.h - this is expensive! */
+       return 1;
+}
 
-       i = 0;
-       while (i < ulen) {
-               int end;
+static int
+looks_extended(const unsigned char *buf, int nbytes,
+               /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
+       /*@modifies *ubuf, *ulen @*/
+{
+       int i;
 
-               /*
-                * skip past any leading space
-                */
-               while (i < ulen && ISSPC(ubuf[i]))
-                       i++;
-               if (i >= ulen)
-                       break;
+       *ulen = 0;
 
-               /*
-                * find the next whitespace
-                */
-               for (end = i + 1; end < nbytes; end++)
-                       if (ISSPC(ubuf[end]))
-                               /*@innerbreak@*/ break;
+       for (i = 0; i < nbytes; i++) {
+               int t = text_chars[buf[i]];
 
-               /*
-                * compare the word thus isolated against the token list
-                */
-               for (p = names; p < names + NNAMES; p++) {
-                       if (ascmatch(p->name, ubuf + i, end - i)) {
-                               subtype = types[p->type].human;
-                               subtype_mime = types[p->type].mime;
-                               goto subtype_identified;
-                       }
-               }
+               if (t != T && t != I && t != X)
+                       return 0;
 
-               i = end;
+               ubuf[(*ulen)++] = buf[i];
        }
 
-subtype_identified:
-
-       /*
-        * Now try to discover other details about the file.
-        */
-       for (i = 0; i < ulen; i++) {
-               if (i > last_line_end + MAXLINELEN)
-                       has_long_lines = 1;
-
-               if (ubuf[i] == '\033')
-                       has_escapes = 1;
-               if (ubuf[i] == '\b')
-                       has_backspace = 1;
-
-               if (ubuf[i] == '\r' && (i + 1 <  ulen && ubuf[i + 1] == '\n')) {
-                       n_crlf++;
-                       last_line_end = i;
-               }
-               if (ubuf[i] == '\r' && (i + 1 >= ulen || ubuf[i + 1] != '\n')) {
-                       n_cr++;
-                       last_line_end = i;
-               }
-               if (ubuf[i] == '\n' && (i - 1 <  0    || ubuf[i - 1] != '\r')) {
-                       n_lf++;
-                       last_line_end = i;
-               }
-               if (ubuf[i] == 0x85) { /* X3.64/ECMA-43 "next line" character */
-                       n_nel++;
-                       last_line_end = i;
-               }
-       }
-
-       if (iflag) {
-               if (subtype_mime != NULL)
-                       ckfputs(subtype_mime, stdout);
-               else
-                       ckfputs("text/plain", stdout);
-
-               if (code_mime != NULL) {
-                       ckfputs("; charset=", stdout);
-                       ckfputs(code_mime, stdout);
-               }
-       } else {
-               ckfputs(code, stdout);
-
-               if (subtype != NULL) {
-                       ckfputs(" ", stdout);
-                       ckfputs(subtype, stdout);
-               }
-
-               ckfputs(" ", stdout);
-               ckfputs(type, stdout);
-
-               if (has_long_lines)
-                       ckfputs(", with very long lines", stdout);
-
-               /*
-                * Only report line terminators if we find one other than LF,
-                * or if we find none at all.
-                */
-               if ((n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) ||
-                   (n_crlf != 0 || n_cr != 0 || n_nel != 0)) {
-                       ckfputs(", with", stdout);
-
-                       if (n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0)
-                               ckfputs(" no", stdout);
-                       else {
-                               if (n_crlf) {
-                                       ckfputs(" CRLF", stdout);
-                                       if (n_cr || n_lf || n_nel)
-                                               ckfputs(",", stdout);
-                               }
-                               if (n_cr) {
-                                       ckfputs(" CR", stdout);
-                                       if (n_lf || n_nel)
-                                               ckfputs(",", stdout);
-                               }
-                               if (n_lf) {
-                                       ckfputs(" LF", stdout);
-                                       if (n_nel)
-                                               ckfputs(",", stdout);
-                               }
-                               if (n_nel)
-                                       ckfputs(" NEL", stdout);
-                       }
-
-                       ckfputs(" line terminators", stdout);
-               }
-
-               if (has_escapes)
-                       ckfputs(", with escape sequences", stdout);
-               if (has_backspace)
-                       ckfputs(", with overstriking", stdout);
-       }
-
-       return 1;
-}
-
-static int
-ascmatch(const unsigned char *s, const unichar *us, int ulen)
-{
-       size_t i;
-
-       for (i = 0; i < ulen; i++) {
-               if (s[i] != us[i])
-                       return 0;
-       }
-
-       if (s[i])
-               return 0;
-       else
-               return 1;
-}
-
-/*
- * This table reflects a particular philosophy about what constitutes
- * "text," and there is room for disagreement about it.
- *
- * Version 3.31 of the file command considered a file to be ASCII if
- * each of its characters was approved by either the isascii() or
- * isalpha() function.  On most systems, this would mean that any
- * file consisting only of characters in the range 0x00 ... 0x7F
- * would be called ASCII text, but many systems might reasonably
- * consider some characters outside this range to be alphabetic,
- * so the file command would call such characters ASCII.  It might
- * have been more accurate to call this "considered textual on the
- * local system" than "ASCII."
- *
- * It considered a file to be "International language text" if each
- * of its characters was either an ASCII printing character (according
- * to the real ASCII standard, not the above test), a character in
- * the range 0x80 ... 0xFF, or one of the following control characters:
- * backspace, tab, line feed, vertical tab, form feed, carriage return,
- * escape.  No attempt was made to determine the language in which files
- * of this type were written.
- *
- *
- * The table below considers a file to be ASCII if all of its characters
- * are either ASCII printing characters (again, according to the X3.4
- * standard, not isascii()) or any of the following controls: bell,
- * backspace, tab, line feed, form feed, carriage return, esc, nextline.
- *
- * I include bell because some programs (particularly shell scripts)
- * use it literally, even though it is rare in normal text.  I exclude
- * vertical tab because it never seems to be used in real text.  I also
- * include, with hesitation, the X3.64/ECMA-43 control nextline (0x85),
- * because that's what the dd EBCDIC->ASCII table maps the EBCDIC newline
- * character to.  It might be more appropriate to include it in the 8859
- * set instead of the ASCII set, but it's got to be included in *something*
- * we recognize or EBCDIC files aren't going to be considered textual.
- * Some old Unix source files use SO/SI (^N/^O) to shift between Greek
- * and Latin characters, so these should possibly be allowed.  But they
- * make a real mess on VT100-style displays if they're not paired properly,
- * so we are probably better off not calling them text.
- *
- * A file is considered to be ISO-8859 text if its characters are all
- * either ASCII, according to the above definition, or printing characters
- * from the ISO-8859 8-bit extension, characters 0xA0 ... 0xFF.
- *
- * Finally, a file is considered to be international text from some other
- * character code if its characters are all either ISO-8859 (according to
- * the above definition) or characters in the range 0x80 ... 0x9F, which
- * ISO-8859 considers to be control characters but the IBM PC and Macintosh
- * consider to be printing characters.
- */
-
-#define F 0   /* character never appears in text */
-#define T 1   /* character appears in plain ASCII text */
-#define I 2   /* character appears in ISO-8859 text */
-#define X 3   /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
-
-/*@unchecked@*/ /*@observer@*/
-static char text_chars[256] = {
-       /*                  BEL BS HT LF    FF CR    */
-       F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F,  /* 0x0X */
-        /*                              ESC          */
-       F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F,  /* 0x1X */
-       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x2X */
-       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x3X */
-       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x4X */
-       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x5X */
-       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  /* 0x6X */
-       T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F,  /* 0x7X */
-       /*            NEL                            */
-       X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X,  /* 0x8X */
-       X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,  /* 0x9X */
-       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xaX */
-       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xbX */
-       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xcX */
-       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xdX */
-       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  /* 0xeX */
-       I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I   /* 0xfX */
-};
-
-static int
-looks_ascii(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen)
-{
-       int i;
-
-       *ulen = 0;
-
-       for (i = 0; i < nbytes; i++) {
-               int t = text_chars[buf[i]];
-
-               if (t != T)
-                       return 0;
-
-               ubuf[(*ulen)++] = buf[i];
-       }
-
-       return 1;
-}
-
-static int
-looks_latin1(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen)
-{
-       int i;
-
-       *ulen = 0;
-
-       for (i = 0; i < nbytes; i++) {
-               int t = text_chars[buf[i]];
-
-               if (t != T && t != I)
-                       return 0;
-
-               ubuf[(*ulen)++] = buf[i];
-       }
-
-       return 1;
-}
-
-static int
-looks_extended(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen)
-{
-       int i;
-
-       *ulen = 0;
-
-       for (i = 0; i < nbytes; i++) {
-               int t = text_chars[buf[i]];
-
-               if (t != T && t != I && t != X)
-                       return 0;
-
-               ubuf[(*ulen)++] = buf[i];
-       }
-
-       return 1;
-}
+       return 1;
+}
 
 int
-looks_utf8(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen)
+looks_utf8(const unsigned char *buf, int nbytes,
+               /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
+       /*@modifies *ubuf, *ulen @*/
 {
        int i, n;
        unichar c;
@@ -548,7 +262,9 @@ done:
 }
 
 static int
-looks_unicode(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen)
+looks_unicode(const unsigned char *buf, int nbytes,
+               /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
+       /*@modifies *ubuf, *ulen @*/
 {
        int bigend;
        int i;
@@ -667,7 +383,8 @@ unsigned char ebcdic_1047_to_8859[] = {
  * Copy buf[0 ... nbytes-1] into out[], translating EBCDIC to ASCII.
  */
 static void
-from_ebcdic(const unsigned char *buf, int nbytes, unsigned char *otp)
+from_ebcdic(const unsigned char *buf, int nbytes, /*@out@*/ unsigned char *otp)
+       /*@modifies *otp @*/
 {
        int i;
 
@@ -675,3 +392,277 @@ from_ebcdic(const unsigned char *buf, int nbytes, unsigned char *otp)
                otp[i] = ebcdic_to_ascii[buf[i]];
        }
 }
+
+static int
+ascmatch(const unsigned char *s, const unichar *us, int ulen)
+       /*@*/
+{
+       size_t i;
+
+       for (i = 0; i < ulen; i++) {
+               if (s[i] != us[i])
+                       return 0;
+       }
+
+       if (s[i])
+               return 0;
+       else
+               return 1;
+}
+
+/* int nbytes: size actually read */
+int
+ascmagic(unsigned char *buf, int nbytes)
+{
+       int i;
+       char nbuf[HOWMANY+1];           /* one extra for terminating '\0' */
+       unichar ubuf[HOWMANY+1];        /* one extra for terminating '\0' */
+       int ulen;
+       struct names *p;
+
+       char *code = NULL;
+       char *code_mime = NULL;
+       char *type = NULL;
+       char *subtype = NULL;
+       char *subtype_mime = NULL;
+
+       int has_escapes = 0;
+       int has_backspace = 0;
+
+       int n_crlf = 0;
+       int n_lf = 0;
+       int n_cr = 0;
+       int n_nel = 0;
+
+       int last_line_end = -1;
+       int has_long_lines = 0;
+
+       /*
+        * Do the tar test first, because if the first file in the tar
+        * archive starts with a dot, we can confuse it with an nroff file.
+        */
+       switch (is_tar(buf, nbytes)) {
+       case 1:
+               ckfputs(iflag ? "application/x-tar" : "tar archive", stdout);
+               return 1;
+       case 2:
+               ckfputs(iflag ? "application/x-tar, POSIX"
+                               : "POSIX tar archive", stdout);
+               return 1;
+       }
+
+       /*
+        * Undo the NUL-termination kindly provided by process()
+        * but leave at least one byte to look at
+        */
+
+       while (nbytes > 1 && buf[nbytes - 1] == '\0')
+               nbytes--;
+
+       /*
+        * Then try to determine whether it's any character code we can
+        * identify.  Each of these tests, if it succeeds, will leave
+        * the text converted into one-unichar-per-character Unicode in
+        * ubuf, and the number of characters converted in ulen.
+        */
+       if (looks_ascii(buf, nbytes, ubuf, &ulen)) {
+               code = "ASCII";
+               code_mime = "us-ascii";
+               type = "text";
+       } else if (looks_utf8(buf, nbytes, ubuf, &ulen)) {
+               code = "UTF-8 Unicode";
+               code_mime = "utf-8";
+               type = "text";
+       } else if ((i = looks_unicode(buf, nbytes, ubuf, &ulen))) {
+               if (i == 1)
+                       code = "Little-endian UTF-16 Unicode";
+               else
+                       code = "Big-endian UTF-16 Unicode";
+
+               type = "character data";
+               code_mime = "utf-16";    /* is this defined? */
+       } else if (looks_latin1(buf, nbytes, ubuf, &ulen)) {
+               code = "ISO-8859";
+               type = "text";
+               code_mime = "iso-8859-1"; 
+       } else if (looks_extended(buf, nbytes, ubuf, &ulen)) {
+               code = "Non-ISO extended-ASCII";
+               type = "text";
+               code_mime = "unknown";
+       } else {
+               from_ebcdic(buf, nbytes, nbuf);
+
+               if (looks_ascii(nbuf, nbytes, ubuf, &ulen)) {
+                       code = "EBCDIC";
+                       type = "character data";
+                       code_mime = "ebcdic";
+               } else if (looks_latin1(nbuf, nbytes, ubuf, &ulen)) {
+                       code = "International EBCDIC";
+                       type = "character data";
+                       code_mime = "ebcdic";
+               } else {
+                       return 0;  /* doesn't look like text at all */
+               }
+       }
+
+       /*
+        * for troff, look for . + letter + letter or .\";
+        * this must be done to disambiguate tar archives' ./file
+        * and other trash from real troff input.
+        *
+        * I believe Plan 9 troff allows non-ASCII characters in the names
+        * of macros, so this test might possibly fail on such a file.
+        */
+       if (*ubuf == '.') {
+               unichar *tp = ubuf + 1;
+
+               while (ISSPC(*tp))
+                       ++tp;   /* skip leading whitespace */
+               if ((tp[0] == '\\' && tp[1] == '\"') ||
+                   (isascii(tp[0]) && isalnum(tp[0]) &&
+                    isascii(tp[1]) && isalnum(tp[1]) &&
+                    ISSPC(tp[2]))) {
+                       subtype_mime = "text/troff";
+                       subtype = "troff or preprocessor input";
+                       goto subtype_identified;
+               }
+       }
+
+       if ((*buf == 'c' || *buf == 'C') && ISSPC(buf[1])) {
+               subtype_mime = "text/fortran";
+               subtype = "fortran program";
+               goto subtype_identified;
+       }
+
+       /* look for tokens from names.h - this is expensive! */
+
+       i = 0;
+       while (i < ulen) {
+               int end;
+
+               /*
+                * skip past any leading space
+                */
+               while (i < ulen && ISSPC(ubuf[i]))
+                       i++;
+               if (i >= ulen)
+                       break;
+
+               /*
+                * find the next whitespace
+                */
+               for (end = i + 1; end < nbytes; end++)
+                       if (ISSPC(ubuf[end]))
+                               /*@innerbreak@*/ break;
+
+               /*
+                * compare the word thus isolated against the token list
+                */
+               for (p = names; p < names + NNAMES; p++) {
+                       if (ascmatch(p->name, ubuf + i, end - i)) {
+                               subtype = types[p->type].human;
+                               subtype_mime = types[p->type].mime;
+                               goto subtype_identified;
+                       }
+               }
+
+               i = end;
+       }
+
+subtype_identified:
+
+       /*
+        * Now try to discover other details about the file.
+        */
+       for (i = 0; i < ulen; i++) {
+               if (i > last_line_end + MAXLINELEN)
+                       has_long_lines = 1;
+
+               if (ubuf[i] == '\033')
+                       has_escapes = 1;
+               if (ubuf[i] == '\b')
+                       has_backspace = 1;
+
+               if (ubuf[i] == '\r' && (i + 1 <  ulen && ubuf[i + 1] == '\n')) {
+                       n_crlf++;
+                       last_line_end = i;
+               }
+               if (ubuf[i] == '\r' && (i + 1 >= ulen || ubuf[i + 1] != '\n')) {
+                       n_cr++;
+                       last_line_end = i;
+               }
+               if (ubuf[i] == '\n' && (i - 1 <  0    || ubuf[i - 1] != '\r')) {
+                       n_lf++;
+                       last_line_end = i;
+               }
+               if (ubuf[i] == 0x85) { /* X3.64/ECMA-43 "next line" character */
+                       n_nel++;
+                       last_line_end = i;
+               }
+       }
+
+       if (iflag) {
+               if (subtype_mime != NULL)
+                       ckfputs(subtype_mime, stdout);
+               else
+                       ckfputs("text/plain", stdout);
+
+               if (code_mime != NULL) {
+                       ckfputs("; charset=", stdout);
+                       ckfputs(code_mime, stdout);
+               }
+       } else {
+               ckfputs(code, stdout);
+
+               if (subtype != NULL) {
+                       ckfputs(" ", stdout);
+                       ckfputs(subtype, stdout);
+               }
+
+               ckfputs(" ", stdout);
+               ckfputs(type, stdout);
+
+               if (has_long_lines)
+                       ckfputs(", with very long lines", stdout);
+
+               /*
+                * Only report line terminators if we find one other than LF,
+                * or if we find none at all.
+                */
+               if ((n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) ||
+                   (n_crlf != 0 || n_cr != 0 || n_nel != 0)) {
+                       ckfputs(", with", stdout);
+
+                       if (n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0)
+                               ckfputs(" no", stdout);
+                       else {
+                               if (n_crlf) {
+                                       ckfputs(" CRLF", stdout);
+                                       if (n_cr || n_lf || n_nel)
+                                               ckfputs(",", stdout);
+                               }
+                               if (n_cr) {
+                                       ckfputs(" CR", stdout);
+                                       if (n_lf || n_nel)
+                                               ckfputs(",", stdout);
+                               }
+                               if (n_lf) {
+                                       ckfputs(" LF", stdout);
+                                       if (n_nel)
+                                               ckfputs(",", stdout);
+                               }
+                               if (n_nel)
+                                       ckfputs(" NEL", stdout);
+                       }
+
+                       ckfputs(" line terminators", stdout);
+               }
+
+               if (has_escapes)
+                       ckfputs(", with escape sequences", stdout);
+               if (has_backspace)
+                       ckfputs(", with overstriking", stdout);
+       }
+
+       return 1;
+}
index 2991e11..d457ef5 100644 (file)
@@ -1,10 +1,4 @@
-/*
- * compress routines:
- *     zmagic() - returns 0 if not recognized, uncompresses and prints
- *                information if recognized
- *     uncompress(method, old, n, newch) - uncompress old into new, 
- *                                         using method, return sizeof new
- */
+
 #include "file.h"
 #include <stdlib.h>
 #ifdef HAVE_UNISTD_H
@@ -22,7 +16,6 @@
 FILE_RCSID("@(#)Id: compress.c,v 1.25 2002/07/03 18:26:37 christos Exp ")
 #endif
 
-
 /*@-nullassign@*/
 /*@unchecked@*/
 static struct {
@@ -49,59 +42,17 @@ static struct {
 /*@unchecked@*/
 static int ncompr = sizeof(compr) / sizeof(compr[0]);
 
-
-static int swrite(int fd, const void *buf, size_t n)
-       /*@*/;
-static int sread(int fd, /*@out@*/ void *buf, size_t n)
-       /*@modifies *buf @*/;
-static int uncompressbuf(int method, const unsigned char *old,
-               /*@out@*/ unsigned char **newch, int n)
-       /*@globals fileSystem, internalState @*/
-       /*@modifies *newch, fileSystem, internalState @*/;
-#ifdef HAVE_LIBZ
-static int uncompressgzipped(const unsigned char *old,
-               /*@out@*/ unsigned char **newch, int n)
-       /*@globals fileSystem @*/
-       /*@modifies *newch, fileSystem @*/;
-#endif
-
-int
-zmagic(const char *fname, unsigned char *buf, int nbytes)
-{
-       unsigned char *newbuf;
-       int newsize;
-       int i;
-
-       for (i = 0; i < ncompr; i++) {
-               if (nbytes < compr[i].maglen)
-                       continue;
-               if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 &&
-                   (newsize = uncompressbuf(i, buf, &newbuf, nbytes)) != 0) {
-                       (void) tryit(fname, newbuf, newsize, 1);
-                       free(newbuf);
-                       printf(" (");
-                       (void) tryit(fname, buf, nbytes, 0);
-                       printf(")");
-                       return 1;
-               }
-       }
-
-       if (i == ncompr)
-               return 0;
-
-       return 1;
-}
-
 /*
  * `safe' write for sockets and pipes.
  */
 static int
 swrite(int fd, const void *buf, size_t n)
+       /*@*/
 {
        int rv;
        size_t rn = n;
 
-       do
+       do {
                switch (rv = write(fd, buf, n)) {
                case -1:
                        if (errno == EINTR)
@@ -112,7 +63,7 @@ swrite(int fd, const void *buf, size_t n)
                        buf = ((const char *)buf) + rv;
                        /*@switchbreak@*/ break;
                }
-       while (n > 0);
+       while (n > 0);
        return rn;
 }
 
@@ -121,12 +72,13 @@ swrite(int fd, const void *buf, size_t n)
  * `safe' read for sockets and pipes.
  */
 static int
-sread(int fd, void *buf, size_t n)
+sread(int fd, /*@out@*/ void *buf, size_t n)
+       /*@modifies *buf @*/
 {
        int rv;
        size_t rn = n;
 
-       do
+       do {
                switch (rv = read(fd, buf, n)) {
                case -1:
                        if (errno == EINTR)
@@ -139,7 +91,7 @@ sread(int fd, void *buf, size_t n)
                        buf = ((char *)buf) + rv;
                        /*@switchbreak@*/ break;
                }
-       while (n > 0);
+       while (n > 0);
        return rn;
 }
 
@@ -217,7 +169,10 @@ pipe2file(int fd, void *startbuf, size_t nbytes)
 #define FCOMMENT       (1 << 4)
 
 static int
-uncompressgzipped(const unsigned char *old, unsigned char **newch, int n)
+uncompressgzipped(const unsigned char *old,
+               /*@out@*/ unsigned char **newch, int n)
+       /*@globals fileSystem @*/
+       /*@modifies *newch, fileSystem @*/
 {
        unsigned char flg = old[3];
        int data_start = 10;
@@ -280,8 +235,10 @@ uncompressgzipped(const unsigned char *old, unsigned char **newch, int n)
 #endif
 
 static int
-uncompressbuf(int method, const unsigned char *old, unsigned char **newch,
-             int n)
+uncompressbuf(int method, const unsigned char *old,
+               /*@out@*/ unsigned char **newch, int n)
+       /*@globals fileSystem, internalState @*/
+       /*@modifies *newch, fileSystem, internalState @*/
 {
        int fdin[2], fdout[2];
 
@@ -348,3 +305,35 @@ err:
        }
        /*@notreached@*/
 }
+
+/*
+ * compress routines:
+ *     zmagic() - returns 0 if not recognized, uncompresses and prints
+ *                information if recognized
+ */
+int
+zmagic(const char *fname, unsigned char *buf, int nbytes)
+{
+       unsigned char *newbuf;
+       int newsize;
+       int i;
+
+       for (i = 0; i < ncompr; i++) {
+               if (nbytes < compr[i].maglen)
+                       continue;
+               if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 &&
+                   (newsize = uncompressbuf(i, buf, &newbuf, nbytes)) != 0) {
+                       (void) tryit(fname, newbuf, newsize, 1);
+                       free(newbuf);
+                       printf(" (");
+                       (void) tryit(fname, buf, nbytes, 0);
+                       printf(")");
+                       return 1;
+               }
+       }
+
+       if (i == ncompr)
+               return 0;
+
+       return 1;
+}
index 61307c0..84c703c 100644 (file)
@@ -53,8 +53,6 @@
 #include <getopt.h>    /* for long options (is this portable?)*/
 #endif
 
-#include <netinet/in.h>                /* for byte swapping */
-
 #include "patchlevel.h"
 
 #ifndef        lint
@@ -92,13 +90,6 @@ int                  /* Global command-line options          */
        nobuffer = 0,   /* Do not buffer stdout */
        kflag = 0;      /* Keep going after the first match     */
 
-/*@unchecked@*/ /*@unused@*/
-int                    /* Misc globals                         */
-       nmagic = 0;     /* number of valid magic[]s             */
-
-/*@unchecked@*/ /*@unused@*/
-struct  magic *magic;  /* array of magic entries               */
-
 /*@unchecked@*/ /*@null@*/
 const char *magicfile = 0;     /* where the magic is           */
 /*@unchecked@*/ /*@observer@*/
@@ -109,34 +100,239 @@ char *progname;          /* used throughout                      */
 /*@unchecked@*/
 int lineno;            /* line number in the magic file        */
 
+int
+tryit(const char *fn, unsigned char *buf, int nb, int zfl)
+{
+
+       /*
+        * The main work is done here!
+        * We have the file name and/or the data buffer to be identified. 
+        */
+
+#ifdef __EMX__
+       /*
+        * Ok, here's the right place to add a call to some os-specific
+        * routine, e.g.
+        */
+       if (os2_apptype(fn, buf, nb) == 1)
+              return 'o';
+#endif
+       /* try compression stuff */
+       if (zfl && zmagic(fn, buf, nb))
+               return 'z';
+
+       /* try tests in /etc/magic (or surrogate magic file) */
+       if (softmagic(buf, nb))
+               return 's';
+
+       /* try known keywords, check whether it is ASCII */
+       if (ascmagic(buf, nb))
+               return 'a';
+
+       /* abandon hope, all ye who remain here */
+       ckfputs(iflag ? "application/octet-stream" : "data", stdout);
+               return '\0';
+}
+
+/*
+ * process - process input file
+ */
+void
+process(const char *inname, int wid)
+{
+       int     fd = 0;
+       static  const char stdname[] = "standard input";
+       unsigned char   buf[HOWMANY+1]; /* one extra for terminating '\0' */
+       struct stat     sb;
+       int nbytes = 0; /* number of bytes read from a datafile */
+       char match = '\0';
+
+       if (strcmp("-", inname) == 0) {
+               if (fstat(0, &sb)<0) {
+                       error("cannot fstat `%s' (%s).\n", stdname,
+                             strerror(errno));
+                       /*@notreached@*/
+               }
+               inname = stdname;
+       }
+
+       if (wid > 0 && !bflag)
+            (void) printf("%s:%*s ", inname, 
+                          (int) (wid - strlen(inname)), "");
+
+       if (inname != stdname) {
+               /*
+                * first try judging the file based on its filesystem status
+                */
+               if (fsmagic(inname, &sb) != 0) {
+                       (void) putchar('\n');
+                       return;
+               }
+
+               if ((fd = open(inname, O_RDONLY)) < 0) {
+                       /* We can't open it, but we were able to stat it. */
+                       if (sb.st_mode & 0002) ckfputs("writeable, ", stdout);
+                       if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
+                       ckfprintf(stdout, "can't read `%s' (%s).\n",
+                           inname, strerror(errno));
+                       return;
+               }
+       }
+
+
+       /*
+        * try looking at the first HOWMANY bytes
+        */
+       if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
+               error("read failed (%s).\n", strerror(errno));
+               /*@notreached@*/
+       }
+
+       if (nbytes == 0)
+               ckfputs(iflag ? "application/x-empty" : "empty", stdout);
+       else {
+               buf[nbytes++] = '\0';   /* null-terminate it */
+               match = tryit(inname, buf, nbytes, zflag);
+       }
 
-static void    unwrap(char *fn)
+#ifdef BUILTIN_ELF
+       if (match == 's' && nbytes > 5) {
+               /*
+                * We matched something in the file, so this *might*
+                * be an ELF file, and the file is at least 5 bytes long,
+                * so if it's an ELF file it has at least one byte
+                * past the ELF magic number - try extracting information
+                * from the ELF headers that can't easily be extracted
+                * with rules in the magic file.
+                */
+               tryelf(fd, buf, nbytes);
+       }
+#endif
+
+       if (inname != stdname) {
+#ifdef RESTORE_TIME
+               /*
+                * Try to restore access, modification times if read it.
+                * This is really *bad* because it will modify the status
+                * time of the file... And of course this will affect
+                * backup programs
+                */
+# ifdef USE_UTIMES
+               struct timeval  utsbuf[2];
+               utsbuf[0].tv_sec = sb.st_atime;
+               utsbuf[1].tv_sec = sb.st_mtime;
+
+               (void) utimes(inname, utsbuf); /* don't care if loses */
+# else
+               struct utimbuf  utbuf;
+
+               utbuf.actime = sb.st_atime;
+               utbuf.modtime = sb.st_mtime;
+               (void) utime(inname, &utbuf); /* don't care if loses */
+# endif
+#endif
+               (void) close(fd);
+       }
+       (void) putchar('\n');
+}
+
+/*
+ * unwrap -- read a file of filenames, do each one.
+ */
+static void
+unwrap(char *fn)
        /*@globals fileSystem, internalState @*/
-       /*@modifies fileSystem, internalState @*/;
+       /*@modifies fileSystem, internalState @*/
+{
+       char buf[MAXPATHLEN];
+       FILE *f;
+       int wid = 0, cwid;
+
+       if (strcmp("-", fn) == 0) {
+               f = stdin;
+               wid = 1;
+       } else {
+               if ((f = fopen(fn, "r")) == NULL) {
+                       error("Cannot open `%s' (%s).\n", fn, strerror(errno));
+                       /*@notreached@*/
+               }
+
+               while (fgets(buf, MAXPATHLEN, f) != NULL) {
+                       cwid = strlen(buf) - 1;
+                       if (cwid > wid)
+                               wid = cwid;
+               }
+
+               rewind(f);
+       }
+
+       while (fgets(buf, MAXPATHLEN, f) != NULL) {
+               buf[strlen(buf)-1] = '\0';
+               process(buf, wid);
+               if(nobuffer)
+                       (void) fflush(stdout);
+       }
+
+       (void) fclose(f);
+}
+
 /*@exits@*/
-static void    usage(void)
+static void
+usage(void)
        /*@globals fileSystem @*/
-       /*@modifies fileSystem @*/;
+       /*@modifies fileSystem @*/
+{
+       (void)fprintf(stderr, USAGE, progname);
+       (void)fprintf(stderr, "Usage: %s -C [-m magic]\n", progname);
+#ifdef HAVE_GETOPT_H
+       (void)fputs("Try `file --help' for more information.\n", stderr);
+#endif
+       exit(EXIT_FAILURE);
+}
+
 #ifdef HAVE_GETOPT_H
 /*@exits@*/
-static void    help(void)
+static void
+help(void)
        /*@globals fileSystem @*/
-       /*@modifies fileSystem @*/;
+       /*@modifies fileSystem @*/
+{
+       (void) puts(
+"Usage: file [OPTION]... [FILE]...\n"
+"Determine file type of FILEs.\n"
+"\n"
+"  -m, --magic-file LIST      use LIST as a colon-separated list of magic\n"
+"                               number files\n"
+"  -z, --uncompress           try to look inside compressed files\n"
+"  -b, --brief                do not prepend filenames to output lines\n"
+"  -c, --checking-printout    print the parsed form of the magic file, use in\n"
+"                               conjunction with -m to debug a new magic file\n"
+"                               before installing it\n"
+"  -f, --files-from FILE      read the filenames to be examined from FILE\n"
+"  -i, --mime                 output mime type strings\n"
+"  -k, --keep-going           don't stop at the first match\n"
+"  -L, --dereference          causes symlinks to be followed\n"
+"  -n, --no-buffer            do not buffer output\n"
+"  -s, --special-files        treat special (block/char devices) files as\n"
+"                             ordinary ones\n"
+"      --help                 display this help and exit\n"
+"      --version              output version information and exit\n"
+);
+       exit(0);
+}
 #endif
 
-int main(int argc, char *argv[])
-       /*@globals debug, bflag, zflag, sflag, iflag, nobuffer, kflag,
-               default_magicfile, lineno, magicfile, mlist, optind, progname,
-               fileSystem, internalState @*/
-       /*@modifies argv, debug, bflag, zflag, sflag, iflag, nobuffer, kflag,
-               default_magicfile, lineno, magicfile, mlist, optind, progname,
-               fileSystem, internalState @*/;
-
 /*
  * main - parse arguments and handle options
  */
 int
 main(int argc, char **argv)
+       /*@globals debug, bflag, zflag, sflag, iflag, nobuffer, kflag,
+               default_magicfile, lineno, magicfile, mlist, optind, progname,
+               fileSystem, internalState @*/
+       /*@modifies argv, debug, bflag, zflag, sflag, iflag, nobuffer, kflag,
+               default_magicfile, lineno, magicfile, mlist, optind, progname,
+               fileSystem, internalState @*/
 {
        int c;
        int action = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0;
@@ -188,7 +384,7 @@ main(int argc, char **argv)
        magicfile = default_magicfile;
        if ((usermagic = getenv("MAGIC")) != NULL)
                magicfile = usermagic;
-       else
+       else {
                if ((home = getenv("HOME")) != NULL) {
                        if ((usermagic = malloc(strlen(home) + 8)) != NULL) {
                                (void)strcpy(usermagic, home);
@@ -199,6 +395,7 @@ main(int argc, char **argv)
                                        magicfile = usermagic;
                        }
                }
+       }
 
 #ifndef HAVE_GETOPT_H
        while ((c = getopt(argc, argv, OPTSTRING)) != -1)
@@ -206,6 +403,7 @@ main(int argc, char **argv)
        while ((c = getopt_long(argc, argv, OPTSTRING, long_options,
            &longindex)) != -1)
 #endif
+       {
                switch (c) {
 #ifdef HAVE_GETOPT_H
                case 0 :
@@ -274,6 +472,7 @@ main(int argc, char **argv)
                        errflg++;
                        /*@switchbreak@*/ break;
                }
+       }
 
        if (errflg) {
                usage();
@@ -304,279 +503,3 @@ main(int argc, char **argv)
 
        return 0;
 }
-
-
-/*
- * unwrap -- read a file of filenames, do each one.
- */
-static void
-unwrap(char *fn)
-{
-       char buf[MAXPATHLEN];
-       FILE *f;
-       int wid = 0, cwid;
-
-       if (strcmp("-", fn) == 0) {
-               f = stdin;
-               wid = 1;
-       } else {
-               if ((f = fopen(fn, "r")) == NULL) {
-                       error("Cannot open `%s' (%s).\n", fn, strerror(errno));
-                       /*@notreached@*/
-               }
-
-               while (fgets(buf, MAXPATHLEN, f) != NULL) {
-                       cwid = strlen(buf) - 1;
-                       if (cwid > wid)
-                               wid = cwid;
-               }
-
-               rewind(f);
-       }
-
-       while (fgets(buf, MAXPATHLEN, f) != NULL) {
-               buf[strlen(buf)-1] = '\0';
-               process(buf, wid);
-               if(nobuffer)
-                       (void) fflush(stdout);
-       }
-
-       (void) fclose(f);
-}
-
-
-#if 0
-/*
- * byteconv4
- * Input:
- *     from            4 byte quantity to convert
- *     same            whether to perform byte swapping
- *     big_endian      whether we are a big endian host
- */
-static int
-byteconv4(int from, int same, int big_endian)
-       /*@*/
-{
-       if (same)
-               return from;
-       else if (big_endian) {          /* lsb -> msb conversion on msb */
-               union {
-                       int i;
-                       char c[4];
-               } retval, tmpval;
-
-               tmpval.i = from;
-               retval.c[0] = tmpval.c[3];
-               retval.c[1] = tmpval.c[2];
-               retval.c[2] = tmpval.c[1];
-               retval.c[3] = tmpval.c[0];
-
-               return retval.i;
-       }
-       else
-               return ntohl(from);     /* msb -> lsb conversion on lsb */
-}
-
-/*
- * byteconv2
- * Same as byteconv4, but for shorts
- */
-static short
-byteconv2(int from, int same, int big_endian)
-       /*@*/
-{
-       if (same)
-               return from;
-       else if (big_endian) {          /* lsb -> msb conversion on msb */
-               union {
-                       short s;
-                       char c[2];
-               } retval, tmpval;
-
-               tmpval.s = (short) from;
-               retval.c[0] = tmpval.c[1];
-               retval.c[1] = tmpval.c[0];
-
-               return retval.s;
-       }
-       else
-               return ntohs(from);     /* msb -> lsb conversion on lsb */
-}
-#endif
-
-/*
- * process - process input file
- */
-void
-process(const char *inname, int wid)
-{
-       int     fd = 0;
-       static  const char stdname[] = "standard input";
-       unsigned char   buf[HOWMANY+1]; /* one extra for terminating '\0' */
-       struct stat     sb;
-       int nbytes = 0; /* number of bytes read from a datafile */
-       char match = '\0';
-
-       if (strcmp("-", inname) == 0) {
-               if (fstat(0, &sb)<0) {
-                       error("cannot fstat `%s' (%s).\n", stdname,
-                             strerror(errno));
-                       /*@notreached@*/
-               }
-               inname = stdname;
-       }
-
-       if (wid > 0 && !bflag)
-            (void) printf("%s:%*s ", inname, 
-                          (int) (wid - strlen(inname)), "");
-
-       if (inname != stdname) {
-               /*
-                * first try judging the file based on its filesystem status
-                */
-               if (fsmagic(inname, &sb) != 0) {
-                       (void) putchar('\n');
-                       return;
-               }
-
-               if ((fd = open(inname, O_RDONLY)) < 0) {
-                       /* We can't open it, but we were able to stat it. */
-                       if (sb.st_mode & 0002) ckfputs("writeable, ", stdout);
-                       if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
-                       ckfprintf(stdout, "can't read `%s' (%s).\n",
-                           inname, strerror(errno));
-                       return;
-               }
-       }
-
-
-       /*
-        * try looking at the first HOWMANY bytes
-        */
-       if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
-               error("read failed (%s).\n", strerror(errno));
-               /*@notreached@*/
-       }
-
-       if (nbytes == 0)
-               ckfputs(iflag ? "application/x-empty" : "empty", stdout);
-       else {
-               buf[nbytes++] = '\0';   /* null-terminate it */
-               match = tryit(inname, buf, nbytes, zflag);
-       }
-
-#ifdef BUILTIN_ELF
-       if (match == 's' && nbytes > 5) {
-               /*
-                * We matched something in the file, so this *might*
-                * be an ELF file, and the file is at least 5 bytes long,
-                * so if it's an ELF file it has at least one byte
-                * past the ELF magic number - try extracting information
-                * from the ELF headers that can't easily be extracted
-                * with rules in the magic file.
-                */
-               tryelf(fd, buf, nbytes);
-       }
-#endif
-
-       if (inname != stdname) {
-#ifdef RESTORE_TIME
-               /*
-                * Try to restore access, modification times if read it.
-                * This is really *bad* because it will modify the status
-                * time of the file... And of course this will affect
-                * backup programs
-                */
-# ifdef USE_UTIMES
-               struct timeval  utsbuf[2];
-               utsbuf[0].tv_sec = sb.st_atime;
-               utsbuf[1].tv_sec = sb.st_mtime;
-
-               (void) utimes(inname, utsbuf); /* don't care if loses */
-# else
-               struct utimbuf  utbuf;
-
-               utbuf.actime = sb.st_atime;
-               utbuf.modtime = sb.st_mtime;
-               (void) utime(inname, &utbuf); /* don't care if loses */
-# endif
-#endif
-               (void) close(fd);
-       }
-       (void) putchar('\n');
-}
-
-
-int
-tryit(const char *fn, unsigned char *buf, int nb, int zfl)
-{
-
-       /*
-        * The main work is done here!
-        * We have the file name and/or the data buffer to be identified. 
-        */
-
-#ifdef __EMX__
-       /*
-        * Ok, here's the right place to add a call to some os-specific
-        * routine, e.g.
-        */
-       if (os2_apptype(fn, buf, nb) == 1)
-              return 'o';
-#endif
-       /* try compression stuff */
-       if (zfl && zmagic(fn, buf, nb))
-               return 'z';
-
-       /* try tests in /etc/magic (or surrogate magic file) */
-       if (softmagic(buf, nb))
-               return 's';
-
-       /* try known keywords, check whether it is ASCII */
-       if (ascmagic(buf, nb))
-               return 'a';
-
-       /* abandon hope, all ye who remain here */
-       ckfputs(iflag ? "application/octet-stream" : "data", stdout);
-               return '\0';
-}
-
-static void
-usage(void)
-{
-       (void)fprintf(stderr, USAGE, progname);
-       (void)fprintf(stderr, "Usage: %s -C [-m magic]\n", progname);
-#ifdef HAVE_GETOPT_H
-       (void)fputs("Try `file --help' for more information.\n", stderr);
-#endif
-       exit(EXIT_FAILURE);
-}
-
-#ifdef HAVE_GETOPT_H
-static void
-help(void)
-{
-       (void) puts(
-"Usage: file [OPTION]... [FILE]...\n"
-"Determine file type of FILEs.\n"
-"\n"
-"  -m, --magic-file LIST      use LIST as a colon-separated list of magic\n"
-"                               number files\n"
-"  -z, --uncompress           try to look inside compressed files\n"
-"  -b, --brief                do not prepend filenames to output lines\n"
-"  -c, --checking-printout    print the parsed form of the magic file, use in\n"
-"                               conjunction with -m to debug a new magic file\n"
-"                               before installing it\n"
-"  -f, --files-from FILE      read the filenames to be examined from FILE\n"
-"  -i, --mime                 output mime type strings\n"
-"  -k, --keep-going           don't stop at the first match\n"
-"  -L, --dereference          causes symlinks to be followed\n"
-"  -n, --no-buffer            do not buffer output\n"
-"  -s, --special-files        treat special (block/char devices) files as\n"
-"                             ordinary ones\n"
-"      --help                 display this help and exit\n"
-"      --version              output version information and exit\n"
-);
-       exit(0);
-}
-#endif
index 6e5f77c..aa9150e 100644 (file)
@@ -23,9 +23,33 @@ FILE_RCSID("@(#)Id: is_tar.c,v 1.17 2002/07/03 18:26:38 christos Exp ")
 
 #define        isodigit(c)     ( ((c) >= '0') && ((c) <= '7') )
 
-/* Decode octal number */
-static int from_oct(int digs, char *where)
-       /*@*/;
+/*
+ * Quick and dirty octal conversion.
+ *
+ * Result is -1 if the field is invalid (all blank, or nonoctal).
+ */
+static int
+from_oct(int digs, char *where)
+       /*@*/
+{
+       int     value;
+
+       while (isspace((unsigned char)*where)) {        /* Skip spaces */
+               where++;
+               if (--digs <= 0)
+                       return -1;              /* All blank field */
+       }
+       value = 0;
+       while (digs > 0 && isodigit(*where)) {  /* Scan til nonoctal */
+               value = (value << 3) | (*where++ - '0');
+               --digs;
+       }
+
+       if (digs > 0 && *where && !isspace((unsigned char)*where))
+               return -1;                      /* Ended on non-space/nul */
+
+       return value;
+}
 
 /*
  * Return 
@@ -69,31 +93,3 @@ is_tar(unsigned char *buf, int nbytes)
 
        return 1;                       /* Old fashioned tar archive */
 }
-
-
-/*
- * Quick and dirty octal conversion.
- *
- * Result is -1 if the field is invalid (all blank, or nonoctal).
- */
-static int
-from_oct(int digs, char *where)
-{
-       int     value;
-
-       while (isspace((unsigned char)*where)) {        /* Skip spaces */
-               where++;
-               if (--digs <= 0)
-                       return -1;              /* All blank field */
-       }
-       value = 0;
-       while (digs > 0 && isodigit(*where)) {  /* Scan til nonoctal */
-               value = (value << 3) | (*where++ - '0');
-               --digs;
-       }
-
-       if (digs > 0 && *where && !isspace((unsigned char)*where))
-               return -1;                      /* Ended on non-space/nul */
-
-       return value;
-}
index 212e627..4909944 100644 (file)
 FILE_RCSID("@(#)Id: readelf.c,v 1.22 2002/07/03 18:26:38 christos Exp ")
 #endif
 
-#ifdef ELFCORE
-static void dophn_core(int class, int swap, int fd, off_t off, int num,
-               size_t size)
-       /*@globals fileSystem @*/
-       /*@modifies fileSystem @*/;
-#endif
-static void dophn_exec(int class, int swap, int fd, off_t off, int num,
-               size_t size)
-       /*@globals fileSystem @*/
-       /*@modifies fileSystem @*/;
-static void doshn(int class, int swap, int fd, off_t off, int num, size_t size)
-       /*@globals fileSystem @*/
-       /*@modifies fileSystem @*/;
-
-static uint16_t getu16(int swap, uint16_t value)
-       /*@*/;
-static uint32_t getu32(int swap, uint32_t value)
-       /*@*/;
-static uint64_t getu64(int swap, uint64_t value)
-       /*@*/;
-
 static uint16_t
 getu16(int swap, uint16_t value)
+       /*@*/
 {
        union {
                uint16_t ui;
@@ -56,6 +36,7 @@ getu16(int swap, uint16_t value)
 
 static uint32_t
 getu32(int swap, uint32_t value)
+       /*@*/
 {
        union {
                uint32_t ui;
@@ -77,6 +58,7 @@ getu32(int swap, uint32_t value)
 
 static uint64_t
 getu64(int swap, uint64_t value)
+       /*@*/
 {
        union {
                uint64_t ui;
@@ -100,39 +82,41 @@ getu64(int swap, uint64_t value)
                return value;
 }
 
-#define sh_addr                (class == ELFCLASS32            \
+#define sh_addr                (cls == ELFCLASS32              \
                         ? (void *) &sh32               \
                         : (void *) &sh64)
-#define shs_type       (class == ELFCLASS32            \
+#define shs_type       (cls == ELFCLASS32              \
                         ? getu32(swap, sh32.sh_type)   \
                         : getu32(swap, sh64.sh_type))
-#define ph_addr                (class == ELFCLASS32            \
+#define ph_addr                (cls == ELFCLASS32              \
                         ? (void *) &ph32               \
                         : (void *) &ph64)
-#define ph_type                (class == ELFCLASS32            \
+#define ph_type                (cls == ELFCLASS32              \
                         ? getu32(swap, ph32.p_type)    \
                         : getu32(swap, ph64.p_type))
-#define ph_offset      (class == ELFCLASS32            \
+#define ph_offset      (cls == ELFCLASS32              \
                         ? getu32(swap, ph32.p_offset)  \
                         : getu64(swap, ph64.p_offset))
-#define nh_size                (class == ELFCLASS32            \
+#define nh_size                (cls == ELFCLASS32              \
                         ? sizeof *nh32                 \
                         : sizeof *nh64)
-#define nh_type                (class == ELFCLASS32            \
+#define nh_type                (cls == ELFCLASS32              \
                         ? getu32(swap, nh32->n_type)   \
                         : getu32(swap, nh64->n_type))
-#define nh_namesz      (class == ELFCLASS32            \
+#define nh_namesz      (cls == ELFCLASS32              \
                         ? getu32(swap, nh32->n_namesz) \
                         : getu32(swap, nh64->n_namesz))
-#define nh_descsz      (class == ELFCLASS32            \
+#define nh_descsz      (cls == ELFCLASS32              \
                         ? getu32(swap, nh32->n_descsz) \
                         : getu32(swap, nh64->n_descsz))
-#define prpsoffsets(i) (class == ELFCLASS32            \
+#define prpsoffsets(i) (cls == ELFCLASS32              \
                         ? prpsoffsets32[i]             \
                         : prpsoffsets64[i])
 
 static void
-doshn(int class, int swap, int fd, off_t off, int num, size_t size)
+doshn(int cls, int swap, int fd, off_t off, int num, size_t size)
+       /*@globals fileSystem @*/
+       /*@modifies fileSystem @*/
 {
        Elf32_Shdr sh32;
        Elf64_Shdr sh64;
@@ -157,7 +141,9 @@ doshn(int class, int swap, int fd, off_t off, int num, size_t size)
  * otherwise it's statically linked.
  */
 static void
-dophn_exec(int class, int swap, int fd, off_t off, int num, size_t size)
+dophn_exec(int cls, int swap, int fd, off_t off, int num, size_t size)
+       /*@globals fileSystem @*/
+       /*@modifies fileSystem @*/
 {
        Elf32_Phdr ph32;
        Elf32_Nhdr *nh32 = NULL;
@@ -198,7 +184,7 @@ dophn_exec(int class, int swap, int fd, off_t off, int num, size_t size)
                        for (;;) {
                                if (offset >= bufsize)
                                        /*@innerbreak@*/ break;
-                               if (class == ELFCLASS32)
+                               if (cls == ELFCLASS32)
                                        nh32 = (Elf32_Nhdr *)&nbuf[offset];
                                else
                                        nh64 = (Elf64_Nhdr *)&nbuf[offset];
@@ -296,23 +282,23 @@ dophn_exec(int class, int swap, int fd, off_t off, int num, size_t size)
 }
 
 #ifdef ELFCORE
-/*@unchecked@*/
-size_t prpsoffsets32[] = {
+/*@unchecked@*/ /*@observer@*/
+static size_t  prpsoffsets32[] = {
        8,              /* FreeBSD */
        28,             /* Linux 2.0.36 */
        32,             /* Linux (I forget which kernel version) */
-       84,             /* SunOS 5.x */
+       84              /* SunOS 5.x */
 };
 
-/*@unchecked@*/
-size_t prpsoffsets64[] = {
-       120,            /* SunOS 5.x, 64-bit */
+/*@unchecked@*/ /*@observer@*/
+static size_t  prpsoffsets64[] = {
+       120             /* SunOS 5.x, 64-bit */
 };
 
 #define        NOFFSETS32      (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
 #define NOFFSETS64     (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
 
-#define NOFFSETS       (class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
+#define NOFFSETS       (cls == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
 
 /*
  * Look through the program headers of an executable image, searching
@@ -347,7 +333,9 @@ static const char *os_style_names[] = {
 };
 
 static void
-dophn_core(int class, int swap, int fd, off_t off, int num, size_t size)
+dophn_core(int cls, int swap, int fd, off_t off, int num, size_t size)
+       /*@globals fileSystem @*/
+       /*@modifies fileSystem @*/
 {
        Elf32_Phdr ph32;
        Elf32_Nhdr *nh32 = NULL;
@@ -385,7 +373,7 @@ dophn_core(int class, int swap, int fd, off_t off, int num, size_t size)
                for (;;) {
                        if (offset >= bufsize)
                                /*@innerbreak@*/ break;
-                       if (class == ELFCLASS32)
+                       if (cls == ELFCLASS32)
                                nh32 = (Elf32_Nhdr *)&nbuf[offset];
                        else
                                nh64 = (Elf64_Nhdr *)&nbuf[offset];
@@ -548,7 +536,7 @@ tryelf(int fd, unsigned char *buf, int nbytes)
                int32_t l;
                char c[sizeof (int32_t)];
        } u;
-       int class;
+       int cls;
        int swap;
 
        /*
@@ -569,9 +557,9 @@ tryelf(int fd, unsigned char *buf, int nbytes)
            return;
 
 
-       class = buf[4];
+       cls = buf[4];
 
-       if (class == ELFCLASS32) {
+       if (cls == ELFCLASS32) {
                Elf32_Ehdr elfhdr;
                if (nbytes <= sizeof (Elf32_Ehdr))
                        return;
@@ -583,7 +571,7 @@ tryelf(int fd, unsigned char *buf, int nbytes)
 
                if (getu16(swap, elfhdr.e_type) == ET_CORE) 
 #ifdef ELFCORE
-                       dophn_core(class, swap,
+                       dophn_core(cls, swap,
                                   fd,
                                   getu32(swap, elfhdr.e_phoff),
                                   getu16(swap, elfhdr.e_phnum), 
@@ -593,13 +581,13 @@ tryelf(int fd, unsigned char *buf, int nbytes)
 #endif
                else {
                        if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
-                               dophn_exec(class, swap,
+                               dophn_exec(cls, swap,
                                           fd,
                                           getu32(swap, elfhdr.e_phoff),
                                           getu16(swap, elfhdr.e_phnum), 
                                           getu16(swap, elfhdr.e_phentsize));
                        }
-                       doshn(class, swap,
+                       doshn(cls, swap,
                              fd,
                              getu32(swap, elfhdr.e_shoff),
                              getu16(swap, elfhdr.e_shnum),
@@ -608,7 +596,7 @@ tryelf(int fd, unsigned char *buf, int nbytes)
                return;
        }
 
-        if (class == ELFCLASS64) {
+        if (cls == ELFCLASS64) {
                Elf64_Ehdr elfhdr;
                if (nbytes <= sizeof (Elf64_Ehdr))
                        return;
@@ -620,7 +608,7 @@ tryelf(int fd, unsigned char *buf, int nbytes)
 
                if (getu16(swap, elfhdr.e_type) == ET_CORE) 
 #ifdef ELFCORE
-                       dophn_core(class, swap,
+                       dophn_core(cls, swap,
                                   fd,
 #ifdef USE_ARRAY_FOR_64BIT_TYPES
                                   getu32(swap, elfhdr.e_phoff[1]),
@@ -635,7 +623,7 @@ tryelf(int fd, unsigned char *buf, int nbytes)
                else
                {
                        if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
-                               dophn_exec(class, swap,
+                               dophn_exec(cls, swap,
                                           fd,
 #ifdef USE_ARRAY_FOR_64BIT_TYPES
                                           getu32(swap, elfhdr.e_phoff[1]),
@@ -645,7 +633,7 @@ tryelf(int fd, unsigned char *buf, int nbytes)
                                           getu16(swap, elfhdr.e_phnum), 
                                           getu16(swap, elfhdr.e_phentsize));
                        }
-                       doshn(class, swap,
+                       doshn(cls, swap,
                              fd,
 #ifdef USE_ARRAY_FOR_64BIT_TYPES
                              getu32(swap, elfhdr.e_shoff[1]),
index fd66ae9..b87e9dd 100644 (file)
@@ -32,7 +32,6 @@
 #include <time.h>
 #include <regex.h>
 
-
 #ifndef        lint
 FILE_RCSID("@(#)Id: softmagic.c,v 1.51 2002/07/03 18:26:38 christos Exp ")
 #endif /* lint */
@@ -42,185 +41,10 @@ FILE_RCSID("@(#)Id: softmagic.c,v 1.51 2002/07/03 18:26:38 christos Exp ")
 extern int kflag;
 /*@=redecl@*/
 
-static int match(struct magic *m, uint32_t nmagic,
-               unsigned char *s, int nbytes)
-       /*@globals fileSystem @*/
-       /*@modifies m, s, fileSystem @*/;
-static int mget(union VALUETYPE *p, unsigned char *s,
-               struct magic *m, int nbytes)
-       /*@globals fileSystem @*/
-       /*@modifies p, s, fileSystem @*/;
-static int mcheck(union VALUETYPE *p, struct magic *m)
-       /*@globals fileSystem @*/
-       /*@modifies fileSystem @*/;
-static int32_t mprint(union VALUETYPE *p, struct magic *m)
-       /*@globals fileSystem @*/
-       /*@modifies p, fileSystem @*/;
-static void mdebug(int32_t offset, char *str, int len)
-       /*@globals fileSystem @*/
-       /*@modifies fileSystem @*/;
-static int mconvert(union VALUETYPE *p, struct magic *m)
-       /*@globals fileSystem @*/
-       /*@modifies p, fileSystem @*/;
-
-/*
- * softmagic - lookup one file in database 
- * (already read from MAGIC by apprentice.c).
- * Passed the name and FILE * of one file to be typed.
- */
-/*ARGSUSED1*/          /* nbytes passed for regularity, maybe need later */
-int
-softmagic(unsigned char *buf, int nbytes)
-{
-       struct mlist *ml;
-
-       for (ml = mlist.next; ml != &mlist; ml = ml->next)
-               if (match(ml->magic, ml->nmagic, buf, nbytes))
-                       return 1;
-
-       return 0;
-}
-
-/*
- * Go through the whole list, stopping if you find a match.  Process all
- * the continuations of that match before returning.
- *
- * We support multi-level continuations:
- *
- *     At any time when processing a successful top-level match, there is a
- *     current continuation level; it represents the level of the last
- *     successfully matched continuation.
- *
- *     Continuations above that level are skipped as, if we see one, it
- *     means that the continuation that controls them - i.e, the
- *     lower-level continuation preceding them - failed to match.
- *
- *     Continuations below that level are processed as, if we see one,
- *     it means we've finished processing or skipping higher-level
- *     continuations under the control of a successful or unsuccessful
- *     lower-level continuation, and are now seeing the next lower-level
- *     continuation and should process it.  The current continuation
- *     level reverts to the level of the one we're seeing.
- *
- *     Continuations at the current level are processed as, if we see
- *     one, there's no lower-level continuation that may have failed.
- *
- *     If a continuation matches, we bump the current continuation level
- *     so that higher-level continuations are processed.
- */
-static int
-match(struct magic *m, uint32_t nmagic, unsigned char *s, int nbytes)
-{
-       int magindex = 0;
-       int cont_level = 0;
-       int need_separator = 0;
-       union VALUETYPE p;
-       /*@only@*/
-       static int32_t *tmpoff = NULL;
-       static size_t tmplen = 0;
-       int32_t oldoff = 0;
-       int returnval = 0; /* if a match is found it is set to 1*/
-       int firstline = 1; /* a flag to print X\n  X\n- X */
-
-       if (tmpoff == NULL)
-               if ((tmpoff = (int32_t *) malloc(tmplen = 20)) == NULL)
-                       error("out of memory\n");
-
-       for (magindex = 0; magindex < nmagic; magindex++) {
-               /* if main entry matches, print it... */
-               if (!mget(&p, s, &m[magindex], nbytes) ||
-                   !mcheck(&p, &m[magindex])) {
-                           /* 
-                            * main entry didn't match,
-                            * flush its continuations
-                            */
-                           while (magindex < nmagic &&
-                                  m[magindex + 1].cont_level != 0)
-                                  magindex++;
-                           continue;
-               }
-
-               if (! firstline) { /* we found another match */
-                       /* put a newline and '-' to do some simple formatting*/
-                       printf("\n- ");
-               }
-
-               tmpoff[cont_level] = mprint(&p, &m[magindex]);
-               /*
-                * If we printed something, we'll need to print
-                * a blank before we print something else.
-                */
-               if (m[magindex].desc[0])
-                       need_separator = 1;
-               /* and any continuations that match */
-               if (++cont_level >= tmplen)
-                       if ((tmpoff = (int32_t *) realloc(tmpoff,
-                                                      tmplen += 20)) == NULL)
-                               error("out of memory\n");
-               while (m[magindex+1].cont_level != 0 && 
-                      ++magindex < nmagic) {
-                       if (cont_level >= m[magindex].cont_level) {
-                               if (cont_level > m[magindex].cont_level) {
-                                       /*
-                                        * We're at the end of the level
-                                        * "cont_level" continuations.
-                                        */
-                                       cont_level = m[magindex].cont_level;
-                               }
-                               if (m[magindex].flag & OFFADD) {
-                                       oldoff=m[magindex].offset;
-                                       m[magindex].offset +=
-                                           tmpoff[cont_level-1];
-                               }
-                               if (mget(&p, s, &m[magindex], nbytes) &&
-                                   mcheck(&p, &m[magindex])) {
-                                       /*
-                                        * This continuation matched.
-                                        * Print its message, with
-                                        * a blank before it if
-                                        * the previous item printed
-                                        * and this item isn't empty.
-                                        */
-                                       /* space if previous printed */
-                                       if (need_separator
-                                          && (m[magindex].nospflag == 0)
-                                          && (m[magindex].desc[0] != '\0')
-                                          ) {
-                                               (void) putchar(' ');
-                                               need_separator = 0;
-                                       }
-                                       tmpoff[cont_level] =
-                                           mprint(&p, &m[magindex]);
-                                       if (m[magindex].desc[0])
-                                               need_separator = 1;
-
-                                       /*
-                                        * If we see any continuations
-                                        * at a higher level,
-                                        * process them.
-                                        */
-                                       if (++cont_level >= tmplen)
-                                               if ((tmpoff = 
-                                                   (int32_t *) realloc(tmpoff,
-                                                   tmplen += 20)) == NULL)
-                                                       error("out of memory\n");
-                               }
-                               if (m[magindex].flag & OFFADD) {
-                                        m[magindex].offset = oldoff;
-                               }
-                       }
-               }
-               firstline = 0;
-               returnval = 1;
-               if (!kflag) {
-                       return 1; /* don't keep searching */
-               }                       
-       }
-       return returnval;  /* This is hit if -k is set or there is no match */
-}
-
 static int32_t
 mprint(union VALUETYPE *p, struct magic *m)
+       /*@globals fileSystem @*/
+       /*@modifies p, fileSystem @*/
 {
        uint32_t v;
        int32_t t=0 ;
@@ -298,6 +122,8 @@ mprint(union VALUETYPE *p, struct magic *m)
  */
 static int
 mconvert(union VALUETYPE *p, struct magic *m)
+       /*@globals fileSystem @*/
+       /*@modifies p, fileSystem @*/
 {
        switch (m->type) {
        case BYTE:
@@ -566,6 +392,8 @@ mconvert(union VALUETYPE *p, struct magic *m)
 
 static void
 mdebug(int32_t offset, char *str, int len)
+       /*@globals fileSystem @*/
+       /*@modifies fileSystem @*/
 {
        (void) fprintf(stderr, "mget @%d: ", offset);
        showstr(stderr, (char *) str, len);
@@ -575,6 +403,8 @@ mdebug(int32_t offset, char *str, int len)
 
 static int
 mget(union VALUETYPE *p, unsigned char *s, struct magic *m, int nbytes)
+       /*@globals fileSystem @*/
+       /*@modifies p, s, fileSystem @*/
 {
        int32_t offset = m->offset;
 
@@ -952,6 +782,8 @@ mget(union VALUETYPE *p, unsigned char *s, struct magic *m, int nbytes)
 
 static int
 mcheck(union VALUETYPE *p, struct magic *m)
+       /*@globals fileSystem @*/
+       /*@modifies fileSystem @*/
 {
        uint32_t l = m->value.l;
        uint32_t v;
@@ -1131,3 +963,160 @@ mcheck(union VALUETYPE *p, struct magic *m)
 
        return matched;
 }
+
+/*
+ * Go through the whole list, stopping if you find a match.  Process all
+ * the continuations of that match before returning.
+ *
+ * We support multi-level continuations:
+ *
+ *     At any time when processing a successful top-level match, there is a
+ *     current continuation level; it represents the level of the last
+ *     successfully matched continuation.
+ *
+ *     Continuations above that level are skipped as, if we see one, it
+ *     means that the continuation that controls them - i.e, the
+ *     lower-level continuation preceding them - failed to match.
+ *
+ *     Continuations below that level are processed as, if we see one,
+ *     it means we've finished processing or skipping higher-level
+ *     continuations under the control of a successful or unsuccessful
+ *     lower-level continuation, and are now seeing the next lower-level
+ *     continuation and should process it.  The current continuation
+ *     level reverts to the level of the one we're seeing.
+ *
+ *     Continuations at the current level are processed as, if we see
+ *     one, there's no lower-level continuation that may have failed.
+ *
+ *     If a continuation matches, we bump the current continuation level
+ *     so that higher-level continuations are processed.
+ */
+static int
+match(struct magic *m, uint32_t nmagic, unsigned char *s, int nbytes)
+       /*@globals fileSystem @*/
+       /*@modifies m, s, fileSystem @*/
+{
+       int magindex = 0;
+       int cont_level = 0;
+       int need_separator = 0;
+       union VALUETYPE p;
+       /*@only@*/
+       static int32_t *tmpoff = NULL;
+       static size_t tmplen = 0;
+       int32_t oldoff = 0;
+       int returnval = 0; /* if a match is found it is set to 1*/
+       int firstline = 1; /* a flag to print X\n  X\n- X */
+
+       if (tmpoff == NULL)
+               if ((tmpoff = (int32_t *) malloc(tmplen = 20)) == NULL)
+                       error("out of memory\n");
+
+       for (magindex = 0; magindex < nmagic; magindex++) {
+               /* if main entry matches, print it... */
+               if (!mget(&p, s, &m[magindex], nbytes) ||
+                   !mcheck(&p, &m[magindex])) {
+                           /* 
+                            * main entry didn't match,
+                            * flush its continuations
+                            */
+                           while (magindex < nmagic &&
+                                  m[magindex + 1].cont_level != 0)
+                                  magindex++;
+                           continue;
+               }
+
+               if (! firstline) { /* we found another match */
+                       /* put a newline and '-' to do some simple formatting*/
+                       printf("\n- ");
+               }
+
+               tmpoff[cont_level] = mprint(&p, &m[magindex]);
+               /*
+                * If we printed something, we'll need to print
+                * a blank before we print something else.
+                */
+               if (m[magindex].desc[0])
+                       need_separator = 1;
+               /* and any continuations that match */
+               if (++cont_level >= tmplen)
+                       if ((tmpoff = (int32_t *) realloc(tmpoff,
+                                                      tmplen += 20)) == NULL)
+                               error("out of memory\n");
+               while (m[magindex+1].cont_level != 0 && 
+                      ++magindex < nmagic) {
+                       if (cont_level >= m[magindex].cont_level) {
+                               if (cont_level > m[magindex].cont_level) {
+                                       /*
+                                        * We're at the end of the level
+                                        * "cont_level" continuations.
+                                        */
+                                       cont_level = m[magindex].cont_level;
+                               }
+                               if (m[magindex].flag & OFFADD) {
+                                       oldoff=m[magindex].offset;
+                                       m[magindex].offset +=
+                                           tmpoff[cont_level-1];
+                               }
+                               if (mget(&p, s, &m[magindex], nbytes) &&
+                                   mcheck(&p, &m[magindex])) {
+                                       /*
+                                        * This continuation matched.
+                                        * Print its message, with
+                                        * a blank before it if
+                                        * the previous item printed
+                                        * and this item isn't empty.
+                                        */
+                                       /* space if previous printed */
+                                       if (need_separator
+                                          && (m[magindex].nospflag == 0)
+                                          && (m[magindex].desc[0] != '\0')
+                                          ) {
+                                               (void) putchar(' ');
+                                               need_separator = 0;
+                                       }
+                                       tmpoff[cont_level] =
+                                           mprint(&p, &m[magindex]);
+                                       if (m[magindex].desc[0])
+                                               need_separator = 1;
+
+                                       /*
+                                        * If we see any continuations
+                                        * at a higher level,
+                                        * process them.
+                                        */
+                                       if (++cont_level >= tmplen)
+                                               if ((tmpoff = 
+                                                   (int32_t *) realloc(tmpoff,
+                                                   tmplen += 20)) == NULL)
+                                                       error("out of memory\n");
+                               }
+                               if (m[magindex].flag & OFFADD) {
+                                        m[magindex].offset = oldoff;
+                               }
+                       }
+               }
+               firstline = 0;
+               returnval = 1;
+               if (!kflag) {
+                       return 1; /* don't keep searching */
+               }                       
+       }
+       return returnval;  /* This is hit if -k is set or there is no match */
+}
+
+/*
+ * softmagic - lookup one file in database 
+ * (already read from MAGIC by apprentice.c).
+ * Passed the name and FILE * of one file to be typed.
+ */
+int
+softmagic(unsigned char *buf, int nbytes)
+{
+       struct mlist *ml;
+
+       for (ml = mlist.next; ml != &mlist; ml = ml->next)
+               if (match(ml->magic, ml->nmagic, buf, nbytes))
+                       return 1;
+
+       return 0;
+}