* apprentice - make one pass through /etc/magic, learning its secrets.
* Copyright (c) Ian F. Darwin, 1987.
* Written by Ian F. Darwin.
* This software is not subject to any license of the American Telephone
* and Telegraph Company or of the Regents of the University of California.
* Permission is granted to anyone to use this software for any purpose on
* any computer system, and to alter it and redistribute it freely, subject
* to the following restrictions:
* 1. The author is not responsible for the consequences of use of this
* software, no matter how awful, even if they arise from flaws in it.
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Since few users ever read sources,
* credits must appear in the documentation.
* 3. Altered versions must be plainly marked as such, and must not be
* misrepresented as being the original software. Since few users
* ever read sources, credits must appear in the documentation.
* 4. This notice may not be removed or altered.
"@(#)apprentice.c,v 1.2 1993/06/10 00:38:02 jtc Exp";
#define EATAB {while (isascii((unsigned char) *l) && \
isspace((unsigned char) *l)) ++l;}
static int getvalue
__P((struct magic
*, char **));
static int hextoint
__P((int));
static char *getstr
__P((char *, char *, int, int *));
static int parse
__P((char *, int *, int));
char *fn
; /* name of magic file */
int check
; /* non-zero? checking-only run. */
(void) fprintf(stderr
, "%s: can't read magic file %s\n",
if ((magic
= (struct magic
*) malloc(sizeof(struct magic
) * maxmagic
))
(void) fprintf(stderr
, "%s: Out of memory.\n", progname
);
if (check
) /* print silly verbose header for USG compat. */
(void) printf("cont\toffset\ttype\topcode\tmask\tvalue\tdesc\n");
for (lineno
= 1;fgets(line
, BUFSIZ
, f
) != NULL
; lineno
++) {
if (line
[0]=='#') /* comment, do not parse */
if (strlen(line
) <= (unsigned)1) /* null line, garbage, etc */
line
[strlen(line
)-1] = '\0'; /* delete newline */
if (parse(line
, &nmagic
, check
) != 0)
* parse one line from magic file, put into magic[index++] if valid
if ((magic
= (struct magic
*) realloc(magic
,
(void) fprintf(stderr
, "%s: Out of memory.\n", progname
);
if (m
->cont_level
!= 0 && *l
== '(') {
/* get offset, then skip over it */
m
->offset
= (int) strtol(l
,&t
,0);
magwarn("offset %s invalid", l
);
magwarn("indirect offset type %c invalid", *l
);
if (*l
== '+' || *l
== '-') l
++;
if (isdigit((unsigned char)*l
)) {
m
->in
.offset
= strtol(l
, &t
, 0);
if (*s
== '-') m
->in
.offset
= - m
->in
.offset
;
magwarn("missing ')' in indirect offset");
while (isascii((unsigned char)*l
) && isdigit((unsigned char)*l
))
if (strncmp(l
, "byte", NBYTE
)==0) {
} else if (strncmp(l
, "short", NSHORT
)==0) {
} else if (strncmp(l
, "long", NLONG
)==0) {
} else if (strncmp(l
, "string", NSTRING
)==0) {
} else if (strncmp(l
, "date", NDATE
)==0) {
} else if (strncmp(l
, "beshort", NBESHORT
)==0) {
} else if (strncmp(l
, "belong", NBELONG
)==0) {
} else if (strncmp(l
, "bedate", NBEDATE
)==0) {
} else if (strncmp(l
, "leshort", NLESHORT
)==0) {
} else if (strncmp(l
, "lelong", NLELONG
)==0) {
} else if (strncmp(l
, "ledate", NLEDATE
)==0) {
magwarn("type %s invalid", l
);
/* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
m
->mask
= strtol(l
, &l
, 0);
/* Old-style anding: "0 byte &0x80 dynamically linked" */
if (*l
== 'x' && isascii((unsigned char)l
[1]) &&
isspace((unsigned char)l
[1])) {
goto GetDesc
; /* Bill The Cat */
* TODO finish this macro and start using it!
* #define offsetcheck {if (offset > HOWMANY-1)
* magwarn("offset too big"); }
* now get last part - the description
} else if ((l
[0] == '\\') && (l
[1] == 'b')) {
while ((m
->desc
[i
++] = *l
++) != '\0' && i
<MAXDESC
)
++(*ndx
); /* make room for next */
* Read a numeric value from a pointer, into the value union of a magic
* pointer, according to the magic type. Update the string pointer to point
* just after the number read. Return 0 for success, non-zero for failure.
*p
= getstr(*p
, m
->value
.s
, sizeof(m
->value
.s
), &slen
);
* Do not remove the casts below. They are vital.
* When later compared with the data, the sign
* extension must have happened.
m
->value
.l
= (char) strtol(*p
,p
,0);
m
->value
.l
= (short) strtol(*p
,p
,0);
m
->value
.l
= (long) strtol(*p
,p
,0);
magwarn("can't happen: m->type=%d\n", m
->type
);
* Convert a string containing C character escapes. Stop at an unescaped
* Copy the converted version to "p", returning its length in *slen.
* Return updated scan pointer as function result.
char *origs
= s
, *origp
= p
;
char *pmax
= p
+ plen
- 1;
while ((c
= *s
++) != '\0') {
if (isspace((unsigned char) c
))
fprintf(stderr
, "String too long: %s\n", origs
);
/* \ and up to 3 octal digits */
c
= *s
++; /* try for 2 */
if(c
>= '0' && c
<= '7') {
val
= (val
<<3) | (c
- '0');
c
= *s
++; /* try for 3 */
val
= (val
<<3) | (c
-'0');
/* \x and up to 3 hex digits */
val
= 'x'; /* Default if no digits */
c
= hextoint(*s
++); /* Get next char */
/* Single hex char to int; -1 if not a hex char. */
if (!isascii((unsigned char) c
)) return -1;
if (isdigit((unsigned char) c
)) return c
- '0';
if ((c
>='a')&&(c
<='f')) return c
+ 10 - 'a';
if ((c
>='A')&&(c
<='F')) return c
+ 10 - 'A';
* Print a string containing C character escapes.
while((c
= *s
++) != '\0') {
if(c
>= 040 && c
<= 0176) /* TODO isprint && !iscntrl */
printf("%.3o", c
& 0377);