1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1985-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> *
18da2e3ebdSchin * David Korn <dgk@research.att.com> *
19da2e3ebdSchin * Phong Vo <kpv@research.att.com> *
20da2e3ebdSchin * *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin * Glenn Fowler
25da2e3ebdSchin * AT&T Research
26da2e3ebdSchin *
27da2e3ebdSchin * library interface to file
28da2e3ebdSchin *
29da2e3ebdSchin * the sum of the hacks {s5,v10,planix} is _____ than the parts
30da2e3ebdSchin */
31da2e3ebdSchin
327c2fbfb3SApril Chin static const char id[] = "\n@(#)$Id: magic library (AT&T Research) 2008-09-10 $\0\n";
33da2e3ebdSchin
34da2e3ebdSchin static const char lib[] = "libast:magic";
35da2e3ebdSchin
36da2e3ebdSchin #include <ast.h>
37da2e3ebdSchin #include <ctype.h>
38da2e3ebdSchin #include <ccode.h>
39da2e3ebdSchin #include <dt.h>
40da2e3ebdSchin #include <modex.h>
41da2e3ebdSchin #include <error.h>
42da2e3ebdSchin #include <regex.h>
43da2e3ebdSchin #include <swap.h>
44da2e3ebdSchin
45da2e3ebdSchin #define T(m) (*m?ERROR_translate(NiL,NiL,lib,m):m)
46da2e3ebdSchin
47da2e3ebdSchin #define match(s,p) strgrpmatch(s,p,NiL,0,STR_LEFT|STR_RIGHT|STR_ICASE)
48da2e3ebdSchin
49da2e3ebdSchin #define MAXNEST 10 /* { ... } nesting limit */
50da2e3ebdSchin #define MINITEM 4 /* magic buffer rounding */
51da2e3ebdSchin
52da2e3ebdSchin typedef struct /* identifier dictionary entry */
53da2e3ebdSchin {
54da2e3ebdSchin const char name[16]; /* identifier name */
55da2e3ebdSchin int value; /* identifier value */
56da2e3ebdSchin Dtlink_t link; /* dictionary link */
57da2e3ebdSchin } Info_t;
58da2e3ebdSchin
59da2e3ebdSchin typedef struct Edit /* edit substitution */
60da2e3ebdSchin {
61da2e3ebdSchin struct Edit* next; /* next in list */
62da2e3ebdSchin regex_t* from; /* from pattern */
63da2e3ebdSchin } Edit_t;
64da2e3ebdSchin
65da2e3ebdSchin struct Entry;
66da2e3ebdSchin
67da2e3ebdSchin typedef struct /* loop info */
68da2e3ebdSchin {
69da2e3ebdSchin struct Entry* lab; /* call this function */
70da2e3ebdSchin int start; /* start here */
71da2e3ebdSchin int size; /* increment by this amount */
72da2e3ebdSchin int count; /* dynamic loop count */
73da2e3ebdSchin int offset; /* dynamic offset */
74da2e3ebdSchin } Loop_t;
75da2e3ebdSchin
76da2e3ebdSchin typedef struct Entry /* magic file entry */
77da2e3ebdSchin {
78da2e3ebdSchin struct Entry* next; /* next in list */
79da2e3ebdSchin char* expr; /* offset expression */
80da2e3ebdSchin union
81da2e3ebdSchin {
82da2e3ebdSchin unsigned long num;
83da2e3ebdSchin char* str;
84da2e3ebdSchin struct Entry* lab;
85da2e3ebdSchin regex_t* sub;
86da2e3ebdSchin Loop_t* loop;
87da2e3ebdSchin } value; /* comparison value */
88da2e3ebdSchin char* desc; /* file description */
89da2e3ebdSchin char* mime; /* file mime type */
90da2e3ebdSchin unsigned long offset; /* offset in bytes */
91da2e3ebdSchin unsigned long mask; /* mask before compare */
92da2e3ebdSchin char cont; /* continuation operation */
93da2e3ebdSchin char type; /* datum type */
94da2e3ebdSchin char op; /* comparison operation */
95da2e3ebdSchin char nest; /* { or } nesting operation */
96da2e3ebdSchin char swap; /* forced swap order */
97da2e3ebdSchin } Entry_t;
98da2e3ebdSchin
99da2e3ebdSchin #define CC_BIT 5
100da2e3ebdSchin
101da2e3ebdSchin #if (CC_MAPS*CC_BIT) <= (CHAR_BIT*2)
102da2e3ebdSchin typedef unsigned short Cctype_t;
103da2e3ebdSchin #else
104da2e3ebdSchin typedef unsigned long Cctype_t;
105da2e3ebdSchin #endif
106da2e3ebdSchin
107da2e3ebdSchin #define CC_text 0x01
108da2e3ebdSchin #define CC_control 0x02
109da2e3ebdSchin #define CC_latin 0x04
110da2e3ebdSchin #define CC_binary 0x08
111da2e3ebdSchin #define CC_utf_8 0x10
112da2e3ebdSchin
113da2e3ebdSchin #define CC_notext CC_text /* CC_text is flipped before checking */
114da2e3ebdSchin
115da2e3ebdSchin #define CC_MASK (CC_binary|CC_latin|CC_control|CC_text)
116da2e3ebdSchin
117da2e3ebdSchin #define CCTYPE(c) (((c)>0240)?CC_binary:((c)>=0200)?CC_latin:((c)<040&&(c)!=007&&(c)!=011&&(c)!=012&&(c)!=013&&(c)!=015)?CC_control:CC_text)
118da2e3ebdSchin
119da2e3ebdSchin #define ID_NONE 0
120da2e3ebdSchin #define ID_ASM 1
121da2e3ebdSchin #define ID_C 2
122da2e3ebdSchin #define ID_COBOL 3
123da2e3ebdSchin #define ID_COPYBOOK 4
124da2e3ebdSchin #define ID_CPLUSPLUS 5
125da2e3ebdSchin #define ID_FORTRAN 6
126da2e3ebdSchin #define ID_HTML 7
127da2e3ebdSchin #define ID_INCL1 8
128da2e3ebdSchin #define ID_INCL2 9
129da2e3ebdSchin #define ID_INCL3 10
130da2e3ebdSchin #define ID_MAM1 11
131da2e3ebdSchin #define ID_MAM2 12
132da2e3ebdSchin #define ID_MAM3 13
133da2e3ebdSchin #define ID_NOTEXT 14
134da2e3ebdSchin #define ID_PL1 15
135da2e3ebdSchin #define ID_YACC 16
136da2e3ebdSchin
137da2e3ebdSchin #define ID_MAX ID_YACC
138da2e3ebdSchin
139da2e3ebdSchin #define INFO_atime 1
140da2e3ebdSchin #define INFO_blocks 2
141da2e3ebdSchin #define INFO_ctime 3
142da2e3ebdSchin #define INFO_fstype 4
143da2e3ebdSchin #define INFO_gid 5
144da2e3ebdSchin #define INFO_mode 6
145da2e3ebdSchin #define INFO_mtime 7
146da2e3ebdSchin #define INFO_name 8
147da2e3ebdSchin #define INFO_nlink 9
148da2e3ebdSchin #define INFO_size 10
149da2e3ebdSchin #define INFO_uid 11
150da2e3ebdSchin
151da2e3ebdSchin #define _MAGIC_PRIVATE_ \
152da2e3ebdSchin Magicdisc_t* disc; /* discipline */ \
153da2e3ebdSchin Vmalloc_t* vm; /* vmalloc region */ \
154da2e3ebdSchin Entry_t* magic; /* parsed magic table */ \
155da2e3ebdSchin Entry_t* magiclast; /* last entry in magic */ \
156da2e3ebdSchin char* mime; /* MIME type */ \
157da2e3ebdSchin unsigned char* x2n; /* CC_ALIEN=>CC_NATIVE */ \
158da2e3ebdSchin char fbuf[SF_BUFSIZE + 1]; /* file data */ \
159da2e3ebdSchin char xbuf[SF_BUFSIZE + 1]; /* indirect file data */ \
160da2e3ebdSchin char nbuf[256]; /* !CC_NATIVE data */ \
161da2e3ebdSchin char mbuf[64]; /* mime string */ \
162da2e3ebdSchin char sbuf[64]; /* type suffix string */ \
163da2e3ebdSchin char tbuf[2 * PATH_MAX]; /* type string */ \
164da2e3ebdSchin Cctype_t cctype[UCHAR_MAX + 1]; /* char code types */ \
165da2e3ebdSchin unsigned int count[UCHAR_MAX + 1]; /* char frequency count */ \
166da2e3ebdSchin unsigned int multi[UCHAR_MAX + 1]; /* muti char count */ \
167da2e3ebdSchin int keep[MAXNEST]; /* ckmagic nest stack */ \
168da2e3ebdSchin char* cap[MAXNEST]; /* ckmagic mime stack */ \
169da2e3ebdSchin char* msg[MAXNEST]; /* ckmagic text stack */ \
170da2e3ebdSchin Entry_t* ret[MAXNEST]; /* ckmagic return stack */ \
171da2e3ebdSchin int fbsz; /* fbuf size */ \
172da2e3ebdSchin int fbmx; /* fbuf max size */ \
173da2e3ebdSchin int xbsz; /* xbuf size */ \
174da2e3ebdSchin int swap; /* swap() operation */ \
175da2e3ebdSchin unsigned long flags; /* disc+open flags */ \
176da2e3ebdSchin long xoff; /* xbuf offset */ \
177da2e3ebdSchin int identifier[ID_MAX + 1]; /* Info_t identifier */ \
178da2e3ebdSchin Sfio_t* fp; /* fbuf fp */ \
179da2e3ebdSchin Sfio_t* tmp; /* tmp string */ \
180da2e3ebdSchin regdisc_t redisc; /* regex discipline */ \
181da2e3ebdSchin Dtdisc_t dtdisc; /* dict discipline */ \
182da2e3ebdSchin Dt_t* idtab; /* identifier dict */ \
183da2e3ebdSchin Dt_t* infotab; /* info keyword dict */
184da2e3ebdSchin
185da2e3ebdSchin #include <magic.h>
186da2e3ebdSchin
187da2e3ebdSchin static Info_t dict[] = /* keyword dictionary */
188da2e3ebdSchin {
189da2e3ebdSchin { "COMMON", ID_FORTRAN },
190da2e3ebdSchin { "COMPUTE", ID_COBOL },
191da2e3ebdSchin { "COMP", ID_COPYBOOK },
192da2e3ebdSchin { "COMPUTATIONAL",ID_COPYBOOK },
193da2e3ebdSchin { "DCL", ID_PL1 },
194da2e3ebdSchin { "DEFINED", ID_PL1 },
195da2e3ebdSchin { "DIMENSION", ID_FORTRAN },
196da2e3ebdSchin { "DIVISION", ID_COBOL },
197da2e3ebdSchin { "FILLER", ID_COPYBOOK },
198da2e3ebdSchin { "FIXED", ID_PL1 },
199da2e3ebdSchin { "FUNCTION", ID_FORTRAN },
200da2e3ebdSchin { "HTML", ID_HTML },
201da2e3ebdSchin { "INTEGER", ID_FORTRAN },
202da2e3ebdSchin { "MAIN", ID_PL1 },
203da2e3ebdSchin { "OPTIONS", ID_PL1 },
204da2e3ebdSchin { "PERFORM", ID_COBOL },
205da2e3ebdSchin { "PIC", ID_COPYBOOK },
206da2e3ebdSchin { "REAL", ID_FORTRAN },
207da2e3ebdSchin { "REDEFINES", ID_COPYBOOK },
208da2e3ebdSchin { "S9", ID_COPYBOOK },
209da2e3ebdSchin { "SECTION", ID_COBOL },
210da2e3ebdSchin { "SELECT", ID_COBOL },
211da2e3ebdSchin { "SUBROUTINE", ID_FORTRAN },
212da2e3ebdSchin { "TEXT", ID_ASM },
213da2e3ebdSchin { "VALUE", ID_COPYBOOK },
214da2e3ebdSchin { "attr", ID_MAM3 },
215da2e3ebdSchin { "binary", ID_YACC },
216da2e3ebdSchin { "block", ID_FORTRAN },
217da2e3ebdSchin { "bss", ID_ASM },
218da2e3ebdSchin { "byte", ID_ASM },
219da2e3ebdSchin { "char", ID_C },
220da2e3ebdSchin { "class", ID_CPLUSPLUS },
221da2e3ebdSchin { "clr", ID_NOTEXT },
222da2e3ebdSchin { "comm", ID_ASM },
223da2e3ebdSchin { "common", ID_FORTRAN },
224da2e3ebdSchin { "data", ID_ASM },
225da2e3ebdSchin { "dimension", ID_FORTRAN },
226da2e3ebdSchin { "done", ID_MAM2 },
227da2e3ebdSchin { "double", ID_C },
228da2e3ebdSchin { "even", ID_ASM },
229da2e3ebdSchin { "exec", ID_MAM3 },
230da2e3ebdSchin { "extern", ID_C },
231da2e3ebdSchin { "float", ID_C },
232da2e3ebdSchin { "function", ID_FORTRAN },
233da2e3ebdSchin { "globl", ID_ASM },
234da2e3ebdSchin { "h", ID_INCL3 },
235da2e3ebdSchin { "html", ID_HTML },
236da2e3ebdSchin { "include", ID_INCL1 },
237da2e3ebdSchin { "int", ID_C },
238da2e3ebdSchin { "integer", ID_FORTRAN },
239da2e3ebdSchin { "jmp", ID_NOTEXT },
240da2e3ebdSchin { "left", ID_YACC },
241da2e3ebdSchin { "libc", ID_INCL2 },
242da2e3ebdSchin { "long", ID_C },
243da2e3ebdSchin { "make", ID_MAM1 },
244da2e3ebdSchin { "mov", ID_NOTEXT },
245da2e3ebdSchin { "private", ID_CPLUSPLUS },
246da2e3ebdSchin { "public", ID_CPLUSPLUS },
247da2e3ebdSchin { "real", ID_FORTRAN },
248da2e3ebdSchin { "register", ID_C },
249da2e3ebdSchin { "right", ID_YACC },
250da2e3ebdSchin { "sfio", ID_INCL2 },
251da2e3ebdSchin { "static", ID_C },
252da2e3ebdSchin { "stdio", ID_INCL2 },
253da2e3ebdSchin { "struct", ID_C },
254da2e3ebdSchin { "subroutine", ID_FORTRAN },
255da2e3ebdSchin { "sys", ID_NOTEXT },
256da2e3ebdSchin { "term", ID_YACC },
257da2e3ebdSchin { "text", ID_ASM },
258da2e3ebdSchin { "tst", ID_NOTEXT },
259da2e3ebdSchin { "type", ID_YACC },
260da2e3ebdSchin { "typedef", ID_C },
261da2e3ebdSchin { "u", ID_INCL2 },
262da2e3ebdSchin { "union", ID_YACC },
263da2e3ebdSchin { "void", ID_C },
264da2e3ebdSchin };
265da2e3ebdSchin
266da2e3ebdSchin static Info_t info[] =
267da2e3ebdSchin {
268da2e3ebdSchin { "atime", INFO_atime },
269da2e3ebdSchin { "blocks", INFO_blocks },
270da2e3ebdSchin { "ctime", INFO_ctime },
271da2e3ebdSchin { "fstype", INFO_fstype },
272da2e3ebdSchin { "gid", INFO_gid },
273da2e3ebdSchin { "mode", INFO_mode },
274da2e3ebdSchin { "mtime", INFO_mtime },
275da2e3ebdSchin { "name", INFO_name },
276da2e3ebdSchin { "nlink", INFO_nlink },
277da2e3ebdSchin { "size", INFO_size },
278da2e3ebdSchin { "uid", INFO_uid },
279da2e3ebdSchin };
280da2e3ebdSchin
281da2e3ebdSchin /*
282da2e3ebdSchin * return pointer to data at offset off and size siz
283da2e3ebdSchin */
284da2e3ebdSchin
285da2e3ebdSchin static char*
getdata(register Magic_t * mp,register long off,register int siz)286da2e3ebdSchin getdata(register Magic_t* mp, register long off, register int siz)
287da2e3ebdSchin {
288da2e3ebdSchin register long n;
289da2e3ebdSchin
290da2e3ebdSchin if (off < 0)
291da2e3ebdSchin return 0;
292da2e3ebdSchin if (off + siz <= mp->fbsz)
293da2e3ebdSchin return mp->fbuf + off;
294da2e3ebdSchin if (off < mp->xoff || off + siz > mp->xoff + mp->xbsz)
295da2e3ebdSchin {
296da2e3ebdSchin if (off + siz > mp->fbmx)
297da2e3ebdSchin return 0;
298da2e3ebdSchin n = (off / (SF_BUFSIZE / 2)) * (SF_BUFSIZE / 2);
299da2e3ebdSchin if (sfseek(mp->fp, n, SEEK_SET) != n)
300da2e3ebdSchin return 0;
301da2e3ebdSchin if ((mp->xbsz = sfread(mp->fp, mp->xbuf, sizeof(mp->xbuf) - 1)) < 0)
302da2e3ebdSchin {
303da2e3ebdSchin mp->xoff = 0;
304da2e3ebdSchin mp->xbsz = 0;
305da2e3ebdSchin return 0;
306da2e3ebdSchin }
307da2e3ebdSchin mp->xbuf[mp->xbsz] = 0;
308da2e3ebdSchin mp->xoff = n;
309da2e3ebdSchin if (off + siz > mp->xoff + mp->xbsz)
310da2e3ebdSchin return 0;
311da2e3ebdSchin }
312da2e3ebdSchin return mp->xbuf + off - mp->xoff;
313da2e3ebdSchin }
314da2e3ebdSchin
315da2e3ebdSchin /*
316da2e3ebdSchin * @... evaluator for strexpr()
317da2e3ebdSchin */
318da2e3ebdSchin
319da2e3ebdSchin static long
indirect(const char * cs,char ** e,void * handle)320da2e3ebdSchin indirect(const char* cs, char** e, void* handle)
321da2e3ebdSchin {
322da2e3ebdSchin register char* s = (char*)cs;
323da2e3ebdSchin register Magic_t* mp = (Magic_t*)handle;
324da2e3ebdSchin register long n = 0;
325da2e3ebdSchin register char* p;
326da2e3ebdSchin
327da2e3ebdSchin if (s)
328da2e3ebdSchin {
329da2e3ebdSchin if (*s == '@')
330da2e3ebdSchin {
331da2e3ebdSchin n = *++s == '(' ? strexpr(s, e, indirect, mp) : strtol(s, e, 0);
332da2e3ebdSchin switch (*(s = *e))
333da2e3ebdSchin {
334da2e3ebdSchin case 'b':
335da2e3ebdSchin case 'B':
336da2e3ebdSchin s++;
337da2e3ebdSchin if (p = getdata(mp, n, 1))
338da2e3ebdSchin n = *(unsigned char*)p;
339da2e3ebdSchin else
340da2e3ebdSchin s = (char*)cs;
341da2e3ebdSchin break;
342da2e3ebdSchin case 'h':
343da2e3ebdSchin case 'H':
344da2e3ebdSchin s++;
345da2e3ebdSchin if (p = getdata(mp, n, 2))
346da2e3ebdSchin n = swapget(mp->swap, p, 2);
347da2e3ebdSchin else
348da2e3ebdSchin s = (char*)cs;
349da2e3ebdSchin break;
350da2e3ebdSchin case 'q':
351da2e3ebdSchin case 'Q':
352da2e3ebdSchin s++;
353da2e3ebdSchin if (p = getdata(mp, n, 8))
354da2e3ebdSchin n = swapget(mp->swap, p, 8);
355da2e3ebdSchin else
356da2e3ebdSchin s = (char*)cs;
357da2e3ebdSchin break;
358da2e3ebdSchin default:
359da2e3ebdSchin if (isalnum(*s))
360da2e3ebdSchin s++;
361da2e3ebdSchin if (p = getdata(mp, n, 4))
362da2e3ebdSchin n = swapget(mp->swap, p, 4);
363da2e3ebdSchin else
364da2e3ebdSchin s = (char*)cs;
365da2e3ebdSchin break;
366da2e3ebdSchin }
367da2e3ebdSchin }
368da2e3ebdSchin *e = s;
369da2e3ebdSchin }
370da2e3ebdSchin else if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
371da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 2, "%s in indirect expression", *e);
372da2e3ebdSchin return n;
373da2e3ebdSchin }
374da2e3ebdSchin
375da2e3ebdSchin /*
376da2e3ebdSchin * emit regex error message
377da2e3ebdSchin */
378da2e3ebdSchin
379da2e3ebdSchin static void
regmessage(Magic_t * mp,regex_t * re,int code)380da2e3ebdSchin regmessage(Magic_t* mp, regex_t* re, int code)
381da2e3ebdSchin {
382da2e3ebdSchin char buf[128];
383da2e3ebdSchin
384da2e3ebdSchin if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
385da2e3ebdSchin {
386da2e3ebdSchin regerror(code, re, buf, sizeof(buf));
387da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 3, "regex: %s", buf);
388da2e3ebdSchin }
389da2e3ebdSchin }
390da2e3ebdSchin
391da2e3ebdSchin /*
392da2e3ebdSchin * decompose vcodex(3) method composition
393da2e3ebdSchin */
394da2e3ebdSchin
395da2e3ebdSchin static char*
vcdecomp(char * b,char * e,unsigned char * m,unsigned char * x)396da2e3ebdSchin vcdecomp(char* b, char* e, unsigned char* m, unsigned char* x)
397da2e3ebdSchin {
398da2e3ebdSchin unsigned char* map;
3997c2fbfb3SApril Chin const char* o;
400da2e3ebdSchin int c;
401da2e3ebdSchin int n;
402da2e3ebdSchin int i;
4037c2fbfb3SApril Chin int a;
404da2e3ebdSchin
405da2e3ebdSchin map = CCMAP(CC_ASCII, CC_NATIVE);
4067c2fbfb3SApril Chin a = 0;
407da2e3ebdSchin i = 1;
408da2e3ebdSchin for (;;)
409da2e3ebdSchin {
410da2e3ebdSchin if (i)
411da2e3ebdSchin i = 0;
412da2e3ebdSchin else
413da2e3ebdSchin *b++ = '^';
4147c2fbfb3SApril Chin if (m < (x - 1) && !*(m + 1))
4157c2fbfb3SApril Chin {
4167c2fbfb3SApril Chin /*
4177c2fbfb3SApril Chin * obsolete indices
4187c2fbfb3SApril Chin */
4197c2fbfb3SApril Chin
4207c2fbfb3SApril Chin if (!a)
4217c2fbfb3SApril Chin {
4227c2fbfb3SApril Chin a = 1;
4237c2fbfb3SApril Chin o = "old, ";
4247c2fbfb3SApril Chin while (b < e && (c = *o++))
4257c2fbfb3SApril Chin *b++ = c;
4267c2fbfb3SApril Chin }
4277c2fbfb3SApril Chin switch (*m)
4287c2fbfb3SApril Chin {
4297c2fbfb3SApril Chin case 0: o = "delta"; break;
4307c2fbfb3SApril Chin case 1: o = "huffman"; break;
4317c2fbfb3SApril Chin case 2: o = "huffgroup"; break;
4327c2fbfb3SApril Chin case 3: o = "arith"; break;
4337c2fbfb3SApril Chin case 4: o = "bwt"; break;
4347c2fbfb3SApril Chin case 5: o = "rle"; break;
4357c2fbfb3SApril Chin case 6: o = "mtf"; break;
4367c2fbfb3SApril Chin case 7: o = "transpose"; break;
4377c2fbfb3SApril Chin case 8: o = "table"; break;
4387c2fbfb3SApril Chin case 9: o = "huffpart"; break;
4397c2fbfb3SApril Chin case 50: o = "map"; break;
4407c2fbfb3SApril Chin case 100: o = "recfm"; break;
4417c2fbfb3SApril Chin case 101: o = "ss7"; break;
4427c2fbfb3SApril Chin default: o = "UNKNOWN"; break;
4437c2fbfb3SApril Chin }
4447c2fbfb3SApril Chin m += 2;
4457c2fbfb3SApril Chin while (b < e && (c = *o++))
4467c2fbfb3SApril Chin *b++ = c;
4477c2fbfb3SApril Chin }
4487c2fbfb3SApril Chin else
449da2e3ebdSchin while (b < e && m < x && (c = *m++))
450da2e3ebdSchin {
451da2e3ebdSchin if (map)
452da2e3ebdSchin c = map[c];
453da2e3ebdSchin *b++ = c;
454da2e3ebdSchin }
455da2e3ebdSchin if (b >= e)
456da2e3ebdSchin break;
457da2e3ebdSchin n = 0;
458da2e3ebdSchin while (m < x)
459da2e3ebdSchin {
460da2e3ebdSchin n = (n<<7) | (*m & 0x7f);
461da2e3ebdSchin if (!(*m++ & 0x80))
462da2e3ebdSchin break;
463da2e3ebdSchin }
464da2e3ebdSchin if (n >= (x - m))
465da2e3ebdSchin break;
466da2e3ebdSchin m += n;
467da2e3ebdSchin }
468da2e3ebdSchin return b;
469da2e3ebdSchin }
470da2e3ebdSchin
471da2e3ebdSchin /*
472da2e3ebdSchin * check for magic table match in buf
473da2e3ebdSchin */
474da2e3ebdSchin
475da2e3ebdSchin static char*
ckmagic(register Magic_t * mp,const char * file,char * buf,struct stat * st,unsigned long off)476da2e3ebdSchin ckmagic(register Magic_t* mp, const char* file, char* buf, struct stat* st, unsigned long off)
477da2e3ebdSchin {
478da2e3ebdSchin register Entry_t* ep;
479da2e3ebdSchin register char* p;
480da2e3ebdSchin register char* b;
481da2e3ebdSchin register int level = 0;
482da2e3ebdSchin int call = -1;
483da2e3ebdSchin int c;
484da2e3ebdSchin char* q;
485da2e3ebdSchin char* t;
486da2e3ebdSchin char* base = 0;
487da2e3ebdSchin unsigned long num;
488da2e3ebdSchin unsigned long mask;
489da2e3ebdSchin regmatch_t matches[10];
490da2e3ebdSchin
491da2e3ebdSchin mp->swap = 0;
492da2e3ebdSchin b = mp->msg[0] = buf;
493da2e3ebdSchin mp->mime = mp->cap[0] = 0;
494da2e3ebdSchin mp->keep[0] = 0;
495da2e3ebdSchin for (ep = mp->magic; ep; ep = ep->next)
496da2e3ebdSchin {
497da2e3ebdSchin fun:
498da2e3ebdSchin if (ep->nest == '{')
499da2e3ebdSchin {
500da2e3ebdSchin if (++level >= MAXNEST)
501da2e3ebdSchin {
502da2e3ebdSchin call = -1;
503da2e3ebdSchin level = 0;
504da2e3ebdSchin mp->keep[0] = 0;
505da2e3ebdSchin b = mp->msg[0];
506da2e3ebdSchin mp->mime = mp->cap[0];
507da2e3ebdSchin continue;
508da2e3ebdSchin }
509da2e3ebdSchin mp->keep[level] = mp->keep[level - 1] != 0;
510da2e3ebdSchin mp->msg[level] = b;
511da2e3ebdSchin mp->cap[level] = mp->mime;
512da2e3ebdSchin }
513da2e3ebdSchin switch (ep->cont)
514da2e3ebdSchin {
515da2e3ebdSchin case '#':
516da2e3ebdSchin if (mp->keep[level] && b > buf)
517da2e3ebdSchin {
518da2e3ebdSchin *b = 0;
519da2e3ebdSchin return buf;
520da2e3ebdSchin }
521da2e3ebdSchin mp->swap = 0;
522da2e3ebdSchin b = mp->msg[0] = buf;
523da2e3ebdSchin mp->mime = mp->cap[0] = 0;
524da2e3ebdSchin if (ep->type == ' ')
525da2e3ebdSchin continue;
526da2e3ebdSchin break;
527da2e3ebdSchin case '$':
528da2e3ebdSchin if (mp->keep[level] && call < (MAXNEST - 1))
529da2e3ebdSchin {
530da2e3ebdSchin mp->ret[++call] = ep;
531da2e3ebdSchin ep = ep->value.lab;
532da2e3ebdSchin goto fun;
533da2e3ebdSchin }
534da2e3ebdSchin continue;
535da2e3ebdSchin case ':':
536da2e3ebdSchin ep = mp->ret[call--];
537da2e3ebdSchin if (ep->op == 'l')
538da2e3ebdSchin goto fun;
539da2e3ebdSchin continue;
540da2e3ebdSchin case '|':
541da2e3ebdSchin if (mp->keep[level] > 1)
542da2e3ebdSchin goto checknest;
543da2e3ebdSchin /*FALLTHROUGH*/
544da2e3ebdSchin default:
545da2e3ebdSchin if (!mp->keep[level])
546da2e3ebdSchin {
547da2e3ebdSchin b = mp->msg[level];
548da2e3ebdSchin mp->mime = mp->cap[level];
549da2e3ebdSchin goto checknest;
550da2e3ebdSchin }
551da2e3ebdSchin break;
552da2e3ebdSchin }
5537c2fbfb3SApril Chin p = "";
5547c2fbfb3SApril Chin num = 0;
555da2e3ebdSchin if (!ep->expr)
556da2e3ebdSchin num = ep->offset + off;
557da2e3ebdSchin else
558da2e3ebdSchin switch (ep->offset)
559da2e3ebdSchin {
560da2e3ebdSchin case 0:
561da2e3ebdSchin num = strexpr(ep->expr, NiL, indirect, mp) + off;
562da2e3ebdSchin break;
563da2e3ebdSchin case INFO_atime:
564da2e3ebdSchin num = st->st_atime;
565da2e3ebdSchin ep->type = 'D';
566da2e3ebdSchin break;
567da2e3ebdSchin case INFO_blocks:
568da2e3ebdSchin num = iblocks(st);
569da2e3ebdSchin ep->type = 'N';
570da2e3ebdSchin break;
571da2e3ebdSchin case INFO_ctime:
572da2e3ebdSchin num = st->st_ctime;
573da2e3ebdSchin ep->type = 'D';
574da2e3ebdSchin break;
575da2e3ebdSchin case INFO_fstype:
576da2e3ebdSchin p = fmtfs(st);
577da2e3ebdSchin ep->type = toupper(ep->type);
578da2e3ebdSchin break;
579da2e3ebdSchin case INFO_gid:
580da2e3ebdSchin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
581da2e3ebdSchin {
582da2e3ebdSchin p = fmtgid(st->st_gid);
583da2e3ebdSchin ep->type = toupper(ep->type);
584da2e3ebdSchin }
585da2e3ebdSchin else
586da2e3ebdSchin {
587da2e3ebdSchin num = st->st_gid;
588da2e3ebdSchin ep->type = 'N';
589da2e3ebdSchin }
590da2e3ebdSchin break;
591da2e3ebdSchin case INFO_mode:
592da2e3ebdSchin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
593da2e3ebdSchin {
594da2e3ebdSchin p = fmtmode(st->st_mode, 0);
595da2e3ebdSchin ep->type = toupper(ep->type);
596da2e3ebdSchin }
597da2e3ebdSchin else
598da2e3ebdSchin {
599da2e3ebdSchin num = modex(st->st_mode);
600da2e3ebdSchin ep->type = 'N';
601da2e3ebdSchin }
602da2e3ebdSchin break;
603da2e3ebdSchin case INFO_mtime:
604da2e3ebdSchin num = st->st_ctime;
605da2e3ebdSchin ep->type = 'D';
606da2e3ebdSchin break;
607da2e3ebdSchin case INFO_name:
608da2e3ebdSchin if (!base)
609da2e3ebdSchin {
610da2e3ebdSchin if (base = strrchr(file, '/'))
611da2e3ebdSchin base++;
612da2e3ebdSchin else
613da2e3ebdSchin base = (char*)file;
614da2e3ebdSchin }
615da2e3ebdSchin p = base;
616da2e3ebdSchin ep->type = toupper(ep->type);
617da2e3ebdSchin break;
618da2e3ebdSchin case INFO_nlink:
619da2e3ebdSchin num = st->st_nlink;
620da2e3ebdSchin ep->type = 'N';
621da2e3ebdSchin break;
622da2e3ebdSchin case INFO_size:
623da2e3ebdSchin num = st->st_size;
624da2e3ebdSchin ep->type = 'N';
625da2e3ebdSchin break;
626da2e3ebdSchin case INFO_uid:
627da2e3ebdSchin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
628da2e3ebdSchin {
629da2e3ebdSchin p = fmtuid(st->st_uid);
630da2e3ebdSchin ep->type = toupper(ep->type);
631da2e3ebdSchin }
632da2e3ebdSchin else
633da2e3ebdSchin {
634da2e3ebdSchin num = st->st_uid;
635da2e3ebdSchin ep->type = 'N';
636da2e3ebdSchin }
637da2e3ebdSchin break;
638da2e3ebdSchin }
639da2e3ebdSchin switch (ep->type)
640da2e3ebdSchin {
641da2e3ebdSchin
642da2e3ebdSchin case 'b':
643da2e3ebdSchin if (!(p = getdata(mp, num, 1)))
644da2e3ebdSchin goto next;
645da2e3ebdSchin num = *(unsigned char*)p;
646da2e3ebdSchin break;
647da2e3ebdSchin
648da2e3ebdSchin case 'h':
649da2e3ebdSchin if (!(p = getdata(mp, num, 2)))
650da2e3ebdSchin goto next;
651da2e3ebdSchin num = swapget(ep->swap ? (~ep->swap ^ mp->swap) : mp->swap, p, 2);
652da2e3ebdSchin break;
653da2e3ebdSchin
654da2e3ebdSchin case 'd':
655da2e3ebdSchin case 'l':
656da2e3ebdSchin case 'v':
657da2e3ebdSchin if (!(p = getdata(mp, num, 4)))
658da2e3ebdSchin goto next;
659da2e3ebdSchin num = swapget(ep->swap ? (~ep->swap ^ mp->swap) : mp->swap, p, 4);
660da2e3ebdSchin break;
661da2e3ebdSchin
662da2e3ebdSchin case 'q':
663da2e3ebdSchin if (!(p = getdata(mp, num, 8)))
664da2e3ebdSchin goto next;
665da2e3ebdSchin num = swapget(ep->swap ? (~ep->swap ^ mp->swap) : mp->swap, p, 8);
666da2e3ebdSchin break;
667da2e3ebdSchin
668da2e3ebdSchin case 'e':
669da2e3ebdSchin if (!(p = getdata(mp, num, 0)))
670da2e3ebdSchin goto next;
671da2e3ebdSchin /*FALLTHROUGH*/
672da2e3ebdSchin case 'E':
673da2e3ebdSchin if (!ep->value.sub)
674da2e3ebdSchin goto next;
675da2e3ebdSchin if ((c = regexec(ep->value.sub, p, elementsof(matches), matches, 0)) || (c = regsubexec(ep->value.sub, p, elementsof(matches), matches)))
676da2e3ebdSchin {
677da2e3ebdSchin c = mp->fbsz;
678da2e3ebdSchin if (c >= sizeof(mp->nbuf))
679da2e3ebdSchin c = sizeof(mp->nbuf) - 1;
680da2e3ebdSchin p = (char*)memcpy(mp->nbuf, p, c);
681da2e3ebdSchin p[c] = 0;
682da2e3ebdSchin ccmapstr(mp->x2n, p, c);
683da2e3ebdSchin if ((c = regexec(ep->value.sub, p, elementsof(matches), matches, 0)) || (c = regsubexec(ep->value.sub, p, elementsof(matches), matches)))
684da2e3ebdSchin {
685da2e3ebdSchin if (c != REG_NOMATCH)
686da2e3ebdSchin regmessage(mp, ep->value.sub, c);
687da2e3ebdSchin goto next;
688da2e3ebdSchin }
689da2e3ebdSchin }
690da2e3ebdSchin p = ep->value.sub->re_sub->re_buf;
691da2e3ebdSchin q = T(ep->desc);
692da2e3ebdSchin t = *q ? q : p;
693da2e3ebdSchin if (mp->keep[level]++ && b > buf && *(b - 1) != ' ' && *t && *t != ',' && *t != '.' && *t != '\b')
694da2e3ebdSchin *b++ = ' ';
695da2e3ebdSchin b += sfsprintf(b, PATH_MAX - (b - buf), *q ? q : "%s", p + (*p == '\b'));
696da2e3ebdSchin if (ep->mime)
697da2e3ebdSchin mp->mime = ep->mime;
698da2e3ebdSchin goto checknest;
699da2e3ebdSchin
700da2e3ebdSchin case 's':
701da2e3ebdSchin if (!(p = getdata(mp, num, ep->mask)))
702da2e3ebdSchin goto next;
703da2e3ebdSchin goto checkstr;
704da2e3ebdSchin case 'm':
705da2e3ebdSchin if (!(p = getdata(mp, num, 0)))
706da2e3ebdSchin goto next;
707da2e3ebdSchin /*FALLTHROUGH*/
708da2e3ebdSchin case 'M':
709da2e3ebdSchin case 'S':
710da2e3ebdSchin checkstr:
711da2e3ebdSchin for (;;)
712da2e3ebdSchin {
713da2e3ebdSchin if (*ep->value.str == '*' && !*(ep->value.str + 1) && isprint(*p))
714da2e3ebdSchin break;
715da2e3ebdSchin if ((ep->type == 'm' || ep->type == 'M') ? strmatch(p, ep->value.str) : !memcmp(p, ep->value.str, ep->mask))
716da2e3ebdSchin break;
717da2e3ebdSchin if (p == mp->nbuf || ep->mask >= sizeof(mp->nbuf))
718da2e3ebdSchin goto next;
719da2e3ebdSchin p = (char*)memcpy(mp->nbuf, p, ep->mask);
720da2e3ebdSchin p[ep->mask] = 0;
721da2e3ebdSchin ccmapstr(mp->x2n, p, ep->mask);
722da2e3ebdSchin }
723da2e3ebdSchin q = T(ep->desc);
724da2e3ebdSchin if (mp->keep[level]++ && b > buf && *(b - 1) != ' ' && *q && *q != ',' && *q != '.' && *q != '\b')
725da2e3ebdSchin *b++ = ' ';
726da2e3ebdSchin for (t = p; (c = *t) >= 0 && c <= 0177 && isprint(c) && c != '\n'; t++);
727da2e3ebdSchin *t = 0;
728da2e3ebdSchin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), p);
729da2e3ebdSchin *t = c;
730da2e3ebdSchin if (ep->mime)
731da2e3ebdSchin mp->mime = ep->mime;
732da2e3ebdSchin goto checknest;
733da2e3ebdSchin
734da2e3ebdSchin }
735da2e3ebdSchin if (mask = ep->mask)
736da2e3ebdSchin num &= mask;
737da2e3ebdSchin switch (ep->op)
738da2e3ebdSchin {
739da2e3ebdSchin
740da2e3ebdSchin case '=':
741da2e3ebdSchin case '@':
742da2e3ebdSchin if (num == ep->value.num)
743da2e3ebdSchin break;
744da2e3ebdSchin if (ep->cont != '#')
745da2e3ebdSchin goto next;
746da2e3ebdSchin if (!mask)
747da2e3ebdSchin mask = ~mask;
748da2e3ebdSchin if (ep->type == 'h')
749da2e3ebdSchin {
750da2e3ebdSchin if ((num = swapget(mp->swap = 1, p, 2) & mask) == ep->value.num)
751da2e3ebdSchin {
752da2e3ebdSchin if (!(mp->swap & (mp->swap + 1)))
753da2e3ebdSchin mp->swap = 7;
754da2e3ebdSchin goto swapped;
755da2e3ebdSchin }
756da2e3ebdSchin }
757da2e3ebdSchin else if (ep->type == 'l')
758da2e3ebdSchin {
759da2e3ebdSchin for (c = 1; c < 4; c++)
760da2e3ebdSchin if ((num = swapget(mp->swap = c, p, 4) & mask) == ep->value.num)
761da2e3ebdSchin {
762da2e3ebdSchin if (!(mp->swap & (mp->swap + 1)))
763da2e3ebdSchin mp->swap = 7;
764da2e3ebdSchin goto swapped;
765da2e3ebdSchin }
766da2e3ebdSchin }
767da2e3ebdSchin else if (ep->type == 'q')
768da2e3ebdSchin {
769da2e3ebdSchin for (c = 1; c < 8; c++)
770da2e3ebdSchin if ((num = swapget(mp->swap = c, p, 8) & mask) == ep->value.num)
771da2e3ebdSchin goto swapped;
772da2e3ebdSchin }
773da2e3ebdSchin goto next;
774da2e3ebdSchin
775da2e3ebdSchin case '!':
776da2e3ebdSchin if (num != ep->value.num)
777da2e3ebdSchin break;
778da2e3ebdSchin goto next;
779da2e3ebdSchin
780da2e3ebdSchin case '^':
781da2e3ebdSchin if (num ^ ep->value.num)
782da2e3ebdSchin break;
783da2e3ebdSchin goto next;
784da2e3ebdSchin
785da2e3ebdSchin case '>':
786da2e3ebdSchin if (num > ep->value.num)
787da2e3ebdSchin break;
788da2e3ebdSchin goto next;
789da2e3ebdSchin
790da2e3ebdSchin case '<':
791da2e3ebdSchin if (num < ep->value.num)
792da2e3ebdSchin break;
793da2e3ebdSchin goto next;
794da2e3ebdSchin
795da2e3ebdSchin case 'l':
796da2e3ebdSchin if (num > 0 && mp->keep[level] && call < (MAXNEST - 1))
797da2e3ebdSchin {
798da2e3ebdSchin if (!ep->value.loop->count)
799da2e3ebdSchin {
800da2e3ebdSchin ep->value.loop->count = num;
801da2e3ebdSchin ep->value.loop->offset = off;
802da2e3ebdSchin off = ep->value.loop->start;
803da2e3ebdSchin }
804da2e3ebdSchin else if (!--ep->value.loop->count)
805da2e3ebdSchin {
806da2e3ebdSchin off = ep->value.loop->offset;
807da2e3ebdSchin goto next;
808da2e3ebdSchin }
809da2e3ebdSchin else
810da2e3ebdSchin off += ep->value.loop->size;
811da2e3ebdSchin mp->ret[++call] = ep;
812da2e3ebdSchin ep = ep->value.loop->lab;
813da2e3ebdSchin goto fun;
814da2e3ebdSchin }
815da2e3ebdSchin goto next;
816da2e3ebdSchin
817da2e3ebdSchin case 'm':
818da2e3ebdSchin c = mp->swap;
819da2e3ebdSchin t = ckmagic(mp, file, b + (b > buf), st, num);
820da2e3ebdSchin mp->swap = c;
821da2e3ebdSchin if (!t)
822da2e3ebdSchin goto next;
823da2e3ebdSchin if (b > buf)
824da2e3ebdSchin *b = ' ';
825da2e3ebdSchin b += strlen(b);
826da2e3ebdSchin break;
827da2e3ebdSchin
828da2e3ebdSchin case 'r':
829da2e3ebdSchin #if _UWIN
830da2e3ebdSchin {
831da2e3ebdSchin char* e;
832da2e3ebdSchin Sfio_t* rp;
833da2e3ebdSchin Sfio_t* gp;
834da2e3ebdSchin
835da2e3ebdSchin if (!(t = strrchr(file, '.')))
836da2e3ebdSchin goto next;
837da2e3ebdSchin sfprintf(mp->tmp, "/reg/classes_root/%s", t);
838da2e3ebdSchin if (!(t = sfstruse(mp->tmp)) || !(rp = sfopen(NiL, t, "r")))
839da2e3ebdSchin goto next;
840da2e3ebdSchin *ep->desc = 0;
841da2e3ebdSchin *ep->mime = 0;
842da2e3ebdSchin gp = 0;
843da2e3ebdSchin while (t = sfgetr(rp, '\n', 1))
844da2e3ebdSchin {
845da2e3ebdSchin if (strneq(t, "Content Type=", 13))
846da2e3ebdSchin {
847da2e3ebdSchin ep->mime = vmnewof(mp->vm, ep->mime, char, sfvalue(rp), 0);
848da2e3ebdSchin strcpy(ep->mime, t + 13);
849da2e3ebdSchin if (gp)
850da2e3ebdSchin break;
851da2e3ebdSchin }
852da2e3ebdSchin else
853da2e3ebdSchin {
854da2e3ebdSchin sfprintf(mp->tmp, "/reg/classes_root/%s", t);
855da2e3ebdSchin if ((e = sfstruse(mp->tmp)) && (gp = sfopen(NiL, e, "r")))
856da2e3ebdSchin {
857da2e3ebdSchin ep->desc = vmnewof(mp->vm, ep->desc, char, strlen(t), 1);
858da2e3ebdSchin strcpy(ep->desc, t);
859da2e3ebdSchin if (*ep->mime)
860da2e3ebdSchin break;
861da2e3ebdSchin }
862da2e3ebdSchin }
863da2e3ebdSchin }
864da2e3ebdSchin sfclose(rp);
865da2e3ebdSchin if (!gp)
866da2e3ebdSchin goto next;
867da2e3ebdSchin if (!*ep->mime)
868da2e3ebdSchin {
869da2e3ebdSchin t = T(ep->desc);
870da2e3ebdSchin if (!strncasecmp(t, "microsoft", 9))
871da2e3ebdSchin t += 9;
872da2e3ebdSchin while (isspace(*t))
873da2e3ebdSchin t++;
874da2e3ebdSchin e = "application/x-ms-";
875da2e3ebdSchin ep->mime = vmnewof(mp->vm, ep->mime, char, strlen(t), strlen(e));
876da2e3ebdSchin e = strcopy(ep->mime, e);
877da2e3ebdSchin while ((c = *t++) && c != '.' && c != ' ')
878da2e3ebdSchin *e++ = isupper(c) ? tolower(c) : c;
879da2e3ebdSchin *e = 0;
880da2e3ebdSchin }
881da2e3ebdSchin while (t = sfgetr(gp, '\n', 1))
882da2e3ebdSchin if (*t && !streq(t, "\"\""))
883da2e3ebdSchin {
884da2e3ebdSchin ep->desc = vmnewof(mp->vm, ep->desc, char, sfvalue(gp), 0);
885da2e3ebdSchin strcpy(ep->desc, t);
886da2e3ebdSchin break;
887da2e3ebdSchin }
888da2e3ebdSchin sfclose(gp);
889da2e3ebdSchin if (!*ep->desc)
890da2e3ebdSchin goto next;
891da2e3ebdSchin if (!t)
892da2e3ebdSchin for (t = T(ep->desc); *t; t++)
893da2e3ebdSchin if (*t == '.')
894da2e3ebdSchin *t = ' ';
895da2e3ebdSchin if (!mp->keep[level])
896da2e3ebdSchin mp->keep[level] = 2;
897da2e3ebdSchin mp->mime = ep->mime;
898da2e3ebdSchin break;
899da2e3ebdSchin }
900da2e3ebdSchin #else
901da2e3ebdSchin if (ep->cont == '#' && !mp->keep[level])
902da2e3ebdSchin mp->keep[level] = 1;
903da2e3ebdSchin goto next;
904da2e3ebdSchin #endif
905da2e3ebdSchin
906da2e3ebdSchin case 'v':
907da2e3ebdSchin if (!(p = getdata(mp, num, 4)))
908da2e3ebdSchin goto next;
909da2e3ebdSchin c = 0;
910da2e3ebdSchin do
911da2e3ebdSchin {
912da2e3ebdSchin num++;
913da2e3ebdSchin c = (c<<7) | (*p & 0x7f);
914da2e3ebdSchin } while (*p++ & 0x80);
915da2e3ebdSchin if (!(p = getdata(mp, num, c)))
916da2e3ebdSchin goto next;
917da2e3ebdSchin if (mp->keep[level]++ && b > buf && *(b - 1) != ' ')
918da2e3ebdSchin {
919da2e3ebdSchin *b++ = ',';
920da2e3ebdSchin *b++ = ' ';
921da2e3ebdSchin }
922da2e3ebdSchin b = vcdecomp(b, buf + PATH_MAX, (unsigned char*)p, (unsigned char*)p + c);
923da2e3ebdSchin goto checknest;
924da2e3ebdSchin
925da2e3ebdSchin }
926da2e3ebdSchin swapped:
927da2e3ebdSchin q = T(ep->desc);
928da2e3ebdSchin if (mp->keep[level]++ && b > buf && *(b - 1) != ' ' && *q && *q != ',' && *q != '.' && *q != '\b')
929da2e3ebdSchin *b++ = ' ';
930da2e3ebdSchin if (ep->type == 'd' || ep->type == 'D')
931da2e3ebdSchin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), fmttime("%?%l", (time_t)num));
932da2e3ebdSchin else if (ep->type == 'v')
933da2e3ebdSchin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), fmtversion(num));
934da2e3ebdSchin else
935da2e3ebdSchin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), num);
936da2e3ebdSchin if (ep->mime && *ep->mime)
937da2e3ebdSchin mp->mime = ep->mime;
938da2e3ebdSchin checknest:
939da2e3ebdSchin if (ep->nest == '}')
940da2e3ebdSchin {
941da2e3ebdSchin if (!mp->keep[level])
942da2e3ebdSchin {
943da2e3ebdSchin b = mp->msg[level];
944da2e3ebdSchin mp->mime = mp->cap[level];
945da2e3ebdSchin }
946da2e3ebdSchin else if (level > 0)
947da2e3ebdSchin mp->keep[level - 1] = mp->keep[level];
948da2e3ebdSchin if (--level < 0)
949da2e3ebdSchin {
950da2e3ebdSchin level = 0;
951da2e3ebdSchin mp->keep[0] = 0;
952da2e3ebdSchin }
953da2e3ebdSchin }
954da2e3ebdSchin continue;
955da2e3ebdSchin next:
956da2e3ebdSchin if (ep->cont == '&')
957da2e3ebdSchin mp->keep[level] = 0;
958da2e3ebdSchin goto checknest;
959da2e3ebdSchin }
960da2e3ebdSchin if (mp->keep[level] && b > buf)
961da2e3ebdSchin {
962da2e3ebdSchin *b = 0;
963da2e3ebdSchin return buf;
964da2e3ebdSchin }
965da2e3ebdSchin return 0;
966da2e3ebdSchin }
967da2e3ebdSchin
968da2e3ebdSchin /*
969da2e3ebdSchin * check english language stats
970da2e3ebdSchin */
971da2e3ebdSchin
972da2e3ebdSchin static int
ckenglish(register Magic_t * mp,int pun,int badpun)973da2e3ebdSchin ckenglish(register Magic_t* mp, int pun, int badpun)
974da2e3ebdSchin {
975da2e3ebdSchin register char* s;
976da2e3ebdSchin register int vowl = 0;
977da2e3ebdSchin register int freq = 0;
978da2e3ebdSchin register int rare = 0;
979da2e3ebdSchin
980da2e3ebdSchin if (5 * badpun > pun)
981da2e3ebdSchin return 0;
982da2e3ebdSchin if (2 * mp->count[';'] > mp->count['E'] + mp->count['e'])
983da2e3ebdSchin return 0;
984da2e3ebdSchin if ((mp->count['>'] + mp->count['<'] + mp->count['/']) > mp->count['E'] + mp->count['e'])
985da2e3ebdSchin return 0;
986da2e3ebdSchin for (s = "aeiou"; *s; s++)
987da2e3ebdSchin vowl += mp->count[toupper(*s)] + mp->count[*s];
988da2e3ebdSchin for (s = "etaion"; *s; s++)
989da2e3ebdSchin freq += mp->count[toupper(*s)] + mp->count[*s];
990da2e3ebdSchin for (s = "vjkqxz"; *s; s++)
991da2e3ebdSchin rare += mp->count[toupper(*s)] + mp->count[*s];
992da2e3ebdSchin return 5 * vowl >= mp->fbsz - mp->count[' '] && freq >= 10 * rare;
993da2e3ebdSchin }
994da2e3ebdSchin
995da2e3ebdSchin /*
996da2e3ebdSchin * check programming language stats
997da2e3ebdSchin */
998da2e3ebdSchin
999da2e3ebdSchin static char*
cklang(register Magic_t * mp,const char * file,char * buf,struct stat * st)1000da2e3ebdSchin cklang(register Magic_t* mp, const char* file, char* buf, struct stat* st)
1001da2e3ebdSchin {
1002da2e3ebdSchin register int c;
1003da2e3ebdSchin register unsigned char* b;
1004da2e3ebdSchin register unsigned char* e;
1005da2e3ebdSchin register int q;
1006da2e3ebdSchin register char* s;
1007da2e3ebdSchin char* t;
1008da2e3ebdSchin char* base;
1009da2e3ebdSchin char* suff;
1010da2e3ebdSchin char* t1;
1011da2e3ebdSchin char* t2;
1012da2e3ebdSchin char* t3;
1013da2e3ebdSchin int n;
1014da2e3ebdSchin int badpun;
1015da2e3ebdSchin int code;
1016da2e3ebdSchin int pun;
1017da2e3ebdSchin Cctype_t flags;
1018da2e3ebdSchin Info_t* ip;
1019da2e3ebdSchin
1020da2e3ebdSchin b = (unsigned char*)mp->fbuf;
1021da2e3ebdSchin e = b + mp->fbsz;
1022da2e3ebdSchin memzero(mp->count, sizeof(mp->count));
1023da2e3ebdSchin memzero(mp->multi, sizeof(mp->multi));
1024da2e3ebdSchin memzero(mp->identifier, sizeof(mp->identifier));
1025da2e3ebdSchin
1026da2e3ebdSchin /*
1027da2e3ebdSchin * check character coding
1028da2e3ebdSchin */
1029da2e3ebdSchin
1030da2e3ebdSchin flags = 0;
1031da2e3ebdSchin while (b < e)
1032da2e3ebdSchin flags |= mp->cctype[*b++];
1033da2e3ebdSchin b = (unsigned char*)mp->fbuf;
1034da2e3ebdSchin code = 0;
1035da2e3ebdSchin q = CC_ASCII;
1036da2e3ebdSchin n = CC_MASK;
1037da2e3ebdSchin for (c = 0; c < CC_MAPS; c++)
1038da2e3ebdSchin {
1039da2e3ebdSchin flags ^= CC_text;
1040da2e3ebdSchin if ((flags & CC_MASK) < n)
1041da2e3ebdSchin {
1042da2e3ebdSchin n = flags & CC_MASK;
1043da2e3ebdSchin q = c;
1044da2e3ebdSchin }
1045da2e3ebdSchin flags >>= CC_BIT;
1046da2e3ebdSchin }
1047da2e3ebdSchin flags = n;
1048da2e3ebdSchin if (!(flags & (CC_binary|CC_notext)))
1049da2e3ebdSchin {
1050da2e3ebdSchin if (q != CC_NATIVE)
1051da2e3ebdSchin {
1052da2e3ebdSchin code = q;
1053da2e3ebdSchin ccmaps(mp->fbuf, mp->fbsz, q, CC_NATIVE);
1054da2e3ebdSchin }
1055da2e3ebdSchin if (b[0] == '#' && b[1] == '!')
1056da2e3ebdSchin {
1057da2e3ebdSchin for (b += 2; b < e && isspace(*b); b++);
1058da2e3ebdSchin for (s = (char*)b; b < e && isprint(*b); b++);
1059da2e3ebdSchin c = *b;
1060da2e3ebdSchin *b = 0;
1061da2e3ebdSchin if ((st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) || match(s, "/*bin*/*") || !access(s, F_OK))
1062da2e3ebdSchin {
1063da2e3ebdSchin if (t = strrchr(s, '/'))
1064da2e3ebdSchin s = t + 1;
1065da2e3ebdSchin for (t = s; *t; t++)
1066da2e3ebdSchin if (isspace(*t))
1067da2e3ebdSchin {
1068da2e3ebdSchin *t = 0;
1069da2e3ebdSchin break;
1070da2e3ebdSchin }
1071da2e3ebdSchin sfsprintf(mp->mbuf, sizeof(mp->mbuf), "application/x-%s", *s ? s : "sh");
1072da2e3ebdSchin mp->mime = mp->mbuf;
1073da2e3ebdSchin if (match(s, "*sh"))
1074da2e3ebdSchin {
1075da2e3ebdSchin t1 = T("command");
1076da2e3ebdSchin if (streq(s, "sh"))
1077da2e3ebdSchin *s = 0;
1078da2e3ebdSchin else
1079da2e3ebdSchin {
1080da2e3ebdSchin *b++ = ' ';
1081da2e3ebdSchin *b = 0;
1082da2e3ebdSchin }
1083da2e3ebdSchin }
1084da2e3ebdSchin else
1085da2e3ebdSchin {
1086da2e3ebdSchin t1 = T("interpreter");
1087da2e3ebdSchin *b++ = ' ';
1088da2e3ebdSchin *b = 0;
1089da2e3ebdSchin }
1090da2e3ebdSchin sfsprintf(mp->sbuf, sizeof(mp->sbuf), T("%s%s script"), s, t1);
1091da2e3ebdSchin s = mp->sbuf;
1092da2e3ebdSchin goto qualify;
1093da2e3ebdSchin }
1094da2e3ebdSchin *b = c;
1095da2e3ebdSchin b = (unsigned char*)mp->fbuf;
1096da2e3ebdSchin }
1097da2e3ebdSchin badpun = 0;
1098da2e3ebdSchin pun = 0;
1099da2e3ebdSchin q = 0;
1100da2e3ebdSchin s = 0;
1101da2e3ebdSchin t = 0;
1102da2e3ebdSchin while (b < e)
1103da2e3ebdSchin {
1104da2e3ebdSchin c = *b++;
1105da2e3ebdSchin mp->count[c]++;
1106da2e3ebdSchin if (c == q && (q != '*' || *b == '/' && b++))
1107da2e3ebdSchin {
1108da2e3ebdSchin mp->multi[q]++;
1109da2e3ebdSchin q = 0;
1110da2e3ebdSchin }
1111da2e3ebdSchin else if (c == '\\')
1112da2e3ebdSchin {
1113da2e3ebdSchin s = 0;
1114da2e3ebdSchin b++;
1115da2e3ebdSchin }
1116da2e3ebdSchin else if (!q)
1117da2e3ebdSchin {
1118da2e3ebdSchin if (isalpha(c) || c == '_')
1119da2e3ebdSchin {
1120da2e3ebdSchin if (!s)
1121da2e3ebdSchin s = (char*)b - 1;
1122da2e3ebdSchin }
1123da2e3ebdSchin else if (!isdigit(c))
1124da2e3ebdSchin {
1125da2e3ebdSchin if (s)
1126da2e3ebdSchin {
1127da2e3ebdSchin if (s > mp->fbuf)
1128da2e3ebdSchin switch (*(s - 1))
1129da2e3ebdSchin {
1130da2e3ebdSchin case ':':
1131da2e3ebdSchin if (*b == ':')
1132da2e3ebdSchin mp->multi[':']++;
1133da2e3ebdSchin break;
1134da2e3ebdSchin case '.':
1135da2e3ebdSchin if (((char*)b - s) == 3 && (s == (mp->fbuf + 1) || *(s - 2) == '\n'))
1136da2e3ebdSchin mp->multi['.']++;
1137da2e3ebdSchin break;
1138da2e3ebdSchin case '\n':
1139da2e3ebdSchin case '\\':
1140da2e3ebdSchin if (*b == '{')
1141da2e3ebdSchin t = (char*)b + 1;
1142da2e3ebdSchin break;
1143da2e3ebdSchin case '{':
1144da2e3ebdSchin if (s == t && *b == '}')
1145da2e3ebdSchin mp->multi['X']++;
1146da2e3ebdSchin break;
1147da2e3ebdSchin }
1148da2e3ebdSchin if (!mp->idtab)
1149da2e3ebdSchin {
1150da2e3ebdSchin if (mp->idtab = dtnew(mp->vm, &mp->dtdisc, Dthash))
1151da2e3ebdSchin for (q = 0; q < elementsof(dict); q++)
1152da2e3ebdSchin dtinsert(mp->idtab, &dict[q]);
1153da2e3ebdSchin else if (mp->disc->errorf)
1154da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 3, "out of space");
1155da2e3ebdSchin q = 0;
1156da2e3ebdSchin }
1157da2e3ebdSchin if (mp->idtab)
1158da2e3ebdSchin {
1159da2e3ebdSchin *(b - 1) = 0;
1160da2e3ebdSchin if (ip = (Info_t*)dtmatch(mp->idtab, s))
1161da2e3ebdSchin mp->identifier[ip->value]++;
1162da2e3ebdSchin *(b - 1) = c;
1163da2e3ebdSchin }
1164da2e3ebdSchin s = 0;
1165da2e3ebdSchin }
1166da2e3ebdSchin switch (c)
1167da2e3ebdSchin {
1168da2e3ebdSchin case '\t':
1169da2e3ebdSchin if (b == (unsigned char*)(mp->fbuf + 1) || *(b - 2) == '\n')
1170da2e3ebdSchin mp->multi['\t']++;
1171da2e3ebdSchin break;
1172da2e3ebdSchin case '"':
1173da2e3ebdSchin case '\'':
1174da2e3ebdSchin q = c;
1175da2e3ebdSchin break;
1176da2e3ebdSchin case '/':
1177da2e3ebdSchin if (*b == '*')
1178da2e3ebdSchin q = *b++;
1179da2e3ebdSchin else if (*b == '/')
1180da2e3ebdSchin q = '\n';
1181da2e3ebdSchin break;
1182da2e3ebdSchin case '$':
1183da2e3ebdSchin if (*b == '(' && *(b + 1) != ' ')
1184da2e3ebdSchin mp->multi['$']++;
1185da2e3ebdSchin break;
1186da2e3ebdSchin case '{':
1187da2e3ebdSchin case '}':
1188da2e3ebdSchin case '[':
1189da2e3ebdSchin case ']':
1190da2e3ebdSchin case '(':
1191da2e3ebdSchin mp->multi[c]++;
1192da2e3ebdSchin break;
1193da2e3ebdSchin case ')':
1194da2e3ebdSchin mp->multi[c]++;
1195da2e3ebdSchin goto punctuation;
1196da2e3ebdSchin case ':':
1197da2e3ebdSchin if (*b == ':' && isspace(*(b + 1)) && b > (unsigned char*)(mp->fbuf + 1) && isspace(*(b - 2)))
1198da2e3ebdSchin mp->multi[':']++;
1199da2e3ebdSchin goto punctuation;
1200da2e3ebdSchin case '.':
1201da2e3ebdSchin case ',':
1202da2e3ebdSchin case '%':
1203da2e3ebdSchin case ';':
1204da2e3ebdSchin case '?':
1205da2e3ebdSchin punctuation:
1206da2e3ebdSchin pun++;
1207da2e3ebdSchin if (*b != ' ' && *b != '\n')
1208da2e3ebdSchin badpun++;
1209da2e3ebdSchin break;
1210da2e3ebdSchin }
1211da2e3ebdSchin }
1212da2e3ebdSchin }
1213da2e3ebdSchin }
1214da2e3ebdSchin }
1215da2e3ebdSchin else
1216da2e3ebdSchin while (b < e)
1217da2e3ebdSchin mp->count[*b++]++;
1218da2e3ebdSchin base = (t1 = strrchr(file, '/')) ? t1 + 1 : (char*)file;
1219da2e3ebdSchin suff = (t1 = strrchr(base, '.')) ? t1 + 1 : "";
1220da2e3ebdSchin if (!flags)
1221da2e3ebdSchin {
1222da2e3ebdSchin if (match(suff, "*sh|bat|cmd"))
1223da2e3ebdSchin goto id_sh;
1224da2e3ebdSchin if (match(base, "*@(mkfile)"))
1225da2e3ebdSchin goto id_mk;
1226da2e3ebdSchin if (match(base, "*@(makefile|.mk)"))
1227da2e3ebdSchin goto id_make;
1228da2e3ebdSchin if (match(base, "*@(mamfile|.mam)"))
1229da2e3ebdSchin goto id_mam;
1230da2e3ebdSchin if (match(suff, "[cly]?(pp|xx|++)|cc|ll|yy"))
1231da2e3ebdSchin goto id_c;
1232da2e3ebdSchin if (match(suff, "f"))
1233da2e3ebdSchin goto id_fortran;
1234da2e3ebdSchin if (match(suff, "htm+(l)"))
1235da2e3ebdSchin goto id_html;
1236da2e3ebdSchin if (match(suff, "cpy"))
1237da2e3ebdSchin goto id_copybook;
1238da2e3ebdSchin if (match(suff, "cob|cbl|cb2"))
1239da2e3ebdSchin goto id_cobol;
1240da2e3ebdSchin if (match(suff, "pl[1i]"))
1241da2e3ebdSchin goto id_pl1;
1242da2e3ebdSchin if (match(suff, "tex"))
1243da2e3ebdSchin goto id_tex;
1244da2e3ebdSchin if (match(suff, "asm|s"))
1245da2e3ebdSchin goto id_asm;
1246da2e3ebdSchin if ((st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) && (!suff || suff != strchr(suff, '.')))
1247da2e3ebdSchin {
1248da2e3ebdSchin id_sh:
1249da2e3ebdSchin s = T("command script");
1250da2e3ebdSchin mp->mime = "application/sh";
1251da2e3ebdSchin goto qualify;
1252da2e3ebdSchin }
1253da2e3ebdSchin if (strmatch(mp->fbuf, "From * [0-9][0-9]:[0-9][0-9]:[0-9][0-9] *"))
1254da2e3ebdSchin {
1255da2e3ebdSchin s = T("mail message");
1256da2e3ebdSchin mp->mime = "message/rfc822";
1257da2e3ebdSchin goto qualify;
1258da2e3ebdSchin }
1259da2e3ebdSchin if (match(base, "*@(mkfile)"))
1260da2e3ebdSchin {
1261da2e3ebdSchin id_mk:
1262da2e3ebdSchin s = "mkfile";
1263da2e3ebdSchin mp->mime = "application/mk";
1264da2e3ebdSchin goto qualify;
1265da2e3ebdSchin }
1266da2e3ebdSchin if (match(base, "*@(makefile|.mk)") || mp->multi['\t'] >= mp->count[':'] && (mp->multi['$'] > 0 || mp->multi[':'] > 0))
1267da2e3ebdSchin {
1268da2e3ebdSchin id_make:
1269da2e3ebdSchin s = "makefile";
1270da2e3ebdSchin mp->mime = "application/make";
1271da2e3ebdSchin goto qualify;
1272da2e3ebdSchin }
1273da2e3ebdSchin if (mp->multi['.'] >= 3)
1274da2e3ebdSchin {
1275da2e3ebdSchin s = T("nroff input");
1276da2e3ebdSchin mp->mime = "application/x-troff";
1277da2e3ebdSchin goto qualify;
1278da2e3ebdSchin }
1279da2e3ebdSchin if (mp->multi['X'] >= 3)
1280da2e3ebdSchin {
1281da2e3ebdSchin s = T("TeX input");
1282da2e3ebdSchin mp->mime = "application/x-tex";
1283da2e3ebdSchin goto qualify;
1284da2e3ebdSchin }
1285da2e3ebdSchin if (mp->fbsz < SF_BUFSIZE &&
1286da2e3ebdSchin (mp->multi['('] == mp->multi[')'] &&
1287da2e3ebdSchin mp->multi['{'] == mp->multi['}'] &&
1288da2e3ebdSchin mp->multi['['] == mp->multi[']']) ||
1289da2e3ebdSchin mp->fbsz >= SF_BUFSIZE &&
1290da2e3ebdSchin (mp->multi['('] >= mp->multi[')'] &&
1291da2e3ebdSchin mp->multi['{'] >= mp->multi['}'] &&
1292da2e3ebdSchin mp->multi['['] >= mp->multi[']']))
1293da2e3ebdSchin {
1294da2e3ebdSchin c = mp->identifier[ID_INCL1];
1295da2e3ebdSchin if (c >= 2 && mp->identifier[ID_INCL2] >= c && mp->identifier[ID_INCL3] >= c && mp->count['.'] >= c ||
1296da2e3ebdSchin mp->identifier[ID_C] >= 5 && mp->count[';'] >= 5 ||
1297da2e3ebdSchin mp->count['='] >= 20 && mp->count[';'] >= 20)
1298da2e3ebdSchin {
1299da2e3ebdSchin id_c:
1300da2e3ebdSchin t1 = "";
1301da2e3ebdSchin t2 = "c ";
1302da2e3ebdSchin t3 = T("program");
1303da2e3ebdSchin switch (*suff)
1304da2e3ebdSchin {
1305da2e3ebdSchin case 'c':
1306da2e3ebdSchin case 'C':
1307da2e3ebdSchin mp->mime = "application/x-cc";
1308da2e3ebdSchin break;
1309da2e3ebdSchin case 'l':
1310da2e3ebdSchin case 'L':
1311da2e3ebdSchin t1 = "lex ";
1312da2e3ebdSchin mp->mime = "application/x-lex";
1313da2e3ebdSchin break;
1314da2e3ebdSchin default:
1315da2e3ebdSchin t3 = T("header");
1316da2e3ebdSchin if (mp->identifier[ID_YACC] < 5 || mp->count['%'] < 5)
1317da2e3ebdSchin {
1318da2e3ebdSchin mp->mime = "application/x-cc";
1319da2e3ebdSchin break;
1320da2e3ebdSchin }
1321da2e3ebdSchin /*FALLTHROUGH*/
1322da2e3ebdSchin case 'y':
1323da2e3ebdSchin case 'Y':
1324da2e3ebdSchin t1 = "yacc ";
1325da2e3ebdSchin mp->mime = "application/x-yacc";
1326da2e3ebdSchin break;
1327da2e3ebdSchin }
1328da2e3ebdSchin if (mp->identifier[ID_CPLUSPLUS] >= 3)
1329da2e3ebdSchin {
1330da2e3ebdSchin t2 = "c++ ";
1331da2e3ebdSchin mp->mime = "application/x-c++";
1332da2e3ebdSchin }
1333da2e3ebdSchin sfsprintf(mp->sbuf, sizeof(mp->sbuf), "%s%s%s", t1, t2, t3);
1334da2e3ebdSchin s = mp->sbuf;
1335da2e3ebdSchin goto qualify;
1336da2e3ebdSchin }
1337da2e3ebdSchin }
1338da2e3ebdSchin if (mp->identifier[ID_MAM1] >= 2 && mp->identifier[ID_MAM3] >= 2 &&
1339da2e3ebdSchin (mp->fbsz < SF_BUFSIZE && mp->identifier[ID_MAM1] == mp->identifier[ID_MAM2] ||
1340da2e3ebdSchin mp->fbsz >= SF_BUFSIZE && mp->identifier[ID_MAM1] >= mp->identifier[ID_MAM2]))
1341da2e3ebdSchin {
1342da2e3ebdSchin id_mam:
1343da2e3ebdSchin s = T("mam program");
1344da2e3ebdSchin mp->mime = "application/x-mam";
1345da2e3ebdSchin goto qualify;
1346da2e3ebdSchin }
1347da2e3ebdSchin if (mp->identifier[ID_FORTRAN] >= 8)
1348da2e3ebdSchin {
1349da2e3ebdSchin id_fortran:
1350da2e3ebdSchin s = T("fortran program");
1351da2e3ebdSchin mp->mime = "application/x-fortran";
1352da2e3ebdSchin goto qualify;
1353da2e3ebdSchin }
1354da2e3ebdSchin if (mp->identifier[ID_HTML] > 0 && mp->count['<'] >= 8 && (c = mp->count['<'] - mp->count['>']) >= -2 && c <= 2)
1355da2e3ebdSchin {
1356da2e3ebdSchin id_html:
1357da2e3ebdSchin s = T("html input");
1358da2e3ebdSchin mp->mime = "text/html";
1359da2e3ebdSchin goto qualify;
1360da2e3ebdSchin }
1361da2e3ebdSchin if (mp->identifier[ID_COPYBOOK] > 0 && mp->identifier[ID_COBOL] == 0 && (c = mp->count['('] - mp->count[')']) >= -2 && c <= 2)
1362da2e3ebdSchin {
1363da2e3ebdSchin id_copybook:
1364da2e3ebdSchin s = T("cobol copybook");
1365da2e3ebdSchin mp->mime = "application/x-cobol";
1366da2e3ebdSchin goto qualify;
1367da2e3ebdSchin }
1368da2e3ebdSchin if (mp->identifier[ID_COBOL] > 0 && mp->identifier[ID_COPYBOOK] > 0 && (c = mp->count['('] - mp->count[')']) >= -2 && c <= 2)
1369da2e3ebdSchin {
1370da2e3ebdSchin id_cobol:
1371da2e3ebdSchin s = T("cobol program");
1372da2e3ebdSchin mp->mime = "application/x-cobol";
1373da2e3ebdSchin goto qualify;
1374da2e3ebdSchin }
1375da2e3ebdSchin if (mp->identifier[ID_PL1] > 0 && (c = mp->count['('] - mp->count[')']) >= -2 && c <= 2)
1376da2e3ebdSchin {
1377da2e3ebdSchin id_pl1:
1378da2e3ebdSchin s = T("pl1 program");
1379da2e3ebdSchin mp->mime = "application/x-pl1";
1380da2e3ebdSchin goto qualify;
1381da2e3ebdSchin }
1382da2e3ebdSchin if (mp->count['{'] >= 6 && (c = mp->count['{'] - mp->count['}']) >= -2 && c <= 2 && mp->count['\\'] >= mp->count['{'])
1383da2e3ebdSchin {
1384da2e3ebdSchin id_tex:
1385da2e3ebdSchin s = T("TeX input");
1386da2e3ebdSchin mp->mime = "text/tex";
1387da2e3ebdSchin goto qualify;
1388da2e3ebdSchin }
1389da2e3ebdSchin if (mp->identifier[ID_ASM] >= 4)
1390da2e3ebdSchin {
1391da2e3ebdSchin id_asm:
1392da2e3ebdSchin s = T("as program");
1393da2e3ebdSchin mp->mime = "application/x-as";
1394da2e3ebdSchin goto qualify;
1395da2e3ebdSchin }
1396da2e3ebdSchin if (ckenglish(mp, pun, badpun))
1397da2e3ebdSchin {
1398da2e3ebdSchin s = T("english text");
1399da2e3ebdSchin mp->mime = "text/plain";
1400da2e3ebdSchin goto qualify;
1401da2e3ebdSchin }
1402da2e3ebdSchin }
1403da2e3ebdSchin else if (streq(base, "core"))
1404da2e3ebdSchin {
1405da2e3ebdSchin mp->mime = "x-system/core";
1406da2e3ebdSchin return T("core dump");
1407da2e3ebdSchin }
1408da2e3ebdSchin if (flags & (CC_binary|CC_notext))
1409da2e3ebdSchin {
1410da2e3ebdSchin b = (unsigned char*)mp->fbuf;
1411da2e3ebdSchin e = b + mp->fbsz;
1412da2e3ebdSchin n = 0;
1413da2e3ebdSchin for (;;)
1414da2e3ebdSchin {
1415da2e3ebdSchin c = *b++;
1416da2e3ebdSchin q = 0;
1417da2e3ebdSchin while (c & 0x80)
1418da2e3ebdSchin {
1419da2e3ebdSchin c <<= 1;
1420da2e3ebdSchin q++;
1421da2e3ebdSchin }
1422da2e3ebdSchin switch (q)
1423da2e3ebdSchin {
1424da2e3ebdSchin case 4:
1425da2e3ebdSchin if (b < e && (*b++ & 0xc0) != 0x80)
1426da2e3ebdSchin break;
1427da2e3ebdSchin case 3:
1428da2e3ebdSchin if (b < e && (*b++ & 0xc0) != 0x80)
1429da2e3ebdSchin break;
1430da2e3ebdSchin case 2:
1431da2e3ebdSchin if (b < e && (*b++ & 0xc0) != 0x80)
1432da2e3ebdSchin break;
1433da2e3ebdSchin n = 1;
1434da2e3ebdSchin case 0:
1435da2e3ebdSchin if (b >= e)
1436da2e3ebdSchin {
1437da2e3ebdSchin if (n)
1438da2e3ebdSchin {
1439da2e3ebdSchin flags &= ~(CC_binary|CC_notext);
1440da2e3ebdSchin flags |= CC_utf_8;
1441da2e3ebdSchin }
1442da2e3ebdSchin break;
1443da2e3ebdSchin }
1444da2e3ebdSchin continue;
1445da2e3ebdSchin }
1446da2e3ebdSchin break;
1447da2e3ebdSchin }
1448da2e3ebdSchin }
1449da2e3ebdSchin if (flags & (CC_binary|CC_notext))
1450da2e3ebdSchin {
1451da2e3ebdSchin unsigned long d = 0;
1452da2e3ebdSchin
1453da2e3ebdSchin if ((q = mp->fbsz / UCHAR_MAX) >= 2)
1454da2e3ebdSchin {
1455da2e3ebdSchin /*
1456da2e3ebdSchin * compression/encryption via standard deviation
1457da2e3ebdSchin */
1458da2e3ebdSchin
1459da2e3ebdSchin
1460da2e3ebdSchin for (c = 0; c < UCHAR_MAX; c++)
1461da2e3ebdSchin {
1462da2e3ebdSchin pun = mp->count[c] - q;
1463da2e3ebdSchin d += pun * pun;
1464da2e3ebdSchin }
1465da2e3ebdSchin d /= mp->fbsz;
1466da2e3ebdSchin }
1467da2e3ebdSchin if (d <= 0)
1468da2e3ebdSchin s = T("binary");
1469da2e3ebdSchin else if (d < 4)
1470da2e3ebdSchin s = T("encrypted");
1471da2e3ebdSchin else if (d < 16)
1472da2e3ebdSchin s = T("packed");
1473da2e3ebdSchin else if (d < 64)
1474da2e3ebdSchin s = T("compressed");
1475da2e3ebdSchin else if (d < 256)
1476da2e3ebdSchin s = T("delta");
1477da2e3ebdSchin else
1478da2e3ebdSchin s = T("data");
1479da2e3ebdSchin mp->mime = "application/octet-stream";
1480da2e3ebdSchin return s;
1481da2e3ebdSchin }
1482da2e3ebdSchin mp->mime = "text/plain";
1483da2e3ebdSchin if (flags & CC_utf_8)
1484da2e3ebdSchin s = (flags & CC_control) ? T("utf-8 text with control characters") : T("utf-8 text");
1485da2e3ebdSchin else if (flags & CC_latin)
1486da2e3ebdSchin s = (flags & CC_control) ? T("latin text with control characters") : T("latin text");
1487da2e3ebdSchin else
1488da2e3ebdSchin s = (flags & CC_control) ? T("text with control characters") : T("text");
1489da2e3ebdSchin qualify:
1490da2e3ebdSchin if (!flags && mp->count['\n'] >= mp->count['\r'] && mp->count['\n'] <= (mp->count['\r'] + 1) && mp->count['\r'])
1491da2e3ebdSchin {
1492da2e3ebdSchin t = "dos ";
1493da2e3ebdSchin mp->mime = "text/dos";
1494da2e3ebdSchin }
1495da2e3ebdSchin else
1496da2e3ebdSchin t = "";
1497da2e3ebdSchin if (code)
1498da2e3ebdSchin {
1499da2e3ebdSchin if (code == CC_ASCII)
1500da2e3ebdSchin sfsprintf(buf, PATH_MAX, "ascii %s%s", t, s);
1501da2e3ebdSchin else
1502da2e3ebdSchin {
1503da2e3ebdSchin sfsprintf(buf, PATH_MAX, "ebcdic%d %s%s", code - 1, t, s);
1504da2e3ebdSchin mp->mime = "text/ebcdic";
1505da2e3ebdSchin }
1506da2e3ebdSchin s = buf;
1507da2e3ebdSchin }
1508da2e3ebdSchin else if (*t)
1509da2e3ebdSchin {
1510da2e3ebdSchin sfsprintf(buf, PATH_MAX, "%s%s", t, s);
1511da2e3ebdSchin s = buf;
1512da2e3ebdSchin }
1513da2e3ebdSchin return s;
1514da2e3ebdSchin }
1515da2e3ebdSchin
1516da2e3ebdSchin /*
1517da2e3ebdSchin * return the basic magic string for file,st in buf,size
1518da2e3ebdSchin */
1519da2e3ebdSchin
1520da2e3ebdSchin static char*
type(register Magic_t * mp,const char * file,struct stat * st,char * buf,int size)1521da2e3ebdSchin type(register Magic_t* mp, const char* file, struct stat* st, char* buf, int size)
1522da2e3ebdSchin {
1523da2e3ebdSchin register char* s;
1524da2e3ebdSchin register char* t;
1525da2e3ebdSchin
1526da2e3ebdSchin mp->mime = 0;
1527da2e3ebdSchin if (!S_ISREG(st->st_mode))
1528da2e3ebdSchin {
1529da2e3ebdSchin if (S_ISDIR(st->st_mode))
1530da2e3ebdSchin {
1531da2e3ebdSchin mp->mime = "x-system/dir";
1532da2e3ebdSchin return T("directory");
1533da2e3ebdSchin }
1534da2e3ebdSchin if (S_ISLNK(st->st_mode))
1535da2e3ebdSchin {
1536da2e3ebdSchin mp->mime = "x-system/lnk";
1537da2e3ebdSchin s = buf;
1538da2e3ebdSchin s += sfsprintf(s, PATH_MAX, T("symbolic link to "));
1539da2e3ebdSchin if (pathgetlink(file, s, size - (s - buf)) < 0)
1540da2e3ebdSchin return T("cannot read symbolic link text");
1541da2e3ebdSchin return buf;
1542da2e3ebdSchin }
1543da2e3ebdSchin if (S_ISBLK(st->st_mode))
1544da2e3ebdSchin {
1545da2e3ebdSchin mp->mime = "x-system/blk";
1546da2e3ebdSchin sfsprintf(buf, PATH_MAX, T("block special (%s)"), fmtdev(st));
1547da2e3ebdSchin return buf;
1548da2e3ebdSchin }
1549da2e3ebdSchin if (S_ISCHR(st->st_mode))
1550da2e3ebdSchin {
1551da2e3ebdSchin mp->mime = "x-system/chr";
1552da2e3ebdSchin sfsprintf(buf, PATH_MAX, T("character special (%s)"), fmtdev(st));
1553da2e3ebdSchin return buf;
1554da2e3ebdSchin }
1555da2e3ebdSchin if (S_ISFIFO(st->st_mode))
1556da2e3ebdSchin {
1557da2e3ebdSchin mp->mime = "x-system/fifo";
1558da2e3ebdSchin return "fifo";
1559da2e3ebdSchin }
1560da2e3ebdSchin #ifdef S_ISSOCK
1561da2e3ebdSchin if (S_ISSOCK(st->st_mode))
1562da2e3ebdSchin {
1563da2e3ebdSchin mp->mime = "x-system/sock";
1564da2e3ebdSchin return "socket";
1565da2e3ebdSchin }
1566da2e3ebdSchin #endif
1567da2e3ebdSchin }
1568da2e3ebdSchin if (!(mp->fbmx = st->st_size))
1569da2e3ebdSchin s = T("empty");
1570da2e3ebdSchin else if (!mp->fp)
1571da2e3ebdSchin s = T("cannot read");
1572da2e3ebdSchin else
1573da2e3ebdSchin {
1574da2e3ebdSchin mp->fbsz = sfread(mp->fp, mp->fbuf, sizeof(mp->fbuf) - 1);
1575da2e3ebdSchin if (mp->fbsz < 0)
1576da2e3ebdSchin s = fmterror(errno);
1577da2e3ebdSchin else if (mp->fbsz == 0)
1578da2e3ebdSchin s = T("empty");
1579da2e3ebdSchin else
1580da2e3ebdSchin {
1581da2e3ebdSchin mp->fbuf[mp->fbsz] = 0;
1582da2e3ebdSchin mp->xoff = 0;
1583da2e3ebdSchin mp->xbsz = 0;
1584da2e3ebdSchin if (!(s = ckmagic(mp, file, buf, st, 0)))
1585da2e3ebdSchin s = cklang(mp, file, buf, st);
1586da2e3ebdSchin }
1587da2e3ebdSchin }
1588da2e3ebdSchin if (!mp->mime)
1589da2e3ebdSchin mp->mime = "application/unknown";
1590da2e3ebdSchin else if ((t = strchr(mp->mime, '%')) && *(t + 1) == 's' && !*(t + 2))
1591da2e3ebdSchin {
1592da2e3ebdSchin register char* b;
1593da2e3ebdSchin register char* be;
1594da2e3ebdSchin register char* m;
1595da2e3ebdSchin register char* me;
1596da2e3ebdSchin
1597da2e3ebdSchin b = mp->mime;
1598da2e3ebdSchin me = (m = mp->mime = mp->fbuf) + sizeof(mp->fbuf) - 1;
1599da2e3ebdSchin while (m < me && b < t)
1600da2e3ebdSchin *m++ = *b++;
1601da2e3ebdSchin b = t = s;
1602da2e3ebdSchin for (;;)
1603da2e3ebdSchin {
1604da2e3ebdSchin if (!(be = strchr(t, ' ')))
1605da2e3ebdSchin {
1606da2e3ebdSchin be = b + strlen(b);
1607da2e3ebdSchin break;
1608da2e3ebdSchin }
1609da2e3ebdSchin if (*(be - 1) == ',' || strneq(be + 1, "data", 4) || strneq(be + 1, "file", 4))
1610da2e3ebdSchin break;
1611da2e3ebdSchin b = t;
1612da2e3ebdSchin t = be + 1;
1613da2e3ebdSchin }
1614da2e3ebdSchin while (m < me && b < be)
1615da2e3ebdSchin if ((*m++ = *b++) == ' ')
1616da2e3ebdSchin *(m - 1) = '-';
1617da2e3ebdSchin *m = 0;
1618da2e3ebdSchin }
1619da2e3ebdSchin return s;
1620da2e3ebdSchin }
1621da2e3ebdSchin
1622da2e3ebdSchin /*
1623da2e3ebdSchin * low level for magicload()
1624da2e3ebdSchin */
1625da2e3ebdSchin
1626da2e3ebdSchin static int
load(register Magic_t * mp,char * file,register Sfio_t * fp)1627da2e3ebdSchin load(register Magic_t* mp, char* file, register Sfio_t* fp)
1628da2e3ebdSchin {
1629da2e3ebdSchin register Entry_t* ep;
1630da2e3ebdSchin register char* p;
1631da2e3ebdSchin register char* p2;
1632da2e3ebdSchin char* p3;
1633da2e3ebdSchin char* next;
1634da2e3ebdSchin int n;
1635da2e3ebdSchin int lge;
1636da2e3ebdSchin int lev;
1637da2e3ebdSchin int ent;
1638da2e3ebdSchin int old;
1639da2e3ebdSchin int cont;
1640da2e3ebdSchin Info_t* ip;
1641da2e3ebdSchin Entry_t* ret;
1642da2e3ebdSchin Entry_t* first;
1643da2e3ebdSchin Entry_t* last = 0;
1644da2e3ebdSchin Entry_t* fun['z' - 'a' + 1];
1645da2e3ebdSchin
1646da2e3ebdSchin memzero(fun, sizeof(fun));
1647da2e3ebdSchin cont = '$';
1648da2e3ebdSchin ent = 0;
1649da2e3ebdSchin lev = 0;
1650da2e3ebdSchin old = 0;
1651da2e3ebdSchin ret = 0;
1652da2e3ebdSchin error_info.file = file;
1653da2e3ebdSchin error_info.line = 0;
1654da2e3ebdSchin first = ep = vmnewof(mp->vm, 0, Entry_t, 1, 0);
1655da2e3ebdSchin while (p = sfgetr(fp, '\n', 1))
1656da2e3ebdSchin {
1657da2e3ebdSchin error_info.line++;
1658da2e3ebdSchin for (; isspace(*p); p++);
1659da2e3ebdSchin
1660da2e3ebdSchin /*
1661da2e3ebdSchin * nesting
1662da2e3ebdSchin */
1663da2e3ebdSchin
1664da2e3ebdSchin switch (*p)
1665da2e3ebdSchin {
1666da2e3ebdSchin case 0:
1667da2e3ebdSchin case '#':
1668da2e3ebdSchin cont = '#';
1669da2e3ebdSchin continue;
1670da2e3ebdSchin case '{':
1671da2e3ebdSchin if (++lev < MAXNEST)
1672da2e3ebdSchin ep->nest = *p;
1673da2e3ebdSchin else if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
1674da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 1, "{ ... } operator nesting too deep -- %d max", MAXNEST);
1675da2e3ebdSchin continue;
1676da2e3ebdSchin case '}':
1677da2e3ebdSchin if (!last || lev <= 0)
1678da2e3ebdSchin {
1679da2e3ebdSchin if (mp->disc->errorf)
1680da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 2, "`%c': invalid nesting", *p);
1681da2e3ebdSchin }
1682da2e3ebdSchin else if (lev-- == ent)
1683da2e3ebdSchin {
1684da2e3ebdSchin ent = 0;
1685da2e3ebdSchin ep->cont = ':';
1686da2e3ebdSchin ep->offset = ret->offset;
1687da2e3ebdSchin ep->nest = ' ';
1688da2e3ebdSchin ep->type = ' ';
1689da2e3ebdSchin ep->op = ' ';
1690da2e3ebdSchin ep->desc = "[RETURN]";
1691da2e3ebdSchin last = ep;
1692da2e3ebdSchin ep = ret->next = vmnewof(mp->vm, 0, Entry_t, 1, 0);
1693da2e3ebdSchin ret = 0;
1694da2e3ebdSchin }
1695da2e3ebdSchin else
1696da2e3ebdSchin last->nest = *p;
1697da2e3ebdSchin continue;
1698da2e3ebdSchin default:
1699da2e3ebdSchin if (*(p + 1) == '{' || *(p + 1) == '(' && *p != '+' && *p != '>' && *p != '&' && *p != '|')
1700da2e3ebdSchin {
1701da2e3ebdSchin n = *p++;
1702da2e3ebdSchin if (n >= 'a' && n <= 'z')
1703da2e3ebdSchin n -= 'a';
1704da2e3ebdSchin else
1705da2e3ebdSchin {
1706da2e3ebdSchin if (mp->disc->errorf)
1707da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: invalid function name", n);
1708da2e3ebdSchin n = 0;
1709da2e3ebdSchin }
1710da2e3ebdSchin if (ret && mp->disc->errorf)
1711da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function has no return", ret->offset + 'a');
1712da2e3ebdSchin if (*p == '{')
1713da2e3ebdSchin {
1714da2e3ebdSchin ent = ++lev;
1715da2e3ebdSchin ret = ep;
1716da2e3ebdSchin ep->desc = "[FUNCTION]";
1717da2e3ebdSchin }
1718da2e3ebdSchin else
1719da2e3ebdSchin {
1720da2e3ebdSchin if (*(p + 1) != ')' && mp->disc->errorf)
1721da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: invalid function call argument list", n + 'a');
1722da2e3ebdSchin ep->desc = "[CALL]";
1723da2e3ebdSchin }
1724da2e3ebdSchin ep->cont = cont;
1725da2e3ebdSchin ep->offset = n;
1726da2e3ebdSchin ep->nest = ' ';
1727da2e3ebdSchin ep->type = ' ';
1728da2e3ebdSchin ep->op = ' ';
1729da2e3ebdSchin last = ep;
1730da2e3ebdSchin ep = ep->next = vmnewof(mp->vm, 0, Entry_t, 1, 0);
1731da2e3ebdSchin if (ret)
1732da2e3ebdSchin fun[n] = last->value.lab = ep;
1733da2e3ebdSchin else if (!(last->value.lab = fun[n]) && mp->disc->errorf)
1734da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function not defined", n + 'a');
1735da2e3ebdSchin continue;
1736da2e3ebdSchin }
1737da2e3ebdSchin if (!ep->nest)
1738da2e3ebdSchin ep->nest = (lev > 0 && lev != ent) ? ('0' + lev - !!ent) : ' ';
1739da2e3ebdSchin break;
1740da2e3ebdSchin }
1741da2e3ebdSchin
1742da2e3ebdSchin /*
1743da2e3ebdSchin * continuation
1744da2e3ebdSchin */
1745da2e3ebdSchin
1746da2e3ebdSchin cont = '$';
1747da2e3ebdSchin switch (*p)
1748da2e3ebdSchin {
1749da2e3ebdSchin case '>':
1750da2e3ebdSchin old = 1;
1751da2e3ebdSchin if (*(p + 1) == *p)
1752da2e3ebdSchin {
1753da2e3ebdSchin /*
1754da2e3ebdSchin * old style nesting push
1755da2e3ebdSchin */
1756da2e3ebdSchin
1757da2e3ebdSchin p++;
1758da2e3ebdSchin old = 2;
1759da2e3ebdSchin if (!lev && last)
1760da2e3ebdSchin {
1761da2e3ebdSchin lev = 1;
1762da2e3ebdSchin last->nest = '{';
1763da2e3ebdSchin if (last->cont == '>')
1764da2e3ebdSchin last->cont = '&';
1765da2e3ebdSchin ep->nest = '1';
1766da2e3ebdSchin }
1767da2e3ebdSchin }
1768da2e3ebdSchin /*FALLTHROUGH*/
1769da2e3ebdSchin case '+':
1770da2e3ebdSchin case '&':
1771da2e3ebdSchin case '|':
1772da2e3ebdSchin ep->cont = *p++;
1773da2e3ebdSchin break;
1774da2e3ebdSchin default:
1775da2e3ebdSchin if ((mp->flags & MAGIC_VERBOSE) && !isalpha(*p) && mp->disc->errorf)
1776da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 1, "`%c': invalid line continuation operator", *p);
1777da2e3ebdSchin /*FALLTHROUGH*/
1778da2e3ebdSchin case '*':
1779da2e3ebdSchin case '0': case '1': case '2': case '3': case '4':
1780da2e3ebdSchin case '5': case '6': case '7': case '8': case '9':
1781da2e3ebdSchin ep->cont = (lev > 0) ? '&' : '#';
1782da2e3ebdSchin break;
1783da2e3ebdSchin }
1784da2e3ebdSchin switch (old)
1785da2e3ebdSchin {
1786da2e3ebdSchin case 1:
1787da2e3ebdSchin old = 0;
1788da2e3ebdSchin if (lev)
1789da2e3ebdSchin {
1790da2e3ebdSchin /*
1791da2e3ebdSchin * old style nesting pop
1792da2e3ebdSchin */
1793da2e3ebdSchin
1794da2e3ebdSchin lev = 0;
1795da2e3ebdSchin if (last)
1796da2e3ebdSchin last->nest = '}';
1797da2e3ebdSchin ep->nest = ' ';
1798da2e3ebdSchin if (ep->cont == '&')
1799da2e3ebdSchin ep->cont = '#';
1800da2e3ebdSchin }
1801da2e3ebdSchin break;
1802da2e3ebdSchin case 2:
1803da2e3ebdSchin old = 1;
1804da2e3ebdSchin break;
1805da2e3ebdSchin }
1806da2e3ebdSchin if (isdigit(*p))
1807da2e3ebdSchin {
1808da2e3ebdSchin /*
1809da2e3ebdSchin * absolute offset
1810da2e3ebdSchin */
1811da2e3ebdSchin
1812da2e3ebdSchin ep->offset = strton(p, &next, NiL, 0);
1813da2e3ebdSchin p2 = next;
1814da2e3ebdSchin }
1815da2e3ebdSchin else
1816da2e3ebdSchin {
1817da2e3ebdSchin for (p2 = p; *p2 && !isspace(*p2); p2++);
1818da2e3ebdSchin if (!*p2)
1819da2e3ebdSchin {
1820da2e3ebdSchin if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
1821da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 1, "not enough fields: `%s'", p);
1822da2e3ebdSchin continue;
1823da2e3ebdSchin }
1824da2e3ebdSchin
1825da2e3ebdSchin /*
1826da2e3ebdSchin * offset expression
1827da2e3ebdSchin */
1828da2e3ebdSchin
1829da2e3ebdSchin *p2++ = 0;
1830da2e3ebdSchin ep->expr = vmstrdup(mp->vm, p);
1831da2e3ebdSchin if (isalpha(*p))
1832da2e3ebdSchin ep->offset = (ip = (Info_t*)dtmatch(mp->infotab, p)) ? ip->value : 0;
1833da2e3ebdSchin else if (*p == '(' && ep->cont == '>')
1834da2e3ebdSchin {
1835da2e3ebdSchin /*
1836da2e3ebdSchin * convert old style indirection to @
1837da2e3ebdSchin */
1838da2e3ebdSchin
1839da2e3ebdSchin p = ep->expr + 1;
1840da2e3ebdSchin for (;;)
1841da2e3ebdSchin {
1842da2e3ebdSchin switch (*p++)
1843da2e3ebdSchin {
1844da2e3ebdSchin case 0:
1845da2e3ebdSchin case '@':
1846da2e3ebdSchin case '(':
1847da2e3ebdSchin break;
1848da2e3ebdSchin case ')':
1849da2e3ebdSchin break;
1850da2e3ebdSchin default:
1851da2e3ebdSchin continue;
1852da2e3ebdSchin }
1853da2e3ebdSchin break;
1854da2e3ebdSchin }
1855da2e3ebdSchin if (*--p == ')')
1856da2e3ebdSchin {
1857da2e3ebdSchin *p = 0;
1858da2e3ebdSchin *ep->expr = '@';
1859da2e3ebdSchin }
1860da2e3ebdSchin }
1861da2e3ebdSchin }
1862da2e3ebdSchin for (; isspace(*p2); p2++);
1863da2e3ebdSchin for (p = p2; *p2 && !isspace(*p2); p2++);
1864da2e3ebdSchin if (!*p2)
1865da2e3ebdSchin {
1866da2e3ebdSchin if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
1867da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 1, "not enough fields: `%s'", p);
1868da2e3ebdSchin continue;
1869da2e3ebdSchin }
1870da2e3ebdSchin *p2++ = 0;
1871da2e3ebdSchin
1872da2e3ebdSchin /*
1873da2e3ebdSchin * type
1874da2e3ebdSchin */
1875da2e3ebdSchin
1876da2e3ebdSchin if ((*p == 'b' || *p == 'l') && *(p + 1) == 'e')
1877da2e3ebdSchin {
1878da2e3ebdSchin ep->swap = ~(*p == 'l' ? 7 : 0);
1879da2e3ebdSchin p += 2;
1880da2e3ebdSchin }
1881da2e3ebdSchin if (*p == 's')
1882da2e3ebdSchin {
1883da2e3ebdSchin if (*(p + 1) == 'h')
1884da2e3ebdSchin ep->type = 'h';
1885da2e3ebdSchin else
1886da2e3ebdSchin ep->type = 's';
1887da2e3ebdSchin }
1888da2e3ebdSchin else if (*p == 'a')
1889da2e3ebdSchin ep->type = 's';
1890da2e3ebdSchin else
1891da2e3ebdSchin ep->type = *p;
1892da2e3ebdSchin if (p = strchr(p, '&'))
1893da2e3ebdSchin {
1894da2e3ebdSchin /*
1895da2e3ebdSchin * old style mask
1896da2e3ebdSchin */
1897da2e3ebdSchin
1898da2e3ebdSchin ep->mask = strton(++p, NiL, NiL, 0);
1899da2e3ebdSchin }
1900da2e3ebdSchin for (; isspace(*p2); p2++);
1901da2e3ebdSchin if (ep->mask)
1902da2e3ebdSchin *--p2 = '=';
1903da2e3ebdSchin
1904da2e3ebdSchin /*
1905da2e3ebdSchin * comparison operation
1906da2e3ebdSchin */
1907da2e3ebdSchin
1908da2e3ebdSchin p = p2;
1909da2e3ebdSchin if (p2 = strchr(p, '\t'))
1910da2e3ebdSchin *p2++ = 0;
1911da2e3ebdSchin else
1912da2e3ebdSchin {
1913da2e3ebdSchin int qe = 0;
1914da2e3ebdSchin int qn = 0;
1915da2e3ebdSchin
1916da2e3ebdSchin /*
1917da2e3ebdSchin * assume balanced {}[]()\\""'' field
1918da2e3ebdSchin */
1919da2e3ebdSchin
1920da2e3ebdSchin for (p2 = p;;)
1921da2e3ebdSchin {
1922da2e3ebdSchin switch (n = *p2++)
1923da2e3ebdSchin {
1924da2e3ebdSchin case 0:
1925da2e3ebdSchin break;
1926da2e3ebdSchin case '{':
1927da2e3ebdSchin if (!qe)
1928da2e3ebdSchin qe = '}';
1929da2e3ebdSchin if (qe == '}')
1930da2e3ebdSchin qn++;
1931da2e3ebdSchin continue;
1932da2e3ebdSchin case '(':
1933da2e3ebdSchin if (!qe)
1934da2e3ebdSchin qe = ')';
1935da2e3ebdSchin if (qe == ')')
1936da2e3ebdSchin qn++;
1937da2e3ebdSchin continue;
1938da2e3ebdSchin case '[':
1939da2e3ebdSchin if (!qe)
1940da2e3ebdSchin qe = ']';
1941da2e3ebdSchin if (qe == ']')
1942da2e3ebdSchin qn++;
1943da2e3ebdSchin continue;
1944da2e3ebdSchin case '}':
1945da2e3ebdSchin case ')':
1946da2e3ebdSchin case ']':
1947da2e3ebdSchin if (qe == n && qn > 0)
1948da2e3ebdSchin qn--;
1949da2e3ebdSchin continue;
1950da2e3ebdSchin case '"':
1951da2e3ebdSchin case '\'':
1952da2e3ebdSchin if (!qe)
1953da2e3ebdSchin qe = n;
1954da2e3ebdSchin else if (qe == n)
1955da2e3ebdSchin qe = 0;
1956da2e3ebdSchin continue;
1957da2e3ebdSchin case '\\':
1958da2e3ebdSchin if (*p2)
1959da2e3ebdSchin p2++;
1960da2e3ebdSchin continue;
1961da2e3ebdSchin default:
1962da2e3ebdSchin if (!qe && isspace(n))
1963da2e3ebdSchin break;
1964da2e3ebdSchin continue;
1965da2e3ebdSchin }
1966da2e3ebdSchin if (n)
1967da2e3ebdSchin *(p2 - 1) = 0;
1968da2e3ebdSchin else
1969da2e3ebdSchin p2--;
1970da2e3ebdSchin break;
1971da2e3ebdSchin }
1972da2e3ebdSchin }
1973da2e3ebdSchin lge = 0;
1974da2e3ebdSchin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
1975da2e3ebdSchin ep->op = '=';
1976da2e3ebdSchin else
1977da2e3ebdSchin {
1978da2e3ebdSchin if (*p == '&')
1979da2e3ebdSchin {
1980da2e3ebdSchin ep->mask = strton(++p, &next, NiL, 0);
1981da2e3ebdSchin p = next;
1982da2e3ebdSchin }
1983da2e3ebdSchin switch (*p)
1984da2e3ebdSchin {
1985da2e3ebdSchin case '=':
1986da2e3ebdSchin case '>':
1987da2e3ebdSchin case '<':
1988da2e3ebdSchin case '*':
1989da2e3ebdSchin ep->op = *p++;
1990da2e3ebdSchin if (*p == '=')
1991da2e3ebdSchin {
1992da2e3ebdSchin p++;
1993da2e3ebdSchin switch (ep->op)
1994da2e3ebdSchin {
1995da2e3ebdSchin case '>':
1996da2e3ebdSchin lge = -1;
1997da2e3ebdSchin break;
1998da2e3ebdSchin case '<':
1999da2e3ebdSchin lge = 1;
2000da2e3ebdSchin break;
2001da2e3ebdSchin }
2002da2e3ebdSchin }
2003da2e3ebdSchin break;
2004da2e3ebdSchin case '!':
2005da2e3ebdSchin case '@':
2006da2e3ebdSchin ep->op = *p++;
2007da2e3ebdSchin if (*p == '=')
2008da2e3ebdSchin p++;
2009da2e3ebdSchin break;
2010da2e3ebdSchin case 'x':
2011da2e3ebdSchin p++;
2012da2e3ebdSchin ep->op = '*';
2013da2e3ebdSchin break;
2014da2e3ebdSchin default:
2015da2e3ebdSchin ep->op = '=';
2016da2e3ebdSchin if (ep->mask)
2017da2e3ebdSchin ep->value.num = ep->mask;
2018da2e3ebdSchin break;
2019da2e3ebdSchin }
2020da2e3ebdSchin }
2021da2e3ebdSchin if (ep->op != '*' && !ep->value.num)
2022da2e3ebdSchin {
2023da2e3ebdSchin if (ep->type == 'e')
2024da2e3ebdSchin {
2025da2e3ebdSchin if (ep->value.sub = vmnewof(mp->vm, 0, regex_t, 1, 0))
2026da2e3ebdSchin {
2027da2e3ebdSchin ep->value.sub->re_disc = &mp->redisc;
2028da2e3ebdSchin if (!(n = regcomp(ep->value.sub, p, REG_DELIMITED|REG_LENIENT|REG_NULL|REG_DISCIPLINE)))
2029da2e3ebdSchin {
2030da2e3ebdSchin p += ep->value.sub->re_npat;
2031da2e3ebdSchin if (!(n = regsubcomp(ep->value.sub, p, NiL, 0, 0)))
2032da2e3ebdSchin p += ep->value.sub->re_npat;
2033da2e3ebdSchin }
2034da2e3ebdSchin if (n)
2035da2e3ebdSchin {
2036da2e3ebdSchin regmessage(mp, ep->value.sub, n);
2037da2e3ebdSchin ep->value.sub = 0;
2038da2e3ebdSchin }
2039da2e3ebdSchin else if (*p && mp->disc->errorf)
2040da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 1, "invalid characters after substitution: %s", p);
2041da2e3ebdSchin }
2042da2e3ebdSchin }
2043da2e3ebdSchin else if (ep->type == 'm')
2044da2e3ebdSchin {
2045da2e3ebdSchin ep->mask = stresc(p) + 1;
2046da2e3ebdSchin ep->value.str = vmnewof(mp->vm, 0, char, ep->mask + 1, 0);
2047da2e3ebdSchin memcpy(ep->value.str, p, ep->mask);
2048da2e3ebdSchin if ((!ep->expr || !ep->offset) && !strmatch(ep->value.str, "\\!\\(*\\)"))
2049da2e3ebdSchin ep->value.str[ep->mask - 1] = '*';
2050da2e3ebdSchin }
2051da2e3ebdSchin else if (ep->type == 's')
2052da2e3ebdSchin {
2053da2e3ebdSchin ep->mask = stresc(p);
2054da2e3ebdSchin ep->value.str = vmnewof(mp->vm, 0, char, ep->mask, 0);
2055da2e3ebdSchin memcpy(ep->value.str, p, ep->mask);
2056da2e3ebdSchin }
2057da2e3ebdSchin else if (*p == '\'')
2058da2e3ebdSchin {
2059da2e3ebdSchin stresc(p);
2060da2e3ebdSchin ep->value.num = *(unsigned char*)(p + 1) + lge;
2061da2e3ebdSchin }
2062da2e3ebdSchin else if (strmatch(p, "+([a-z])\\(*\\)"))
2063da2e3ebdSchin {
2064da2e3ebdSchin char* t;
2065da2e3ebdSchin
2066da2e3ebdSchin t = p;
2067da2e3ebdSchin ep->type = 'V';
2068da2e3ebdSchin ep->op = *p;
2069da2e3ebdSchin while (*p && *p++ != '(');
2070da2e3ebdSchin switch (ep->op)
2071da2e3ebdSchin {
2072da2e3ebdSchin case 'l':
2073da2e3ebdSchin n = *p++;
2074da2e3ebdSchin if (n < 'a' || n > 'z')
2075da2e3ebdSchin {
2076da2e3ebdSchin if (mp->disc->errorf)
2077da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: invalid function name", n);
2078da2e3ebdSchin }
2079da2e3ebdSchin else if (!fun[n -= 'a'])
2080da2e3ebdSchin {
2081da2e3ebdSchin if (mp->disc->errorf)
2082da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function not defined", n + 'a');
2083da2e3ebdSchin }
2084da2e3ebdSchin else
2085da2e3ebdSchin {
2086da2e3ebdSchin ep->value.loop = vmnewof(mp->vm, 0, Loop_t, 1, 0);
2087da2e3ebdSchin ep->value.loop->lab = fun[n];
2088da2e3ebdSchin while (*p && *p++ != ',');
2089da2e3ebdSchin ep->value.loop->start = strton(p, &t, NiL, 0);
2090da2e3ebdSchin while (*t && *t++ != ',');
2091da2e3ebdSchin ep->value.loop->size = strton(t, &t, NiL, 0);
2092da2e3ebdSchin }
2093da2e3ebdSchin break;
2094da2e3ebdSchin case 'm':
2095da2e3ebdSchin case 'r':
2096da2e3ebdSchin ep->desc = vmnewof(mp->vm, 0, char, 32, 0);
2097da2e3ebdSchin ep->mime = vmnewof(mp->vm, 0, char, 32, 0);
2098da2e3ebdSchin break;
2099da2e3ebdSchin case 'v':
2100da2e3ebdSchin break;
2101da2e3ebdSchin default:
2102da2e3ebdSchin if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
2103da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 1, "%-.*s: unknown function", p - t, t);
2104da2e3ebdSchin break;
2105da2e3ebdSchin }
2106da2e3ebdSchin }
2107da2e3ebdSchin else
2108da2e3ebdSchin {
2109da2e3ebdSchin ep->value.num = strton(p, NiL, NiL, 0) + lge;
2110da2e3ebdSchin if (ep->op == '@')
2111da2e3ebdSchin ep->value.num = swapget(0, (char*)&ep->value.num, sizeof(ep->value.num));
2112da2e3ebdSchin }
2113da2e3ebdSchin }
2114da2e3ebdSchin
2115da2e3ebdSchin /*
2116da2e3ebdSchin * file description
2117da2e3ebdSchin */
2118da2e3ebdSchin
2119da2e3ebdSchin if (p2)
2120da2e3ebdSchin {
2121da2e3ebdSchin for (; isspace(*p2); p2++);
2122da2e3ebdSchin if (p = strchr(p2, '\t'))
2123da2e3ebdSchin {
2124da2e3ebdSchin /*
2125da2e3ebdSchin * check for message catalog index
2126da2e3ebdSchin */
2127da2e3ebdSchin
2128da2e3ebdSchin *p++ = 0;
2129da2e3ebdSchin if (isalpha(*p2))
2130da2e3ebdSchin {
2131da2e3ebdSchin for (p3 = p2; isalnum(*p3); p3++);
2132da2e3ebdSchin if (*p3++ == ':')
2133da2e3ebdSchin {
2134da2e3ebdSchin for (; isdigit(*p3); p3++);
2135da2e3ebdSchin if (!*p3)
2136da2e3ebdSchin {
2137da2e3ebdSchin for (p2 = p; isspace(*p2); p2++);
2138da2e3ebdSchin if (p = strchr(p2, '\t'))
2139da2e3ebdSchin *p++ = 0;
2140da2e3ebdSchin }
2141da2e3ebdSchin }
2142da2e3ebdSchin }
2143da2e3ebdSchin }
2144da2e3ebdSchin stresc(p2);
2145da2e3ebdSchin ep->desc = vmstrdup(mp->vm, p2);
2146da2e3ebdSchin if (p)
2147da2e3ebdSchin {
2148da2e3ebdSchin for (; isspace(*p); p++);
2149da2e3ebdSchin if (*p)
2150da2e3ebdSchin ep->mime = vmstrdup(mp->vm, p);
2151da2e3ebdSchin }
2152da2e3ebdSchin }
2153da2e3ebdSchin else
2154da2e3ebdSchin ep->desc = "";
2155da2e3ebdSchin
2156da2e3ebdSchin /*
2157da2e3ebdSchin * get next entry
2158da2e3ebdSchin */
2159da2e3ebdSchin
2160da2e3ebdSchin last = ep;
2161da2e3ebdSchin ep = ep->next = vmnewof(mp->vm, 0, Entry_t, 1, 0);
2162da2e3ebdSchin }
2163da2e3ebdSchin if (last)
2164da2e3ebdSchin {
2165da2e3ebdSchin last->next = 0;
2166da2e3ebdSchin if (mp->magiclast)
2167da2e3ebdSchin mp->magiclast->next = first;
2168da2e3ebdSchin else
2169da2e3ebdSchin mp->magic = first;
2170da2e3ebdSchin mp->magiclast = last;
2171da2e3ebdSchin }
2172da2e3ebdSchin vmfree(mp->vm, ep);
2173da2e3ebdSchin if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
2174da2e3ebdSchin {
2175da2e3ebdSchin if (lev < 0)
2176da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 1, "too many } operators");
2177da2e3ebdSchin else if (lev > 0)
2178da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 1, "not enough } operators");
2179da2e3ebdSchin if (ret)
2180da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function has no return", ret->offset + 'a');
2181da2e3ebdSchin }
2182da2e3ebdSchin error_info.file = 0;
2183da2e3ebdSchin error_info.line = 0;
2184da2e3ebdSchin return 0;
2185da2e3ebdSchin }
2186da2e3ebdSchin
2187da2e3ebdSchin /*
2188da2e3ebdSchin * load a magic file into mp
2189da2e3ebdSchin */
2190da2e3ebdSchin
2191da2e3ebdSchin int
magicload(register Magic_t * mp,const char * file,unsigned long flags)2192da2e3ebdSchin magicload(register Magic_t* mp, const char* file, unsigned long flags)
2193da2e3ebdSchin {
2194da2e3ebdSchin register char* s;
2195da2e3ebdSchin register char* e;
2196da2e3ebdSchin register char* t;
2197da2e3ebdSchin int n;
2198da2e3ebdSchin int found;
2199da2e3ebdSchin int list;
2200da2e3ebdSchin Sfio_t* fp;
2201da2e3ebdSchin
2202da2e3ebdSchin mp->flags = mp->disc->flags | flags;
2203da2e3ebdSchin found = 0;
2204da2e3ebdSchin if (list = !(s = (char*)file) || !*s || (*s == '-' || *s == '.') && !*(s + 1))
2205da2e3ebdSchin {
2206da2e3ebdSchin if (!(s = getenv(MAGIC_FILE_ENV)) || !*s)
2207da2e3ebdSchin s = MAGIC_FILE;
2208da2e3ebdSchin }
2209da2e3ebdSchin for (;;)
2210da2e3ebdSchin {
2211da2e3ebdSchin if (!list)
2212da2e3ebdSchin e = 0;
2213da2e3ebdSchin else if (e = strchr(s, ':'))
2214da2e3ebdSchin {
2215da2e3ebdSchin /*
2216da2e3ebdSchin * ok, so ~ won't work for the last list element
2217da2e3ebdSchin * we do it for MAGIC_FILES_ENV anyway
2218da2e3ebdSchin */
2219da2e3ebdSchin
2220da2e3ebdSchin if ((strneq(s, "~/", n = 2) || strneq(s, "$HOME/", n = 6) || strneq(s, "${HOME}/", n = 8)) && (t = getenv("HOME")))
2221da2e3ebdSchin {
2222da2e3ebdSchin sfputr(mp->tmp, t, -1);
2223da2e3ebdSchin s += n - 1;
2224da2e3ebdSchin }
2225da2e3ebdSchin sfwrite(mp->tmp, s, e - s);
2226da2e3ebdSchin if (!(s = sfstruse(mp->tmp)))
2227da2e3ebdSchin goto nospace;
2228da2e3ebdSchin }
2229da2e3ebdSchin if (!*s || streq(s, "-"))
2230da2e3ebdSchin s = MAGIC_FILE;
2231da2e3ebdSchin if (!(fp = sfopen(NiL, s, "r")))
2232da2e3ebdSchin {
2233da2e3ebdSchin if (list)
2234da2e3ebdSchin {
2235da2e3ebdSchin if (!(t = pathpath(mp->fbuf, s, "", PATH_REGULAR|PATH_READ)) && !strchr(s, '/'))
2236da2e3ebdSchin {
2237da2e3ebdSchin strcpy(mp->fbuf, s);
2238da2e3ebdSchin sfprintf(mp->tmp, "%s/%s", MAGIC_DIR, mp->fbuf);
2239da2e3ebdSchin if (!(s = sfstruse(mp->tmp)))
2240da2e3ebdSchin goto nospace;
2241da2e3ebdSchin if (!(t = pathpath(mp->fbuf, s, "", PATH_REGULAR|PATH_READ)))
2242da2e3ebdSchin goto next;
2243da2e3ebdSchin }
2244da2e3ebdSchin if (!(fp = sfopen(NiL, t, "r")))
2245da2e3ebdSchin goto next;
2246da2e3ebdSchin }
2247da2e3ebdSchin else
2248da2e3ebdSchin {
2249da2e3ebdSchin if (mp->disc->errorf)
2250da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 3, "%s: cannot open magic file", s);
2251da2e3ebdSchin return -1;
2252da2e3ebdSchin }
2253da2e3ebdSchin }
2254da2e3ebdSchin found = 1;
2255da2e3ebdSchin n = load(mp, s, fp);
2256da2e3ebdSchin sfclose(fp);
2257da2e3ebdSchin if (n && !list)
2258da2e3ebdSchin return -1;
2259da2e3ebdSchin next:
2260da2e3ebdSchin if (!e)
2261da2e3ebdSchin break;
2262da2e3ebdSchin s = e + 1;
2263da2e3ebdSchin }
2264da2e3ebdSchin if (!found)
2265da2e3ebdSchin {
2266da2e3ebdSchin if (mp->flags & MAGIC_VERBOSE)
2267da2e3ebdSchin {
2268da2e3ebdSchin if (mp->disc->errorf)
2269da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 2, "cannot find magic file");
2270da2e3ebdSchin }
2271da2e3ebdSchin return -1;
2272da2e3ebdSchin }
2273da2e3ebdSchin return 0;
2274da2e3ebdSchin nospace:
2275da2e3ebdSchin if (mp->disc->errorf)
2276da2e3ebdSchin (*mp->disc->errorf)(mp, mp->disc, 3, "out of space");
2277da2e3ebdSchin return -1;
2278da2e3ebdSchin }
2279da2e3ebdSchin
2280da2e3ebdSchin /*
2281da2e3ebdSchin * open a magic session
2282da2e3ebdSchin */
2283da2e3ebdSchin
2284da2e3ebdSchin Magic_t*
magicopen(Magicdisc_t * disc)2285da2e3ebdSchin magicopen(Magicdisc_t* disc)
2286da2e3ebdSchin {
2287da2e3ebdSchin register Magic_t* mp;
2288da2e3ebdSchin register int i;
2289da2e3ebdSchin register int n;
2290da2e3ebdSchin register int f;
2291da2e3ebdSchin register int c;
2292da2e3ebdSchin register Vmalloc_t* vm;
2293da2e3ebdSchin unsigned char* map[CC_MAPS + 1];
2294da2e3ebdSchin
2295da2e3ebdSchin if (!(vm = vmopen(Vmdcheap, Vmbest, 0)))
2296da2e3ebdSchin return 0;
2297da2e3ebdSchin if (!(mp = vmnewof(vm, 0, Magic_t, 1, 0)))
2298da2e3ebdSchin {
2299da2e3ebdSchin vmclose(vm);
2300da2e3ebdSchin return 0;
2301da2e3ebdSchin }
2302da2e3ebdSchin mp->id = lib;
2303da2e3ebdSchin mp->disc = disc;
2304da2e3ebdSchin mp->vm = vm;
2305da2e3ebdSchin mp->flags = disc->flags;
2306da2e3ebdSchin mp->redisc.re_version = REG_VERSION;
2307da2e3ebdSchin mp->redisc.re_flags = REG_NOFREE;
2308da2e3ebdSchin mp->redisc.re_errorf = (regerror_t)disc->errorf;
2309da2e3ebdSchin mp->redisc.re_resizef = (regresize_t)vmgetmem;
2310da2e3ebdSchin mp->redisc.re_resizehandle = (void*)mp->vm;
2311da2e3ebdSchin mp->dtdisc.key = offsetof(Info_t, name);
2312da2e3ebdSchin mp->dtdisc.link = offsetof(Info_t, link);
2313da2e3ebdSchin if (!(mp->tmp = sfstropen()) || !(mp->infotab = dtnew(mp->vm, &mp->dtdisc, Dthash)))
2314da2e3ebdSchin goto bad;
2315da2e3ebdSchin for (n = 0; n < elementsof(info); n++)
2316da2e3ebdSchin dtinsert(mp->infotab, &info[n]);
2317da2e3ebdSchin for (i = 0; i < CC_MAPS; i++)
2318da2e3ebdSchin map[i] = ccmap(i, CC_ASCII);
2319da2e3ebdSchin mp->x2n = ccmap(CC_ALIEN, CC_NATIVE);
2320da2e3ebdSchin for (n = 0; n <= UCHAR_MAX; n++)
2321da2e3ebdSchin {
2322da2e3ebdSchin f = 0;
2323da2e3ebdSchin i = CC_MAPS;
2324da2e3ebdSchin while (--i >= 0)
2325da2e3ebdSchin {
2326da2e3ebdSchin c = ccmapchr(map[i], n);
2327da2e3ebdSchin f = (f << CC_BIT) | CCTYPE(c);
2328da2e3ebdSchin }
2329da2e3ebdSchin mp->cctype[n] = f;
2330da2e3ebdSchin }
2331da2e3ebdSchin return mp;
2332da2e3ebdSchin bad:
2333da2e3ebdSchin magicclose(mp);
2334da2e3ebdSchin return 0;
2335da2e3ebdSchin }
2336da2e3ebdSchin
2337da2e3ebdSchin /*
2338da2e3ebdSchin * close a magicopen() session
2339da2e3ebdSchin */
2340da2e3ebdSchin
2341da2e3ebdSchin int
magicclose(register Magic_t * mp)2342da2e3ebdSchin magicclose(register Magic_t* mp)
2343da2e3ebdSchin {
2344da2e3ebdSchin if (!mp)
2345da2e3ebdSchin return -1;
2346da2e3ebdSchin if (mp->tmp)
2347da2e3ebdSchin sfstrclose(mp->tmp);
2348da2e3ebdSchin if (mp->vm)
2349da2e3ebdSchin vmclose(mp->vm);
2350da2e3ebdSchin return 0;
2351da2e3ebdSchin }
2352da2e3ebdSchin
2353da2e3ebdSchin /*
2354da2e3ebdSchin * return the magic string for file with optional stat info st
2355da2e3ebdSchin */
2356da2e3ebdSchin
2357da2e3ebdSchin char*
magictype(register Magic_t * mp,Sfio_t * fp,const char * file,register struct stat * st)2358da2e3ebdSchin magictype(register Magic_t* mp, Sfio_t* fp, const char* file, register struct stat* st)
2359da2e3ebdSchin {
2360da2e3ebdSchin off_t off;
2361da2e3ebdSchin char* s;
2362da2e3ebdSchin
2363da2e3ebdSchin mp->flags = mp->disc->flags;
2364da2e3ebdSchin mp->mime = 0;
2365da2e3ebdSchin if (!st)
2366da2e3ebdSchin s = T("cannot stat");
2367da2e3ebdSchin else
2368da2e3ebdSchin {
2369da2e3ebdSchin if (mp->fp = fp)
2370da2e3ebdSchin off = sfseek(mp->fp, (off_t)0, SEEK_CUR);
2371da2e3ebdSchin s = type(mp, file, st, mp->tbuf, sizeof(mp->tbuf));
2372da2e3ebdSchin if (mp->fp)
2373da2e3ebdSchin sfseek(mp->fp, off, SEEK_SET);
2374da2e3ebdSchin if (!(mp->flags & MAGIC_MIME))
2375da2e3ebdSchin {
2376da2e3ebdSchin if (S_ISREG(st->st_mode) && (st->st_size > 0) && (st->st_size < 128))
2377da2e3ebdSchin sfprintf(mp->tmp, "%s ", T("short"));
2378da2e3ebdSchin sfprintf(mp->tmp, "%s", s);
2379da2e3ebdSchin if (!mp->fp && (st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
2380da2e3ebdSchin sfprintf(mp->tmp, ", %s", S_ISDIR(st->st_mode) ? T("searchable") : T("executable"));
2381da2e3ebdSchin if (st->st_mode & S_ISUID)
2382da2e3ebdSchin sfprintf(mp->tmp, ", setuid=%s", fmtuid(st->st_uid));
2383da2e3ebdSchin if (st->st_mode & S_ISGID)
2384da2e3ebdSchin sfprintf(mp->tmp, ", setgid=%s", fmtgid(st->st_gid));
2385da2e3ebdSchin if (st->st_mode & S_ISVTX)
2386da2e3ebdSchin sfprintf(mp->tmp, ", sticky");
2387da2e3ebdSchin if (!(s = sfstruse(mp->tmp)))
2388da2e3ebdSchin s = T("out of space");
2389da2e3ebdSchin }
2390da2e3ebdSchin }
2391da2e3ebdSchin if (mp->flags & MAGIC_MIME)
2392da2e3ebdSchin s = mp->mime;
2393da2e3ebdSchin if (!s)
2394da2e3ebdSchin s = T("error");
2395da2e3ebdSchin return s;
2396da2e3ebdSchin }
2397da2e3ebdSchin
2398da2e3ebdSchin /*
2399da2e3ebdSchin * list the magic table in mp on sp
2400da2e3ebdSchin */
2401da2e3ebdSchin
2402da2e3ebdSchin int
magiclist(register Magic_t * mp,register Sfio_t * sp)2403da2e3ebdSchin magiclist(register Magic_t* mp, register Sfio_t* sp)
2404da2e3ebdSchin {
2405da2e3ebdSchin register Entry_t* ep = mp->magic;
2406da2e3ebdSchin register Entry_t* rp = 0;
2407da2e3ebdSchin
2408da2e3ebdSchin mp->flags = mp->disc->flags;
2409da2e3ebdSchin sfprintf(sp, "cont\toffset\ttype\top\tmask\tvalue\tmime\tdesc\n");
2410da2e3ebdSchin while (ep)
2411da2e3ebdSchin {
2412da2e3ebdSchin sfprintf(sp, "%c %c\t", ep->cont, ep->nest);
2413da2e3ebdSchin if (ep->expr)
2414da2e3ebdSchin sfprintf(sp, "%s", ep->expr);
2415da2e3ebdSchin else
2416da2e3ebdSchin sfprintf(sp, "%ld", ep->offset);
2417da2e3ebdSchin sfprintf(sp, "\t%s%c\t%c\t%lo\t", ep->swap == (char)~3 ? "L" : ep->swap == (char)~0 ? "B" : "", ep->type, ep->op, ep->mask);
2418da2e3ebdSchin switch (ep->type)
2419da2e3ebdSchin {
2420da2e3ebdSchin case 'm':
2421da2e3ebdSchin case 's':
2422da2e3ebdSchin sfputr(sp, fmtesc(ep->value.str), -1);
2423da2e3ebdSchin break;
2424da2e3ebdSchin case 'V':
2425da2e3ebdSchin switch (ep->op)
2426da2e3ebdSchin {
2427da2e3ebdSchin case 'l':
2428da2e3ebdSchin sfprintf(sp, "loop(%d,%d,%d,%d)", ep->value.loop->start, ep->value.loop->size, ep->value.loop->count, ep->value.loop->offset);
2429da2e3ebdSchin break;
2430da2e3ebdSchin case 'v':
2431da2e3ebdSchin sfprintf(sp, "vcodex()");
2432da2e3ebdSchin break;
2433da2e3ebdSchin default:
2434da2e3ebdSchin sfprintf(sp, "%p", ep->value.str);
2435da2e3ebdSchin break;
2436da2e3ebdSchin }
2437da2e3ebdSchin break;
2438da2e3ebdSchin default:
2439da2e3ebdSchin sfprintf(sp, "%lo", ep->value.num);
2440da2e3ebdSchin break;
2441da2e3ebdSchin }
2442da2e3ebdSchin sfprintf(sp, "\t%s\t%s\n", ep->mime ? ep->mime : "", fmtesc(ep->desc));
2443da2e3ebdSchin if (ep->cont == '$' && !ep->value.lab->mask)
2444da2e3ebdSchin {
2445da2e3ebdSchin rp = ep;
2446da2e3ebdSchin ep = ep->value.lab;
2447da2e3ebdSchin }
2448da2e3ebdSchin else
2449da2e3ebdSchin {
2450da2e3ebdSchin if (ep->cont == ':')
2451da2e3ebdSchin {
2452da2e3ebdSchin ep = rp;
2453da2e3ebdSchin ep->value.lab->mask = 1;
2454da2e3ebdSchin }
2455da2e3ebdSchin ep = ep->next;
2456da2e3ebdSchin }
2457da2e3ebdSchin }
2458da2e3ebdSchin return 0;
2459da2e3ebdSchin }
2460