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* 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 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 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* 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* 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 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* 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* 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 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 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* 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 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* 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 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