8 * file - determine type of file
10 #define LENDIAN(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
84 /* codes for 'mode' field in language structure */
87 First, /* first entry for language spanning several ranges */
88 Multi, /* later entries " " " ... */
89 Shared, /* codes used in several languages */
94 int mode; /* see enum above */
102 Normal, 0, 0x0100, 0x01FF, "Extended Latin",
103 Normal, 0, 0x0370, 0x03FF, "Greek",
104 Normal, 0, 0x0400, 0x04FF, "Cyrillic",
105 Normal, 0, 0x0530, 0x058F, "Armenian",
106 Normal, 0, 0x0590, 0x05FF, "Hebrew",
107 Normal, 0, 0x0600, 0x06FF, "Arabic",
108 Normal, 0, 0x0900, 0x097F, "Devanagari",
109 Normal, 0, 0x0980, 0x09FF, "Bengali",
110 Normal, 0, 0x0A00, 0x0A7F, "Gurmukhi",
111 Normal, 0, 0x0A80, 0x0AFF, "Gujarati",
112 Normal, 0, 0x0B00, 0x0B7F, "Oriya",
113 Normal, 0, 0x0B80, 0x0BFF, "Tamil",
114 Normal, 0, 0x0C00, 0x0C7F, "Telugu",
115 Normal, 0, 0x0C80, 0x0CFF, "Kannada",
116 Normal, 0, 0x0D00, 0x0D7F, "Malayalam",
117 Normal, 0, 0x0E00, 0x0E7F, "Thai",
118 Normal, 0, 0x0E80, 0x0EFF, "Lao",
119 Normal, 0, 0x1000, 0x105F, "Tibetan",
120 Normal, 0, 0x10A0, 0x10FF, "Georgian",
121 Normal, 0, 0x3040, 0x30FF, "Japanese",
122 Normal, 0, 0x3100, 0x312F, "Chinese",
123 First, 0, 0x3130, 0x318F, "Korean",
124 Multi, 0, 0x3400, 0x3D2F, "Korean",
125 Shared, 0, 0x4e00, 0x9fff, "CJK",
126 Normal, 0, 0, 0, 0, /* terminal entry */
132 Fascii, /* printable ascii */
134 Futf, /* UTF character set */
135 Fbinary, /* binary */
136 Feascii, /* ASCII with control chars */
137 Fnull, /* NULL in file */
140 void bump_utf_count(Rune);
141 int cistrncmp(char*, char*, int);
143 int getfontnum(uchar*, uchar**);
167 int p9bitnum(uchar*);
168 int p9subfont(uchar*);
169 void print_utf(void);
170 void type(char*, int);
174 int (*call[])(void) =
176 long0, /* recognizable by first 4 bytes */
177 istring, /* recognizable by first string */
178 iself, /* ELF (foreign) executable */
179 isexec, /* native executables */
180 iff, /* interchange file format (strings) */
181 longoff, /* recognizable by 4 bytes at some offset */
182 isoffstr, /* recognizable by string at some offset */
183 isrfc822, /* email file */
184 ismbox, /* mail box */
185 istar, /* recognizable by tar checksum */
186 ishtml, /* html keywords */
187 iscint, /* compiler/assembler intermediate */
188 islimbo, /* limbo source */
189 isc, /* c & alef compiler key words */
190 isas, /* assembler key words */
191 isp9font, /* plan 9 font */
192 isp9bit, /* plan 9 image (as from /dev/window) */
193 isrtf, /* rich text format */
194 ismsdos, /* msdos exe (virus file attachement) */
195 isface, /* ascii face file */
198 ismung, /* entropy compressed/encrypted */
199 isenglish, /* char frequency English */
205 char OCTET[] = "application/octet-stream\n";
206 char PLAIN[] = "text/plain\n";
209 main(int argc, char *argv[])
220 fprint(2, "usage: file [-m] [file...]\n");
225 if(mime == 0 || argc > 1){
226 for(i = 0; i < argc; i++) {
227 for (j = 0, cp = argv[i]; *cp; j++, cp += chartorune(&r, cp))
239 for(i = 0; i < argc; i++)
240 type(argv[i], maxlen);
246 type(char *file, int nlen)
254 for (i = 0, p = file; *p; i++) {
255 if (*p == '/') /* find rightmost slash */
257 p += chartorune(&r, p); /* count runes */
259 print("%s:%*s",file, nlen-i+1, "");
262 if ((fd = open(file, OREAD)) < 0) {
263 print("cannot open: %r\n");
271 * Unicode 4.0 4-byte runes.
280 fullrune1(char *p, int n)
288 if(n >= 2 && c < 0xE0)
290 if(n >= 3 && c < 0xF0)
299 chartorune1(Rune1 *rune, char *str)
301 int c, c1, c2, c3, n;
307 n = chartorune(&r, str);
312 c1 = *(uchar*)(str+1) & ~0x80;
313 c2 = *(uchar*)(str+2) & ~0x80;
314 c3 = *(uchar*)(str+3) & ~0x80;
315 n = (c<<18) | (c1<<12) | (c2<<6) | c3;
316 if(n < 0x10000 || n > 0x10FFFF){
334 print("cannot stat: %r\n");
337 if(mbuf->mode & DMDIR) {
338 print(mime ? OCTET : "directory\n");
341 if(mbuf->type != 'M' && mbuf->type != '|') {
342 print(mime ? OCTET : "special file #%C/%s\n",
343 mbuf->type, mbuf->name);
346 /* may be reading a pipe on standard input */
347 nbuf = readn(fd, buf, sizeof(buf)-1);
349 print("cannot read: %r\n");
353 print(mime ? PLAIN : "empty file\n");
359 * build histogram table
361 memset(cfreq, 0, sizeof(cfreq));
362 for (i = 0; language[i].name; i++)
363 language[i].count = 0;
364 eob = (char *)buf+nbuf;
365 for(n = 0, p = (char *)buf; p < eob; n++) {
366 if (!fullrune1(p, eob-p) && eob-p < UTFmax1)
368 p += chartorune1(&r, p);
371 else if (r <= 0x7f) {
372 if (!isprint(r) && !isspace(r))
373 f = Ceascii; /* ASCII control char */
375 } else if (r == 0x80) {
379 f = Cbinary; /* Invalid Runes */
381 f = Clatin; /* Latin 1 */
384 f = Cutf; /* UTF extension */
386 cfreq[f]++; /* ASCII chars peg directly */
393 else if (cfreq[Cutf])
395 else if (cfreq[Clatin])
397 else if (cfreq[Ceascii])
399 else if (cfreq[Cnull])
404 * lookup dictionary words
406 memset(wfreq, 0, sizeof(wfreq));
407 if(guess == Fascii || guess == Flatin || guess == Futf)
410 * call individual classify routines
412 for(i=0; call[i]; i++)
418 * print out gross classification
420 if (nbuf < 100 && !mime)
421 print(mime ? PLAIN : "short ");
423 print(mime ? PLAIN : "Ascii\n");
424 else if (guess == Feascii)
425 print(mime ? PLAIN : "extended ascii\n");
426 else if (guess == Flatin)
427 print(mime ? PLAIN : "latin ascii\n");
428 else if (guess == Futf && utf_count() < 4)
430 else print(mime ? OCTET : "binary\n");
434 bump_utf_count(Rune r)
438 high = sizeof(language)/sizeof(language[0])-1;
439 for (low = 0; low < high;) {
441 if (r >= language[mid].low) {
442 if (r <= language[mid].high) {
443 language[mid].count++;
456 for (i = 0; language[i].name; i++)
457 if (language[i].count > 0)
458 switch (language[i].mode) {
474 for (i = 'a'; i < 'z'; i++)
477 for (i = 'A'; i < 'Z'; i++)
484 find_first(char *name)
488 for (i = 0; language[i].name != 0; i++)
489 if (language[i].mode == First
490 && strcmp(language[i].name, name) == 0)
509 for (i = 0; language[i].name; i++)
510 if (language[i].count) {
511 switch(language[i].mode) {
513 j = find_first(language[i].name);
516 if (language[j].count > 0)
524 print("%s", language[i].name);
539 int low, high, mid, r;
544 while (p < buf+nbuf && !isalpha(*p))
549 while(p < buf+nbuf && isalpha(*p))
553 high = sizeof(dict)/sizeof(dict[0]);
554 for(low = 0;low < high;) {
556 r = strcmp(dict[mid].word, (char*)p2);
558 wfreq[dict[mid].class]++;
570 typedef struct Filemagic Filemagic;
579 * integers in this table must be as seen on a little-endian machine
580 * when read from a file.
582 Filemagic long0tab[] = {
583 0xF16DF16D, 0xFFFFFFFF, "pac1 audio file\n", OCTET,
585 0x31636170, 0xFFFFFFFF, "pac3 audio file\n", OCTET,
587 0x32630070, 0xFFFF00FF, "pac4 audio file\n", OCTET,
588 0xBA010000, 0xFFFFFFFF, "mpeg system stream\n", OCTET,
589 0x43614c66, 0xFFFFFFFF, "FLAC audio file\n", OCTET,
590 0x30800CC0, 0xFFFFFFFF, "inferno .dis executable\n", OCTET,
591 0x04034B50, 0xFFFFFFFF, "zip archive\n", "application/zip",
592 070707, 0xFFFF, "cpio archive\n", OCTET,
593 0x2F7, 0xFFFF, "tex dvi\n", "application/dvi",
594 0xfaff, 0xfeff, "mp3 audio\n", "audio/mpeg",
595 0xfeff0000, 0xffffffff, "utf-32be\n", "text/plain charset=utf-32be",
596 0xfffe, 0xffffffff, "utf-32le\n", "text/plain charset=utf-32le",
597 0xfeff, 0xffff, "utf-16be\n", "text/plain charset=utf-16be",
598 0xfffe, 0xffff, "utf-16le\n", "text/plain charset=utf-16le",
599 /* 0xfeedface: this could alternately be a Next Plan 9 boot image */
600 0xcefaedfe, 0xFFFFFFFF, "32-bit power Mach-O executable\n", OCTET,
602 0xcffaedfe, 0xFFFFFFFF, "64-bit power Mach-O executable\n", OCTET,
604 0xfeedface, 0xFFFFFFFF, "386 Mach-O executable\n", OCTET,
606 0xfeedfacf, 0xFFFFFFFF, "amd64 Mach-O executable\n", OCTET,
608 0xbebafeca, 0xFFFFFFFF, "Mach-O universal executable\n", OCTET,
610 * venti & fossil magic numbers are stored big-endian on disk,
611 * thus the numbers appear reversed in this table.
613 0xad4e5cd1, 0xFFFFFFFF, "venti arena\n", OCTET,
617 filemagic(Filemagic *tab, int ntab, ulong x)
621 for(i=0; i<ntab; i++)
622 if((x&tab[i].mask) == tab[i].x){
623 print(mime ? tab[i].mime : tab[i].desc);
632 return filemagic(long0tab, nelem(long0tab), LENDIAN(buf));
635 typedef struct Fileoffmag Fileoffmag;
642 * integers in this table must be as seen on a little-endian machine
643 * when read from a file.
645 Fileoffmag longofftab[] = {
647 * venti & fossil magic numbers are stored big-endian on disk,
648 * thus the numbers appear reversed in this table.
650 256*1024, 0xe7a5e4a9, 0xFFFFFFFF, "venti arenas partition\n", OCTET,
651 256*1024, 0xc75e5cd1, 0xFFFFFFFF, "venti index section\n", OCTET,
652 128*1024, 0x89ae7637, 0xFFFFFFFF, "fossil write buffer\n", OCTET,
653 4, 0x31647542, 0xFFFFFFFF, "OS X finder properties\n", OCTET,
657 fileoffmagic(Fileoffmag *tab, int ntab)
662 uchar buf[sizeof(long)];
664 for(i=0; i<ntab; i++) {
666 seek(fd, tp->off, 0);
667 if (readn(fd, buf, sizeof buf) != sizeof buf)
670 if((x&tp->mask) == tp->x){
671 print(mime? tp->mime: tp->desc);
681 return fileoffmagic(longofftab, nelem(longofftab));
689 seek(fd, 0, 0); /* reposition to start of file */
690 if(crackhdr(fd, &f)) {
691 print(mime ? OCTET : "%s\n", f.name);
699 enum { NAMSIZ = 100, TBLOCK = 512 };
714 char linkname[NAMSIZ];
715 /* rest are defined by POSIX's ustar format; see p1003.2b */
716 char magic[6]; /* "ustar" */
722 char prefix[155]; /* if non-null, path = prefix "/" name */
727 checksum(union hblock *hp)
731 struct header *hdr = &hp->dbuf;
733 for (cp = hdr->chksum; cp < &hdr->chksum[sizeof hdr->chksum]; cp++)
736 for (cp = hp->dummy; cp < &hp->dummy[TBLOCK]; cp++)
746 union hblock *hp = (union hblock *)tblock;
747 struct header *hdr = &hp->dbuf;
749 seek(fd, 0, 0); /* reposition to start of file */
750 if (readn(fd, tblock, sizeof tblock) != sizeof tblock)
752 chksum = strtol(hdr->chksum, 0, 8);
753 if (hdr->name[0] != '\0' && checksum(hp) == chksum) {
754 if (strcmp(hdr->magic, "ustar") == 0)
755 print(mime? "application/x-ustar\n":
756 "posix tar archive\n");
758 print(mime? "application/x-tar\n": "tar archive\n");
765 * initial words to classify file
775 "!<arch>\n__.SYMDEF", "archive random library", 16, "application/octet-stream",
776 "!<arch>\n", "archive", 8, "application/octet-stream",
777 "070707", "cpio archive - ascii header", 6, "application/octet-stream",
778 "#!/bin/rc", "rc executable file", 9, "text/plain",
779 "#!/bin/sh", "sh executable file", 9, "text/plain",
780 "%!", "postscript", 2, "application/postscript",
781 "\004%!", "postscript", 3, "application/postscript",
782 "x T post", "troff output for post", 8, "application/troff",
783 "x T Latin1", "troff output for Latin1", 10, "application/troff",
784 "x T utf", "troff output for UTF", 7, "application/troff",
785 "x T 202", "troff output for 202", 7, "application/troff",
786 "x T aps", "troff output for aps", 7, "application/troff",
787 "GIF", "GIF image", 3, "image/gif",
788 "\0PC Research, Inc\0", "ghostscript fax file", 18, "application/ghostscript",
789 "%PDF", "PDF", 4, "application/pdf",
790 "<html>\n", "HTML file", 7, "text/html",
791 "<HTML>\n", "HTML file", 7, "text/html",
792 "\111\111\052\000", "tiff", 4, "image/tiff",
793 "\115\115\000\052", "tiff", 4, "image/tiff",
794 "\377\330\377\340", "jpeg", 4, "image/jpeg",
795 "\377\330\377\341", "jpeg", 4, "image/jpeg",
796 "\377\330\377\333", "jpeg", 4, "image/jpeg",
797 "BM", "bmp", 2, "image/bmp",
798 "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1", "microsoft office document", 8, "application/octet-stream",
799 "<MakerFile ", "FrameMaker file", 11, "application/framemaker",
800 "\033E\033", "HP PCL printer data", 3, OCTET,
801 "\033%-12345X", "HPJCL file", 9, "application/hpjcl",
802 "ID3", "mp3 audio with id3", 3, "audio/mpeg",
803 "\211PNG", "PNG image", 4, "image/png",
804 "P3\n", "ppm", 3, "image/ppm",
805 "P6\n", "ppm", 3, "image/ppm",
806 "/* XPM */\n", "xbm", 10, "image/xbm",
807 ".HTML ", "troff -ms input", 6, "text/troff",
808 ".LP", "troff -ms input", 3, "text/troff",
809 ".ND", "troff -ms input", 3, "text/troff",
810 ".PP", "troff -ms input", 3, "text/troff",
811 ".TL", "troff -ms input", 3, "text/troff",
812 ".TR", "troff -ms input", 3, "text/troff",
813 ".TH", "manual page", 3, "text/troff",
814 ".\\\"", "troff input", 3, "text/troff",
815 ".de", "troff input", 3, "text/troff",
816 ".if", "troff input", 3, "text/troff",
817 ".nr", "troff input", 3, "text/troff",
818 ".tr", "troff input", 3, "text/troff",
819 "vac:", "venti score", 4, "text/plain",
820 "-----BEGIN CERTIFICATE-----\n",
821 "pem certificate", -1, "text/plain",
822 "-----BEGIN TRUSTED CERTIFICATE-----\n",
823 "pem trusted certificate", -1, "text/plain",
824 "-----BEGIN X509 CERTIFICATE-----\n",
825 "pem x.509 certificate", -1, "text/plain",
826 "subject=/C=", "pem certificate with header", -1, "text/plain",
827 "process snapshot ", "process snapshot", -1, "application/snapfs",
835 struct FILE_STRING *p;
837 for(p = file_string; p->key; p++) {
841 if(nbuf >= l && memcmp(buf, p->key, l) == 0) {
843 print("%s\n", p->mime);
845 print("%s\n", p->filetype);
849 if(strncmp((char*)buf, "TYPE=", 5) == 0) { /* td */
850 for(i = 5; i < nbuf; i++)
856 print("%.*s picture\n", utfnlen((char*)buf+5, i-5), (char*)buf+5);
867 32*1024, "\001CD001\001", "ISO9660 CD image", 7, OCTET,
878 for(p = offstrs; p->key; p++) {
883 if (readn(fd, buf, n) != n)
885 if(memcmp(buf, p->key, n) == 0) {
887 print("%s\n", p->mime);
889 print("%s\n", p->filetype);
899 if (strncmp((char*)buf, "FORM", 4) == 0 &&
900 strncmp((char*)buf+8, "AIFF", 4) == 0) {
901 print("%s\n", mime? "audio/x-aiff": "aiff audio");
904 if (strncmp((char*)buf, "RIFF", 4) == 0) {
905 if (strncmp((char*)buf+8, "WAVE", 4) == 0)
906 print("%s\n", mime? "audio/wave": "wave audio");
907 else if (strncmp((char*)buf+8, "AVI ", 4) == 0)
908 print("%s\n", mime? "video/avi": "avi video");
910 print("%s\n", mime? "application/octet-stream":
917 char* html_string[] =
943 /* compare strings between '<' and '>' to html table */
947 while (p < buf+nbuf && *p != '<')
955 while(p < buf+nbuf && *p != '>')
959 for(i = 0; html_string[i]; i++) {
960 if(cistrncmp(html_string[i], (char*)q, p-q) == 0) {
962 print(mime ? "text/html\n" : "HTML file\n");
973 char* rfc822_string[] =
999 if(p == (char*)buf && strncmp(p, "From ", 5) == 0 && strstr(p, " remote from ")){
1006 if(*p != '\t' && *p != ' '){
1010 for(i = 0; rfc822_string[i]; i++) {
1011 if(cistrncmp(p, rfc822_string[i], strlen(rfc822_string[i])) == 0){
1020 print(mime ? "message/rfc822\n" : "email file\n");
1032 q = strchr(p, '\n');
1036 if(strncmp(p, "From ", 5) == 0 && strstr(p, " remote from ") == nil){
1037 print(mime ? "text/plain\n" : "mail box\n");
1051 if(Binit(&b, fd, OREAD) == Beof)
1054 type = objtype(&b, &name);
1060 print("%s intermediate\n", name);
1073 if(n >= 2 && wfreq[I2] >= n && wfreq[I3] >= n && cfreq['.'] >= n)
1075 if(n >= 1 && wfreq[Alword] >= n && wfreq[I3] >= n && cfreq['.'] >= n)
1080 if(wfreq[Cword] >= 5 && cfreq[';'] >= 5)
1085 if(cfreq[';'] >= 10 && cfreq['='] >= 10 && wfreq[Cword] >= 1)
1094 if(wfreq[Alword] > 0)
1095 print("alef program\n");
1097 print("c program\n");
1108 if(wfreq[Lword] < 4)
1110 print(mime ? PLAIN : "limbo program\n");
1121 if(wfreq[Aword] < 2)
1123 print(mime ? PLAIN : "as program\n");
1128 * low entropy means encrypted
1138 memset(bucket, 0, sizeof(bucket));
1139 for(i=nbuf-64; i<nbuf; i++)
1140 bucket[(buf[i]>>5)&07] += 1;
1144 cs += (bucket[i]-8)*(bucket[i]-8);
1147 if(buf[0]==0x1f && buf[1]==0x9d)
1148 print(mime ? OCTET : "compressed\n");
1150 if(buf[0]==0x1f && buf[1]==0x8b)
1151 print(mime ? OCTET : "gzip compressed\n");
1153 if(buf[0]=='B' && buf[1]=='Z' && buf[2]=='h')
1154 print(mime ? OCTET : "bzip2 compressed\n");
1156 print(mime ? OCTET : "encrypted\n");
1163 * english by punctuation and frequencies
1168 int vow, comm, rare, badpun, punct;
1171 if(guess != Fascii && guess != Feascii)
1175 for(p = (char *)buf; p < (char *)buf+nbuf-1; p++)
1185 if(p[1] != ' ' && p[1] != '\n')
1188 if(badpun*5 > punct)
1190 if(cfreq['>']+cfreq['<']+cfreq['/'] > cfreq['e']) /* shell file test */
1192 if(2*cfreq[';'] > cfreq['e'])
1196 for(p="AEIOU"; *p; p++) {
1198 vow += cfreq[tolower(*p)];
1201 for(p="ETAION"; *p; p++) {
1203 comm += cfreq[tolower(*p)];
1206 for(p="VJKQXZ"; *p; p++) {
1208 rare += cfreq[tolower(*p)];
1210 if(vow*5 >= nbuf-cfreq[' '] && comm >= 10*rare) {
1211 print(mime ? PLAIN : "English text\n");
1218 * pick up a number with
1248 depthof(char *s, int *newp)
1255 while(s<es && *s==' ')
1259 if('0'<=*s && *s<='9')
1260 return 1<<strtol(s, 0, 0);
1264 while(s<es && *s!=' '){
1265 s++; /* skip letter */
1266 d += strtoul(s, &s, 10);
1269 if(d % 8 == 0 || 8 % d == 0)
1278 int dep, lox, loy, hix, hiy, px, new, cmpr;
1288 if(memcmp(cp, "compressed\n", 11) == 0) {
1293 dep = depthof((char*)cp + 0*P9BITLEN, &new);
1296 lox = p9bitnum(cp + 1*P9BITLEN);
1297 loy = p9bitnum(cp + 2*P9BITLEN);
1298 hix = p9bitnum(cp + 3*P9BITLEN);
1299 hiy = p9bitnum(cp + 4*P9BITLEN);
1300 if(dep < 0 || lox < 0 || loy < 0 || hix < 0 || hiy < 0)
1304 px = 8/dep; /* pixels per byte */
1305 /* set l to number of bytes of data per scan line */
1307 len = (hix+px-1)/px - lox/px;
1308 else{ /* make positive before divide */
1311 len = (t+hix+px-1)/px;
1314 len = (hix-lox)*dep/8;
1315 len *= hiy - loy; /* col length */
1316 len += 5 * P9BITLEN; /* size of initial ascii */
1319 * for compressed images, don't look any further. otherwise:
1320 * for image file, length is non-zero and must match calculation above.
1321 * for /dev/window and /dev/screen the length is always zero.
1322 * for subfont, the subfont header should follow immediately.
1325 print(mime ? OCTET : "Compressed %splan 9 image or subfont, depth %d\n",
1330 * mbuf->length == 0 probably indicates reading a pipe.
1331 * Ghostscript sometimes produces a little extra on the end.
1333 if (len != 0 && (mbuf->length == 0 || mbuf->length == len ||
1334 mbuf->length > len && mbuf->length < len+P9BITLEN)) {
1335 print(mime ? OCTET : "%splan 9 image, depth %d\n", newlabel, dep);
1338 if (p9subfont(buf+len)) {
1339 print(mime ? OCTET : "%ssubfont file, depth %d\n", newlabel, dep);
1350 /* if image too big, assume it's a subfont */
1351 if (p+3*P9BITLEN > buf+sizeof(buf))
1354 n = p9bitnum(p + 0*P9BITLEN); /* char count */
1357 h = p9bitnum(p + 1*P9BITLEN); /* height */
1360 a = p9bitnum(p + 2*P9BITLEN); /* ascent */
1366 #define WHITESPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
1373 char pathname[1024];
1376 if (!getfontnum(cp, &cp)) /* height */
1378 if (!getfontnum(cp, &cp)) /* ascent */
1380 for (i = 0; cp=(uchar*)strchr((char*)cp, '\n'); i++) {
1381 if (!getfontnum(cp, &cp)) /* min */
1383 if (!getfontnum(cp, &cp)) /* max */
1385 getfontnum(cp, &cp); /* optional offset */
1386 while (WHITESPACE(*cp))
1388 for (p = cp; *cp && !WHITESPACE(*cp); cp++)
1390 /* construct a path name, if needed */
1392 if (*p != '/' && slash) {
1394 if (n < sizeof(pathname))
1395 memcpy(pathname, fname, n);
1398 if (n+cp-p+4 < sizeof(pathname)) {
1399 memcpy(pathname+n, p, cp-p);
1402 if (access(pathname, AEXIST) < 0) {
1403 strcpy(pathname+n, ".0");
1404 if (access(pathname, AEXIST) < 0)
1410 print(mime ? "text/plain\n" : "font file\n");
1417 getfontnum(uchar *cp, uchar **rp)
1419 while (WHITESPACE(*cp)) /* extract ulong delimited by whitespace */
1421 if (*cp < '0' || *cp > '9')
1423 strtoul((char *)cp, (char **)rp, 0);
1424 if (!WHITESPACE(**rp)) {
1434 if(strstr((char *)buf, "\\rtf1")){
1435 print(mime ? "application/rtf\n" : "rich text format\n");
1444 if (buf[0] == 0x4d && buf[1] == 0x5a){
1445 print(mime ? "application/x-msdownload\n" : "MSDOS executable\n");
1454 static char *cpu[] = { /* NB: incomplete and arbitary list */
1477 static char *type[] = {
1478 [1] "relocatable object",
1480 [3] "shared library",
1484 if (memcmp(buf, "\x7fELF", 4) == 0){
1487 int n = (buf[19] << 8) | buf[18];
1488 char *p = "unknown";
1489 char *t = "unknown";
1491 if (n > 0 && n < nelem(cpu) && cpu[n])
1494 /* try the other byte order */
1496 n = (buf[18] << 8) | buf[19];
1497 if (n > 0 && n < nelem(cpu) && cpu[n])
1501 n = (buf[16]<< 8) | buf[17];
1503 n = (buf[17]<< 8) | buf[16];
1505 if(n>0 && n < nelem(type) && type[n])
1507 print("%s ELF %s\n", p, t);
1510 print("application/x-elf-executable");
1520 int i, j, ldepth, l;
1524 for(j = 0; j < 3; j++){
1525 for(p = (char*)buf, i=0; i<3; i++){
1526 if(p[0] != '0' || p[1] != 'x')
1530 else if(buf[2+4] == ',')
1541 while(*p == ' ' || *p == '\t')
1549 print("application/x-face\n");
1551 print("face image depth %d\n", ldepth);