175490c83Stsutsui /* @(#)apprentice.c 1.13 09/07/11 joerg */
275490c83Stsutsui #ifndef lint
3*7804f23eStsutsui static const char sccsid[] =
475490c83Stsutsui "@(#)apprentice.c 1.13 09/07/11 joerg";
575490c83Stsutsui #endif
675490c83Stsutsui /*
775490c83Stsutsui ** find file types by using a modified "magic" file
875490c83Stsutsui **
975490c83Stsutsui ** based on file v3.22 by Ian F. Darwin (see below)
1075490c83Stsutsui **
1175490c83Stsutsui ** Modified for mkhybrid James Pearson 19/5/98
1275490c83Stsutsui */
1375490c83Stsutsui
1475490c83Stsutsui /*
1575490c83Stsutsui * apprentice - make one pass through /etc/magic, learning its secrets.
1675490c83Stsutsui *
1775490c83Stsutsui * Copyright (c) Ian F. Darwin, 1987.
1875490c83Stsutsui * Written by Ian F. Darwin.
1975490c83Stsutsui *
2075490c83Stsutsui * This software is not subject to any export provision of the United States
2175490c83Stsutsui * Department of Commerce, and may be exported to any country or planet.
2275490c83Stsutsui *
2375490c83Stsutsui * Redistribution and use in source and binary forms, with or without
2475490c83Stsutsui * modification, are permitted provided that the following conditions
2575490c83Stsutsui * are met:
2675490c83Stsutsui * 1. Redistributions of source code must retain the above copyright
2775490c83Stsutsui * notice immediately at the beginning of the file, without modification,
2875490c83Stsutsui * this list of conditions, and the following disclaimer.
2975490c83Stsutsui * 2. Redistributions in binary form must reproduce the above copyright
3075490c83Stsutsui * notice, this list of conditions and the following disclaimer in the
3175490c83Stsutsui * documentation and/or other materials provided with the distribution.
3275490c83Stsutsui *
3375490c83Stsutsui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
3475490c83Stsutsui * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3575490c83Stsutsui * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3675490c83Stsutsui * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
3775490c83Stsutsui * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3875490c83Stsutsui * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3975490c83Stsutsui * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4075490c83Stsutsui * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4175490c83Stsutsui * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4275490c83Stsutsui * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4375490c83Stsutsui * SUCH DAMAGE.
4475490c83Stsutsui */
4575490c83Stsutsui
46*7804f23eStsutsui #include <stdio.h>
47*7804f23eStsutsui #include <stdlib.h>
48*7804f23eStsutsui #include <string.h>
49*7804f23eStsutsui #include <ctype.h>
50*7804f23eStsutsui #include "proto.h"
5175490c83Stsutsui #include "file.h"
5275490c83Stsutsui
5375490c83Stsutsui #ifndef lint
54*7804f23eStsutsui static const char moduleid[] =
5575490c83Stsutsui "@(#)Id: apprentice.c,v 1.25 1997/01/15 17:23:24 christos Exp";
5675490c83Stsutsui #endif /* lint */
5775490c83Stsutsui
5875490c83Stsutsui int __f_nmagic = 0; /* number of valid magic[]s */
5975490c83Stsutsui #if defined(IS_MACOS_X)
6075490c83Stsutsui /*
6175490c83Stsutsui * The MAC OS X linker does not grok "common" varaibles.
6275490c83Stsutsui * Make __f_magic a "data" variable.
6375490c83Stsutsui */
6475490c83Stsutsui struct magic *__f_magic = 0; /* array of magic entries */
6575490c83Stsutsui #else
6675490c83Stsutsui struct magic *__f_magic; /* array of magic entries */
6775490c83Stsutsui #endif
6875490c83Stsutsui
6975490c83Stsutsui #define EATAB {while (isascii((unsigned char) *l) && \
7075490c83Stsutsui isspace((unsigned char) *l)) ++l;}
7175490c83Stsutsui #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
7275490c83Stsutsui tolower((unsigned char) (l)) : (l))
7375490c83Stsutsui
7475490c83Stsutsui
75*7804f23eStsutsui static int getvalue (struct magic *, char **);
76*7804f23eStsutsui static int hextoint (int);
77*7804f23eStsutsui static char *apgetstr (char *, char *, int, int *);
78*7804f23eStsutsui static int parse (char *, int *, int);
79*7804f23eStsutsui static void eatsize (char **);
8075490c83Stsutsui
8175490c83Stsutsui static int maxmagic = 0;
8275490c83Stsutsui
83*7804f23eStsutsui static int apprentice_1 (char *, int);
8475490c83Stsutsui
8575490c83Stsutsui /*
8675490c83Stsutsui * init_magic - read magic file and set up mapping
8775490c83Stsutsui * based on the original apprentice()
8875490c83Stsutsui */
8975490c83Stsutsui int
init_magic(char * fn)90*7804f23eStsutsui init_magic(
91*7804f23eStsutsui char *fn /* list of magic files */
92*7804f23eStsutsui )
9375490c83Stsutsui {
9475490c83Stsutsui maxmagic = MAXMAGIS;
9575490c83Stsutsui __f_magic = (struct magic *) calloc(sizeof(struct magic), maxmagic);
9675490c83Stsutsui if (__f_magic == NULL)
9775490c83Stsutsui return -1;
9875490c83Stsutsui
9975490c83Stsutsui return(apprentice_1(fn, 0));
10075490c83Stsutsui }
10175490c83Stsutsui
10275490c83Stsutsui static int
apprentice_1(char * fn,int check)103*7804f23eStsutsui apprentice_1(
104*7804f23eStsutsui char *fn, /* name of magic file */
105*7804f23eStsutsui int check /* non-zero? checking-only run. */
106*7804f23eStsutsui )
10775490c83Stsutsui {
10875490c83Stsutsui static const char hdr[] =
10975490c83Stsutsui "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
11075490c83Stsutsui FILE *f;
11175490c83Stsutsui char line[BUFSIZ+1];
11275490c83Stsutsui int errs = 0;
11375490c83Stsutsui int lineno;
11475490c83Stsutsui
11575490c83Stsutsui f = fopen(fn, "r");
11675490c83Stsutsui if (f==NULL) {
11775490c83Stsutsui return -1;
11875490c83Stsutsui }
11975490c83Stsutsui
12075490c83Stsutsui /* parse it */
12175490c83Stsutsui if (check) /* print silly verbose header for USG compat. */
12275490c83Stsutsui (void) printf("%s\n", hdr);
12375490c83Stsutsui
12475490c83Stsutsui for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
12575490c83Stsutsui if (line[0]=='#') /* comment, do not parse */
12675490c83Stsutsui continue;
12775490c83Stsutsui if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
12875490c83Stsutsui continue;
12975490c83Stsutsui line[strlen(line)-1] = '\0'; /* delete newline */
13075490c83Stsutsui if (parse(line, &__f_nmagic, check) != 0)
13175490c83Stsutsui errs = 1;
13275490c83Stsutsui }
13375490c83Stsutsui
13475490c83Stsutsui (void) fclose(f);
13575490c83Stsutsui return errs;
13675490c83Stsutsui }
13775490c83Stsutsui
13875490c83Stsutsui /*
13975490c83Stsutsui * extend the sign bit if the comparison is to be signed
14075490c83Stsutsui * XXX is uint32 really a good idea XXX JS
14175490c83Stsutsui */
14275490c83Stsutsui UInt32_t
signextend(struct magic * m,UInt32_t v)143*7804f23eStsutsui signextend(struct magic *m, UInt32_t v)
14475490c83Stsutsui {
14575490c83Stsutsui if (!(m->flag & UNSIGNED))
14675490c83Stsutsui switch(m->type) {
14775490c83Stsutsui /*
14875490c83Stsutsui * Do not remove the casts below. They are
14975490c83Stsutsui * vital. When later compared with the data,
15075490c83Stsutsui * the sign extension must have happened.
15175490c83Stsutsui */
15275490c83Stsutsui case BYTE:
15375490c83Stsutsui v = (char) v;
15475490c83Stsutsui break;
15575490c83Stsutsui case SHORT:
15675490c83Stsutsui case BESHORT:
15775490c83Stsutsui case LESHORT:
15875490c83Stsutsui v = (short) v;
15975490c83Stsutsui break;
16075490c83Stsutsui case DATE:
16175490c83Stsutsui case BEDATE:
16275490c83Stsutsui case LEDATE:
16375490c83Stsutsui case LONG:
16475490c83Stsutsui case BELONG:
16575490c83Stsutsui case LELONG:
16675490c83Stsutsui v = (Int32_t) v;
16775490c83Stsutsui break;
16875490c83Stsutsui case STRING:
16975490c83Stsutsui break;
17075490c83Stsutsui default:
17175490c83Stsutsui return -1;
17275490c83Stsutsui }
17375490c83Stsutsui return v;
17475490c83Stsutsui }
17575490c83Stsutsui
17675490c83Stsutsui /*
17775490c83Stsutsui * parse one line from magic file, put into magic[index++] if valid
17875490c83Stsutsui */
17975490c83Stsutsui static int
parse(char * l,int * ndx,int check)180*7804f23eStsutsui parse(char *l, int *ndx, int check)
18175490c83Stsutsui {
18275490c83Stsutsui int i = 0, nd = *ndx;
18375490c83Stsutsui struct magic *m;
18475490c83Stsutsui char *t, *s;
18575490c83Stsutsui
18675490c83Stsutsui #define ALLOC_INCR 20
18775490c83Stsutsui if (nd+1 >= maxmagic){
18875490c83Stsutsui maxmagic += ALLOC_INCR;
18975490c83Stsutsui if ((__f_magic = (struct magic *) realloc(__f_magic,
19075490c83Stsutsui sizeof(struct magic) *
19175490c83Stsutsui maxmagic)) == NULL) {
19275490c83Stsutsui #ifdef MAIN
19375490c83Stsutsui (void) fprintf(stderr, "%s: Out of memory.\n", progname);
19475490c83Stsutsui #else
19575490c83Stsutsui (void) fprintf(stderr, "libfile: Out of memory.\n");
19675490c83Stsutsui #endif
19775490c83Stsutsui if (check)
19875490c83Stsutsui return -1;
19975490c83Stsutsui else
20075490c83Stsutsui exit(1);
20175490c83Stsutsui }
20275490c83Stsutsui memset(&__f_magic[*ndx], 0, sizeof(struct magic) * ALLOC_INCR);
20375490c83Stsutsui }
20475490c83Stsutsui m = &__f_magic[*ndx];
20575490c83Stsutsui m->flag = 0;
20675490c83Stsutsui m->cont_level = 0;
20775490c83Stsutsui
20875490c83Stsutsui while (*l == '>') {
20975490c83Stsutsui ++l; /* step over */
21075490c83Stsutsui m->cont_level++;
21175490c83Stsutsui }
21275490c83Stsutsui
21375490c83Stsutsui if (m->cont_level != 0 && *l == '(') {
21475490c83Stsutsui ++l; /* step over */
21575490c83Stsutsui m->flag |= INDIR;
21675490c83Stsutsui }
21775490c83Stsutsui if (m->cont_level != 0 && *l == '&') {
21875490c83Stsutsui ++l; /* step over */
21975490c83Stsutsui m->flag |= ADD;
22075490c83Stsutsui }
22175490c83Stsutsui
22275490c83Stsutsui /* get offset, then skip over it */
22375490c83Stsutsui m->offset = (int) strtoul(l,&t,0);
22475490c83Stsutsui /*
22575490c83Stsutsui if (l == t)
22675490c83Stsutsui magwarn("offset %s invalid", l);
22775490c83Stsutsui */
22875490c83Stsutsui l = t;
22975490c83Stsutsui
23075490c83Stsutsui if (m->flag & INDIR) {
23175490c83Stsutsui m->in.type = LONG;
23275490c83Stsutsui m->in.offset = 0;
23375490c83Stsutsui /*
23475490c83Stsutsui * read [.lbs][+-]nnnnn)
23575490c83Stsutsui */
23675490c83Stsutsui if (*l == '.') {
23775490c83Stsutsui l++;
23875490c83Stsutsui switch (LOWCASE(*l)) {
23975490c83Stsutsui case 'l':
24075490c83Stsutsui m->in.type = LONG;
24175490c83Stsutsui break;
24275490c83Stsutsui case 'h':
24375490c83Stsutsui case 's':
24475490c83Stsutsui m->in.type = SHORT;
24575490c83Stsutsui break;
24675490c83Stsutsui case 'c':
24775490c83Stsutsui case 'b':
24875490c83Stsutsui m->in.type = BYTE;
24975490c83Stsutsui break;
25075490c83Stsutsui default:
25175490c83Stsutsui break;
25275490c83Stsutsui }
25375490c83Stsutsui l++;
25475490c83Stsutsui }
25575490c83Stsutsui s = l;
25675490c83Stsutsui if (*l == '+' || *l == '-') l++;
25775490c83Stsutsui if (isdigit((unsigned char)*l)) {
25875490c83Stsutsui m->in.offset = strtoul(l, &t, 0);
25975490c83Stsutsui if (*s == '-') m->in.offset = - m->in.offset;
26075490c83Stsutsui }
26175490c83Stsutsui else
26275490c83Stsutsui t = l;
26375490c83Stsutsui /*
26475490c83Stsutsui if (*t++ != ')')
26575490c83Stsutsui magwarn("missing ')' in indirect offset");
26675490c83Stsutsui */
26775490c83Stsutsui l = t;
26875490c83Stsutsui }
26975490c83Stsutsui
27075490c83Stsutsui
27175490c83Stsutsui while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
27275490c83Stsutsui ++l;
27375490c83Stsutsui EATAB;
27475490c83Stsutsui
27575490c83Stsutsui #define NBYTE 4
27675490c83Stsutsui #define NSHORT 5
27775490c83Stsutsui #define NLONG 4
27875490c83Stsutsui #define NSTRING 6
27975490c83Stsutsui #define NDATE 4
28075490c83Stsutsui #define NBESHORT 7
28175490c83Stsutsui #define NBELONG 6
28275490c83Stsutsui #define NBEDATE 6
28375490c83Stsutsui #define NLESHORT 7
28475490c83Stsutsui #define NLELONG 6
28575490c83Stsutsui #define NLEDATE 6
28675490c83Stsutsui
28775490c83Stsutsui if (*l == 'u') {
28875490c83Stsutsui ++l;
28975490c83Stsutsui m->flag |= UNSIGNED;
29075490c83Stsutsui }
29175490c83Stsutsui
29275490c83Stsutsui /* get type, skip it */
29375490c83Stsutsui if (strncmp(l, "byte", NBYTE)==0) {
29475490c83Stsutsui m->type = BYTE;
29575490c83Stsutsui l += NBYTE;
29675490c83Stsutsui } else if (strncmp(l, "short", NSHORT)==0) {
29775490c83Stsutsui m->type = SHORT;
29875490c83Stsutsui l += NSHORT;
29975490c83Stsutsui } else if (strncmp(l, "long", NLONG)==0) {
30075490c83Stsutsui m->type = LONG;
30175490c83Stsutsui l += NLONG;
30275490c83Stsutsui } else if (strncmp(l, "string", NSTRING)==0) {
30375490c83Stsutsui m->type = STRING;
30475490c83Stsutsui l += NSTRING;
30575490c83Stsutsui } else if (strncmp(l, "date", NDATE)==0) {
30675490c83Stsutsui m->type = DATE;
30775490c83Stsutsui l += NDATE;
30875490c83Stsutsui } else if (strncmp(l, "beshort", NBESHORT)==0) {
30975490c83Stsutsui m->type = BESHORT;
31075490c83Stsutsui l += NBESHORT;
31175490c83Stsutsui } else if (strncmp(l, "belong", NBELONG)==0) {
31275490c83Stsutsui m->type = BELONG;
31375490c83Stsutsui l += NBELONG;
31475490c83Stsutsui } else if (strncmp(l, "bedate", NBEDATE)==0) {
31575490c83Stsutsui m->type = BEDATE;
31675490c83Stsutsui l += NBEDATE;
31775490c83Stsutsui } else if (strncmp(l, "leshort", NLESHORT)==0) {
31875490c83Stsutsui m->type = LESHORT;
31975490c83Stsutsui l += NLESHORT;
32075490c83Stsutsui } else if (strncmp(l, "lelong", NLELONG)==0) {
32175490c83Stsutsui m->type = LELONG;
32275490c83Stsutsui l += NLELONG;
32375490c83Stsutsui } else if (strncmp(l, "ledate", NLEDATE)==0) {
32475490c83Stsutsui m->type = LEDATE;
32575490c83Stsutsui l += NLEDATE;
32675490c83Stsutsui } else {
32775490c83Stsutsui return -1;
32875490c83Stsutsui }
32975490c83Stsutsui /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
33075490c83Stsutsui if (*l == '&') {
33175490c83Stsutsui ++l;
33275490c83Stsutsui m->mask = signextend(m, (UInt32_t)strtoul(l, &l, 0)); /* XXX JS uint32 cat may be wrong */
33375490c83Stsutsui eatsize(&l);
33475490c83Stsutsui } else
33575490c83Stsutsui m->mask = ~0L;
33675490c83Stsutsui EATAB;
33775490c83Stsutsui
33875490c83Stsutsui switch (*l) {
33975490c83Stsutsui case '>':
34075490c83Stsutsui case '<':
34175490c83Stsutsui /* Old-style anding: "0 byte &0x80 dynamically linked" */
34275490c83Stsutsui case '&':
34375490c83Stsutsui case '^':
34475490c83Stsutsui case '=':
34575490c83Stsutsui m->reln = *l;
34675490c83Stsutsui ++l;
34775490c83Stsutsui break;
34875490c83Stsutsui case '!':
34975490c83Stsutsui if (m->type != STRING) {
35075490c83Stsutsui m->reln = *l;
35175490c83Stsutsui ++l;
35275490c83Stsutsui break;
35375490c83Stsutsui }
35475490c83Stsutsui /* FALL THROUGH */
35575490c83Stsutsui default:
35675490c83Stsutsui if (*l == 'x' && isascii((unsigned char)l[1]) &&
35775490c83Stsutsui isspace((unsigned char)l[1])) {
35875490c83Stsutsui m->reln = *l;
35975490c83Stsutsui ++l;
36075490c83Stsutsui goto GetDesc; /* Bill The Cat */
36175490c83Stsutsui }
36275490c83Stsutsui m->reln = '=';
36375490c83Stsutsui break;
36475490c83Stsutsui }
36575490c83Stsutsui EATAB;
36675490c83Stsutsui
36775490c83Stsutsui if (getvalue(m, &l))
36875490c83Stsutsui return -1;
36975490c83Stsutsui /*
37075490c83Stsutsui * TODO finish this macro and start using it!
37175490c83Stsutsui * #define offsetcheck {if (offset > HOWMANY-1)
37275490c83Stsutsui * magwarn("offset too big"); }
37375490c83Stsutsui */
37475490c83Stsutsui
37575490c83Stsutsui /*
37675490c83Stsutsui * now get last part - the description
37775490c83Stsutsui */
37875490c83Stsutsui GetDesc:
37975490c83Stsutsui EATAB;
38075490c83Stsutsui if (l[0] == '\b') {
38175490c83Stsutsui ++l;
38275490c83Stsutsui m->nospflag = 1;
38375490c83Stsutsui } else if ((l[0] == '\\') && (l[1] == 'b')) {
38475490c83Stsutsui ++l;
38575490c83Stsutsui ++l;
38675490c83Stsutsui m->nospflag = 1;
38775490c83Stsutsui } else
38875490c83Stsutsui m->nospflag = 0;
38975490c83Stsutsui while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
39075490c83Stsutsui /* NULLBODY */;
39175490c83Stsutsui
39275490c83Stsutsui ++(*ndx); /* make room for next */
39375490c83Stsutsui return 0;
39475490c83Stsutsui }
39575490c83Stsutsui
39675490c83Stsutsui /*
39775490c83Stsutsui * Read a numeric value from a pointer, into the value union of a magic
39875490c83Stsutsui * pointer, according to the magic type. Update the string pointer to point
39975490c83Stsutsui * just after the number read. Return 0 for success, non-zero for failure.
40075490c83Stsutsui */
40175490c83Stsutsui static int
getvalue(struct magic * m,char ** p)402*7804f23eStsutsui getvalue(struct magic *m, char **p)
40375490c83Stsutsui {
40475490c83Stsutsui int slen;
40575490c83Stsutsui
40675490c83Stsutsui if (m->type == STRING) {
40775490c83Stsutsui *p = apgetstr(*p, m->value.s, sizeof(m->value.s), &slen);
40875490c83Stsutsui m->vallen = slen;
40975490c83Stsutsui } else
41075490c83Stsutsui if (m->reln != 'x') {
41175490c83Stsutsui m->value.l = signextend(m, (UInt32_t)strtoul(*p, p, 0)); /* XXX JS uint32 cat may be wrong */
41275490c83Stsutsui eatsize(p);
41375490c83Stsutsui }
41475490c83Stsutsui return 0;
41575490c83Stsutsui }
41675490c83Stsutsui
41775490c83Stsutsui /*
41875490c83Stsutsui * Convert a string containing C character escapes. Stop at an unescaped
41975490c83Stsutsui * space or tab.
42075490c83Stsutsui * Copy the converted version to "p", returning its length in *slen.
42175490c83Stsutsui * Return updated scan pointer as function result.
42275490c83Stsutsui */
42375490c83Stsutsui static char *
apgetstr(char * s,char * p,int plen,int * slen)424*7804f23eStsutsui apgetstr(char *s, char *p, int plen, int *slen)
42575490c83Stsutsui {
42675490c83Stsutsui char *origs = s, *origp = p;
42775490c83Stsutsui char *pmax = p + plen - 1;
42875490c83Stsutsui register int c;
42975490c83Stsutsui register int val;
43075490c83Stsutsui
43175490c83Stsutsui while ((c = *s++) != '\0') {
43275490c83Stsutsui if (isspace((unsigned char) c))
43375490c83Stsutsui break;
43475490c83Stsutsui if (p >= pmax) {
43575490c83Stsutsui fprintf(stderr, "String too long: %s\n", origs);
43675490c83Stsutsui break;
43775490c83Stsutsui }
43875490c83Stsutsui if(c == '\\') {
43975490c83Stsutsui switch(c = *s++) {
44075490c83Stsutsui
44175490c83Stsutsui case '\0':
44275490c83Stsutsui goto out;
44375490c83Stsutsui
44475490c83Stsutsui default:
44575490c83Stsutsui *p++ = (char) c;
44675490c83Stsutsui break;
44775490c83Stsutsui
44875490c83Stsutsui case 'n':
44975490c83Stsutsui *p++ = '\n';
45075490c83Stsutsui break;
45175490c83Stsutsui
45275490c83Stsutsui case 'r':
45375490c83Stsutsui *p++ = '\r';
45475490c83Stsutsui break;
45575490c83Stsutsui
45675490c83Stsutsui case 'b':
45775490c83Stsutsui *p++ = '\b';
45875490c83Stsutsui break;
45975490c83Stsutsui
46075490c83Stsutsui case 't':
46175490c83Stsutsui *p++ = '\t';
46275490c83Stsutsui break;
46375490c83Stsutsui
46475490c83Stsutsui case 'f':
46575490c83Stsutsui *p++ = '\f';
46675490c83Stsutsui break;
46775490c83Stsutsui
46875490c83Stsutsui case 'v':
46975490c83Stsutsui *p++ = '\v';
47075490c83Stsutsui break;
47175490c83Stsutsui
47275490c83Stsutsui /* \ and up to 3 octal digits */
47375490c83Stsutsui case '0':
47475490c83Stsutsui case '1':
47575490c83Stsutsui case '2':
47675490c83Stsutsui case '3':
47775490c83Stsutsui case '4':
47875490c83Stsutsui case '5':
47975490c83Stsutsui case '6':
48075490c83Stsutsui case '7':
48175490c83Stsutsui val = c - '0';
48275490c83Stsutsui c = *s++; /* try for 2 */
48375490c83Stsutsui if(c >= '0' && c <= '7') {
48475490c83Stsutsui val = (val<<3) | (c - '0');
48575490c83Stsutsui c = *s++; /* try for 3 */
48675490c83Stsutsui if(c >= '0' && c <= '7')
48775490c83Stsutsui val = (val<<3) | (c-'0');
48875490c83Stsutsui else
48975490c83Stsutsui --s;
49075490c83Stsutsui }
49175490c83Stsutsui else
49275490c83Stsutsui --s;
49375490c83Stsutsui *p++ = (char)val;
49475490c83Stsutsui break;
49575490c83Stsutsui
49675490c83Stsutsui /* \x and up to 2 hex digits */
49775490c83Stsutsui case 'x':
49875490c83Stsutsui val = 'x'; /* Default if no digits */
49975490c83Stsutsui c = hextoint(*s++); /* Get next char */
50075490c83Stsutsui if (c >= 0) {
50175490c83Stsutsui val = c;
50275490c83Stsutsui c = hextoint(*s++);
50375490c83Stsutsui if (c >= 0)
50475490c83Stsutsui val = (val << 4) + c;
50575490c83Stsutsui else
50675490c83Stsutsui --s;
50775490c83Stsutsui } else
50875490c83Stsutsui --s;
50975490c83Stsutsui *p++ = (char)val;
51075490c83Stsutsui break;
51175490c83Stsutsui }
51275490c83Stsutsui } else
51375490c83Stsutsui *p++ = (char)c;
51475490c83Stsutsui }
51575490c83Stsutsui out:
51675490c83Stsutsui *p = '\0';
51775490c83Stsutsui *slen = p - origp;
51875490c83Stsutsui return s;
51975490c83Stsutsui }
52075490c83Stsutsui
52175490c83Stsutsui
52275490c83Stsutsui /* Single hex char to int; -1 if not a hex char. */
52375490c83Stsutsui static int
hextoint(int c)524*7804f23eStsutsui hextoint(int c)
52575490c83Stsutsui {
52675490c83Stsutsui if (!isascii((unsigned char) c)) return -1;
52775490c83Stsutsui if (isdigit((unsigned char) c)) return c - '0';
52875490c83Stsutsui if ((c>='a')&&(c<='f')) return c + 10 - 'a';
52975490c83Stsutsui if ((c>='A')&&(c<='F')) return c + 10 - 'A';
53075490c83Stsutsui return -1;
53175490c83Stsutsui }
53275490c83Stsutsui
53375490c83Stsutsui
53475490c83Stsutsui /*
53575490c83Stsutsui * Print a string containing C character escapes.
53675490c83Stsutsui */
53775490c83Stsutsui void
showstr(FILE * fp,const char * s,int len)538*7804f23eStsutsui showstr(FILE *fp, const char *s, int len)
53975490c83Stsutsui {
54075490c83Stsutsui register char c;
54175490c83Stsutsui
54275490c83Stsutsui for (;;) {
54375490c83Stsutsui c = *s++;
54475490c83Stsutsui if (len == -1) {
54575490c83Stsutsui if (c == '\0')
54675490c83Stsutsui break;
54775490c83Stsutsui }
54875490c83Stsutsui else {
54975490c83Stsutsui if (len-- == 0)
55075490c83Stsutsui break;
55175490c83Stsutsui }
55275490c83Stsutsui if(c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
55375490c83Stsutsui (void) fputc(c, fp);
55475490c83Stsutsui else {
55575490c83Stsutsui (void) fputc('\\', fp);
55675490c83Stsutsui switch (c) {
55775490c83Stsutsui
55875490c83Stsutsui case '\n':
55975490c83Stsutsui (void) fputc('n', fp);
56075490c83Stsutsui break;
56175490c83Stsutsui
56275490c83Stsutsui case '\r':
56375490c83Stsutsui (void) fputc('r', fp);
56475490c83Stsutsui break;
56575490c83Stsutsui
56675490c83Stsutsui case '\b':
56775490c83Stsutsui (void) fputc('b', fp);
56875490c83Stsutsui break;
56975490c83Stsutsui
57075490c83Stsutsui case '\t':
57175490c83Stsutsui (void) fputc('t', fp);
57275490c83Stsutsui break;
57375490c83Stsutsui
57475490c83Stsutsui case '\f':
57575490c83Stsutsui (void) fputc('f', fp);
57675490c83Stsutsui break;
57775490c83Stsutsui
57875490c83Stsutsui case '\v':
57975490c83Stsutsui (void) fputc('v', fp);
58075490c83Stsutsui break;
58175490c83Stsutsui
58275490c83Stsutsui default:
58375490c83Stsutsui (void) fprintf(fp, "%.3o", c & 0377);
58475490c83Stsutsui break;
58575490c83Stsutsui }
58675490c83Stsutsui }
58775490c83Stsutsui }
58875490c83Stsutsui }
58975490c83Stsutsui
59075490c83Stsutsui /*
59175490c83Stsutsui * eatsize(): Eat the size spec from a number [eg. 10UL]
59275490c83Stsutsui */
59375490c83Stsutsui static void
eatsize(char ** p)594*7804f23eStsutsui eatsize(char **p)
59575490c83Stsutsui {
59675490c83Stsutsui char *l = *p;
59775490c83Stsutsui
59875490c83Stsutsui if (LOWCASE(*l) == 'u')
59975490c83Stsutsui l++;
60075490c83Stsutsui
60175490c83Stsutsui switch (LOWCASE(*l)) {
60275490c83Stsutsui case 'l': /* long */
60375490c83Stsutsui case 's': /* short */
60475490c83Stsutsui case 'h': /* short */
60575490c83Stsutsui case 'b': /* char/byte */
60675490c83Stsutsui case 'c': /* char/byte */
60775490c83Stsutsui l++;
60875490c83Stsutsui /*FALLTHROUGH*/
60975490c83Stsutsui default:
61075490c83Stsutsui break;
61175490c83Stsutsui }
61275490c83Stsutsui
61375490c83Stsutsui *p = l;
61475490c83Stsutsui }
615