undump: Allow for trailing backslash
[wk-misc.git] / undump.c
1 /* undump - Hex undump tool
2  * Copyright (C) 2000, 2010 Werner Koch (dd9jn)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16  *
17  * 2010-09-02 wk  Changed to GPLv3.
18  *                Fixed detection of write errors.  Reported by Marcus
19  *                Brinkmann
20  * 2011-02-24 wk  Allow for 0x and \x prefixes.  Print offset with
21  *                the error messages.
22  * 2019-03-20 wk  Allow for trailing backslashes.
23  */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #define digitp(p)   ((p) >= '0' && (p) <= '9')
29 #define hexdigitp(a) (digitp (a)                     \
30                       || ((a) >= 'A' && (a) <= 'F')  \
31                       || ((a) >= 'a' && (a) <= 'f'))
32 #define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
33 #define xtoi_1(p)   ((p) <= '9'? ((p)- '0'): \
34                      (p) <= 'F'? ((p)-'A'+10):((p)-'a'+10))
35
36
37
38
39 int
40 main (int argc, char **argv )
41 {
42   int c1, c2;
43   unsigned int value;
44   unsigned long lnr, off;
45
46   if ( argc > 1 )
47     {
48       fprintf (stderr, "usage: undump < input\n");
49       return 1;
50     }
51
52
53   lnr = 1;
54   off = 0;
55   while ( (c1=getchar ()) != EOF )
56     {
57       off++;
58       if (c1 == '\n')
59         lnr++;
60       if (ascii_isspace (c1))
61         continue;
62       if (c1 == '\\')
63         {
64           /* Assume the hex digits are prefixed with \x.  */
65           c1 = getchar ();
66           off++;
67           if (c1 == '\n')
68             {
69               /* But this is a trailing backslash - skip.  */
70               lnr++;
71               continue;
72             }
73           if (ascii_isspace (c1))
74             {
75               /* backslash followed by space - see whether this
76                * can also be considered as a trailing backslash.  */
77               while ((c1 = getchar ()) != EOF && ++off && c1 != '\n')
78                 {
79                   if (!ascii_isspace (c1))
80                     {
81                       fprintf (stderr, "undump: spurious backslash "
82                                "at line %lu, off %lu\n", lnr, off);
83                       return 1;
84                     }
85                 }
86               if (c1 == '\n')
87                 {
88                   lnr++;
89                   continue;
90                 }
91               /* EOF */
92               break;
93             }
94           if (c1 != EOF)
95             {
96               c2 = getchar ();
97               off++;
98             }
99           if (c1 != 'x' || c2 == EOF)
100             {
101               fprintf (stderr, "undump: incomplete \\x "
102                        "prefix at line %lu, off %lu\n", lnr, off);
103               return 1;
104             }
105           c1 = c2;
106         }
107       if (!hexdigitp (c1))
108         {
109           fprintf (stderr,
110                    "undump: non hex-digit encountered at line %lu, off %lu\n",
111                    lnr, off);
112           return 1;
113         }
114       if ( (c2=getchar ()) == EOF )
115         {
116           fprintf (stderr,
117                    "undump: error reading second nibble at line %lu, off %lu\n",
118                    lnr, off);
119           return 1;
120         }
121       off++;
122       if (c2 == '\n')
123         lnr++;
124       if (!hexdigitp (c2))
125         {
126           if (c1 == '0' && c2 == 'x')
127             {
128               /* Assume the hex digits are prefixed with 0x.  */
129               c1 = getchar ();
130               off++;
131               if (c1 != EOF)
132                 {
133                   c2 = getchar ();
134                   off++;
135                 }
136               if (c1 == EOF || c2 == EOF || !hexdigitp (c1) || !hexdigitp (c2))
137                 {
138                   fprintf (stderr, "undump: incomplete 0x "
139                            "prefix at line %lu, off %lu\n", lnr, off);
140                   return 1;
141                 }
142             }
143           else
144             {
145               fprintf (stderr, "undump: second nibble is not a hex-digit"
146                        " at line %lu, off %lu\n", lnr, off);
147               return 1;
148             }
149         }
150       value = xtoi_1 (c1) * 16 + xtoi_1 (c2);
151       putchar (value);
152     }
153   if (ferror (stdin))
154     {
155       fprintf (stderr, "undump: read error at line %lu, off %lu\n", lnr, off);
156       return 1;
157     }
158   if (ferror (stdout))
159     {
160       fprintf (stderr, "undump: write error at input line %lu, off %lu\n",
161                lnr, off);
162       return 1;
163     }
164
165   return 0;
166 }
167
168 /*
169 Local Variables:
170 compile-command: "cc -Wall -o undump undump.c"
171 End:
172 */