Merge branch 'vendor/LIBPCAP'
[dragonfly.git] / contrib / file / src / apprentice.c
1 /*
2  * Copyright (c) Ian F. Darwin 1986-1995.
3  * Software written by Ian F. Darwin and others;
4  * maintained 1995-present by Christos Zoulas and others.
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice immediately at the beginning of the file, without modification,
11  *    this list of conditions, and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *  
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 /*
29  * apprentice - make one pass through /etc/magic, learning its secrets.
30  */
31
32 #include "file.h"
33
34 #ifndef lint
35 FILE_RCSID("@(#)$File: apprentice.c,v 1.173 2011/12/08 12:38:24 rrt Exp $")
36 #endif  /* lint */
37
38 #include "magic.h"
39 #include <stdlib.h>
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #include <string.h>
44 #include <assert.h>
45 #include <ctype.h>
46 #include <fcntl.h>
47 #ifdef QUICK
48 #include <sys/mman.h>
49 #endif
50 #include <dirent.h>
51
52 #define EATAB {while (isascii((unsigned char) *l) && \
53                       isspace((unsigned char) *l))  ++l;}
54 #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
55                         tolower((unsigned char) (l)) : (l))
56 /*
57  * Work around a bug in headers on Digital Unix.
58  * At least confirmed for: OSF1 V4.0 878
59  */
60 #if defined(__osf__) && defined(__DECC)
61 #ifdef MAP_FAILED
62 #undef MAP_FAILED
63 #endif
64 #endif
65
66 #ifndef MAP_FAILED
67 #define MAP_FAILED (void *) -1
68 #endif
69
70 #ifndef MAP_FILE
71 #define MAP_FILE 0
72 #endif
73
74 struct magic_entry {
75         struct magic *mp;       
76         uint32_t cont_count;
77         uint32_t max_count;
78 };
79
80 int file_formats[FILE_NAMES_SIZE];
81 const size_t file_nformats = FILE_NAMES_SIZE;
82 const char *file_names[FILE_NAMES_SIZE];
83 const size_t file_nnames = FILE_NAMES_SIZE;
84
85 private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
86 private int hextoint(int);
87 private const char *getstr(struct magic_set *, struct magic *, const char *,
88     int);
89 private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
90     const char *, size_t, int);
91 private void eatsize(const char **);
92 private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
93 private size_t apprentice_magic_strength(const struct magic *);
94 private int apprentice_sort(const void *, const void *);
95 private void apprentice_list(struct mlist *, int );
96 private int apprentice_load(struct magic_set *, struct magic **, uint32_t *,
97     const char *, int);
98 private void byteswap(struct magic *, uint32_t);
99 private void bs1(struct magic *);
100 private uint16_t swap2(uint16_t);
101 private uint32_t swap4(uint32_t);
102 private uint64_t swap8(uint64_t);
103 private char *mkdbname(struct magic_set *, const char *, int);
104 private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
105     const char *);
106 private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
107     const char *);
108 private int check_format_type(const char *, int);
109 private int check_format(struct magic_set *, struct magic *);
110 private int get_op(char);
111 private int parse_mime(struct magic_set *, struct magic_entry *, const char *);
112 private int parse_strength(struct magic_set *, struct magic_entry *, const char *);
113 private int parse_apple(struct magic_set *, struct magic_entry *, const char *);
114
115
116 private size_t maxmagic = 0;
117 private size_t magicsize = sizeof(struct magic);
118
119 private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
120
121 private struct {
122         const char *name;
123         size_t len;
124         int (*fun)(struct magic_set *, struct magic_entry *, const char *);
125 } bang[] = {
126 #define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name }
127         DECLARE_FIELD(mime),
128         DECLARE_FIELD(apple),
129         DECLARE_FIELD(strength),
130 #undef  DECLARE_FIELD
131         { NULL, 0, NULL }
132 };
133
134 #ifdef COMPILE_ONLY
135
136 int main(int, char *[]);
137
138 int
139 main(int argc, char *argv[])
140 {
141         int ret;
142         struct magic_set *ms;
143         char *progname;
144
145         if ((progname = strrchr(argv[0], '/')) != NULL)
146                 progname++;
147         else
148                 progname = argv[0];
149
150         if (argc != 2) {
151                 (void)fprintf(stderr, "Usage: %s file\n", progname);
152                 return 1;
153         }
154
155         if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
156                 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
157                 return 1;
158         }
159         ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
160         if (ret == 1)
161                 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
162         magic_close(ms);
163         return ret;
164 }
165 #endif /* COMPILE_ONLY */
166
167 static const struct type_tbl_s {
168         const char name[16];
169         const size_t len;
170         const int type;
171         const int format;
172 } type_tbl[] = {
173 # define XX(s)          s, (sizeof(s) - 1)
174 # define XX_NULL        "", 0
175         { XX("byte"),           FILE_BYTE,              FILE_FMT_NUM },
176         { XX("short"),          FILE_SHORT,             FILE_FMT_NUM },
177         { XX("default"),        FILE_DEFAULT,           FILE_FMT_STR },
178         { XX("long"),           FILE_LONG,              FILE_FMT_NUM },
179         { XX("string"),         FILE_STRING,            FILE_FMT_STR },
180         { XX("date"),           FILE_DATE,              FILE_FMT_STR },
181         { XX("beshort"),        FILE_BESHORT,           FILE_FMT_NUM },
182         { XX("belong"),         FILE_BELONG,            FILE_FMT_NUM },
183         { XX("bedate"),         FILE_BEDATE,            FILE_FMT_STR },
184         { XX("leshort"),        FILE_LESHORT,           FILE_FMT_NUM },
185         { XX("lelong"),         FILE_LELONG,            FILE_FMT_NUM },
186         { XX("ledate"),         FILE_LEDATE,            FILE_FMT_STR },
187         { XX("pstring"),        FILE_PSTRING,           FILE_FMT_STR },
188         { XX("ldate"),          FILE_LDATE,             FILE_FMT_STR },
189         { XX("beldate"),        FILE_BELDATE,           FILE_FMT_STR },
190         { XX("leldate"),        FILE_LELDATE,           FILE_FMT_STR },
191         { XX("regex"),          FILE_REGEX,             FILE_FMT_STR },
192         { XX("bestring16"),     FILE_BESTRING16,        FILE_FMT_STR },
193         { XX("lestring16"),     FILE_LESTRING16,        FILE_FMT_STR },
194         { XX("search"),         FILE_SEARCH,            FILE_FMT_STR },
195         { XX("medate"),         FILE_MEDATE,            FILE_FMT_STR },
196         { XX("meldate"),        FILE_MELDATE,           FILE_FMT_STR },
197         { XX("melong"),         FILE_MELONG,            FILE_FMT_NUM },
198         { XX("quad"),           FILE_QUAD,              FILE_FMT_QUAD },
199         { XX("lequad"),         FILE_LEQUAD,            FILE_FMT_QUAD },
200         { XX("bequad"),         FILE_BEQUAD,            FILE_FMT_QUAD },
201         { XX("qdate"),          FILE_QDATE,             FILE_FMT_STR },
202         { XX("leqdate"),        FILE_LEQDATE,           FILE_FMT_STR },
203         { XX("beqdate"),        FILE_BEQDATE,           FILE_FMT_STR },
204         { XX("qldate"),         FILE_QLDATE,            FILE_FMT_STR },
205         { XX("leqldate"),       FILE_LEQLDATE,          FILE_FMT_STR },
206         { XX("beqldate"),       FILE_BEQLDATE,          FILE_FMT_STR },
207         { XX("float"),          FILE_FLOAT,             FILE_FMT_FLOAT },
208         { XX("befloat"),        FILE_BEFLOAT,           FILE_FMT_FLOAT },
209         { XX("lefloat"),        FILE_LEFLOAT,           FILE_FMT_FLOAT },
210         { XX("double"),         FILE_DOUBLE,            FILE_FMT_DOUBLE },
211         { XX("bedouble"),       FILE_BEDOUBLE,          FILE_FMT_DOUBLE },
212         { XX("ledouble"),       FILE_LEDOUBLE,          FILE_FMT_DOUBLE },
213         { XX("leid3"),          FILE_LEID3,             FILE_FMT_NUM },
214         { XX("beid3"),          FILE_BEID3,             FILE_FMT_NUM },
215         { XX("indirect"),       FILE_INDIRECT,          FILE_FMT_NONE },
216         { XX_NULL,              FILE_INVALID,           FILE_FMT_NONE },
217 # undef XX
218 # undef XX_NULL
219 };
220
221 private int
222 get_type(const char *l, const char **t)
223 {
224         const struct type_tbl_s *p;
225
226         for (p = type_tbl; p->len; p++) {
227                 if (strncmp(l, p->name, p->len) == 0) {
228                         if (t)
229                                 *t = l + p->len;
230                         break;
231                 }
232         }
233         return p->type;
234 }
235
236 private void
237 init_file_tables(void)
238 {
239         static int done = 0;
240         const struct type_tbl_s *p;
241
242         if (done)
243                 return;
244         done++;
245
246         for (p = type_tbl; p->len; p++) {
247                 assert(p->type < FILE_NAMES_SIZE);
248                 file_names[p->type] = p->name;
249                 file_formats[p->type] = p->format;
250         }
251 }
252
253 /*
254  * Handle one file or directory.
255  */
256 private int
257 apprentice_1(struct magic_set *ms, const char *fn, int action,
258     struct mlist *mlist)
259 {
260         struct magic *magic = NULL;
261         uint32_t nmagic = 0;
262         struct mlist *ml;
263         int rv = -1;
264         int mapped;
265
266         if (magicsize != FILE_MAGICSIZE) {
267                 file_error(ms, 0, "magic element size %lu != %lu",
268                     (unsigned long)sizeof(*magic),
269                     (unsigned long)FILE_MAGICSIZE);
270                 return -1;
271         }
272
273         if (action == FILE_COMPILE) {
274                 rv = apprentice_load(ms, &magic, &nmagic, fn, action);
275                 if (rv != 0)
276                         return -1;
277                 rv = apprentice_compile(ms, &magic, &nmagic, fn);
278                 free(magic);
279                 return rv;
280         }
281
282 #ifndef COMPILE_ONLY
283         if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
284                 if (ms->flags & MAGIC_CHECK)
285                         file_magwarn(ms, "using regular magic file `%s'", fn);
286                 rv = apprentice_load(ms, &magic, &nmagic, fn, action);
287                 if (rv != 0)
288                         return -1;
289         }
290
291         mapped = rv;
292              
293         if (magic == NULL) {
294                 file_delmagic(magic, mapped, nmagic);
295                 return -1;
296         }
297
298         if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) {
299                 file_delmagic(magic, mapped, nmagic);
300                 file_oomem(ms, sizeof(*ml));
301                 return -1;
302         }
303
304         ml->magic = magic;
305         ml->nmagic = nmagic;
306         ml->mapped = mapped;
307
308         mlist->prev->next = ml;
309         ml->prev = mlist->prev;
310         ml->next = mlist;
311         mlist->prev = ml;
312
313         if (action == FILE_LIST) {
314                 printf("Binary patterns:\n");
315                 apprentice_list(mlist, BINTEST);
316                 printf("Text patterns:\n");
317                 apprentice_list(mlist, TEXTTEST);
318         }
319         
320         return 0;
321 #endif /* COMPILE_ONLY */
322 }
323
324 protected void
325 file_delmagic(struct magic *p, int type, size_t entries)
326 {
327         if (p == NULL)
328                 return;
329         switch (type) {
330         case 2:
331 #ifdef QUICK
332                 p--;
333                 (void)munmap((void *)p, sizeof(*p) * (entries + 1));
334                 break;
335 #else
336                 (void)&entries;
337                 abort();
338                 /*NOTREACHED*/
339 #endif
340         case 1:
341                 p--;
342                 /*FALLTHROUGH*/
343         case 0:
344                 free(p);
345                 break;
346         default:
347                 abort();
348         }
349 }
350
351 /* const char *fn: list of magic files and directories */
352 protected struct mlist *
353 file_apprentice(struct magic_set *ms, const char *fn, int action)
354 {
355         char *p, *mfn;
356         int file_err, errs = -1;
357         struct mlist *mlist;
358
359         if ((fn = magic_getpath(fn, action)) == NULL)
360                 return NULL;
361
362         init_file_tables();
363
364         if ((mfn = strdup(fn)) == NULL) {
365                 file_oomem(ms, strlen(fn));
366                 return NULL;
367         }
368         fn = mfn;
369
370         if ((mlist = CAST(struct mlist *, malloc(sizeof(*mlist)))) == NULL) {
371                 free(mfn);
372                 file_oomem(ms, sizeof(*mlist));
373                 return NULL;
374         }
375         mlist->next = mlist->prev = mlist;
376
377         while (fn) {
378                 p = strchr(fn, PATHSEP);
379                 if (p)
380                         *p++ = '\0';
381                 if (*fn == '\0')
382                         break;
383                 file_err = apprentice_1(ms, fn, action, mlist);
384                 errs = MAX(errs, file_err);
385                 fn = p;
386         }
387         if (errs == -1) {
388                 free(mfn);
389                 free(mlist);
390                 mlist = NULL;
391                 file_error(ms, 0, "could not find any magic files!");
392                 return NULL;
393         }
394         free(mfn);
395         return mlist;
396 }
397
398 /*
399  * Get weight of this magic entry, for sorting purposes.
400  */
401 private size_t
402 apprentice_magic_strength(const struct magic *m)
403 {
404 #define MULT 10
405         size_t val = 2 * MULT;  /* baseline strength */
406
407         switch (m->type) {
408         case FILE_DEFAULT:      /* make sure this sorts last */
409                 if (m->factor_op != FILE_FACTOR_OP_NONE)
410                         abort();
411                 return 0;
412
413         case FILE_BYTE:
414                 val += 1 * MULT;
415                 break;
416
417         case FILE_SHORT:
418         case FILE_LESHORT:
419         case FILE_BESHORT:
420                 val += 2 * MULT;
421                 break;
422
423         case FILE_LONG:
424         case FILE_LELONG:
425         case FILE_BELONG:
426         case FILE_MELONG:
427                 val += 4 * MULT;
428                 break;
429
430         case FILE_PSTRING:
431         case FILE_STRING:
432                 val += m->vallen * MULT;
433                 break;
434
435         case FILE_BESTRING16:
436         case FILE_LESTRING16:
437                 val += m->vallen * MULT / 2;
438                 break;
439
440         case FILE_SEARCH:
441         case FILE_REGEX:
442                 val += m->vallen * MAX(MULT / m->vallen, 1);
443                 break;
444
445         case FILE_DATE:
446         case FILE_LEDATE:
447         case FILE_BEDATE:
448         case FILE_MEDATE:
449         case FILE_LDATE:
450         case FILE_LELDATE:
451         case FILE_BELDATE:
452         case FILE_MELDATE:
453         case FILE_FLOAT:
454         case FILE_BEFLOAT:
455         case FILE_LEFLOAT:
456                 val += 4 * MULT;
457                 break;
458
459         case FILE_QUAD:
460         case FILE_BEQUAD:
461         case FILE_LEQUAD:
462         case FILE_QDATE:
463         case FILE_LEQDATE:
464         case FILE_BEQDATE:
465         case FILE_QLDATE:
466         case FILE_LEQLDATE:
467         case FILE_BEQLDATE:
468         case FILE_DOUBLE:
469         case FILE_BEDOUBLE:
470         case FILE_LEDOUBLE:
471                 val += 8 * MULT;
472                 break;
473
474         default:
475                 val = 0;
476                 (void)fprintf(stderr, "Bad type %d\n", m->type);
477                 abort();
478         }
479
480         switch (m->reln) {
481         case 'x':       /* matches anything penalize */
482         case '!':       /* matches almost anything penalize */
483                 val = 0;
484                 break;
485
486         case '=':       /* Exact match, prefer */
487                 val += MULT;
488                 break;
489
490         case '>':
491         case '<':       /* comparison match reduce strength */
492                 val -= 2 * MULT;
493                 break;
494
495         case '^':
496         case '&':       /* masking bits, we could count them too */
497                 val -= MULT;
498                 break;
499
500         default:
501                 (void)fprintf(stderr, "Bad relation %c\n", m->reln);
502                 abort();
503         }
504
505         if (val == 0)   /* ensure we only return 0 for FILE_DEFAULT */
506                 val = 1;
507
508         switch (m->factor_op) {
509         case FILE_FACTOR_OP_NONE:
510                 break;
511         case FILE_FACTOR_OP_PLUS:
512                 val += m->factor;
513                 break;
514         case FILE_FACTOR_OP_MINUS:
515                 val -= m->factor;
516                 break;
517         case FILE_FACTOR_OP_TIMES:
518                 val *= m->factor;
519                 break;
520         case FILE_FACTOR_OP_DIV:
521                 val /= m->factor;
522                 break;
523         default:
524                 abort();
525         }
526
527         /*
528          * Magic entries with no description get a bonus because they depend
529          * on subsequent magic entries to print something.
530          */
531         if (m->desc[0] == '\0')
532                 val++;
533         return val;
534 }
535
536 /*  
537  * Sort callback for sorting entries by "strength" (basically length)
538  */
539 private int
540 apprentice_sort(const void *a, const void *b)
541 {
542         const struct magic_entry *ma = CAST(const struct magic_entry *, a);
543         const struct magic_entry *mb = CAST(const struct magic_entry *, b);
544         size_t sa = apprentice_magic_strength(ma->mp);
545         size_t sb = apprentice_magic_strength(mb->mp);
546         if (sa == sb)
547                 return 0;
548         else if (sa > sb)
549                 return -1;
550         else
551                 return 1;
552 }
553
554 /*  
555  * Shows sorted patterns list in the order which is used for the matching
556  */
557 private void
558 apprentice_list(struct mlist *mlist, int mode)
559 {
560         uint32_t magindex = 0;
561         struct mlist *ml;
562         for (ml = mlist->next; ml != mlist; ml = ml->next) {
563                 for (magindex = 0; magindex < ml->nmagic; magindex++) {
564                         struct magic *m = &ml->magic[magindex];
565                         if ((m->flag & mode) != mode) {
566                                 /* Skip sub-tests */
567                                 while (magindex + 1 < ml->nmagic &&
568                                        ml->magic[magindex + 1].cont_level != 0)
569                                         ++magindex;
570                                 continue; /* Skip to next top-level test*/
571                         }
572
573                         /*
574                          * Try to iterate over the tree until we find item with
575                          * description/mimetype.
576                          */
577                         while (magindex + 1 < ml->nmagic &&
578                                ml->magic[magindex + 1].cont_level != 0 &&
579                                *ml->magic[magindex].desc == '\0' &&
580                                *ml->magic[magindex].mimetype == '\0')
581                                 magindex++;
582
583                         printf("Strength = %3" SIZE_T_FORMAT "u : %s [%s]\n",
584                             apprentice_magic_strength(m),
585                             ml->magic[magindex].desc,
586                             ml->magic[magindex].mimetype);
587                 }
588         }
589 }
590
591 private void
592 set_test_type(struct magic *mstart, struct magic *m)
593 {
594         switch (m->type) {
595         case FILE_BYTE:
596         case FILE_SHORT:
597         case FILE_LONG:
598         case FILE_DATE:
599         case FILE_BESHORT:
600         case FILE_BELONG:
601         case FILE_BEDATE:
602         case FILE_LESHORT:
603         case FILE_LELONG:
604         case FILE_LEDATE:
605         case FILE_LDATE:
606         case FILE_BELDATE:
607         case FILE_LELDATE:
608         case FILE_MEDATE:
609         case FILE_MELDATE:
610         case FILE_MELONG:
611         case FILE_QUAD:
612         case FILE_LEQUAD:
613         case FILE_BEQUAD:
614         case FILE_QDATE:
615         case FILE_LEQDATE:
616         case FILE_BEQDATE:
617         case FILE_QLDATE:
618         case FILE_LEQLDATE:
619         case FILE_BEQLDATE:
620         case FILE_FLOAT:
621         case FILE_BEFLOAT:
622         case FILE_LEFLOAT:
623         case FILE_DOUBLE:
624         case FILE_BEDOUBLE:
625         case FILE_LEDOUBLE:
626                 mstart->flag |= BINTEST;
627                 break;
628         case FILE_STRING:
629         case FILE_PSTRING:
630         case FILE_BESTRING16:
631         case FILE_LESTRING16:
632                 /* Allow text overrides */
633                 if (mstart->str_flags & STRING_TEXTTEST)
634                         mstart->flag |= TEXTTEST;
635                 else
636                         mstart->flag |= BINTEST;
637                 break;
638         case FILE_REGEX:
639         case FILE_SEARCH:
640 #ifndef COMPILE_ONLY
641                 if (mstart->str_flags & STRING_BINTEST)
642                         mstart->flag |= BINTEST;
643                 if (mstart->str_flags & STRING_TEXTTEST)
644                         mstart->flag |= TEXTTEST;
645                     
646                 if (mstart->flag & (TEXTTEST|BINTEST))
647                         break;
648
649                 /* binary test if pattern is not text */
650                 if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL,
651                     NULL) <= 0)
652                         mstart->flag |= BINTEST;
653                 else
654                         mstart->flag |= TEXTTEST;
655 #endif
656                 break;
657         case FILE_DEFAULT:
658                 /* can't deduce anything; we shouldn't see this at the
659                    top level anyway */
660                 break;
661         case FILE_INVALID:
662         default:
663                 /* invalid search type, but no need to complain here */
664                 break;
665         }
666 }
667
668 /*
669  * Load and parse one file.
670  */
671 private void
672 load_1(struct magic_set *ms, int action, const char *fn, int *errs,
673    struct magic_entry **marray, uint32_t *marraycount)
674 {
675         size_t lineno = 0, llen = 0;
676         char *line = NULL;
677         ssize_t len;
678
679         FILE *f = fopen(ms->file = fn, "r");
680         if (f == NULL) {
681                 if (errno != ENOENT)
682                         file_error(ms, errno, "cannot read magic file `%s'",
683                                    fn);
684                 (*errs)++;
685                 return;
686         }
687
688         /* read and parse this file */
689         for (ms->line = 1; (len = getline(&line, &llen, f)) != -1;
690             ms->line++) {
691                 if (len == 0) /* null line, garbage, etc */
692                         continue;
693                 if (line[len - 1] == '\n') {
694                         lineno++;
695                         line[len - 1] = '\0'; /* delete newline */
696                 }
697                 switch (line[0]) {
698                 case '\0':      /* empty, do not parse */
699                 case '#':       /* comment, do not parse */
700                         continue;
701                 case '!':
702                         if (line[1] == ':') {
703                                 size_t i;
704
705                                 for (i = 0; bang[i].name != NULL; i++) {
706                                         if ((size_t)(len - 2) > bang[i].len &&
707                                             memcmp(bang[i].name, line + 2,
708                                             bang[i].len) == 0)
709                                                 break;
710                                 }
711                                 if (bang[i].name == NULL) {
712                                         file_error(ms, 0,
713                                             "Unknown !: entry `%s'", line);
714                                         (*errs)++;
715                                         continue;
716                                 }
717                                 if (*marraycount == 0) {
718                                         file_error(ms, 0,
719                                             "No current entry for :!%s type",
720                                                 bang[i].name);
721                                         (*errs)++;
722                                         continue;
723                                 }
724                                 if ((*bang[i].fun)(ms, 
725                                     &(*marray)[*marraycount - 1],
726                                     line + bang[i].len + 2) != 0) {
727                                         (*errs)++;
728                                         continue;
729                                 }
730                                 continue;
731                         }
732                         /*FALLTHROUGH*/
733                 default:
734                         if (parse(ms, marray, marraycount, line, lineno,
735                             action) != 0)
736                                 (*errs)++;
737                         break;
738                 }
739         }
740         free(line);
741         (void)fclose(f);
742 }
743
744 /*
745  * parse a file or directory of files
746  * const char *fn: name of magic file or directory
747  */
748 private int
749 cmpstrp(const void *p1, const void *p2)
750 {
751         return strcmp(*(char *const *)p1, *(char *const *)p2);
752 }
753
754 private int
755 apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
756     const char *fn, int action)
757 {
758         int errs = 0;
759         struct magic_entry *marray;
760         uint32_t marraycount, i, mentrycount = 0, starttest;
761         size_t slen, files = 0, maxfiles = 0;
762         char **filearr = NULL, *mfn;
763         struct stat st;
764         DIR *dir;
765         struct dirent *d;
766
767         ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */
768
769         maxmagic = MAXMAGIS;
770         if ((marray = CAST(struct magic_entry *, calloc(maxmagic,
771             sizeof(*marray)))) == NULL) {
772                 file_oomem(ms, maxmagic * sizeof(*marray));
773                 return -1;
774         }
775         marraycount = 0;
776
777         /* print silly verbose header for USG compat. */
778         if (action == FILE_CHECK)
779                 (void)fprintf(stderr, "%s\n", usg_hdr);
780
781         /* load directory or file */
782         if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
783                 dir = opendir(fn);
784                 if (!dir) {
785                         errs++;
786                         goto out;
787                 }
788                 while ((d = readdir(dir)) != NULL) {
789                         if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) {
790                                 file_oomem(ms,
791                                     strlen(fn) + strlen(d->d_name) + 2);
792                                 errs++;
793                                 closedir(dir);
794                                 goto out;
795                         }
796                         if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) {
797                                 free(mfn);
798                                 continue;
799                         }
800                         if (files >= maxfiles) {
801                                 size_t mlen;
802                                 maxfiles = (maxfiles + 1) * 2;
803                                 mlen = maxfiles * sizeof(*filearr);
804                                 if ((filearr = CAST(char **,
805                                     realloc(filearr, mlen))) == NULL) {
806                                         file_oomem(ms, mlen);
807                                         free(mfn);
808                                         closedir(dir);
809                                         errs++;
810                                         goto out;
811                                 }
812                         }
813                         filearr[files++] = mfn;
814                 }
815                 closedir(dir);
816                 qsort(filearr, files, sizeof(*filearr), cmpstrp);
817                 for (i = 0; i < files; i++) {
818                         load_1(ms, action, filearr[i], &errs, &marray,
819                             &marraycount);
820                         free(filearr[i]);
821                 }
822                 free(filearr);
823         } else
824                 load_1(ms, action, fn, &errs, &marray, &marraycount);
825         if (errs)
826                 goto out;
827
828         /* Set types of tests */
829         for (i = 0; i < marraycount; ) {
830                 if (marray[i].mp->cont_level != 0) {
831                         i++;
832                         continue;
833                 }
834
835                 starttest = i;
836                 do {
837                         static const char text[] = "text";
838                         static const char binary[] = "binary";
839                         static const size_t len = sizeof(text);
840                         set_test_type(marray[starttest].mp, marray[i].mp);
841                         if ((ms->flags & MAGIC_DEBUG) == 0)
842                                 continue;
843                         (void)fprintf(stderr, "%s%s%s: %s\n",
844                             marray[i].mp->mimetype,
845                             marray[i].mp->mimetype[0] == '\0' ? "" : "; ",
846                             marray[i].mp->desc[0] ? marray[i].mp->desc :
847                             "(no description)",
848                             marray[i].mp->flag & BINTEST ? binary : text);
849                         if (marray[i].mp->flag & BINTEST) {
850                                 char *p = strstr(marray[i].mp->desc, text);
851                                 if (p && (p == marray[i].mp->desc ||
852                                     isspace((unsigned char)p[-1])) &&
853                                     (p + len - marray[i].mp->desc == 
854                                     MAXstring || (p[len] == '\0' ||
855                                     isspace((unsigned char)p[len]))))
856                                         (void)fprintf(stderr, "*** Possible "
857                                             "binary test for text type\n");
858                         }
859                 } while (++i < marraycount && marray[i].mp->cont_level != 0);
860         }
861
862         qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
863
864         /*
865          * Make sure that any level 0 "default" line is last (if one exists).
866          */
867         for (i = 0; i < marraycount; i++) {
868                 if (marray[i].mp->cont_level == 0 &&
869                     marray[i].mp->type == FILE_DEFAULT) {
870                         while (++i < marraycount)
871                                 if (marray[i].mp->cont_level == 0)
872                                         break;
873                         if (i != marraycount) {
874                                 /* XXX - Ugh! */
875                                 ms->line = marray[i].mp->lineno;
876                                 file_magwarn(ms,
877                                     "level 0 \"default\" did not sort last");
878                         }
879                         break;                                      
880                 }
881         }
882
883         for (i = 0; i < marraycount; i++)
884                 mentrycount += marray[i].cont_count;
885
886         slen = sizeof(**magicp) * mentrycount;
887         if ((*magicp = CAST(struct magic *, malloc(slen))) == NULL) {
888                 file_oomem(ms, slen);
889                 errs++;
890                 goto out;
891         }
892
893         mentrycount = 0;
894         for (i = 0; i < marraycount; i++) {
895                 (void)memcpy(*magicp + mentrycount, marray[i].mp,
896                     marray[i].cont_count * sizeof(**magicp));
897                 mentrycount += marray[i].cont_count;
898         }
899 out:
900         for (i = 0; i < marraycount; i++)
901                 free(marray[i].mp);
902         free(marray);
903         if (errs) {
904                 *magicp = NULL;
905                 *nmagicp = 0;
906                 return errs;
907         } else {
908                 *nmagicp = mentrycount;
909                 return 0;
910         }
911
912 }
913
914 /*
915  * extend the sign bit if the comparison is to be signed
916  */
917 protected uint64_t
918 file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
919 {
920         if (!(m->flag & UNSIGNED)) {
921                 switch(m->type) {
922                 /*
923                  * Do not remove the casts below.  They are
924                  * vital.  When later compared with the data,
925                  * the sign extension must have happened.
926                  */
927                 case FILE_BYTE:
928                         v = (char) v;
929                         break;
930                 case FILE_SHORT:
931                 case FILE_BESHORT:
932                 case FILE_LESHORT:
933                         v = (short) v;
934                         break;
935                 case FILE_DATE:
936                 case FILE_BEDATE:
937                 case FILE_LEDATE:
938                 case FILE_MEDATE:
939                 case FILE_LDATE:
940                 case FILE_BELDATE:
941                 case FILE_LELDATE:
942                 case FILE_MELDATE:
943                 case FILE_LONG:
944                 case FILE_BELONG:
945                 case FILE_LELONG:
946                 case FILE_MELONG:
947                 case FILE_FLOAT:
948                 case FILE_BEFLOAT:
949                 case FILE_LEFLOAT:
950                         v = (int32_t) v;
951                         break;
952                 case FILE_QUAD:
953                 case FILE_BEQUAD:
954                 case FILE_LEQUAD:
955                 case FILE_QDATE:
956                 case FILE_QLDATE:
957                 case FILE_BEQDATE:
958                 case FILE_BEQLDATE:
959                 case FILE_LEQDATE:
960                 case FILE_LEQLDATE:
961                 case FILE_DOUBLE:
962                 case FILE_BEDOUBLE:
963                 case FILE_LEDOUBLE:
964                         v = (int64_t) v;
965                         break;
966                 case FILE_STRING:
967                 case FILE_PSTRING:
968                 case FILE_BESTRING16:
969                 case FILE_LESTRING16:
970                 case FILE_REGEX:
971                 case FILE_SEARCH:
972                 case FILE_DEFAULT:
973                 case FILE_INDIRECT:
974                         break;
975                 default:
976                         if (ms->flags & MAGIC_CHECK)
977                             file_magwarn(ms, "cannot happen: m->type=%d\n",
978                                     m->type);
979                         return ~0U;
980                 }
981         }
982         return v;
983 }
984
985 private int
986 string_modifier_check(struct magic_set *ms, struct magic *m)
987 {
988         if ((ms->flags & MAGIC_CHECK) == 0)
989                 return 0;
990
991         if (m->type != FILE_PSTRING && (m->str_flags & PSTRING_LEN) != 0) {
992                 file_magwarn(ms,
993                     "'/BHhLl' modifiers are only allowed for pascal strings\n");
994                 return -1;
995         }
996         switch (m->type) {
997         case FILE_BESTRING16:
998         case FILE_LESTRING16:
999                 if (m->str_flags != 0) {
1000                         file_magwarn(ms,
1001                             "no modifiers allowed for 16-bit strings\n");
1002                         return -1;
1003                 }
1004                 break;
1005         case FILE_STRING:
1006         case FILE_PSTRING:
1007                 if ((m->str_flags & REGEX_OFFSET_START) != 0) {
1008                         file_magwarn(ms,
1009                             "'/%c' only allowed on regex and search\n",
1010                             CHAR_REGEX_OFFSET_START);
1011                         return -1;
1012                 }
1013                 break;
1014         case FILE_SEARCH:
1015                 if (m->str_range == 0) {
1016                         file_magwarn(ms,
1017                             "missing range; defaulting to %d\n",
1018                             STRING_DEFAULT_RANGE);
1019                         m->str_range = STRING_DEFAULT_RANGE;
1020                         return -1;
1021                 }
1022                 break;
1023         case FILE_REGEX:
1024                 if ((m->str_flags & STRING_COMPACT_WHITESPACE) != 0) {
1025                         file_magwarn(ms, "'/%c' not allowed on regex\n",
1026                             CHAR_COMPACT_WHITESPACE);
1027                         return -1;
1028                 }
1029                 if ((m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE) != 0) {
1030                         file_magwarn(ms, "'/%c' not allowed on regex\n",
1031                             CHAR_COMPACT_OPTIONAL_WHITESPACE);
1032                         return -1;
1033                 }
1034                 break;
1035         default:
1036                 file_magwarn(ms, "coding error: m->type=%d\n",
1037                     m->type);
1038                 return -1;
1039         }
1040         return 0;
1041 }
1042
1043 private int
1044 get_op(char c)
1045 {
1046         switch (c) {
1047         case '&':
1048                 return FILE_OPAND;
1049         case '|':
1050                 return FILE_OPOR;
1051         case '^':
1052                 return FILE_OPXOR;
1053         case '+':
1054                 return FILE_OPADD;
1055         case '-':
1056                 return FILE_OPMINUS;
1057         case '*':
1058                 return FILE_OPMULTIPLY;
1059         case '/':
1060                 return FILE_OPDIVIDE;
1061         case '%':
1062                 return FILE_OPMODULO;
1063         default:
1064                 return -1;
1065         }
1066 }
1067
1068 #ifdef ENABLE_CONDITIONALS
1069 private int
1070 get_cond(const char *l, const char **t)
1071 {
1072         static const struct cond_tbl_s {
1073                 char name[8];
1074                 size_t len;
1075                 int cond;
1076         } cond_tbl[] = {
1077                 { "if",         2,      COND_IF },
1078                 { "elif",       4,      COND_ELIF },
1079                 { "else",       4,      COND_ELSE },
1080                 { "",           0,      COND_NONE },
1081         };
1082         const struct cond_tbl_s *p;
1083
1084         for (p = cond_tbl; p->len; p++) {
1085                 if (strncmp(l, p->name, p->len) == 0 &&
1086                     isspace((unsigned char)l[p->len])) {
1087                         if (t)
1088                                 *t = l + p->len;
1089                         break;
1090                 }
1091         }
1092         return p->cond;
1093 }
1094
1095 private int
1096 check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
1097 {
1098         int last_cond;
1099         last_cond = ms->c.li[cont_level].last_cond;
1100
1101         switch (cond) {
1102         case COND_IF:
1103                 if (last_cond != COND_NONE && last_cond != COND_ELIF) {
1104                         if (ms->flags & MAGIC_CHECK)
1105                                 file_magwarn(ms, "syntax error: `if'");
1106                         return -1;
1107                 }
1108                 last_cond = COND_IF;
1109                 break;
1110
1111         case COND_ELIF:
1112                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
1113                         if (ms->flags & MAGIC_CHECK)
1114                                 file_magwarn(ms, "syntax error: `elif'");
1115                         return -1;
1116                 }
1117                 last_cond = COND_ELIF;
1118                 break;
1119
1120         case COND_ELSE:
1121                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
1122                         if (ms->flags & MAGIC_CHECK)
1123                                 file_magwarn(ms, "syntax error: `else'");
1124                         return -1;
1125                 }
1126                 last_cond = COND_NONE;
1127                 break;
1128
1129         case COND_NONE:
1130                 last_cond = COND_NONE;
1131                 break;
1132         }
1133
1134         ms->c.li[cont_level].last_cond = last_cond;
1135         return 0;
1136 }
1137 #endif /* ENABLE_CONDITIONALS */
1138
1139 /*
1140  * parse one line from magic file, put into magic[index++] if valid
1141  */
1142 private int
1143 parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, 
1144     const char *line, size_t lineno, int action)
1145 {
1146 #ifdef ENABLE_CONDITIONALS
1147         static uint32_t last_cont_level = 0;
1148 #endif
1149         size_t i;
1150         struct magic_entry *me;
1151         struct magic *m;
1152         const char *l = line;
1153         char *t;
1154         int op;
1155         uint32_t cont_level;
1156
1157         cont_level = 0;
1158
1159         while (*l == '>') {
1160                 ++l;            /* step over */
1161                 cont_level++; 
1162         }
1163 #ifdef ENABLE_CONDITIONALS
1164         if (cont_level == 0 || cont_level > last_cont_level)
1165                 if (file_check_mem(ms, cont_level) == -1)
1166                         return -1;
1167         last_cont_level = cont_level;
1168 #endif
1169
1170 #define ALLOC_CHUNK     (size_t)10
1171 #define ALLOC_INCR      (size_t)200
1172
1173         if (cont_level != 0) {
1174                 if (*nmentryp == 0) {
1175                         file_error(ms, 0, "No current entry for continuation");
1176                         return -1;
1177                 }
1178                 me = &(*mentryp)[*nmentryp - 1];
1179                 if (me->cont_count == me->max_count) {
1180                         struct magic *nm;
1181                         size_t cnt = me->max_count + ALLOC_CHUNK;
1182                         if ((nm = CAST(struct magic *, realloc(me->mp,
1183                             sizeof(*nm) * cnt))) == NULL) {
1184                                 file_oomem(ms, sizeof(*nm) * cnt);
1185                                 return -1;
1186                         }
1187                         me->mp = m = nm;
1188                         me->max_count = CAST(uint32_t, cnt);
1189                 }
1190                 m = &me->mp[me->cont_count++];
1191                 (void)memset(m, 0, sizeof(*m));
1192                 m->cont_level = cont_level;
1193         } else {
1194                 if (*nmentryp == maxmagic) {
1195                         struct magic_entry *mp;
1196
1197                         maxmagic += ALLOC_INCR;
1198                         if ((mp = CAST(struct magic_entry *,
1199                             realloc(*mentryp, sizeof(*mp) * maxmagic))) ==
1200                             NULL) {
1201                                 file_oomem(ms, sizeof(*mp) * maxmagic);
1202                                 return -1;
1203                         }
1204                         (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
1205                             ALLOC_INCR);
1206                         *mentryp = mp;
1207                 }
1208                 me = &(*mentryp)[*nmentryp];
1209                 if (me->mp == NULL) {
1210                         size_t len = sizeof(*m) * ALLOC_CHUNK;
1211                         if ((m = CAST(struct magic *, malloc(len))) == NULL) {
1212                                 file_oomem(ms, len);
1213                                 return -1;
1214                         }
1215                         me->mp = m;
1216                         me->max_count = ALLOC_CHUNK;
1217                 } else
1218                         m = me->mp;
1219                 (void)memset(m, 0, sizeof(*m));
1220                 m->factor_op = FILE_FACTOR_OP_NONE;
1221                 m->cont_level = 0;
1222                 me->cont_count = 1;
1223         }
1224         m->lineno = CAST(uint32_t, lineno);
1225
1226         if (*l == '&') {  /* m->cont_level == 0 checked below. */
1227                 ++l;            /* step over */
1228                 m->flag |= OFFADD;
1229         }
1230         if (*l == '(') {
1231                 ++l;            /* step over */
1232                 m->flag |= INDIR;
1233                 if (m->flag & OFFADD)
1234                         m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
1235
1236                 if (*l == '&') {  /* m->cont_level == 0 checked below */
1237                         ++l;            /* step over */
1238                         m->flag |= OFFADD;
1239                 }
1240         }
1241         /* Indirect offsets are not valid at level 0. */
1242         if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
1243                 if (ms->flags & MAGIC_CHECK)
1244                         file_magwarn(ms, "relative offset at level 0");
1245
1246         /* get offset, then skip over it */
1247         m->offset = (uint32_t)strtoul(l, &t, 0);
1248         if (l == t)
1249                 if (ms->flags & MAGIC_CHECK)
1250                         file_magwarn(ms, "offset `%s' invalid", l);
1251         l = t;
1252
1253         if (m->flag & INDIR) {
1254                 m->in_type = FILE_LONG;
1255                 m->in_offset = 0;
1256                 /*
1257                  * read [.lbs][+-]nnnnn)
1258                  */
1259                 if (*l == '.') {
1260                         l++;
1261                         switch (*l) {
1262                         case 'l':
1263                                 m->in_type = FILE_LELONG;
1264                                 break;
1265                         case 'L':
1266                                 m->in_type = FILE_BELONG;
1267                                 break;
1268                         case 'm':
1269                                 m->in_type = FILE_MELONG;
1270                                 break;
1271                         case 'h':
1272                         case 's':
1273                                 m->in_type = FILE_LESHORT;
1274                                 break;
1275                         case 'H':
1276                         case 'S':
1277                                 m->in_type = FILE_BESHORT;
1278                                 break;
1279                         case 'c':
1280                         case 'b':
1281                         case 'C':
1282                         case 'B':
1283                                 m->in_type = FILE_BYTE;
1284                                 break;
1285                         case 'e':
1286                         case 'f':
1287                         case 'g':
1288                                 m->in_type = FILE_LEDOUBLE;
1289                                 break;
1290                         case 'E':
1291                         case 'F':
1292                         case 'G':
1293                                 m->in_type = FILE_BEDOUBLE;
1294                                 break;
1295                         case 'i':
1296                                 m->in_type = FILE_LEID3;
1297                                 break;
1298                         case 'I':
1299                                 m->in_type = FILE_BEID3;
1300                                 break;
1301                         default:
1302                                 if (ms->flags & MAGIC_CHECK)
1303                                         file_magwarn(ms,
1304                                             "indirect offset type `%c' invalid",
1305                                             *l);
1306                                 break;
1307                         }
1308                         l++;
1309                 }
1310
1311                 m->in_op = 0;
1312                 if (*l == '~') {
1313                         m->in_op |= FILE_OPINVERSE;
1314                         l++;
1315                 }
1316                 if ((op = get_op(*l)) != -1) {
1317                         m->in_op |= op;
1318                         l++;
1319                 }
1320                 if (*l == '(') {
1321                         m->in_op |= FILE_OPINDIRECT;
1322                         l++;
1323                 }
1324                 if (isdigit((unsigned char)*l) || *l == '-') {
1325                         m->in_offset = (int32_t)strtol(l, &t, 0);
1326                         if (l == t)
1327                                 if (ms->flags & MAGIC_CHECK)
1328                                         file_magwarn(ms,
1329                                             "in_offset `%s' invalid", l);
1330                         l = t;
1331                 }
1332                 if (*l++ != ')' || 
1333                     ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
1334                         if (ms->flags & MAGIC_CHECK)
1335                                 file_magwarn(ms,
1336                                     "missing ')' in indirect offset");
1337         }
1338         EATAB;
1339
1340 #ifdef ENABLE_CONDITIONALS
1341         m->cond = get_cond(l, &l);
1342         if (check_cond(ms, m->cond, cont_level) == -1)
1343                 return -1;
1344
1345         EATAB;
1346 #endif
1347
1348         if (*l == 'u') {
1349                 ++l;
1350                 m->flag |= UNSIGNED;
1351         }
1352
1353         m->type = get_type(l, &l);
1354         if (m->type == FILE_INVALID) {
1355                 if (ms->flags & MAGIC_CHECK)
1356                         file_magwarn(ms, "type `%s' invalid", l);
1357                 return -1;
1358         }
1359
1360         /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
1361         /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
1362
1363         m->mask_op = 0;
1364         if (*l == '~') {
1365                 if (!IS_STRING(m->type))
1366                         m->mask_op |= FILE_OPINVERSE;
1367                 else if (ms->flags & MAGIC_CHECK)
1368                         file_magwarn(ms, "'~' invalid for string types");
1369                 ++l;
1370         }
1371         m->str_range = 0;
1372         m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0;
1373         if ((op = get_op(*l)) != -1) {
1374                 if (!IS_STRING(m->type)) {
1375                         uint64_t val;
1376                         ++l;
1377                         m->mask_op |= op;
1378                         val = (uint64_t)strtoull(l, &t, 0);
1379                         l = t;
1380                         m->num_mask = file_signextend(ms, m, val);
1381                         eatsize(&l);
1382                 }
1383                 else if (op == FILE_OPDIVIDE) {
1384                         int have_range = 0;
1385                         while (!isspace((unsigned char)*++l)) {
1386                                 switch (*l) {
1387                                 case '0':  case '1':  case '2':
1388                                 case '3':  case '4':  case '5':
1389                                 case '6':  case '7':  case '8':
1390                                 case '9':
1391                                         if (have_range &&
1392                                             (ms->flags & MAGIC_CHECK))
1393                                                 file_magwarn(ms,
1394                                                     "multiple ranges");
1395                                         have_range = 1;
1396                                         m->str_range = CAST(uint32_t,
1397                                             strtoul(l, &t, 0));
1398                                         if (m->str_range == 0)
1399                                                 file_magwarn(ms,
1400                                                     "zero range");
1401                                         l = t - 1;
1402                                         break;
1403                                 case CHAR_COMPACT_WHITESPACE:
1404                                         m->str_flags |=
1405                                             STRING_COMPACT_WHITESPACE;
1406                                         break;
1407                                 case CHAR_COMPACT_OPTIONAL_WHITESPACE:
1408                                         m->str_flags |=
1409                                             STRING_COMPACT_OPTIONAL_WHITESPACE;
1410                                         break;
1411                                 case CHAR_IGNORE_LOWERCASE:
1412                                         m->str_flags |= STRING_IGNORE_LOWERCASE;
1413                                         break;
1414                                 case CHAR_IGNORE_UPPERCASE:
1415                                         m->str_flags |= STRING_IGNORE_UPPERCASE;
1416                                         break;
1417                                 case CHAR_REGEX_OFFSET_START:
1418                                         m->str_flags |= REGEX_OFFSET_START;
1419                                         break;
1420                                 case CHAR_BINTEST:
1421                                         m->str_flags |= STRING_BINTEST;
1422                                         break;
1423                                 case CHAR_TEXTTEST:
1424                                         m->str_flags |= STRING_TEXTTEST;
1425                                         break;
1426                                 case CHAR_PSTRING_1_LE:
1427                                         if (m->type != FILE_PSTRING)
1428                                                 goto bad;
1429                                         m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_1_LE;
1430                                         break;
1431                                 case CHAR_PSTRING_2_BE:
1432                                         if (m->type != FILE_PSTRING)
1433                                                 goto bad;
1434                                         m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_2_BE;
1435                                         break;
1436                                 case CHAR_PSTRING_2_LE:
1437                                         if (m->type != FILE_PSTRING)
1438                                                 goto bad;
1439                                         m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_2_LE;
1440                                         break;
1441                                 case CHAR_PSTRING_4_BE:
1442                                         if (m->type != FILE_PSTRING)
1443                                                 goto bad;
1444                                         m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_4_BE;
1445                                         break;
1446                                 case CHAR_PSTRING_4_LE:
1447                                         if (m->type != FILE_PSTRING)
1448                                                 goto bad;
1449                                         m->str_flags = (m->str_flags & ~PSTRING_LEN) | PSTRING_4_LE;
1450                                         break;
1451                                 case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF:
1452                                         if (m->type != FILE_PSTRING)
1453                                                 goto bad;
1454                                         m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF;
1455                                         break;
1456                                 default:
1457                                 bad:
1458                                         if (ms->flags & MAGIC_CHECK)
1459                                                 file_magwarn(ms,
1460                                                     "string extension `%c' "
1461                                                     "invalid", *l);
1462                                         return -1;
1463                                 }
1464                                 /* allow multiple '/' for readability */
1465                                 if (l[1] == '/' &&
1466                                     !isspace((unsigned char)l[2]))
1467                                         l++;
1468                         }
1469                         if (string_modifier_check(ms, m) == -1)
1470                                 return -1;
1471                 }
1472                 else {
1473                         if (ms->flags & MAGIC_CHECK)
1474                                 file_magwarn(ms, "invalid string op: %c", *t);
1475                         return -1;
1476                 }
1477         }
1478         /*
1479          * We used to set mask to all 1's here, instead let's just not do
1480          * anything if mask = 0 (unless you have a better idea)
1481          */
1482         EATAB;
1483   
1484         switch (*l) {
1485         case '>':
1486         case '<':
1487                 m->reln = *l;
1488                 ++l;
1489                 if (*l == '=') {
1490                         if (ms->flags & MAGIC_CHECK) {
1491                                 file_magwarn(ms, "%c= not supported",
1492                                     m->reln);
1493                                 return -1;
1494                         }
1495                    ++l;
1496                 }
1497                 break;
1498         /* Old-style anding: "0 byte &0x80 dynamically linked" */
1499         case '&':
1500         case '^':
1501         case '=':
1502                 m->reln = *l;
1503                 ++l;
1504                 if (*l == '=') {
1505                    /* HP compat: ignore &= etc. */
1506                    ++l;
1507                 }
1508                 break;
1509         case '!':
1510                 m->reln = *l;
1511                 ++l;
1512                 break;
1513         default:
1514                 m->reln = '=';  /* the default relation */
1515                 if (*l == 'x' && ((isascii((unsigned char)l[1]) && 
1516                     isspace((unsigned char)l[1])) || !l[1])) {
1517                         m->reln = *l;
1518                         ++l;
1519                 }
1520                 break;
1521         }
1522         /*
1523          * Grab the value part, except for an 'x' reln.
1524          */
1525         if (m->reln != 'x' && getvalue(ms, m, &l, action))
1526                 return -1;
1527
1528         /*
1529          * TODO finish this macro and start using it!
1530          * #define offsetcheck {if (offset > HOWMANY-1) 
1531          *      magwarn("offset too big"); }
1532          */
1533
1534         /*
1535          * Now get last part - the description
1536          */
1537         EATAB;
1538         if (l[0] == '\b') {
1539                 ++l;
1540                 m->flag |= NOSPACE;
1541         } else if ((l[0] == '\\') && (l[1] == 'b')) {
1542                 ++l;
1543                 ++l;
1544                 m->flag |= NOSPACE;
1545         }
1546         for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
1547                 continue;
1548         if (i == sizeof(m->desc)) {
1549                 m->desc[sizeof(m->desc) - 1] = '\0';
1550                 if (ms->flags & MAGIC_CHECK)
1551                         file_magwarn(ms, "description `%s' truncated", m->desc);
1552         }
1553
1554         /*
1555          * We only do this check while compiling, or if any of the magic
1556          * files were not compiled.
1557          */
1558         if (ms->flags & MAGIC_CHECK) {
1559                 if (check_format(ms, m) == -1)
1560                         return -1;
1561         }
1562 #ifndef COMPILE_ONLY
1563         if (action == FILE_CHECK) {
1564                 file_mdump(m);
1565         }
1566 #endif
1567         m->mimetype[0] = '\0';          /* initialise MIME type to none */
1568         if (m->cont_level == 0)
1569                 ++(*nmentryp);          /* make room for next */
1570         return 0;
1571 }
1572
1573 /*
1574  * parse a STRENGTH annotation line from magic file, put into magic[index - 1]
1575  * if valid
1576  */
1577 private int
1578 parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line)
1579 {
1580         const char *l = line;
1581         char *el;
1582         unsigned long factor;
1583         struct magic *m = &me->mp[0];
1584
1585         if (m->factor_op != FILE_FACTOR_OP_NONE) {
1586                 file_magwarn(ms,
1587                     "Current entry already has a strength type: %c %d",
1588                     m->factor_op, m->factor);
1589                 return -1;
1590         }
1591         EATAB;
1592         switch (*l) {
1593         case FILE_FACTOR_OP_NONE:
1594         case FILE_FACTOR_OP_PLUS:
1595         case FILE_FACTOR_OP_MINUS:
1596         case FILE_FACTOR_OP_TIMES:
1597         case FILE_FACTOR_OP_DIV:
1598                 m->factor_op = *l++;
1599                 break;
1600         default:
1601                 file_magwarn(ms, "Unknown factor op `%c'", *l);
1602                 return -1;
1603         }
1604         EATAB;
1605         factor = strtoul(l, &el, 0);
1606         if (factor > 255) {
1607                 file_magwarn(ms, "Too large factor `%lu'", factor);
1608                 goto out;
1609         }
1610         if (*el && !isspace((unsigned char)*el)) {
1611                 file_magwarn(ms, "Bad factor `%s'", l);
1612                 goto out;
1613         }
1614         m->factor = (uint8_t)factor;
1615         if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) {
1616                 file_magwarn(ms, "Cannot have factor op `%c' and factor %u",
1617                     m->factor_op, m->factor);
1618                 goto out;
1619         }
1620         return 0;
1621 out:
1622         m->factor_op = FILE_FACTOR_OP_NONE;
1623         m->factor = 0;
1624         return -1;
1625 }
1626
1627 /*
1628  * Parse an Apple CREATOR/TYPE annotation from magic file and put it into
1629  * magic[index - 1]
1630  */
1631 private int
1632 parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line)
1633 {
1634         size_t i;
1635         const char *l = line;
1636         struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
1637
1638         if (m->apple[0] != '\0') {
1639                 file_magwarn(ms, "Current entry already has a APPLE type "
1640                     "`%.8s', new type `%s'", m->mimetype, l);
1641                 return -1;
1642         }       
1643
1644         EATAB;
1645         for (i = 0; *l && ((isascii((unsigned char)*l) &&
1646             isalnum((unsigned char)*l)) || strchr("-+/.", *l)) &&
1647             i < sizeof(m->apple); m->apple[i++] = *l++)
1648                 continue;
1649         if (i == sizeof(m->apple) && *l) {
1650                 /* We don't need to NUL terminate here, printing handles it */
1651                 if (ms->flags & MAGIC_CHECK)
1652                         file_magwarn(ms, "APPLE type `%s' truncated %"
1653                             SIZE_T_FORMAT "u", line, i);
1654         }
1655
1656         if (i > 0)
1657                 return 0;
1658         else
1659                 return -1;
1660 }
1661
1662 /*
1663  * parse a MIME annotation line from magic file, put into magic[index - 1]
1664  * if valid
1665  */
1666 private int
1667 parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line)
1668 {
1669         size_t i;
1670         const char *l = line;
1671         struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
1672
1673         if (m->mimetype[0] != '\0') {
1674                 file_magwarn(ms, "Current entry already has a MIME type `%s',"
1675                     " new type `%s'", m->mimetype, l);
1676                 return -1;
1677         }       
1678
1679         EATAB;
1680         for (i = 0; *l && ((isascii((unsigned char)*l) &&
1681             isalnum((unsigned char)*l)) || strchr("-+/.", *l)) &&
1682             i < sizeof(m->mimetype); m->mimetype[i++] = *l++)
1683                 continue;
1684         if (i == sizeof(m->mimetype)) {
1685                 m->mimetype[sizeof(m->mimetype) - 1] = '\0';
1686                 if (ms->flags & MAGIC_CHECK)
1687                         file_magwarn(ms, "MIME type `%s' truncated %"
1688                             SIZE_T_FORMAT "u", m->mimetype, i);
1689         } else
1690                 m->mimetype[i] = '\0';
1691
1692         if (i > 0)
1693                 return 0;
1694         else
1695                 return -1;
1696 }
1697
1698 private int
1699 check_format_type(const char *ptr, int type)
1700 {
1701         int quad = 0;
1702         if (*ptr == '\0') {
1703                 /* Missing format string; bad */
1704                 return -1;
1705         }
1706
1707         switch (type) {
1708         case FILE_FMT_QUAD:
1709                 quad = 1;
1710                 /*FALLTHROUGH*/
1711         case FILE_FMT_NUM:
1712                 if (*ptr == '-')
1713                         ptr++;
1714                 if (*ptr == '.')
1715                         ptr++;
1716                 while (isdigit((unsigned char)*ptr)) ptr++;
1717                 if (*ptr == '.')
1718                         ptr++;
1719                 while (isdigit((unsigned char)*ptr)) ptr++;
1720                 if (quad) {
1721                         if (*ptr++ != 'l')
1722                                 return -1;
1723                         if (*ptr++ != 'l')
1724                                 return -1;
1725                 }
1726         
1727                 switch (*ptr++) {
1728                 case 'l':
1729                         switch (*ptr++) {
1730                         case 'i':
1731                         case 'd':
1732                         case 'u':
1733                         case 'x':
1734                         case 'X':
1735                                 return 0;
1736                         default:
1737                                 return -1;
1738                         }
1739                 
1740                 case 'h':
1741                         switch (*ptr++) {
1742                         case 'h':
1743                                 switch (*ptr++) {
1744                                 case 'i':
1745                                 case 'd':
1746                                 case 'u':
1747                                 case 'x':
1748                                 case 'X':
1749                                         return 0;
1750                                 default:
1751                                         return -1;
1752                                 }
1753                         case 'd':
1754                                 return 0;
1755                         default:
1756                                 return -1;
1757                         }
1758
1759                 case 'i':
1760                 case 'c':
1761                 case 'd':
1762                 case 'u':
1763                 case 'x':
1764                 case 'X':
1765                         return 0;
1766                         
1767                 default:
1768                         return -1;
1769                 }
1770                 
1771         case FILE_FMT_FLOAT:
1772         case FILE_FMT_DOUBLE:
1773                 if (*ptr == '-')
1774                         ptr++;
1775                 if (*ptr == '.')
1776                         ptr++;
1777                 while (isdigit((unsigned char)*ptr)) ptr++;
1778                 if (*ptr == '.')
1779                         ptr++;
1780                 while (isdigit((unsigned char)*ptr)) ptr++;
1781         
1782                 switch (*ptr++) {
1783                 case 'e':
1784                 case 'E':
1785                 case 'f':
1786                 case 'F':
1787                 case 'g':
1788                 case 'G':
1789                         return 0;
1790                         
1791                 default:
1792                         return -1;
1793                 }
1794                 
1795
1796         case FILE_FMT_STR:
1797                 if (*ptr == '-')
1798                         ptr++;
1799                 while (isdigit((unsigned char )*ptr))
1800                         ptr++;
1801                 if (*ptr == '.') {
1802                         ptr++;
1803                         while (isdigit((unsigned char )*ptr))
1804                                 ptr++;
1805                 }
1806                 
1807                 switch (*ptr++) {
1808                 case 's':
1809                         return 0;
1810                 default:
1811                         return -1;
1812                 }
1813                 
1814         default:
1815                 /* internal error */
1816                 abort();
1817         }
1818         /*NOTREACHED*/
1819         return -1;
1820 }
1821         
1822 /*
1823  * Check that the optional printf format in description matches
1824  * the type of the magic.
1825  */
1826 private int
1827 check_format(struct magic_set *ms, struct magic *m)
1828 {
1829         char *ptr;
1830
1831         for (ptr = m->desc; *ptr; ptr++)
1832                 if (*ptr == '%')
1833                         break;
1834         if (*ptr == '\0') {
1835                 /* No format string; ok */
1836                 return 1;
1837         }
1838
1839         assert(file_nformats == file_nnames);
1840
1841         if (m->type >= file_nformats) {
1842                 file_magwarn(ms, "Internal error inconsistency between "
1843                     "m->type and format strings");              
1844                 return -1;
1845         }
1846         if (file_formats[m->type] == FILE_FMT_NONE) {
1847                 file_magwarn(ms, "No format string for `%s' with description "
1848                     "`%s'", m->desc, file_names[m->type]);
1849                 return -1;
1850         }
1851
1852         ptr++;
1853         if (check_format_type(ptr, file_formats[m->type]) == -1) {
1854                 /*
1855                  * TODO: this error message is unhelpful if the format
1856                  * string is not one character long
1857                  */
1858                 file_magwarn(ms, "Printf format `%c' is not valid for type "
1859                     "`%s' in description `%s'", *ptr ? *ptr : '?',
1860                     file_names[m->type], m->desc);
1861                 return -1;
1862         }
1863         
1864         for (; *ptr; ptr++) {
1865                 if (*ptr == '%') {
1866                         file_magwarn(ms,
1867                             "Too many format strings (should have at most one) "
1868                             "for `%s' with description `%s'",
1869                             file_names[m->type], m->desc);
1870                         return -1;
1871                 }
1872         }
1873         return 0;
1874 }
1875
1876 /* 
1877  * Read a numeric value from a pointer, into the value union of a magic 
1878  * pointer, according to the magic type.  Update the string pointer to point 
1879  * just after the number read.  Return 0 for success, non-zero for failure.
1880  */
1881 private int
1882 getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
1883 {
1884         switch (m->type) {
1885         case FILE_BESTRING16:
1886         case FILE_LESTRING16:
1887         case FILE_STRING:
1888         case FILE_PSTRING:
1889         case FILE_REGEX:
1890         case FILE_SEARCH:
1891                 *p = getstr(ms, m, *p, action == FILE_COMPILE);
1892                 if (*p == NULL) {
1893                         if (ms->flags & MAGIC_CHECK)
1894                                 file_magwarn(ms, "cannot get string from `%s'",
1895                                     m->value.s);
1896                         return -1;
1897                 }
1898                 return 0;
1899         case FILE_FLOAT:
1900         case FILE_BEFLOAT:
1901         case FILE_LEFLOAT:
1902                 if (m->reln != 'x') {
1903                         char *ep;
1904 #if defined(HAVE_STRTOF) && !defined(COMPILE_ONLY)
1905                         m->value.f = strtof(*p, &ep);
1906 #else
1907                         m->value.f = (float)strtod(*p, &ep);
1908 #endif
1909                         *p = ep;
1910                 }
1911                 return 0;
1912         case FILE_DOUBLE:
1913         case FILE_BEDOUBLE:
1914         case FILE_LEDOUBLE:
1915                 if (m->reln != 'x') {
1916                         char *ep;
1917                         m->value.d = strtod(*p, &ep);
1918                         *p = ep;
1919                 }
1920                 return 0;
1921         default:
1922                 if (m->reln != 'x') {
1923                         char *ep;
1924                         m->value.q = file_signextend(ms, m,
1925                             (uint64_t)strtoull(*p, &ep, 0));
1926                         *p = ep;
1927                         eatsize(p);
1928                 }
1929                 return 0;
1930         }
1931 }
1932
1933 /*
1934  * Convert a string containing C character escapes.  Stop at an unescaped
1935  * space or tab.
1936  * Copy the converted version to "m->value.s", and the length in m->vallen.
1937  * Return updated scan pointer as function result. Warn if set.
1938  */
1939 private const char *
1940 getstr(struct magic_set *ms, struct magic *m, const char *s, int warn)
1941 {
1942         const char *origs = s;
1943         char    *p = m->value.s;
1944         size_t  plen = sizeof(m->value.s);
1945         char    *origp = p;
1946         char    *pmax = p + plen - 1;
1947         int     c;
1948         int     val;
1949
1950         while ((c = *s++) != '\0') {
1951                 if (isspace((unsigned char) c))
1952                         break;
1953                 if (p >= pmax) {
1954                         file_error(ms, 0, "string too long: `%s'", origs);
1955                         return NULL;
1956                 }
1957                 if (c == '\\') {
1958                         switch(c = *s++) {
1959
1960                         case '\0':
1961                                 if (warn)
1962                                         file_magwarn(ms, "incomplete escape");
1963                                 goto out;
1964
1965                         case '\t':
1966                                 if (warn) {
1967                                         file_magwarn(ms,
1968                                             "escaped tab found, use \\t instead");
1969                                         warn = 0;       /* already did */
1970                                 }
1971                                 /*FALLTHROUGH*/
1972                         default:
1973                                 if (warn) {
1974                                         if (isprint((unsigned char)c)) {
1975                                                 /* Allow escaping of 
1976                                                  * ``relations'' */
1977                                                 if (strchr("<>&^=!", c) == NULL
1978                                                     && (m->type != FILE_REGEX ||
1979                                                     strchr("[]().*?^$|{}", c)
1980                                                     == NULL)) {
1981                                                         file_magwarn(ms, "no "
1982                                                             "need to escape "
1983                                                             "`%c'", c);
1984                                                 }
1985                                         } else {
1986                                                 file_magwarn(ms,
1987                                                     "unknown escape sequence: "
1988                                                     "\\%03o", c);
1989                                         }
1990                                 }
1991                                 /*FALLTHROUGH*/
1992                         /* space, perhaps force people to use \040? */
1993                         case ' ':
1994 #if 0
1995                         /*
1996                          * Other things people escape, but shouldn't need to,
1997                          * so we disallow them
1998                          */
1999                         case '\'':
2000                         case '"':
2001                         case '?':
2002 #endif
2003                         /* Relations */
2004                         case '>':
2005                         case '<':
2006                         case '&':
2007                         case '^':
2008                         case '=':
2009                         case '!':
2010                         /* and baskslash itself */
2011                         case '\\':
2012                                 *p++ = (char) c;
2013                                 break;
2014
2015                         case 'a':
2016                                 *p++ = '\a';
2017                                 break;
2018
2019                         case 'b':
2020                                 *p++ = '\b';
2021                                 break;
2022
2023                         case 'f':
2024                                 *p++ = '\f';
2025                                 break;
2026
2027                         case 'n':
2028                                 *p++ = '\n';
2029                                 break;
2030
2031                         case 'r':
2032                                 *p++ = '\r';
2033                                 break;
2034
2035                         case 't':
2036                                 *p++ = '\t';
2037                                 break;
2038
2039                         case 'v':
2040                                 *p++ = '\v';
2041                                 break;
2042
2043                         /* \ and up to 3 octal digits */
2044                         case '0':
2045                         case '1':
2046                         case '2':
2047                         case '3':
2048                         case '4':
2049                         case '5':
2050                         case '6':
2051                         case '7':
2052                                 val = c - '0';
2053                                 c = *s++;  /* try for 2 */
2054                                 if (c >= '0' && c <= '7') {
2055                                         val = (val << 3) | (c - '0');
2056                                         c = *s++;  /* try for 3 */
2057                                         if (c >= '0' && c <= '7')
2058                                                 val = (val << 3) | (c-'0');
2059                                         else
2060                                                 --s;
2061                                 }
2062                                 else
2063                                         --s;
2064                                 *p++ = (char)val;
2065                                 break;
2066
2067                         /* \x and up to 2 hex digits */
2068                         case 'x':
2069                                 val = 'x';      /* Default if no digits */
2070                                 c = hextoint(*s++);     /* Get next char */
2071                                 if (c >= 0) {
2072                                         val = c;
2073                                         c = hextoint(*s++);
2074                                         if (c >= 0)
2075                                                 val = (val << 4) + c;
2076                                         else
2077                                                 --s;
2078                                 } else
2079                                         --s;
2080                                 *p++ = (char)val;
2081                                 break;
2082                         }
2083                 } else
2084                         *p++ = (char)c;
2085         }
2086 out:
2087         *p = '\0';
2088         m->vallen = CAST(unsigned char, (p - origp));
2089         if (m->type == FILE_PSTRING)
2090                 m->vallen += (unsigned char)file_pstring_length_size(m);
2091         return s;
2092 }
2093
2094
2095 /* Single hex char to int; -1 if not a hex char. */
2096 private int
2097 hextoint(int c)
2098 {
2099         if (!isascii((unsigned char) c))
2100                 return -1;
2101         if (isdigit((unsigned char) c))
2102                 return c - '0';
2103         if ((c >= 'a') && (c <= 'f'))
2104                 return c + 10 - 'a';
2105         if (( c>= 'A') && (c <= 'F'))
2106                 return c + 10 - 'A';
2107         return -1;
2108 }
2109
2110
2111 /*
2112  * Print a string containing C character escapes.
2113  */
2114 protected void
2115 file_showstr(FILE *fp, const char *s, size_t len)
2116 {
2117         char    c;
2118
2119         for (;;) {
2120                 if (len == ~0U) {
2121                         c = *s++;
2122                         if (c == '\0')
2123                                 break;
2124                 }
2125                 else  {
2126                         if (len-- == 0)
2127                                 break;
2128                         c = *s++;
2129                 }
2130                 if (c >= 040 && c <= 0176)      /* TODO isprint && !iscntrl */
2131                         (void) fputc(c, fp);
2132                 else {
2133                         (void) fputc('\\', fp);
2134                         switch (c) {
2135                         case '\a':
2136                                 (void) fputc('a', fp);
2137                                 break;
2138
2139                         case '\b':
2140                                 (void) fputc('b', fp);
2141                                 break;
2142
2143                         case '\f':
2144                                 (void) fputc('f', fp);
2145                                 break;
2146
2147                         case '\n':
2148                                 (void) fputc('n', fp);
2149                                 break;
2150
2151                         case '\r':
2152                                 (void) fputc('r', fp);
2153                                 break;
2154
2155                         case '\t':
2156                                 (void) fputc('t', fp);
2157                                 break;
2158
2159                         case '\v':
2160                                 (void) fputc('v', fp);
2161                                 break;
2162
2163                         default:
2164                                 (void) fprintf(fp, "%.3o", c & 0377);
2165                                 break;
2166                         }
2167                 }
2168         }
2169 }
2170
2171 /*
2172  * eatsize(): Eat the size spec from a number [eg. 10UL]
2173  */
2174 private void
2175 eatsize(const char **p)
2176 {
2177         const char *l = *p;
2178
2179         if (LOWCASE(*l) == 'u') 
2180                 l++;
2181
2182         switch (LOWCASE(*l)) {
2183         case 'l':    /* long */
2184         case 's':    /* short */
2185         case 'h':    /* short */
2186         case 'b':    /* char/byte */
2187         case 'c':    /* char/byte */
2188                 l++;
2189                 /*FALLTHROUGH*/
2190         default:
2191                 break;
2192         }
2193
2194         *p = l;
2195 }
2196
2197 /*
2198  * handle a compiled file.
2199  */
2200 private int
2201 apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
2202     const char *fn)
2203 {
2204         int fd;
2205         struct stat st;
2206         uint32_t *ptr;
2207         uint32_t version;
2208         int needsbyteswap;
2209         char *dbname = NULL;
2210         void *mm = NULL;
2211
2212         dbname = mkdbname(ms, fn, 0);
2213         if (dbname == NULL)
2214                 goto error2;
2215
2216         if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
2217                 goto error2;
2218
2219         if (fstat(fd, &st) == -1) {
2220                 file_error(ms, errno, "cannot stat `%s'", dbname);
2221                 goto error1;
2222         }
2223         if (st.st_size < 8) {
2224                 file_error(ms, 0, "file `%s' is too small", dbname);
2225                 goto error1;
2226         }
2227
2228 #ifdef QUICK
2229         if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
2230             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
2231                 file_error(ms, errno, "cannot map `%s'", dbname);
2232                 goto error1;
2233         }
2234 #define RET     2
2235 #else
2236         if ((mm = CAST(void *, malloc((size_t)st.st_size))) == NULL) {
2237                 file_oomem(ms, (size_t)st.st_size);
2238                 goto error1;
2239         }
2240         if (read(fd, mm, (size_t)st.st_size) != (ssize_t)st.st_size) {
2241                 file_badread(ms);
2242                 goto error1;
2243         }
2244 #define RET     1
2245 #endif
2246         *magicp = CAST(struct magic *, mm);
2247         (void)close(fd);
2248         fd = -1;
2249         ptr = (uint32_t *)(void *)*magicp;
2250         if (*ptr != MAGICNO) {
2251                 if (swap4(*ptr) != MAGICNO) {
2252                         file_error(ms, 0, "bad magic in `%s'", dbname);
2253                         goto error1;
2254                 }
2255                 needsbyteswap = 1;
2256         } else
2257                 needsbyteswap = 0;
2258         if (needsbyteswap)
2259                 version = swap4(ptr[1]);
2260         else
2261                 version = ptr[1];
2262         if (version != VERSIONNO) {
2263                 file_error(ms, 0, "File %s supports only version %d magic "
2264                     "files. `%s' is version %d", VERSION,
2265                     VERSIONNO, dbname, version);
2266                 goto error1;
2267         }
2268         *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic));
2269         if (*nmagicp > 0)
2270                 (*nmagicp)--;
2271         (*magicp)++;
2272         if (needsbyteswap)
2273                 byteswap(*magicp, *nmagicp);
2274         free(dbname);
2275         return RET;
2276
2277 error1:
2278         if (fd != -1)
2279                 (void)close(fd);
2280         if (mm) {
2281 #ifdef QUICK
2282                 (void)munmap((void *)mm, (size_t)st.st_size);
2283 #else
2284                 free(mm);
2285 #endif
2286         } else {
2287                 *magicp = NULL;
2288                 *nmagicp = 0;
2289         }
2290 error2:
2291         free(dbname);
2292         return -1;
2293 }
2294
2295 private const uint32_t ar[] = {
2296     MAGICNO, VERSIONNO
2297 };
2298 /*
2299  * handle an mmaped file.
2300  */
2301 private int
2302 apprentice_compile(struct magic_set *ms, struct magic **magicp,
2303     uint32_t *nmagicp, const char *fn)
2304 {
2305         int fd = -1;
2306         char *dbname;
2307         int rv = -1;
2308
2309         dbname = mkdbname(ms, fn, 1);
2310
2311         if (dbname == NULL) 
2312                 goto out;
2313
2314         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
2315                 file_error(ms, errno, "cannot open `%s'", dbname);
2316                 goto out;
2317         }
2318
2319         if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
2320                 file_error(ms, errno, "error writing `%s'", dbname);
2321                 goto out;
2322         }
2323
2324         if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
2325             != sizeof(struct magic)) {
2326                 file_error(ms, errno, "error seeking `%s'", dbname);
2327                 goto out;
2328         }
2329
2330         if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp)) 
2331             != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
2332                 file_error(ms, errno, "error writing `%s'", dbname);
2333                 goto out;
2334         }
2335
2336         if (fd != -1)
2337                 (void)close(fd);
2338         rv = 0;
2339 out:
2340         free(dbname);
2341         return rv;
2342 }
2343
2344 private const char ext[] = ".mgc";
2345 /*
2346  * make a dbname
2347  */
2348 private char *
2349 mkdbname(struct magic_set *ms, const char *fn, int strip)
2350 {
2351         const char *p, *q;
2352         char *buf;
2353
2354         if (strip) {
2355                 if ((p = strrchr(fn, '/')) != NULL)
2356                         fn = ++p;
2357         }
2358
2359         for (q = fn; *q; q++)
2360                 continue;
2361         /* Look for .mgc */
2362         for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--)
2363                 if (*p != *q)
2364                         break;
2365
2366         /* Did not find .mgc, restore q */
2367         if (p >= ext)
2368                 while (*q)
2369                         q++;
2370
2371         q++;
2372         /* Compatibility with old code that looked in .mime */
2373         if (ms->flags & MAGIC_MIME) {
2374                 asprintf(&buf, "%.*s.mime%s", (int)(q - fn), fn, ext);
2375                 if (access(buf, R_OK) != -1) {
2376                         ms->flags &= MAGIC_MIME_TYPE;
2377                         return buf;
2378                 }
2379                 free(buf);
2380         }
2381         asprintf(&buf, "%.*s%s", (int)(q - fn), fn, ext);
2382
2383         /* Compatibility with old code that looked in .mime */
2384         if (strstr(p, ".mime") != NULL)
2385                 ms->flags &= MAGIC_MIME_TYPE;
2386         return buf;
2387 }
2388
2389 /*
2390  * Byteswap an mmap'ed file if needed
2391  */
2392 private void
2393 byteswap(struct magic *magic, uint32_t nmagic)
2394 {
2395         uint32_t i;
2396         for (i = 0; i < nmagic; i++)
2397                 bs1(&magic[i]);
2398 }
2399
2400 /*
2401  * swap a short
2402  */
2403 private uint16_t
2404 swap2(uint16_t sv)
2405 {
2406         uint16_t rv;
2407         uint8_t *s = (uint8_t *)(void *)&sv; 
2408         uint8_t *d = (uint8_t *)(void *)&rv; 
2409         d[0] = s[1];
2410         d[1] = s[0];
2411         return rv;
2412 }
2413
2414 /*
2415  * swap an int
2416  */
2417 private uint32_t
2418 swap4(uint32_t sv)
2419 {
2420         uint32_t rv;
2421         uint8_t *s = (uint8_t *)(void *)&sv; 
2422         uint8_t *d = (uint8_t *)(void *)&rv; 
2423         d[0] = s[3];
2424         d[1] = s[2];
2425         d[2] = s[1];
2426         d[3] = s[0];
2427         return rv;
2428 }
2429
2430 /*
2431  * swap a quad
2432  */
2433 private uint64_t
2434 swap8(uint64_t sv)
2435 {
2436         uint64_t rv;
2437         uint8_t *s = (uint8_t *)(void *)&sv; 
2438         uint8_t *d = (uint8_t *)(void *)&rv; 
2439 #if 0
2440         d[0] = s[3];
2441         d[1] = s[2];
2442         d[2] = s[1];
2443         d[3] = s[0];
2444         d[4] = s[7];
2445         d[5] = s[6];
2446         d[6] = s[5];
2447         d[7] = s[4];
2448 #else
2449         d[0] = s[7];
2450         d[1] = s[6];
2451         d[2] = s[5];
2452         d[3] = s[4];
2453         d[4] = s[3];
2454         d[5] = s[2];
2455         d[6] = s[1];
2456         d[7] = s[0];
2457 #endif
2458         return rv;
2459 }
2460
2461 /*
2462  * byteswap a single magic entry
2463  */
2464 private void
2465 bs1(struct magic *m)
2466 {
2467         m->cont_level = swap2(m->cont_level);
2468         m->offset = swap4((uint32_t)m->offset);
2469         m->in_offset = swap4((uint32_t)m->in_offset);
2470         m->lineno = swap4((uint32_t)m->lineno);
2471         if (IS_STRING(m->type)) {
2472                 m->str_range = swap4(m->str_range);
2473                 m->str_flags = swap4(m->str_flags);
2474         }
2475         else {
2476                 m->value.q = swap8(m->value.q);
2477                 m->num_mask = swap8(m->num_mask);
2478         }
2479 }
2480
2481 protected size_t 
2482 file_pstring_length_size(const struct magic *m)
2483 {
2484         switch (m->str_flags & PSTRING_LEN) {
2485         case PSTRING_1_LE:
2486                 return 1;
2487         case PSTRING_2_LE:
2488         case PSTRING_2_BE:
2489                 return 2;
2490         case PSTRING_4_LE:
2491         case PSTRING_4_BE:
2492                 return 4;
2493         default:
2494                 abort();        /* Impossible */
2495                 return 1;
2496         }
2497 }
2498 protected size_t
2499 file_pstring_get_length(const struct magic *m, const char *s)
2500 {
2501         size_t len = 0;
2502
2503         switch (m->str_flags & PSTRING_LEN) {
2504         case PSTRING_1_LE:
2505                 len = *s;
2506                 break;
2507         case PSTRING_2_LE:
2508                 len = (s[1] << 8) | s[0];
2509                 break;
2510         case PSTRING_2_BE:
2511                 len = (s[0] << 8) | s[1];
2512                 break;
2513         case PSTRING_4_LE:
2514                 len = (s[3] << 24) | (s[2] << 16) | (s[1] << 8) | s[0];
2515                 break;
2516         case PSTRING_4_BE:
2517                 len = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
2518                 break;
2519         default:
2520                 abort();        /* Impossible */
2521         }
2522
2523         if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF)
2524                 len -= file_pstring_length_size(m);
2525
2526         return len;
2527 }