]> granicus.if.org Git - file/commitdiff
Initial revision
authorIan Darwin <ian@darwinsys.com>
Sun, 23 Aug 1987 19:51:03 +0000 (19:51 +0000)
committerIan Darwin <ian@darwinsys.com>
Sun, 23 Aug 1987 19:51:03 +0000 (19:51 +0000)
13 files changed:
LEGAL.NOTICE [new file with mode: 0644]
README [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/PORTING [new file with mode: 0644]
src/apprentice.c [new file with mode: 0644]
src/ascmagic.c [new file with mode: 0644]
src/file.c [new file with mode: 0644]
src/file.h [new file with mode: 0644]
src/fsmagic.c [new file with mode: 0644]
src/is_tar.c [new file with mode: 0644]
src/names.h [new file with mode: 0644]
src/print.c [new file with mode: 0644]
src/softmagic.c [new file with mode: 0644]

diff --git a/LEGAL.NOTICE b/LEGAL.NOTICE
new file mode 100644 (file)
index 0000000..12e5645
--- /dev/null
@@ -0,0 +1,29 @@
+Written by Ian Darwin,
+Box 603, Station F, Toronto, CANADA M4Y 2L8.
+Uucp: {utzoo|ihnp4}!darwin!ian.
+Internet: ian@sq.com (proposed).
+
+Copyright (c) 1986, Ian Darwin. All rights reserved, except as noted below.
+
+This program may be used for its intended purpose on any computer system.
+
+       *** Unmodified copies ***
+of the source may be freely copied for this purpose
+provided this notice is maintained.
+       *** Redistribution of modified source copies is prohibited; ***
+distribute the original source with your changes as diff listings
+or as RCS archives (or SCCS if you can find a way to mail them).
+Please send me your changes; if I like 'em I'll incorporate them.
+
+Binary copies may also be distributed; if they are derived from
+modified source then you must inform every recipient of the
+origin of the program and that the source is available from the author.
+
+The module is_tar.c is by Fred Blonder at the University of Maryland
+and appeared as part of his fixes to the UNIX file(1) program
+in net.sources; it is not covered by the above restrictions.
+
+The module strtok.c is by Henry Spencer at the University of Toronto
+and is not covered by the above restrictions.
+
+The module strtol is a quick hack and is not covered by the above.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..1dca6f3
--- /dev/null
+++ b/README
@@ -0,0 +1,43 @@
+** ALPHA TEST RELEASE **
+You are getting this ahead of the rest of the world because
+you need it or because I like you or something. Please do not
+forward it to anybody yet. The "official" version will appear
+in mod.sources at a theater or USENET site near you in time
+for the Christmas rush. 
+
+** File(1) Command **
+This is Ian Darwin's (copyright but distributable unmodified)
+file(1) command. It follows the USG (Sys V) model of the file
+command, rather than the Research (V7) version. That is, there
+is a file (/etc/magic) that contains much of the ritual information
+that is the source of this program's power. It knows a little
+more magic (including tar archives) than System V; the /etc/magic
+parsing seems to be compatible with the (poorly documented)
+System V /etc/magic format. 
+
+In addition, the /etc/magic file is built from a subdirectory
+for easier maintenance. At the instigation of John Gilmore,
+I will act as a clearinghouse for magic numbers assigned to
+all sorts of whacko data files that are in reasonable circulation.
+Send your whacko magic numbers, in file(5) format please(!), to the 
+address above.
+
+LEGAL.NOTICE - read this first.
+README - read this second.
+Makefile - read this third.
+TODO - read this last (sigh).
+apprentice.c - parses /etc/magic to learn magic
+ascmagic.c - third & last set of tests, based on hardwired assumptions.
+core - not included in distribution
+debug.c - includes -c printout routine
+file.1 - man page
+file.c - main program
+file.h - fairly standard header file
+fsmagic.c - first set of tests the program runs, based on filesystem info
+is_tar.c - knows about tarchives (courtesy of Fred Blonder, U Maryland)
+magdir - directory of /etc/magic pieces
+names.h - header file for ascmagic.c
+softmagic.c - 2nd set of tests, based on /etc/magic
+strtol.c - in case you need it
+strtol.tst.c - in case you need to test it
+
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..2d73011
--- /dev/null
@@ -0,0 +1,41 @@
+# Makefile for file(1) cmd. Copyright (c) Darwin 86/09/01 - see LEGAL.NOTICE.
+
+DEFS = # -Dvoid=int
+CFLAGS = -O $(DEFS)
+OTHERS = darwin!ian    # people to whom we mail updates
+FILE=/usr/bin/file.sun # old version or system-provided command, for comparison
+
+# There are no system-dependant configuration options (except maybe CFLAGS);
+# you may delete some of LOCALSRCS and LOCALOBJS if they're in your C library.
+LOCALSRCS = strtol.c strtok.c
+SRCS = file.c apprentice.c fsmagic.c softmagic.c ascmagic.c is_tar.c \
+       print.c $(LOCALSRCS)
+LOCALOBJS = strtol.o strtok.o
+OBJS = file.o apprentice.o fsmagic.o softmagic.o ascmagic.o is_tar.o \
+       print.o $(LOCALOBJS)
+
+ALLSRC = LEGAL.NOTICE README PORTING TODO $(SRCS) *.h \
+       Makefile file.[15] magdir tst/Makefile
+
+run:           file magic
+               time $(FILE) -m ./magic * tst/* >/tmp/t1
+               time ./file -m ./magic * tst/* >/tmp/t2
+               diff -b /tmp/t[12]
+
+file:          $(OBJS)
+               cc $(CFLAGS) $(OBJS) -o $@
+lint:          $(SRCS)
+               lint -ha $(DEFS) $(SRCS)
+magic:         magdir
+               cat magdir/[a-z]* >$@ # exclude RCS or SCCS dirs
+
+ascmagic.o:    names.h
+
+apprentice.o ascmagic.o file.o fsmagic.o print.o softmagic.o: file.h
+
+dist:          $(ALLSRC)
+               (echo mkdir tst; bundle $(ALLSRC)) | \
+                       mailx -s 'semi-public-domain file(1)' $(OTHERS)
+update:                $(ALLSRC)
+               (echo mkdir tst; bundle $?; echo touch $@) | mail $(OTHERS)
+               touch $@
diff --git a/src/PORTING b/src/PORTING
new file mode 100644 (file)
index 0000000..1eacce7
--- /dev/null
@@ -0,0 +1,28 @@
+Portability of the new file(1) command.
+
+Obviously if you are running the old Ritchie compiler or
+something else that doesn't know about void, you will have
+to un-comment-out the definition of `void=int' in the Makefile.
+
+I had hoped to be able to make a file command that
+didn't have any system-dependant #ifdefs, no special libraries,
+etc., etc. Well, System V shot me down. They moved the definition
+of major() and minor() out of <sys/types.h> into <sys/sysmacros.h>.
+So, if major isn't defined after including types.h, I automatically
+include sys/sysmacros.h. If you have a system in which neither
+types.h nor sysmacros.h defines `major', you will get a compilation
+error in trying to compile a warning message. Please do the following:
+       1) change the appropriate (2nd) #include at the start of 
+               fsmagic.c
+and    2) let me know the name of the system, the release number,
+          and the name of the header file that *does* include
+          this "standard" definition.
+
+Other than this, there should be no portability problems,
+but one never knows these days. Please let me know of any
+other problems you find porting to a UNIX system. I don't much
+care about non-UNIX systems but will collect magic numbers
+for them.
+
+Ian Darwin
+Toronto, Canada
diff --git a/src/apprentice.c b/src/apprentice.c
new file mode 100644 (file)
index 0000000..9b5d15e
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * make one pass through /etc/magic, reading it into core
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "file.h"
+
+#define MAXSTR         500
+#define        EATAB {while (isascii(*l) && *l == '\t')  ++l;}
+
+extern char *progname;
+extern char *magicfile;
+extern int debug, check;       /* options */
+extern int nmagic;             /* number of valid magic[]s */
+extern long strtol();
+
+struct magic magic[MAXMAGIS];
+
+apprentice(fn)
+char *fn;
+{
+       FILE *f;
+       char line[MAXSTR+1];
+
+       f = fopen(fn, "r");
+       if (f==NULL) {
+               (void) fprintf(stderr, "%s: can't read magic file %s\n",
+               progname, fn);
+               exit(1);
+       }
+
+       /* parse it */
+       if (check)      /* print silly verbose header for USG compat. */
+               (void) printf("cont\toffset\ttype\topcode\tvalue\tdesc\n");
+       while (fgets(line, MAXSTR, f) != NULL) {
+               if (line[0]=='#')
+                       continue;
+               line[strlen(line)-1] = '\0'; /* nuke newline */
+               (void) parse(line, &nmagic);
+       }
+
+       (void) fclose(f);
+}
+
+/*
+ * parse one line from magic file, put into magic[index++] if valid
+ */
+
+
+parse(l, ndx)
+char *l;
+int *ndx;
+{
+       int i = 0, nd = *ndx;
+       static int warned = 0;
+       struct magic *m;
+
+       if (nd+1 >= MAXMAGIS){
+               if (warned++ == 0)
+                       warning("magic tab overflow - increase MAXMAGIS beyond %d in file/apprentice.c\n", MAXMAGIS);
+               return 0;
+       }
+       m = &magic[*ndx];
+
+       if (*l == '>') {
+               ++l;            /* step over */
+               m->contflag = 1;
+       } else
+               m->contflag = 0;
+
+       /* get offset, then skip over it */
+       m->offset = atoi(l);
+       while (isascii(*l) && isdigit(*l))
+               ++l;
+       EATAB;
+
+#define NBYTE 4
+#define NSHORT 5
+#define NLONG 4
+#define NSTRING 6
+       /* get type, skip it */
+       if (strncmp(l, "byte", NBYTE)==0) {
+               m->type = BYTE;
+               l += NBYTE;
+       } else if (strncmp(l, "short", NSHORT)==0) {
+               m->type = SHORT;
+               l += NSHORT;
+       } else if (strncmp(l, "long", NLONG)==0) {
+               m->type = LONG;
+               l += NLONG;
+       } else if (strncmp(l, "string", NSTRING)==0) {
+               m->type = STRING;
+               l += NSTRING;
+       } else {
+               warning("type %s invalid\n", l);
+               return 0;
+       }
+       EATAB;
+
+       if (*l == '>' || *l == '&' || *l == '=') {
+               m->reln = *l;
+               ++l;
+       } else
+               m->reln = '=';
+       EATAB;
+
+/* TODO finish this macro and start using it! */
+#define offsetcheck {if (offset > HOWMANY-1) warning("offset too big"); }
+       switch(m->type) {
+       case BYTE:
+               m->value.l = strtol(l,&l,0);
+               break;
+       case SHORT:
+               m->value.l = strtol(l,&l,0);
+               break;
+       case LONG:
+               m->value.l = strtol(l,&l,0);
+               break;
+       case STRING:
+               /* TODO check return from sscanf (system dependant?) */
+               (void) sscanf(l, "%[^\t]", m->value.s);
+               l += strlen(m->value.s);
+               break;
+       default:
+               warning("can't happen: m->type=%d\n", m->type);
+       }
+
+       /*
+        * now get last part - the description
+        */
+       EATAB;
+       while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
+               /* NULLBODY */;
+
+       if (check) {
+               mdump(m);
+       }
+       ++(*ndx);               /* make room for next */
+       return 1;
+}
+
diff --git a/src/ascmagic.c b/src/ascmagic.c
new file mode 100644 (file)
index 0000000..9768234
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Ascii magic -- file types that we know based on keywords
+ * that can appear anywhere in the file.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "file.h"
+char ckfmsg[] = "write error on output";
+#include "names.h"
+
+                       /* an optimisation over plain strcmp() */
+#define        STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
+
+ascmagic(buf)
+register char  *buf;
+{
+       register int i;
+       char    *s, *strtok(), *token;
+       register struct names *p;
+       extern int nbytes;
+       short has_escapes = 0;
+
+       /* these are easy, do them first */
+
+       /*
+        * for troff, look for . + letter + letter;
+        * this must be done to disambiguate tar archives' ./file
+        * and other trash from real troff input.
+        */
+       if (*buf == '.' && 
+               isascii(*(buf+1)) && isalnum(*(buf+1)) &&
+               isascii(*(buf+2)) && isalnum(*(buf+2))){
+               ckfputs("troff or preprocessor input text", stdout);
+               return 1;
+       }
+       if ((*buf == 'c' || *buf == 'C') && 
+           isascii(*(buf + 1)) && isspace(*(buf + 1))) {
+               ckfputs("fortran program text", stdout);
+               return 1;
+       }
+
+       /* look for tokens from names.h - this is expensive! */
+       s = buf;
+       while ((token = strtok(s, " \t\n\r\f")) != NULL) {
+               s = NULL;       /* make strtok() keep on tokin' */
+               for (p = names; p < names + NNAMES; p++) {
+                       if (STREQ(p->name, token)) {
+                               ckfputs(types[p->type], stdout);
+                               return 1;
+                       }
+               }
+       }
+
+       if (is_tar(buf)) {
+               ckfputs("tar archive", stdout);
+               return 1;
+       }
+
+       for (i = 0; i < nbytes; i++) {
+               if (!isascii(*(buf+i)))
+                       return 0;       /* not all ascii */
+               if (*(buf+i) == '\033') /* ascii ESCAPE */
+                       has_escapes ++;
+       }
+
+       /* all else fails, but it is ascii... */
+       if (has_escapes){
+               ckfputs("ascii text (with escape sequences)", stdout);
+               }
+       else {
+               ckfputs("ascii text", stdout);
+               }
+       return 1;
+}
+
+
diff --git a/src/file.c b/src/file.c
new file mode 100644 (file)
index 0000000..66cb4cb
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * file - find type of a file or files
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "file.h"
+
+#define USAGE          "usage: %s [-f file] [-m magicfile] file...\n"
+
+extern char *ckfmsg;
+int check = 0,         /* check format of magic file */
+       debug = 0,      /* huh? */
+       nbytes = 0,     /* number of bytes read from a datafile */
+       nmagic = 0;     /* number of valid magic[]s */
+FILE *efopen();
+char *magicfile = "/etc/magic";        /* where magic be found */
+char *progname;
+struct stat statbuf;
+struct utimbuf {       /* for utime(2), belongs in a .h file */
+       time_t actime;  /* access time */
+       time_t modtime; /* modification time */
+};
+
+/*
+ * main - parse arguments and handle options
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       int c;
+       int errflg = 0;
+       extern int optind;
+       extern char *optarg;
+
+       progname = argv[0];
+
+       while ((c = getopt(argc, argv, "cdf:m:")) != EOF)
+               switch (c) {
+               case 'c':
+                       ++check;
+                       break;
+               case 'd':
+                       ++debug;
+                       break;
+               case 'f':
+                       unwrap(optarg);
+                       break;
+               case 'm':
+                       magicfile = optarg;
+                       break;
+               case '?':
+               default:
+                       errflg++;
+                       break;
+               }
+       if (errflg) {
+               (void) fprintf(stderr, USAGE, progname);
+               exit(2);
+       }
+
+       apprentice(magicfile);
+
+       if (optind == argc)
+               (void)fprintf(stderr, USAGE, progname);
+       else
+               for (; optind < argc; optind++)
+                       process(argv[optind]);
+
+       exit(0);
+}
+
+/*
+ * unwrap -- read a file of filenames, do each one.
+ */
+unwrap(fn)
+char *fn;
+{
+#define FILENAMELEN 128
+       char buf[FILENAMELEN];
+       FILE *f;
+
+       if ((f = fopen(fn, "r")) == NULL)
+               (void) fprintf(stderr, "%s: file %s unreadable\n",
+                       progname, fn);
+       else {
+               while (fgets(buf, FILENAMELEN, f) != NULL) {
+                       buf[strlen(buf)-1] = '\0';
+                       process(buf);
+               }
+               (void) fclose(f);
+       }
+}
+
+/*
+ * process - process input file
+ */
+process(inname)
+char   *inname;
+{
+       int     fd;
+       char    buf[HOWMANY];
+       struct utimbuf utbuf;
+
+       (void) printf("%s:\t", inname);
+
+       /*
+        * first try judging the file based on its filesystem status
+        * Side effect: fsmagic updates global data `statbuf'.
+        */
+       if (fsmagic(inname) != 0) {
+               /*NULLBODY*/;
+       } else if ((fd = open(inname, 0)) < 0) {
+               warning("can't open for reading");
+       } else {
+               /*
+                * try looking at the first HOWMANY bytes
+                */
+               if ((nbytes = read(fd, buf, HOWMANY)) == -1)
+                       warning("read failed");
+               /*
+                * try tests in /etc/magic (or surrogate magic file
+                */
+               if (softmagic(buf) == 1)
+                       /*NULLBODY*/;
+               else if (ascmagic(buf) == 1)
+                       /*
+                        * try known keywords, check for ascii-ness too.
+                        */
+                       /*NULLBODY*/;
+               else {
+                       /*
+                        * abandon hope, all ye who remain here
+                        */
+                       ckfputs("data", stdout);
+               }
+               /*
+                * Restore access, modification times if we read the file.
+                */
+               utbuf.actime = statbuf.st_atime;
+               utbuf.modtime = statbuf.st_mtime;
+               (void) utime(inname, &utbuf); /* don't care if we lack perms */
+               (void) close(fd);
+       }
+
+       (void) putchar('\n');
+}
+
+
diff --git a/src/file.h b/src/file.h
new file mode 100644 (file)
index 0000000..d15bfd2
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * definitions for file(1) program:
+ */
+
+#define HOWMANY        1024            /* how much of the file to look at */
+#define MAXMAGIS 250           /* max entries in /etc/magic */
+#define MAXDESC        50              /* max leng of text description */
+#define MAXstring 32           /* max leng of "string" types */
+#define ckfputs(str,fil) {if (fputs(str,fil)==EOF) error(ckfmsg,"");}
+
+struct magic {
+       short contflag;         /* 1 if '>0' appears */
+       long offset;            /* offset to magic number */
+       char reln;              /* relation (0=.eq, '>'=gt, etc) */
+       short type;             /* int, short, long or string. */
+#define                        BYTE    1
+#define                                SHORT   2
+#define                                LONG    4
+#define                                STRING  5
+       union VALUETYPE {
+               char b;
+               short h;
+               long l;
+               char s[MAXstring];
+       } value;                /* either number or string */
+       char desc[MAXDESC];     /* description */
+};
+
+extern void error(), exit();
diff --git a/src/fsmagic.c b/src/fsmagic.c
new file mode 100644 (file)
index 0000000..541a354
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * magic based on mode of file - directory, special files, etc.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifndef        major                   /* if `major' not defined in types.h, */
+#include <sys/sysmacros.h>     /* try this one. */
+#endif
+#ifndef        major
+               /* If cc tries to compile this, read and act on it. */
+               /* On most systems cpp will discard it automatically */
+               Congratulations, you have found a portability bug.
+               Please grep /usr/include/sys and edit the above #include 
+               to point at the file that defines the `major' macro.
+#endif /*major*/
+#include <sys/stat.h>
+#include "file.h"
+
+#define USAGE          "usage: %s [-f file] [-m magicfile] file...\n"
+
+extern char *progname;
+extern char *ckfmsg, *magicfile;
+extern int debug;
+extern FILE *efopen();
+
+fsmagic(fn)
+char *fn;
+{
+       extern struct stat statbuf;
+
+       /*
+        * Fstat is cheaper but fails for files you don't have read perms on.
+        * On 4.2BSD and similar systems, use lstat() so identify symlinks.
+        */
+#ifdef S_IFLNK
+       if (lstat(fn, &statbuf) <0)
+#else
+       if (stat(fn, &statbuf) <0)
+#endif
+               {
+                       warning("can't stat");
+                       return -1;
+               }
+       switch (statbuf.st_mode & S_IFMT) {
+       case S_IFDIR:
+               ckfputs("directory", stdout);
+               return 1;
+       case S_IFCHR:
+               (void) printf("character special (%d/%d)",
+                       major(statbuf.st_rdev), minor(statbuf.st_rdev));
+               return 1;
+       case S_IFBLK:
+               (void) printf("block special (%d/%d)",
+                       major(statbuf.st_rdev), minor(statbuf.st_rdev));
+               return 1;
+       /* TODO add code to handle V7 MUX and Blit MUX files */
+#ifdef S_IFIFO
+       case S_IFIFO:
+               ckfputs("fifo (named pipe)", stdout);
+               return 1;
+#endif
+#ifdef S_IFLNK
+       case S_IFLNK:
+               ckfputs("symbolic link", stdout);
+               return 1;
+#endif
+#ifdef S_IFSOCK
+       case S_IFSOCK:
+               ckfputs("socket", stdout);
+               return 1;
+#endif
+       case S_IFREG:
+               break;
+       default:
+               warning("invalid st_mode %d in statbuf!", statbuf.st_mode);
+       }
+
+       /*
+        * regular file, check next possibility
+        */
+       if (statbuf.st_size == 0) {
+               ckfputs("empty", stdout);
+               return 1;
+       }
+       return 0;
+}
+
diff --git a/src/is_tar.c b/src/is_tar.c
new file mode 100644 (file)
index 0000000..7f84062
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * istar() - see if it is a tar file. Found in code written by
+ *     Fred Blonder (301) 454-7690
+ *     harpo!seismo!umcp-cs!fred
+ *     Fred@Maryland.ARPA
+ *     Net.sources, <9@gyre.uucp>, October 1983
+ * I changed the calling sequence, added a cast or two, and ran through cb -sj.
+ */
+
+is_tar(buf)    /* Is it a tar file? */
+char *buf;
+{
+       /* This stuff is copied from tar.c. */
+#define TBLOCK 512
+#define NAMSIZ 100
+       register struct header {
+               char    name[NAMSIZ];
+               char    mode[8];
+               char    uid[8];
+               char    gid[8];
+               char    size[12];
+               char    mtime[12];
+               char    chksum[8];
+               char    linkflag;
+               char    linkname[NAMSIZ];
+       };
+       register comp_chksum;
+       register char   *cp;
+       int     header_chksum;
+
+       /* Compute checksum */
+       comp_chksum = 0;
+       for (cp = buf; cp < &buf[TBLOCK]; cp++)
+               comp_chksum += (cp < ((struct header *)buf)->chksum
+                    || cp >= &((struct header *)buf)->chksum[8]) ? 
+                   *cp : ' ';
+
+       /* Convert checksum field to integer */
+       (void) sscanf(((struct header *)buf)->chksum, "%o", &header_chksum);
+
+       return (comp_chksum == header_chksum); /* Is checksum correct? */
+}
+
+
diff --git a/src/names.h b/src/names.h
new file mode 100644 (file)
index 0000000..d7499f3
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Names.h - names and types used by ascmagic in file(1).
+ * These tokens are here because they can appear anywhere in
+ * the first HOWMANY bytes, while tokens in /etc/magic must
+ * appear at fixed offsets into the file. Don't make HOWMANY
+ * too high unless you have a very fast CPU.
+ */
+
+/* these types are used to index the table 'types': keep em in sync! */
+#define L_C    0               /* first and foremost on UNIX */
+#define        L_FORT  1               /* the oldest one */
+#define L_MAKE 2               /* Makefiles */
+#define L_PLI  3               /* PL/1 */
+#define L_MACH 4               /* some kinda assembler */
+#define L_ENG  5               /* English */
+#define        L_PAS   6               /* Pascal */
+
+char *types[] = {
+       "c program text",
+       "fortran program text",
+       "makefile commands text" ,
+       "pl/1 (blech) program text",
+       "assembler (blech) program text",
+       "english text",
+       "pascal program text",
+       "can't happen error on names.h/types",
+       0};
+
+struct names {
+       char *name;
+       short type;
+} names[] = {
+       /* These must be sorted by eye for optimal hit rate */
+       /* Add to this list only after substantial meditation */
+       {"/*",          L_C},
+       {"#include",    L_C},
+       {"char",        L_C},
+       {"The",         L_ENG},
+       {"double",      L_C},
+       {"extern",      L_C},
+       {"float",       L_C},
+       {"real",        L_C},
+       {"struct",      L_C},
+       {"union",       L_C},
+       {"CFLAGS",      L_MAKE},
+       {"LDFLAGS",     L_MAKE},
+       {"all:",        L_MAKE},
+       {".PRECIOUS",   L_MAKE},
+       {"subroutine",  L_FORT},
+       {"function",    L_FORT},
+       {"block",       L_FORT},
+       {"common",      L_FORT},
+       {"dimension",   L_FORT},
+       {"integer",     L_FORT},
+       {"data",        L_FORT},
+       {".ascii",      L_MACH},
+       {".asciiz",     L_MACH},
+       {".byte",       L_MACH},
+       {".even",       L_MACH},
+       {".globl",      L_MACH},
+       {"clr",         L_MACH},
+       {"(input,",     L_PAS},
+       {"dcl",         L_PLI},
+       0};
+#define NNAMES ((sizeof(names)/sizeof(struct names)) - 1)
diff --git a/src/print.c b/src/print.c
new file mode 100644 (file)
index 0000000..0226e25
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Debugging printout routines
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include "file.h"
+
+#define MAXSTR         500
+
+extern char *progname;
+extern char *magicfile;
+extern int debug, nmagic;      /* number of valid magic[]s */
+
+mdump(m)
+struct magic *m;
+{
+       (void) printf("%d\t%d\t%d\t%c\t",
+               m->contflag,
+               m->offset,
+               m->type,
+               m->reln,
+               0);
+       if (m->type == STRING)
+               (void) printf("%s",m->value.s);
+       else
+               (void) printf("%d",m->value.l);
+       (void) printf("\t%s", m->desc);
+       (void) putchar('\n');
+}
+
+/*
+ * error - print best error message possible and exit
+ */
+void
+error(s1, s2)
+char *s1, *s2;
+{
+       warning(s1, s2);
+       exit(1);
+}
+
+/*VARARGS*/
+warning(f, a)
+char *f, *a;
+{
+       extern int errno, sys_nerr;
+       extern char *sys_errlist[];
+       int myerrno;
+
+       myerrno = errno;
+       (void) printf(f, a);
+       if (myerrno > 0 && myerrno < sys_nerr)
+               (void) printf(" (%s)", sys_errlist[myerrno]);
+}
diff --git a/src/softmagic.c b/src/softmagic.c
new file mode 100644 (file)
index 0000000..6cb7d91
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * variable magic from /etc/magic
+ */
+
+#include <stdio.h>
+#include "file.h"
+
+#define USAGE          "usage: %s [-f file] [-m magicfile] file...\n"
+
+extern char *progname;
+extern char *magicfile;        /* name of current /etc/magic or clone */
+extern int debug, nmagic;
+extern FILE *efopen();
+extern struct magic magic[];
+static int magindex;
+
+/*
+ * softmagic - lookup one file in /etc/magic database.
+ * Passed the name and FILE * of one file to be typed.
+ */
+softmagic(buf)
+char *buf;
+{
+       magindex = 0;
+       if (match(buf))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * go through the whole list, stopping if you find a match.
+ * Be sure to process every continuation of this match.
+ */
+match(s)
+char   *s;
+{
+       while (magindex < nmagic) {
+               /* if main entry matches, print it... */
+               if (mcheck(s, &magic[magindex])) {
+                       mprint(&magic[magindex],s);
+                       /* and any continuations that match */
+                       while (magic[magindex+1].contflag &&
+                               magindex < nmagic) {
+                               ++magindex;
+                               if (mcheck(s, &magic[magindex])){
+                                       (void) putchar(' ');
+                                       mprint(&magic[magindex],s);
+                               }
+                       }
+                       return 1;               /* all through */
+               } else {
+                       /* main entry didn't match, flush its continuations */
+                       while (magic[magindex+1].contflag &&
+                               magindex < nmagic) {
+                               ++magindex;
+                       }
+               }
+               ++magindex;                     /* on to the next */
+       }
+       return 0;                               /* no match at all */
+}
+
+
+mprint(m,s)
+struct magic *m;
+char *s;
+{
+       register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset);
+
+       switch (m->type) {
+       case BYTE:
+               (void) printf(m->desc, p->b);
+               break;
+       case SHORT:
+               (void) printf(m->desc, p->h);
+               break;
+       case LONG:
+               (void) printf(m->desc, p->l);
+               break;
+       case STRING:
+               (void) printf(m->desc, p->s);
+               break;
+       default:
+               warning("invalid m->type (%d) in mprint()", m->type);
+       }
+}
+
+mcheck(s, m)
+char   *s;
+struct magic *m;
+{
+       register char reln = m->reln;
+       register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset);
+       register long l = m->value.l;
+
+       if (debug) {
+               (void) printf("mcheck: %10.10s ", s);
+               mdump(m);
+       }
+       switch (m->type) {
+       case BYTE:
+               if (reln == '>')
+                       return p->b > l;
+               if (reln == '&')
+                       return l & p->b;
+               if (reln == '=')
+                       return l == p->b;
+               warning("mcheck: can't happen: invalid BYTE reln %d", reln);
+               return 0;
+       case SHORT:
+               if (reln == '=')
+                       return l == p->h;
+               if (reln == '>')
+                       return p->h > l;
+               if (reln == '&')
+                       return l & p->h;
+               warning("mcheck: can't happen: invalid SHORT reln %d", reln);
+               return 0;
+       case LONG:
+               if (reln == '=')
+                       return l == p->l;
+               if (reln == '>')
+                       return p->l > l;
+               if (reln == '&')
+                       return l & p->l;
+               warning("mcheck: can't happen: invalid LONG reln %d", reln);
+               return 0;
+       case STRING:
+               if (reln == '=')
+                       return strncmp(m->value.s, p->s,
+                               strlen(m->value.s)) == 0;
+               if (reln == '>')
+                       if (strcmp(m->value.s, "0") == 0) /* special case! */
+                               return *s > '\0';
+                       else
+                               return strncmp(m->value.s, p->s,
+                                       strlen(m->value.s)) > 0;
+               warning("mcheck: can't happen: invalid STRING reln %c(0%o)",
+                       reln, reln);
+               return 0;
+       default:
+               warning("invalid type %d in mcheck()", m->type);
+               return 0;
+       }
+}
+
+