xref: /plan9/sys/src/cmd/file.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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 
123e12c5d1SDavid du Colombier uchar	buf[6000];
133e12c5d1SDavid du Colombier short	cfreq[140];
143e12c5d1SDavid du Colombier short	wfreq[50];
153e12c5d1SDavid du Colombier int	nbuf;
163e12c5d1SDavid 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,
26*219b2ee8SDavid du Colombier 	Alword,
273e12c5d1SDavid du Colombier 	I1,
283e12c5d1SDavid du Colombier 	I2,
293e12c5d1SDavid du Colombier 	I3,
303e12c5d1SDavid du Colombier 	Clatin	= 128,
313e12c5d1SDavid du Colombier 	Cbinary,
323e12c5d1SDavid du Colombier 	Cnull,
333e12c5d1SDavid du Colombier 	Ceascii,
343e12c5d1SDavid du Colombier 	Cutf,
353e12c5d1SDavid du Colombier };
363e12c5d1SDavid du Colombier struct
373e12c5d1SDavid du Colombier {
383e12c5d1SDavid du Colombier 	char*	word;
393e12c5d1SDavid du Colombier 	int	class;
403e12c5d1SDavid du Colombier } dict[] =
413e12c5d1SDavid du Colombier {
42*219b2ee8SDavid du Colombier 	"TEXT",		Aword,
43*219b2ee8SDavid du Colombier 	"adt",		Alword,
44*219b2ee8SDavid du Colombier 	"aggr",		Alword,
45*219b2ee8SDavid du Colombier 	"alef",		Alword,
46*219b2ee8SDavid du Colombier 	"block",	Fword,
47*219b2ee8SDavid du Colombier 	"chan",		Alword,
48*219b2ee8SDavid du Colombier 	"char",		Cword,
49*219b2ee8SDavid du Colombier 	"common",	Fword,
50*219b2ee8SDavid du Colombier 	"data",		Fword,
51*219b2ee8SDavid du Colombier 	"dimension",	Fword,
52*219b2ee8SDavid du Colombier 	"double",	Cword,
53*219b2ee8SDavid du Colombier 	"extern",	Cword,
54*219b2ee8SDavid du Colombier 	"bio",		I2,
55*219b2ee8SDavid du Colombier 	"float",	Cword,
56*219b2ee8SDavid du Colombier 	"function",	Fword,
57*219b2ee8SDavid du Colombier 	"h",		I3,
58*219b2ee8SDavid du Colombier 	"include",	I1,
59*219b2ee8SDavid du Colombier 	"int",		Cword,
60*219b2ee8SDavid du Colombier 	"integer",	Fword,
61*219b2ee8SDavid du Colombier 	"libc",		I2,
62*219b2ee8SDavid du Colombier 	"long",		Cword,
63*219b2ee8SDavid du Colombier 	"real",		Fword,
64*219b2ee8SDavid du Colombier 	"register",	Cword,
65*219b2ee8SDavid du Colombier 	"short",	Cword,
66*219b2ee8SDavid du Colombier 	"static",	Cword,
67*219b2ee8SDavid du Colombier 	"stdio",	I2,
68*219b2ee8SDavid du Colombier 	"struct",	Cword,
69*219b2ee8SDavid du Colombier 	"subroutine",	Fword,
70*219b2ee8SDavid du Colombier 	"u",		I2,
71*219b2ee8SDavid du Colombier 	"void",		Cword,
72*219b2ee8SDavid du Colombier };
73*219b2ee8SDavid du Colombier 
74*219b2ee8SDavid du Colombier 	/* codes for 'mode' field in language structure */
75*219b2ee8SDavid du Colombier enum	{
76*219b2ee8SDavid du Colombier 		Normal	= 0,
77*219b2ee8SDavid du Colombier 		First,		/* first entry for language spanning several ranges */
78*219b2ee8SDavid du Colombier 		Multi,		/* later entries "   "       "  ... */
79*219b2ee8SDavid du Colombier 		Shared,		/* codes used in several languages */
803e12c5d1SDavid du Colombier 	};
813e12c5d1SDavid du Colombier 
823e12c5d1SDavid du Colombier struct
833e12c5d1SDavid du Colombier {
84*219b2ee8SDavid du Colombier 	int	mode;		/* see enum above */
853e12c5d1SDavid du Colombier 	int 	count;
863e12c5d1SDavid du Colombier 	int	low;
873e12c5d1SDavid du Colombier 	int	high;
883e12c5d1SDavid du Colombier 	char	*name;
893e12c5d1SDavid du Colombier 
903e12c5d1SDavid du Colombier } language[] =
913e12c5d1SDavid du Colombier {
92*219b2ee8SDavid du Colombier 	Normal, 0,	0x0080, 0x0080,	"Extended Latin",
93*219b2ee8SDavid du Colombier 	Normal,	0,	0x0100,	0x01FF,	"Extended Latin",
94*219b2ee8SDavid du Colombier 	Normal,	0,	0x0370,	0x03FF,	"Greek",
95*219b2ee8SDavid du Colombier 	Normal,	0,	0x0400,	0x04FF,	"Cyrillic",
96*219b2ee8SDavid du Colombier 	Normal,	0,	0x0530,	0x058F,	"Armenian",
97*219b2ee8SDavid du Colombier 	Normal,	0,	0x0590,	0x05FF,	"Hebrew",
98*219b2ee8SDavid du Colombier 	Normal,	0,	0x0600,	0x06FF,	"Arabic",
99*219b2ee8SDavid du Colombier 	Normal,	0,	0x0900,	0x097F,	"Devanagari",
100*219b2ee8SDavid du Colombier 	Normal,	0,	0x0980,	0x09FF,	"Bengali",
101*219b2ee8SDavid du Colombier 	Normal,	0,	0x0A00,	0x0A7F,	"Gurmukhi",
102*219b2ee8SDavid du Colombier 	Normal,	0,	0x0A80,	0x0AFF,	"Gujarati",
103*219b2ee8SDavid du Colombier 	Normal,	0,	0x0B00,	0x0B7F,	"Oriya",
104*219b2ee8SDavid du Colombier 	Normal,	0,	0x0B80,	0x0BFF,	"Tamil",
105*219b2ee8SDavid du Colombier 	Normal,	0,	0x0C00,	0x0C7F,	"Telugu",
106*219b2ee8SDavid du Colombier 	Normal,	0,	0x0C80,	0x0CFF,	"Kannada",
107*219b2ee8SDavid du Colombier 	Normal,	0,	0x0D00,	0x0D7F,	"Malayalam",
108*219b2ee8SDavid du Colombier 	Normal,	0,	0x0E00,	0x0E7F,	"Thai",
109*219b2ee8SDavid du Colombier 	Normal,	0,	0x0E80,	0x0EFF,	"Lao",
110*219b2ee8SDavid du Colombier 	Normal,	0,	0x1000,	0x105F,	"Tibetan",
111*219b2ee8SDavid du Colombier 	Normal,	0,	0x10A0,	0x10FF,	"Georgian",
112*219b2ee8SDavid du Colombier 	Normal,	0,	0x3040,	0x30FF,	"Japanese",
113*219b2ee8SDavid du Colombier 	Normal,	0,	0x3100,	0x312F,	"Chinese",
114*219b2ee8SDavid du Colombier 	First,	0,	0x3130,	0x318F,	"Korean",
115*219b2ee8SDavid du Colombier 	Multi,	0,	0x3400,	0x3D2F,	"Korean",
116*219b2ee8SDavid du Colombier 	Shared,	0,	0x4e00,	0x9fff,	"CJK",
117*219b2ee8SDavid du Colombier 	Normal,	0,	0,	0,	0,		/* terminal entry */
1183e12c5d1SDavid du Colombier };
1193e12c5d1SDavid du Colombier 
1203e12c5d1SDavid du Colombier 
1213e12c5d1SDavid du Colombier enum
1223e12c5d1SDavid du Colombier {
1233e12c5d1SDavid du Colombier 	Fascii,		/* printable ascii */
1243e12c5d1SDavid du Colombier 	Flatin,		/* latin 1*/
1253e12c5d1SDavid du Colombier 	Futf,		/* UTf character set */
1263e12c5d1SDavid du Colombier 	Fbinary,	/* binary */
1273e12c5d1SDavid du Colombier 	Feascii,	/* ASCII with control chars */
1283e12c5d1SDavid du Colombier 	Fnull,		/* NULL in file */
1293e12c5d1SDavid du Colombier } guess;
1303e12c5d1SDavid du Colombier 
1313e12c5d1SDavid du Colombier void	bump_utf_count(Rune);
1323e12c5d1SDavid du Colombier void	filetype(int);
1333e12c5d1SDavid du Colombier int	getfontnum(uchar *, uchar **);
1343e12c5d1SDavid du Colombier int	isas(void);
1353e12c5d1SDavid du Colombier int	isc(void);
1363e12c5d1SDavid du Colombier int	iscint(void);
1373e12c5d1SDavid du Colombier int	isenglish(void);
1383e12c5d1SDavid du Colombier int	ismung(void);
1393e12c5d1SDavid du Colombier int	isp9bit(void);
1403e12c5d1SDavid du Colombier int	isp9font(void);
1413e12c5d1SDavid du Colombier int	istring(void);
1423e12c5d1SDavid du Colombier int	long0(void);
1433e12c5d1SDavid du Colombier int	p9bitnum(uchar *);
1443e12c5d1SDavid du Colombier int	p9subfont(uchar *);
1453e12c5d1SDavid du Colombier void	print_utf(void);
1463e12c5d1SDavid du Colombier int	short0(void);
1473e12c5d1SDavid du Colombier void	type(char*, int);
1483e12c5d1SDavid du Colombier int	utf_count(void);
1493e12c5d1SDavid du Colombier void	wordfreq(void);
1503e12c5d1SDavid du Colombier 
1513e12c5d1SDavid du Colombier int	(*call[])(void) =
1523e12c5d1SDavid du Colombier {
1533e12c5d1SDavid du Colombier 	long0,		/* recognizable by first 4 bytes */
1543e12c5d1SDavid du Colombier 	short0,		/* recognizable by first 2 bytes */
1553e12c5d1SDavid du Colombier 	istring,	/* recognizable by first string */
156*219b2ee8SDavid du Colombier 	iscint,		/* compiler/assembler intermediate */
157*219b2ee8SDavid du Colombier 	isc,		/* c & alef compiler key words */
1583e12c5d1SDavid du Colombier 	isas,		/* assembler key words */
1593e12c5d1SDavid du Colombier 	ismung,		/* entropy compressed/encrypted */
1603e12c5d1SDavid du Colombier 	isenglish,	/* char frequency English */
1613e12c5d1SDavid du Colombier 	isp9font,	/* plan 9 font */
1623e12c5d1SDavid du Colombier 	isp9bit,	/* plan 9 bitmap (as from /dev/window) */
1633e12c5d1SDavid du Colombier 	0
1643e12c5d1SDavid du Colombier };
1653e12c5d1SDavid du Colombier 
1663e12c5d1SDavid du Colombier void
1673e12c5d1SDavid du Colombier main(int argc, char *argv[])
1683e12c5d1SDavid du Colombier {
1693e12c5d1SDavid du Colombier 	int i, j, maxlen;
1703e12c5d1SDavid du Colombier 	char *cp;
1713e12c5d1SDavid du Colombier 	Rune r;
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier 	maxlen = 0;
1743e12c5d1SDavid du Colombier 	for(i = 1; i < argc; i++) {
1753e12c5d1SDavid du Colombier 		for (j = 0, cp = argv[i]; *cp; j++, cp += chartorune(&r, cp))
1763e12c5d1SDavid du Colombier 				;
1773e12c5d1SDavid du Colombier 		if(j > maxlen)
1783e12c5d1SDavid du Colombier 			maxlen = j;
1793e12c5d1SDavid du Colombier 	}
1803e12c5d1SDavid du Colombier 	if (argc <= 1) {
1813e12c5d1SDavid du Colombier 		print ("stdin: ");
1823e12c5d1SDavid du Colombier 		filetype(0);
1833e12c5d1SDavid du Colombier 	}
1843e12c5d1SDavid du Colombier 	else {
1853e12c5d1SDavid du Colombier 		for(i = 1; i < argc; i++)
1863e12c5d1SDavid du Colombier 			type(argv[i], maxlen);
1873e12c5d1SDavid du Colombier 	}
1883e12c5d1SDavid du Colombier 	exits(0);
1893e12c5d1SDavid du Colombier }
1903e12c5d1SDavid du Colombier 
1913e12c5d1SDavid du Colombier void
1923e12c5d1SDavid du Colombier type(char *file, int nlen)
1933e12c5d1SDavid du Colombier {
1943e12c5d1SDavid du Colombier 	Rune r;
1953e12c5d1SDavid du Colombier 	int i;
1963e12c5d1SDavid du Colombier 	char *p;
1973e12c5d1SDavid du Colombier 
1983e12c5d1SDavid du Colombier 	slash = 0;
1993e12c5d1SDavid du Colombier 	for (i = 0, p = file; *p; i++) {
2003e12c5d1SDavid du Colombier 		if (*p == '/')			/* find rightmost slash */
2013e12c5d1SDavid du Colombier 			slash = p;
2023e12c5d1SDavid du Colombier 		p += chartorune(&r, p);		/* count runes */
2033e12c5d1SDavid du Colombier 	}
2043e12c5d1SDavid du Colombier 	print("%s:%*s",file, nlen-i+1, "");
2053e12c5d1SDavid du Colombier 	fname = file;
2063e12c5d1SDavid du Colombier 	if ((fd = open(file, OREAD)) < 0) {
2073e12c5d1SDavid du Colombier 		print("cannot open\n");
2083e12c5d1SDavid du Colombier 		return;
2093e12c5d1SDavid du Colombier 	}
2103e12c5d1SDavid du Colombier 	filetype(fd);
2113e12c5d1SDavid du Colombier 	close(fd);
2123e12c5d1SDavid du Colombier }
2133e12c5d1SDavid du Colombier 
2143e12c5d1SDavid du Colombier void
2153e12c5d1SDavid du Colombier filetype(int fd)
2163e12c5d1SDavid du Colombier {
2173e12c5d1SDavid du Colombier 	Rune r;
218*219b2ee8SDavid du Colombier 	int i, f, n;
219*219b2ee8SDavid du Colombier 	char *p, *eob;
2203e12c5d1SDavid du Colombier 
2213e12c5d1SDavid du Colombier 	if(dirfstat(fd, &mbuf) < 0) {
2223e12c5d1SDavid du Colombier 		print("cannot stat\n");
2233e12c5d1SDavid du Colombier 		return;
2243e12c5d1SDavid du Colombier 	}
2253e12c5d1SDavid du Colombier 	if(mbuf.mode & CHDIR) {
2263e12c5d1SDavid du Colombier 		print("directory\n");
2273e12c5d1SDavid du Colombier 		return;
2283e12c5d1SDavid du Colombier 	}
2293e12c5d1SDavid du Colombier 	if(mbuf.type != 'M' && mbuf.type != '|') {
2303e12c5d1SDavid du Colombier 		print("special file #%c\n", mbuf.type);
2313e12c5d1SDavid du Colombier 		return;
2323e12c5d1SDavid du Colombier 	}
2333e12c5d1SDavid du Colombier 	nbuf = read(fd, buf, sizeof(buf));
2343e12c5d1SDavid du Colombier 
2353e12c5d1SDavid du Colombier 	if(nbuf < 0) {
2363e12c5d1SDavid du Colombier 		print("cannot read\n");
2373e12c5d1SDavid du Colombier 		return;
2383e12c5d1SDavid du Colombier 	}
2393e12c5d1SDavid du Colombier 	if(nbuf == 0) {
2403e12c5d1SDavid du Colombier 		print("empty\n");
2413e12c5d1SDavid du Colombier 		return;
2423e12c5d1SDavid du Colombier 	}
2433e12c5d1SDavid du Colombier 
2443e12c5d1SDavid du Colombier 	/*
2453e12c5d1SDavid du Colombier 	 * build histogram table
2463e12c5d1SDavid du Colombier 	 */
2473e12c5d1SDavid du Colombier 	memset(cfreq, 0, sizeof(cfreq));
2483e12c5d1SDavid du Colombier 	for (i = 0; language[i].name; i++)
2493e12c5d1SDavid du Colombier 		language[i].count = 0;
250*219b2ee8SDavid du Colombier 	eob = (char *)buf+nbuf;
251*219b2ee8SDavid du Colombier 	for(n = 0, p = (char *)buf; p < eob; n++) {
252*219b2ee8SDavid du Colombier 		if (!fullrune(p, eob-p) && eob-p < UTFmax)
253*219b2ee8SDavid du Colombier 			break;
2543e12c5d1SDavid du Colombier 		p += chartorune(&r, p);
2553e12c5d1SDavid du Colombier 		if (r == 0)
2563e12c5d1SDavid du Colombier 			f = Cnull;
2573e12c5d1SDavid du Colombier 		else if (r <= 0x7f) {
2583e12c5d1SDavid du Colombier 			if (!isprint(r) && !isspace(r))
2593e12c5d1SDavid du Colombier 				f = Ceascii;	/* ASCII control char */
2603e12c5d1SDavid du Colombier 			else f = r;
261*219b2ee8SDavid du Colombier 		} else if (r == 0x080) {
262*219b2ee8SDavid du Colombier 			bump_utf_count(r);
263*219b2ee8SDavid du Colombier 			f = Cutf;
2643e12c5d1SDavid du Colombier 		} else if (r < 0xA0)
2653e12c5d1SDavid du Colombier 				f = Cbinary;	/* Invalid Runes */
2663e12c5d1SDavid du Colombier 		else if (r <= 0xff)
2673e12c5d1SDavid du Colombier 				f = Clatin;	/* Latin 1 */
2683e12c5d1SDavid du Colombier 		else {
2693e12c5d1SDavid du Colombier 			bump_utf_count(r);
2703e12c5d1SDavid du Colombier 			f = Cutf;		/* UTF extension */
2713e12c5d1SDavid du Colombier 		}
2723e12c5d1SDavid du Colombier 		cfreq[f]++;			/* ASCII chars peg directly */
2733e12c5d1SDavid du Colombier 	}
2743e12c5d1SDavid du Colombier 	/*
2753e12c5d1SDavid du Colombier 	 * gross classify
2763e12c5d1SDavid du Colombier 	 */
2773e12c5d1SDavid du Colombier 	if (cfreq[Cbinary])
2783e12c5d1SDavid du Colombier 		guess = Fbinary;
2793e12c5d1SDavid du Colombier 	else if (cfreq[Cutf])
2803e12c5d1SDavid du Colombier 		guess = Futf;
2813e12c5d1SDavid du Colombier 	else if (cfreq[Clatin])
2823e12c5d1SDavid du Colombier 		guess = Flatin;
2833e12c5d1SDavid du Colombier 	else if (cfreq[Ceascii])
2843e12c5d1SDavid du Colombier 		guess = Feascii;
285*219b2ee8SDavid du Colombier 	else if (cfreq[Cnull] == n) {
286*219b2ee8SDavid du Colombier 		print("all null bytes\n");
2873e12c5d1SDavid du Colombier 		return;
2883e12c5d1SDavid du Colombier 	}
2893e12c5d1SDavid du Colombier 	else guess = Fascii;
2903e12c5d1SDavid du Colombier 	/*
2913e12c5d1SDavid du Colombier 	 * lookup dictionary words
2923e12c5d1SDavid du Colombier 	 */
293*219b2ee8SDavid du Colombier 	memset(wfreq, 0, sizeof(wfreq));
294*219b2ee8SDavid du Colombier 	if(guess == Fascii || guess == Flatin)
2953e12c5d1SDavid du Colombier 		wordfreq();
2963e12c5d1SDavid du Colombier 	/*
2973e12c5d1SDavid du Colombier 	 * call individual classify routines
2983e12c5d1SDavid du Colombier 	 */
2993e12c5d1SDavid du Colombier 	for(i=0; call[i]; i++)
3003e12c5d1SDavid du Colombier 		if((*call[i])())
3013e12c5d1SDavid du Colombier 			return;
3023e12c5d1SDavid du Colombier 
3033e12c5d1SDavid du Colombier 	/*
3043e12c5d1SDavid du Colombier 	 * if all else fails,
3053e12c5d1SDavid du Colombier 	 * print out gross classification
3063e12c5d1SDavid du Colombier 	 */
3073e12c5d1SDavid du Colombier 	if (nbuf < 100)
3083e12c5d1SDavid du Colombier 		print("short ");
3093e12c5d1SDavid du Colombier 	if (guess == Fascii)
310*219b2ee8SDavid du Colombier 		print("Ascii\n");
3113e12c5d1SDavid du Colombier 	else if (guess == Feascii)
3123e12c5d1SDavid du Colombier 		print("extended ascii\n");
3133e12c5d1SDavid du Colombier 	else if (guess == Flatin)
3143e12c5d1SDavid du Colombier 		print("latin ascii\n");
3153e12c5d1SDavid du Colombier 	else if (guess == Futf && utf_count() < 4)
3163e12c5d1SDavid du Colombier 		print_utf();
3173e12c5d1SDavid du Colombier 	else print("binary\n");
3183e12c5d1SDavid du Colombier }
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier void
3213e12c5d1SDavid du Colombier bump_utf_count(Rune r)
3223e12c5d1SDavid du Colombier {
3233e12c5d1SDavid du Colombier 	int low, high, mid;
3243e12c5d1SDavid du Colombier 
3253e12c5d1SDavid du Colombier 	high = sizeof(language)/sizeof(language[0])-1;
3263e12c5d1SDavid du Colombier 	for (low = 0; low < high;) {
3273e12c5d1SDavid du Colombier 		mid = (low+high)/2;
3283e12c5d1SDavid du Colombier 		if (r >=language[mid].low) {
3293e12c5d1SDavid du Colombier 			if (r <= language[mid].high) {
3303e12c5d1SDavid du Colombier 				language[mid].count++;
3313e12c5d1SDavid du Colombier 				break;
3323e12c5d1SDavid du Colombier 			} else low = mid+1;
3333e12c5d1SDavid du Colombier 		} else high = mid;
3343e12c5d1SDavid du Colombier 	}
3353e12c5d1SDavid du Colombier }
3363e12c5d1SDavid du Colombier 
3373e12c5d1SDavid du Colombier int
3383e12c5d1SDavid du Colombier utf_count(void)
3393e12c5d1SDavid du Colombier {
3403e12c5d1SDavid du Colombier 	int i, count;
3413e12c5d1SDavid du Colombier 
342*219b2ee8SDavid du Colombier 	count = 0;
343*219b2ee8SDavid du Colombier 	for (i = 0; language[i].name; i++)
3443e12c5d1SDavid du Colombier 		if (language[i].count > 0)
345*219b2ee8SDavid du Colombier 			switch (language[i].mode) {
346*219b2ee8SDavid du Colombier 			case Normal:
347*219b2ee8SDavid du Colombier 			case First:
3483e12c5d1SDavid du Colombier 				count++;
349*219b2ee8SDavid du Colombier 				break;
350*219b2ee8SDavid du Colombier 			default:
351*219b2ee8SDavid du Colombier 				break;
352*219b2ee8SDavid du Colombier 			}
3533e12c5d1SDavid du Colombier 	return count;
3543e12c5d1SDavid du Colombier }
3553e12c5d1SDavid du Colombier 
356*219b2ee8SDavid du Colombier int
357*219b2ee8SDavid du Colombier chkascii(void)
358*219b2ee8SDavid du Colombier {
359*219b2ee8SDavid du Colombier 	int i;
360*219b2ee8SDavid du Colombier 
361*219b2ee8SDavid du Colombier 	for (i = 'a'; i < 'z'; i++)
362*219b2ee8SDavid du Colombier 		if (cfreq[i])
363*219b2ee8SDavid du Colombier 			return 1;
364*219b2ee8SDavid du Colombier 	for (i = 'A'; i < 'Z'; i++)
365*219b2ee8SDavid du Colombier 		if (cfreq[i])
366*219b2ee8SDavid du Colombier 			return 1;
367*219b2ee8SDavid du Colombier 	return 0;
368*219b2ee8SDavid du Colombier }
369*219b2ee8SDavid du Colombier 
370*219b2ee8SDavid du Colombier int
371*219b2ee8SDavid du Colombier find_first(char *name)
372*219b2ee8SDavid du Colombier {
373*219b2ee8SDavid du Colombier 	int i;
374*219b2ee8SDavid du Colombier 
375*219b2ee8SDavid du Colombier 	for (i = 0; language[i].name != 0; i++)
376*219b2ee8SDavid du Colombier 		if (language[i].mode == First
377*219b2ee8SDavid du Colombier 			&& strcmp(language[i].name, name) == 0)
378*219b2ee8SDavid du Colombier 			return i;
379*219b2ee8SDavid du Colombier 	return -1;
380*219b2ee8SDavid du Colombier }
381*219b2ee8SDavid du Colombier 
3823e12c5d1SDavid du Colombier void
3833e12c5d1SDavid du Colombier print_utf(void)
3843e12c5d1SDavid du Colombier {
385*219b2ee8SDavid du Colombier 	int i, printed, j;
3863e12c5d1SDavid du Colombier 
387*219b2ee8SDavid du Colombier 	if (chkascii()) {
388*219b2ee8SDavid du Colombier 		printed = 1;
389*219b2ee8SDavid du Colombier 		print("Ascii");
390*219b2ee8SDavid du Colombier 	} else
391*219b2ee8SDavid du Colombier 		printed = 0;
392*219b2ee8SDavid du Colombier 	for (i = 0; language[i].name; i++)
3933e12c5d1SDavid du Colombier 		if (language[i].count) {
394*219b2ee8SDavid du Colombier 			switch(language[i].mode) {
395*219b2ee8SDavid du Colombier 			case Multi:
396*219b2ee8SDavid du Colombier 				j = find_first(language[i].name);
397*219b2ee8SDavid du Colombier 				if (j < 0)
398*219b2ee8SDavid du Colombier 					break;
399*219b2ee8SDavid du Colombier 				if (language[j].count > 0)
400*219b2ee8SDavid du Colombier 					break;
401*219b2ee8SDavid du Colombier 				/* Fall through */
402*219b2ee8SDavid du Colombier 			case Normal:
403*219b2ee8SDavid du Colombier 			case First:
4043e12c5d1SDavid du Colombier 				if (printed)
4053e12c5d1SDavid du Colombier 					print(" & ");
4063e12c5d1SDavid du Colombier 				else printed = 1;
4073e12c5d1SDavid du Colombier 				print("%s", language[i].name);
408*219b2ee8SDavid du Colombier 				break;
409*219b2ee8SDavid du Colombier 			case Shared:
410*219b2ee8SDavid du Colombier 			default:
411*219b2ee8SDavid du Colombier 				break;
412*219b2ee8SDavid du Colombier 			}
4133e12c5d1SDavid du Colombier 		}
4143e12c5d1SDavid du Colombier 	if(!printed)
4153e12c5d1SDavid du Colombier 		print("UTF");
4163e12c5d1SDavid du Colombier 	print(" text\n");
4173e12c5d1SDavid du Colombier }
4183e12c5d1SDavid du Colombier 
4193e12c5d1SDavid du Colombier void
4203e12c5d1SDavid du Colombier wordfreq(void)
4213e12c5d1SDavid du Colombier {
422*219b2ee8SDavid du Colombier 	int low, high, mid, r;
423*219b2ee8SDavid du Colombier 	uchar *p, *p2, c;
4243e12c5d1SDavid du Colombier 
425*219b2ee8SDavid du Colombier 	p = buf;
426*219b2ee8SDavid du Colombier 	for(;;) {
427*219b2ee8SDavid du Colombier 		while (p < buf+nbuf && !isalpha(*p))
428*219b2ee8SDavid du Colombier 			p++;
429*219b2ee8SDavid du Colombier 		if (p >= buf+nbuf)
430*219b2ee8SDavid du Colombier 			return;
431*219b2ee8SDavid du Colombier 		p2 = p;
432*219b2ee8SDavid du Colombier 		while(p < buf+nbuf && isalpha(*p))
433*219b2ee8SDavid du Colombier 			p++;
434*219b2ee8SDavid du Colombier 		c = *p;
435*219b2ee8SDavid du Colombier 		*p = 0;
4363e12c5d1SDavid du Colombier 		high = sizeof(dict)/sizeof(dict[0]);
4373e12c5d1SDavid du Colombier 		for(low = 0;low < high;) {
4383e12c5d1SDavid du Colombier 			mid = (low+high)/2;
439*219b2ee8SDavid du Colombier 			r = strcmp(dict[mid].word, (char*)p2);
440*219b2ee8SDavid du Colombier 			if(r == 0) {
4413e12c5d1SDavid du Colombier 				wfreq[dict[mid].class]++;
4423e12c5d1SDavid du Colombier 				break;
4433e12c5d1SDavid du Colombier 			}
444*219b2ee8SDavid du Colombier 			if(r < 0)
4453e12c5d1SDavid du Colombier 				low = mid+1;
4463e12c5d1SDavid du Colombier 			else
4473e12c5d1SDavid du Colombier 				high = mid;
4483e12c5d1SDavid du Colombier 		}
449*219b2ee8SDavid du Colombier 		*p++ = c;
4503e12c5d1SDavid du Colombier 	}
4513e12c5d1SDavid du Colombier }
4523e12c5d1SDavid du Colombier 
4533e12c5d1SDavid du Colombier int
4543e12c5d1SDavid du Colombier long0(void)
4553e12c5d1SDavid du Colombier {
4563e12c5d1SDavid du Colombier 	Fhdr f;
4573e12c5d1SDavid du Colombier 
4583e12c5d1SDavid du Colombier 	seek(fd, 0, 0);		/* reposition to start of file */
4593e12c5d1SDavid du Colombier 	if (crackhdr(fd, &f)) {
4603e12c5d1SDavid du Colombier 		print("%s\n", f.name);
4613e12c5d1SDavid du Colombier 		return 1;
4623e12c5d1SDavid du Colombier 	}
4633e12c5d1SDavid du Colombier 	switch(LENDIAN(buf)) {
464*219b2ee8SDavid du Colombier 	case 0xf16df16d:
465*219b2ee8SDavid du Colombier 		print("pac1 audio file\n");
466*219b2ee8SDavid du Colombier 		return 1;
467*219b2ee8SDavid du Colombier 	case 0x31636170:
468*219b2ee8SDavid du Colombier 		print("pac3 audio file\n");
469*219b2ee8SDavid du Colombier 		return 1;
470*219b2ee8SDavid du Colombier 	case 0x32636170:
471*219b2ee8SDavid du Colombier 		print("pac4 audio file\n");
4723e12c5d1SDavid du Colombier 		return 1;
4733e12c5d1SDavid du Colombier 	default:
4743e12c5d1SDavid du Colombier 		return 0;
4753e12c5d1SDavid du Colombier 	}
4763e12c5d1SDavid du Colombier 	return 1;
4773e12c5d1SDavid du Colombier }
4783e12c5d1SDavid du Colombier 
4793e12c5d1SDavid du Colombier int
4803e12c5d1SDavid du Colombier short0(void)
4813e12c5d1SDavid du Colombier {
4823e12c5d1SDavid du Colombier 
4833e12c5d1SDavid du Colombier 	switch(LENDIAN(buf) & 0xffff) {
4843e12c5d1SDavid du Colombier 	case 070707:
4853e12c5d1SDavid du Colombier 		print("cpio archive\n");
4863e12c5d1SDavid du Colombier 		break;
4873e12c5d1SDavid du Colombier 
4883e12c5d1SDavid du Colombier 	case 0x02f7:
4893e12c5d1SDavid du Colombier 		print("tex dvi\n");
4903e12c5d1SDavid du Colombier 		break;
4913e12c5d1SDavid du Colombier 	default:
4923e12c5d1SDavid du Colombier 		return 0;
4933e12c5d1SDavid du Colombier 	}
4943e12c5d1SDavid du Colombier 	return 1;
4953e12c5d1SDavid du Colombier }
4963e12c5d1SDavid du Colombier 
4973e12c5d1SDavid du Colombier /*
4983e12c5d1SDavid du Colombier  * initial words to classify file
4993e12c5d1SDavid du Colombier  */
500*219b2ee8SDavid du Colombier struct	FILE_STRING
501*219b2ee8SDavid du Colombier {
5023e12c5d1SDavid du Colombier 	char 	*key;
5033e12c5d1SDavid du Colombier 	char	*filetype;
5043e12c5d1SDavid du Colombier 	int	length;
5053e12c5d1SDavid du Colombier }	file_string[] =
5063e12c5d1SDavid du Colombier {
5073e12c5d1SDavid du Colombier 	"!<arch>\n__.SYMDEF",	"archive random library",	16,
5083e12c5d1SDavid du Colombier 	"!<arch>\n",		"archive",			8,
5093e12c5d1SDavid du Colombier 	"070707",		"cpio archive - ascii header",	6,
5103e12c5d1SDavid du Colombier 	"#!/bin/rc",		"rc executable file",		9,
5113e12c5d1SDavid du Colombier 	"#!/bin/sh",		"sh executable file",		9,
5123e12c5d1SDavid du Colombier 	"%!",			"postscript",			2,
5133e12c5d1SDavid du Colombier 	"x T post",		"troff output for post",	8,
5143e12c5d1SDavid du Colombier 	"x T Latin1",		"troff output for Latin1",	10,
5153e12c5d1SDavid du Colombier 	"x T utf",		"troff output for UTF",		7,
5163e12c5d1SDavid du Colombier 	"x T 202",		"troff output for 202",		7,
5173e12c5d1SDavid du Colombier 	"x T aps",		"troff output for aps",		7,
518*219b2ee8SDavid du Colombier 	"GIF",			"GIF image", 			3,
519*219b2ee8SDavid du Colombier 	"\0PC Research, Inc", "ghostscript fax file",	23,
5203e12c5d1SDavid du Colombier 	0,0,0
5213e12c5d1SDavid du Colombier };
5223e12c5d1SDavid du Colombier 
5233e12c5d1SDavid du Colombier int
5243e12c5d1SDavid du Colombier istring(void)
5253e12c5d1SDavid du Colombier {
5263e12c5d1SDavid du Colombier 	int i;
5273e12c5d1SDavid du Colombier 	struct FILE_STRING *p;
5283e12c5d1SDavid du Colombier 
5293e12c5d1SDavid du Colombier 	for(p = file_string; p->key; p++) {
530*219b2ee8SDavid du Colombier 		if(nbuf >= p->length && !memcmp(buf, p->key, p->length)) {
5313e12c5d1SDavid du Colombier 			print("%s\n", p->filetype);
5323e12c5d1SDavid du Colombier 			return 1;
5333e12c5d1SDavid du Colombier 		}
5343e12c5d1SDavid du Colombier 	}
5353e12c5d1SDavid du Colombier 	if(strncmp((char*)buf, "TYPE=", 5) == 0) {	/* td */
5363e12c5d1SDavid du Colombier 		for(i = 5; i < nbuf; i++)
5373e12c5d1SDavid du Colombier 			if(buf[i] == '\n')
5383e12c5d1SDavid du Colombier 				break;
5393e12c5d1SDavid du Colombier 		print("%.*s picture\n", i-5, buf+5);
5403e12c5d1SDavid du Colombier 		return 1;
5413e12c5d1SDavid du Colombier 	}
5423e12c5d1SDavid du Colombier 	return 0;
5433e12c5d1SDavid du Colombier }
5443e12c5d1SDavid du Colombier 
5453e12c5d1SDavid du Colombier int
5463e12c5d1SDavid du Colombier iscint(void)
5473e12c5d1SDavid du Colombier {
548*219b2ee8SDavid du Colombier 	int type;
549*219b2ee8SDavid du Colombier 	char *name;
550*219b2ee8SDavid du Colombier 	Biobuf b;
5513e12c5d1SDavid du Colombier 
552*219b2ee8SDavid du Colombier 	if(Binit(&b, fd, OREAD) == Beof)
5533e12c5d1SDavid du Colombier 		return 0;
554*219b2ee8SDavid du Colombier 	seek(fd, 0, 0);
555*219b2ee8SDavid du Colombier 	type = objtype(&b, &name);
556*219b2ee8SDavid du Colombier 	if(type < 0)
557*219b2ee8SDavid du Colombier 		return 0;
558*219b2ee8SDavid du Colombier 	print("%s intermediate\n", name);
559*219b2ee8SDavid du Colombier 	return 1;
5603e12c5d1SDavid du Colombier }
5613e12c5d1SDavid du Colombier 
5623e12c5d1SDavid du Colombier int
5633e12c5d1SDavid du Colombier isc(void)
5643e12c5d1SDavid du Colombier {
5653e12c5d1SDavid du Colombier 	int n;
5663e12c5d1SDavid du Colombier 
5673e12c5d1SDavid du Colombier 	n = wfreq[I1];
5683e12c5d1SDavid du Colombier 	/*
5693e12c5d1SDavid du Colombier 	 * includes
5703e12c5d1SDavid du Colombier 	 */
5713e12c5d1SDavid du Colombier 	if(n >= 2 && wfreq[I2] >= n && wfreq[I3] >= n && cfreq['.'] >= n)
5723e12c5d1SDavid du Colombier 		goto yes;
573*219b2ee8SDavid du Colombier 	if(n >= 1 && wfreq[Alword] >= n && wfreq[I3] >= n && cfreq['.'] >= n)
574*219b2ee8SDavid du Colombier 		goto yes;
5753e12c5d1SDavid du Colombier 	/*
5763e12c5d1SDavid du Colombier 	 * declarations
5773e12c5d1SDavid du Colombier 	 */
5783e12c5d1SDavid du Colombier 	if(wfreq[Cword] >= 5 && cfreq[';'] >= 5)
5793e12c5d1SDavid du Colombier 		goto yes;
5803e12c5d1SDavid du Colombier 	/*
5813e12c5d1SDavid du Colombier 	 * assignments
5823e12c5d1SDavid du Colombier 	 */
5833e12c5d1SDavid du Colombier 	if(cfreq[';'] >= 10 && cfreq['='] >= 10 && wfreq[Cword] >= 1)
5843e12c5d1SDavid du Colombier 		goto yes;
5853e12c5d1SDavid du Colombier 	return 0;
5863e12c5d1SDavid du Colombier 
5873e12c5d1SDavid du Colombier yes:
588*219b2ee8SDavid du Colombier 	if(wfreq[Alword] > 0)
589*219b2ee8SDavid du Colombier 		print("alef program\n");
590*219b2ee8SDavid du Colombier 	else
5913e12c5d1SDavid du Colombier 		print("c program\n");
5923e12c5d1SDavid du Colombier 	return 1;
5933e12c5d1SDavid du Colombier }
5943e12c5d1SDavid du Colombier 
5953e12c5d1SDavid du Colombier int
5963e12c5d1SDavid du Colombier isas(void)
5973e12c5d1SDavid du Colombier {
5983e12c5d1SDavid du Colombier 
5993e12c5d1SDavid du Colombier 	/*
6003e12c5d1SDavid du Colombier 	 * includes
6013e12c5d1SDavid du Colombier 	 */
6023e12c5d1SDavid du Colombier 	if(wfreq[Aword] < 2)
6033e12c5d1SDavid du Colombier 		return 0;
6043e12c5d1SDavid du Colombier 	print("as program\n");
6053e12c5d1SDavid du Colombier 	return 1;
6063e12c5d1SDavid du Colombier }
6073e12c5d1SDavid du Colombier 
6083e12c5d1SDavid du Colombier /*
6093e12c5d1SDavid du Colombier  * low entropy means encrypted
6103e12c5d1SDavid du Colombier  */
6113e12c5d1SDavid du Colombier int
6123e12c5d1SDavid du Colombier ismung(void)
6133e12c5d1SDavid du Colombier {
6143e12c5d1SDavid du Colombier 	int i, bucket[8];
6153e12c5d1SDavid du Colombier 	float cs;
6163e12c5d1SDavid du Colombier 
6173e12c5d1SDavid du Colombier 	if(nbuf < 64)
6183e12c5d1SDavid du Colombier 		return 0;
6193e12c5d1SDavid du Colombier 	memset(bucket, 0, sizeof(bucket));
6203e12c5d1SDavid du Colombier 	for(i=0; i<64; i++)
6213e12c5d1SDavid du Colombier 		bucket[(buf[i]>>5)&07] += 1;
6223e12c5d1SDavid du Colombier 
6233e12c5d1SDavid du Colombier 	cs = 0.;
6243e12c5d1SDavid du Colombier 	for(i=0; i<8; i++)
6253e12c5d1SDavid du Colombier 		cs += (bucket[i]-8)*(bucket[i]-8);
6263e12c5d1SDavid du Colombier 	cs /= 8.;
6273e12c5d1SDavid du Colombier 	if(cs <= 24.322) {
6283e12c5d1SDavid du Colombier 		if(buf[0]==037 && buf[1]==0235)
6293e12c5d1SDavid du Colombier 			print("compressed\n");
6303e12c5d1SDavid du Colombier 		else
6313e12c5d1SDavid du Colombier 			print("encrypted\n");
6323e12c5d1SDavid du Colombier 		return 1;
6333e12c5d1SDavid du Colombier 	}
6343e12c5d1SDavid du Colombier 	return 0;
6353e12c5d1SDavid du Colombier }
6363e12c5d1SDavid du Colombier 
6373e12c5d1SDavid du Colombier /*
6383e12c5d1SDavid du Colombier  * english by punctuation and frequencies
6393e12c5d1SDavid du Colombier  */
6403e12c5d1SDavid du Colombier int
6413e12c5d1SDavid du Colombier isenglish(void)
6423e12c5d1SDavid du Colombier {
6433e12c5d1SDavid du Colombier 	int vow, comm, rare, badpun, punct;
6443e12c5d1SDavid du Colombier 	char *p;
6453e12c5d1SDavid du Colombier 
6463e12c5d1SDavid du Colombier 	if(guess != Fascii && guess != Feascii)
6473e12c5d1SDavid du Colombier 		return 0;
6483e12c5d1SDavid du Colombier 	badpun = 0;
6493e12c5d1SDavid du Colombier 	punct = 0;
6503e12c5d1SDavid du Colombier 	for(p = (char *)buf; p < (char *)buf+nbuf-1; p++)
6513e12c5d1SDavid du Colombier 		switch(*p) {
6523e12c5d1SDavid du Colombier 		case '.':
6533e12c5d1SDavid du Colombier 		case ',':
6543e12c5d1SDavid du Colombier 		case ')':
6553e12c5d1SDavid du Colombier 		case '%':
6563e12c5d1SDavid du Colombier 		case ';':
6573e12c5d1SDavid du Colombier 		case ':':
6583e12c5d1SDavid du Colombier 		case '?':
6593e12c5d1SDavid du Colombier 			punct++;
6603e12c5d1SDavid du Colombier 			if(p[1] != ' ' && p[1] != '\n')
6613e12c5d1SDavid du Colombier 				badpun++;
6623e12c5d1SDavid du Colombier 		}
6633e12c5d1SDavid du Colombier 	if(badpun*5 > punct)
6643e12c5d1SDavid du Colombier 		return 0;
6653e12c5d1SDavid du Colombier 	if(cfreq['>']+cfreq['<']+cfreq['/'] > cfreq['e'])	/* shell file test */
6663e12c5d1SDavid du Colombier 		return 0;
6673e12c5d1SDavid du Colombier 	if(2*cfreq[';'] > cfreq['e'])
6683e12c5d1SDavid du Colombier 		return 0;
6693e12c5d1SDavid du Colombier 
6703e12c5d1SDavid du Colombier 	vow = 0;
6713e12c5d1SDavid du Colombier 	for(p="AEIOU"; *p; p++) {
6723e12c5d1SDavid du Colombier 		vow += cfreq[*p];
6733e12c5d1SDavid du Colombier 		vow += cfreq[tolower(*p)];
6743e12c5d1SDavid du Colombier 	}
6753e12c5d1SDavid du Colombier 	comm = 0;
6763e12c5d1SDavid du Colombier 	for(p="ETAION"; *p; p++) {
6773e12c5d1SDavid du Colombier 		comm += cfreq[*p];
6783e12c5d1SDavid du Colombier 		comm += cfreq[tolower(*p)];
6793e12c5d1SDavid du Colombier 	}
6803e12c5d1SDavid du Colombier 	rare = 0;
6813e12c5d1SDavid du Colombier 	for(p="VJKQXZ"; *p; p++) {
6823e12c5d1SDavid du Colombier 		rare += cfreq[*p];
6833e12c5d1SDavid du Colombier 		rare += cfreq[tolower(*p)];
6843e12c5d1SDavid du Colombier 	}
6853e12c5d1SDavid du Colombier 	if(vow*5 >= nbuf-cfreq[' '] && comm >= 10*rare) {
6863e12c5d1SDavid du Colombier 		print("English text\n");
6873e12c5d1SDavid du Colombier 		return 1;
6883e12c5d1SDavid du Colombier 	}
6893e12c5d1SDavid du Colombier 	return 0;
6903e12c5d1SDavid du Colombier }
6913e12c5d1SDavid du Colombier 
6923e12c5d1SDavid du Colombier /*
6933e12c5d1SDavid du Colombier  * pick up a number with
6943e12c5d1SDavid du Colombier  * syntax _*[0-9]+_
6953e12c5d1SDavid du Colombier  */
6963e12c5d1SDavid du Colombier #define	P9BITLEN	12
6973e12c5d1SDavid du Colombier int
6983e12c5d1SDavid du Colombier p9bitnum(uchar *bp)
6993e12c5d1SDavid du Colombier {
7003e12c5d1SDavid du Colombier 	int n, c, len;
7013e12c5d1SDavid du Colombier 
7023e12c5d1SDavid du Colombier 	len = P9BITLEN;
7033e12c5d1SDavid du Colombier 	while(*bp == ' ') {
7043e12c5d1SDavid du Colombier 		bp++;
7053e12c5d1SDavid du Colombier 		len--;
7063e12c5d1SDavid du Colombier 		if(len <= 0)
7073e12c5d1SDavid du Colombier 			return -1;
7083e12c5d1SDavid du Colombier 	}
7093e12c5d1SDavid du Colombier 	n = 0;
7103e12c5d1SDavid du Colombier 	while(len > 1) {
7113e12c5d1SDavid du Colombier 		c = *bp++;
7123e12c5d1SDavid du Colombier 		if(!isdigit(c))
7133e12c5d1SDavid du Colombier 			return -1;
7143e12c5d1SDavid du Colombier 		n = n*10 + c-'0';
7153e12c5d1SDavid du Colombier 		len--;
7163e12c5d1SDavid du Colombier 	}
7173e12c5d1SDavid du Colombier 	if(*bp != ' ')
7183e12c5d1SDavid du Colombier 		return -1;
7193e12c5d1SDavid du Colombier 	return n;
7203e12c5d1SDavid du Colombier }
7213e12c5d1SDavid du Colombier 
7223e12c5d1SDavid du Colombier int
7233e12c5d1SDavid du Colombier isp9bit(void)
7243e12c5d1SDavid du Colombier {
725*219b2ee8SDavid du Colombier 	int ldep, lox, loy, hix, hiy, px;
726*219b2ee8SDavid du Colombier 	ulong t;
7273e12c5d1SDavid du Colombier 	long len;
7283e12c5d1SDavid du Colombier 
7293e12c5d1SDavid du Colombier 	ldep = p9bitnum(buf + 0*P9BITLEN);
7303e12c5d1SDavid du Colombier 	lox = p9bitnum(buf + 1*P9BITLEN);
7313e12c5d1SDavid du Colombier 	loy = p9bitnum(buf + 2*P9BITLEN);
7323e12c5d1SDavid du Colombier 	hix = p9bitnum(buf + 3*P9BITLEN);
7333e12c5d1SDavid du Colombier 	hiy = p9bitnum(buf + 4*P9BITLEN);
7343e12c5d1SDavid du Colombier 
7353e12c5d1SDavid du Colombier 	if(ldep < 0 || lox < 0 || loy < 0 || hix < 0 || hiy < 0)
7363e12c5d1SDavid du Colombier 		return 0;
7373e12c5d1SDavid du Colombier 
738*219b2ee8SDavid du Colombier 	px = 1<<(3-ldep);	/* pixels per byte */
739*219b2ee8SDavid du Colombier 	/* set l to number of bytes of data per scan line */
740*219b2ee8SDavid du Colombier 	if(lox >= 0)
741*219b2ee8SDavid du Colombier 		len = (hix+px-1)/px - lox/px;
742*219b2ee8SDavid du Colombier 	else{	/* make positive before divide */
743*219b2ee8SDavid du Colombier 		t = (-lox)+px-1;
744*219b2ee8SDavid du Colombier 		t = (t/px)*px;
745*219b2ee8SDavid du Colombier 		len = (t+hix+px-1)/px;
746*219b2ee8SDavid du Colombier 	}
7473e12c5d1SDavid du Colombier 	len *= (hiy-loy);		/* col length */
7483e12c5d1SDavid du Colombier 	len += 5*P9BITLEN;		/* size of initial ascii */
7493e12c5d1SDavid du Colombier 
7503e12c5d1SDavid du Colombier 	/*
7513e12c5d1SDavid du Colombier 	 * for bitmap file, length is non-zero and must match calculation above
7523e12c5d1SDavid du Colombier 	 * for /dev/window and /dev/screen the length is always zero
7533e12c5d1SDavid du Colombier 	 * for subfont, the subfont header should follow immediately.
7543e12c5d1SDavid du Colombier 	 */
7553e12c5d1SDavid du Colombier 	if (mbuf.length == 0)
7563e12c5d1SDavid du Colombier 		return 0;
7573e12c5d1SDavid du Colombier 	if (mbuf.length == len) {
7583e12c5d1SDavid du Colombier 		print("plan 9 bitmap\n");
7593e12c5d1SDavid du Colombier 		return 1;
7603e12c5d1SDavid du Colombier 	}
7613e12c5d1SDavid du Colombier 	if (p9subfont(buf+len)) {
7623e12c5d1SDavid du Colombier 		print("subfont file\n");
7633e12c5d1SDavid du Colombier 		return 1;
7643e12c5d1SDavid du Colombier 	}
7653e12c5d1SDavid du Colombier 	return 0;
7663e12c5d1SDavid du Colombier }
7673e12c5d1SDavid du Colombier 
7683e12c5d1SDavid du Colombier int
7693e12c5d1SDavid du Colombier p9subfont(uchar *p)
7703e12c5d1SDavid du Colombier {
7713e12c5d1SDavid du Colombier 	int n, h, a;
7723e12c5d1SDavid du Colombier 
7733e12c5d1SDavid du Colombier 		/* if bitmap too big, assume it's a subfont */
7743e12c5d1SDavid du Colombier 	if (p+3*P9BITLEN > buf+sizeof(buf))
7753e12c5d1SDavid du Colombier 		return 1;
7763e12c5d1SDavid du Colombier 
7773e12c5d1SDavid du Colombier 	n = p9bitnum(p + 0*P9BITLEN);	/* char count */
7783e12c5d1SDavid du Colombier 	if (n < 0)
7793e12c5d1SDavid du Colombier 		return 0;
7803e12c5d1SDavid du Colombier 	h = p9bitnum(p + 1*P9BITLEN);	/* height */
7813e12c5d1SDavid du Colombier 	if (h < 0)
7823e12c5d1SDavid du Colombier 		return 0;
7833e12c5d1SDavid du Colombier 	a = p9bitnum(p + 2*P9BITLEN);	/* ascent */
7843e12c5d1SDavid du Colombier 	if (a < 0)
7853e12c5d1SDavid du Colombier 		return 0;
7863e12c5d1SDavid du Colombier 	return 1;
7873e12c5d1SDavid du Colombier }
7883e12c5d1SDavid du Colombier 
7893e12c5d1SDavid du Colombier #define	WHITESPACE(c)		((c) == ' ' || (c) == '\t' || (c) == '\n')
7903e12c5d1SDavid du Colombier 
7913e12c5d1SDavid du Colombier int
7923e12c5d1SDavid du Colombier isp9font(void)
7933e12c5d1SDavid du Colombier {
7943e12c5d1SDavid du Colombier 	uchar *cp, *p;
7953e12c5d1SDavid du Colombier 	int i, n;
7963e12c5d1SDavid du Colombier 	char dbuf[DIRLEN];
7973e12c5d1SDavid du Colombier 	char pathname[1024];
7983e12c5d1SDavid du Colombier 
7993e12c5d1SDavid du Colombier 	cp = buf;
8003e12c5d1SDavid du Colombier 	if (!getfontnum(cp, &cp))	/* height */
8013e12c5d1SDavid du Colombier 		return 0;
8023e12c5d1SDavid du Colombier 	if (!getfontnum(cp, &cp))	/* ascent */
8033e12c5d1SDavid du Colombier 		return 0;
8043e12c5d1SDavid du Colombier 	for (i = 0; 1; i++) {
8053e12c5d1SDavid du Colombier 		if (!getfontnum(cp, &cp))	/* min */
8063e12c5d1SDavid du Colombier 			break;
8073e12c5d1SDavid du Colombier 		if (!getfontnum(cp, &cp))	/* max */
8083e12c5d1SDavid du Colombier 			return 0;
8093e12c5d1SDavid du Colombier 		while (WHITESPACE(*cp))
8103e12c5d1SDavid du Colombier 			cp++;
8113e12c5d1SDavid du Colombier 		for (p = cp; *cp && !WHITESPACE(*cp); cp++)
8123e12c5d1SDavid du Colombier 				;
8133e12c5d1SDavid du Colombier 			/* construct a path name, if needed */
8143e12c5d1SDavid du Colombier 		n = 0;
8153e12c5d1SDavid du Colombier 		if (*p != '/' && slash) {
8163e12c5d1SDavid du Colombier 			n = slash-fname+1;
8173e12c5d1SDavid du Colombier 			if (n < sizeof(pathname))
8183e12c5d1SDavid du Colombier 				memcpy(pathname, fname, n);
8193e12c5d1SDavid du Colombier 			else n = 0;
8203e12c5d1SDavid du Colombier 		}
8213e12c5d1SDavid du Colombier 		if (n+cp-p < sizeof(pathname)) {
8223e12c5d1SDavid du Colombier 			memcpy(pathname+n, p, cp-p);
8233e12c5d1SDavid du Colombier 			n += cp-p;
8243e12c5d1SDavid du Colombier 			pathname[n] = 0;
8253e12c5d1SDavid du Colombier 			if (stat(pathname, dbuf) < 0)
8263e12c5d1SDavid du Colombier 				return 0;
8273e12c5d1SDavid du Colombier 		}
8283e12c5d1SDavid du Colombier 	}
8293e12c5d1SDavid du Colombier 	if (i) {
8303e12c5d1SDavid du Colombier 		print("font file\n");
8313e12c5d1SDavid du Colombier 		return 1;
8323e12c5d1SDavid du Colombier 	}
8333e12c5d1SDavid du Colombier 	return 0;
8343e12c5d1SDavid du Colombier }
8353e12c5d1SDavid du Colombier 
8363e12c5d1SDavid du Colombier int
8373e12c5d1SDavid du Colombier getfontnum(uchar *cp, uchar **rp)
8383e12c5d1SDavid du Colombier {
8393e12c5d1SDavid du Colombier 	while (WHITESPACE(*cp))		/* extract ulong delimited by whitespace */
8403e12c5d1SDavid du Colombier 		cp++;
8413e12c5d1SDavid du Colombier 	if (*cp < '0' || *cp > '9')
8423e12c5d1SDavid du Colombier 		return 0;
8433e12c5d1SDavid du Colombier 	strtoul((char *)cp, (char **)rp, 0);
8443e12c5d1SDavid du Colombier 	if (!WHITESPACE(**rp))
8453e12c5d1SDavid du Colombier 		return 0;
8463e12c5d1SDavid du Colombier 	return 1;
8473e12c5d1SDavid du Colombier }
848