123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759 |
- /* Octal (and other formats) dump of contents of a file.
- Copyright 1984 (C) Richard Stallman
- Permission is granted to anyone to make or distribute
- verbatim copies of this program
- provided that the copyright notice and this permission notice are preserved;
- and provided that the recipient is not asked to waive or limit his right to
- redistribute copies as permitted by this permission notice;
- and provided that anyone possessing a machine-executable copy
- is granted access to copy the source code, in machine-readable form,
- in some reasonable manner.
- Permission is granted to distribute derived works or enhanced versions of
- this program under the above conditions with the additional condition
- that the entire derivative or enhanced work
- must be covered by a permission notice identical to this one.
- Anything distributed as part of a package containing portions derived
- from this program, which cannot in current practice perform its function
- usefully in the absence of what was derived directly from this program,
- is to be considered as forming, together with the latter,
- a single work derived from this program,
- which must be entirely covered by a permission notice identical to this one
- in order for distribution of the package to be permitted.
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding! */
- #include <stdio.h>
- /* Format to be used: */
- #define OCTAL 1
- #define DECIMAL 2
- #define SIGNED_DECIMAL 3
- #define HEX 4
- #define FLOAT 5
- #define ASCII 6
- #define CHARNAME 7
- #define STRINGS 8
- int format; /* Value is one of the codes listed above */
- /* Size of unit of dumping, in bytes. */
- int size;
- /* What to do about bit 7 of each byte, in CHARNAME mode.
- 1 => flag odd parity. 2 => flag even parity. 0 => ignore it. */
- int parity;
- /* Number of bytes to display on each line of output. */
- int bytesperline;
- /* Nonzero means elide an output line identical to the previous one. */
- int elide;
- /* Radix for printing addresses (must be 8, 10 or 16) */
- int address_radix;
- /* For STRINGS output format, this is minimum length of sequence
- of graphic chars to trigger output. */
- int stringmin;
- /* Name of file to be dumped. */
- char *filename; /* 0 means dump fropm stdin. */
- /* Starting offset in the file, in bytes. */
- long start_point;
- /* Stopping point in the file, in bytes. */
- long stop_point;
- /* Base of pseudo-address to use for printed lines.
- This address is printed for the first line of data
- and appropriately greater addresses for later lines.
- Pseudo-addresses are printed if `labelflag' is nonzero. */
- long label;
- int labelflag;
- char *concat ();
- long integer_arg ();
- main (argc, argv)
- int argc;
- char **argv;
- {
- FILE *stream;
- /* Initialize all parameters to their defaults */
- format = OCTAL;
- size = 2;
- bytesperline = 16;
- elide = 1;
- start_point = 0;
- stop_point = -1;
- filename = 0;
- labelflag = 0;
- label = 0;
- address_radix = 8;
- parity = 0; /* Relevant only for CHARNAMES mode */
- stringmin = 3; /* Relevant only if STRINGS mode selected */
- {
- int i;
- for (i = 1; i < argc; i++)
- {
- if (argv[i][0] == '-')
- { /* this arg is a switch */
- char *p = &argv[i][1];
- char c;
- if (!strcmp (argv[i], "-B"))
- {
- if (++i == argc)
- fatal ("-B used without argument", 0);
- start_point = integer_arg (argv[i]);
- continue;
- }
- if (!strcmp (argv[i], "-E"))
- {
- if (++i == argc)
- fatal ("-E used without argument", 0);
- stop_point = integer_arg (argv[i]);
- continue;
- }
- if (!strcmp (argv[i], "-R"))
- {
- if (++i == argc)
- fatal ("-R used without argument", 0);
- address_radix = integer_arg (argv[i]);
- continue;
- }
- if (!strcmp (argv[i], "-L"))
- {
- if (++i == argc)
- fatal ("-L used without argument", 0);
- labelflag = 1;
- label = integer_arg (argv[i]);
- continue;
- }
- while (c = *p++)
- switch (c)
- {
- case 'a':
- format = CHARNAME;
- size = 1;
- break;
- case 'b':
- format = OCTAL;
- size = 1;
- break;
- case 'c':
- format = ASCII;
- size = 1;
- break;
- case 'd':
- format = DECIMAL;
- size = 2;
- break;
- case 'D':
- format = DECIMAL;
- size = 4;
- break;
- case 'f':
- format = FLOAT;
- size = 4;
- break;
- case 'F':
- format = FLOAT;
- size = 8;
- break;
- case 'h':
- format = HEX;
- size = 2;
- break;
- case 'H':
- format = HEX;
- size = 4;
- break;
- case 'i':
- format = SIGNED_DECIMAL;
- size = 2;
- break;
- case 'l':
- case 'I':
- format = SIGNED_DECIMAL;
- size = 4;
- break;
- case 'o':
- format = OCTAL;
- size = 2;
- break;
- case 'O':
- format = OCTAL;
- size = 4;
- break;
- case 'p':
- parity = 1;
- break;
- case 'P':
- parity = 2;
- break;
- case 's':
- format = STRINGS;
- if (*p >= '0' && *p <= '9')
- stringmin = parse_int (&p);
- break;
- case 'v':
- elide = 0;
- break;
- case 'w':
- if (*p >= '0' && *p <= '9')
- bytesperline = parse_int (&p);
- else
- bytesperline = 32;
- break;
- case 'x':
- format = HEX;
- size = 2;
- break;
- case 'X':
- format = HEX;
- size = 4;
- break;
- }
- }
- else
- break; /* We have reached a non-switch. */
- }
- if (i < argc)
- filename = argv[i++];
- if (i < argc)
- error ("too many arguments; extra arguments being ignored");
- }
- /* Command args have been decoded; do the work */
- if (filename)
- stream = fopen (filename, "r");
- else
- stream = stdin;
- if (!stream)
- pfatal_with_name (filename);
- /* Seek or skip to specified start point in the file */
- if (fseek (stream, start_point, 0))
- {
- /* fseek did not work; do it the slow way. */
- char *buf[1024];
- long i;
- for (i = start_point / 1024; i > 0; i--)
- fread (buf, 1, 1024, stream);
- fread (buf, 1, start_point % 1024, stream);
- }
- if (format == STRINGS)
- dump_strings (stream);
- else
- {
- long address = start_point;
- /* buffer holds data for this line, buffer1 for prev line */
- char *buffer = (char *) malloc (bytesperline);
- char *buffer1 = (char *) malloc (bytesperline);
- int linecount = 0;
- int elidecount = 0;
- /* Loop, a line's worth of data at a time. */
- while (stop_point == -1 || address < (unsigned) stop_point)
- {
- /* Read the data */
- int nread = fread (buffer, 1, bytesperline, stream);
- if (!nread) break;
- /* If this line matches the previous, elide it. */
- if (elide && linecount++ && !bcmp (buffer, buffer1, bytesperline))
- {
- if (!elidecount++)
- printf ("*\n");
- }
- else
- {
- char *tem;
- /* Not eliding => print the line of data */
- elidecount = 0;
- dumpline (buffer, address, nread);
- putchar ('\n');
- /* the line just dumped becomes "previous" by pointer-shuffle */
- tem = buffer; buffer = buffer1; buffer1 = tem;
- }
- address += nread;
- }
- }
- fclose (stream);
- }
- /* Dump the data in `buffer' as one line of text.
- There are `nbytes' bytes actually available.
- The data came from address `address' within the input file.
- */
- dumpline (buffer, address, nbytes)
- char *buffer;
- long address;
- int nbytes;
- {
- /* If specified stop point is within this line, don't go past it. */
- if (stop_point != -1 && (unsigned) stop_point - address < nbytes)
- nbytes = (unsigned) stop_point - address;
- print_address (address);
- {
- char *p = buffer;
- int units = (nbytes + size - 1) / size;
- int i;
- for (i = 0; i < units; i++)
- {
- if (format == FLOAT)
- {
- if (size == 4)
- printf ("%15.7#e", *(float *) p);
- else
- printf ("%22.14#e", *(double *) p);
- }
- else
- {
- int unit;
- /* Fetch the next unit - `size' says how long it is. */
- switch (size)
- {
- case 1:
- unit = *(unsigned char *) p;
- break;
- case 2:
- if (format == SIGNED_DECIMAL)
- unit = *(short *) p;
- else
- unit = *(unsigned short *)p;
- break;
- case 4:
- unit = *(int *)p;
- break;
- }
- /* Print the unit. */
- switch (format)
- {
- case DECIMAL:
- printf (" %0*u", 5 * (size >> 1), unit);
- break;
- case SIGNED_DECIMAL:
- printf (" %*d", 1 + 5 * (size >> 1), unit);
- break;
- case OCTAL:
- printf (" %0*o", (size == 4) ? 11 : size * 3, unit);
- break;
- case HEX:
- printf (" %0*x", size * 2, unit);
- break;
- case ASCII:
- dump_char (unit & 0377);
- break;
- case CHARNAME:
- dump_charname (unit);
- break;
- default:
- printf (" xxx", unit);
- }
- }
- p += size;
- }
- }
- }
- /* Print the address of a line of output data.
- This is done at the beginning of each line.
- A space is printed after the address. */
- print_address (address)
- long address;
- {
- print_address_1 (address);
- putchar (' ');
- if (labelflag)
- {
- putchar ('(');
- print_address_1 (address - start_point + label);
- putchar (')');
- putchar (' ');
- }
- }
- print_address_1 (address)
- long address;
- {
- switch (address_radix)
- {
- case 8:
- printf ("%07o", address);
- break;
- case 10:
- printf ("%7d", address);
- break;
- case 16:
- printf ("0x%06x", address);
- break;
- default: ;
- }
- }
- /* Dump a single character, as a character, right-justified in four columns */
- dump_char (c)
- unsigned char c;
- {
- switch (c)
- {
- case 0:
- printf (" \\0");
- break;
- case '\n':
- printf (" \\n");
- break;
- case '\t':
- printf (" \\t");
- break;
- case '\r':
- printf (" \\r");
- break;
- case '\b':
- printf (" \\b");
- break;
- case '\f':
- printf (" \\f");
- break;
- default:
- if (c < 040 || c >= 0200)
- printf (" %03o", c);
- else
- printf (" %c", c);
- }
- }
- /* Print the name of character c, and indicate its parity
- in the way specified by `parity'. */
- char *charname[33] =
- {
- "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
- "bs", "ht", "lf", "vt", "ff", "cr", "so", "si",
- "dle", "dc1", "dc2", "dc3", "nak", "syn", "etb",
- "can", "em", "sub", "esc", "fs", "gs", "rs", "us",
- "sp"
- };
- dump_charname (c)
- char c;
- {
- char c1 = c & 127;
- if (c1 == 127)
- printf (" del");
- else if (c1 > 040)
- printf (" %c", c1);
- else printf ("%4s", charname[c1]);
- if (parity)
- {
- if ((parity == 1 && char_parity (c) == 0) ||
- (parity == 2 && char_parity (c) == 1))
- putchar ('*');
- else
- putchar (' ');
- }
- }
- /* Return 1 if character `c' has odd parity. */
- char_parity (c)
- char c;
- {
- return !!(c & 1) ^ !!(c & 2) ^ !!(c & 4) ^ !!(c & 8) ^
- !!(c & 16) ^ !!(c & 32) ^ !!(c & 64) ^ !!(c & 128);
- }
- /* STRINGS mode. Find each "string constant" in the file.
- A string constant is a run of at least `stringmin' ASCII graphic (or formatting) characters
- terminated by a null. */
- dump_strings (stream)
- FILE *stream;
- {
- int bufsize = 100;
- char *buf = (char *) malloc (bufsize);
- long address = start_point;
- while (1)
- {
- int i;
- int c;
- /* See if the next `stringmin' chars are all graphic chars. */
- tryline:
- if (stop_point != -1 && address >= (unsigned) stop_point)
- break;
- for (i = 0; i < stringmin; i++)
- {
- c = getc (stream);
- address++;
- if (c < 0) return;
- if (!graphicp (c))
- /* Found a non-graphic. Try again starting with next char. */
- goto tryline;
- buf [i] = c;
- }
- /* We found a run of `stringmin' graphic characters */
- /* Now see if it is terminated with a null byte. */
- while (1)
- {
- if (i == bufsize)
- buf = (char *) xrealloc (buf, bufsize *= 2);
- c = getc (stream);
- address++;
- if (c < 0) return;
- if (c == 0) break; /* It is; print this string */
- if (!graphicp (c))
- goto tryline; /* It isn't; give up on this string */
- buf[i++] = c; /* String continues; store it all. */
- }
- /* If we get here, the string is all graphics and null-terminated,
- so print it. It is all in `buf' and `i' is its length. */
- buf[i] = 0;
- print_address (address - i - 1);
- for (i = 0; c = buf[i]; i++)
- switch (c)
- {
- case '\n':
- printf ("\\n");
- break;
- case '\t':
- printf ("\\t");
- break;
- case '\f':
- printf ("\\f");
- break;
- case '\b':
- printf ("\\b");
- break;
- case '\r':
- printf ("\\r");
- break;
- default:
- putchar (c);
- }
- putchar ('\n');
- }
- }
- /* Return 1 if `c' is an ASCII graphic character */
- int
- graphicp (c)
- unsigned char c;
- {
- return (c >= 040 && c < 0177) ||
- c == '\n' || c == '\t' || c == '\b' || c == '\f' || c == '\r';
- }
- /* Print error message and exit. */
- fatal (s1, s2)
- char *s1, *s2;
- {
- error (s1, s2);
- exit (1);
- }
- /* Print error message. `s1' is printf control string, `s2' is arg for it. */
- error (s1, s2)
- char *s1, *s2;
- {
- printf ("od: ");
- printf (s1, s2);
- printf ("\n");
- }
- pfatal_with_name (name)
- char *name;
- {
- extern int errno, sys_nerr;
- extern char *sys_errlist[];
- char *s;
- if (errno < sys_nerr)
- s = concat ("", sys_errlist[errno], " for %s");
- else
- s = "cannot open %s";
- fatal (s, name);
- }
- /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
- char *
- concat (s1, s2, s3)
- char *s1, *s2, *s3;
- {
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
- return result;
- }
- /* Like malloc but get fatal error if memory is exhausted. */
- int
- xmalloc (size)
- int size;
- {
- int result = malloc (size);
- if (!result)
- fatal ("virtual memory exhausted", 0);
- return result;
- }
- int
- xrealloc (ptr, size)
- char *ptr;
- int size;
- {
- int result = realloc (ptr, size);
- if (!result)
- fatal ("virtual memory exhausted");
- return result;
- }
- /* Parse string `s' as an integer, using decimal radix by default,
- but allowing octal and hex numbers as in C. */
- long
- integer_arg (s)
- char *s;
- {
- long value;
- int radix = 10;
- char *p = s;
- int c;
- if (*p != '0')
- radix = 10;
- else if (*++p == 'x')
- {
- radix = 16;
- p++;
- }
- else
- radix = 8;
- value = 0;
- while (((c = *p++) >= '0' && c <= '9')
- || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
- {
- value *= radix;
- if (c >= '0' && c <= '9')
- value += c - '0';
- else
- value += (c & ~40) - 'A';
- }
- if (c == 'b')
- value *= 512;
- else if (c == 'B')
- value *= 1024;
- else
- p--;
- if (*p)
- fatal ("invalid integer argument %s", s);
- return value;
- }
- /* Parse an integer in decimal off string `*p' points to,
- and update *p to point at the terminating character.
- The integer is returned as the value. */
- parse_int (p)
- char **p;
- {
- int val = atoi (*p);
- while (**p >= '0' && **p <= '9') (*p)++;
- return val;
- }
|