14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * Phong Vo <kpv@research.att.com> *
204887Schin * *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin * Glenn Fowler
254887Schin * AT&T Research
264887Schin *
274887Schin * library interface to file
284887Schin *
294887Schin * the sum of the hacks {s5,v10,planix} is _____ than the parts
304887Schin */
314887Schin
328462SApril.Chin@Sun.COM static const char id[] = "\n@(#)$Id: magic library (AT&T Research) 2008-09-10 $\0\n";
334887Schin
344887Schin static const char lib[] = "libast:magic";
354887Schin
364887Schin #include <ast.h>
374887Schin #include <ctype.h>
384887Schin #include <ccode.h>
394887Schin #include <dt.h>
404887Schin #include <modex.h>
414887Schin #include <error.h>
424887Schin #include <regex.h>
434887Schin #include <swap.h>
444887Schin
454887Schin #define T(m) (*m?ERROR_translate(NiL,NiL,lib,m):m)
464887Schin
474887Schin #define match(s,p) strgrpmatch(s,p,NiL,0,STR_LEFT|STR_RIGHT|STR_ICASE)
484887Schin
494887Schin #define MAXNEST 10 /* { ... } nesting limit */
504887Schin #define MINITEM 4 /* magic buffer rounding */
514887Schin
524887Schin typedef struct /* identifier dictionary entry */
534887Schin {
544887Schin const char name[16]; /* identifier name */
554887Schin int value; /* identifier value */
564887Schin Dtlink_t link; /* dictionary link */
574887Schin } Info_t;
584887Schin
594887Schin typedef struct Edit /* edit substitution */
604887Schin {
614887Schin struct Edit* next; /* next in list */
624887Schin regex_t* from; /* from pattern */
634887Schin } Edit_t;
644887Schin
654887Schin struct Entry;
664887Schin
674887Schin typedef struct /* loop info */
684887Schin {
694887Schin struct Entry* lab; /* call this function */
704887Schin int start; /* start here */
714887Schin int size; /* increment by this amount */
724887Schin int count; /* dynamic loop count */
734887Schin int offset; /* dynamic offset */
744887Schin } Loop_t;
754887Schin
764887Schin typedef struct Entry /* magic file entry */
774887Schin {
784887Schin struct Entry* next; /* next in list */
794887Schin char* expr; /* offset expression */
804887Schin union
814887Schin {
824887Schin unsigned long num;
834887Schin char* str;
844887Schin struct Entry* lab;
854887Schin regex_t* sub;
864887Schin Loop_t* loop;
874887Schin } value; /* comparison value */
884887Schin char* desc; /* file description */
894887Schin char* mime; /* file mime type */
904887Schin unsigned long offset; /* offset in bytes */
914887Schin unsigned long mask; /* mask before compare */
924887Schin char cont; /* continuation operation */
934887Schin char type; /* datum type */
944887Schin char op; /* comparison operation */
954887Schin char nest; /* { or } nesting operation */
964887Schin char swap; /* forced swap order */
974887Schin } Entry_t;
984887Schin
994887Schin #define CC_BIT 5
1004887Schin
1014887Schin #if (CC_MAPS*CC_BIT) <= (CHAR_BIT*2)
1024887Schin typedef unsigned short Cctype_t;
1034887Schin #else
1044887Schin typedef unsigned long Cctype_t;
1054887Schin #endif
1064887Schin
1074887Schin #define CC_text 0x01
1084887Schin #define CC_control 0x02
1094887Schin #define CC_latin 0x04
1104887Schin #define CC_binary 0x08
1114887Schin #define CC_utf_8 0x10
1124887Schin
1134887Schin #define CC_notext CC_text /* CC_text is flipped before checking */
1144887Schin
1154887Schin #define CC_MASK (CC_binary|CC_latin|CC_control|CC_text)
1164887Schin
1174887Schin #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)
1184887Schin
1194887Schin #define ID_NONE 0
1204887Schin #define ID_ASM 1
1214887Schin #define ID_C 2
1224887Schin #define ID_COBOL 3
1234887Schin #define ID_COPYBOOK 4
1244887Schin #define ID_CPLUSPLUS 5
1254887Schin #define ID_FORTRAN 6
1264887Schin #define ID_HTML 7
1274887Schin #define ID_INCL1 8
1284887Schin #define ID_INCL2 9
1294887Schin #define ID_INCL3 10
1304887Schin #define ID_MAM1 11
1314887Schin #define ID_MAM2 12
1324887Schin #define ID_MAM3 13
1334887Schin #define ID_NOTEXT 14
1344887Schin #define ID_PL1 15
1354887Schin #define ID_YACC 16
1364887Schin
1374887Schin #define ID_MAX ID_YACC
1384887Schin
1394887Schin #define INFO_atime 1
1404887Schin #define INFO_blocks 2
1414887Schin #define INFO_ctime 3
1424887Schin #define INFO_fstype 4
1434887Schin #define INFO_gid 5
1444887Schin #define INFO_mode 6
1454887Schin #define INFO_mtime 7
1464887Schin #define INFO_name 8
1474887Schin #define INFO_nlink 9
1484887Schin #define INFO_size 10
1494887Schin #define INFO_uid 11
1504887Schin
1514887Schin #define _MAGIC_PRIVATE_ \
1524887Schin Magicdisc_t* disc; /* discipline */ \
1534887Schin Vmalloc_t* vm; /* vmalloc region */ \
1544887Schin Entry_t* magic; /* parsed magic table */ \
1554887Schin Entry_t* magiclast; /* last entry in magic */ \
1564887Schin char* mime; /* MIME type */ \
1574887Schin unsigned char* x2n; /* CC_ALIEN=>CC_NATIVE */ \
1584887Schin char fbuf[SF_BUFSIZE + 1]; /* file data */ \
1594887Schin char xbuf[SF_BUFSIZE + 1]; /* indirect file data */ \
1604887Schin char nbuf[256]; /* !CC_NATIVE data */ \
1614887Schin char mbuf[64]; /* mime string */ \
1624887Schin char sbuf[64]; /* type suffix string */ \
1634887Schin char tbuf[2 * PATH_MAX]; /* type string */ \
1644887Schin Cctype_t cctype[UCHAR_MAX + 1]; /* char code types */ \
1654887Schin unsigned int count[UCHAR_MAX + 1]; /* char frequency count */ \
1664887Schin unsigned int multi[UCHAR_MAX + 1]; /* muti char count */ \
1674887Schin int keep[MAXNEST]; /* ckmagic nest stack */ \
1684887Schin char* cap[MAXNEST]; /* ckmagic mime stack */ \
1694887Schin char* msg[MAXNEST]; /* ckmagic text stack */ \
1704887Schin Entry_t* ret[MAXNEST]; /* ckmagic return stack */ \
1714887Schin int fbsz; /* fbuf size */ \
1724887Schin int fbmx; /* fbuf max size */ \
1734887Schin int xbsz; /* xbuf size */ \
1744887Schin int swap; /* swap() operation */ \
1754887Schin unsigned long flags; /* disc+open flags */ \
1764887Schin long xoff; /* xbuf offset */ \
1774887Schin int identifier[ID_MAX + 1]; /* Info_t identifier */ \
1784887Schin Sfio_t* fp; /* fbuf fp */ \
1794887Schin Sfio_t* tmp; /* tmp string */ \
1804887Schin regdisc_t redisc; /* regex discipline */ \
1814887Schin Dtdisc_t dtdisc; /* dict discipline */ \
1824887Schin Dt_t* idtab; /* identifier dict */ \
1834887Schin Dt_t* infotab; /* info keyword dict */
1844887Schin
1854887Schin #include <magic.h>
1864887Schin
1874887Schin static Info_t dict[] = /* keyword dictionary */
1884887Schin {
1894887Schin { "COMMON", ID_FORTRAN },
1904887Schin { "COMPUTE", ID_COBOL },
1914887Schin { "COMP", ID_COPYBOOK },
1924887Schin { "COMPUTATIONAL",ID_COPYBOOK },
1934887Schin { "DCL", ID_PL1 },
1944887Schin { "DEFINED", ID_PL1 },
1954887Schin { "DIMENSION", ID_FORTRAN },
1964887Schin { "DIVISION", ID_COBOL },
1974887Schin { "FILLER", ID_COPYBOOK },
1984887Schin { "FIXED", ID_PL1 },
1994887Schin { "FUNCTION", ID_FORTRAN },
2004887Schin { "HTML", ID_HTML },
2014887Schin { "INTEGER", ID_FORTRAN },
2024887Schin { "MAIN", ID_PL1 },
2034887Schin { "OPTIONS", ID_PL1 },
2044887Schin { "PERFORM", ID_COBOL },
2054887Schin { "PIC", ID_COPYBOOK },
2064887Schin { "REAL", ID_FORTRAN },
2074887Schin { "REDEFINES", ID_COPYBOOK },
2084887Schin { "S9", ID_COPYBOOK },
2094887Schin { "SECTION", ID_COBOL },
2104887Schin { "SELECT", ID_COBOL },
2114887Schin { "SUBROUTINE", ID_FORTRAN },
2124887Schin { "TEXT", ID_ASM },
2134887Schin { "VALUE", ID_COPYBOOK },
2144887Schin { "attr", ID_MAM3 },
2154887Schin { "binary", ID_YACC },
2164887Schin { "block", ID_FORTRAN },
2174887Schin { "bss", ID_ASM },
2184887Schin { "byte", ID_ASM },
2194887Schin { "char", ID_C },
2204887Schin { "class", ID_CPLUSPLUS },
2214887Schin { "clr", ID_NOTEXT },
2224887Schin { "comm", ID_ASM },
2234887Schin { "common", ID_FORTRAN },
2244887Schin { "data", ID_ASM },
2254887Schin { "dimension", ID_FORTRAN },
2264887Schin { "done", ID_MAM2 },
2274887Schin { "double", ID_C },
2284887Schin { "even", ID_ASM },
2294887Schin { "exec", ID_MAM3 },
2304887Schin { "extern", ID_C },
2314887Schin { "float", ID_C },
2324887Schin { "function", ID_FORTRAN },
2334887Schin { "globl", ID_ASM },
2344887Schin { "h", ID_INCL3 },
2354887Schin { "html", ID_HTML },
2364887Schin { "include", ID_INCL1 },
2374887Schin { "int", ID_C },
2384887Schin { "integer", ID_FORTRAN },
2394887Schin { "jmp", ID_NOTEXT },
2404887Schin { "left", ID_YACC },
2414887Schin { "libc", ID_INCL2 },
2424887Schin { "long", ID_C },
2434887Schin { "make", ID_MAM1 },
2444887Schin { "mov", ID_NOTEXT },
2454887Schin { "private", ID_CPLUSPLUS },
2464887Schin { "public", ID_CPLUSPLUS },
2474887Schin { "real", ID_FORTRAN },
2484887Schin { "register", ID_C },
2494887Schin { "right", ID_YACC },
2504887Schin { "sfio", ID_INCL2 },
2514887Schin { "static", ID_C },
2524887Schin { "stdio", ID_INCL2 },
2534887Schin { "struct", ID_C },
2544887Schin { "subroutine", ID_FORTRAN },
2554887Schin { "sys", ID_NOTEXT },
2564887Schin { "term", ID_YACC },
2574887Schin { "text", ID_ASM },
2584887Schin { "tst", ID_NOTEXT },
2594887Schin { "type", ID_YACC },
2604887Schin { "typedef", ID_C },
2614887Schin { "u", ID_INCL2 },
2624887Schin { "union", ID_YACC },
2634887Schin { "void", ID_C },
2644887Schin };
2654887Schin
2664887Schin static Info_t info[] =
2674887Schin {
2684887Schin { "atime", INFO_atime },
2694887Schin { "blocks", INFO_blocks },
2704887Schin { "ctime", INFO_ctime },
2714887Schin { "fstype", INFO_fstype },
2724887Schin { "gid", INFO_gid },
2734887Schin { "mode", INFO_mode },
2744887Schin { "mtime", INFO_mtime },
2754887Schin { "name", INFO_name },
2764887Schin { "nlink", INFO_nlink },
2774887Schin { "size", INFO_size },
2784887Schin { "uid", INFO_uid },
2794887Schin };
2804887Schin
2814887Schin /*
2824887Schin * return pointer to data at offset off and size siz
2834887Schin */
2844887Schin
2854887Schin static char*
getdata(register Magic_t * mp,register long off,register int siz)2864887Schin getdata(register Magic_t* mp, register long off, register int siz)
2874887Schin {
2884887Schin register long n;
2894887Schin
2904887Schin if (off < 0)
2914887Schin return 0;
2924887Schin if (off + siz <= mp->fbsz)
2934887Schin return mp->fbuf + off;
2944887Schin if (off < mp->xoff || off + siz > mp->xoff + mp->xbsz)
2954887Schin {
2964887Schin if (off + siz > mp->fbmx)
2974887Schin return 0;
2984887Schin n = (off / (SF_BUFSIZE / 2)) * (SF_BUFSIZE / 2);
2994887Schin if (sfseek(mp->fp, n, SEEK_SET) != n)
3004887Schin return 0;
3014887Schin if ((mp->xbsz = sfread(mp->fp, mp->xbuf, sizeof(mp->xbuf) - 1)) < 0)
3024887Schin {
3034887Schin mp->xoff = 0;
3044887Schin mp->xbsz = 0;
3054887Schin return 0;
3064887Schin }
3074887Schin mp->xbuf[mp->xbsz] = 0;
3084887Schin mp->xoff = n;
3094887Schin if (off + siz > mp->xoff + mp->xbsz)
3104887Schin return 0;
3114887Schin }
3124887Schin return mp->xbuf + off - mp->xoff;
3134887Schin }
3144887Schin
3154887Schin /*
3164887Schin * @... evaluator for strexpr()
3174887Schin */
3184887Schin
3194887Schin static long
indirect(const char * cs,char ** e,void * handle)3204887Schin indirect(const char* cs, char** e, void* handle)
3214887Schin {
3224887Schin register char* s = (char*)cs;
3234887Schin register Magic_t* mp = (Magic_t*)handle;
3244887Schin register long n = 0;
3254887Schin register char* p;
3264887Schin
3274887Schin if (s)
3284887Schin {
3294887Schin if (*s == '@')
3304887Schin {
3314887Schin n = *++s == '(' ? strexpr(s, e, indirect, mp) : strtol(s, e, 0);
3324887Schin switch (*(s = *e))
3334887Schin {
3344887Schin case 'b':
3354887Schin case 'B':
3364887Schin s++;
3374887Schin if (p = getdata(mp, n, 1))
3384887Schin n = *(unsigned char*)p;
3394887Schin else
3404887Schin s = (char*)cs;
3414887Schin break;
3424887Schin case 'h':
3434887Schin case 'H':
3444887Schin s++;
3454887Schin if (p = getdata(mp, n, 2))
3464887Schin n = swapget(mp->swap, p, 2);
3474887Schin else
3484887Schin s = (char*)cs;
3494887Schin break;
3504887Schin case 'q':
3514887Schin case 'Q':
3524887Schin s++;
3534887Schin if (p = getdata(mp, n, 8))
3544887Schin n = swapget(mp->swap, p, 8);
3554887Schin else
3564887Schin s = (char*)cs;
3574887Schin break;
3584887Schin default:
3594887Schin if (isalnum(*s))
3604887Schin s++;
3614887Schin if (p = getdata(mp, n, 4))
3624887Schin n = swapget(mp->swap, p, 4);
3634887Schin else
3644887Schin s = (char*)cs;
3654887Schin break;
3664887Schin }
3674887Schin }
3684887Schin *e = s;
3694887Schin }
3704887Schin else if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
3714887Schin (*mp->disc->errorf)(mp, mp->disc, 2, "%s in indirect expression", *e);
3724887Schin return n;
3734887Schin }
3744887Schin
3754887Schin /*
3764887Schin * emit regex error message
3774887Schin */
3784887Schin
3794887Schin static void
regmessage(Magic_t * mp,regex_t * re,int code)3804887Schin regmessage(Magic_t* mp, regex_t* re, int code)
3814887Schin {
3824887Schin char buf[128];
3834887Schin
3844887Schin if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
3854887Schin {
3864887Schin regerror(code, re, buf, sizeof(buf));
3874887Schin (*mp->disc->errorf)(mp, mp->disc, 3, "regex: %s", buf);
3884887Schin }
3894887Schin }
3904887Schin
3914887Schin /*
3924887Schin * decompose vcodex(3) method composition
3934887Schin */
3944887Schin
3954887Schin static char*
vcdecomp(char * b,char * e,unsigned char * m,unsigned char * x)3964887Schin vcdecomp(char* b, char* e, unsigned char* m, unsigned char* x)
3974887Schin {
3984887Schin unsigned char* map;
3998462SApril.Chin@Sun.COM const char* o;
4004887Schin int c;
4014887Schin int n;
4024887Schin int i;
4038462SApril.Chin@Sun.COM int a;
4044887Schin
4054887Schin map = CCMAP(CC_ASCII, CC_NATIVE);
4068462SApril.Chin@Sun.COM a = 0;
4074887Schin i = 1;
4084887Schin for (;;)
4094887Schin {
4104887Schin if (i)
4114887Schin i = 0;
4124887Schin else
4134887Schin *b++ = '^';
4148462SApril.Chin@Sun.COM if (m < (x - 1) && !*(m + 1))
4154887Schin {
4168462SApril.Chin@Sun.COM /*
4178462SApril.Chin@Sun.COM * obsolete indices
4188462SApril.Chin@Sun.COM */
4198462SApril.Chin@Sun.COM
4208462SApril.Chin@Sun.COM if (!a)
4218462SApril.Chin@Sun.COM {
4228462SApril.Chin@Sun.COM a = 1;
4238462SApril.Chin@Sun.COM o = "old, ";
4248462SApril.Chin@Sun.COM while (b < e && (c = *o++))
4258462SApril.Chin@Sun.COM *b++ = c;
4268462SApril.Chin@Sun.COM }
4278462SApril.Chin@Sun.COM switch (*m)
4288462SApril.Chin@Sun.COM {
4298462SApril.Chin@Sun.COM case 0: o = "delta"; break;
4308462SApril.Chin@Sun.COM case 1: o = "huffman"; break;
4318462SApril.Chin@Sun.COM case 2: o = "huffgroup"; break;
4328462SApril.Chin@Sun.COM case 3: o = "arith"; break;
4338462SApril.Chin@Sun.COM case 4: o = "bwt"; break;
4348462SApril.Chin@Sun.COM case 5: o = "rle"; break;
4358462SApril.Chin@Sun.COM case 6: o = "mtf"; break;
4368462SApril.Chin@Sun.COM case 7: o = "transpose"; break;
4378462SApril.Chin@Sun.COM case 8: o = "table"; break;
4388462SApril.Chin@Sun.COM case 9: o = "huffpart"; break;
4398462SApril.Chin@Sun.COM case 50: o = "map"; break;
4408462SApril.Chin@Sun.COM case 100: o = "recfm"; break;
4418462SApril.Chin@Sun.COM case 101: o = "ss7"; break;
4428462SApril.Chin@Sun.COM default: o = "UNKNOWN"; break;
4438462SApril.Chin@Sun.COM }
4448462SApril.Chin@Sun.COM m += 2;
4458462SApril.Chin@Sun.COM while (b < e && (c = *o++))
4468462SApril.Chin@Sun.COM *b++ = c;
4474887Schin }
4488462SApril.Chin@Sun.COM else
4498462SApril.Chin@Sun.COM while (b < e && m < x && (c = *m++))
4508462SApril.Chin@Sun.COM {
4518462SApril.Chin@Sun.COM if (map)
4528462SApril.Chin@Sun.COM c = map[c];
4538462SApril.Chin@Sun.COM *b++ = c;
4548462SApril.Chin@Sun.COM }
4554887Schin if (b >= e)
4564887Schin break;
4574887Schin n = 0;
4584887Schin while (m < x)
4594887Schin {
4604887Schin n = (n<<7) | (*m & 0x7f);
4614887Schin if (!(*m++ & 0x80))
4624887Schin break;
4634887Schin }
4644887Schin if (n >= (x - m))
4654887Schin break;
4664887Schin m += n;
4674887Schin }
4684887Schin return b;
4694887Schin }
4704887Schin
4714887Schin /*
4724887Schin * check for magic table match in buf
4734887Schin */
4744887Schin
4754887Schin static char*
ckmagic(register Magic_t * mp,const char * file,char * buf,struct stat * st,unsigned long off)4764887Schin ckmagic(register Magic_t* mp, const char* file, char* buf, struct stat* st, unsigned long off)
4774887Schin {
4784887Schin register Entry_t* ep;
4794887Schin register char* p;
4804887Schin register char* b;
4814887Schin register int level = 0;
4824887Schin int call = -1;
4834887Schin int c;
4844887Schin char* q;
4854887Schin char* t;
4864887Schin char* base = 0;
4874887Schin unsigned long num;
4884887Schin unsigned long mask;
4894887Schin regmatch_t matches[10];
4904887Schin
4914887Schin mp->swap = 0;
4924887Schin b = mp->msg[0] = buf;
4934887Schin mp->mime = mp->cap[0] = 0;
4944887Schin mp->keep[0] = 0;
4954887Schin for (ep = mp->magic; ep; ep = ep->next)
4964887Schin {
4974887Schin fun:
4984887Schin if (ep->nest == '{')
4994887Schin {
5004887Schin if (++level >= MAXNEST)
5014887Schin {
5024887Schin call = -1;
5034887Schin level = 0;
5044887Schin mp->keep[0] = 0;
5054887Schin b = mp->msg[0];
5064887Schin mp->mime = mp->cap[0];
5074887Schin continue;
5084887Schin }
5094887Schin mp->keep[level] = mp->keep[level - 1] != 0;
5104887Schin mp->msg[level] = b;
5114887Schin mp->cap[level] = mp->mime;
5124887Schin }
5134887Schin switch (ep->cont)
5144887Schin {
5154887Schin case '#':
5164887Schin if (mp->keep[level] && b > buf)
5174887Schin {
5184887Schin *b = 0;
5194887Schin return buf;
5204887Schin }
5214887Schin mp->swap = 0;
5224887Schin b = mp->msg[0] = buf;
5234887Schin mp->mime = mp->cap[0] = 0;
5244887Schin if (ep->type == ' ')
5254887Schin continue;
5264887Schin break;
5274887Schin case '$':
5284887Schin if (mp->keep[level] && call < (MAXNEST - 1))
5294887Schin {
5304887Schin mp->ret[++call] = ep;
5314887Schin ep = ep->value.lab;
5324887Schin goto fun;
5334887Schin }
5344887Schin continue;
5354887Schin case ':':
5364887Schin ep = mp->ret[call--];
5374887Schin if (ep->op == 'l')
5384887Schin goto fun;
5394887Schin continue;
5404887Schin case '|':
5414887Schin if (mp->keep[level] > 1)
5424887Schin goto checknest;
5434887Schin /*FALLTHROUGH*/
5444887Schin default:
5454887Schin if (!mp->keep[level])
5464887Schin {
5474887Schin b = mp->msg[level];
5484887Schin mp->mime = mp->cap[level];
5494887Schin goto checknest;
5504887Schin }
5514887Schin break;
5524887Schin }
5538462SApril.Chin@Sun.COM p = "";
5548462SApril.Chin@Sun.COM num = 0;
5554887Schin if (!ep->expr)
5564887Schin num = ep->offset + off;
5574887Schin else
5584887Schin switch (ep->offset)
5594887Schin {
5604887Schin case 0:
5614887Schin num = strexpr(ep->expr, NiL, indirect, mp) + off;
5624887Schin break;
5634887Schin case INFO_atime:
5644887Schin num = st->st_atime;
5654887Schin ep->type = 'D';
5664887Schin break;
5674887Schin case INFO_blocks:
5684887Schin num = iblocks(st);
5694887Schin ep->type = 'N';
5704887Schin break;
5714887Schin case INFO_ctime:
5724887Schin num = st->st_ctime;
5734887Schin ep->type = 'D';
5744887Schin break;
5754887Schin case INFO_fstype:
5764887Schin p = fmtfs(st);
5774887Schin ep->type = toupper(ep->type);
5784887Schin break;
5794887Schin case INFO_gid:
5804887Schin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
5814887Schin {
5824887Schin p = fmtgid(st->st_gid);
5834887Schin ep->type = toupper(ep->type);
5844887Schin }
5854887Schin else
5864887Schin {
5874887Schin num = st->st_gid;
5884887Schin ep->type = 'N';
5894887Schin }
5904887Schin break;
5914887Schin case INFO_mode:
5924887Schin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
5934887Schin {
5944887Schin p = fmtmode(st->st_mode, 0);
5954887Schin ep->type = toupper(ep->type);
5964887Schin }
5974887Schin else
5984887Schin {
5994887Schin num = modex(st->st_mode);
6004887Schin ep->type = 'N';
6014887Schin }
6024887Schin break;
6034887Schin case INFO_mtime:
6044887Schin num = st->st_ctime;
6054887Schin ep->type = 'D';
6064887Schin break;
6074887Schin case INFO_name:
6084887Schin if (!base)
6094887Schin {
6104887Schin if (base = strrchr(file, '/'))
6114887Schin base++;
6124887Schin else
6134887Schin base = (char*)file;
6144887Schin }
6154887Schin p = base;
6164887Schin ep->type = toupper(ep->type);
6174887Schin break;
6184887Schin case INFO_nlink:
6194887Schin num = st->st_nlink;
6204887Schin ep->type = 'N';
6214887Schin break;
6224887Schin case INFO_size:
6234887Schin num = st->st_size;
6244887Schin ep->type = 'N';
6254887Schin break;
6264887Schin case INFO_uid:
6274887Schin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
6284887Schin {
6294887Schin p = fmtuid(st->st_uid);
6304887Schin ep->type = toupper(ep->type);
6314887Schin }
6324887Schin else
6334887Schin {
6344887Schin num = st->st_uid;
6354887Schin ep->type = 'N';
6364887Schin }
6374887Schin break;
6384887Schin }
6394887Schin switch (ep->type)
6404887Schin {
6414887Schin
6424887Schin case 'b':
6434887Schin if (!(p = getdata(mp, num, 1)))
6444887Schin goto next;
6454887Schin num = *(unsigned char*)p;
6464887Schin break;
6474887Schin
6484887Schin case 'h':
6494887Schin if (!(p = getdata(mp, num, 2)))
6504887Schin goto next;
6514887Schin num = swapget(ep->swap ? (~ep->swap ^ mp->swap) : mp->swap, p, 2);
6524887Schin break;
6534887Schin
6544887Schin case 'd':
6554887Schin case 'l':
6564887Schin case 'v':
6574887Schin if (!(p = getdata(mp, num, 4)))
6584887Schin goto next;
6594887Schin num = swapget(ep->swap ? (~ep->swap ^ mp->swap) : mp->swap, p, 4);
6604887Schin break;
6614887Schin
6624887Schin case 'q':
6634887Schin if (!(p = getdata(mp, num, 8)))
6644887Schin goto next;
6654887Schin num = swapget(ep->swap ? (~ep->swap ^ mp->swap) : mp->swap, p, 8);
6664887Schin break;
6674887Schin
6684887Schin case 'e':
6694887Schin if (!(p = getdata(mp, num, 0)))
6704887Schin goto next;
6714887Schin /*FALLTHROUGH*/
6724887Schin case 'E':
6734887Schin if (!ep->value.sub)
6744887Schin goto next;
6754887Schin if ((c = regexec(ep->value.sub, p, elementsof(matches), matches, 0)) || (c = regsubexec(ep->value.sub, p, elementsof(matches), matches)))
6764887Schin {
6774887Schin c = mp->fbsz;
6784887Schin if (c >= sizeof(mp->nbuf))
6794887Schin c = sizeof(mp->nbuf) - 1;
6804887Schin p = (char*)memcpy(mp->nbuf, p, c);
6814887Schin p[c] = 0;
6824887Schin ccmapstr(mp->x2n, p, c);
6834887Schin if ((c = regexec(ep->value.sub, p, elementsof(matches), matches, 0)) || (c = regsubexec(ep->value.sub, p, elementsof(matches), matches)))
6844887Schin {
6854887Schin if (c != REG_NOMATCH)
6864887Schin regmessage(mp, ep->value.sub, c);
6874887Schin goto next;
6884887Schin }
6894887Schin }
6904887Schin p = ep->value.sub->re_sub->re_buf;
6914887Schin q = T(ep->desc);
6924887Schin t = *q ? q : p;
6934887Schin if (mp->keep[level]++ && b > buf && *(b - 1) != ' ' && *t && *t != ',' && *t != '.' && *t != '\b')
6944887Schin *b++ = ' ';
6954887Schin b += sfsprintf(b, PATH_MAX - (b - buf), *q ? q : "%s", p + (*p == '\b'));
6964887Schin if (ep->mime)
6974887Schin mp->mime = ep->mime;
6984887Schin goto checknest;
6994887Schin
7004887Schin case 's':
7014887Schin if (!(p = getdata(mp, num, ep->mask)))
7024887Schin goto next;
7034887Schin goto checkstr;
7044887Schin case 'm':
7054887Schin if (!(p = getdata(mp, num, 0)))
7064887Schin goto next;
7074887Schin /*FALLTHROUGH*/
7084887Schin case 'M':
7094887Schin case 'S':
7104887Schin checkstr:
7114887Schin for (;;)
7124887Schin {
7134887Schin if (*ep->value.str == '*' && !*(ep->value.str + 1) && isprint(*p))
7144887Schin break;
7154887Schin if ((ep->type == 'm' || ep->type == 'M') ? strmatch(p, ep->value.str) : !memcmp(p, ep->value.str, ep->mask))
7164887Schin break;
7174887Schin if (p == mp->nbuf || ep->mask >= sizeof(mp->nbuf))
7184887Schin goto next;
7194887Schin p = (char*)memcpy(mp->nbuf, p, ep->mask);
7204887Schin p[ep->mask] = 0;
7214887Schin ccmapstr(mp->x2n, p, ep->mask);
7224887Schin }
7234887Schin q = T(ep->desc);
7244887Schin if (mp->keep[level]++ && b > buf && *(b - 1) != ' ' && *q && *q != ',' && *q != '.' && *q != '\b')
7254887Schin *b++ = ' ';
7264887Schin for (t = p; (c = *t) >= 0 && c <= 0177 && isprint(c) && c != '\n'; t++);
7274887Schin *t = 0;
7284887Schin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), p);
7294887Schin *t = c;
7304887Schin if (ep->mime)
7314887Schin mp->mime = ep->mime;
7324887Schin goto checknest;
7334887Schin
7344887Schin }
7354887Schin if (mask = ep->mask)
7364887Schin num &= mask;
7374887Schin switch (ep->op)
7384887Schin {
7394887Schin
7404887Schin case '=':
7414887Schin case '@':
7424887Schin if (num == ep->value.num)
7434887Schin break;
7444887Schin if (ep->cont != '#')
7454887Schin goto next;
7464887Schin if (!mask)
7474887Schin mask = ~mask;
7484887Schin if (ep->type == 'h')
7494887Schin {
7504887Schin if ((num = swapget(mp->swap = 1, p, 2) & mask) == ep->value.num)
7514887Schin {
7524887Schin if (!(mp->swap & (mp->swap + 1)))
7534887Schin mp->swap = 7;
7544887Schin goto swapped;
7554887Schin }
7564887Schin }
7574887Schin else if (ep->type == 'l')
7584887Schin {
7594887Schin for (c = 1; c < 4; c++)
7604887Schin if ((num = swapget(mp->swap = c, p, 4) & mask) == ep->value.num)
7614887Schin {
7624887Schin if (!(mp->swap & (mp->swap + 1)))
7634887Schin mp->swap = 7;
7644887Schin goto swapped;
7654887Schin }
7664887Schin }
7674887Schin else if (ep->type == 'q')
7684887Schin {
7694887Schin for (c = 1; c < 8; c++)
7704887Schin if ((num = swapget(mp->swap = c, p, 8) & mask) == ep->value.num)
7714887Schin goto swapped;
7724887Schin }
7734887Schin goto next;
7744887Schin
7754887Schin case '!':
7764887Schin if (num != ep->value.num)
7774887Schin break;
7784887Schin goto next;
7794887Schin
7804887Schin case '^':
7814887Schin if (num ^ ep->value.num)
7824887Schin break;
7834887Schin goto next;
7844887Schin
7854887Schin case '>':
7864887Schin if (num > ep->value.num)
7874887Schin break;
7884887Schin goto next;
7894887Schin
7904887Schin case '<':
7914887Schin if (num < ep->value.num)
7924887Schin break;
7934887Schin goto next;
7944887Schin
7954887Schin case 'l':
7964887Schin if (num > 0 && mp->keep[level] && call < (MAXNEST - 1))
7974887Schin {
7984887Schin if (!ep->value.loop->count)
7994887Schin {
8004887Schin ep->value.loop->count = num;
8014887Schin ep->value.loop->offset = off;
8024887Schin off = ep->value.loop->start;
8034887Schin }
8044887Schin else if (!--ep->value.loop->count)
8054887Schin {
8064887Schin off = ep->value.loop->offset;
8074887Schin goto next;
8084887Schin }
8094887Schin else
8104887Schin off += ep->value.loop->size;
8114887Schin mp->ret[++call] = ep;
8124887Schin ep = ep->value.loop->lab;
8134887Schin goto fun;
8144887Schin }
8154887Schin goto next;
8164887Schin
8174887Schin case 'm':
8184887Schin c = mp->swap;
8194887Schin t = ckmagic(mp, file, b + (b > buf), st, num);
8204887Schin mp->swap = c;
8214887Schin if (!t)
8224887Schin goto next;
8234887Schin if (b > buf)
8244887Schin *b = ' ';
8254887Schin b += strlen(b);
8264887Schin break;
8274887Schin
8284887Schin case 'r':
8294887Schin #if _UWIN
8304887Schin {
8314887Schin char* e;
8324887Schin Sfio_t* rp;
8334887Schin Sfio_t* gp;
8344887Schin
8354887Schin if (!(t = strrchr(file, '.')))
8364887Schin goto next;
8374887Schin sfprintf(mp->tmp, "/reg/classes_root/%s", t);
8384887Schin if (!(t = sfstruse(mp->tmp)) || !(rp = sfopen(NiL, t, "r")))
8394887Schin goto next;
8404887Schin *ep->desc = 0;
8414887Schin *ep->mime = 0;
8424887Schin gp = 0;
8434887Schin while (t = sfgetr(rp, '\n', 1))
8444887Schin {
8454887Schin if (strneq(t, "Content Type=", 13))
8464887Schin {
8474887Schin ep->mime = vmnewof(mp->vm, ep->mime, char, sfvalue(rp), 0);
8484887Schin strcpy(ep->mime, t + 13);
8494887Schin if (gp)
8504887Schin break;
8514887Schin }
8524887Schin else
8534887Schin {
8544887Schin sfprintf(mp->tmp, "/reg/classes_root/%s", t);
8554887Schin if ((e = sfstruse(mp->tmp)) && (gp = sfopen(NiL, e, "r")))
8564887Schin {
8574887Schin ep->desc = vmnewof(mp->vm, ep->desc, char, strlen(t), 1);
8584887Schin strcpy(ep->desc, t);
8594887Schin if (*ep->mime)
8604887Schin break;
8614887Schin }
8624887Schin }
8634887Schin }
8644887Schin sfclose(rp);
8654887Schin if (!gp)
8664887Schin goto next;
8674887Schin if (!*ep->mime)
8684887Schin {
8694887Schin t = T(ep->desc);
8704887Schin if (!strncasecmp(t, "microsoft", 9))
8714887Schin t += 9;
8724887Schin while (isspace(*t))
8734887Schin t++;
8744887Schin e = "application/x-ms-";
8754887Schin ep->mime = vmnewof(mp->vm, ep->mime, char, strlen(t), strlen(e));
8764887Schin e = strcopy(ep->mime, e);
8774887Schin while ((c = *t++) && c != '.' && c != ' ')
8784887Schin *e++ = isupper(c) ? tolower(c) : c;
8794887Schin *e = 0;
8804887Schin }
8814887Schin while (t = sfgetr(gp, '\n', 1))
8824887Schin if (*t && !streq(t, "\"\""))
8834887Schin {
8844887Schin ep->desc = vmnewof(mp->vm, ep->desc, char, sfvalue(gp), 0);
8854887Schin strcpy(ep->desc, t);
8864887Schin break;
8874887Schin }
8884887Schin sfclose(gp);
8894887Schin if (!*ep->desc)
8904887Schin goto next;
8914887Schin if (!t)
8924887Schin for (t = T(ep->desc); *t; t++)
8934887Schin if (*t == '.')
8944887Schin *t = ' ';
8954887Schin if (!mp->keep[level])
8964887Schin mp->keep[level] = 2;
8974887Schin mp->mime = ep->mime;
8984887Schin break;
8994887Schin }
9004887Schin #else
9014887Schin if (ep->cont == '#' && !mp->keep[level])
9024887Schin mp->keep[level] = 1;
9034887Schin goto next;
9044887Schin #endif
9054887Schin
9064887Schin case 'v':
9074887Schin if (!(p = getdata(mp, num, 4)))
9084887Schin goto next;
9094887Schin c = 0;
9104887Schin do
9114887Schin {
9124887Schin num++;
9134887Schin c = (c<<7) | (*p & 0x7f);
9144887Schin } while (*p++ & 0x80);
9154887Schin if (!(p = getdata(mp, num, c)))
9164887Schin goto next;
9174887Schin if (mp->keep[level]++ && b > buf && *(b - 1) != ' ')
9184887Schin {
9194887Schin *b++ = ',';
9204887Schin *b++ = ' ';
9214887Schin }
9224887Schin b = vcdecomp(b, buf + PATH_MAX, (unsigned char*)p, (unsigned char*)p + c);
9234887Schin goto checknest;
9244887Schin
9254887Schin }
9264887Schin swapped:
9274887Schin q = T(ep->desc);
9284887Schin if (mp->keep[level]++ && b > buf && *(b - 1) != ' ' && *q && *q != ',' && *q != '.' && *q != '\b')
9294887Schin *b++ = ' ';
9304887Schin if (ep->type == 'd' || ep->type == 'D')
9314887Schin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), fmttime("%?%l", (time_t)num));
9324887Schin else if (ep->type == 'v')
9334887Schin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), fmtversion(num));
9344887Schin else
9354887Schin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), num);
9364887Schin if (ep->mime && *ep->mime)
9374887Schin mp->mime = ep->mime;
9384887Schin checknest:
9394887Schin if (ep->nest == '}')
9404887Schin {
9414887Schin if (!mp->keep[level])
9424887Schin {
9434887Schin b = mp->msg[level];
9444887Schin mp->mime = mp->cap[level];
9454887Schin }
9464887Schin else if (level > 0)
9474887Schin mp->keep[level - 1] = mp->keep[level];
9484887Schin if (--level < 0)
9494887Schin {
9504887Schin level = 0;
9514887Schin mp->keep[0] = 0;
9524887Schin }
9534887Schin }
9544887Schin continue;
9554887Schin next:
9564887Schin if (ep->cont == '&')
9574887Schin mp->keep[level] = 0;
9584887Schin goto checknest;
9594887Schin }
9604887Schin if (mp->keep[level] && b > buf)
9614887Schin {
9624887Schin *b = 0;
9634887Schin return buf;
9644887Schin }
9654887Schin return 0;
9664887Schin }
9674887Schin
9684887Schin /*
9694887Schin * check english language stats
9704887Schin */
9714887Schin
9724887Schin static int
ckenglish(register Magic_t * mp,int pun,int badpun)9734887Schin ckenglish(register Magic_t* mp, int pun, int badpun)
9744887Schin {
9754887Schin register char* s;
9764887Schin register int vowl = 0;
9774887Schin register int freq = 0;
9784887Schin register int rare = 0;
9794887Schin
9804887Schin if (5 * badpun > pun)
9814887Schin return 0;
9824887Schin if (2 * mp->count[';'] > mp->count['E'] + mp->count['e'])
9834887Schin return 0;
9844887Schin if ((mp->count['>'] + mp->count['<'] + mp->count['/']) > mp->count['E'] + mp->count['e'])
9854887Schin return 0;
9864887Schin for (s = "aeiou"; *s; s++)
9874887Schin vowl += mp->count[toupper(*s)] + mp->count[*s];
9884887Schin for (s = "etaion"; *s; s++)
9894887Schin freq += mp->count[toupper(*s)] + mp->count[*s];
9904887Schin for (s = "vjkqxz"; *s; s++)
9914887Schin rare += mp->count[toupper(*s)] + mp->count[*s];
9924887Schin return 5 * vowl >= mp->fbsz - mp->count[' '] && freq >= 10 * rare;
9934887Schin }
9944887Schin
9954887Schin /*
9964887Schin * check programming language stats
9974887Schin */
9984887Schin
9994887Schin static char*
cklang(register Magic_t * mp,const char * file,char * buf,struct stat * st)10004887Schin cklang(register Magic_t* mp, const char* file, char* buf, struct stat* st)
10014887Schin {
10024887Schin register int c;
10034887Schin register unsigned char* b;
10044887Schin register unsigned char* e;
10054887Schin register int q;
10064887Schin register char* s;
10074887Schin char* t;
10084887Schin char* base;
10094887Schin char* suff;
10104887Schin char* t1;
10114887Schin char* t2;
10124887Schin char* t3;
10134887Schin int n;
10144887Schin int badpun;
10154887Schin int code;
10164887Schin int pun;
10174887Schin Cctype_t flags;
10184887Schin Info_t* ip;
10194887Schin
10204887Schin b = (unsigned char*)mp->fbuf;
10214887Schin e = b + mp->fbsz;
10224887Schin memzero(mp->count, sizeof(mp->count));
10234887Schin memzero(mp->multi, sizeof(mp->multi));
10244887Schin memzero(mp->identifier, sizeof(mp->identifier));
10254887Schin
10264887Schin /*
10274887Schin * check character coding
10284887Schin */
10294887Schin
10304887Schin flags = 0;
10314887Schin while (b < e)
10324887Schin flags |= mp->cctype[*b++];
10334887Schin b = (unsigned char*)mp->fbuf;
10344887Schin code = 0;
10354887Schin q = CC_ASCII;
10364887Schin n = CC_MASK;
10374887Schin for (c = 0; c < CC_MAPS; c++)
10384887Schin {
10394887Schin flags ^= CC_text;
10404887Schin if ((flags & CC_MASK) < n)
10414887Schin {
10424887Schin n = flags & CC_MASK;
10434887Schin q = c;
10444887Schin }
10454887Schin flags >>= CC_BIT;
10464887Schin }
10474887Schin flags = n;
10484887Schin if (!(flags & (CC_binary|CC_notext)))
10494887Schin {
10504887Schin if (q != CC_NATIVE)
10514887Schin {
10524887Schin code = q;
10534887Schin ccmaps(mp->fbuf, mp->fbsz, q, CC_NATIVE);
10544887Schin }
10554887Schin if (b[0] == '#' && b[1] == '!')
10564887Schin {
10574887Schin for (b += 2; b < e && isspace(*b); b++);
10584887Schin for (s = (char*)b; b < e && isprint(*b); b++);
10594887Schin c = *b;
10604887Schin *b = 0;
10614887Schin if ((st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) || match(s, "/*bin*/*") || !access(s, F_OK))
10624887Schin {
10634887Schin if (t = strrchr(s, '/'))
10644887Schin s = t + 1;
10654887Schin for (t = s; *t; t++)
10664887Schin if (isspace(*t))
10674887Schin {
10684887Schin *t = 0;
10694887Schin break;
10704887Schin }
10714887Schin sfsprintf(mp->mbuf, sizeof(mp->mbuf), "application/x-%s", *s ? s : "sh");
10724887Schin mp->mime = mp->mbuf;
10734887Schin if (match(s, "*sh"))
10744887Schin {
10754887Schin t1 = T("command");
10764887Schin if (streq(s, "sh"))
10774887Schin *s = 0;
10784887Schin else
10794887Schin {
10804887Schin *b++ = ' ';
10814887Schin *b = 0;
10824887Schin }
10834887Schin }
10844887Schin else
10854887Schin {
10864887Schin t1 = T("interpreter");
10874887Schin *b++ = ' ';
10884887Schin *b = 0;
10894887Schin }
10904887Schin sfsprintf(mp->sbuf, sizeof(mp->sbuf), T("%s%s script"), s, t1);
10914887Schin s = mp->sbuf;
10924887Schin goto qualify;
10934887Schin }
10944887Schin *b = c;
10954887Schin b = (unsigned char*)mp->fbuf;
10964887Schin }
10974887Schin badpun = 0;
10984887Schin pun = 0;
10994887Schin q = 0;
11004887Schin s = 0;
11014887Schin t = 0;
11024887Schin while (b < e)
11034887Schin {
11044887Schin c = *b++;
11054887Schin mp->count[c]++;
11064887Schin if (c == q && (q != '*' || *b == '/' && b++))
11074887Schin {
11084887Schin mp->multi[q]++;
11094887Schin q = 0;
11104887Schin }
11114887Schin else if (c == '\\')
11124887Schin {
11134887Schin s = 0;
11144887Schin b++;
11154887Schin }
11164887Schin else if (!q)
11174887Schin {
11184887Schin if (isalpha(c) || c == '_')
11194887Schin {
11204887Schin if (!s)
11214887Schin s = (char*)b - 1;
11224887Schin }
11234887Schin else if (!isdigit(c))
11244887Schin {
11254887Schin if (s)
11264887Schin {
11274887Schin if (s > mp->fbuf)
11284887Schin switch (*(s - 1))
11294887Schin {
11304887Schin case ':':
11314887Schin if (*b == ':')
11324887Schin mp->multi[':']++;
11334887Schin break;
11344887Schin case '.':
11354887Schin if (((char*)b - s) == 3 && (s == (mp->fbuf + 1) || *(s - 2) == '\n'))
11364887Schin mp->multi['.']++;
11374887Schin break;
11384887Schin case '\n':
11394887Schin case '\\':
11404887Schin if (*b == '{')
11414887Schin t = (char*)b + 1;
11424887Schin break;
11434887Schin case '{':
11444887Schin if (s == t && *b == '}')
11454887Schin mp->multi['X']++;
11464887Schin break;
11474887Schin }
11484887Schin if (!mp->idtab)
11494887Schin {
11504887Schin if (mp->idtab = dtnew(mp->vm, &mp->dtdisc, Dthash))
11514887Schin for (q = 0; q < elementsof(dict); q++)
11524887Schin dtinsert(mp->idtab, &dict[q]);
11534887Schin else if (mp->disc->errorf)
11544887Schin (*mp->disc->errorf)(mp, mp->disc, 3, "out of space");
11554887Schin q = 0;
11564887Schin }
11574887Schin if (mp->idtab)
11584887Schin {
11594887Schin *(b - 1) = 0;
11604887Schin if (ip = (Info_t*)dtmatch(mp->idtab, s))
11614887Schin mp->identifier[ip->value]++;
11624887Schin *(b - 1) = c;
11634887Schin }
11644887Schin s = 0;
11654887Schin }
11664887Schin switch (c)
11674887Schin {
11684887Schin case '\t':
11694887Schin if (b == (unsigned char*)(mp->fbuf + 1) || *(b - 2) == '\n')
11704887Schin mp->multi['\t']++;
11714887Schin break;
11724887Schin case '"':
11734887Schin case '\'':
11744887Schin q = c;
11754887Schin break;
11764887Schin case '/':
11774887Schin if (*b == '*')
11784887Schin q = *b++;
11794887Schin else if (*b == '/')
11804887Schin q = '\n';
11814887Schin break;
11824887Schin case '$':
11834887Schin if (*b == '(' && *(b + 1) != ' ')
11844887Schin mp->multi['$']++;
11854887Schin break;
11864887Schin case '{':
11874887Schin case '}':
11884887Schin case '[':
11894887Schin case ']':
11904887Schin case '(':
11914887Schin mp->multi[c]++;
11924887Schin break;
11934887Schin case ')':
11944887Schin mp->multi[c]++;
11954887Schin goto punctuation;
11964887Schin case ':':
11974887Schin if (*b == ':' && isspace(*(b + 1)) && b > (unsigned char*)(mp->fbuf + 1) && isspace(*(b - 2)))
11984887Schin mp->multi[':']++;
11994887Schin goto punctuation;
12004887Schin case '.':
12014887Schin case ',':
12024887Schin case '%':
12034887Schin case ';':
12044887Schin case '?':
12054887Schin punctuation:
12064887Schin pun++;
12074887Schin if (*b != ' ' && *b != '\n')
12084887Schin badpun++;
12094887Schin break;
12104887Schin }
12114887Schin }
12124887Schin }
12134887Schin }
12144887Schin }
12154887Schin else
12164887Schin while (b < e)
12174887Schin mp->count[*b++]++;
12184887Schin base = (t1 = strrchr(file, '/')) ? t1 + 1 : (char*)file;
12194887Schin suff = (t1 = strrchr(base, '.')) ? t1 + 1 : "";
12204887Schin if (!flags)
12214887Schin {
12224887Schin if (match(suff, "*sh|bat|cmd"))
12234887Schin goto id_sh;
12244887Schin if (match(base, "*@(mkfile)"))
12254887Schin goto id_mk;
12264887Schin if (match(base, "*@(makefile|.mk)"))
12274887Schin goto id_make;
12284887Schin if (match(base, "*@(mamfile|.mam)"))
12294887Schin goto id_mam;
12304887Schin if (match(suff, "[cly]?(pp|xx|++)|cc|ll|yy"))
12314887Schin goto id_c;
12324887Schin if (match(suff, "f"))
12334887Schin goto id_fortran;
12344887Schin if (match(suff, "htm+(l)"))
12354887Schin goto id_html;
12364887Schin if (match(suff, "cpy"))
12374887Schin goto id_copybook;
12384887Schin if (match(suff, "cob|cbl|cb2"))
12394887Schin goto id_cobol;
12404887Schin if (match(suff, "pl[1i]"))
12414887Schin goto id_pl1;
12424887Schin if (match(suff, "tex"))
12434887Schin goto id_tex;
12444887Schin if (match(suff, "asm|s"))
12454887Schin goto id_asm;
12464887Schin if ((st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) && (!suff || suff != strchr(suff, '.')))
12474887Schin {
12484887Schin id_sh:
12494887Schin s = T("command script");
12504887Schin mp->mime = "application/sh";
12514887Schin goto qualify;
12524887Schin }
12534887Schin if (strmatch(mp->fbuf, "From * [0-9][0-9]:[0-9][0-9]:[0-9][0-9] *"))
12544887Schin {
12554887Schin s = T("mail message");
12564887Schin mp->mime = "message/rfc822";
12574887Schin goto qualify;
12584887Schin }
12594887Schin if (match(base, "*@(mkfile)"))
12604887Schin {
12614887Schin id_mk:
12624887Schin s = "mkfile";
12634887Schin mp->mime = "application/mk";
12644887Schin goto qualify;
12654887Schin }
12664887Schin if (match(base, "*@(makefile|.mk)") || mp->multi['\t'] >= mp->count[':'] && (mp->multi['$'] > 0 || mp->multi[':'] > 0))
12674887Schin {
12684887Schin id_make:
12694887Schin s = "makefile";
12704887Schin mp->mime = "application/make";
12714887Schin goto qualify;
12724887Schin }
12734887Schin if (mp->multi['.'] >= 3)
12744887Schin {
12754887Schin s = T("nroff input");
12764887Schin mp->mime = "application/x-troff";
12774887Schin goto qualify;
12784887Schin }
12794887Schin if (mp->multi['X'] >= 3)
12804887Schin {
12814887Schin s = T("TeX input");
12824887Schin mp->mime = "application/x-tex";
12834887Schin goto qualify;
12844887Schin }
12854887Schin if (mp->fbsz < SF_BUFSIZE &&
12864887Schin (mp->multi['('] == mp->multi[')'] &&
12874887Schin mp->multi['{'] == mp->multi['}'] &&
12884887Schin mp->multi['['] == mp->multi[']']) ||
12894887Schin mp->fbsz >= SF_BUFSIZE &&
12904887Schin (mp->multi['('] >= mp->multi[')'] &&
12914887Schin mp->multi['{'] >= mp->multi['}'] &&
12924887Schin mp->multi['['] >= mp->multi[']']))
12934887Schin {
12944887Schin c = mp->identifier[ID_INCL1];
12954887Schin if (c >= 2 && mp->identifier[ID_INCL2] >= c && mp->identifier[ID_INCL3] >= c && mp->count['.'] >= c ||
12964887Schin mp->identifier[ID_C] >= 5 && mp->count[';'] >= 5 ||
12974887Schin mp->count['='] >= 20 && mp->count[';'] >= 20)
12984887Schin {
12994887Schin id_c:
13004887Schin t1 = "";
13014887Schin t2 = "c ";
13024887Schin t3 = T("program");
13034887Schin switch (*suff)
13044887Schin {
13054887Schin case 'c':
13064887Schin case 'C':
13074887Schin mp->mime = "application/x-cc";
13084887Schin break;
13094887Schin case 'l':
13104887Schin case 'L':
13114887Schin t1 = "lex ";
13124887Schin mp->mime = "application/x-lex";
13134887Schin break;
13144887Schin default:
13154887Schin t3 = T("header");
13164887Schin if (mp->identifier[ID_YACC] < 5 || mp->count['%'] < 5)
13174887Schin {
13184887Schin mp->mime = "application/x-cc";
13194887Schin break;
13204887Schin }
13214887Schin /*FALLTHROUGH*/
13224887Schin case 'y':
13234887Schin case 'Y':
13244887Schin t1 = "yacc ";
13254887Schin mp->mime = "application/x-yacc";
13264887Schin break;
13274887Schin }
13284887Schin if (mp->identifier[ID_CPLUSPLUS] >= 3)
13294887Schin {
13304887Schin t2 = "c++ ";
13314887Schin mp->mime = "application/x-c++";
13324887Schin }
13334887Schin sfsprintf(mp->sbuf, sizeof(mp->sbuf), "%s%s%s", t1, t2, t3);
13344887Schin s = mp->sbuf;
13354887Schin goto qualify;
13364887Schin }
13374887Schin }
13384887Schin if (mp->identifier[ID_MAM1] >= 2 && mp->identifier[ID_MAM3] >= 2 &&
13394887Schin (mp->fbsz < SF_BUFSIZE && mp->identifier[ID_MAM1] == mp->identifier[ID_MAM2] ||
13404887Schin mp->fbsz >= SF_BUFSIZE && mp->identifier[ID_MAM1] >= mp->identifier[ID_MAM2]))
13414887Schin {
13424887Schin id_mam:
13434887Schin s = T("mam program");
13444887Schin mp->mime = "application/x-mam";
13454887Schin goto qualify;
13464887Schin }
13474887Schin if (mp->identifier[ID_FORTRAN] >= 8)
13484887Schin {
13494887Schin id_fortran:
13504887Schin s = T("fortran program");
13514887Schin mp->mime = "application/x-fortran";
13524887Schin goto qualify;
13534887Schin }
13544887Schin if (mp->identifier[ID_HTML] > 0 && mp->count['<'] >= 8 && (c = mp->count['<'] - mp->count['>']) >= -2 && c <= 2)
13554887Schin {
13564887Schin id_html:
13574887Schin s = T("html input");
13584887Schin mp->mime = "text/html";
13594887Schin goto qualify;
13604887Schin }
13614887Schin if (mp->identifier[ID_COPYBOOK] > 0 && mp->identifier[ID_COBOL] == 0 && (c = mp->count['('] - mp->count[')']) >= -2 && c <= 2)
13624887Schin {
13634887Schin id_copybook:
13644887Schin s = T("cobol copybook");
13654887Schin mp->mime = "application/x-cobol";
13664887Schin goto qualify;
13674887Schin }
13684887Schin if (mp->identifier[ID_COBOL] > 0 && mp->identifier[ID_COPYBOOK] > 0 && (c = mp->count['('] - mp->count[')']) >= -2 && c <= 2)
13694887Schin {
13704887Schin id_cobol:
13714887Schin s = T("cobol program");
13724887Schin mp->mime = "application/x-cobol";
13734887Schin goto qualify;
13744887Schin }
13754887Schin if (mp->identifier[ID_PL1] > 0 && (c = mp->count['('] - mp->count[')']) >= -2 && c <= 2)
13764887Schin {
13774887Schin id_pl1:
13784887Schin s = T("pl1 program");
13794887Schin mp->mime = "application/x-pl1";
13804887Schin goto qualify;
13814887Schin }
13824887Schin if (mp->count['{'] >= 6 && (c = mp->count['{'] - mp->count['}']) >= -2 && c <= 2 && mp->count['\\'] >= mp->count['{'])
13834887Schin {
13844887Schin id_tex:
13854887Schin s = T("TeX input");
13864887Schin mp->mime = "text/tex";
13874887Schin goto qualify;
13884887Schin }
13894887Schin if (mp->identifier[ID_ASM] >= 4)
13904887Schin {
13914887Schin id_asm:
13924887Schin s = T("as program");
13934887Schin mp->mime = "application/x-as";
13944887Schin goto qualify;
13954887Schin }
13964887Schin if (ckenglish(mp, pun, badpun))
13974887Schin {
13984887Schin s = T("english text");
13994887Schin mp->mime = "text/plain";
14004887Schin goto qualify;
14014887Schin }
14024887Schin }
14034887Schin else if (streq(base, "core"))
14044887Schin {
14054887Schin mp->mime = "x-system/core";
14064887Schin return T("core dump");
14074887Schin }
14084887Schin if (flags & (CC_binary|CC_notext))
14094887Schin {
14104887Schin b = (unsigned char*)mp->fbuf;
14114887Schin e = b + mp->fbsz;
14124887Schin n = 0;
14134887Schin for (;;)
14144887Schin {
14154887Schin c = *b++;
14164887Schin q = 0;
14174887Schin while (c & 0x80)
14184887Schin {
14194887Schin c <<= 1;
14204887Schin q++;
14214887Schin }
14224887Schin switch (q)
14234887Schin {
14244887Schin case 4:
14254887Schin if (b < e && (*b++ & 0xc0) != 0x80)
14264887Schin break;
14274887Schin case 3:
14284887Schin if (b < e && (*b++ & 0xc0) != 0x80)
14294887Schin break;
14304887Schin case 2:
14314887Schin if (b < e && (*b++ & 0xc0) != 0x80)
14324887Schin break;
14334887Schin n = 1;
14344887Schin case 0:
14354887Schin if (b >= e)
14364887Schin {
14374887Schin if (n)
14384887Schin {
14394887Schin flags &= ~(CC_binary|CC_notext);
14404887Schin flags |= CC_utf_8;
14414887Schin }
14424887Schin break;
14434887Schin }
14444887Schin continue;
14454887Schin }
14464887Schin break;
14474887Schin }
14484887Schin }
14494887Schin if (flags & (CC_binary|CC_notext))
14504887Schin {
14514887Schin unsigned long d = 0;
14524887Schin
14534887Schin if ((q = mp->fbsz / UCHAR_MAX) >= 2)
14544887Schin {
14554887Schin /*
14564887Schin * compression/encryption via standard deviation
14574887Schin */
14584887Schin
14594887Schin
14604887Schin for (c = 0; c < UCHAR_MAX; c++)
14614887Schin {
14624887Schin pun = mp->count[c] - q;
14634887Schin d += pun * pun;
14644887Schin }
14654887Schin d /= mp->fbsz;
14664887Schin }
14674887Schin if (d <= 0)
14684887Schin s = T("binary");
14694887Schin else if (d < 4)
14704887Schin s = T("encrypted");
14714887Schin else if (d < 16)
14724887Schin s = T("packed");
14734887Schin else if (d < 64)
14744887Schin s = T("compressed");
14754887Schin else if (d < 256)
14764887Schin s = T("delta");
14774887Schin else
14784887Schin s = T("data");
14794887Schin mp->mime = "application/octet-stream";
14804887Schin return s;
14814887Schin }
14824887Schin mp->mime = "text/plain";
14834887Schin if (flags & CC_utf_8)
14844887Schin s = (flags & CC_control) ? T("utf-8 text with control characters") : T("utf-8 text");
14854887Schin else if (flags & CC_latin)
14864887Schin s = (flags & CC_control) ? T("latin text with control characters") : T("latin text");
14874887Schin else
14884887Schin s = (flags & CC_control) ? T("text with control characters") : T("text");
14894887Schin qualify:
14904887Schin if (!flags && mp->count['\n'] >= mp->count['\r'] && mp->count['\n'] <= (mp->count['\r'] + 1) && mp->count['\r'])
14914887Schin {
14924887Schin t = "dos ";
14934887Schin mp->mime = "text/dos";
14944887Schin }
14954887Schin else
14964887Schin t = "";
14974887Schin if (code)
14984887Schin {
14994887Schin if (code == CC_ASCII)
15004887Schin sfsprintf(buf, PATH_MAX, "ascii %s%s", t, s);
15014887Schin else
15024887Schin {
15034887Schin sfsprintf(buf, PATH_MAX, "ebcdic%d %s%s", code - 1, t, s);
15044887Schin mp->mime = "text/ebcdic";
15054887Schin }
15064887Schin s = buf;
15074887Schin }
15084887Schin else if (*t)
15094887Schin {
15104887Schin sfsprintf(buf, PATH_MAX, "%s%s", t, s);
15114887Schin s = buf;
15124887Schin }
15134887Schin return s;
15144887Schin }
15154887Schin
15164887Schin /*
15174887Schin * return the basic magic string for file,st in buf,size
15184887Schin */
15194887Schin
15204887Schin static char*
type(register Magic_t * mp,const char * file,struct stat * st,char * buf,int size)15214887Schin type(register Magic_t* mp, const char* file, struct stat* st, char* buf, int size)
15224887Schin {
15234887Schin register char* s;
15244887Schin register char* t;
15254887Schin
15264887Schin mp->mime = 0;
15274887Schin if (!S_ISREG(st->st_mode))
15284887Schin {
15294887Schin if (S_ISDIR(st->st_mode))
15304887Schin {
15314887Schin mp->mime = "x-system/dir";
15324887Schin return T("directory");
15334887Schin }
15344887Schin if (S_ISLNK(st->st_mode))
15354887Schin {
15364887Schin mp->mime = "x-system/lnk";
15374887Schin s = buf;
15384887Schin s += sfsprintf(s, PATH_MAX, T("symbolic link to "));
15394887Schin if (pathgetlink(file, s, size - (s - buf)) < 0)
15404887Schin return T("cannot read symbolic link text");
15414887Schin return buf;
15424887Schin }
15434887Schin if (S_ISBLK(st->st_mode))
15444887Schin {
15454887Schin mp->mime = "x-system/blk";
15464887Schin sfsprintf(buf, PATH_MAX, T("block special (%s)"), fmtdev(st));
15474887Schin return buf;
15484887Schin }
15494887Schin if (S_ISCHR(st->st_mode))
15504887Schin {
15514887Schin mp->mime = "x-system/chr";
15524887Schin sfsprintf(buf, PATH_MAX, T("character special (%s)"), fmtdev(st));
15534887Schin return buf;
15544887Schin }
15554887Schin if (S_ISFIFO(st->st_mode))
15564887Schin {
15574887Schin mp->mime = "x-system/fifo";
15584887Schin return "fifo";
15594887Schin }
15604887Schin #ifdef S_ISSOCK
15614887Schin if (S_ISSOCK(st->st_mode))
15624887Schin {
15634887Schin mp->mime = "x-system/sock";
15644887Schin return "socket";
15654887Schin }
15664887Schin #endif
15674887Schin }
15684887Schin if (!(mp->fbmx = st->st_size))
15694887Schin s = T("empty");
15704887Schin else if (!mp->fp)
15714887Schin s = T("cannot read");
15724887Schin else
15734887Schin {
15744887Schin mp->fbsz = sfread(mp->fp, mp->fbuf, sizeof(mp->fbuf) - 1);
15754887Schin if (mp->fbsz < 0)
15764887Schin s = fmterror(errno);
15774887Schin else if (mp->fbsz == 0)
15784887Schin s = T("empty");
15794887Schin else
15804887Schin {
15814887Schin mp->fbuf[mp->fbsz] = 0;
15824887Schin mp->xoff = 0;
15834887Schin mp->xbsz = 0;
15844887Schin if (!(s = ckmagic(mp, file, buf, st, 0)))
15854887Schin s = cklang(mp, file, buf, st);
15864887Schin }
15874887Schin }
15884887Schin if (!mp->mime)
15894887Schin mp->mime = "application/unknown";
15904887Schin else if ((t = strchr(mp->mime, '%')) && *(t + 1) == 's' && !*(t + 2))
15914887Schin {
15924887Schin register char* b;
15934887Schin register char* be;
15944887Schin register char* m;
15954887Schin register char* me;
15964887Schin
15974887Schin b = mp->mime;
15984887Schin me = (m = mp->mime = mp->fbuf) + sizeof(mp->fbuf) - 1;
15994887Schin while (m < me && b < t)
16004887Schin *m++ = *b++;
16014887Schin b = t = s;
16024887Schin for (;;)
16034887Schin {
16044887Schin if (!(be = strchr(t, ' ')))
16054887Schin {
16064887Schin be = b + strlen(b);
16074887Schin break;
16084887Schin }
16094887Schin if (*(be - 1) == ',' || strneq(be + 1, "data", 4) || strneq(be + 1, "file", 4))
16104887Schin break;
16114887Schin b = t;
16124887Schin t = be + 1;
16134887Schin }
16144887Schin while (m < me && b < be)
16154887Schin if ((*m++ = *b++) == ' ')
16164887Schin *(m - 1) = '-';
16174887Schin *m = 0;
16184887Schin }
16194887Schin return s;
16204887Schin }
16214887Schin
16224887Schin /*
16234887Schin * low level for magicload()
16244887Schin */
16254887Schin
16264887Schin static int
load(register Magic_t * mp,char * file,register Sfio_t * fp)16274887Schin load(register Magic_t* mp, char* file, register Sfio_t* fp)
16284887Schin {
16294887Schin register Entry_t* ep;
16304887Schin register char* p;
16314887Schin register char* p2;
16324887Schin char* p3;
16334887Schin char* next;
16344887Schin int n;
16354887Schin int lge;
16364887Schin int lev;
16374887Schin int ent;
16384887Schin int old;
16394887Schin int cont;
16404887Schin Info_t* ip;
16414887Schin Entry_t* ret;
16424887Schin Entry_t* first;
16434887Schin Entry_t* last = 0;
16444887Schin Entry_t* fun['z' - 'a' + 1];
16454887Schin
16464887Schin memzero(fun, sizeof(fun));
16474887Schin cont = '$';
16484887Schin ent = 0;
16494887Schin lev = 0;
16504887Schin old = 0;
16514887Schin ret = 0;
16524887Schin error_info.file = file;
16534887Schin error_info.line = 0;
16544887Schin first = ep = vmnewof(mp->vm, 0, Entry_t, 1, 0);
16554887Schin while (p = sfgetr(fp, '\n', 1))
16564887Schin {
16574887Schin error_info.line++;
16584887Schin for (; isspace(*p); p++);
16594887Schin
16604887Schin /*
16614887Schin * nesting
16624887Schin */
16634887Schin
16644887Schin switch (*p)
16654887Schin {
16664887Schin case 0:
16674887Schin case '#':
16684887Schin cont = '#';
16694887Schin continue;
16704887Schin case '{':
16714887Schin if (++lev < MAXNEST)
16724887Schin ep->nest = *p;
16734887Schin else if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
16744887Schin (*mp->disc->errorf)(mp, mp->disc, 1, "{ ... } operator nesting too deep -- %d max", MAXNEST);
16754887Schin continue;
16764887Schin case '}':
16774887Schin if (!last || lev <= 0)
16784887Schin {
16794887Schin if (mp->disc->errorf)
16804887Schin (*mp->disc->errorf)(mp, mp->disc, 2, "`%c': invalid nesting", *p);
16814887Schin }
16824887Schin else if (lev-- == ent)
16834887Schin {
16844887Schin ent = 0;
16854887Schin ep->cont = ':';
16864887Schin ep->offset = ret->offset;
16874887Schin ep->nest = ' ';
16884887Schin ep->type = ' ';
16894887Schin ep->op = ' ';
16904887Schin ep->desc = "[RETURN]";
16914887Schin last = ep;
16924887Schin ep = ret->next = vmnewof(mp->vm, 0, Entry_t, 1, 0);
16934887Schin ret = 0;
16944887Schin }
16954887Schin else
16964887Schin last->nest = *p;
16974887Schin continue;
16984887Schin default:
16994887Schin if (*(p + 1) == '{' || *(p + 1) == '(' && *p != '+' && *p != '>' && *p != '&' && *p != '|')
17004887Schin {
17014887Schin n = *p++;
17024887Schin if (n >= 'a' && n <= 'z')
17034887Schin n -= 'a';
17044887Schin else
17054887Schin {
17064887Schin if (mp->disc->errorf)
17074887Schin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: invalid function name", n);
17084887Schin n = 0;
17094887Schin }
17104887Schin if (ret && mp->disc->errorf)
17114887Schin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function has no return", ret->offset + 'a');
17124887Schin if (*p == '{')
17134887Schin {
17144887Schin ent = ++lev;
17154887Schin ret = ep;
17164887Schin ep->desc = "[FUNCTION]";
17174887Schin }
17184887Schin else
17194887Schin {
17204887Schin if (*(p + 1) != ')' && mp->disc->errorf)
17214887Schin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: invalid function call argument list", n + 'a');
17224887Schin ep->desc = "[CALL]";
17234887Schin }
17244887Schin ep->cont = cont;
17254887Schin ep->offset = n;
17264887Schin ep->nest = ' ';
17274887Schin ep->type = ' ';
17284887Schin ep->op = ' ';
17294887Schin last = ep;
17304887Schin ep = ep->next = vmnewof(mp->vm, 0, Entry_t, 1, 0);
17314887Schin if (ret)
17324887Schin fun[n] = last->value.lab = ep;
17334887Schin else if (!(last->value.lab = fun[n]) && mp->disc->errorf)
17344887Schin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function not defined", n + 'a');
17354887Schin continue;
17364887Schin }
17374887Schin if (!ep->nest)
17384887Schin ep->nest = (lev > 0 && lev != ent) ? ('0' + lev - !!ent) : ' ';
17394887Schin break;
17404887Schin }
17414887Schin
17424887Schin /*
17434887Schin * continuation
17444887Schin */
17454887Schin
17464887Schin cont = '$';
17474887Schin switch (*p)
17484887Schin {
17494887Schin case '>':
17504887Schin old = 1;
17514887Schin if (*(p + 1) == *p)
17524887Schin {
17534887Schin /*
17544887Schin * old style nesting push
17554887Schin */
17564887Schin
17574887Schin p++;
17584887Schin old = 2;
17594887Schin if (!lev && last)
17604887Schin {
17614887Schin lev = 1;
17624887Schin last->nest = '{';
17634887Schin if (last->cont == '>')
17644887Schin last->cont = '&';
17654887Schin ep->nest = '1';
17664887Schin }
17674887Schin }
17684887Schin /*FALLTHROUGH*/
17694887Schin case '+':
17704887Schin case '&':
17714887Schin case '|':
17724887Schin ep->cont = *p++;
17734887Schin break;
17744887Schin default:
17754887Schin if ((mp->flags & MAGIC_VERBOSE) && !isalpha(*p) && mp->disc->errorf)
17764887Schin (*mp->disc->errorf)(mp, mp->disc, 1, "`%c': invalid line continuation operator", *p);
17774887Schin /*FALLTHROUGH*/
17784887Schin case '*':
17794887Schin case '0': case '1': case '2': case '3': case '4':
17804887Schin case '5': case '6': case '7': case '8': case '9':
17814887Schin ep->cont = (lev > 0) ? '&' : '#';
17824887Schin break;
17834887Schin }
17844887Schin switch (old)
17854887Schin {
17864887Schin case 1:
17874887Schin old = 0;
17884887Schin if (lev)
17894887Schin {
17904887Schin /*
17914887Schin * old style nesting pop
17924887Schin */
17934887Schin
17944887Schin lev = 0;
17954887Schin if (last)
17964887Schin last->nest = '}';
17974887Schin ep->nest = ' ';
17984887Schin if (ep->cont == '&')
17994887Schin ep->cont = '#';
18004887Schin }
18014887Schin break;
18024887Schin case 2:
18034887Schin old = 1;
18044887Schin break;
18054887Schin }
18064887Schin if (isdigit(*p))
18074887Schin {
18084887Schin /*
18094887Schin * absolute offset
18104887Schin */
18114887Schin
18124887Schin ep->offset = strton(p, &next, NiL, 0);
18134887Schin p2 = next;
18144887Schin }
18154887Schin else
18164887Schin {
18174887Schin for (p2 = p; *p2 && !isspace(*p2); p2++);
18184887Schin if (!*p2)
18194887Schin {
18204887Schin if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
18214887Schin (*mp->disc->errorf)(mp, mp->disc, 1, "not enough fields: `%s'", p);
18224887Schin continue;
18234887Schin }
18244887Schin
18254887Schin /*
18264887Schin * offset expression
18274887Schin */
18284887Schin
18294887Schin *p2++ = 0;
18304887Schin ep->expr = vmstrdup(mp->vm, p);
18314887Schin if (isalpha(*p))
18324887Schin ep->offset = (ip = (Info_t*)dtmatch(mp->infotab, p)) ? ip->value : 0;
18334887Schin else if (*p == '(' && ep->cont == '>')
18344887Schin {
18354887Schin /*
18364887Schin * convert old style indirection to @
18374887Schin */
18384887Schin
18394887Schin p = ep->expr + 1;
18404887Schin for (;;)
18414887Schin {
18424887Schin switch (*p++)
18434887Schin {
18444887Schin case 0:
18454887Schin case '@':
18464887Schin case '(':
18474887Schin break;
18484887Schin case ')':
18494887Schin break;
18504887Schin default:
18514887Schin continue;
18524887Schin }
18534887Schin break;
18544887Schin }
18554887Schin if (*--p == ')')
18564887Schin {
18574887Schin *p = 0;
18584887Schin *ep->expr = '@';
18594887Schin }
18604887Schin }
18614887Schin }
18624887Schin for (; isspace(*p2); p2++);
18634887Schin for (p = p2; *p2 && !isspace(*p2); p2++);
18644887Schin if (!*p2)
18654887Schin {
18664887Schin if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
18674887Schin (*mp->disc->errorf)(mp, mp->disc, 1, "not enough fields: `%s'", p);
18684887Schin continue;
18694887Schin }
18704887Schin *p2++ = 0;
18714887Schin
18724887Schin /*
18734887Schin * type
18744887Schin */
18754887Schin
18764887Schin if ((*p == 'b' || *p == 'l') && *(p + 1) == 'e')
18774887Schin {
18784887Schin ep->swap = ~(*p == 'l' ? 7 : 0);
18794887Schin p += 2;
18804887Schin }
18814887Schin if (*p == 's')
18824887Schin {
18834887Schin if (*(p + 1) == 'h')
18844887Schin ep->type = 'h';
18854887Schin else
18864887Schin ep->type = 's';
18874887Schin }
18884887Schin else if (*p == 'a')
18894887Schin ep->type = 's';
18904887Schin else
18914887Schin ep->type = *p;
18924887Schin if (p = strchr(p, '&'))
18934887Schin {
18944887Schin /*
18954887Schin * old style mask
18964887Schin */
18974887Schin
18984887Schin ep->mask = strton(++p, NiL, NiL, 0);
18994887Schin }
19004887Schin for (; isspace(*p2); p2++);
19014887Schin if (ep->mask)
19024887Schin *--p2 = '=';
19034887Schin
19044887Schin /*
19054887Schin * comparison operation
19064887Schin */
19074887Schin
19084887Schin p = p2;
19094887Schin if (p2 = strchr(p, '\t'))
19104887Schin *p2++ = 0;
19114887Schin else
19124887Schin {
19134887Schin int qe = 0;
19144887Schin int qn = 0;
19154887Schin
19164887Schin /*
19174887Schin * assume balanced {}[]()\\""'' field
19184887Schin */
19194887Schin
19204887Schin for (p2 = p;;)
19214887Schin {
19224887Schin switch (n = *p2++)
19234887Schin {
19244887Schin case 0:
19254887Schin break;
19264887Schin case '{':
19274887Schin if (!qe)
19284887Schin qe = '}';
19294887Schin if (qe == '}')
19304887Schin qn++;
19314887Schin continue;
19324887Schin case '(':
19334887Schin if (!qe)
19344887Schin qe = ')';
19354887Schin if (qe == ')')
19364887Schin qn++;
19374887Schin continue;
19384887Schin case '[':
19394887Schin if (!qe)
19404887Schin qe = ']';
19414887Schin if (qe == ']')
19424887Schin qn++;
19434887Schin continue;
19444887Schin case '}':
19454887Schin case ')':
19464887Schin case ']':
19474887Schin if (qe == n && qn > 0)
19484887Schin qn--;
19494887Schin continue;
19504887Schin case '"':
19514887Schin case '\'':
19524887Schin if (!qe)
19534887Schin qe = n;
19544887Schin else if (qe == n)
19554887Schin qe = 0;
19564887Schin continue;
19574887Schin case '\\':
19584887Schin if (*p2)
19594887Schin p2++;
19604887Schin continue;
19614887Schin default:
19624887Schin if (!qe && isspace(n))
19634887Schin break;
19644887Schin continue;
19654887Schin }
19664887Schin if (n)
19674887Schin *(p2 - 1) = 0;
19684887Schin else
19694887Schin p2--;
19704887Schin break;
19714887Schin }
19724887Schin }
19734887Schin lge = 0;
19744887Schin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
19754887Schin ep->op = '=';
19764887Schin else
19774887Schin {
19784887Schin if (*p == '&')
19794887Schin {
19804887Schin ep->mask = strton(++p, &next, NiL, 0);
19814887Schin p = next;
19824887Schin }
19834887Schin switch (*p)
19844887Schin {
19854887Schin case '=':
19864887Schin case '>':
19874887Schin case '<':
19884887Schin case '*':
19894887Schin ep->op = *p++;
19904887Schin if (*p == '=')
19914887Schin {
19924887Schin p++;
19934887Schin switch (ep->op)
19944887Schin {
19954887Schin case '>':
19964887Schin lge = -1;
19974887Schin break;
19984887Schin case '<':
19994887Schin lge = 1;
20004887Schin break;
20014887Schin }
20024887Schin }
20034887Schin break;
20044887Schin case '!':
20054887Schin case '@':
20064887Schin ep->op = *p++;
20074887Schin if (*p == '=')
20084887Schin p++;
20094887Schin break;
20104887Schin case 'x':
20114887Schin p++;
20124887Schin ep->op = '*';
20134887Schin break;
20144887Schin default:
20154887Schin ep->op = '=';
20164887Schin if (ep->mask)
20174887Schin ep->value.num = ep->mask;
20184887Schin break;
20194887Schin }
20204887Schin }
20214887Schin if (ep->op != '*' && !ep->value.num)
20224887Schin {
20234887Schin if (ep->type == 'e')
20244887Schin {
20254887Schin if (ep->value.sub = vmnewof(mp->vm, 0, regex_t, 1, 0))
20264887Schin {
20274887Schin ep->value.sub->re_disc = &mp->redisc;
20284887Schin if (!(n = regcomp(ep->value.sub, p, REG_DELIMITED|REG_LENIENT|REG_NULL|REG_DISCIPLINE)))
20294887Schin {
20304887Schin p += ep->value.sub->re_npat;
20314887Schin if (!(n = regsubcomp(ep->value.sub, p, NiL, 0, 0)))
20324887Schin p += ep->value.sub->re_npat;
20334887Schin }
20344887Schin if (n)
20354887Schin {
20364887Schin regmessage(mp, ep->value.sub, n);
20374887Schin ep->value.sub = 0;
20384887Schin }
20394887Schin else if (*p && mp->disc->errorf)
20404887Schin (*mp->disc->errorf)(mp, mp->disc, 1, "invalid characters after substitution: %s", p);
20414887Schin }
20424887Schin }
20434887Schin else if (ep->type == 'm')
20444887Schin {
20454887Schin ep->mask = stresc(p) + 1;
20464887Schin ep->value.str = vmnewof(mp->vm, 0, char, ep->mask + 1, 0);
20474887Schin memcpy(ep->value.str, p, ep->mask);
20484887Schin if ((!ep->expr || !ep->offset) && !strmatch(ep->value.str, "\\!\\(*\\)"))
20494887Schin ep->value.str[ep->mask - 1] = '*';
20504887Schin }
20514887Schin else if (ep->type == 's')
20524887Schin {
20534887Schin ep->mask = stresc(p);
20544887Schin ep->value.str = vmnewof(mp->vm, 0, char, ep->mask, 0);
20554887Schin memcpy(ep->value.str, p, ep->mask);
20564887Schin }
20574887Schin else if (*p == '\'')
20584887Schin {
20594887Schin stresc(p);
20604887Schin ep->value.num = *(unsigned char*)(p + 1) + lge;
20614887Schin }
20624887Schin else if (strmatch(p, "+([a-z])\\(*\\)"))
20634887Schin {
20644887Schin char* t;
20654887Schin
20664887Schin t = p;
20674887Schin ep->type = 'V';
20684887Schin ep->op = *p;
20694887Schin while (*p && *p++ != '(');
20704887Schin switch (ep->op)
20714887Schin {
20724887Schin case 'l':
20734887Schin n = *p++;
20744887Schin if (n < 'a' || n > 'z')
20754887Schin {
20764887Schin if (mp->disc->errorf)
20774887Schin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: invalid function name", n);
20784887Schin }
20794887Schin else if (!fun[n -= 'a'])
20804887Schin {
20814887Schin if (mp->disc->errorf)
20824887Schin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function not defined", n + 'a');
20834887Schin }
20844887Schin else
20854887Schin {
20864887Schin ep->value.loop = vmnewof(mp->vm, 0, Loop_t, 1, 0);
20874887Schin ep->value.loop->lab = fun[n];
20884887Schin while (*p && *p++ != ',');
20894887Schin ep->value.loop->start = strton(p, &t, NiL, 0);
20904887Schin while (*t && *t++ != ',');
20914887Schin ep->value.loop->size = strton(t, &t, NiL, 0);
20924887Schin }
20934887Schin break;
20944887Schin case 'm':
20954887Schin case 'r':
20964887Schin ep->desc = vmnewof(mp->vm, 0, char, 32, 0);
20974887Schin ep->mime = vmnewof(mp->vm, 0, char, 32, 0);
20984887Schin break;
20994887Schin case 'v':
21004887Schin break;
21014887Schin default:
21024887Schin if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
21034887Schin (*mp->disc->errorf)(mp, mp->disc, 1, "%-.*s: unknown function", p - t, t);
21044887Schin break;
21054887Schin }
21064887Schin }
21074887Schin else
21084887Schin {
21094887Schin ep->value.num = strton(p, NiL, NiL, 0) + lge;
21104887Schin if (ep->op == '@')
21114887Schin ep->value.num = swapget(0, (char*)&ep->value.num, sizeof(ep->value.num));
21124887Schin }
21134887Schin }
21144887Schin
21154887Schin /*
21164887Schin * file description
21174887Schin */
21184887Schin
21194887Schin if (p2)
21204887Schin {
21214887Schin for (; isspace(*p2); p2++);
21224887Schin if (p = strchr(p2, '\t'))
21234887Schin {
21244887Schin /*
21254887Schin * check for message catalog index
21264887Schin */
21274887Schin
21284887Schin *p++ = 0;
21294887Schin if (isalpha(*p2))
21304887Schin {
21314887Schin for (p3 = p2; isalnum(*p3); p3++);
21324887Schin if (*p3++ == ':')
21334887Schin {
21344887Schin for (; isdigit(*p3); p3++);
21354887Schin if (!*p3)
21364887Schin {
21374887Schin for (p2 = p; isspace(*p2); p2++);
21384887Schin if (p = strchr(p2, '\t'))
21394887Schin *p++ = 0;
21404887Schin }
21414887Schin }
21424887Schin }
21434887Schin }
21444887Schin stresc(p2);
21454887Schin ep->desc = vmstrdup(mp->vm, p2);
21464887Schin if (p)
21474887Schin {
21484887Schin for (; isspace(*p); p++);
21494887Schin if (*p)
21504887Schin ep->mime = vmstrdup(mp->vm, p);
21514887Schin }
21524887Schin }
21534887Schin else
21544887Schin ep->desc = "";
21554887Schin
21564887Schin /*
21574887Schin * get next entry
21584887Schin */
21594887Schin
21604887Schin last = ep;
21614887Schin ep = ep->next = vmnewof(mp->vm, 0, Entry_t, 1, 0);
21624887Schin }
21634887Schin if (last)
21644887Schin {
21654887Schin last->next = 0;
21664887Schin if (mp->magiclast)
21674887Schin mp->magiclast->next = first;
21684887Schin else
21694887Schin mp->magic = first;
21704887Schin mp->magiclast = last;
21714887Schin }
21724887Schin vmfree(mp->vm, ep);
21734887Schin if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
21744887Schin {
21754887Schin if (lev < 0)
21764887Schin (*mp->disc->errorf)(mp, mp->disc, 1, "too many } operators");
21774887Schin else if (lev > 0)
21784887Schin (*mp->disc->errorf)(mp, mp->disc, 1, "not enough } operators");
21794887Schin if (ret)
21804887Schin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function has no return", ret->offset + 'a');
21814887Schin }
21824887Schin error_info.file = 0;
21834887Schin error_info.line = 0;
21844887Schin return 0;
21854887Schin }
21864887Schin
21874887Schin /*
21884887Schin * load a magic file into mp
21894887Schin */
21904887Schin
21914887Schin int
magicload(register Magic_t * mp,const char * file,unsigned long flags)21924887Schin magicload(register Magic_t* mp, const char* file, unsigned long flags)
21934887Schin {
21944887Schin register char* s;
21954887Schin register char* e;
21964887Schin register char* t;
21974887Schin int n;
21984887Schin int found;
21994887Schin int list;
22004887Schin Sfio_t* fp;
22014887Schin
22024887Schin mp->flags = mp->disc->flags | flags;
22034887Schin found = 0;
22044887Schin if (list = !(s = (char*)file) || !*s || (*s == '-' || *s == '.') && !*(s + 1))
22054887Schin {
22064887Schin if (!(s = getenv(MAGIC_FILE_ENV)) || !*s)
22074887Schin s = MAGIC_FILE;
22084887Schin }
22094887Schin for (;;)
22104887Schin {
22114887Schin if (!list)
22124887Schin e = 0;
22134887Schin else if (e = strchr(s, ':'))
22144887Schin {
22154887Schin /*
22164887Schin * ok, so ~ won't work for the last list element
22174887Schin * we do it for MAGIC_FILES_ENV anyway
22184887Schin */
22194887Schin
22204887Schin if ((strneq(s, "~/", n = 2) || strneq(s, "$HOME/", n = 6) || strneq(s, "${HOME}/", n = 8)) && (t = getenv("HOME")))
22214887Schin {
22224887Schin sfputr(mp->tmp, t, -1);
22234887Schin s += n - 1;
22244887Schin }
22254887Schin sfwrite(mp->tmp, s, e - s);
22264887Schin if (!(s = sfstruse(mp->tmp)))
22274887Schin goto nospace;
22284887Schin }
22294887Schin if (!*s || streq(s, "-"))
22304887Schin s = MAGIC_FILE;
22314887Schin if (!(fp = sfopen(NiL, s, "r")))
22324887Schin {
22334887Schin if (list)
22344887Schin {
22354887Schin if (!(t = pathpath(mp->fbuf, s, "", PATH_REGULAR|PATH_READ)) && !strchr(s, '/'))
22364887Schin {
22374887Schin strcpy(mp->fbuf, s);
22384887Schin sfprintf(mp->tmp, "%s/%s", MAGIC_DIR, mp->fbuf);
22394887Schin if (!(s = sfstruse(mp->tmp)))
22404887Schin goto nospace;
22414887Schin if (!(t = pathpath(mp->fbuf, s, "", PATH_REGULAR|PATH_READ)))
22424887Schin goto next;
22434887Schin }
22444887Schin if (!(fp = sfopen(NiL, t, "r")))
22454887Schin goto next;
22464887Schin }
22474887Schin else
22484887Schin {
22494887Schin if (mp->disc->errorf)
22504887Schin (*mp->disc->errorf)(mp, mp->disc, 3, "%s: cannot open magic file", s);
22514887Schin return -1;
22524887Schin }
22534887Schin }
22544887Schin found = 1;
22554887Schin n = load(mp, s, fp);
22564887Schin sfclose(fp);
22574887Schin if (n && !list)
22584887Schin return -1;
22594887Schin next:
22604887Schin if (!e)
22614887Schin break;
22624887Schin s = e + 1;
22634887Schin }
22644887Schin if (!found)
22654887Schin {
22664887Schin if (mp->flags & MAGIC_VERBOSE)
22674887Schin {
22684887Schin if (mp->disc->errorf)
22694887Schin (*mp->disc->errorf)(mp, mp->disc, 2, "cannot find magic file");
22704887Schin }
22714887Schin return -1;
22724887Schin }
22734887Schin return 0;
22744887Schin nospace:
22754887Schin if (mp->disc->errorf)
22764887Schin (*mp->disc->errorf)(mp, mp->disc, 3, "out of space");
22774887Schin return -1;
22784887Schin }
22794887Schin
22804887Schin /*
22814887Schin * open a magic session
22824887Schin */
22834887Schin
22844887Schin Magic_t*
magicopen(Magicdisc_t * disc)22854887Schin magicopen(Magicdisc_t* disc)
22864887Schin {
22874887Schin register Magic_t* mp;
22884887Schin register int i;
22894887Schin register int n;
22904887Schin register int f;
22914887Schin register int c;
22924887Schin register Vmalloc_t* vm;
22934887Schin unsigned char* map[CC_MAPS + 1];
22944887Schin
22954887Schin if (!(vm = vmopen(Vmdcheap, Vmbest, 0)))
22964887Schin return 0;
22974887Schin if (!(mp = vmnewof(vm, 0, Magic_t, 1, 0)))
22984887Schin {
22994887Schin vmclose(vm);
23004887Schin return 0;
23014887Schin }
23024887Schin mp->id = lib;
23034887Schin mp->disc = disc;
23044887Schin mp->vm = vm;
23054887Schin mp->flags = disc->flags;
23064887Schin mp->redisc.re_version = REG_VERSION;
23074887Schin mp->redisc.re_flags = REG_NOFREE;
23084887Schin mp->redisc.re_errorf = (regerror_t)disc->errorf;
23094887Schin mp->redisc.re_resizef = (regresize_t)vmgetmem;
23104887Schin mp->redisc.re_resizehandle = (void*)mp->vm;
23114887Schin mp->dtdisc.key = offsetof(Info_t, name);
23124887Schin mp->dtdisc.link = offsetof(Info_t, link);
23134887Schin if (!(mp->tmp = sfstropen()) || !(mp->infotab = dtnew(mp->vm, &mp->dtdisc, Dthash)))
23144887Schin goto bad;
23154887Schin for (n = 0; n < elementsof(info); n++)
23164887Schin dtinsert(mp->infotab, &info[n]);
23174887Schin for (i = 0; i < CC_MAPS; i++)
23184887Schin map[i] = ccmap(i, CC_ASCII);
23194887Schin mp->x2n = ccmap(CC_ALIEN, CC_NATIVE);
23204887Schin for (n = 0; n <= UCHAR_MAX; n++)
23214887Schin {
23224887Schin f = 0;
23234887Schin i = CC_MAPS;
23244887Schin while (--i >= 0)
23254887Schin {
23264887Schin c = ccmapchr(map[i], n);
23274887Schin f = (f << CC_BIT) | CCTYPE(c);
23284887Schin }
23294887Schin mp->cctype[n] = f;
23304887Schin }
23314887Schin return mp;
23324887Schin bad:
23334887Schin magicclose(mp);
23344887Schin return 0;
23354887Schin }
23364887Schin
23374887Schin /*
23384887Schin * close a magicopen() session
23394887Schin */
23404887Schin
23414887Schin int
magicclose(register Magic_t * mp)23424887Schin magicclose(register Magic_t* mp)
23434887Schin {
23444887Schin if (!mp)
23454887Schin return -1;
23464887Schin if (mp->tmp)
23474887Schin sfstrclose(mp->tmp);
23484887Schin if (mp->vm)
23494887Schin vmclose(mp->vm);
23504887Schin return 0;
23514887Schin }
23524887Schin
23534887Schin /*
23544887Schin * return the magic string for file with optional stat info st
23554887Schin */
23564887Schin
23574887Schin char*
magictype(register Magic_t * mp,Sfio_t * fp,const char * file,register struct stat * st)23584887Schin magictype(register Magic_t* mp, Sfio_t* fp, const char* file, register struct stat* st)
23594887Schin {
23604887Schin off_t off;
23614887Schin char* s;
23624887Schin
23634887Schin mp->flags = mp->disc->flags;
23644887Schin mp->mime = 0;
23654887Schin if (!st)
23664887Schin s = T("cannot stat");
23674887Schin else
23684887Schin {
23694887Schin if (mp->fp = fp)
23704887Schin off = sfseek(mp->fp, (off_t)0, SEEK_CUR);
23714887Schin s = type(mp, file, st, mp->tbuf, sizeof(mp->tbuf));
23724887Schin if (mp->fp)
23734887Schin sfseek(mp->fp, off, SEEK_SET);
23744887Schin if (!(mp->flags & MAGIC_MIME))
23754887Schin {
23764887Schin if (S_ISREG(st->st_mode) && (st->st_size > 0) && (st->st_size < 128))
23774887Schin sfprintf(mp->tmp, "%s ", T("short"));
23784887Schin sfprintf(mp->tmp, "%s", s);
23794887Schin if (!mp->fp && (st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
23804887Schin sfprintf(mp->tmp, ", %s", S_ISDIR(st->st_mode) ? T("searchable") : T("executable"));
23814887Schin if (st->st_mode & S_ISUID)
23824887Schin sfprintf(mp->tmp, ", setuid=%s", fmtuid(st->st_uid));
23834887Schin if (st->st_mode & S_ISGID)
23844887Schin sfprintf(mp->tmp, ", setgid=%s", fmtgid(st->st_gid));
23854887Schin if (st->st_mode & S_ISVTX)
23864887Schin sfprintf(mp->tmp, ", sticky");
23874887Schin if (!(s = sfstruse(mp->tmp)))
23884887Schin s = T("out of space");
23894887Schin }
23904887Schin }
23914887Schin if (mp->flags & MAGIC_MIME)
23924887Schin s = mp->mime;
23934887Schin if (!s)
23944887Schin s = T("error");
23954887Schin return s;
23964887Schin }
23974887Schin
23984887Schin /*
23994887Schin * list the magic table in mp on sp
24004887Schin */
24014887Schin
24024887Schin int
magiclist(register Magic_t * mp,register Sfio_t * sp)24034887Schin magiclist(register Magic_t* mp, register Sfio_t* sp)
24044887Schin {
24054887Schin register Entry_t* ep = mp->magic;
24064887Schin register Entry_t* rp = 0;
24074887Schin
24084887Schin mp->flags = mp->disc->flags;
24094887Schin sfprintf(sp, "cont\toffset\ttype\top\tmask\tvalue\tmime\tdesc\n");
24104887Schin while (ep)
24114887Schin {
24124887Schin sfprintf(sp, "%c %c\t", ep->cont, ep->nest);
24134887Schin if (ep->expr)
24144887Schin sfprintf(sp, "%s", ep->expr);
24154887Schin else
24164887Schin sfprintf(sp, "%ld", ep->offset);
24174887Schin 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);
24184887Schin switch (ep->type)
24194887Schin {
24204887Schin case 'm':
24214887Schin case 's':
24224887Schin sfputr(sp, fmtesc(ep->value.str), -1);
24234887Schin break;
24244887Schin case 'V':
24254887Schin switch (ep->op)
24264887Schin {
24274887Schin case 'l':
24284887Schin sfprintf(sp, "loop(%d,%d,%d,%d)", ep->value.loop->start, ep->value.loop->size, ep->value.loop->count, ep->value.loop->offset);
24294887Schin break;
24304887Schin case 'v':
24314887Schin sfprintf(sp, "vcodex()");
24324887Schin break;
24334887Schin default:
24344887Schin sfprintf(sp, "%p", ep->value.str);
24354887Schin break;
24364887Schin }
24374887Schin break;
24384887Schin default:
24394887Schin sfprintf(sp, "%lo", ep->value.num);
24404887Schin break;
24414887Schin }
24424887Schin sfprintf(sp, "\t%s\t%s\n", ep->mime ? ep->mime : "", fmtesc(ep->desc));
24434887Schin if (ep->cont == '$' && !ep->value.lab->mask)
24444887Schin {
24454887Schin rp = ep;
24464887Schin ep = ep->value.lab;
24474887Schin }
24484887Schin else
24494887Schin {
24504887Schin if (ep->cont == ':')
24514887Schin {
24524887Schin ep = rp;
24534887Schin ep->value.lab->mask = 1;
24544887Schin }
24554887Schin ep = ep->next;
24564887Schin }
24574887Schin }
24584887Schin return 0;
24594887Schin }
2460