da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/***********************************************************************
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* This software is part of the ast package *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner* Copyright (c) 1985-2010 AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* and is licensed under the *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Common Public License, Version 1.0 *
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin* by AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* A copy of the License is available at *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Information and Software Systems Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* AT&T Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Florham Park NJ *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Glenn Fowler <gsf@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* David Korn <dgk@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Phong Vo <kpv@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***********************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Glenn Fowler
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * AT&T Research
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * library interface to file
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the sum of the hacks {s5,v10,planix} is _____ than the parts
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic const char id[] = "\n@(#)$Id: magic library (AT&T Research) 2008-09-10 $\0\n";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define match(s,p) strgrpmatch(s,p,NiL,0,STR_LEFT|STR_RIGHT|STR_ICASE)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chintypedef struct /* identifier dictionary entry */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chintypedef struct /* loop info */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define CC_notext CC_text /* CC_text is flipped before checking */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#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)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Cctype_t cctype[UCHAR_MAX + 1]; /* char code types */ \
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unsigned int count[UCHAR_MAX + 1]; /* char frequency count */ \
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unsigned int multi[UCHAR_MAX + 1]; /* muti char count */ \
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return pointer to data at offset off and size siz
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chingetdata(register Magic_t* mp, register long off, register int siz)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register long n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((mp->xbsz = sfread(mp->fp, mp->xbuf, sizeof(mp->xbuf) - 1)) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * @... evaluator for strexpr()
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic long
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* s = (char*)cs;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register long n = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* p;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*s == '@')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = *++s == '(' ? strexpr(s, e, indirect, mp) : strtol(s, e, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (*(s = *e))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = *(unsigned char*)p;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = (char*)cs;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = (char*)cs;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = (char*)cs;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = (char*)cs;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 2, "%s in indirect expression", *e);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * emit regex error message
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 3, "regex: %s", buf);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * decompose vcodex(3) method composition
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvcdecomp(char* b, char* e, unsigned char* m, unsigned char* x)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin const char* o;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *b++ = '^';
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * obsolete indices
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin o = "old, ";
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while (b < e && (c = *o++))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin case 0: o = "delta"; break;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin default: o = "UNKNOWN"; break;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while (b < e && (c = *o++))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while (b < e && m < x && (c = *m++))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (b >= e)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (m < x)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!(*m++ & 0x80))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (n >= (x - m))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * check for magic table match in buf
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinckmagic(register Magic_t* mp, const char* file, char* buf, struct stat* st, unsigned long off)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* p;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* b;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*FALLTHROUGH*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin num = *(unsigned char*)p;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin num = swapget(ep->swap ? (~ep->swap ^ mp->swap) : mp->swap, p, 2);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin num = swapget(ep->swap ? (~ep->swap ^ mp->swap) : mp->swap, p, 4);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin num = swapget(ep->swap ? (~ep->swap ^ mp->swap) : mp->swap, p, 8);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*FALLTHROUGH*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((c = regexec(ep->value.sub, p, elementsof(matches), matches, 0)) || (c = regsubexec(ep->value.sub, p, elementsof(matches), matches)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((c = regexec(ep->value.sub, p, elementsof(matches), matches, 0)) || (c = regsubexec(ep->value.sub, p, elementsof(matches), matches)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin t = *q ? q : p;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (mp->keep[level]++ && b > buf && *(b - 1) != ' ' && *t && *t != ',' && *t != '.' && *t != '\b')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *b++ = ' ';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b += sfsprintf(b, PATH_MAX - (b - buf), *q ? q : "%s", p + (*p == '\b'));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*FALLTHROUGH*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*ep->value.str == '*' && !*(ep->value.str + 1) && isprint(*p))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((ep->type == 'm' || ep->type == 'M') ? strmatch(p, ep->value.str) : !memcmp(p, ep->value.str, ep->mask))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (mp->keep[level]++ && b > buf && *(b - 1) != ' ' && *q && *q != ',' && *q != '.' && *q != '\b')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *b++ = ' ';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (t = p; (c = *t) >= 0 && c <= 0177 && isprint(c) && c != '\n'; t++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), p);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((num = swapget(mp->swap = 1, p, 2) & mask) == ep->value.num)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((num = swapget(mp->swap = c, p, 4) & mask) == ep->value.num)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((num = swapget(mp->swap = c, p, 8) & mask) == ep->value.num)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (num > 0 && mp->keep[level] && call < (MAXNEST - 1))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!(t = sfstruse(mp->tmp)) || !(rp = sfopen(NiL, t, "r")))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ep->mime = vmnewof(mp->vm, ep->mime, char, sfvalue(rp), 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((e = sfstruse(mp->tmp)) && (gp = sfopen(NiL, e, "r")))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ep->desc = vmnewof(mp->vm, ep->desc, char, strlen(t), 1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (isspace(*t))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ep->mime = vmnewof(mp->vm, ep->mime, char, strlen(t), strlen(e));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ep->desc = vmnewof(mp->vm, ep->desc, char, sfvalue(gp), 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*t == '.')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } while (*p++ & 0x80);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *b++ = ',';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *b++ = ' ';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b = vcdecomp(b, buf + PATH_MAX, (unsigned char*)p, (unsigned char*)p + c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (mp->keep[level]++ && b > buf && *(b - 1) != ' ' && *q && *q != ',' && *q != '.' && *q != '\b')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *b++ = ' ';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), fmttime("%?%l", (time_t)num));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), fmtversion(num));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b += sfsprintf(b, PATH_MAX - (b - buf), q + (*q == '\b'), num);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (level > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * check english language stats
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* s;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (2 * mp->count[';'] > mp->count['E'] + mp->count['e'])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((mp->count['>'] + mp->count['<'] + mp->count['/']) > mp->count['E'] + mp->count['e'])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (s = "aeiou"; *s; s++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (s = "etaion"; *s; s++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (s = "vjkqxz"; *s; s++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return 5 * vowl >= mp->fbsz - mp->count[' '] && freq >= 10 * rare;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * check programming language stats
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chincklang(register Magic_t* mp, const char* file, char* buf, struct stat* st)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register unsigned char* b;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register unsigned char* e;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int q;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* s;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * check character coding
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (b < e)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (c = 0; c < CC_MAPS; c++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (s = (char*)b; b < e && isprint(*b); b++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) || match(s, "/*bin*/*") || !access(s, F_OK))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = t + 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (t = s; *t; t++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsprintf(mp->mbuf, sizeof(mp->mbuf), "application/x-%s", *s ? s : "sh");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *b++ = ' ';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *b++ = ' ';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsprintf(mp->sbuf, sizeof(mp->sbuf), T("%s%s script"), s, t1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (b < e)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (c == '\\')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (!q)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = (char*)b - 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (!isdigit(c))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (*(s - 1))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*b == ':')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (((char*)b - s) == 3 && (s == (mp->fbuf + 1) || *(s - 2) == '\n'))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '\n':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '\\':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*b == '{')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin t = (char*)b + 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (s == t && *b == '}')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *(b - 1) = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *(b - 1) = c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (c)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '\t':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (b == (unsigned char*)(mp->fbuf + 1) || *(b - 2) == '\n')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '\'':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*b == '*')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (*b == '/')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*b == ':' && isspace(*(b + 1)) && b > (unsigned char*)(mp->fbuf + 1) && isspace(*(b - 2)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (b < e)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin base = (t1 = strrchr(file, '/')) ? t1 + 1 : (char*)file;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) && (!suff || suff != strchr(suff, '.')))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("command script");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (strmatch(mp->fbuf, "From * [0-9][0-9]:[0-9][0-9]:[0-9][0-9] *"))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("mail message");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = "mkfile";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (match(base, "*@(makefile|.mk)") || mp->multi['\t'] >= mp->count[':'] && (mp->multi['$'] > 0 || mp->multi[':'] > 0))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = "makefile";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("nroff input");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("TeX input");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (c >= 2 && mp->identifier[ID_INCL2] >= c && mp->identifier[ID_INCL3] >= c && mp->count['.'] >= c ||
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*FALLTHROUGH*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsprintf(mp->sbuf, sizeof(mp->sbuf), "%s%s%s", t1, t2, t3);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (mp->identifier[ID_MAM1] >= 2 && mp->identifier[ID_MAM3] >= 2 &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (mp->fbsz < SF_BUFSIZE && mp->identifier[ID_MAM1] == mp->identifier[ID_MAM2] ||
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mp->fbsz >= SF_BUFSIZE && mp->identifier[ID_MAM1] >= mp->identifier[ID_MAM2]))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("mam program");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("fortran program");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (mp->identifier[ID_HTML] > 0 && mp->count['<'] >= 8 && (c = mp->count['<'] - mp->count['>']) >= -2 && c <= 2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("html input");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (mp->identifier[ID_COPYBOOK] > 0 && mp->identifier[ID_COBOL] == 0 && (c = mp->count['('] - mp->count[')']) >= -2 && c <= 2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("cobol copybook");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (mp->identifier[ID_COBOL] > 0 && mp->identifier[ID_COPYBOOK] > 0 && (c = mp->count['('] - mp->count[')']) >= -2 && c <= 2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("cobol program");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (mp->identifier[ID_PL1] > 0 && (c = mp->count['('] - mp->count[')']) >= -2 && c <= 2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("pl1 program");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (mp->count['{'] >= 6 && (c = mp->count['{'] - mp->count['}']) >= -2 && c <= 2 && mp->count['\\'] >= mp->count['{'])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("TeX input");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("as program");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("english text");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return T("core dump");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (c & 0x80)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (q)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (b >= e)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unsigned long d = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * compression/encryption via standard deviation
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (c = 0; c < UCHAR_MAX; c++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (d <= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("binary");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (d < 4)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("encrypted");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (d < 16)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("packed");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (d < 64)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("compressed");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (d < 256)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("delta");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("data");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = (flags & CC_control) ? T("utf-8 text with control characters") : T("utf-8 text");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = (flags & CC_control) ? T("latin text with control characters") : T("latin text");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = (flags & CC_control) ? T("text with control characters") : T("text");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!flags && mp->count['\n'] >= mp->count['\r'] && mp->count['\n'] <= (mp->count['\r'] + 1) && mp->count['\r'])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin t = "dos ";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsprintf(buf, PATH_MAX, "ebcdic%d %s%s", code - 1, t, s);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (*t)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return the basic magic string for file,st in buf,size
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chintype(register Magic_t* mp, const char* file, struct stat* st, char* buf, int size)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* s;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* t;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return T("directory");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return T("cannot read symbolic link text");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsprintf(buf, PATH_MAX, T("block special (%s)"), fmtdev(st));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsprintf(buf, PATH_MAX, T("character special (%s)"), fmtdev(st));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return "fifo";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return "socket";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("empty");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("cannot read");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mp->fbsz = sfread(mp->fp, mp->fbuf, sizeof(mp->fbuf) - 1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("empty");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if ((t = strchr(mp->mime, '%')) && *(t + 1) == 's' && !*(t + 2))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* b;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* m;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (m < me && b < t)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *m++ = *b++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin b = t = s;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*(be - 1) == ',' || strneq(be + 1, "data", 4) || strneq(be + 1, "file", 4))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((*m++ = *b++) == ' ')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * low level for magicload()
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinload(register Magic_t* mp, char* file, register Sfio_t* fp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* p;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (; isspace(*p); p++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (*p)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if ((mp->flags & MAGIC_VERBOSE) && mp->disc->errorf)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 1, "{ ... } operator nesting too deep -- %d max", MAXNEST);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 2, "`%c': invalid nesting", *p);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*(p + 1) == '{' || *(p + 1) == '(' && *p != '+' && *p != '>' && *p != '&' && *p != '|')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: invalid function name", n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function has no return", ret->offset + 'a');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*p == '{')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: invalid function call argument list", n + 'a');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (!(last->value.lab = fun[n]) && mp->disc->errorf)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function not defined", n + 'a');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ep->nest = (lev > 0 && lev != ent) ? ('0' + lev - !!ent) : ' ';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * continuation
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (*p)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*(p + 1) == *p)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * old style nesting push
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*FALLTHROUGH*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((mp->flags & MAGIC_VERBOSE) && !isalpha(*p) && mp->disc->errorf)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 1, "`%c': invalid line continuation operator", *p);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*FALLTHROUGH*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * old style nesting pop
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * absolute offset
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 1, "not enough fields: `%s'", p);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * offset expression
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ep->offset = (ip = (Info_t*)dtmatch(mp->infotab, p)) ? ip->value : 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * convert old style indirection to @
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (*p++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*--p == ')')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 1, "not enough fields: `%s'", p);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*p == 's')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (*p == 'a')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * old style mask
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * comparison operation
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * assume balanced {}[]()\\""'' field
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (p2 = p;;)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (n = *p2++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '\'':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (qe == n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '\\':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (ep->type == 'e' || ep->type == 'm' || ep->type == 's')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*p == '&')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (*p)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*p == '=')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*p == '=')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!(n = regcomp(ep->value.sub, p, REG_DELIMITED|REG_LENIENT|REG_NULL|REG_DISCIPLINE)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 1, "invalid characters after substitution: %s", p);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ep->value.str = vmnewof(mp->vm, 0, char, ep->mask + 1, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((!ep->expr || !ep->offset) && !strmatch(ep->value.str, "\\!\\(*\\)"))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (*p == '\'')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (*p && *p++ != '(');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: invalid function name", n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function not defined", n + 'a');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (*p && *p++ != ',');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (*t && *t++ != ',');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 1, "%-.*s: unknown function", p - t, t);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ep->value.num = swapget(0, (char*)&ep->value.num, sizeof(ep->value.num));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * file description
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * check for message catalog index
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (; isspace(*p); p++);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * get next entry
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 1, "too many } operators");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (lev > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 1, "not enough } operators");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 2, "%c: function has no return", ret->offset + 'a');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * load a magic file into mp
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinmagicload(register Magic_t* mp, const char* file, unsigned long flags)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* s;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* e;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* t;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (list = !(s = (char*)file) || !*s || (*s == '-' || *s == '.') && !*(s + 1))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * ok, so ~ won't work for the last list element
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * we do it for MAGIC_FILES_ENV anyway
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((strneq(s, "~/", n = 2) || strneq(s, "$HOME/", n = 6) || strneq(s, "${HOME}/", n = 8)) && (t = getenv("HOME")))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s += n - 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!(t = pathpath(mp->fbuf, s, "", PATH_REGULAR|PATH_READ)) && !strchr(s, '/'))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!(t = pathpath(mp->fbuf, s, "", PATH_REGULAR|PATH_READ)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 3, "%s: cannot open magic file", s);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (n && !list)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = e + 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*mp->disc->errorf)(mp, mp->disc, 2, "cannot find magic file");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * open a magic session
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int i;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int f;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!(mp->tmp = sfstropen()) || !(mp->infotab = dtnew(mp->vm, &mp->dtdisc, Dthash)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (i = 0; i < CC_MAPS; i++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (n = 0; n <= UCHAR_MAX; n++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (--i >= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * close a magicopen() session
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return the magic string for file with optional stat info st
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinmagictype(register Magic_t* mp, Sfio_t* fp, const char* file, register struct stat* st)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("cannot stat");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (S_ISREG(st->st_mode) && (st->st_size > 0) && (st->st_size < 128))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!mp->fp && (st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(mp->tmp, ", %s", S_ISDIR(st->st_mode) ? T("searchable") : T("executable"));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("out of space");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = T("error");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * list the magic table in mp on sp
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "cont\toffset\ttype\top\tmask\tvalue\tmime\tdesc\n");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 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);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "loop(%d,%d,%d,%d)", ep->value.loop->start, ep->value.loop->size, ep->value.loop->count, ep->value.loop->offset);