<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf8">
<title>/usr/web/sources/contrib/quanstro/file.c - Plan 9 from Bell Labs</title>
<!-- THIS FILE IS AUTOMATICALLY GENERATED. -->
<!-- EDIT sources.tr INSTEAD. -->
</meta>
</head>
<body>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"><a href="/plan9/">Plan 9 from Bell Labs</a>&rsquo;s /usr/web/sources/contrib/quanstro/file.c</span></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
Copyright © 2009 Alcatel-Lucent.<br />
Distributed under the
<a href="/plan9/license.html">Lucent Public License version 1.02</a>.
<br />
<a href="/plan9/download.html">Download the Plan 9 distribution.</a>
</font>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<table width="100%" cellspacing=0 border=0><tr><td align="center">
<table cellspacing=0 cellpadding=5 bgcolor="#eeeeff"><tr><td align="left">
<pre>
<!-- END HEADER -->
#include &lt;u.h&gt;
#include &lt;libc.h&gt;
#include &lt;bio.h&gt;
#include &lt;ctype.h&gt;
#include &lt;mach.h&gt;

/*
* file - determine type of file
*/
#define LENDIAN(p)      ((p)[0] | ((p)[1]&lt;&lt;8) | ((p)[2]&lt;&lt;16) | ((p)[3]&lt;&lt;24))

uchar   buf[6001];
short   cfreq[140];
short   wfreq[50];
int     nbuf;
Dir*    mbuf;
int     fd;
char    *fname;
char    *slash;
int     currfd;

enum
{
       Cword,
       Fword,
       Aword,
       Alword,
       Lword,
       I1,
       I2,
       I3,
       Clatin  = 128,
       Cbinary,
       Cnull,
       Ceascii,
       Cutf,
};
struct
{
       char*   word;
       int     class;
} dict[] =
{
       "PATH",         Lword,
       "TEXT",         Aword,
       "adt",          Alword,
       "aggr",         Alword,
       "alef",         Alword,
       "array",        Lword,
       "block",        Fword,
       "char",         Cword,
       "common",       Fword,
       "con",          Lword,
       "data",         Fword,
       "dimension",    Fword,
       "double",       Cword,
       "extern",       Cword,
       "bio",          I2,
       "float",        Cword,
       "fn",           Lword,
       "function",     Fword,
       "h",            I3,
       "implement",    Lword,
       "import",       Lword,
       "include",      I1,
       "int",          Cword,
       "integer",      Fword,
       "iota",         Lword,
       "libc",         I2,
       "long",         Cword,
       "module",       Lword,
       "real",         Fword,
       "ref",          Lword,
       "register",     Cword,
       "self",         Lword,
       "short",        Cword,
       "static",       Cword,
       "stdio",        I2,
       "struct",       Cword,
       "subroutine",   Fword,
       "u",            I2,
       "void",         Cword,
};

/* codes for 'mode' field in language structure */
enum    {
               Normal  = 0,
               First,          /* first entry for language spanning several ranges */
               Multi,          /* later entries "   "       "  ... */
               Shared,         /* codes used in several languages */
       };

struct
{
       int     mode;           /* see enum above */
       int     count;
       int     low;
       int     high;
       char    *name;

} language[] =
{
       Normal, 0,      0x00a0, 0x00ff, "Latin",
       Normal, 0,      0x0100, 0x01FF, "Extended Latin",
       Normal, 0,      0x0370, 0x03FF, "Greek",
       Normal, 0,      0x0400, 0x04FF, "Cyrillic",
       Normal, 0,      0x0530, 0x058F, "Armenian",
       Normal, 0,      0x0590, 0x05FF, "Hebrew",
       Normal, 0,      0x0600, 0x06FF, "Arabic",
       Normal, 0,      0x0900, 0x097F, "Devanagari",
       Normal, 0,      0x0980, 0x09FF, "Bengali",
       Normal, 0,      0x0A00, 0x0A7F, "Gurmukhi",
       Normal, 0,      0x0A80, 0x0AFF, "Gujarati",
       Normal, 0,      0x0B00, 0x0B7F, "Oriya",
       Normal, 0,      0x0B80, 0x0BFF, "Tamil",
       Normal, 0,      0x0C00, 0x0C7F, "Telugu",
       Normal, 0,      0x0C80, 0x0CFF, "Kannada",
       Normal, 0,      0x0D00, 0x0D7F, "Malayalam",
       Normal, 0,      0x0E00, 0x0E7F, "Thai",
       Normal, 0,      0x0E80, 0x0EFF, "Lao",
       Normal, 0,      0x1000, 0x105F, "Tibetan",
       Normal, 0,      0x10A0, 0x10FF, "Georgian",
       Normal, 0,      0x3040, 0x30FF, "Japanese",
       Normal, 0,      0x3100, 0x312F, "Chinese",
       First,  0,      0x3130, 0x318F, "Korean",
       Multi,  0,      0x3400, 0x3D2F, "Korean",
       Shared, 0,      0x4e00, 0x9fff, "CJK",
       Normal, 0,      0,      0,      0,              /* terminal entry */
};


enum
{
       Fascii,         /* printable ascii */
       Flatin,         /* latin 1*/
       Futf,           /* UTF character set */
       Fbinary,        /* binary */
       Feascii,        /* ASCII with control chars */
       Fnull,          /* NULL in file */
} guess;

void    bump_utf_count(Rune);
int     cistrncmp(char*, char*, int);
void    filetype(int);
int     getfontnum(uchar*, uchar**);
void    hist(char*, char*);
int     isas(void);
int     isc(void);
int     iscint(void);
int     isenglish(void);
int     ishp(void);
int     ishtml(void);
int     isrfc822(void);
int     ismbox(void);
int     islimbo(void);
int     ismung(void);
int     isp9bit(void);
int     isp9font(void);
int     isrtf(void);
int     ismsdos(void);
int     iself(void);
int     istring(void);
int     isoffstr(void);
int     iff(void);
int     long0(void);
int     longoff(void);
int     istar(void);
int     isface(void);
int     isexec(void);
int     p9bitnum(uchar*);
int     p9subfont(uchar*);
void    print_utf(void);
void    type(char*, int);
int     utf_count(void);
void    wordfreq(void);

int     (*call[])(void) =
{
       long0,          /* recognizable by first 4 bytes */
       istring,        /* recognizable by first string */
       iself,          /* ELF (foreign) executable */
       isexec,         /* native executables */
       iff,            /* interchange file format (strings) */
       longoff,        /* recognizable by 4 bytes at some offset */
       isoffstr,       /* recognizable by string at some offset */
       isrfc822,       /* email file */
       ismbox,         /* mail box */
       istar,          /* recognizable by tar checksum */
       ishtml,         /* html keywords */
       iscint,         /* compiler/assembler intermediate */
       islimbo,        /* limbo source */
       isc,            /* c &amp; alef compiler key words */
       isas,           /* assembler key words */
       isp9font,       /* plan 9 font */
       isp9bit,        /* plan 9 image (as from /dev/window) */
       isrtf,          /* rich text format */
       ismsdos,        /* msdos exe (virus file attachement) */
       isface,         /* ascii face file */

       /* last resorts */
       ismung,         /* entropy compressed/encrypted */
       isenglish,      /* char frequency English */
       0
};

int mime;
int cset = 1;

char OCTET[] =  "application/octet-stream";
char PLAIN[] =  "text/plain";

void
prtype(char *m, char *s)
{
       char buf[80], *p;
       int add, n;

       if(mime){
               if(cset)
                       add = cistrncmp(m, "text/", 5) == 0 &amp;&amp; strchr(m, ';') == nil;
               else{
                       add = 0;
                       if((p = strchr(m, ';')) &amp;&amp; p-m &lt; sizeof buf){
                               snprint(buf, p-m, "%s", m);
                               m = buf;
                       }
               }
               for(;;){
                       if(cfreq[Cnull] + cfreq[Cbinary] &gt; 0
                            ||(cfreq[Clatin] &gt; 0 &amp;&amp; cfreq[Cutf] &gt; 0)){
                               add = 0;
                               m = OCTET;
                               break;
                       }
                       if((n = read(currfd, buf, sizeof buf)) &lt;= 0)
                               break;
                       hist(buf, buf+n);
               }
               if(add &amp;&amp; cfreq[Cutf] != 0)
                       print("%s; charset=\"utf-8\"\n", m);
               else if(add &amp;&amp; cfreq[Clatin])
                       print("%s; charset=\"latin1\"\n", m);
               else if(add)
                       print("%s; charset=\"us-ascii\"\n", m);
               else
                       print("%s\n", m);
       }else
               print("%s\n", s);
}

void
main(int argc, char *argv[])
{
       int i, j, maxlen;
       char *cp;
       Rune r;

       ARGBEGIN{
       case 'c':
               cset ^= 1;
       case 'm':
               mime = 1;
               break;
       default:
               fprint(2, "usage: file [-m] [file...]\n");
               exits("usage");
       }ARGEND;

       maxlen = 0;
       if(mime == 0 || argc &gt; 1){
               for(i = 0; i &lt; argc; i++) {
                       for (j = 0, cp = argv[i]; *cp; j++, cp += chartorune(&amp;r, cp))
                                       ;
                       if(j &gt; maxlen)
                               maxlen = j;
               }
       }
       if (argc &lt;= 0) {
               if(!mime)
                       print ("stdin: ");
               filetype(0);
       }
       else {
               for(i = 0; i &lt; argc; i++)
                       type(argv[i], maxlen);
       }
       exits(0);
}

void
type(char *file, int nlen)
{
       Rune r;
       int i;
       char *p;

       if(nlen &gt; 0){
               slash = 0;
               for (i = 0, p = file; *p; i++) {
                       if (*p == '/')                  /* find rightmost slash */
                               slash = p;
                       p += chartorune(&amp;r, p);             /* count runes */
               }
               print("%s:%*s",file, nlen-i+1, "");
       }
       fname = file;
       if ((fd = open(file, OREAD)) &lt; 0) {
               print("cannot open: %r\n");
               return;
       }
       filetype(fd);
       close(fd);
}

/*
* Unicode 4.0 4-byte runes.
*/
typedef int Rune1;

enum {
       UTFmax1 = 4,
};

int
fullrune1(char *p, int n)
{
       int c;

       if(n &gt;= 1) {
               c = *(uchar*)p;
               if(c &lt; 0x80)
                       return 1;
               if(n &gt;= 2 &amp;&amp; c &lt; 0xE0)
                       return 1;
               if(n &gt;= 3 &amp;&amp; c &lt; 0xF0)
                       return 1;
               if(n &gt;= 4)
                       return 1;
       }
       return 0;
}

int
chartorune1(Rune1 *rune, char *str)
{
       int c, c1, c2, c3, n;
       Rune r;

       c = *(uchar*)str;
       if(c &lt; 0xF0){
               r = 0;
               n = chartorune(&amp;r, str);
               *rune = r;
               return n;
       }
       c &amp;= ~0xF0;
       c1 = *(uchar*)(str+1) &amp; ~0x80;
       c2 = *(uchar*)(str+2) &amp; ~0x80;
       c3 = *(uchar*)(str+3) &amp; ~0x80;
       n = (c&lt;&lt;18) | (c1&lt;&lt;12) | (c2&lt;&lt;6) | c3;
       if(n &lt; 0x10000 || n &gt; 0x10FFFF){
               *rune = Runeerror;
               return 1;
       }
       *rune = n;
       return 4;
}

void
hist(char *buf, char *eob)
{
       char x[5], *p;
       int n, f;
       Rune1 r;
       static char push[5];
       static int npush;

       for(p = buf; p &lt; eob; ) {
               if(npush){
                       memset(x, 0, sizeof x);
                       memcpy(x, push, npush);
                       memcpy(x + npush, p, sizeof x - 1 - npush);
                       n = chartorune1(&amp;r, x);
                       if(n &gt;= npush){
                               n -= npush;
                               npush = 0;
                               p += n;
                       }else{
                               memmove(push, push + n, sizeof push - n);
                               npush -= n;
                       }
               }else{
                       if (!fullrune1(p, eob-p) &amp;&amp; eob-p &lt; UTFmax1)
                               break;
                       p += chartorune1(&amp;r, p);
               }
               if (r == 0)
                       f = Cnull;
               else if (r &lt;= 0x7f) {
                       if (!isprint(r) &amp;&amp; !isspace(r))
                               f = Ceascii;    /* ASCII control char */
                       else f = r;
               } else if (r == 0x80) {
                       bump_utf_count(r);
                       f = Cutf;
               } else if (r &lt; 0xA0)
                       f = Cbinary;    /* Invalid Runes */
               else if (r &lt;= 0xff)
                       f = Clatin;     /* Latin 1 */
               else {
                       bump_utf_count(r);
                       f = Cutf;               /* UTF extension */
               }
               cfreq[f]++;                     /* ASCII chars peg directly */
       }
       npush = eob-p;
       memcpy(push, p, npush);
}

void
filetype(int fd)
{
       int i;
       char *m;

       free(mbuf);
       mbuf = dirfstat(fd);
       if(mbuf == nil){
               print("cannot stat: %r\n");
               return;
       }
       if(mbuf-&gt;mode &amp; DMDIR) {
               prtype("text/directory", "directory");
               return;
       }
       if(mbuf-&gt;type != 'M' &amp;&amp; mbuf-&gt;type != '|') {
               m = smprint("special file #%c/%s", mbuf-&gt;type, mbuf-&gt;name);
               prtype(OCTET, m);
               free(m);
               return;
       }
       /* may be reading a pipe on standard input */
       nbuf = readn(fd, buf, sizeof(buf)-1);
       if(nbuf &lt; 0) {
               print("cannot read: %r\n");
               return;
       }
       if(nbuf == 0) {
               print(PLAIN, "empty file");
               return;
       }
       buf[nbuf] = 0;

       /*
        * build histogram table
        */
       memset(cfreq, 0, sizeof(cfreq));
       for (i = 0; language[i].name; i++)
               language[i].count = 0;
       hist((char*)buf, (char*)buf+nbuf);
       /*
        * gross classify
        */
       if (cfreq[Cbinary])
               guess = Fbinary;
       else if (cfreq[Cutf])
               guess = Futf;
       else if (cfreq[Clatin])
               guess = Flatin;
       else if (cfreq[Ceascii])
               guess = Feascii;
       else if (cfreq[Cnull])
               guess = Fbinary;
       else
               guess = Fascii;
       /*
        * lookup dictionary words
        */
       memset(wfreq, 0, sizeof(wfreq));
       if(guess == Fascii || guess == Flatin || guess == Futf)
               wordfreq();
       /*
        * call individual classify routines
        */
       currfd = fd;
       for(i=0; call[i]; i++)
               if((*call[i])())
                       return;

       /*
        * if all else fails,
        * print out gross classification
        */
       if (nbuf &lt; 100 &amp;&amp; !mime)
               print("short ");
       if (guess == Fascii)
               prtype(PLAIN, "Ascii");
       else if (guess == Feascii)
               prtype(PLAIN,"extended ascii");
       else if (guess == Flatin)
               prtype(PLAIN,"latin ascii");
       else if (guess == Futf &amp;&amp; utf_count() &lt; 4)
               print_utf();
       else prtype(OCTET, "binary");
}

void
bump_utf_count(Rune r)
{
       int low, high, mid;

       high = sizeof(language)/sizeof(language[0])-1;
       for (low = 0; low &lt; high;) {
               mid = (low+high)/2;
               if (r &gt;= language[mid].low) {
                       if (r &lt;= language[mid].high) {
                               language[mid].count++;
                               break;
                       } else low = mid+1;
               } else high = mid;
       }
}

int
utf_count(void)
{
       int i, count;

       count = 0;
       for (i = 0; language[i].name; i++)
               if (language[i].count &gt; 0)
                       switch (language[i].mode) {
                       case Normal:
                       case First:
                               count++;
                               break;
                       default:
                               break;
                       }
       return count;
}

int
chkascii(void)
{
       int i;

       for (i = 'a'; i &lt; 'z'; i++)
               if (cfreq[i])
                       return 1;
       for (i = 'A'; i &lt; 'Z'; i++)
               if (cfreq[i])
                       return 1;
       return 0;
}

int
find_first(char *name)
{
       int i;

       for (i = 0; language[i].name != 0; i++)
               if (language[i].mode == First
                       &amp;&amp; strcmp(language[i].name, name) == 0)
                       return i;
       return -1;
}

void
print_utf(void)
{
       int i, printed, j;

       if(mime){
               prtype(PLAIN, nil);
               return;
       }
       if (chkascii()) {
               printed = 1;
               print("Ascii");
       } else
               printed = 0;
       for (i = 0; language[i].name; i++)
               if (language[i].count) {
                       switch(language[i].mode) {
                       case Multi:
                               j = find_first(language[i].name);
                               if (j &lt; 0)
                                       break;
                               if (language[j].count &gt; 0)
                                       break;
                               /* Fall through */
                       case Normal:
                       case First:
                               if (printed)
                                       print(" &amp; ");
                               else printed = 1;
                               print("%s", language[i].name);
                               break;
                       case Shared:
                       default:
                               break;
                       }
               }
       if(!printed)
               print("UTF");
       print(" text\n");
}

void
wordfreq(void)
{
       int low, high, mid, r;
       uchar *p, *p2, c;

       p = buf;
       for(;;) {
               while (p &lt; buf+nbuf &amp;&amp; !isalpha(*p))
                       p++;
               if (p &gt;= buf+nbuf)
                       return;
               p2 = p;
               while(p &lt; buf+nbuf &amp;&amp; isalpha(*p))
                       p++;
               c = *p;
               *p = 0;
               high = sizeof(dict)/sizeof(dict[0]);
               for(low = 0;low &lt; high;) {
                       mid = (low+high)/2;
                       r = strcmp(dict[mid].word, (char*)p2);
                       if(r == 0) {
                               wfreq[dict[mid].class]++;
                               break;
                       }
                       if(r &lt; 0)
                               low = mid+1;
                       else
                               high = mid;
               }
               *p++ = c;
       }
}

typedef struct Filemagic Filemagic;
struct Filemagic {
       ulong x;
       ulong mask;
       char *desc;
       char *mime;
};

/*
* integers in this table must be as seen on a little-endian machine
* when read from a file.
*/
Filemagic long0tab[] = {
       0xF16DF16D,     0xFFFFFFFF,     "pac1 audio file",      OCTET,
       /* "pac1" */
       0x31636170,     0xFFFFFFFF,     "pac3 audio file",      OCTET,
       /* "pXc2 */
       0x32630070,     0xFFFF00FF,     "pac4 audio file",      OCTET,
       0xBA010000,     0xFFFFFFFF,     "mpeg system stream",   OCTET,
       0x30800CC0,     0xFFFFFFFF,     "inferno .dis executable", OCTET,
       0x04034B50,     0xFFFFFFFF,     "zip archive", "application/zip",
       070707,         0xFFFF,         "cpio archive", OCTET,
       0x2F7,          0xFFFF,         "tex dvi", "application/dvi",
       0xfaff,         0xfeff,         "mp3 audio",    "audio/mpeg",
       0xfeff0000,     0xffffffff,     "utf-32be",     "text/plain; charset=utf-32be",
       0xfffe,         0xffffffff,     "utf-32le",     "text/plain; charset=utf-32le",
       0xfeff,         0xffff,         "utf-16be",     "text/plain; charset=utf-16be",
       0xfffe,         0xffff,         "utf-16le",     "text/plain; charset=utf-16le",
       /*
        * venti &amp; fossil magic numbers are stored big-endian on disk,
        * thus the numbers appear reversed in this table.
        */
       0xad4e5cd1,     0xFFFFFFFF,     "venti arena", OCTET,
};

int
filemagic(Filemagic *tab, int ntab, ulong x)
{
       int i;

       for(i=0; i&lt;ntab; i++)
               if((x&amp;tab[i].mask) == tab[i].x){
                       prtype(tab[i].mime, tab[i].desc);
                       return 1;
               }
       return 0;
}

int
long0(void)
{
       return filemagic(long0tab, nelem(long0tab), LENDIAN(buf));
}

typedef struct Fileoffmag Fileoffmag;
struct Fileoffmag {
       ulong   off;
       Filemagic;
};

/*
* integers in this table must be as seen on a little-endian machine
* when read from a file.
*/
Fileoffmag longofftab[] = {
       /*
        * venti &amp; fossil magic numbers are stored big-endian on disk,
        * thus the numbers appear reversed in this table.
        */
       256*1024, 0xe7a5e4a9, 0xFFFFFFFF, "venti arenas partition", OCTET,
       256*1024, 0xc75e5cd1, 0xFFFFFFFF, "venti index section", OCTET,
       128*1024, 0x89ae7637, 0xFFFFFFFF, "fossil write buffer", OCTET,
       4,        0x31647542, 0xFFFFFFFF, "OS X finder properties", OCTET,
};

int
fileoffmagic(Fileoffmag *tab, int ntab)
{
       int i;
       ulong x;
       Fileoffmag *tp;
       uchar buf[sizeof(long)];

       for(i=0; i&lt;ntab; i++) {
               tp = tab + i;
               if(seek(fd, tp-&gt;off, 0) == -1)
                       return 0;
               if (readn(fd, buf, sizeof buf) != sizeof buf)
                       continue;
               x = LENDIAN(buf);
               if((x&amp;tp-&gt;mask) == tp-&gt;x){
                       prtype(tp-&gt;mime, tp-&gt;desc);
                       return 1;
               }
       }
       return 0;
}

int
longoff(void)
{
       return fileoffmagic(longofftab, nelem(longofftab));
}

int
isexec(void)
{
       Fhdr f;

       if(seek(fd, 0, 0) == -1)                /* reposition to start of file */
               return 0;
       if(crackhdr(fd, &amp;f)) {
               prtype(OCTET, f.name);
               return 1;
       }
       return 0;
}


/* from tar.c */
enum { NAMSIZ = 100, TBLOCK = 512 };

union   hblock
{
       char    dummy[TBLOCK];
       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];
               /* rest are defined by POSIX's ustar format; see p1003.2b */
               char    magic[6];       /* "ustar" */
               char    version[2];
               char    uname[32];
               char    gname[32];
               char    devmajor[8];
               char    devminor[8];
               char    prefix[155];  /* if non-null, path = prefix "/" name */
       } dbuf;
};

int
checksum(union hblock *hp)
{
       int i;
       char *cp;
       struct header *hdr = &amp;hp-&gt;dbuf;

       for (cp = hdr-&gt;chksum; cp &lt; &amp;hdr-&gt;chksum[sizeof hdr-&gt;chksum]; cp++)
               *cp = ' ';
       i = 0;
       for (cp = hp-&gt;dummy; cp &lt; &amp;hp-&gt;dummy[TBLOCK]; cp++)
               i += *cp &amp; 0xff;
       return i;
}

int
istar(void)
{
       int chksum;
       char tblock[TBLOCK];
       union hblock *hp = (union hblock *)tblock;
       struct header *hdr = &amp;hp-&gt;dbuf;

       if(seek(fd, 0, 0) == -1)                /* reposition to start of file */
               return 0;
       if (readn(fd, tblock, sizeof tblock) != sizeof tblock)
               return 0;
       chksum = strtol(hdr-&gt;chksum, 0, 8);
       if (hdr-&gt;name[0] != '\0' &amp;&amp; checksum(hp) == chksum) {
               if (strcmp(hdr-&gt;magic, "ustar") == 0)
                       prtype("application/x-ustar", "posix tar archive");
               else
                       prtype("application/x-tar", "tar archive");
               return 1;
       }
       return 0;
}

/*
* initial words to classify file
*/
struct  FILE_STRING
{
       char    *key;
       char    *filetype;
       int     length;
       char    *mime;
} file_string[] =
{
       "!&lt;arch&gt;\n__.SYMDEF",     "archive random library",       16,     "application/octet-stream",
       "!&lt;arch&gt;\n",              "archive",                      8,      "application/octet-stream",
       "070707",               "cpio archive - ascii header",  6,      "application/octet-stream",
       "#!/bin/rc",            "rc executable file",           9,      PLAIN,
       "#!/bin/sh",            "sh executable file",           9,      PLAIN,
       "%!",                   "postscript",                   2,      "application/postscript",
       "\004%!",               "postscript",                   3,      "application/postscript",
       "x T post",             "troff output for post",        8,      "application/troff",
       "x T Latin1",           "troff output for Latin1",      10,     "application/troff",
       "x T utf",              "troff output for UTF",         7,      "application/troff",
       "x T 202",              "troff output for 202",         7,      "application/troff",
       "x T aps",              "troff output for aps",         7,      "application/troff",
       "GIF",                  "GIF image",                    3,      "image/gif",
       "\0PC Research, Inc\0", "ghostscript fax file",         18,     "application/ghostscript",
       "%PDF",                 "PDF",                          4,      "application/pdf",
       "&lt;html&gt;\n",               "HTML file",                    7,      "text/html",
       "&lt;HTML&gt;\n",               "HTML file",                    7,      "text/html",
       "\111\111\052\000",     "tiff",                         4,      "image/tiff",
       "\115\115\000\052",     "tiff",                         4,      "image/tiff",
       "\377\330\377\340",     "jpeg",                         4,      "image/jpeg",
       "\377\330\377\341",     "jpeg",                         4,      "image/jpeg",
       "\377\330\377\333",     "jpeg",                         4,      "image/jpeg",
       "BM",                   "bmp",                          2,      "image/bmp",
       "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1",     "microsoft office document",    8,      "application/octet-stream",
       "&lt;MakerFile ",               "FrameMaker file",              11,     "application/framemaker",
       "\033E\033",    "HP PCL printer data",          3,      OCTET,
       "\033%-12345X", "HPJCL file",           9,      "application/hpjcl",
       "ID3",                  "mp3 audio with id3",   3,      "audio/mpeg",
       "\211PNG",              "PNG image",            4,      "image/png",
       "P3\n",                 "ppm",                          3,      "image/ppm",
       "P6\n",                 "ppm",                          3,      "image/ppm",
       "/* XPM */\n",  "xbm",                          10,     "image/xbm",
       ".HTML ",               "troff -ms input",      6,      "text/troff",
       ".LP",                  "troff -ms input",      3,      "text/troff",
       ".ND",                  "troff -ms input",      3,      "text/troff",
       ".PP",                  "troff -ms input",      3,      "text/troff",
       ".TL",                  "troff -ms input",      3,      "text/troff",
       ".TR",                  "troff -ms input",      3,      "text/troff",
       ".TH",                  "manual page",          3,      "text/troff",
       ".\\\"",                "troff input",          3,      "text/troff",
       ".de",                  "troff input",          3,      "text/troff",
       ".if",                  "troff input",          3,      "text/troff",
       ".nr",                  "troff input",          3,      "text/troff",
       ".tr",                  "troff input",          3,      "text/troff",
       "vac:",                 "venti score",          4,      PLAIN,
       "-----BEGIN CERTIFICATE-----\n",
                               "pem certificate",      -1,     PLAIN,
       "-----BEGIN TRUSTED CERTIFICATE-----\n",
                               "pem trusted certificate", -1,  PLAIN,
       "-----BEGIN X509 CERTIFICATE-----\n",
                               "pem x.509 certificate", -1,    PLAIN,
       "subject=/C=",          "pem certificate with header", -1, PLAIN,
       "process snapshot ",    "process snapshot",     -1,     "application/snapfs",
       "OggS",                 "ogg",                  4,      "application/ogg",
       0,0,0,0
};

int
istring(void)
{
       char *m, *s;
       int i, l;
       struct FILE_STRING *p;

       for(p = file_string; p-&gt;key; p++) {
               l = p-&gt;length;
               if(l == -1)
                       l = strlen(p-&gt;key);
               if(nbuf &gt;= l &amp;&amp; memcmp(buf, p-&gt;key, l) == 0) {
                       prtype(p-&gt;mime, p-&gt;filetype);
                       return 1;
               }
       }
       if(strncmp((char*)buf, "TYPE=", 5) == 0) {      /* td */
               for(i = 5; i &lt; nbuf; i++)
                       if(buf[i] == '\n')
                               break;
               s = (char*)buf + 5;
               m = smprint("%.*s picture", utfnlen(s, i-5), s);
               prtype(OCTET, m);
               free(m);
               return 1;
       }
       return 0;
}

struct offstr
{
       ulong   off;
       struct FILE_STRING;
} offstrs[] = {
       32*1024, "\001CD001\001",       "ISO9660 CD image",     7,      OCTET,
       0, 0, 0, 0, 0
};

int
isoffstr(void)
{
       int n;
       char buf[256];
       struct offstr *p;

       for(p = offstrs; p-&gt;key; p++) {
               if(seek(fd, p-&gt;off, 0) == -1)
                       return 0;
               n = p-&gt;length;
               if (n &gt; sizeof buf)
                       n = sizeof buf;
               if (readn(fd, buf, n) != n)
                       continue;
               if(memcmp(buf, p-&gt;key, n) == 0) {
                       prtype(p-&gt;mime, p-&gt;filetype);
                       return 1;
               }
       }
       return 0;
}

int
iff(void)
{
       if (strncmp((char*)buf, "FORM", 4) == 0 &amp;&amp;
           strncmp((char*)buf+8, "AIFF", 4) == 0) {
               prtype("audio/x-aiff", "aiff audio");
               return 1;
       }
       if (strncmp((char*)buf, "RIFF", 4) == 0) {
               if (strncmp((char*)buf+8, "WAVE", 4) == 0)
                       prtype("audio/wave", "wave audio");
               else if (strncmp((char*)buf+8, "AVI ", 4) == 0)
                       prtype("video/avi", "avi video");
               else
                       prtype("application/octet-stream", "riff file");
               return 1;
       }
       return 0;
}

char*   html_string[] =
{
       "title",
       "body",
       "head",
       "strong",
       "h1",
       "h2",
       "h3",
       "h4",
       "h5",
       "h6",
       "ul",
       "li",
       "dl",
       "br",
       "em",
       0,
};

int
ishtml(void)
{
       uchar *p, *q;
       int i, count;

               /* compare strings between '&lt;' and '&gt;' to html table */
       count = 0;
       p = buf;
       for(;;) {
               while (p &lt; buf+nbuf &amp;&amp; *p != '&lt;')
                       p++;
               p++;
               if (p &gt;= buf+nbuf)
                       break;
               if(*p == '/')
                       p++;
               q = p;
               while(p &lt; buf+nbuf &amp;&amp; *p != '&gt;')
                       p++;
               if (p &gt;= buf+nbuf)
                       break;
               for(i = 0; html_string[i]; i++) {
                       if(cistrncmp(html_string[i], (char*)q, p-q) == 0) {
                               if(count++ &gt; 4) {
                                       prtype("text/html", "HTML file");
                                       return 1;
                               }
                               break;
                       }
               }
               p++;
       }
       return 0;
}

char*   rfc822_string[] =
{
       "from:",
       "date:",
       "to:",
       "subject:",
       "received:",
       "reply to:",
       "sender:",
       0,
};

int
isrfc822(void)
{

       char *p, *q, *r;
       int i, count;

       count = 0;
       p = (char*)buf;
       for(;;) {
               q = strchr(p, '\n');
               if(q == nil)
                       break;
               *q = 0;
               if(p == (char*)buf &amp;&amp; strncmp(p, "From ", 5) == 0 &amp;&amp; strstr(p, " remote from ")){
                       count++;
                       *q = '\n';
                       p = q+1;
                       continue;
               }
               *q = '\n';
               if(*p != '\t' &amp;&amp; *p != ' '){
                       r = strchr(p, ':');
                       if(r == 0 || r &gt; q)
                               break;
                       for(i = 0; rfc822_string[i]; i++) {
                               if(cistrncmp(p, rfc822_string[i], strlen(rfc822_string[i])) == 0){
                                       count++;
                                       break;
                               }
                       }
               }
               p = q+1;
       }
       if(count &gt;= 3){
               prtype("message/rfc822", "email file");
               return 1;
       }
       return 0;
}

int
ismbox(void)
{
       char *p, *q;

       p = (char*)buf;
       q = strchr(p, '\n');
       if(q == nil)
               return 0;
       *q = 0;
       if(strncmp(p, "From ", 5) == 0 &amp;&amp; strstr(p, " remote from ") == nil){
               prtype(PLAIN, "mail box");
               return 1;
       }
       *q = '\n';
       return 0;
}

int
iscint(void)
{
       int type;
       char *name, *m;
       Biobuf b;

       if(seek(fd, 0, 0) == -1)
               return 0;
       if(Binit(&amp;b, fd, OREAD) == Beof)
               return 0;
       type = objtype(&amp;b, &amp;name);
       if(type &lt; 0)
               return 0;
       m = smprint("%s intermediate", name);
       prtype(OCTET, m);
       free(m);
       return 1;
}

int
isc(void)
{
       int n;

       n = wfreq[I1];
       /*
        * includes
        */
       if(n &gt;= 2 &amp;&amp; wfreq[I2] &gt;= n &amp;&amp; wfreq[I3] &gt;= n &amp;&amp; cfreq['.'] &gt;= n)
               goto yes;
       if(n &gt;= 1 &amp;&amp; wfreq[Alword] &gt;= n &amp;&amp; wfreq[I3] &gt;= n &amp;&amp; cfreq['.'] &gt;= n)
               goto yes;
       /*
        * declarations
        */
       if(wfreq[Cword] &gt;= 5 &amp;&amp; cfreq[';'] &gt;= 5)
               goto yes;
       /*
        * assignments
        */
       if(cfreq[';'] &gt;= 10 &amp;&amp; cfreq['='] &gt;= 10 &amp;&amp; wfreq[Cword] &gt;= 1)
               goto yes;
       return 0;

yes:
       prtype(PLAIN, wfreq[Alword] &gt; 0? "alef program": "c program");
       return 1;
}

int
islimbo(void)
{

       /*
        * includes
        */
       if(wfreq[Lword] &lt; 4)
               return 0;
       prtype(PLAIN, "limbo program");
       return 1;
}

int
isas(void)
{

       /*
        * includes
        */
       if(wfreq[Aword] &lt; 2)
               return 0;
       prtype(PLAIN, "as program");
       return 1;
}

/*
* low entropy means encrypted
*/
int
ismung(void)
{
       int i, bucket[8];
       float cs;

       if(nbuf &lt; 64)
               return 0;
       memset(bucket, 0, sizeof(bucket));
       for(i=nbuf-64; i&lt;nbuf; i++)
               bucket[(buf[i]&gt;&gt;5)&amp;07] += 1;

       cs = 0.;
       for(i=0; i&lt;8; i++)
               cs += (bucket[i]-8)*(bucket[i]-8);
       cs /= 8.;
       if(cs &lt;= 24.322) {
               if(buf[0]==0x1f &amp;&amp; buf[1]==0x9d)
                       prtype(OCTET, "compressed");
               else
               if(buf[0]==0x1f &amp;&amp; buf[1]==0x8b)
                       prtype(OCTET, "gzip compressed");
               else
               if(buf[0]=='B' &amp;&amp; buf[1]=='Z' &amp;&amp; buf[2]=='h')
                       prtype(OCTET, "bzip2 compressed");
               else
                       prtype(OCTET, "encrypted");
               return 1;
       }
       return 0;
}

/*
* english by punctuation and frequencies
*/
int
isenglish(void)
{
       int vow, comm, rare, badpun, punct;
       char *p;

       if(guess != Fascii &amp;&amp; guess != Feascii)
               return 0;
       badpun = 0;
       punct = 0;
       for(p = (char *)buf; p &lt; (char *)buf+nbuf-1; p++)
               switch(*p) {
               case '.':
               case ',':
               case ')':
               case '%':
               case ';':
               case ':':
               case '?':
                       punct++;
                       if(p[1] != ' ' &amp;&amp; p[1] != '\n')
                               badpun++;
               }
       if(badpun*5 &gt; punct)
               return 0;
       if(cfreq['&gt;']+cfreq['&lt;']+cfreq['/'] &gt; cfreq['e'])      /* shell file test */
               return 0;
       if(2*cfreq[';'] &gt; cfreq['e'])
               return 0;

       vow = 0;
       for(p="AEIOU"; *p; p++) {
               vow += cfreq[*p];
               vow += cfreq[tolower(*p)];
       }
       comm = 0;
       for(p="ETAION"; *p; p++) {
               comm += cfreq[*p];
               comm += cfreq[tolower(*p)];
       }
       rare = 0;
       for(p="VJKQXZ"; *p; p++) {
               rare += cfreq[*p];
               rare += cfreq[tolower(*p)];
       }
       if(vow*5 &gt;= nbuf-cfreq[' '] &amp;&amp; comm &gt;= 10*rare) {
               prtype(PLAIN, "English text");
               return 1;
       }
       return 0;
}

/*
* pick up a number with
* syntax _*[0-9]+_
*/
#define P9BITLEN        12
int
p9bitnum(uchar *bp)
{
       int n, c, len;

       len = P9BITLEN;
       while(*bp == ' ') {
               bp++;
               len--;
               if(len &lt;= 0)
                       return -1;
       }
       n = 0;
       while(len &gt; 1) {
               c = *bp++;
               if(!isdigit(c))
                       return -1;
               n = n*10 + c-'0';
               len--;
       }
       if(*bp != ' ')
               return -1;
       return n;
}

int
depthof(char *s, int *newp)
{
       char *es;
       int d;

       *newp = 0;
       es = s+12;
       while(s&lt;es &amp;&amp; *s==' ')
               s++;
       if(s == es)
               return -1;
       if('0'&lt;=*s &amp;&amp; *s&lt;='9')
               return 1&lt;&lt;strtol(s, 0, 0);

       *newp = 1;
       d = 0;
       while(s&lt;es &amp;&amp; *s!=' '){
               s++;                    /* skip letter */
               d += strtoul(s, &amp;s, 10);
       }

       switch(d){
       case 32:
       case 24:
       case 16:
       case 8:
               return d;
       default:
               return -1;
       }
}

int
isp9bit(void)
{
       int dep, lox, loy, hix, hiy, px, new, cmpr;
       ulong t;
       long len;
       char *newlabel, *m;
       uchar *cp;

       cp = buf;
       cmpr = 0;
       newlabel = "old ";

       if(memcmp(cp, "compressed\n", 11) == 0) {
               cmpr = 1;
               cp = buf + 11;
       }

       dep = depthof((char*)cp + 0*P9BITLEN, &amp;new);
       if(new)
               newlabel = "";
       lox = p9bitnum(cp + 1*P9BITLEN);
       loy = p9bitnum(cp + 2*P9BITLEN);
       hix = p9bitnum(cp + 3*P9BITLEN);
       hiy = p9bitnum(cp + 4*P9BITLEN);
       if(dep &lt; 0 || lox &lt; 0 || loy &lt; 0 || hix &lt; 0 || hiy &lt; 0)
               return 0;

       if(dep &lt; 8){
               px = 8/dep;             /* pixels per byte */
               /* set l to number of bytes of data per scan line */
               if(lox &gt;= 0)
                       len = (hix+px-1)/px - lox/px;
               else{                   /* make positive before divide */
                       t = (-lox)+px-1;
                       t = (t/px)*px;
                       len = (t+hix+px-1)/px;
               }
       }else
               len = (hix-lox)*dep/8;
       len *= hiy - loy;               /* col length */
       len += 5 * P9BITLEN;            /* size of initial ascii */

       /*
        * for compressed images, don't look any further. otherwise:
        * for image file, length is non-zero and must match calculation above.
        * for /dev/window and /dev/screen the length is always zero.
        * for subfont, the subfont header should follow immediately.
        */
       if (cmpr) {
               m = smprint("Compressed %splan 9 image or subfont, depth %d",
                       newlabel, dep);
               prtype(OCTET, m);
               free(m);
               return 1;
       }
       /*
        * mbuf-&gt;length == 0 probably indicates reading a pipe.
        * Ghostscript sometimes produces a little extra on the end.
        */
       if (len != 0 &amp;&amp; (mbuf-&gt;length == 0 || mbuf-&gt;length == len ||
           mbuf-&gt;length &gt; len &amp;&amp; mbuf-&gt;length &lt; len+P9BITLEN)) {
               m = smprint("%splan 9 image, depth %d", newlabel, dep);
               prtype(OCTET, m);
               free(m);
               return 1;
       }
       if (p9subfont(buf+len)) {
               m = smprint("%ssubfont file, depth %d", newlabel, dep);
               prtype(OCTET, m);
               free(m);
               return 1;
       }
       return 0;
}

int
p9subfont(uchar *p)
{
       int n, h, a;

       /* if image too big, assume it's a subfont */
       if (p+3*P9BITLEN &gt; buf+sizeof(buf))
               return 1;

       n = p9bitnum(p + 0*P9BITLEN);   /* char count */
       if (n &lt; 0)
               return 0;
       h = p9bitnum(p + 1*P9BITLEN);   /* height */
       if (h &lt; 0)
               return 0;
       a = p9bitnum(p + 2*P9BITLEN);   /* ascent */
       if (a &lt; 0)
               return 0;
       return 1;
}

#define WHITESPACE(c)           ((c) == ' ' || (c) == '\t' || (c) == '\n')

int
isp9font(void)
{
       uchar *cp, *p;
       int i, n;
       char pathname[1024];

       cp = buf;
       if (!getfontnum(cp, &amp;cp))   /* height */
               return 0;
       if (!getfontnum(cp, &amp;cp))   /* ascent */
               return 0;
       for (i = 0; cp=(uchar*)strchr((char*)cp, '\n'); i++) {
               if (!getfontnum(cp, &amp;cp))   /* min */
                       break;
               if (!getfontnum(cp, &amp;cp))   /* max */
                       return 0;
               getfontnum(cp, &amp;cp);        /* optional offset */
               while (WHITESPACE(*cp))
                       cp++;
               for (p = cp; *cp &amp;&amp; !WHITESPACE(*cp); cp++)
                               ;
                       /* construct a path name, if needed */
               n = 0;
               if (*p != '/' &amp;&amp; slash) {
                       n = slash-fname+1;
                       if (n &lt; sizeof(pathname))
                               memcpy(pathname, fname, n);
                       else n = 0;
               }
               if (n+cp-p+4 &lt; sizeof(pathname)) {
                       memcpy(pathname+n, p, cp-p);
                       n += cp-p;
                       pathname[n] = 0;
                       if (access(pathname, AEXIST) &lt; 0) {
                               strcpy(pathname+n, ".0");
                               if (access(pathname, AEXIST) &lt; 0)
                                       return 0;
                       }
               }
       }
       if (i) {
               prtype(PLAIN, "font file");
               return 1;
       }
       return 0;
}

int
getfontnum(uchar *cp, uchar **rp)
{
       while (WHITESPACE(*cp))         /* extract ulong delimited by whitespace */
               cp++;
       if (*cp &lt; '0' || *cp &gt; '9')
               return 0;
       strtoul((char *)cp, (char **)rp, 0);
       if (!WHITESPACE(**rp)) {
               *rp = cp;
               return 0;
       }
       return 1;
}

int
isrtf(void)
{
       if(strstr((char *)buf, "\\rtf1")){
               prtype("application/rtf", "rich text format");
               return 1;
       }
       return 0;
}

int
ismsdos(void)
{
       if (buf[0] == 0x4d &amp;&amp; buf[1] == 0x5a){
               prtype("application/x-msdownload", "MSDOS executable");
               return 1;
       }
       return 0;
}

int
iself(void)
{
       static char *cpu[] = {          /* NB: incomplete and arbitary list */
       [1]     "WE32100",
       [2]     "SPARC",
       [3]     "i386",
       [4]     "M68000",
       [5]     "M88000",
       [6]     "i486",
       [7]     "i860",
       [8]     "R3000",
       [9]     "S370",
       [10]    "R4000",
       [15]    "HP-PA",
       [18]    "sparc v8+",
       [19]    "i960",
       [20]    "PPC-32",
       [21]    "PPC-64",
       [40]    "ARM",
       [41]    "Alpha",
       [43]    "sparc v9",
       [50]    "IA-64",
       [62]    "AMD64",
       [75]    "VAX",
       };
       static char *type[] = {
       [1]     "relocatable object",
       [2]     "executable",
       [3]     "shared library",
       [4]     "core dump",
       };

       if (memcmp(buf, "\x7fELF", 4) == 0){
               if (!mime){
                       int isdifend = 0;
                       int n = (buf[19] &lt;&lt; 8) | buf[18];
                       char *p = "unknown";
                       char *t = "unknown";

                       if (n &gt; 0 &amp;&amp; n &lt; nelem(cpu) &amp;&amp; cpu[n])
                               p = cpu[n];
                       else {
                               /* try the other byte order */
                               isdifend = 1;
                               n = (buf[18] &lt;&lt; 8) | buf[19];
                               if (n &gt; 0 &amp;&amp; n &lt; nelem(cpu) &amp;&amp; cpu[n])
                                       p = cpu[n];
                       }
                       if(isdifend)
                               n = (buf[16]&lt;&lt; 8) | buf[17];
                       else
                               n = (buf[17]&lt;&lt; 8) | buf[16];

                       if(n&gt;0 &amp;&amp; n &lt; nelem(type) &amp;&amp; type[n])
                               t = type[n];
                       print("%s ELF %s\n", p, t);
               }
               else
                       prtype("application/x-elf-executable", nil);
               return 1;
       }

       return 0;
}

int
isface(void)
{
       int i, j, ldepth, l;
       char *p, *m;

       ldepth = -1;
       for(j = 0; j &lt; 3; j++){
               for(p = (char*)buf, i=0; i&lt;3; i++){
                       if(p[0] != '0' || p[1] != 'x')
                               return 0;
                       if(buf[2+8] == ',')
                               l = 2;
                       else if(buf[2+4] == ',')
                               l = 1;
                       else
                               return 0;
                       if(ldepth == -1)
                               ldepth = l;
                       if(l != ldepth)
                               return 0;
                       strtoul(p, &amp;p, 16);
                       if(*p++ != ',')
                               return 0;
                       while(*p == ' ' || *p == '\t')
                               p++;
               }
               if (*p++ != '\n')
                       return 0;
       }

       m = smprint("face image depth %d", ldepth);
       prtype("application/x-face", m);
       free(m);
       return 1;
}
<!-- BEGIN TAIL -->
</pre>
</td></tr></table>
</td></tr></table>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"></span></p>
<p style="margin-top: 0; margin-bottom: 0.50in"></p>
<p style="margin-top: 0; margin-bottom: 0.33in"></p>
<center><table border="0"><tr>
<td valign="middle"><a href="http://www.alcatel-lucent.com/"><img border="0" src="/plan9/img/logo_ft.gif" alt="Bell Labs" />
</a></td>
<td valign="middle"><a href="http://www.opensource.org"><img border="0" alt="OSI certified" src="/plan9/img/osi-certified-60x50.gif" />
</a></td>
<td><img style="padding-right: 45px;" alt="Powered by Plan 9" src="/plan9/img/power36.gif" />
</td>
</tr></table></center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center>
<span style="font-size: 10pt">(<a href="/plan9/">Return to Plan 9 Home Page</a>)</span>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
<span style="font-size: 10pt"><a href="http://www.lucent.com/copyright.html">Copyright</a></span>
<span style="font-size: 10pt">© 2009 Alcatel-Lucent.</span>
<span style="font-size: 10pt">All Rights Reserved.</span>
<br />
<span style="font-size: 10pt">Comments to</span>
<span style="font-size: 10pt"><a href="mailto:[email protected]">[email protected]</a>.</span>
</font></center>
</body>
</html>