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