xref: /plan9/sys/src/cmd/file.c (revision 169412245338dfec43f8f92e11a8c60d07ec34d7)
1bd389b36SDavid du Colombier #include <u.h>
2bd389b36SDavid du Colombier #include <libc.h>
3bd389b36SDavid du Colombier #include <bio.h>
4bd389b36SDavid du Colombier #include <ctype.h>
5bd389b36SDavid du Colombier #include <mach.h>
63e12c5d1SDavid du Colombier 
73e12c5d1SDavid du Colombier /*
83e12c5d1SDavid du Colombier  * file - determine type of file
93e12c5d1SDavid du Colombier  */
103e12c5d1SDavid du Colombier #define	LENDIAN(p)	((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
113e12c5d1SDavid du Colombier 
129a747e4fSDavid du Colombier uchar	buf[6001];
133e12c5d1SDavid du Colombier short	cfreq[140];
143e12c5d1SDavid du Colombier short	wfreq[50];
153e12c5d1SDavid du Colombier int	nbuf;
169a747e4fSDavid du Colombier Dir*	mbuf;
173e12c5d1SDavid du Colombier int	fd;
183e12c5d1SDavid du Colombier char 	*fname;
193e12c5d1SDavid du Colombier char	*slash;
203e12c5d1SDavid du Colombier 
213e12c5d1SDavid du Colombier enum
223e12c5d1SDavid du Colombier {
233e12c5d1SDavid du Colombier 	Cword,
243e12c5d1SDavid du Colombier 	Fword,
253e12c5d1SDavid du Colombier 	Aword,
26219b2ee8SDavid du Colombier 	Alword,
277dd7cddfSDavid du Colombier 	Lword,
283e12c5d1SDavid du Colombier 	I1,
293e12c5d1SDavid du Colombier 	I2,
303e12c5d1SDavid du Colombier 	I3,
313e12c5d1SDavid du Colombier 	Clatin	= 128,
323e12c5d1SDavid du Colombier 	Cbinary,
333e12c5d1SDavid du Colombier 	Cnull,
343e12c5d1SDavid du Colombier 	Ceascii,
353e12c5d1SDavid du Colombier 	Cutf,
363e12c5d1SDavid du Colombier };
373e12c5d1SDavid du Colombier struct
383e12c5d1SDavid du Colombier {
393e12c5d1SDavid du Colombier 	char*	word;
403e12c5d1SDavid du Colombier 	int	class;
413e12c5d1SDavid du Colombier } dict[] =
423e12c5d1SDavid du Colombier {
437dd7cddfSDavid du Colombier 	"PATH",		Lword,
44219b2ee8SDavid du Colombier 	"TEXT",		Aword,
45219b2ee8SDavid du Colombier 	"adt",		Alword,
46219b2ee8SDavid du Colombier 	"aggr",		Alword,
47219b2ee8SDavid du Colombier 	"alef",		Alword,
487dd7cddfSDavid du Colombier 	"array",	Lword,
49219b2ee8SDavid du Colombier 	"block",	Fword,
50219b2ee8SDavid du Colombier 	"chan",		Alword,
51219b2ee8SDavid du Colombier 	"char",		Cword,
52219b2ee8SDavid du Colombier 	"common",	Fword,
537dd7cddfSDavid du Colombier 	"con",		Lword,
54219b2ee8SDavid du Colombier 	"data",		Fword,
55219b2ee8SDavid du Colombier 	"dimension",	Fword,
56219b2ee8SDavid du Colombier 	"double",	Cword,
57219b2ee8SDavid du Colombier 	"extern",	Cword,
58219b2ee8SDavid du Colombier 	"bio",		I2,
59219b2ee8SDavid du Colombier 	"float",	Cword,
607dd7cddfSDavid du Colombier 	"fn",		Lword,
61219b2ee8SDavid du Colombier 	"function",	Fword,
62219b2ee8SDavid du Colombier 	"h",		I3,
637dd7cddfSDavid du Colombier 	"implement",	Lword,
647dd7cddfSDavid du Colombier 	"import",	Lword,
65219b2ee8SDavid du Colombier 	"include",	I1,
66219b2ee8SDavid du Colombier 	"int",		Cword,
67219b2ee8SDavid du Colombier 	"integer",	Fword,
687dd7cddfSDavid du Colombier 	"iota",		Lword,
69219b2ee8SDavid du Colombier 	"libc",		I2,
70219b2ee8SDavid du Colombier 	"long",		Cword,
717dd7cddfSDavid du Colombier 	"module",	Lword,
72219b2ee8SDavid du Colombier 	"real",		Fword,
737dd7cddfSDavid du Colombier 	"ref",		Lword,
74219b2ee8SDavid du Colombier 	"register",	Cword,
757dd7cddfSDavid du Colombier 	"self",		Lword,
76219b2ee8SDavid du Colombier 	"short",	Cword,
77219b2ee8SDavid du Colombier 	"static",	Cword,
78219b2ee8SDavid du Colombier 	"stdio",	I2,
79219b2ee8SDavid du Colombier 	"struct",	Cword,
80219b2ee8SDavid du Colombier 	"subroutine",	Fword,
81219b2ee8SDavid du Colombier 	"u",		I2,
82219b2ee8SDavid du Colombier 	"void",		Cword,
83219b2ee8SDavid du Colombier };
84219b2ee8SDavid du Colombier 
85219b2ee8SDavid du Colombier /* codes for 'mode' field in language structure */
86219b2ee8SDavid du Colombier enum	{
87219b2ee8SDavid du Colombier 		Normal	= 0,
88219b2ee8SDavid du Colombier 		First,		/* first entry for language spanning several ranges */
89219b2ee8SDavid du Colombier 		Multi,		/* later entries "   "       "  ... */
90219b2ee8SDavid du Colombier 		Shared,		/* codes used in several languages */
913e12c5d1SDavid du Colombier 	};
923e12c5d1SDavid du Colombier 
933e12c5d1SDavid du Colombier struct
943e12c5d1SDavid du Colombier {
95219b2ee8SDavid du Colombier 	int	mode;		/* see enum above */
963e12c5d1SDavid du Colombier 	int 	count;
973e12c5d1SDavid du Colombier 	int	low;
983e12c5d1SDavid du Colombier 	int	high;
993e12c5d1SDavid du Colombier 	char	*name;
1003e12c5d1SDavid du Colombier 
1013e12c5d1SDavid du Colombier } language[] =
1023e12c5d1SDavid du Colombier {
103219b2ee8SDavid du Colombier 	Normal, 0,	0x0080, 0x0080,	"Extended Latin",
104219b2ee8SDavid du Colombier 	Normal,	0,	0x0100,	0x01FF,	"Extended Latin",
105219b2ee8SDavid du Colombier 	Normal,	0,	0x0370,	0x03FF,	"Greek",
106219b2ee8SDavid du Colombier 	Normal,	0,	0x0400,	0x04FF,	"Cyrillic",
107219b2ee8SDavid du Colombier 	Normal,	0,	0x0530,	0x058F,	"Armenian",
108219b2ee8SDavid du Colombier 	Normal,	0,	0x0590,	0x05FF,	"Hebrew",
109219b2ee8SDavid du Colombier 	Normal,	0,	0x0600,	0x06FF,	"Arabic",
110219b2ee8SDavid du Colombier 	Normal,	0,	0x0900,	0x097F,	"Devanagari",
111219b2ee8SDavid du Colombier 	Normal,	0,	0x0980,	0x09FF,	"Bengali",
112219b2ee8SDavid du Colombier 	Normal,	0,	0x0A00,	0x0A7F,	"Gurmukhi",
113219b2ee8SDavid du Colombier 	Normal,	0,	0x0A80,	0x0AFF,	"Gujarati",
114219b2ee8SDavid du Colombier 	Normal,	0,	0x0B00,	0x0B7F,	"Oriya",
115219b2ee8SDavid du Colombier 	Normal,	0,	0x0B80,	0x0BFF,	"Tamil",
116219b2ee8SDavid du Colombier 	Normal,	0,	0x0C00,	0x0C7F,	"Telugu",
117219b2ee8SDavid du Colombier 	Normal,	0,	0x0C80,	0x0CFF,	"Kannada",
118219b2ee8SDavid du Colombier 	Normal,	0,	0x0D00,	0x0D7F,	"Malayalam",
119219b2ee8SDavid du Colombier 	Normal,	0,	0x0E00,	0x0E7F,	"Thai",
120219b2ee8SDavid du Colombier 	Normal,	0,	0x0E80,	0x0EFF,	"Lao",
121219b2ee8SDavid du Colombier 	Normal,	0,	0x1000,	0x105F,	"Tibetan",
122219b2ee8SDavid du Colombier 	Normal,	0,	0x10A0,	0x10FF,	"Georgian",
123219b2ee8SDavid du Colombier 	Normal,	0,	0x3040,	0x30FF,	"Japanese",
124219b2ee8SDavid du Colombier 	Normal,	0,	0x3100,	0x312F,	"Chinese",
125219b2ee8SDavid du Colombier 	First,	0,	0x3130,	0x318F,	"Korean",
126219b2ee8SDavid du Colombier 	Multi,	0,	0x3400,	0x3D2F,	"Korean",
127219b2ee8SDavid du Colombier 	Shared,	0,	0x4e00,	0x9fff,	"CJK",
128219b2ee8SDavid du Colombier 	Normal,	0,	0,	0,	0,		/* terminal entry */
1293e12c5d1SDavid du Colombier };
1303e12c5d1SDavid du Colombier 
1313e12c5d1SDavid du Colombier 
1323e12c5d1SDavid du Colombier enum
1333e12c5d1SDavid du Colombier {
1343e12c5d1SDavid du Colombier 	Fascii,		/* printable ascii */
1353e12c5d1SDavid du Colombier 	Flatin,		/* latin 1*/
1363e12c5d1SDavid du Colombier 	Futf,		/* UTf character set */
1373e12c5d1SDavid du Colombier 	Fbinary,	/* binary */
1383e12c5d1SDavid du Colombier 	Feascii,	/* ASCII with control chars */
1393e12c5d1SDavid du Colombier 	Fnull,		/* NULL in file */
1403e12c5d1SDavid du Colombier } guess;
1413e12c5d1SDavid du Colombier 
1423e12c5d1SDavid du Colombier void	bump_utf_count(Rune);
1437dd7cddfSDavid du Colombier int	cistrncmp(char*, char*, int);
1443e12c5d1SDavid du Colombier void	filetype(int);
1453e12c5d1SDavid du Colombier int	getfontnum(uchar*, uchar**);
1463e12c5d1SDavid du Colombier int	isas(void);
1473e12c5d1SDavid du Colombier int	isc(void);
1483e12c5d1SDavid du Colombier int	iscint(void);
1493e12c5d1SDavid du Colombier int	isenglish(void);
1507dd7cddfSDavid du Colombier int	ishp(void);
1517dd7cddfSDavid du Colombier int	ishtml(void);
1529a747e4fSDavid du Colombier int	isrfc822(void);
153d9306527SDavid du Colombier int	ismbox(void);
1547dd7cddfSDavid du Colombier int	islimbo(void);
1553e12c5d1SDavid du Colombier int	ismung(void);
1563e12c5d1SDavid du Colombier int	isp9bit(void);
1573e12c5d1SDavid du Colombier int	isp9font(void);
158fb7f0c93SDavid du Colombier int	isrtf(void);
159f2e8132aSDavid du Colombier int	ismsdos(void);
160b7327ca2SDavid du Colombier int	iself(void);
1613e12c5d1SDavid du Colombier int	istring(void);
162ddb951e3SDavid du Colombier int	iff(void);
1633e12c5d1SDavid du Colombier int	long0(void);
1644b30ca09SDavid du Colombier int	istar(void);
1653e12c5d1SDavid du Colombier int	p9bitnum(uchar*);
1663e12c5d1SDavid du Colombier int	p9subfont(uchar*);
1673e12c5d1SDavid du Colombier void	print_utf(void);
1683e12c5d1SDavid du Colombier void	type(char*, int);
1693e12c5d1SDavid du Colombier int	utf_count(void);
1703e12c5d1SDavid du Colombier void	wordfreq(void);
1713e12c5d1SDavid du Colombier 
1723e12c5d1SDavid du Colombier int	(*call[])(void) =
1733e12c5d1SDavid du Colombier {
1743e12c5d1SDavid du Colombier 	long0,		/* recognizable by first 4 bytes */
1753e12c5d1SDavid du Colombier 	istring,	/* recognizable by first string */
176ddb951e3SDavid du Colombier 	iff,		/* interchange file format (strings) */
1779a747e4fSDavid du Colombier 	isrfc822,	/* email file */
178d9306527SDavid du Colombier 	ismbox,		/* mail box */
1794b30ca09SDavid du Colombier 	istar,		/* recognizable by tar checksum */
180643074abSDavid du Colombier 	ishtml,		/* html keywords */
181219b2ee8SDavid du Colombier 	iscint,		/* compiler/assembler intermediate */
1827dd7cddfSDavid du Colombier 	islimbo,	/* limbo source */
183219b2ee8SDavid du Colombier 	isc,		/* c & alef compiler key words */
1843e12c5d1SDavid du Colombier 	isas,		/* assembler key words */
1853e12c5d1SDavid du Colombier 	ismung,		/* entropy compressed/encrypted */
1863e12c5d1SDavid du Colombier 	isp9font,	/* plan 9 font */
1877dd7cddfSDavid du Colombier 	isp9bit,	/* plan 9 image (as from /dev/window) */
1887dd7cddfSDavid du Colombier 	isenglish,	/* char frequency English */
189fb7f0c93SDavid du Colombier 	isrtf,		/* rich text format */
190f2e8132aSDavid du Colombier 	ismsdos,	/* msdos exe (virus file attachement) */
191b7327ca2SDavid du Colombier 	iself,		/* ELF (foreign) executable */
1923e12c5d1SDavid du Colombier 	0
1933e12c5d1SDavid du Colombier };
1943e12c5d1SDavid du Colombier 
1957dd7cddfSDavid du Colombier int mime;
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier #define OCTET	"application/octet-stream\n"
1987dd7cddfSDavid du Colombier #define PLAIN	"text/plain\n"
1997dd7cddfSDavid du Colombier 
2003e12c5d1SDavid du Colombier void
2013e12c5d1SDavid du Colombier main(int argc, char *argv[])
2023e12c5d1SDavid du Colombier {
2033e12c5d1SDavid du Colombier 	int i, j, maxlen;
2043e12c5d1SDavid du Colombier 	char *cp;
2053e12c5d1SDavid du Colombier 	Rune r;
2063e12c5d1SDavid du Colombier 
2077dd7cddfSDavid du Colombier 	ARGBEGIN{
2087dd7cddfSDavid du Colombier 	case 'm':
2097dd7cddfSDavid du Colombier 		mime = 1;
2107dd7cddfSDavid du Colombier 		break;
2117dd7cddfSDavid du Colombier 	default:
2127dd7cddfSDavid du Colombier 		fprint(2, "usage: file [-m] [file...]\n");
2137dd7cddfSDavid du Colombier 		exits("usage");
2147dd7cddfSDavid du Colombier 	}ARGEND;
2157dd7cddfSDavid du Colombier 
2163e12c5d1SDavid du Colombier 	maxlen = 0;
2177dd7cddfSDavid du Colombier 	if(mime == 0 || argc > 1){
2187dd7cddfSDavid du Colombier 		for(i = 0; i < argc; i++) {
2193e12c5d1SDavid du Colombier 			for (j = 0, cp = argv[i]; *cp; j++, cp += chartorune(&r, cp))
2203e12c5d1SDavid du Colombier 					;
2213e12c5d1SDavid du Colombier 			if(j > maxlen)
2223e12c5d1SDavid du Colombier 				maxlen = j;
2233e12c5d1SDavid du Colombier 		}
2247dd7cddfSDavid du Colombier 	}
2257dd7cddfSDavid du Colombier 	if (argc <= 0) {
2267dd7cddfSDavid du Colombier 		if(!mime)
2273e12c5d1SDavid du Colombier 			print ("stdin: ");
2283e12c5d1SDavid du Colombier 		filetype(0);
2293e12c5d1SDavid du Colombier 	}
2303e12c5d1SDavid du Colombier 	else {
2317dd7cddfSDavid du Colombier 		for(i = 0; i < argc; i++)
2323e12c5d1SDavid du Colombier 			type(argv[i], maxlen);
2333e12c5d1SDavid du Colombier 	}
2343e12c5d1SDavid du Colombier 	exits(0);
2353e12c5d1SDavid du Colombier }
2363e12c5d1SDavid du Colombier 
2373e12c5d1SDavid du Colombier void
2383e12c5d1SDavid du Colombier type(char *file, int nlen)
2393e12c5d1SDavid du Colombier {
2403e12c5d1SDavid du Colombier 	Rune r;
2413e12c5d1SDavid du Colombier 	int i;
2423e12c5d1SDavid du Colombier 	char *p;
2433e12c5d1SDavid du Colombier 
2447dd7cddfSDavid du Colombier 	if(nlen > 0){
2453e12c5d1SDavid du Colombier 		slash = 0;
2463e12c5d1SDavid du Colombier 		for (i = 0, p = file; *p; i++) {
2473e12c5d1SDavid du Colombier 			if (*p == '/')			/* find rightmost slash */
2483e12c5d1SDavid du Colombier 				slash = p;
2493e12c5d1SDavid du Colombier 			p += chartorune(&r, p);		/* count runes */
2503e12c5d1SDavid du Colombier 		}
2513e12c5d1SDavid du Colombier 		print("%s:%*s",file, nlen-i+1, "");
2527dd7cddfSDavid du Colombier 	}
2533e12c5d1SDavid du Colombier 	fname = file;
2543e12c5d1SDavid du Colombier 	if ((fd = open(file, OREAD)) < 0) {
2553e12c5d1SDavid du Colombier 		print("cannot open\n");
2563e12c5d1SDavid du Colombier 		return;
2573e12c5d1SDavid du Colombier 	}
2583e12c5d1SDavid du Colombier 	filetype(fd);
2593e12c5d1SDavid du Colombier 	close(fd);
2603e12c5d1SDavid du Colombier }
2613e12c5d1SDavid du Colombier 
2623e12c5d1SDavid du Colombier void
2633e12c5d1SDavid du Colombier filetype(int fd)
2643e12c5d1SDavid du Colombier {
2653e12c5d1SDavid du Colombier 	Rune r;
266219b2ee8SDavid du Colombier 	int i, f, n;
267219b2ee8SDavid du Colombier 	char *p, *eob;
2683e12c5d1SDavid du Colombier 
2699a747e4fSDavid du Colombier 	free(mbuf);
2709a747e4fSDavid du Colombier 	mbuf = dirfstat(fd);
2719a747e4fSDavid du Colombier 	if(mbuf == nil){
2729a747e4fSDavid du Colombier 		print("cannot stat: %r\n");
2733e12c5d1SDavid du Colombier 		return;
2743e12c5d1SDavid du Colombier 	}
2759a747e4fSDavid du Colombier 	if(mbuf->mode & DMDIR) {
2767dd7cddfSDavid du Colombier 		print(mime ? "text/directory\n" : "directory\n");
2773e12c5d1SDavid du Colombier 		return;
2783e12c5d1SDavid du Colombier 	}
2799a747e4fSDavid du Colombier 	if(mbuf->type != 'M' && mbuf->type != '|') {
2807dd7cddfSDavid du Colombier 		print(mime ? OCTET : "special file #%c/%s\n",
2819a747e4fSDavid du Colombier 			mbuf->type, mbuf->name);
2823e12c5d1SDavid du Colombier 		return;
2833e12c5d1SDavid du Colombier 	}
2849a747e4fSDavid du Colombier 	nbuf = read(fd, buf, sizeof(buf)-1);
2853e12c5d1SDavid du Colombier 
2863e12c5d1SDavid du Colombier 	if(nbuf < 0) {
2873e12c5d1SDavid du Colombier 		print("cannot read\n");
2883e12c5d1SDavid du Colombier 		return;
2893e12c5d1SDavid du Colombier 	}
2903e12c5d1SDavid du Colombier 	if(nbuf == 0) {
2917dd7cddfSDavid du Colombier 		print(mime ? PLAIN : "empty file\n");
2923e12c5d1SDavid du Colombier 		return;
2933e12c5d1SDavid du Colombier 	}
2949a747e4fSDavid du Colombier 	buf[nbuf] = 0;
2953e12c5d1SDavid du Colombier 
2963e12c5d1SDavid du Colombier 	/*
2973e12c5d1SDavid du Colombier 	 * build histogram table
2983e12c5d1SDavid du Colombier 	 */
2993e12c5d1SDavid du Colombier 	memset(cfreq, 0, sizeof(cfreq));
3003e12c5d1SDavid du Colombier 	for (i = 0; language[i].name; i++)
3013e12c5d1SDavid du Colombier 		language[i].count = 0;
302219b2ee8SDavid du Colombier 	eob = (char *)buf+nbuf;
303219b2ee8SDavid du Colombier 	for(n = 0, p = (char *)buf; p < eob; n++) {
304219b2ee8SDavid du Colombier 		if (!fullrune(p, eob-p) && eob-p < UTFmax)
305219b2ee8SDavid du Colombier 			break;
3063e12c5d1SDavid du Colombier 		p += chartorune(&r, p);
3073e12c5d1SDavid du Colombier 		if (r == 0)
3083e12c5d1SDavid du Colombier 			f = Cnull;
3093e12c5d1SDavid du Colombier 		else if (r <= 0x7f) {
3103e12c5d1SDavid du Colombier 			if (!isprint(r) && !isspace(r))
3113e12c5d1SDavid du Colombier 				f = Ceascii;	/* ASCII control char */
3123e12c5d1SDavid du Colombier 			else f = r;
313219b2ee8SDavid du Colombier 		} else if (r == 0x080) {
314219b2ee8SDavid du Colombier 			bump_utf_count(r);
315219b2ee8SDavid du Colombier 			f = Cutf;
3163e12c5d1SDavid du Colombier 		} else if (r < 0xA0)
3173e12c5d1SDavid du Colombier 				f = Cbinary;	/* Invalid Runes */
3183e12c5d1SDavid du Colombier 		else if (r <= 0xff)
3193e12c5d1SDavid du Colombier 				f = Clatin;	/* Latin 1 */
3203e12c5d1SDavid du Colombier 		else {
3213e12c5d1SDavid du Colombier 			bump_utf_count(r);
3223e12c5d1SDavid du Colombier 			f = Cutf;		/* UTF extension */
3233e12c5d1SDavid du Colombier 		}
3243e12c5d1SDavid du Colombier 		cfreq[f]++;			/* ASCII chars peg directly */
3253e12c5d1SDavid du Colombier 	}
3263e12c5d1SDavid du Colombier 	/*
3273e12c5d1SDavid du Colombier 	 * gross classify
3283e12c5d1SDavid du Colombier 	 */
3293e12c5d1SDavid du Colombier 	if (cfreq[Cbinary])
3303e12c5d1SDavid du Colombier 		guess = Fbinary;
3313e12c5d1SDavid du Colombier 	else if (cfreq[Cutf])
3323e12c5d1SDavid du Colombier 		guess = Futf;
3333e12c5d1SDavid du Colombier 	else if (cfreq[Clatin])
3343e12c5d1SDavid du Colombier 		guess = Flatin;
3353e12c5d1SDavid du Colombier 	else if (cfreq[Ceascii])
3363e12c5d1SDavid du Colombier 		guess = Feascii;
337219b2ee8SDavid du Colombier 	else if (cfreq[Cnull] == n) {
33859cc4ca5SDavid du Colombier 		print(mime ? OCTET : "first block all null bytes\n");
3393e12c5d1SDavid du Colombier 		return;
3403e12c5d1SDavid du Colombier 	}
3413e12c5d1SDavid du Colombier 	else guess = Fascii;
3423e12c5d1SDavid du Colombier 	/*
3433e12c5d1SDavid du Colombier 	 * lookup dictionary words
3443e12c5d1SDavid du Colombier 	 */
345219b2ee8SDavid du Colombier 	memset(wfreq, 0, sizeof(wfreq));
3467dd7cddfSDavid du Colombier 	if(guess == Fascii || guess == Flatin || guess == Futf)
3473e12c5d1SDavid du Colombier 		wordfreq();
3483e12c5d1SDavid du Colombier 	/*
3493e12c5d1SDavid du Colombier 	 * call individual classify routines
3503e12c5d1SDavid du Colombier 	 */
3513e12c5d1SDavid du Colombier 	for(i=0; call[i]; i++)
3523e12c5d1SDavid du Colombier 		if((*call[i])())
3533e12c5d1SDavid du Colombier 			return;
3543e12c5d1SDavid du Colombier 
3553e12c5d1SDavid du Colombier 	/*
3563e12c5d1SDavid du Colombier 	 * if all else fails,
3573e12c5d1SDavid du Colombier 	 * print out gross classification
3583e12c5d1SDavid du Colombier 	 */
35980ee5cbfSDavid du Colombier 	if (nbuf < 100 && !mime)
3607dd7cddfSDavid du Colombier 		print(mime ? PLAIN : "short ");
3613e12c5d1SDavid du Colombier 	if (guess == Fascii)
3627dd7cddfSDavid du Colombier 		print(mime ? PLAIN : "Ascii\n");
3633e12c5d1SDavid du Colombier 	else if (guess == Feascii)
3647dd7cddfSDavid du Colombier 		print(mime ? PLAIN : "extended ascii\n");
3653e12c5d1SDavid du Colombier 	else if (guess == Flatin)
3667dd7cddfSDavid du Colombier 		print(mime ? PLAIN : "latin ascii\n");
3673e12c5d1SDavid du Colombier 	else if (guess == Futf && utf_count() < 4)
3683e12c5d1SDavid du Colombier 		print_utf();
3697dd7cddfSDavid du Colombier 	else print(mime ? OCTET : "binary\n");
3703e12c5d1SDavid du Colombier }
3713e12c5d1SDavid du Colombier 
3723e12c5d1SDavid du Colombier void
3733e12c5d1SDavid du Colombier bump_utf_count(Rune r)
3743e12c5d1SDavid du Colombier {
3753e12c5d1SDavid du Colombier 	int low, high, mid;
3763e12c5d1SDavid du Colombier 
3773e12c5d1SDavid du Colombier 	high = sizeof(language)/sizeof(language[0])-1;
3783e12c5d1SDavid du Colombier 	for (low = 0; low < high;) {
3793e12c5d1SDavid du Colombier 		mid = (low+high)/2;
3803e12c5d1SDavid du Colombier 		if (r >=language[mid].low) {
3813e12c5d1SDavid du Colombier 			if (r <= language[mid].high) {
3823e12c5d1SDavid du Colombier 				language[mid].count++;
3833e12c5d1SDavid du Colombier 				break;
3843e12c5d1SDavid du Colombier 			} else low = mid+1;
3853e12c5d1SDavid du Colombier 		} else high = mid;
3863e12c5d1SDavid du Colombier 	}
3873e12c5d1SDavid du Colombier }
3883e12c5d1SDavid du Colombier 
3893e12c5d1SDavid du Colombier int
3903e12c5d1SDavid du Colombier utf_count(void)
3913e12c5d1SDavid du Colombier {
3923e12c5d1SDavid du Colombier 	int i, count;
3933e12c5d1SDavid du Colombier 
394219b2ee8SDavid du Colombier 	count = 0;
395219b2ee8SDavid du Colombier 	for (i = 0; language[i].name; i++)
3963e12c5d1SDavid du Colombier 		if (language[i].count > 0)
397219b2ee8SDavid du Colombier 			switch (language[i].mode) {
398219b2ee8SDavid du Colombier 			case Normal:
399219b2ee8SDavid du Colombier 			case First:
4003e12c5d1SDavid du Colombier 				count++;
401219b2ee8SDavid du Colombier 				break;
402219b2ee8SDavid du Colombier 			default:
403219b2ee8SDavid du Colombier 				break;
404219b2ee8SDavid du Colombier 			}
4053e12c5d1SDavid du Colombier 	return count;
4063e12c5d1SDavid du Colombier }
4073e12c5d1SDavid du Colombier 
408219b2ee8SDavid du Colombier int
409219b2ee8SDavid du Colombier chkascii(void)
410219b2ee8SDavid du Colombier {
411219b2ee8SDavid du Colombier 	int i;
412219b2ee8SDavid du Colombier 
413219b2ee8SDavid du Colombier 	for (i = 'a'; i < 'z'; i++)
414219b2ee8SDavid du Colombier 		if (cfreq[i])
415219b2ee8SDavid du Colombier 			return 1;
416219b2ee8SDavid du Colombier 	for (i = 'A'; i < 'Z'; i++)
417219b2ee8SDavid du Colombier 		if (cfreq[i])
418219b2ee8SDavid du Colombier 			return 1;
419219b2ee8SDavid du Colombier 	return 0;
420219b2ee8SDavid du Colombier }
421219b2ee8SDavid du Colombier 
422219b2ee8SDavid du Colombier int
423219b2ee8SDavid du Colombier find_first(char *name)
424219b2ee8SDavid du Colombier {
425219b2ee8SDavid du Colombier 	int i;
426219b2ee8SDavid du Colombier 
427219b2ee8SDavid du Colombier 	for (i = 0; language[i].name != 0; i++)
428219b2ee8SDavid du Colombier 		if (language[i].mode == First
429219b2ee8SDavid du Colombier 			&& strcmp(language[i].name, name) == 0)
430219b2ee8SDavid du Colombier 			return i;
431219b2ee8SDavid du Colombier 	return -1;
432219b2ee8SDavid du Colombier }
433219b2ee8SDavid du Colombier 
4343e12c5d1SDavid du Colombier void
4353e12c5d1SDavid du Colombier print_utf(void)
4363e12c5d1SDavid du Colombier {
437219b2ee8SDavid du Colombier 	int i, printed, j;
4383e12c5d1SDavid du Colombier 
4397dd7cddfSDavid du Colombier 	if(mime){
4407dd7cddfSDavid du Colombier 		print(PLAIN);
4417dd7cddfSDavid du Colombier 		return;
4427dd7cddfSDavid du Colombier 	}
443219b2ee8SDavid du Colombier 	if (chkascii()) {
444219b2ee8SDavid du Colombier 		printed = 1;
445219b2ee8SDavid du Colombier 		print("Ascii");
446219b2ee8SDavid du Colombier 	} else
447219b2ee8SDavid du Colombier 		printed = 0;
448219b2ee8SDavid du Colombier 	for (i = 0; language[i].name; i++)
4493e12c5d1SDavid du Colombier 		if (language[i].count) {
450219b2ee8SDavid du Colombier 			switch(language[i].mode) {
451219b2ee8SDavid du Colombier 			case Multi:
452219b2ee8SDavid du Colombier 				j = find_first(language[i].name);
453219b2ee8SDavid du Colombier 				if (j < 0)
454219b2ee8SDavid du Colombier 					break;
455219b2ee8SDavid du Colombier 				if (language[j].count > 0)
456219b2ee8SDavid du Colombier 					break;
457219b2ee8SDavid du Colombier 				/* Fall through */
458219b2ee8SDavid du Colombier 			case Normal:
459219b2ee8SDavid du Colombier 			case First:
4603e12c5d1SDavid du Colombier 				if (printed)
4613e12c5d1SDavid du Colombier 					print(" & ");
4623e12c5d1SDavid du Colombier 				else printed = 1;
4633e12c5d1SDavid du Colombier 				print("%s", language[i].name);
464219b2ee8SDavid du Colombier 				break;
465219b2ee8SDavid du Colombier 			case Shared:
466219b2ee8SDavid du Colombier 			default:
467219b2ee8SDavid du Colombier 				break;
468219b2ee8SDavid du Colombier 			}
4693e12c5d1SDavid du Colombier 		}
4703e12c5d1SDavid du Colombier 	if(!printed)
4713e12c5d1SDavid du Colombier 		print("UTF");
4723e12c5d1SDavid du Colombier 	print(" text\n");
4733e12c5d1SDavid du Colombier }
4743e12c5d1SDavid du Colombier 
4753e12c5d1SDavid du Colombier void
4763e12c5d1SDavid du Colombier wordfreq(void)
4773e12c5d1SDavid du Colombier {
478219b2ee8SDavid du Colombier 	int low, high, mid, r;
479219b2ee8SDavid du Colombier 	uchar *p, *p2, c;
4803e12c5d1SDavid du Colombier 
481219b2ee8SDavid du Colombier 	p = buf;
482219b2ee8SDavid du Colombier 	for(;;) {
483219b2ee8SDavid du Colombier 		while (p < buf+nbuf && !isalpha(*p))
484219b2ee8SDavid du Colombier 			p++;
485219b2ee8SDavid du Colombier 		if (p >= buf+nbuf)
486219b2ee8SDavid du Colombier 			return;
487219b2ee8SDavid du Colombier 		p2 = p;
488219b2ee8SDavid du Colombier 		while(p < buf+nbuf && isalpha(*p))
489219b2ee8SDavid du Colombier 			p++;
490219b2ee8SDavid du Colombier 		c = *p;
491219b2ee8SDavid du Colombier 		*p = 0;
4923e12c5d1SDavid du Colombier 		high = sizeof(dict)/sizeof(dict[0]);
4933e12c5d1SDavid du Colombier 		for(low = 0;low < high;) {
4943e12c5d1SDavid du Colombier 			mid = (low+high)/2;
495219b2ee8SDavid du Colombier 			r = strcmp(dict[mid].word, (char*)p2);
496219b2ee8SDavid du Colombier 			if(r == 0) {
4973e12c5d1SDavid du Colombier 				wfreq[dict[mid].class]++;
4983e12c5d1SDavid du Colombier 				break;
4993e12c5d1SDavid du Colombier 			}
500219b2ee8SDavid du Colombier 			if(r < 0)
5013e12c5d1SDavid du Colombier 				low = mid+1;
5023e12c5d1SDavid du Colombier 			else
5033e12c5d1SDavid du Colombier 				high = mid;
5043e12c5d1SDavid du Colombier 		}
505219b2ee8SDavid du Colombier 		*p++ = c;
5063e12c5d1SDavid du Colombier 	}
5073e12c5d1SDavid du Colombier }
5083e12c5d1SDavid du Colombier 
5099a747e4fSDavid du Colombier typedef struct Filemagic Filemagic;
5109a747e4fSDavid du Colombier struct Filemagic {
5119a747e4fSDavid du Colombier 	ulong x;
5129a747e4fSDavid du Colombier 	ulong mask;
5139a747e4fSDavid du Colombier 	char *desc;
5149a747e4fSDavid du Colombier 	char *mime;
5159a747e4fSDavid du Colombier };
5169a747e4fSDavid du Colombier 
5179a747e4fSDavid du Colombier Filemagic long0tab[] = {
5189a747e4fSDavid du Colombier 	0xF16DF16D,	0xFFFFFFFF,	"pac1 audio file\n",	OCTET,
5199a747e4fSDavid du Colombier 	0x31636170,	0xFFFFFFFF,	"pac3 audio file\n",	OCTET,
5209a747e4fSDavid du Colombier 	0x32636170,	0xFFFF00FF,	"pac4 audio file\n",	OCTET,
5219a747e4fSDavid du Colombier 	0xBA010000,	0xFFFFFFFF,	"mpeg system stream\n",	OCTET,
5229a747e4fSDavid du Colombier 	0x30800CC0,	0xFFFFFFFF,	"inferno .dis executable\n", OCTET,
523fb7f0c93SDavid du Colombier 	0x04034B50,	0xFFFFFFFF,	"zip archive\n", "application/zip",
5249a747e4fSDavid du Colombier 	070707,		0xFFFF,		"cpio archive\n", OCTET,
525fb7f0c93SDavid du Colombier 	0x2F7,		0xFFFF,		"tex dvi\n", "application/dvi",
5269552e201SDavid du Colombier 	0xfaff,		0xfeff,		"mp3 audio\n",	"audio/mpeg",
5279a747e4fSDavid du Colombier };
5289a747e4fSDavid du Colombier 
5299a747e4fSDavid du Colombier int
5309a747e4fSDavid du Colombier filemagic(Filemagic *tab, int ntab, ulong x)
5319a747e4fSDavid du Colombier {
5329a747e4fSDavid du Colombier 	int i;
5339a747e4fSDavid du Colombier 
5349a747e4fSDavid du Colombier 	for(i=0; i<ntab; i++)
5359a747e4fSDavid du Colombier 		if((x&tab[i].mask) == tab[i].x){
5369a747e4fSDavid du Colombier 			print(mime ? tab[i].mime : tab[i].desc);
5379a747e4fSDavid du Colombier 			return 1;
5389a747e4fSDavid du Colombier 		}
5399a747e4fSDavid du Colombier 	return 0;
5409a747e4fSDavid du Colombier }
5419a747e4fSDavid du Colombier 
5423e12c5d1SDavid du Colombier int
5433e12c5d1SDavid du Colombier long0(void)
5443e12c5d1SDavid du Colombier {
5453e12c5d1SDavid du Colombier 	Fhdr f;
5467dd7cddfSDavid du Colombier 	long x;
5473e12c5d1SDavid du Colombier 
5483e12c5d1SDavid du Colombier 	seek(fd, 0, 0);		/* reposition to start of file */
5493e12c5d1SDavid du Colombier 	if(crackhdr(fd, &f)) {
5507dd7cddfSDavid du Colombier 		print(mime ? OCTET : "%s\n", f.name);
5513e12c5d1SDavid du Colombier 		return 1;
5523e12c5d1SDavid du Colombier 	}
5537dd7cddfSDavid du Colombier 	x = LENDIAN(buf);
5549a747e4fSDavid du Colombier 	if(filemagic(long0tab, nelem(long0tab), x))
555219b2ee8SDavid du Colombier 		return 1;
5567dd7cddfSDavid du Colombier 	return 0;
5577dd7cddfSDavid du Colombier }
5583e12c5d1SDavid du Colombier 
5594b30ca09SDavid du Colombier /* from tar.c */
5604b30ca09SDavid du Colombier enum { NAMSIZ = 100, TBLOCK = 512 };
5614b30ca09SDavid du Colombier 
5624b30ca09SDavid du Colombier union	hblock
5634b30ca09SDavid du Colombier {
5644b30ca09SDavid du Colombier 	char	dummy[TBLOCK];
5654b30ca09SDavid du Colombier 	struct	header
5664b30ca09SDavid du Colombier 	{
5674b30ca09SDavid du Colombier 		char	name[NAMSIZ];
5684b30ca09SDavid du Colombier 		char	mode[8];
5694b30ca09SDavid du Colombier 		char	uid[8];
5704b30ca09SDavid du Colombier 		char	gid[8];
5714b30ca09SDavid du Colombier 		char	size[12];
5724b30ca09SDavid du Colombier 		char	mtime[12];
5734b30ca09SDavid du Colombier 		char	chksum[8];
5744b30ca09SDavid du Colombier 		char	linkflag;
5754b30ca09SDavid du Colombier 		char	linkname[NAMSIZ];
5764b30ca09SDavid du Colombier 		/* rest are defined by POSIX's ustar format; see p1003.2b */
5774b30ca09SDavid du Colombier 		char	magic[6];	/* "ustar" */
5784b30ca09SDavid du Colombier 		char	version[2];
5794b30ca09SDavid du Colombier 		char	uname[32];
5804b30ca09SDavid du Colombier 		char	gname[32];
5814b30ca09SDavid du Colombier 		char	devmajor[8];
5824b30ca09SDavid du Colombier 		char	devminor[8];
5834b30ca09SDavid du Colombier 		char	prefix[155];  /* if non-null, path = prefix "/" name */
5844b30ca09SDavid du Colombier 	} dbuf;
5854b30ca09SDavid du Colombier };
5864b30ca09SDavid du Colombier 
5874b30ca09SDavid du Colombier int
5884b30ca09SDavid du Colombier checksum(union hblock *hp)
5894b30ca09SDavid du Colombier {
5904b30ca09SDavid du Colombier 	int i;
5914b30ca09SDavid du Colombier 	char *cp;
5924b30ca09SDavid du Colombier 	struct header *hdr = &hp->dbuf;
5934b30ca09SDavid du Colombier 
5944b30ca09SDavid du Colombier 	for (cp = hdr->chksum; cp < &hdr->chksum[sizeof hdr->chksum]; cp++)
5954b30ca09SDavid du Colombier 		*cp = ' ';
5964b30ca09SDavid du Colombier 	i = 0;
5974b30ca09SDavid du Colombier 	for (cp = hp->dummy; cp < &hp->dummy[TBLOCK]; cp++)
5984b30ca09SDavid du Colombier 		i += *cp & 0xff;
5994b30ca09SDavid du Colombier 	return i;
6004b30ca09SDavid du Colombier }
6014b30ca09SDavid du Colombier 
6024b30ca09SDavid du Colombier int
6034b30ca09SDavid du Colombier istar(void)
6044b30ca09SDavid du Colombier {
6054b30ca09SDavid du Colombier 	int chksum;
6064b30ca09SDavid du Colombier 	char tblock[TBLOCK];
6074b30ca09SDavid du Colombier 	union hblock *hp = (union hblock *)tblock;
6084b30ca09SDavid du Colombier 	struct header *hdr = &hp->dbuf;
6094b30ca09SDavid du Colombier 
6104b30ca09SDavid du Colombier 	seek(fd, 0, 0);		/* reposition to start of file */
6114b30ca09SDavid du Colombier 	if (readn(fd, tblock, sizeof tblock) != sizeof tblock)
6124b30ca09SDavid du Colombier 		return 0;
6134b30ca09SDavid du Colombier 	chksum = strtol(hdr->chksum, 0, 8);
6144b30ca09SDavid du Colombier 	if (hdr->name[0] != '\0' && checksum(hp) == chksum) {
6154b30ca09SDavid du Colombier 		if (strcmp(hdr->magic, "ustar") == 0)
6164b30ca09SDavid du Colombier 			print(mime? "application/x-ustar\n":
6174b30ca09SDavid du Colombier 				"posix tar archive\n");
6184b30ca09SDavid du Colombier 		else
6194b30ca09SDavid du Colombier 			print(mime? "application/x-tar\n": "tar archive\n");
6204b30ca09SDavid du Colombier 		return 1;
6214b30ca09SDavid du Colombier 	}
6224b30ca09SDavid du Colombier 	return 0;
6234b30ca09SDavid du Colombier }
6244b30ca09SDavid du Colombier 
6253e12c5d1SDavid du Colombier /*
6263e12c5d1SDavid du Colombier  * initial words to classify file
6273e12c5d1SDavid du Colombier  */
628219b2ee8SDavid du Colombier struct	FILE_STRING
629219b2ee8SDavid du Colombier {
6303e12c5d1SDavid du Colombier 	char 	*key;
6313e12c5d1SDavid du Colombier 	char	*filetype;
6323e12c5d1SDavid du Colombier 	int	length;
6337dd7cddfSDavid du Colombier 	char	*mime;
6343e12c5d1SDavid du Colombier } file_string[] =
6353e12c5d1SDavid du Colombier {
6367dd7cddfSDavid du Colombier 	"!<arch>\n__.SYMDEF",	"archive random library",	16,	"application/octet-stream",
6377dd7cddfSDavid du Colombier 	"!<arch>\n",		"archive",			8,	"application/octet-stream",
6387dd7cddfSDavid du Colombier 	"070707",		"cpio archive - ascii header",	6,	"application/octet-stream",
6397dd7cddfSDavid du Colombier 	"#!/bin/rc",		"rc executable file",		9,	"text/plain",
6407dd7cddfSDavid du Colombier 	"#!/bin/sh",		"sh executable file",		9,	"text/plain",
6417dd7cddfSDavid du Colombier 	"%!",			"postscript",			2,	"application/postscript",
6427dd7cddfSDavid du Colombier 	"\004%!",		"postscript",			3,	"application/postscript",
6437dd7cddfSDavid du Colombier 	"x T post",		"troff output for post",	8,	"application/troff",
6447dd7cddfSDavid du Colombier 	"x T Latin1",		"troff output for Latin1",	10,	"application/troff",
6457dd7cddfSDavid du Colombier 	"x T utf",		"troff output for UTF",		7,	"application/troff",
6467dd7cddfSDavid du Colombier 	"x T 202",		"troff output for 202",		7,	"application/troff",
6477dd7cddfSDavid du Colombier 	"x T aps",		"troff output for aps",		7,	"application/troff",
6487dd7cddfSDavid du Colombier 	"GIF",			"GIF image", 			3,	"image/gif",
6497dd7cddfSDavid du Colombier 	"\0PC Research, Inc\0",	"ghostscript fax file",		18,	"application/ghostscript",
65059cc4ca5SDavid du Colombier 	"%PDF",			"PDF",				4,	"application/pdf",
6517dd7cddfSDavid du Colombier 	"<html>\n",		"HTML file",			7,	"text/html",
6527dd7cddfSDavid du Colombier 	"<HTML>\n",		"HTML file",			7,	"text/html",
6537dd7cddfSDavid du Colombier 	"compressed\n",		"Compressed image or subfont",	11,	"application/octet-stream",
6547dd7cddfSDavid du Colombier 	"\111\111\052\000",	"tiff",				4,	"image/tiff",
6557dd7cddfSDavid du Colombier 	"\115\115\000\052",	"tiff",				4,	"image/tiff",
6567dd7cddfSDavid du Colombier 	"\377\330\377\340",	"jpeg",				4,	"image/jpeg",
6577dd7cddfSDavid du Colombier 	"\377\330\377\341",	"jpeg",				4,	"image/jpeg",
6587dd7cddfSDavid du Colombier 	"\377\330\377\333",	"jpeg",				4,	"image/jpeg",
659da51d93aSDavid du Colombier 	"BM",			"bmp",				2,	"image/bmp",
6607dd7cddfSDavid du Colombier 	"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1",	"microsoft office document",	8,	"application/octet-stream",
661fb7f0c93SDavid du Colombier 	"<MakerFile ",		"FrameMaker file",		11,	"application/framemaker",
662fb7f0c93SDavid du Colombier 	"\033%-12345X",	"HPJCL file",		9,	"application/hpjcl",
663ddb951e3SDavid du Colombier 	"ID3",			"mp3 audio with id3",	3,	"audio/mpeg",
6647989f6fbSDavid du Colombier 	"\211PNG",		"PNG image",		4,	"image/png",
6657dd7cddfSDavid du Colombier 	0,0,0,0
6663e12c5d1SDavid du Colombier };
6673e12c5d1SDavid du Colombier 
6683e12c5d1SDavid du Colombier int
6693e12c5d1SDavid du Colombier istring(void)
6703e12c5d1SDavid du Colombier {
6713e12c5d1SDavid du Colombier 	int i;
6723e12c5d1SDavid du Colombier 	struct FILE_STRING *p;
6733e12c5d1SDavid du Colombier 
6743e12c5d1SDavid du Colombier 	for(p = file_string; p->key; p++) {
675219b2ee8SDavid du Colombier 		if(nbuf >= p->length && !memcmp(buf, p->key, p->length)) {
6767dd7cddfSDavid du Colombier 			if(mime)
6777dd7cddfSDavid du Colombier 				print("%s\n", p->mime);
6787dd7cddfSDavid du Colombier 			else
6793e12c5d1SDavid du Colombier 				print("%s\n", p->filetype);
6803e12c5d1SDavid du Colombier 			return 1;
6813e12c5d1SDavid du Colombier 		}
6823e12c5d1SDavid du Colombier 	}
6833e12c5d1SDavid du Colombier 	if(strncmp((char*)buf, "TYPE=", 5) == 0) {	/* td */
6843e12c5d1SDavid du Colombier 		for(i = 5; i < nbuf; i++)
6853e12c5d1SDavid du Colombier 			if(buf[i] == '\n')
6863e12c5d1SDavid du Colombier 				break;
6877dd7cddfSDavid du Colombier 		if(mime)
6887dd7cddfSDavid du Colombier 			print(OCTET);
6897dd7cddfSDavid du Colombier 		else
69059cc4ca5SDavid du Colombier 			print("%.*s picture\n", utfnlen((char*)buf+5, i-5), (char*)buf+5);
6913e12c5d1SDavid du Colombier 		return 1;
6923e12c5d1SDavid du Colombier 	}
6933e12c5d1SDavid du Colombier 	return 0;
6943e12c5d1SDavid du Colombier }
6953e12c5d1SDavid du Colombier 
696ddb951e3SDavid du Colombier int
697ddb951e3SDavid du Colombier iff(void)
698ddb951e3SDavid du Colombier {
699ddb951e3SDavid du Colombier 	if (strncmp((char*)buf, "FORM", 4) == 0 &&
700ddb951e3SDavid du Colombier 	    strncmp((char*)buf+8, "AIFF", 4) == 0) {
701ddb951e3SDavid du Colombier 		print("%s\n", mime? "audio/x-aiff": "aiff audio");
702ddb951e3SDavid du Colombier 		return 1;
703ddb951e3SDavid du Colombier 	}
704ddb951e3SDavid du Colombier 	return 0;
705ddb951e3SDavid du Colombier }
706ddb951e3SDavid du Colombier 
7077dd7cddfSDavid du Colombier char*	html_string[] =
7087dd7cddfSDavid du Colombier {
7097dd7cddfSDavid du Colombier 	"title",
7107dd7cddfSDavid du Colombier 	"body",
7117dd7cddfSDavid du Colombier 	"head",
7127dd7cddfSDavid du Colombier 	"strong",
7137dd7cddfSDavid du Colombier 	"h1",
7147dd7cddfSDavid du Colombier 	"h2",
7157dd7cddfSDavid du Colombier 	"h3",
7167dd7cddfSDavid du Colombier 	"h4",
7177dd7cddfSDavid du Colombier 	"h5",
7187dd7cddfSDavid du Colombier 	"h6",
7197dd7cddfSDavid du Colombier 	"ul",
7207dd7cddfSDavid du Colombier 	"li",
7217dd7cddfSDavid du Colombier 	"dl",
7227dd7cddfSDavid du Colombier 	"br",
7237dd7cddfSDavid du Colombier 	"em",
7247dd7cddfSDavid du Colombier 	0,
7257dd7cddfSDavid du Colombier };
7267dd7cddfSDavid du Colombier 
7277dd7cddfSDavid du Colombier int
7287dd7cddfSDavid du Colombier ishtml(void)
7297dd7cddfSDavid du Colombier {
7307dd7cddfSDavid du Colombier 	uchar *p, *q;
7317dd7cddfSDavid du Colombier 	int i, count;
7327dd7cddfSDavid du Colombier 
7337dd7cddfSDavid du Colombier 		/* compare strings between '<' and '>' to html table */
7347dd7cddfSDavid du Colombier 	count = 0;
7357dd7cddfSDavid du Colombier 	p = buf;
7367dd7cddfSDavid du Colombier 	for(;;) {
7377dd7cddfSDavid du Colombier 		while (p < buf+nbuf && *p != '<')
7387dd7cddfSDavid du Colombier 			p++;
7397dd7cddfSDavid du Colombier 		p++;
7407dd7cddfSDavid du Colombier 		if (p >= buf+nbuf)
7417dd7cddfSDavid du Colombier 			break;
7427dd7cddfSDavid du Colombier 		if(*p == '/')
7437dd7cddfSDavid du Colombier 			p++;
7447dd7cddfSDavid du Colombier 		q = p;
7457dd7cddfSDavid du Colombier 		while(p < buf+nbuf && *p != '>')
7467dd7cddfSDavid du Colombier 			p++;
7477dd7cddfSDavid du Colombier 		if (p >= buf+nbuf)
7487dd7cddfSDavid du Colombier 			break;
7497dd7cddfSDavid du Colombier 		for(i = 0; html_string[i]; i++) {
7507dd7cddfSDavid du Colombier 			if(cistrncmp(html_string[i], (char*)q, p-q) == 0) {
7517dd7cddfSDavid du Colombier 				if(count++ > 4) {
7527dd7cddfSDavid du Colombier 					print(mime ? "text/html\n" : "HTML file\n");
7537dd7cddfSDavid du Colombier 					return 1;
7547dd7cddfSDavid du Colombier 				}
7557dd7cddfSDavid du Colombier 				break;
7567dd7cddfSDavid du Colombier 			}
7577dd7cddfSDavid du Colombier 		}
7587dd7cddfSDavid du Colombier 		p++;
7597dd7cddfSDavid du Colombier 	}
7607dd7cddfSDavid du Colombier 	return 0;
7617dd7cddfSDavid du Colombier }
7627dd7cddfSDavid du Colombier 
7639a747e4fSDavid du Colombier char*	rfc822_string[] =
7647dd7cddfSDavid du Colombier {
7659a747e4fSDavid du Colombier 	"from:",
7669a747e4fSDavid du Colombier 	"date:",
7679a747e4fSDavid du Colombier 	"to:",
7689a747e4fSDavid du Colombier 	"subject:",
7699a747e4fSDavid du Colombier 	"received:",
770d9306527SDavid du Colombier 	"reply to:",
771d9306527SDavid du Colombier 	"sender:",
7729a747e4fSDavid du Colombier 	0,
7739a747e4fSDavid du Colombier };
7747dd7cddfSDavid du Colombier 
7759a747e4fSDavid du Colombier int
7769a747e4fSDavid du Colombier isrfc822(void)
7779a747e4fSDavid du Colombier {
7789a747e4fSDavid du Colombier 
7799a747e4fSDavid du Colombier 	char *p, *q, *r;
7809a747e4fSDavid du Colombier 	int i, count;
7819a747e4fSDavid du Colombier 
7829a747e4fSDavid du Colombier 	count = 0;
7839a747e4fSDavid du Colombier 	p = (char*)buf;
7849a747e4fSDavid du Colombier 	for(;;) {
7859a747e4fSDavid du Colombier 		q = strchr(p, '\n');
7869a747e4fSDavid du Colombier 		if(q == nil)
7877dd7cddfSDavid du Colombier 			break;
788d9306527SDavid du Colombier 		*q = 0;
789d9306527SDavid du Colombier 		if(p == (char*)buf && strncmp(p, "From ", 5) == 0 && strstr(p, " remote from ")){
790d9306527SDavid du Colombier 			count++;
791d9306527SDavid du Colombier 			*q = '\n';
792d9306527SDavid du Colombier 			p = q+1;
793d9306527SDavid du Colombier 			continue;
794d9306527SDavid du Colombier 		}
795d9306527SDavid du Colombier 		*q = '\n';
7969a747e4fSDavid du Colombier 		if(*p != '\t' && *p != ' '){
7979a747e4fSDavid du Colombier 			r = strchr(p, ':');
7989a747e4fSDavid du Colombier 			if(r == 0 || r > q)
7999a747e4fSDavid du Colombier 				break;
8009a747e4fSDavid du Colombier 			for(i = 0; rfc822_string[i]; i++) {
8019a747e4fSDavid du Colombier 				if(cistrncmp(p, rfc822_string[i], strlen(rfc822_string[i])) == 0){
8029a747e4fSDavid du Colombier 					count++;
8039a747e4fSDavid du Colombier 					break;
8047dd7cddfSDavid du Colombier 				}
8059a747e4fSDavid du Colombier 			}
8069a747e4fSDavid du Colombier 		}
8079a747e4fSDavid du Colombier 		p = q+1;
8089a747e4fSDavid du Colombier 	}
8099a747e4fSDavid du Colombier 	if(count >= 3){
8109a747e4fSDavid du Colombier 		print(mime ? "message/rfc822\n" : "email file\n");
8117dd7cddfSDavid du Colombier 		return 1;
8127dd7cddfSDavid du Colombier 	}
8139a747e4fSDavid du Colombier 	return 0;
8149a747e4fSDavid du Colombier }
8157dd7cddfSDavid du Colombier 
8163e12c5d1SDavid du Colombier int
817d9306527SDavid du Colombier ismbox(void)
818d9306527SDavid du Colombier {
819d9306527SDavid du Colombier 	char *p, *q;
820d9306527SDavid du Colombier 
821d9306527SDavid du Colombier 	p = (char*)buf;
822d9306527SDavid du Colombier 	q = strchr(p, '\n');
823d9306527SDavid du Colombier 	if(q == nil)
824d9306527SDavid du Colombier 		return 0;
825d9306527SDavid du Colombier 	*q = 0;
826d9306527SDavid du Colombier 	if(strncmp(p, "From ", 5) == 0 && strstr(p, " remote from ") == nil){
827d9306527SDavid du Colombier 		print(mime ? "text/plain\n" : "mail box\n");
828d9306527SDavid du Colombier 		return 1;
829d9306527SDavid du Colombier 	}
830d9306527SDavid du Colombier 	*q = '\n';
831d9306527SDavid du Colombier 	return 0;
832d9306527SDavid du Colombier }
833d9306527SDavid du Colombier 
834d9306527SDavid du Colombier int
8353e12c5d1SDavid du Colombier iscint(void)
8363e12c5d1SDavid du Colombier {
837219b2ee8SDavid du Colombier 	int type;
838219b2ee8SDavid du Colombier 	char *name;
839219b2ee8SDavid du Colombier 	Biobuf b;
8403e12c5d1SDavid du Colombier 
841219b2ee8SDavid du Colombier 	if(Binit(&b, fd, OREAD) == Beof)
8423e12c5d1SDavid du Colombier 		return 0;
843219b2ee8SDavid du Colombier 	seek(fd, 0, 0);
844219b2ee8SDavid du Colombier 	type = objtype(&b, &name);
845219b2ee8SDavid du Colombier 	if(type < 0)
846219b2ee8SDavid du Colombier 		return 0;
8477dd7cddfSDavid du Colombier 	if(mime)
8487dd7cddfSDavid du Colombier 		print(OCTET);
8497dd7cddfSDavid du Colombier 	else
850219b2ee8SDavid du Colombier 		print("%s intermediate\n", name);
851219b2ee8SDavid du Colombier 	return 1;
8523e12c5d1SDavid du Colombier }
8533e12c5d1SDavid du Colombier 
8543e12c5d1SDavid du Colombier int
8553e12c5d1SDavid du Colombier isc(void)
8563e12c5d1SDavid du Colombier {
8573e12c5d1SDavid du Colombier 	int n;
8583e12c5d1SDavid du Colombier 
8593e12c5d1SDavid du Colombier 	n = wfreq[I1];
8603e12c5d1SDavid du Colombier 	/*
8613e12c5d1SDavid du Colombier 	 * includes
8623e12c5d1SDavid du Colombier 	 */
8633e12c5d1SDavid du Colombier 	if(n >= 2 && wfreq[I2] >= n && wfreq[I3] >= n && cfreq['.'] >= n)
8643e12c5d1SDavid du Colombier 		goto yes;
865219b2ee8SDavid du Colombier 	if(n >= 1 && wfreq[Alword] >= n && wfreq[I3] >= n && cfreq['.'] >= n)
866219b2ee8SDavid du Colombier 		goto yes;
8673e12c5d1SDavid du Colombier 	/*
8683e12c5d1SDavid du Colombier 	 * declarations
8693e12c5d1SDavid du Colombier 	 */
8703e12c5d1SDavid du Colombier 	if(wfreq[Cword] >= 5 && cfreq[';'] >= 5)
8713e12c5d1SDavid du Colombier 		goto yes;
8723e12c5d1SDavid du Colombier 	/*
8733e12c5d1SDavid du Colombier 	 * assignments
8743e12c5d1SDavid du Colombier 	 */
8753e12c5d1SDavid du Colombier 	if(cfreq[';'] >= 10 && cfreq['='] >= 10 && wfreq[Cword] >= 1)
8763e12c5d1SDavid du Colombier 		goto yes;
8773e12c5d1SDavid du Colombier 	return 0;
8783e12c5d1SDavid du Colombier 
8793e12c5d1SDavid du Colombier yes:
8807dd7cddfSDavid du Colombier 	if(mime){
8817dd7cddfSDavid du Colombier 		print(PLAIN);
8827dd7cddfSDavid du Colombier 		return 1;
8837dd7cddfSDavid du Colombier 	}
884219b2ee8SDavid du Colombier 	if(wfreq[Alword] > 0)
885219b2ee8SDavid du Colombier 		print("alef program\n");
886219b2ee8SDavid du Colombier 	else
8873e12c5d1SDavid du Colombier 		print("c program\n");
8883e12c5d1SDavid du Colombier 	return 1;
8893e12c5d1SDavid du Colombier }
8903e12c5d1SDavid du Colombier 
8913e12c5d1SDavid du Colombier int
8927dd7cddfSDavid du Colombier islimbo(void)
8937dd7cddfSDavid du Colombier {
8947dd7cddfSDavid du Colombier 
8957dd7cddfSDavid du Colombier 	/*
8967dd7cddfSDavid du Colombier 	 * includes
8977dd7cddfSDavid du Colombier 	 */
8987dd7cddfSDavid du Colombier 	if(wfreq[Lword] < 4)
8997dd7cddfSDavid du Colombier 		return 0;
9007dd7cddfSDavid du Colombier 	print(mime ? PLAIN : "limbo program\n");
9017dd7cddfSDavid du Colombier 	return 1;
9027dd7cddfSDavid du Colombier }
9037dd7cddfSDavid du Colombier 
9047dd7cddfSDavid du Colombier int
9053e12c5d1SDavid du Colombier isas(void)
9063e12c5d1SDavid du Colombier {
9073e12c5d1SDavid du Colombier 
9083e12c5d1SDavid du Colombier 	/*
9093e12c5d1SDavid du Colombier 	 * includes
9103e12c5d1SDavid du Colombier 	 */
9113e12c5d1SDavid du Colombier 	if(wfreq[Aword] < 2)
9123e12c5d1SDavid du Colombier 		return 0;
9137dd7cddfSDavid du Colombier 	print(mime ? PLAIN : "as program\n");
9143e12c5d1SDavid du Colombier 	return 1;
9153e12c5d1SDavid du Colombier }
9163e12c5d1SDavid du Colombier 
9173e12c5d1SDavid du Colombier /*
9183e12c5d1SDavid du Colombier  * low entropy means encrypted
9193e12c5d1SDavid du Colombier  */
9203e12c5d1SDavid du Colombier int
9213e12c5d1SDavid du Colombier ismung(void)
9223e12c5d1SDavid du Colombier {
9233e12c5d1SDavid du Colombier 	int i, bucket[8];
9243e12c5d1SDavid du Colombier 	float cs;
9253e12c5d1SDavid du Colombier 
9263e12c5d1SDavid du Colombier 	if(nbuf < 64)
9273e12c5d1SDavid du Colombier 		return 0;
9283e12c5d1SDavid du Colombier 	memset(bucket, 0, sizeof(bucket));
9293e12c5d1SDavid du Colombier 	for(i=0; i<64; i++)
9303e12c5d1SDavid du Colombier 		bucket[(buf[i]>>5)&07] += 1;
9313e12c5d1SDavid du Colombier 
9323e12c5d1SDavid du Colombier 	cs = 0.;
9333e12c5d1SDavid du Colombier 	for(i=0; i<8; i++)
9343e12c5d1SDavid du Colombier 		cs += (bucket[i]-8)*(bucket[i]-8);
9353e12c5d1SDavid du Colombier 	cs /= 8.;
9363e12c5d1SDavid du Colombier 	if(cs <= 24.322) {
9377dd7cddfSDavid du Colombier 		if(buf[0]==0x1f && (buf[1]==0x8b || buf[1]==0x9d))
9387dd7cddfSDavid du Colombier 			print(mime ? OCTET : "compressed\n");
9393e12c5d1SDavid du Colombier 		else
9407dd7cddfSDavid du Colombier 			print(mime ? OCTET : "encrypted\n");
9413e12c5d1SDavid du Colombier 		return 1;
9423e12c5d1SDavid du Colombier 	}
9433e12c5d1SDavid du Colombier 	return 0;
9443e12c5d1SDavid du Colombier }
9453e12c5d1SDavid du Colombier 
9463e12c5d1SDavid du Colombier /*
9473e12c5d1SDavid du Colombier  * english by punctuation and frequencies
9483e12c5d1SDavid du Colombier  */
9493e12c5d1SDavid du Colombier int
9503e12c5d1SDavid du Colombier isenglish(void)
9513e12c5d1SDavid du Colombier {
9523e12c5d1SDavid du Colombier 	int vow, comm, rare, badpun, punct;
9533e12c5d1SDavid du Colombier 	char *p;
9543e12c5d1SDavid du Colombier 
9553e12c5d1SDavid du Colombier 	if(guess != Fascii && guess != Feascii)
9563e12c5d1SDavid du Colombier 		return 0;
9573e12c5d1SDavid du Colombier 	badpun = 0;
9583e12c5d1SDavid du Colombier 	punct = 0;
9593e12c5d1SDavid du Colombier 	for(p = (char *)buf; p < (char *)buf+nbuf-1; p++)
9603e12c5d1SDavid du Colombier 		switch(*p) {
9613e12c5d1SDavid du Colombier 		case '.':
9623e12c5d1SDavid du Colombier 		case ',':
9633e12c5d1SDavid du Colombier 		case ')':
9643e12c5d1SDavid du Colombier 		case '%':
9653e12c5d1SDavid du Colombier 		case ';':
9663e12c5d1SDavid du Colombier 		case ':':
9673e12c5d1SDavid du Colombier 		case '?':
9683e12c5d1SDavid du Colombier 			punct++;
9693e12c5d1SDavid du Colombier 			if(p[1] != ' ' && p[1] != '\n')
9703e12c5d1SDavid du Colombier 				badpun++;
9713e12c5d1SDavid du Colombier 		}
9723e12c5d1SDavid du Colombier 	if(badpun*5 > punct)
9733e12c5d1SDavid du Colombier 		return 0;
9743e12c5d1SDavid du Colombier 	if(cfreq['>']+cfreq['<']+cfreq['/'] > cfreq['e'])	/* shell file test */
9753e12c5d1SDavid du Colombier 		return 0;
9763e12c5d1SDavid du Colombier 	if(2*cfreq[';'] > cfreq['e'])
9773e12c5d1SDavid du Colombier 		return 0;
9783e12c5d1SDavid du Colombier 
9793e12c5d1SDavid du Colombier 	vow = 0;
9803e12c5d1SDavid du Colombier 	for(p="AEIOU"; *p; p++) {
9813e12c5d1SDavid du Colombier 		vow += cfreq[*p];
9823e12c5d1SDavid du Colombier 		vow += cfreq[tolower(*p)];
9833e12c5d1SDavid du Colombier 	}
9843e12c5d1SDavid du Colombier 	comm = 0;
9853e12c5d1SDavid du Colombier 	for(p="ETAION"; *p; p++) {
9863e12c5d1SDavid du Colombier 		comm += cfreq[*p];
9873e12c5d1SDavid du Colombier 		comm += cfreq[tolower(*p)];
9883e12c5d1SDavid du Colombier 	}
9893e12c5d1SDavid du Colombier 	rare = 0;
9903e12c5d1SDavid du Colombier 	for(p="VJKQXZ"; *p; p++) {
9913e12c5d1SDavid du Colombier 		rare += cfreq[*p];
9923e12c5d1SDavid du Colombier 		rare += cfreq[tolower(*p)];
9933e12c5d1SDavid du Colombier 	}
9943e12c5d1SDavid du Colombier 	if(vow*5 >= nbuf-cfreq[' '] && comm >= 10*rare) {
9957dd7cddfSDavid du Colombier 		print(mime ? PLAIN : "English text\n");
9963e12c5d1SDavid du Colombier 		return 1;
9973e12c5d1SDavid du Colombier 	}
9983e12c5d1SDavid du Colombier 	return 0;
9993e12c5d1SDavid du Colombier }
10003e12c5d1SDavid du Colombier 
10013e12c5d1SDavid du Colombier /*
10023e12c5d1SDavid du Colombier  * pick up a number with
10033e12c5d1SDavid du Colombier  * syntax _*[0-9]+_
10043e12c5d1SDavid du Colombier  */
10053e12c5d1SDavid du Colombier #define	P9BITLEN	12
10063e12c5d1SDavid du Colombier int
10073e12c5d1SDavid du Colombier p9bitnum(uchar *bp)
10083e12c5d1SDavid du Colombier {
10093e12c5d1SDavid du Colombier 	int n, c, len;
10103e12c5d1SDavid du Colombier 
10113e12c5d1SDavid du Colombier 	len = P9BITLEN;
10123e12c5d1SDavid du Colombier 	while(*bp == ' ') {
10133e12c5d1SDavid du Colombier 		bp++;
10143e12c5d1SDavid du Colombier 		len--;
10153e12c5d1SDavid du Colombier 		if(len <= 0)
10163e12c5d1SDavid du Colombier 			return -1;
10173e12c5d1SDavid du Colombier 	}
10183e12c5d1SDavid du Colombier 	n = 0;
10193e12c5d1SDavid du Colombier 	while(len > 1) {
10203e12c5d1SDavid du Colombier 		c = *bp++;
10213e12c5d1SDavid du Colombier 		if(!isdigit(c))
10223e12c5d1SDavid du Colombier 			return -1;
10233e12c5d1SDavid du Colombier 		n = n*10 + c-'0';
10243e12c5d1SDavid du Colombier 		len--;
10253e12c5d1SDavid du Colombier 	}
10263e12c5d1SDavid du Colombier 	if(*bp != ' ')
10273e12c5d1SDavid du Colombier 		return -1;
10283e12c5d1SDavid du Colombier 	return n;
10293e12c5d1SDavid du Colombier }
10303e12c5d1SDavid du Colombier 
10313e12c5d1SDavid du Colombier int
10327dd7cddfSDavid du Colombier depthof(char *s, int *newp)
10337dd7cddfSDavid du Colombier {
10347dd7cddfSDavid du Colombier 	char *es;
10357dd7cddfSDavid du Colombier 	int d;
10367dd7cddfSDavid du Colombier 
10377dd7cddfSDavid du Colombier 	*newp = 0;
10387dd7cddfSDavid du Colombier 	es = s+12;
10397dd7cddfSDavid du Colombier 	while(s<es && *s==' ')
10407dd7cddfSDavid du Colombier 		s++;
10417dd7cddfSDavid du Colombier 	if(s == es)
10427dd7cddfSDavid du Colombier 		return -1;
10437dd7cddfSDavid du Colombier 	if('0'<=*s && *s<='9')
1044*16941224SDavid du Colombier 		return 1<<strtol(s, 0, 0);
10457dd7cddfSDavid du Colombier 
10467dd7cddfSDavid du Colombier 	*newp = 1;
10477dd7cddfSDavid du Colombier 	d = 0;
10487dd7cddfSDavid du Colombier 	while(s<es && *s!=' '){
10497dd7cddfSDavid du Colombier 		s++;	/* skip letter */
10507dd7cddfSDavid du Colombier 		d += strtoul(s, &s, 10);
10517dd7cddfSDavid du Colombier 	}
10527dd7cddfSDavid du Colombier 
10537dd7cddfSDavid du Colombier 	switch(d){
10547dd7cddfSDavid du Colombier 	case 32:
10557dd7cddfSDavid du Colombier 	case 24:
10567dd7cddfSDavid du Colombier 	case 16:
10577dd7cddfSDavid du Colombier 	case 8:
10587dd7cddfSDavid du Colombier 		return d;
10597dd7cddfSDavid du Colombier 	}
10607dd7cddfSDavid du Colombier 	return -1;
10617dd7cddfSDavid du Colombier }
10627dd7cddfSDavid du Colombier 
10637dd7cddfSDavid du Colombier int
10643e12c5d1SDavid du Colombier isp9bit(void)
10653e12c5d1SDavid du Colombier {
10667dd7cddfSDavid du Colombier 	int dep, lox, loy, hix, hiy, px, new;
1067219b2ee8SDavid du Colombier 	ulong t;
10683e12c5d1SDavid du Colombier 	long len;
10697dd7cddfSDavid du Colombier 	char *newlabel;
10703e12c5d1SDavid du Colombier 
10717dd7cddfSDavid du Colombier 	newlabel = "old ";
10727dd7cddfSDavid du Colombier 
10737dd7cddfSDavid du Colombier 	dep = depthof((char*)buf + 0*P9BITLEN, &new);
10747dd7cddfSDavid du Colombier 	if(new)
10757dd7cddfSDavid du Colombier 		newlabel = "";
10763e12c5d1SDavid du Colombier 	lox = p9bitnum(buf + 1*P9BITLEN);
10773e12c5d1SDavid du Colombier 	loy = p9bitnum(buf + 2*P9BITLEN);
10783e12c5d1SDavid du Colombier 	hix = p9bitnum(buf + 3*P9BITLEN);
10793e12c5d1SDavid du Colombier 	hiy = p9bitnum(buf + 4*P9BITLEN);
10807dd7cddfSDavid du Colombier 	if(dep < 0 || lox < 0 || loy < 0 || hix < 0 || hiy < 0)
10813e12c5d1SDavid du Colombier 		return 0;
10823e12c5d1SDavid du Colombier 
10837dd7cddfSDavid du Colombier 	if(dep < 8){
10847dd7cddfSDavid du Colombier 		px = 8/dep;	/* pixels per byte */
1085219b2ee8SDavid du Colombier 		/* set l to number of bytes of data per scan line */
1086219b2ee8SDavid du Colombier 		if(lox >= 0)
1087219b2ee8SDavid du Colombier 			len = (hix+px-1)/px - lox/px;
1088219b2ee8SDavid du Colombier 		else{	/* make positive before divide */
1089219b2ee8SDavid du Colombier 			t = (-lox)+px-1;
1090219b2ee8SDavid du Colombier 			t = (t/px)*px;
1091219b2ee8SDavid du Colombier 			len = (t+hix+px-1)/px;
1092219b2ee8SDavid du Colombier 		}
10937dd7cddfSDavid du Colombier 	}else
10947dd7cddfSDavid du Colombier 		len = (hix-lox)*dep/8;
10953e12c5d1SDavid du Colombier 	len *= (hiy-loy);		/* col length */
10963e12c5d1SDavid du Colombier 	len += 5*P9BITLEN;		/* size of initial ascii */
10973e12c5d1SDavid du Colombier 
10983e12c5d1SDavid du Colombier 	/*
10997dd7cddfSDavid du Colombier 	 * for image file, length is non-zero and must match calculation above
11003e12c5d1SDavid du Colombier 	 * for /dev/window and /dev/screen the length is always zero
11013e12c5d1SDavid du Colombier 	 * for subfont, the subfont header should follow immediately.
11023e12c5d1SDavid du Colombier 	 */
11039a747e4fSDavid du Colombier 	if (len != 0 && mbuf->length == 0) {
11047dd7cddfSDavid du Colombier 		print("%splan 9 image\n", newlabel);
11057dd7cddfSDavid du Colombier 		return 1;
11067dd7cddfSDavid du Colombier 	}
11079a747e4fSDavid du Colombier 	if (mbuf->length == len) {
11087dd7cddfSDavid du Colombier 		print("%splan 9 image\n", newlabel);
11097dd7cddfSDavid du Colombier 		return 1;
11107dd7cddfSDavid du Colombier 	}
11117dd7cddfSDavid du Colombier 	/* Ghostscript sometimes produces a little extra on the end */
11129a747e4fSDavid du Colombier 	if (mbuf->length < len+P9BITLEN) {
11137dd7cddfSDavid du Colombier 		print("%splan 9 image\n", newlabel);
11143e12c5d1SDavid du Colombier 		return 1;
11153e12c5d1SDavid du Colombier 	}
11163e12c5d1SDavid du Colombier 	if (p9subfont(buf+len)) {
11177dd7cddfSDavid du Colombier 		print("%ssubfont file\n", newlabel);
11183e12c5d1SDavid du Colombier 		return 1;
11193e12c5d1SDavid du Colombier 	}
11203e12c5d1SDavid du Colombier 	return 0;
11213e12c5d1SDavid du Colombier }
11223e12c5d1SDavid du Colombier 
11233e12c5d1SDavid du Colombier int
11243e12c5d1SDavid du Colombier p9subfont(uchar *p)
11253e12c5d1SDavid du Colombier {
11263e12c5d1SDavid du Colombier 	int n, h, a;
11273e12c5d1SDavid du Colombier 
11287dd7cddfSDavid du Colombier 		/* if image too big, assume it's a subfont */
11293e12c5d1SDavid du Colombier 	if (p+3*P9BITLEN > buf+sizeof(buf))
11303e12c5d1SDavid du Colombier 		return 1;
11313e12c5d1SDavid du Colombier 
11323e12c5d1SDavid du Colombier 	n = p9bitnum(p + 0*P9BITLEN);	/* char count */
11333e12c5d1SDavid du Colombier 	if (n < 0)
11343e12c5d1SDavid du Colombier 		return 0;
11353e12c5d1SDavid du Colombier 	h = p9bitnum(p + 1*P9BITLEN);	/* height */
11363e12c5d1SDavid du Colombier 	if (h < 0)
11373e12c5d1SDavid du Colombier 		return 0;
11383e12c5d1SDavid du Colombier 	a = p9bitnum(p + 2*P9BITLEN);	/* ascent */
11393e12c5d1SDavid du Colombier 	if (a < 0)
11403e12c5d1SDavid du Colombier 		return 0;
11413e12c5d1SDavid du Colombier 	return 1;
11423e12c5d1SDavid du Colombier }
11433e12c5d1SDavid du Colombier 
11443e12c5d1SDavid du Colombier #define	WHITESPACE(c)		((c) == ' ' || (c) == '\t' || (c) == '\n')
11453e12c5d1SDavid du Colombier 
11463e12c5d1SDavid du Colombier int
11473e12c5d1SDavid du Colombier isp9font(void)
11483e12c5d1SDavid du Colombier {
11493e12c5d1SDavid du Colombier 	uchar *cp, *p;
11503e12c5d1SDavid du Colombier 	int i, n;
11513e12c5d1SDavid du Colombier 	char pathname[1024];
11523e12c5d1SDavid du Colombier 
11533e12c5d1SDavid du Colombier 	cp = buf;
11543e12c5d1SDavid du Colombier 	if (!getfontnum(cp, &cp))	/* height */
11553e12c5d1SDavid du Colombier 		return 0;
11563e12c5d1SDavid du Colombier 	if (!getfontnum(cp, &cp))	/* ascent */
11573e12c5d1SDavid du Colombier 		return 0;
11583e12c5d1SDavid du Colombier 	for (i = 0; 1; i++) {
11593e12c5d1SDavid du Colombier 		if (!getfontnum(cp, &cp))	/* min */
11603e12c5d1SDavid du Colombier 			break;
11613e12c5d1SDavid du Colombier 		if (!getfontnum(cp, &cp))	/* max */
11623e12c5d1SDavid du Colombier 			return 0;
11633e12c5d1SDavid du Colombier 		while (WHITESPACE(*cp))
11643e12c5d1SDavid du Colombier 			cp++;
11653e12c5d1SDavid du Colombier 		for (p = cp; *cp && !WHITESPACE(*cp); cp++)
11663e12c5d1SDavid du Colombier 				;
11673e12c5d1SDavid du Colombier 			/* construct a path name, if needed */
11683e12c5d1SDavid du Colombier 		n = 0;
11693e12c5d1SDavid du Colombier 		if (*p != '/' && slash) {
11703e12c5d1SDavid du Colombier 			n = slash-fname+1;
11713e12c5d1SDavid du Colombier 			if (n < sizeof(pathname))
11723e12c5d1SDavid du Colombier 				memcpy(pathname, fname, n);
11733e12c5d1SDavid du Colombier 			else n = 0;
11743e12c5d1SDavid du Colombier 		}
11753e12c5d1SDavid du Colombier 		if (n+cp-p < sizeof(pathname)) {
11763e12c5d1SDavid du Colombier 			memcpy(pathname+n, p, cp-p);
11773e12c5d1SDavid du Colombier 			n += cp-p;
11783e12c5d1SDavid du Colombier 			pathname[n] = 0;
11799a747e4fSDavid du Colombier 			if (access(pathname, AEXIST) < 0)
11803e12c5d1SDavid du Colombier 				return 0;
11813e12c5d1SDavid du Colombier 		}
11823e12c5d1SDavid du Colombier 	}
11833e12c5d1SDavid du Colombier 	if (i) {
11848d37e088SDavid du Colombier 		print(mime ? "text/plain\n" : "font file\n");
11853e12c5d1SDavid du Colombier 		return 1;
11863e12c5d1SDavid du Colombier 	}
11873e12c5d1SDavid du Colombier 	return 0;
11883e12c5d1SDavid du Colombier }
11893e12c5d1SDavid du Colombier 
11903e12c5d1SDavid du Colombier int
11913e12c5d1SDavid du Colombier getfontnum(uchar *cp, uchar **rp)
11923e12c5d1SDavid du Colombier {
11933e12c5d1SDavid du Colombier 	while (WHITESPACE(*cp))		/* extract ulong delimited by whitespace */
11943e12c5d1SDavid du Colombier 		cp++;
11953e12c5d1SDavid du Colombier 	if (*cp < '0' || *cp > '9')
11963e12c5d1SDavid du Colombier 		return 0;
11973e12c5d1SDavid du Colombier 	strtoul((char *)cp, (char **)rp, 0);
11983e12c5d1SDavid du Colombier 	if (!WHITESPACE(**rp))
11993e12c5d1SDavid du Colombier 		return 0;
12003e12c5d1SDavid du Colombier 	return 1;
12013e12c5d1SDavid du Colombier }
12027dd7cddfSDavid du Colombier 
12037dd7cddfSDavid du Colombier int
1204fb7f0c93SDavid du Colombier isrtf(void)
12057dd7cddfSDavid du Colombier {
1206fb7f0c93SDavid du Colombier 	if(strstr((char *)buf, "\\rtf1")){
1207f2e8132aSDavid du Colombier 		print(mime ? "application/rtf\n" : "rich text format\n");
1208f2e8132aSDavid du Colombier 		return 1;
1209f2e8132aSDavid du Colombier 	}
1210f2e8132aSDavid du Colombier 	return 0;
1211f2e8132aSDavid du Colombier }
1212f2e8132aSDavid du Colombier 
1213f2e8132aSDavid du Colombier int
1214f2e8132aSDavid du Colombier ismsdos(void)
1215f2e8132aSDavid du Colombier {
1216f2e8132aSDavid du Colombier 	if (buf[0] == 0x4d && buf[1] == 0x5a){
1217f2e8132aSDavid du Colombier 		print(mime ? "application/x-msdownload\n" : "MSDOS executable\n");
12187dd7cddfSDavid du Colombier 		return 1;
12197dd7cddfSDavid du Colombier 	}
12207dd7cddfSDavid du Colombier 	return 0;
12217dd7cddfSDavid du Colombier }
1222b7327ca2SDavid du Colombier 
1223b7327ca2SDavid du Colombier int
1224b7327ca2SDavid du Colombier iself(void)
1225b7327ca2SDavid du Colombier {
1226b7327ca2SDavid du Colombier 	char *cpu[] = {		/* NB: incomplete and arbitary list */
1227b7327ca2SDavid du Colombier 	[1]	"WE32100",
1228b7327ca2SDavid du Colombier 	[2]	"SPARC",
1229b7327ca2SDavid du Colombier 	[3]	"i386",
1230b7327ca2SDavid du Colombier 	[4]	"M68000",
1231b7327ca2SDavid du Colombier 	[5]	"M88000",
1232b7327ca2SDavid du Colombier 	[6]	"i486",
1233b7327ca2SDavid du Colombier 	[7]	"i860",
1234b7327ca2SDavid du Colombier 	[8]	"R3000",
1235b7327ca2SDavid du Colombier 	[9]	"S370",
1236b7327ca2SDavid du Colombier 	[10]	"R4000",
1237b7327ca2SDavid du Colombier 	[15]	"HP-PA",
1238b7327ca2SDavid du Colombier 	[18]	"sparc v8+",
1239b7327ca2SDavid du Colombier 	[19]	"i960",
1240b7327ca2SDavid du Colombier 	[20]	"PPC-32",
1241b7327ca2SDavid du Colombier 	[21]	"PPC-64",
1242b7327ca2SDavid du Colombier 	[40]	"ARM",
1243b7327ca2SDavid du Colombier 	[41]	"Alpha",
1244b7327ca2SDavid du Colombier 	[43]	"sparc v9",
1245b7327ca2SDavid du Colombier 	[50]	"IA-46",
1246f9247424SDavid du Colombier 	[62]	"AMD64",
1247b7327ca2SDavid du Colombier 	[75]	"VAX",
1248b7327ca2SDavid du Colombier 	};
1249b7327ca2SDavid du Colombier 
1250b7327ca2SDavid du Colombier 
1251b7327ca2SDavid du Colombier 	if (memcmp(buf, "\x7fELF", 4) == 0){
1252b7327ca2SDavid du Colombier 		if (!mime){
1253b7327ca2SDavid du Colombier 			int n = (buf[19] << 8) | buf[18];
12548a2c5ad0SDavid du Colombier 			char *p = "unknown";
12558a2c5ad0SDavid du Colombier 
12568a2c5ad0SDavid du Colombier 			if (n > 0 && n < nelem(cpu) && cpu[n])
12578a2c5ad0SDavid du Colombier 				p = cpu[n];
12588a2c5ad0SDavid du Colombier 			else {
12598a2c5ad0SDavid du Colombier 				/* try the other byte order */
12608a2c5ad0SDavid du Colombier 				n = (buf[18] << 8) | buf[19];
12618a2c5ad0SDavid du Colombier 				if (n > 0 && n < nelem(cpu) && cpu[n])
12628a2c5ad0SDavid du Colombier 					p = cpu[n];
12638a2c5ad0SDavid du Colombier 			}
1264b7327ca2SDavid du Colombier 			print("%s ELF executable\n", p);
1265b7327ca2SDavid du Colombier 		}
1266b7327ca2SDavid du Colombier 		else
1267b7327ca2SDavid du Colombier 			print("application/x-elf-executable");
1268b7327ca2SDavid du Colombier 		return 1;
1269b7327ca2SDavid du Colombier 	}
1270b7327ca2SDavid du Colombier 
1271b7327ca2SDavid du Colombier 	return 0;
1272b7327ca2SDavid du Colombier }
1273