source: rtems/cpukit/libmisc/shell/hexdump-parse.c @ 9a77af8

4.104.115
Last change on this file since 9a77af8 was 9a77af8, checked in by Ralf Corsepius <ralf.corsepius@…>, on Mar 26, 2010 at 5:18:43 PM

Add HAVE_CONFIG_H support to let files receive configure defines.

  • Property mode set to 100644
File size: 12.1 KB
Line 
1/*
2 * Copyright (c) 1989, 1993
3 *      The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *      This product includes software developed by the University of
16 *      California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifdef HAVE_CONFIG_H
35#include "config.h"
36#endif
37
38#ifndef lint
39#if 0
40static char sccsid[] = "@(#)parse.c     8.1 (Berkeley) 6/6/93";
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD: src/usr.bin/hexdump/parse.c,v 1.14 2006/08/09 19:12:10 maxim Exp $");
43#endif
44#endif /* not lint */
45
46#include <sys/types.h>
47
48#include <err.h>
49#include <fcntl.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <ctype.h>
53#include <string.h>
54#include "hexdump.h"
55
56#if RTEMS_REMOVED
57FU *endfu;                                      /* format at end-of-data */
58#endif
59
60void
61addfile(rtems_shell_hexdump_globals* globals, char *name)
62{
63        unsigned char *p;
64        FILE *fp;
65        int ch;
66        char buf[2048 + 1];
67
68        if ((fp = fopen(name, "r")) == NULL)
69                err(exit_jump, 1, "%s", name);
70        while (fgets(buf, sizeof(buf), fp)) {
71                if (!(p = (unsigned char*)index(buf, '\n'))) {
72                        warnx("line too long");
73                        while ((ch = getchar()) != '\n' && ch != EOF);
74                        continue;
75                }
76                *p = '\0';
77                for (p = (unsigned char*) buf; *p && isspace(*p); ++p);
78                if (!*p || *p == '#')
79                        continue;
80                add(globals, (char*)p);
81        }
82        (void)fclose(fp);
83}
84
85void
86add(rtems_shell_hexdump_globals* globals, const char *fmt)
87{
88        unsigned const char *p, *savep;
89        static FS **nextfs;
90        FS *tfs;
91        FU *tfu, **nextfu;
92
93        /* start new linked list of format units */
94        if ((tfs = calloc(1, sizeof(FS))) == NULL)
95                err(exit_jump, 1, NULL);
96        if (!fshead)
97                fshead = tfs;
98        else
99                *nextfs = tfs;
100        nextfs = &tfs->nextfs;
101        nextfu = &tfs->nextfu;
102
103        /* take the format string and break it up into format units */
104        for (p = (unsigned const char*)fmt;;) {
105                /* skip leading white space */
106                for (; isspace(*p); ++p);
107                if (!*p)
108                        break;
109
110                /* allocate a new format unit and link it in */
111                if ((tfu = calloc(1, sizeof(FU))) == NULL)
112                        err(exit_jump, 1, NULL);
113                *nextfu = tfu;
114                nextfu = &tfu->nextfu;
115                tfu->reps = 1;
116
117                /* if leading digit, repetition count */
118                if (isdigit(*p)) {
119                        for (savep = p; isdigit(*p); ++p);
120                        if (!isspace(*p) && *p != '/')
121                                badfmt(globals, fmt);
122                        /* may overwrite either white space or slash */
123                        tfu->reps = atoi((char*)savep);
124                        tfu->flags = F_SETREP;
125                        /* skip trailing white space */
126                        for (++p; isspace(*p); ++p);
127                }
128
129                /* skip slash and trailing white space */
130                if (*p == '/')
131                        while (isspace(*++p));
132
133                /* byte count */
134                if (isdigit(*p)) {
135                        for (savep = p; isdigit(*p); ++p);
136                        if (!isspace(*p))
137                                badfmt(globals, fmt);
138                        tfu->bcnt = atoi((char*)savep);
139                        /* skip trailing white space */
140                        for (++p; isspace(*p); ++p);
141                }
142
143                /* format */
144                if (*p != '"')
145                        badfmt(globals, fmt);
146                for (savep = ++p; *p != '"';)
147                        if (*p++ == 0)
148                                badfmt(globals, fmt);
149                if (!(tfu->fmt = malloc(p - savep + 1)))
150                        err(exit_jump, 1, NULL);
151                (void) strncpy(tfu->fmt, (char*)savep, p - savep);
152                tfu->fmt[p - savep] = '\0';
153                escape(tfu->fmt);
154                p++;
155        }
156}
157
158static const char *spec = ".#-+ 0123456789";
159
160int
161size(rtems_shell_hexdump_globals* globals, FS *fs)
162{
163        FU *fu;
164        int bcnt, cursize;
165        unsigned char *fmt;
166        int prec;
167
168        /* figure out the data block size needed for each format unit */
169        for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
170                if (fu->bcnt) {
171                        cursize += fu->bcnt * fu->reps;
172                        continue;
173                }
174                for (bcnt = prec = 0, fmt = (unsigned char*) fu->fmt; *fmt; ++fmt) {
175                        if (*fmt != '%')
176                                continue;
177                        /*
178                         * skip any special chars -- save precision in
179                         * case it's a %s format.
180                         */
181                        while (index(spec + 1, *++fmt));
182                        if (*fmt == '.' && isdigit(*++fmt)) {
183                                prec = atoi((char*)fmt);
184                                while (isdigit(*++fmt));
185                        }
186                        switch(*fmt) {
187                        case 'c':
188                                bcnt += 1;
189                                break;
190                        case 'd': case 'i': case 'o': case 'u':
191                        case 'x': case 'X':
192                                bcnt += 4;
193                                break;
194                        case 'e': case 'E': case 'f': case 'g': case 'G':
195                                bcnt += 8;
196                                break;
197                        case 's':
198                                bcnt += prec;
199                                break;
200                        case '_':
201                                switch(*++fmt) {
202                                case 'c': case 'p': case 'u':
203                                        bcnt += 1;
204                                        break;
205                                }
206                        }
207                }
208                cursize += bcnt * fu->reps;
209        }
210        return (cursize);
211}
212
213void
214rewrite(rtems_shell_hexdump_globals* globals, FS *fs)
215{
216        enum { NOTOKAY, USEBCNT, USEPREC } sokay;
217        PR *pr, **nextpr;
218        FU *fu;
219        unsigned char *p1, *p2, *fmtp;
220        char savech, cs[3];
221        int nconv, prec;
222        size_t len;
223
224        pr = NULL;
225        nextpr = NULL;
226        prec = 0;
227
228        for (fu = fs->nextfu; fu; fu = fu->nextfu) {
229                /*
230                 * Break each format unit into print units; each conversion
231                 * character gets its own.
232                 */
233                for (nconv = 0, fmtp = (unsigned char*)fu->fmt; *fmtp; nextpr = &pr->nextpr) {
234                        if ((pr = calloc(1, sizeof(PR))) == NULL)
235                                err(exit_jump, 1, NULL);
236                        if (!fu->nextpr)
237                                fu->nextpr = pr;
238                        else {
239                                if (nextpr)
240                                        *nextpr = pr;
241                        }
242
243                        /* Skip preceding text and up to the next % sign. */
244                        for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
245
246                        /* Only text in the string. */
247                        if (!*p1) {
248                                pr->fmt = (char*)fmtp;
249                                pr->flags = F_TEXT;
250                                break;
251                        }
252
253                        /*
254                         * Get precision for %s -- if have a byte count, don't
255                         * need it.
256                         */
257                        if (fu->bcnt) {
258                                sokay = USEBCNT;
259                                /* Skip to conversion character. */
260                                for (++p1; index(spec, *p1); ++p1);
261                        } else {
262                                /* Skip any special chars, field width. */
263                                while (index(spec + 1, *++p1));
264                                if (*p1 == '.' && isdigit(*++p1)) {
265                                        sokay = USEPREC;
266                                        prec = atoi((char*)p1);
267                                        while (isdigit(*++p1));
268                                } else
269                                        sokay = NOTOKAY;
270                        }
271
272                        p2 = p1 + 1;            /* Set end pointer. */
273                        cs[0] = *p1;            /* Set conversion string. */
274                        cs[1] = '\0';
275
276                        /*
277                         * Figure out the byte count for each conversion;
278                         * rewrite the format as necessary, set up blank-
279                         * padding for end of data.
280                         */
281                        switch(cs[0]) {
282                        case 'c':
283                                pr->flags = F_CHAR;
284                                switch(fu->bcnt) {
285                                case 0: case 1:
286                                        pr->bcnt = 1;
287                                        break;
288                                default:
289                                        p1[1] = '\0';
290                                        badcnt(globals, (char*)p1);
291                                }
292                                break;
293                        case 'd': case 'i':
294                                pr->flags = F_INT;
295                                goto isint;
296                        case 'o': case 'u': case 'x': case 'X':
297                                pr->flags = F_UINT;
298isint:                          cs[2] = '\0';
299                                cs[1] = cs[0];
300                                cs[0] = 'q';
301                                switch(fu->bcnt) {
302                                case 0: case 4:
303                                        pr->bcnt = 4;
304                                        break;
305                                case 1:
306                                        pr->bcnt = 1;
307                                        break;
308                                case 2:
309                                        pr->bcnt = 2;
310                                        break;
311                                default:
312                                        p1[1] = '\0';
313                                        badcnt(globals, (char*)p1);
314                                }
315                                break;
316                        case 'e': case 'E': case 'f': case 'g': case 'G':
317                                pr->flags = F_DBL;
318                                switch(fu->bcnt) {
319                                case 0: case 8:
320                                        pr->bcnt = 8;
321                                        break;
322                                case 4:
323                                        pr->bcnt = 4;
324                                        break;
325                                default:
326                                        if (fu->bcnt == sizeof(long double)) {
327                                                cs[2] = '\0';
328                                                cs[1] = cs[0];
329                                                cs[0] = 'L';
330                                                pr->bcnt = sizeof(long double);
331                                        } else {
332                                                p1[1] = '\0';
333                                                badcnt(globals, (char*)p1);
334                                        }
335                                }
336                                break;
337                        case 's':
338                                pr->flags = F_STR;
339                                switch(sokay) {
340                                case NOTOKAY:
341                                        badsfmt(globals);
342                                case USEBCNT:
343                                        pr->bcnt = fu->bcnt;
344                                        break;
345                                case USEPREC:
346                                        pr->bcnt = prec;
347                                        break;
348                                }
349                                break;
350                        case '_':
351                                ++p2;
352                                switch(p1[1]) {
353                                case 'A':
354                                        endfu = fu;
355                                        fu->flags |= F_IGNORE;
356                                        /* FALLTHROUGH */
357                                case 'a':
358                                        pr->flags = F_ADDRESS;
359                                        ++p2;
360                                        switch(p1[2]) {
361                                        case 'd': case 'o': case'x':
362                                                cs[0] = 'q';
363                                                cs[1] = p1[2];
364                                                cs[2] = '\0';
365                                                break;
366                                        default:
367                                                p1[3] = '\0';
368                                                badconv(globals, (char*)p1);
369                                        }
370                                        break;
371                                case 'c':
372                                        pr->flags = F_C;
373                                        /* cs[0] = 'c'; set in conv_c */
374                                        goto isint2;
375                                case 'p':
376                                        pr->flags = F_P;
377                                        cs[0] = 'c';
378                                        goto isint2;
379                                case 'u':
380                                        pr->flags = F_U;
381                                        /* cs[0] = 'c'; set in conv_u */
382isint2:                                 switch(fu->bcnt) {
383                                        case 0: case 1:
384                                                pr->bcnt = 1;
385                                                break;
386                                        default:
387                                                p1[2] = '\0';
388                                                badcnt(globals, (char*)p1);
389                                        }
390                                        break;
391                                default:
392                                        p1[2] = '\0';
393                                        badconv(globals, (char*)p1);
394                                }
395                                break;
396                        default:
397                                p1[1] = '\0';
398                                badconv(globals, (char*)p1);
399                        }
400
401                        /*
402                         * Copy to PR format string, set conversion character
403                         * pointer, update original.
404                         */
405                        savech = *p2;
406                        p1[0] = '\0';
407                        len = strlen((char*)fmtp) + strlen(cs) + 1;
408                        if ((pr->fmt = calloc(1, len)) == NULL)
409                                err(exit_jump, 1, NULL);
410                        snprintf(pr->fmt, len, "%s%s", fmtp, cs);
411                        *p2 = savech;
412                        pr->cchar = pr->fmt + (p1 - fmtp);
413                        fmtp = p2;
414
415                        /* Only one conversion character if byte count. */
416                        if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++)
417        errx(exit_jump, 1, "byte count with multiple conversion characters");
418                }
419                /*
420                 * If format unit byte count not specified, figure it out
421                 * so can adjust rep count later.
422                 */
423                if (!fu->bcnt)
424                        for (pr = fu->nextpr; pr; pr = pr->nextpr)
425                                fu->bcnt += pr->bcnt;
426        }
427        if (pr) {
428                free(pr);
429                pr = NULL;
430        }
431        /*
432         * If the format string interprets any data at all, and it's
433         * not the same as the blocksize, and its last format unit
434         * interprets any data at all, and has no iteration count,
435         * repeat it as necessary.
436         *
437         * If, rep count is greater than 1, no trailing whitespace
438         * gets output from the last iteration of the format unit.
439         */
440        for (fu = fs->nextfu; fu; fu = fu->nextfu) {
441                if (!fu->nextfu && fs->bcnt < blocksize &&
442                    !(fu->flags&F_SETREP) && fu->bcnt)
443                        fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
444                if (fu->reps > 1) {
445                        for (pr = fu->nextpr;; pr = pr->nextpr)
446                                if (!pr->nextpr)
447                                        break;
448                        for (p1 = (unsigned char*)pr->fmt, p2 = NULL; *p1; ++p1)
449                                p2 = isspace(*p1) ? p1 : NULL;
450                        if (p2)
451                                pr->nospace = (char*)p2;
452                }
453        }
454#ifdef DEBUG
455        for (fu = fs->nextfu; fu; fu = fu->nextfu) {
456                (void)printf("fmt:");
457                for (pr = fu->nextpr; pr; pr = pr->nextpr)
458                        (void)printf(" {%s}", pr->fmt);
459                (void)printf("\n");
460        }
461#endif
462}
463
464void
465escape(char *p1)
466{
467        char *p2;
468
469        /* alphabetic escape sequences have to be done in place */
470        for (p2 = p1;; ++p1, ++p2) {
471                if (!*p1) {
472                        *p2 = *p1;
473                        break;
474                }
475                if (*p1 == '\\')
476                        switch(*++p1) {
477                        case 'a':
478                             /* *p2 = '\a'; */
479                                *p2 = '\007';
480                                break;
481                        case 'b':
482                                *p2 = '\b';
483                                break;
484                        case 'f':
485                                *p2 = '\f';
486                                break;
487                        case 'n':
488                                *p2 = '\n';
489                                break;
490                        case 'r':
491                                *p2 = '\r';
492                                break;
493                        case 't':
494                                *p2 = '\t';
495                                break;
496                        case 'v':
497                                *p2 = '\v';
498                                break;
499                        default:
500                                *p2 = *p1;
501                                break;
502                        }
503        }
504}
505
506void
507badcnt(rtems_shell_hexdump_globals* globals, char *s)
508{
509        errx(exit_jump, 1, "%s: bad byte count", s);
510}
511
512void
513badsfmt(rtems_shell_hexdump_globals* globals)
514{
515        errx(exit_jump, 1, "%%s: requires a precision or a byte count");
516}
517
518void
519badfmt(rtems_shell_hexdump_globals* globals, const char *fmt)
520{
521        errx(exit_jump, 1, "\"%s\": bad format", fmt);
522}
523
524void
525badconv(rtems_shell_hexdump_globals* globals, char *ch)
526{
527        errx(exit_jump, 1, "%%%s: bad conversion character", ch);
528}
Note: See TracBrowser for help on using the repository browser.