home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / FILE39.ZIP / apprentice.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-10  |  11.7 KB  |  573 lines

  1. /*
  2.  * apprentice - make one pass through /etc/magic, learning its secrets.
  3.  *
  4.  * Copyright (c) Ian F. Darwin, 1987.
  5.  * Written by Ian F. Darwin.
  6.  *
  7.  * This software is not subject to any license of the American Telephone
  8.  * and Telegraph Company or of the Regents of the University of California.
  9.  *
  10.  * Permission is granted to anyone to use this software for any purpose on
  11.  * any computer system, and to alter it and redistribute it freely, subject
  12.  * to the following restrictions:
  13.  *
  14.  * 1. The author is not responsible for the consequences of use of this
  15.  *    software, no matter how awful, even if they arise from flaws in it.
  16.  *
  17.  * 2. The origin of this software must not be misrepresented, either by
  18.  *    explicit claim or by omission.  Since few users ever read sources,
  19.  *    credits must appear in the documentation.
  20.  *
  21.  * 3. Altered versions must be plainly marked as such, and must not be
  22.  *    misrepresented as being the original software.  Since few users
  23.  *    ever read sources, credits must appear in the documentation.
  24.  *
  25.  * 4. This notice may not be removed or altered.
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <ctype.h>
  32. #include "file.h"
  33.  
  34. #ifndef    lint
  35. static char *moduleid = 
  36.     "@(#)$Id: apprentice.c,v 1.16 93/02/19 14:22:42 ian Exp $";
  37. #endif    /* lint */
  38.  
  39. #define    EATAB {while (isascii((unsigned char) *l) && \
  40.               isspace((unsigned char) *l))  ++l;}
  41.  
  42.  
  43. static int getvalue __P((struct magic *, char **));
  44. static int hextoint __P((int));
  45. static char *getstr __P((char *, char *, int, int *));
  46. #ifdef OS2
  47. static int parse    __P((char *, unsigned int *, int));
  48. static unsigned int maxmagic = 0;
  49. #else
  50. static int parse    __P((char *, int *, int));
  51. static int maxmagic = 0;
  52. #endif
  53.  
  54. int
  55. apprentice(fn, check)
  56. char *fn;            /* name of magic file */
  57. int check;            /* non-zero? checking-only run. */
  58. {
  59.     FILE *f;
  60.     char line[BUFSIZ+1];
  61.     int errs = 0;
  62.  
  63.     f = fopen(fn, "r");
  64.     if (f==NULL) {
  65.         (void) fprintf(stderr, "%s: can't read magic file %s\n",
  66.         progname, fn);
  67.         if (check)
  68.             return -1;
  69.         else
  70.             exit(1);
  71.     }
  72.  
  73.         maxmagic = MAXMAGIS;
  74.     if ((magic = (struct magic *) malloc(sizeof(struct magic) * maxmagic))
  75.         == NULL) {
  76.         (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  77.         if (check)
  78.             return -1;
  79.         else
  80.             exit(1);
  81.     }
  82.  
  83.     /* parse it */
  84.     if (check)    /* print silly verbose header for USG compat. */
  85.         (void) printf("cont\toffset\ttype\topcode\tmask\tvalue\tdesc\n");
  86.  
  87.     for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
  88.         if (line[0]=='#')    /* comment, do not parse */
  89.             continue;
  90.         if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
  91.             continue;
  92.         line[strlen(line)-1] = '\0'; /* delete newline */
  93.         if (parse(line, &nmagic, check) != 0)
  94.             ++errs;
  95.     }
  96.  
  97.     (void) fclose(f);
  98.     return errs ? -1 : 0;
  99. }
  100.  
  101. /*
  102.  * parse one line from magic file, put into magic[index++] if valid
  103.  */
  104. static int
  105. parse(l, ndx, check)
  106. char *l;
  107. #ifdef OS2
  108. unsigned int *ndx;
  109. #else
  110. int *ndx;
  111. #endif
  112. int check;
  113. {
  114.     int i = 0;
  115. #ifdef OS2
  116.     unsigned int nd = *ndx;
  117. #else
  118.     int nd = *ndx;
  119. #endif
  120.     struct magic *m;
  121.     char *t, *s;
  122.  
  123.     if (nd+1 >= maxmagic){
  124. #ifdef MSC                         /* 16-bit int */
  125.         if (maxmagic >= MAXMAGIC) {
  126.             (void) fprintf(stderr, "%s: magic file too large.\n", progname);
  127.             if (check)
  128.                 return -1;
  129.             else
  130.                 exit(1);
  131.         }
  132.         else
  133.             maxmagic = min(maxmagic + 20, MAXMAGIC);
  134. #else
  135.         maxmagic += 20;
  136. #endif
  137.         if ( (magic = (struct magic *) realloc(magic, 
  138.                           sizeof(struct magic) * 
  139.                           maxmagic)) == NULL) {
  140.         (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  141.         if (check)
  142.             return -1;
  143.         else
  144.             exit(1);
  145.         }
  146.     }
  147.     m = &magic[*ndx];
  148.     m->flag = 0;
  149.     m->cont_level = 0;
  150.  
  151.     while (*l == '>') {
  152.         ++l;        /* step over */
  153.         m->cont_level++; 
  154.     }
  155.  
  156.     if (m->cont_level != 0 && *l == '(') {
  157.         ++l;        /* step over */
  158.         m->flag |= INDIR;
  159.     }
  160.  
  161.     /* get offset, then skip over it */
  162.     m->offset = (int) strtol(l,&t,0);
  163.         if (l == t)
  164.         magwarn("offset %s invalid", l);
  165.         l = t;
  166.  
  167.     if (m->flag & INDIR) {
  168.         m->in.type = LONG;
  169.         m->in.offset = 0;
  170.         /*
  171.          * read [.lbs][+-]nnnnn)
  172.          */
  173.         if (*l == '.') {
  174.             switch (*++l) {
  175.             case 'l':
  176.                 m->in.type = LONG;
  177.                 break;
  178.             case 's':
  179.                 m->in.type = SHORT;
  180.                 break;
  181.             case 'b':
  182.                 m->in.type = BYTE;
  183.                 break;
  184.             default:
  185.                 magwarn("indirect offset type %c invalid", *l);
  186.                 break;
  187.             }
  188.             l++;
  189.         }
  190.         s = l;
  191.         if (*l == '+' || *l == '-') l++;
  192.         if (isdigit((unsigned char)*l)) {
  193.             m->in.offset = strtol(l, &t, 0);
  194.             if (*s == '-') m->in.offset = - m->in.offset;
  195.         }
  196.         if (*t++ != ')') 
  197.             magwarn("missing ')' in indirect offset");
  198.         l = t;
  199.     }
  200.  
  201.  
  202.     while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
  203.         ++l;
  204.     EATAB;
  205.  
  206. #define NBYTE        4
  207. #define NSHORT        5
  208. #define NLONG        4
  209. #define NSTRING     6
  210. #define NDATE        4
  211. #define NBESHORT    7
  212. #define NBELONG        6
  213. #define NBEDATE        6
  214. #define NLESHORT    7
  215. #define NLELONG        6
  216. #define NLEDATE        6
  217.  
  218.     /* get type, skip it */
  219.     if (strncmp(l, "byte", NBYTE)==0) {
  220.         m->type = BYTE;
  221.         l += NBYTE;
  222.     } else if (strncmp(l, "short", NSHORT)==0) {
  223.         m->type = SHORT;
  224.         l += NSHORT;
  225.     } else if (strncmp(l, "long", NLONG)==0) {
  226.         m->type = LONG;
  227.         l += NLONG;
  228.     } else if (strncmp(l, "string", NSTRING)==0) {
  229.         m->type = STRING;
  230.         l += NSTRING;
  231.     } else if (strncmp(l, "date", NDATE)==0) {
  232.         m->type = DATE;
  233.         l += NDATE;
  234.     } else if (strncmp(l, "beshort", NBESHORT)==0) {
  235.         m->type = BESHORT;
  236.         l += NBESHORT;
  237.     } else if (strncmp(l, "belong", NBELONG)==0) {
  238.         m->type = BELONG;
  239.         l += NBELONG;
  240.     } else if (strncmp(l, "bedate", NBEDATE)==0) {
  241.         m->type = BEDATE;
  242.         l += NBEDATE;
  243.     } else if (strncmp(l, "leshort", NLESHORT)==0) {
  244.         m->type = LESHORT;
  245.         l += NLESHORT;
  246.     } else if (strncmp(l, "lelong", NLELONG)==0) {
  247.         m->type = LELONG;
  248.         l += NLELONG;
  249.     } else if (strncmp(l, "ledate", NLEDATE)==0) {
  250.         m->type = LEDATE;
  251.         l += NLEDATE;
  252.     } else {
  253.         magwarn("type %s invalid", l);
  254.         return -1;
  255.     }
  256.     /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
  257.     if (*l == '&') {
  258.         ++l;
  259.         m->mask = strtol(l, &l, 0);
  260.     } else
  261.         m->mask = 0L;
  262.     EATAB;
  263.   
  264.     switch (*l) {
  265.     case '>':
  266.     case '<':
  267.     /* Old-style anding: "0 byte &0x80 dynamically linked" */
  268.     case '&':
  269.     case '^':
  270.     case '=':
  271.           m->reln = *l;
  272.           ++l;
  273.         break;
  274.     case '!':
  275.         if (m->type != STRING) {
  276.             m->reln = *l;
  277.             ++l;
  278.             break;
  279.         }
  280.         /* FALL THROUGH */
  281.     default:
  282.         if (*l == 'x' && isascii((unsigned char)l[1]) && 
  283.             isspace((unsigned char)l[1])) {
  284.             m->reln = *l;
  285.             ++l;
  286.             goto GetDesc;    /* Bill The Cat */
  287.         }
  288.           m->reln = '=';
  289.         break;
  290.     }
  291.       EATAB;
  292.   
  293.     if (getvalue(m, &l))
  294.         return -1;
  295.     /*
  296.      * TODO finish this macro and start using it!
  297.      * #define offsetcheck {if (offset > HOWMANY-1) 
  298.      *    magwarn("offset too big"); }
  299.      */
  300.  
  301.     /*
  302.      * now get last part - the description
  303.      */
  304. GetDesc:
  305.     EATAB;
  306.     if (l[0] == '\b') {
  307.         ++l;
  308.         m->nospflag = 1;
  309.     } else if ((l[0] == '\\') && (l[1] == 'b')) {
  310.         ++l;
  311.         ++l;
  312.         m->nospflag = 1;
  313.     } else
  314.         m->nospflag = 0;
  315.  
  316. #ifdef OS2
  317. #ifndef min
  318. #define min(a,b) (((a) < (b)) ? (a) : (b))
  319. #endif
  320.     i = min(strlen(l) + 1, MAXDESC);
  321.     if ((m->desc = (char *) malloc((size_t) i)) == NULL) {
  322.         (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  323.         if (check)
  324.             return -1;
  325.         else
  326.             exit(1);
  327.     }
  328.     m->desc[i-1] = '\0';
  329.     i = 0;
  330. #endif
  331.  
  332.     while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
  333.         /* NULLBODY */;
  334.  
  335.     if (check) {
  336.         mdump(m);
  337.     }
  338.     ++(*ndx);        /* make room for next */
  339.     return 0;
  340. }
  341.  
  342. /* 
  343.  * Read a numeric value from a pointer, into the value union of a magic 
  344.  * pointer, according to the magic type.  Update the string pointer to point 
  345.  * just after the number read.  Return 0 for success, non-zero for failure.
  346.  */
  347. static int
  348. getvalue(m, p)
  349. struct magic *m;
  350. char **p;
  351. {
  352.     int slen;
  353.  
  354.     if (m->type == STRING) {
  355.         *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
  356.         m->vallen = slen;
  357.     } else {
  358.         if (m->reln != 'x') {
  359.             switch(m->type) {
  360.             /*
  361.              * Do not remove the casts below.  They are vital.
  362.              * When later compared with the data, the sign
  363.              * extension must have happened.
  364.              */
  365.             case BYTE:
  366.                 m->value.l = (char) strtol(*p,p,0);
  367.                 break;
  368.             case SHORT:
  369.             case BESHORT:
  370.             case LESHORT:
  371.                 m->value.l = (short) strtol(*p,p,0);
  372.                 break;
  373.             case DATE:
  374.             case BEDATE:
  375.             case LEDATE:
  376.             case LONG:
  377.             case BELONG:
  378.             case LELONG:
  379. #ifdef OS2        /* bugfix, not OS/2-specific (?) */
  380. /*    strtol() in EMX/gcc and MSC lib returns LONG_MAX on overflow.
  381.     Use strtoul() or the supplied localsrc/strtol.c. */
  382.                 slen = (**p == '-') ? (-1) : (1);
  383.                 if (**p == '-' || **p == '+')
  384.                     *p++;
  385.                 m->value.l = (long) strtoul(*p, p, 0) * slen;
  386. #else
  387.                 m->value.l = (long) strtol(*p,p,0);
  388. #endif
  389.                 break;
  390.             default:
  391.                 magwarn("can't happen: m->type=%d\n", m->type);
  392.                 return -1;
  393.             }
  394.         }
  395.     }
  396.     return 0;
  397. }
  398.  
  399. /*
  400.  * Convert a string containing C character escapes.  Stop at an unescaped
  401.  * space or tab.
  402.  * Copy the converted version to "p", returning its length in *slen.
  403.  * Return updated scan pointer as function result.
  404.  */
  405. static char *
  406. getstr(s, p, plen, slen)
  407. register char    *s;
  408. register char    *p;
  409. int    plen, *slen;
  410. {
  411.     char    *origs = s, *origp = p;
  412.     char    *pmax = p + plen - 1;
  413.     register int    c;
  414.     register int    val;
  415.  
  416.     while ((c = *s++) != '\0') {
  417.         if (isspace((unsigned char) c))
  418.             break;
  419.         if (p >= pmax) {
  420.             fprintf(stderr, "String too long: %s\n", origs);
  421.             break;
  422.         }
  423.         if(c == '\\') {
  424.             switch(c = *s++) {
  425.  
  426.             case '\0':
  427.                 goto out;
  428.  
  429.             default:
  430.                 *p++ = (char) c;
  431.                 break;
  432.  
  433.             case 'n':
  434.                 *p++ = '\n';
  435.                 break;
  436.  
  437.             case 'r':
  438.                 *p++ = '\r';
  439.                 break;
  440.  
  441.             case 'b':
  442.                 *p++ = '\b';
  443.                 break;
  444.  
  445.             case 't':
  446.                 *p++ = '\t';
  447.                 break;
  448.  
  449.             case 'f':
  450.                 *p++ = '\f';
  451.                 break;
  452.  
  453.             case 'v':
  454.                 *p++ = '\v';
  455.                 break;
  456.  
  457.             /* \ and up to 3 octal digits */
  458.             case '0':
  459.             case '1':
  460.             case '2':
  461.             case '3':
  462.             case '4':
  463.             case '5':
  464.             case '6':
  465.             case '7':
  466.                 val = c - '0';
  467.                 c = *s++;  /* try for 2 */
  468.                 if(c >= '0' && c <= '7') {
  469.                     val = (val<<3) | (c - '0');
  470.                     c = *s++;  /* try for 3 */
  471.                     if(c >= '0' && c <= '7')
  472.                         val = (val<<3) | (c-'0');
  473.                     else
  474.                         --s;
  475.                 }
  476.                 else
  477.                     --s;
  478.                 *p++ = (char)val;
  479.                 break;
  480.  
  481.             /* \x and up to 3 hex digits */
  482.             case 'x':
  483.                 val = 'x';    /* Default if no digits */
  484.                 c = hextoint(*s++);    /* Get next char */
  485.                 if (c >= 0) {
  486.                     val = c;
  487.                     c = hextoint(*s++);
  488.                     if (c >= 0) {
  489.                         val = (val << 4) + c;
  490.                         c = hextoint(*s++);
  491.                         if (c >= 0) {
  492.                             val = (val << 4) + c;
  493.                         } else
  494.                             --s;
  495.                     } else
  496.                         --s;
  497.                 } else
  498.                     --s;
  499.                 *p++ = (char)val;
  500.                 break;
  501.             }
  502.         } else
  503.             *p++ = (char)c;
  504.     }
  505. out:
  506.     *p = '\0';
  507.     *slen = p - origp;
  508.     return s;
  509. }
  510.  
  511.  
  512. /* Single hex char to int; -1 if not a hex char. */
  513. static int
  514. hextoint(c)
  515. int c;
  516. {
  517.     if (!isascii((unsigned char) c))    return -1;
  518.     if (isdigit((unsigned char) c))        return c - '0';
  519.     if ((c>='a')&&(c<='f'))    return c + 10 - 'a';
  520.     if ((c>='A')&&(c<='F'))    return c + 10 - 'A';
  521.                 return -1;
  522. }
  523.  
  524.  
  525. /*
  526.  * Print a string containing C character escapes.
  527.  */
  528. void
  529. showstr(s)
  530. const char *s;
  531. {
  532.     register char    c;
  533.  
  534.     while((c = *s++) != '\0') {
  535.         if(c >= 040 && c <= 0176)    /* TODO isprint && !iscntrl */
  536.             putchar(c);
  537.         else {
  538.             putchar('\\');
  539.             switch (c) {
  540.             
  541.             case '\n':
  542.                 putchar('n');
  543.                 break;
  544.  
  545.             case '\r':
  546.                 putchar('r');
  547.                 break;
  548.  
  549.             case '\b':
  550.                 putchar('b');
  551.                 break;
  552.  
  553.             case '\t':
  554.                 putchar('t');
  555.                 break;
  556.  
  557.             case '\f':
  558.                 putchar('f');
  559.                 break;
  560.  
  561.             case '\v':
  562.                 putchar('v');
  563.                 break;
  564.  
  565.             default:
  566.                 printf("%.3o", c & 0377);
  567.                 break;
  568.             }
  569.         }
  570.     }
  571.     putchar('\t');
  572. }
  573.