]> mj.ucw.cz Git - libucw.git/blob - ucw/hex.c
Moved some utils from utils/ to ucw/
[libucw.git] / ucw / hex.c
1 /*
2  *  Hexadecimal dumper (CP/M style format)
3  *
4  *  Original version (c) Eric S. Raymond <esr@snark.thyrsus.com>
5  *  Heavily modified by Martin Mares <mj@ucw.cz>
6  *
7  *  Can be freely distributed and used under the terms of the GNU GPL.
8  */
9
10 #include "ucw/lib.h"
11 #include "ucw/lfs.h"
12
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <string.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19
20 #define DEFWIDTH 16             /* Default # chars to show per line */
21 #define MAXWIDTH 32             /* Maximum # of bytes per line  */
22
23 typedef int bool;
24 #define TRUE    1
25 #define FALSE   0
26
27 static long     linesize = DEFWIDTH;    /* # of bytes to print per line */
28 static bool     cflag = FALSE;          /* show printables as ASCII if true */
29 static bool     gflag = FALSE;          /* suppress mid-page gutter if true */
30 static ucw_off_t        start = 0;              /* file offset to start dumping at */
31 static ucw_off_t        length = 0;             /* if nz, how many chars to dump */
32
33 static void dumpfile(FILE *f)
34      /* dump a single, specified file -- stdin if filename is NULL */
35 {
36   int     ch = '\0';            /* current character            */
37   char    ascii[MAXWIDTH+3];    /* printable ascii data         */
38   int     i = 0;                /* counter: # bytes processed   */
39   int     ai = 0;               /* index into ascii[]           */
40   ucw_off_t offset = start;     /* byte offset of line in file  */
41   int     hpos = 0;             /* horizontal position counter  */
42   ucw_off_t fstart = start;
43   ucw_off_t flength = length;
44   char    *specials = "\b\f\n\r\t";
45   char    *escapes = "bfnrt";
46   char    *cp;
47
48   if (fstart && ucw_seek(fileno(f), fstart, SEEK_SET) >= 0)
49     fstart = 0;
50
51   do {
52     ch = getc(f);
53
54     if (ch != EOF)
55       {
56         if (length && flength-- <= 0)
57           ch = EOF;
58       }
59
60     if (ch != EOF)
61       {
62         if (i++ % linesize == 0)
63           {
64             (void) printf("%04Lx ", (long long) offset);
65             offset += linesize;
66             hpos = 5;
67           }
68
69         /* output one space for the mid-page gutter */
70         if (!gflag)
71           if ((i - 1) % (linesize / 2) == 0)
72             {
73               (void) putchar(' ');
74               hpos++;
75               ascii[ai++] = ' ';
76             }
77
78         /* dump the indicated representation of a character */
79         ascii[ai] = (isprint (ch) || ch == ' ') ? ch : '.';
80
81         if (cflag && (isprint(ch) || ch == ' '))
82           (void) printf("%c  ", ch);
83         else if (cflag && ch && (cp = strchr(specials, ch)))
84           (void) printf("\\%c ", escapes[cp - specials]);
85         else
86           (void) printf("%02x ", ch);
87
88         /* update counters and things */
89         ai++;
90         hpos += 3;
91       }
92
93     /* At end-of-line or EOF, show ASCII version of data. */
94     if (i && (ch == EOF || (i % linesize == 0)))
95       {
96         if (!cflag)
97           {
98             while (hpos < linesize * 3 + 7)
99               {
100                 hpos++;
101                 (void) putchar(' ');
102               }
103
104             ascii[ai] = '\0';
105             (void) printf("%s", ascii);
106           }
107
108         if (ch != EOF || (i % linesize != 0))
109           (void) putchar('\n');
110         ai = 0;         /* reset counters */
111       }
112   } while
113     (ch != EOF);
114 }
115
116 static ucw_off_t getoffs(char *cp)
117      /* fetch decimal or hex integer to be used as file start or offset */
118 {
119   ucw_off_t value = 0;
120   char *hexdigits = "0123456789abcdefABCDEF";
121
122 #if 0
123   bool foundzero = FALSE;
124   int base = 0;
125
126   for (; *cp; cp++)
127     if (*cp == '0')
128       foundzero = TRUE;
129     else if (isdigit(*cp))
130       {
131         base = 10;
132         break;
133       }
134     else if (*cp = 'x' || *cp == 'X' || *cp == 'h' || *cp == 'H')
135       {
136         base = 16;
137         cp++;
138         break;
139       }
140     else
141       return(-1L);
142
143   if (base == 0)
144     if (foundzero)
145       base = 10;
146     else
147       return(-1L);
148
149   if (base == 10)
150     {
151       for (; *cp; cp++)
152         if (isdigit(*cp))
153           value = value * 10 + (*cp - '0');
154         else
155           return(-1L);
156     }
157   else
158 #endif
159     {
160       for (; *cp; cp++)
161         if (strchr(hexdigits, *cp))
162           value = value*16 + (strchr(hexdigits, tolower(*cp))-hexdigits);
163         else
164           return -1;
165     }
166
167   return(value);
168 }
169
170 int main(int argc, char **argv)
171 {
172   FILE    *infile;          /* file pointer input file */
173   int       dumpcount = 0;  /* count of files dumped so far */
174   char    *cp;
175   int     fd;
176
177   for (argv++, argc--; argc > 0; argv++, argc--)
178     {
179       char s = **argv;
180
181       if (s == '-' || s == '+')
182         {
183           int   c = *++*argv;
184
185           switch (c)
186             {
187             case 'c': cflag = (s == '-'); continue;
188             case 'g': gflag = (s == '-'); continue;
189
190             case 's':
191               if ((*argv)[1])
192                 (*argv)++;
193               else
194                 argc--, argv++;
195               if (s == '-' && argc >= 0)
196                 {
197                   if (cp = strchr(*argv, ','))
198                     *cp++ = '\0';
199                   if ((start = getoffs(*argv)) < 0)
200                     {
201                       (void) fputs("hex: start offset no good\n", stderr);
202                       exit(1);
203                     }
204
205                   if (cp)
206                     if ((length = getoffs(cp)) < 0)
207                       {
208                         (void) fputs("hex: length no good\n", stderr);
209                         exit(1);
210                       }
211                 }
212               else
213                 start = length = 0L;
214               continue;
215
216             case '\0':
217               infile = stdin;
218               break;
219
220             case 'w':
221               if ((*argv)[1])
222                 (*argv)++;
223               else
224                 argc--, argv++;
225               if ((linesize = getoffs(*argv)) == -1L || linesize > MAXWIDTH)
226                 {
227                   (void) fputs("hex: line width no good\n", stderr);
228                   exit(1);
229                 }
230               if (linesize % 2)
231                 gflag = TRUE;
232               continue;
233
234             default:
235               (void) fprintf(stderr, "hex: no such option as %s\n", *argv);
236               exit(1);
237             }
238         }
239       else
240         {
241           fd = ucw_open(*argv, O_RDONLY, 0);
242           if (fd < 0 || !(infile = fdopen(fd, "r")))
243             {
244               (void) fprintf(stderr, "hex: cannot open %s: %m\n", *argv);
245               exit(1);
246             }
247         }
248
249       if (dumpcount > 0 || argc > 1)
250         if (infile == stdin)
251           (void) printf("---- <Standard input> ----\n");
252         else
253           (void) printf("---- %s ----\n", *argv);
254       dumpfile(infile);
255       dumpcount++;
256       if (infile != stdin)
257         (void) fclose(infile);
258     }
259
260   if (dumpcount == 0)
261     dumpfile(stdin);
262   return(0);
263 }