xref: /netbsd-src/external/gpl2/mkhybrid/dist/libfile/apprentice.c (revision 7804f23efd64308ff6bfc74397b5a25728376f71)
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