od.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. /* Octal (and other formats) dump of contents of a file.
  2. Copyright 1984 (C) Richard Stallman
  3. Permission is granted to anyone to make or distribute
  4. verbatim copies of this program
  5. provided that the copyright notice and this permission notice are preserved;
  6. and provided that the recipient is not asked to waive or limit his right to
  7. redistribute copies as permitted by this permission notice;
  8. and provided that anyone possessing a machine-executable copy
  9. is granted access to copy the source code, in machine-readable form,
  10. in some reasonable manner.
  11. Permission is granted to distribute derived works or enhanced versions of
  12. this program under the above conditions with the additional condition
  13. that the entire derivative or enhanced work
  14. must be covered by a permission notice identical to this one.
  15. Anything distributed as part of a package containing portions derived
  16. from this program, which cannot in current practice perform its function
  17. usefully in the absence of what was derived directly from this program,
  18. is to be considered as forming, together with the latter,
  19. a single work derived from this program,
  20. which must be entirely covered by a permission notice identical to this one
  21. in order for distribution of the package to be permitted.
  22. In other words, you are welcome to use, share and improve this program.
  23. You are forbidden to forbid anyone else to use, share and improve
  24. what you give them. Help stamp out software-hoarding! */
  25. #include <stdio.h>
  26. /* Format to be used: */
  27. #define OCTAL 1
  28. #define DECIMAL 2
  29. #define SIGNED_DECIMAL 3
  30. #define HEX 4
  31. #define FLOAT 5
  32. #define ASCII 6
  33. #define CHARNAME 7
  34. #define STRINGS 8
  35. int format; /* Value is one of the codes listed above */
  36. /* Size of unit of dumping, in bytes. */
  37. int size;
  38. /* What to do about bit 7 of each byte, in CHARNAME mode.
  39. 1 => flag odd parity. 2 => flag even parity. 0 => ignore it. */
  40. int parity;
  41. /* Number of bytes to display on each line of output. */
  42. int bytesperline;
  43. /* Nonzero means elide an output line identical to the previous one. */
  44. int elide;
  45. /* Radix for printing addresses (must be 8, 10 or 16) */
  46. int address_radix;
  47. /* For STRINGS output format, this is minimum length of sequence
  48. of graphic chars to trigger output. */
  49. int stringmin;
  50. /* Name of file to be dumped. */
  51. char *filename; /* 0 means dump fropm stdin. */
  52. /* Starting offset in the file, in bytes. */
  53. long start_point;
  54. /* Stopping point in the file, in bytes. */
  55. long stop_point;
  56. /* Base of pseudo-address to use for printed lines.
  57. This address is printed for the first line of data
  58. and appropriately greater addresses for later lines.
  59. Pseudo-addresses are printed if `labelflag' is nonzero. */
  60. long label;
  61. int labelflag;
  62. char *concat ();
  63. long integer_arg ();
  64. main (argc, argv)
  65. int argc;
  66. char **argv;
  67. {
  68. FILE *stream;
  69. /* Initialize all parameters to their defaults */
  70. format = OCTAL;
  71. size = 2;
  72. bytesperline = 16;
  73. elide = 1;
  74. start_point = 0;
  75. stop_point = -1;
  76. filename = 0;
  77. labelflag = 0;
  78. label = 0;
  79. address_radix = 8;
  80. parity = 0; /* Relevant only for CHARNAMES mode */
  81. stringmin = 3; /* Relevant only if STRINGS mode selected */
  82. {
  83. int i;
  84. for (i = 1; i < argc; i++)
  85. {
  86. if (argv[i][0] == '-')
  87. { /* this arg is a switch */
  88. char *p = &argv[i][1];
  89. char c;
  90. if (!strcmp (argv[i], "-B"))
  91. {
  92. if (++i == argc)
  93. fatal ("-B used without argument", 0);
  94. start_point = integer_arg (argv[i]);
  95. continue;
  96. }
  97. if (!strcmp (argv[i], "-E"))
  98. {
  99. if (++i == argc)
  100. fatal ("-E used without argument", 0);
  101. stop_point = integer_arg (argv[i]);
  102. continue;
  103. }
  104. if (!strcmp (argv[i], "-R"))
  105. {
  106. if (++i == argc)
  107. fatal ("-R used without argument", 0);
  108. address_radix = integer_arg (argv[i]);
  109. continue;
  110. }
  111. if (!strcmp (argv[i], "-L"))
  112. {
  113. if (++i == argc)
  114. fatal ("-L used without argument", 0);
  115. labelflag = 1;
  116. label = integer_arg (argv[i]);
  117. continue;
  118. }
  119. while (c = *p++)
  120. switch (c)
  121. {
  122. case 'a':
  123. format = CHARNAME;
  124. size = 1;
  125. break;
  126. case 'b':
  127. format = OCTAL;
  128. size = 1;
  129. break;
  130. case 'c':
  131. format = ASCII;
  132. size = 1;
  133. break;
  134. case 'd':
  135. format = DECIMAL;
  136. size = 2;
  137. break;
  138. case 'D':
  139. format = DECIMAL;
  140. size = 4;
  141. break;
  142. case 'f':
  143. format = FLOAT;
  144. size = 4;
  145. break;
  146. case 'F':
  147. format = FLOAT;
  148. size = 8;
  149. break;
  150. case 'h':
  151. format = HEX;
  152. size = 2;
  153. break;
  154. case 'H':
  155. format = HEX;
  156. size = 4;
  157. break;
  158. case 'i':
  159. format = SIGNED_DECIMAL;
  160. size = 2;
  161. break;
  162. case 'l':
  163. case 'I':
  164. format = SIGNED_DECIMAL;
  165. size = 4;
  166. break;
  167. case 'o':
  168. format = OCTAL;
  169. size = 2;
  170. break;
  171. case 'O':
  172. format = OCTAL;
  173. size = 4;
  174. break;
  175. case 'p':
  176. parity = 1;
  177. break;
  178. case 'P':
  179. parity = 2;
  180. break;
  181. case 's':
  182. format = STRINGS;
  183. if (*p >= '0' && *p <= '9')
  184. stringmin = parse_int (&p);
  185. break;
  186. case 'v':
  187. elide = 0;
  188. break;
  189. case 'w':
  190. if (*p >= '0' && *p <= '9')
  191. bytesperline = parse_int (&p);
  192. else
  193. bytesperline = 32;
  194. break;
  195. case 'x':
  196. format = HEX;
  197. size = 2;
  198. break;
  199. case 'X':
  200. format = HEX;
  201. size = 4;
  202. break;
  203. }
  204. }
  205. else
  206. break; /* We have reached a non-switch. */
  207. }
  208. if (i < argc)
  209. filename = argv[i++];
  210. if (i < argc)
  211. error ("too many arguments; extra arguments being ignored");
  212. }
  213. /* Command args have been decoded; do the work */
  214. if (filename)
  215. stream = fopen (filename, "r");
  216. else
  217. stream = stdin;
  218. if (!stream)
  219. pfatal_with_name (filename);
  220. /* Seek or skip to specified start point in the file */
  221. if (fseek (stream, start_point, 0))
  222. {
  223. /* fseek did not work; do it the slow way. */
  224. char *buf[1024];
  225. long i;
  226. for (i = start_point / 1024; i > 0; i--)
  227. fread (buf, 1, 1024, stream);
  228. fread (buf, 1, start_point % 1024, stream);
  229. }
  230. if (format == STRINGS)
  231. dump_strings (stream);
  232. else
  233. {
  234. long address = start_point;
  235. /* buffer holds data for this line, buffer1 for prev line */
  236. char *buffer = (char *) malloc (bytesperline);
  237. char *buffer1 = (char *) malloc (bytesperline);
  238. int linecount = 0;
  239. int elidecount = 0;
  240. /* Loop, a line's worth of data at a time. */
  241. while (stop_point == -1 || address < (unsigned) stop_point)
  242. {
  243. /* Read the data */
  244. int nread = fread (buffer, 1, bytesperline, stream);
  245. if (!nread) break;
  246. /* If this line matches the previous, elide it. */
  247. if (elide && linecount++ && !bcmp (buffer, buffer1, bytesperline))
  248. {
  249. if (!elidecount++)
  250. printf ("*\n");
  251. }
  252. else
  253. {
  254. char *tem;
  255. /* Not eliding => print the line of data */
  256. elidecount = 0;
  257. dumpline (buffer, address, nread);
  258. putchar ('\n');
  259. /* the line just dumped becomes "previous" by pointer-shuffle */
  260. tem = buffer; buffer = buffer1; buffer1 = tem;
  261. }
  262. address += nread;
  263. }
  264. }
  265. fclose (stream);
  266. }
  267. /* Dump the data in `buffer' as one line of text.
  268. There are `nbytes' bytes actually available.
  269. The data came from address `address' within the input file.
  270. */
  271. dumpline (buffer, address, nbytes)
  272. char *buffer;
  273. long address;
  274. int nbytes;
  275. {
  276. /* If specified stop point is within this line, don't go past it. */
  277. if (stop_point != -1 && (unsigned) stop_point - address < nbytes)
  278. nbytes = (unsigned) stop_point - address;
  279. print_address (address);
  280. {
  281. char *p = buffer;
  282. int units = (nbytes + size - 1) / size;
  283. int i;
  284. for (i = 0; i < units; i++)
  285. {
  286. if (format == FLOAT)
  287. {
  288. if (size == 4)
  289. printf ("%15.7#e", *(float *) p);
  290. else
  291. printf ("%22.14#e", *(double *) p);
  292. }
  293. else
  294. {
  295. int unit;
  296. /* Fetch the next unit - `size' says how long it is. */
  297. switch (size)
  298. {
  299. case 1:
  300. unit = *(unsigned char *) p;
  301. break;
  302. case 2:
  303. if (format == SIGNED_DECIMAL)
  304. unit = *(short *) p;
  305. else
  306. unit = *(unsigned short *)p;
  307. break;
  308. case 4:
  309. unit = *(int *)p;
  310. break;
  311. }
  312. /* Print the unit. */
  313. switch (format)
  314. {
  315. case DECIMAL:
  316. printf (" %0*u", 5 * (size >> 1), unit);
  317. break;
  318. case SIGNED_DECIMAL:
  319. printf (" %*d", 1 + 5 * (size >> 1), unit);
  320. break;
  321. case OCTAL:
  322. printf (" %0*o", (size == 4) ? 11 : size * 3, unit);
  323. break;
  324. case HEX:
  325. printf (" %0*x", size * 2, unit);
  326. break;
  327. case ASCII:
  328. dump_char (unit & 0377);
  329. break;
  330. case CHARNAME:
  331. dump_charname (unit);
  332. break;
  333. default:
  334. printf (" xxx", unit);
  335. }
  336. }
  337. p += size;
  338. }
  339. }
  340. }
  341. /* Print the address of a line of output data.
  342. This is done at the beginning of each line.
  343. A space is printed after the address. */
  344. print_address (address)
  345. long address;
  346. {
  347. print_address_1 (address);
  348. putchar (' ');
  349. if (labelflag)
  350. {
  351. putchar ('(');
  352. print_address_1 (address - start_point + label);
  353. putchar (')');
  354. putchar (' ');
  355. }
  356. }
  357. print_address_1 (address)
  358. long address;
  359. {
  360. switch (address_radix)
  361. {
  362. case 8:
  363. printf ("%07o", address);
  364. break;
  365. case 10:
  366. printf ("%7d", address);
  367. break;
  368. case 16:
  369. printf ("0x%06x", address);
  370. break;
  371. default: ;
  372. }
  373. }
  374. /* Dump a single character, as a character, right-justified in four columns */
  375. dump_char (c)
  376. unsigned char c;
  377. {
  378. switch (c)
  379. {
  380. case 0:
  381. printf (" \\0");
  382. break;
  383. case '\n':
  384. printf (" \\n");
  385. break;
  386. case '\t':
  387. printf (" \\t");
  388. break;
  389. case '\r':
  390. printf (" \\r");
  391. break;
  392. case '\b':
  393. printf (" \\b");
  394. break;
  395. case '\f':
  396. printf (" \\f");
  397. break;
  398. default:
  399. if (c < 040 || c >= 0200)
  400. printf (" %03o", c);
  401. else
  402. printf (" %c", c);
  403. }
  404. }
  405. /* Print the name of character c, and indicate its parity
  406. in the way specified by `parity'. */
  407. char *charname[33] =
  408. {
  409. "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
  410. "bs", "ht", "lf", "vt", "ff", "cr", "so", "si",
  411. "dle", "dc1", "dc2", "dc3", "nak", "syn", "etb",
  412. "can", "em", "sub", "esc", "fs", "gs", "rs", "us",
  413. "sp"
  414. };
  415. dump_charname (c)
  416. char c;
  417. {
  418. char c1 = c & 127;
  419. if (c1 == 127)
  420. printf (" del");
  421. else if (c1 > 040)
  422. printf (" %c", c1);
  423. else printf ("%4s", charname[c1]);
  424. if (parity)
  425. {
  426. if ((parity == 1 && char_parity (c) == 0) ||
  427. (parity == 2 && char_parity (c) == 1))
  428. putchar ('*');
  429. else
  430. putchar (' ');
  431. }
  432. }
  433. /* Return 1 if character `c' has odd parity. */
  434. char_parity (c)
  435. char c;
  436. {
  437. return !!(c & 1) ^ !!(c & 2) ^ !!(c & 4) ^ !!(c & 8) ^
  438. !!(c & 16) ^ !!(c & 32) ^ !!(c & 64) ^ !!(c & 128);
  439. }
  440. /* STRINGS mode. Find each "string constant" in the file.
  441. A string constant is a run of at least `stringmin' ASCII graphic (or formatting) characters
  442. terminated by a null. */
  443. dump_strings (stream)
  444. FILE *stream;
  445. {
  446. int bufsize = 100;
  447. char *buf = (char *) malloc (bufsize);
  448. long address = start_point;
  449. while (1)
  450. {
  451. int i;
  452. int c;
  453. /* See if the next `stringmin' chars are all graphic chars. */
  454. tryline:
  455. if (stop_point != -1 && address >= (unsigned) stop_point)
  456. break;
  457. for (i = 0; i < stringmin; i++)
  458. {
  459. c = getc (stream);
  460. address++;
  461. if (c < 0) return;
  462. if (!graphicp (c))
  463. /* Found a non-graphic. Try again starting with next char. */
  464. goto tryline;
  465. buf [i] = c;
  466. }
  467. /* We found a run of `stringmin' graphic characters */
  468. /* Now see if it is terminated with a null byte. */
  469. while (1)
  470. {
  471. if (i == bufsize)
  472. buf = (char *) xrealloc (buf, bufsize *= 2);
  473. c = getc (stream);
  474. address++;
  475. if (c < 0) return;
  476. if (c == 0) break; /* It is; print this string */
  477. if (!graphicp (c))
  478. goto tryline; /* It isn't; give up on this string */
  479. buf[i++] = c; /* String continues; store it all. */
  480. }
  481. /* If we get here, the string is all graphics and null-terminated,
  482. so print it. It is all in `buf' and `i' is its length. */
  483. buf[i] = 0;
  484. print_address (address - i - 1);
  485. for (i = 0; c = buf[i]; i++)
  486. switch (c)
  487. {
  488. case '\n':
  489. printf ("\\n");
  490. break;
  491. case '\t':
  492. printf ("\\t");
  493. break;
  494. case '\f':
  495. printf ("\\f");
  496. break;
  497. case '\b':
  498. printf ("\\b");
  499. break;
  500. case '\r':
  501. printf ("\\r");
  502. break;
  503. default:
  504. putchar (c);
  505. }
  506. putchar ('\n');
  507. }
  508. }
  509. /* Return 1 if `c' is an ASCII graphic character */
  510. int
  511. graphicp (c)
  512. unsigned char c;
  513. {
  514. return (c >= 040 && c < 0177) ||
  515. c == '\n' || c == '\t' || c == '\b' || c == '\f' || c == '\r';
  516. }
  517. /* Print error message and exit. */
  518. fatal (s1, s2)
  519. char *s1, *s2;
  520. {
  521. error (s1, s2);
  522. exit (1);
  523. }
  524. /* Print error message. `s1' is printf control string, `s2' is arg for it. */
  525. error (s1, s2)
  526. char *s1, *s2;
  527. {
  528. printf ("od: ");
  529. printf (s1, s2);
  530. printf ("\n");
  531. }
  532. pfatal_with_name (name)
  533. char *name;
  534. {
  535. extern int errno, sys_nerr;
  536. extern char *sys_errlist[];
  537. char *s;
  538. if (errno < sys_nerr)
  539. s = concat ("", sys_errlist[errno], " for %s");
  540. else
  541. s = "cannot open %s";
  542. fatal (s, name);
  543. }
  544. /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
  545. char *
  546. concat (s1, s2, s3)
  547. char *s1, *s2, *s3;
  548. {
  549. int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  550. char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
  551. strcpy (result, s1);
  552. strcpy (result + len1, s2);
  553. strcpy (result + len1 + len2, s3);
  554. *(result + len1 + len2 + len3) = 0;
  555. return result;
  556. }
  557. /* Like malloc but get fatal error if memory is exhausted. */
  558. int
  559. xmalloc (size)
  560. int size;
  561. {
  562. int result = malloc (size);
  563. if (!result)
  564. fatal ("virtual memory exhausted", 0);
  565. return result;
  566. }
  567. int
  568. xrealloc (ptr, size)
  569. char *ptr;
  570. int size;
  571. {
  572. int result = realloc (ptr, size);
  573. if (!result)
  574. fatal ("virtual memory exhausted");
  575. return result;
  576. }
  577. /* Parse string `s' as an integer, using decimal radix by default,
  578. but allowing octal and hex numbers as in C. */
  579. long
  580. integer_arg (s)
  581. char *s;
  582. {
  583. long value;
  584. int radix = 10;
  585. char *p = s;
  586. int c;
  587. if (*p != '0')
  588. radix = 10;
  589. else if (*++p == 'x')
  590. {
  591. radix = 16;
  592. p++;
  593. }
  594. else
  595. radix = 8;
  596. value = 0;
  597. while (((c = *p++) >= '0' && c <= '9')
  598. || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
  599. {
  600. value *= radix;
  601. if (c >= '0' && c <= '9')
  602. value += c - '0';
  603. else
  604. value += (c & ~40) - 'A';
  605. }
  606. if (c == 'b')
  607. value *= 512;
  608. else if (c == 'B')
  609. value *= 1024;
  610. else
  611. p--;
  612. if (*p)
  613. fatal ("invalid integer argument %s", s);
  614. return value;
  615. }
  616. /* Parse an integer in decimal off string `*p' points to,
  617. and update *p to point at the terminating character.
  618. The integer is returned as the value. */
  619. parse_int (p)
  620. char **p;
  621. {
  622. int val = atoi (*p);
  623. while (**p >= '0' && **p <= '9') (*p)++;
  624. return val;
  625. }