Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1412 lines
48 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. hd.c
  5. Abstract:
  6. This module contains the functions that implement the hd program.
  7. This program displays the contents of files in decimal, hexadecimal
  8. and character formats. The contents of the files are displayed in
  9. records of 16 bytes each. Associated to each record, there is an
  10. address that represents the offset of the first byte in the
  11. record relative to the begining of the file. Each record can also be
  12. displayed as printable ASCII characters.
  13. hd can be called with the following arguments:
  14. -ad: displays the address of each record in decimal;
  15. -ax: displays the address of each record in hex;
  16. -ch: displays bytes as ASCII characters;
  17. -cC: displays bytes as ASCII C characters (\n, \t, etc);
  18. -ce: displays bytes as ASCII codes (EOT, CR, SOH, etc);
  19. -cr: displays bytes as ASCII control characters (^A, ^N, etc);
  20. -bd: interprets data in each record as byte, and displays
  21. each byte as a decimal number;
  22. -bx: interprets data in each record as byte, and displays
  23. each byte as an hex number;
  24. -wd: interprets data in each record as word, and displays
  25. each word as a decimal number;
  26. -wx: interprets data in each record as word, and displays
  27. each word as an hex number;
  28. -ld: interprets data in each record as double words, and displays
  29. each double word as a decimal number;
  30. -wx: interprets data in each record as a double word, and displays
  31. each double word as an hex number;
  32. -A: Displays data in each record also as printable ASCII
  33. characters at the end of each line.
  34. -s <offset>: defines the offset of the first byte to be displayed;
  35. -n <bumber>: defines the number of bytes to be displayed;
  36. -i does not print redundant lines;
  37. -?, -h or -H: displays a help message.
  38. If no argument is defined, hd assumes as default: -ax -A -bx
  39. Authors:
  40. Jaime F. Sasson (jaimes) 12-Nov-1990
  41. David J. Gilman (davegi) 12-Nov-1990
  42. Environment:
  43. C run time library
  44. Revision History:
  45. --*/
  46. #include <stdio.h>
  47. #include <assert.h>
  48. #include <ctype.h>
  49. #include <conio.h>
  50. #include <string.h>
  51. #include <stdlib.h>
  52. #include "hd.h"
  53. #define FALSE 0
  54. /*************************************************************************
  55. *
  56. * G L O B A L V A R I A B L E S
  57. *
  58. *************************************************************************/
  59. unsigned long Offset = 0; // -s option
  60. unsigned Count = 0; // -n option
  61. BASE AddrFormat; // -a option
  62. FORMAT DispFormat; // -c, -b, -w or -l options
  63. YESNO DumpAscii; // -A option
  64. int IgnoreRedundantLines; // -i option
  65. unsigned char auchBuffer[BUFFER_SIZE]; // Buffer that contains data read
  66. // from the file being displayed
  67. unsigned long cbBytesInBuffer; // Total number of bytes in the
  68. // buffer
  69. unsigned char* puchPointer; // Points to the next character in
  70. // the buffer to be read
  71. unsigned long cStringSize; // Size of a string pointed by a
  72. // pointer in the ASCII table used
  73. // for the translation (asciiChar,
  74. // asciiC, asciiCode or asciiCtrl)
  75. // The contents of this variable is
  76. // meaningful only if -ch, -cC, -ce
  77. // or -cr was specified.
  78. // It is meaningless in all other
  79. // cases (no ascii translation is
  80. // being performed, and the ascii
  81. // tables are not needed)
  82. /*************************************************************************
  83. *
  84. * A S C I I C O N V E R S I O N T A B L E S
  85. *
  86. *************************************************************************/
  87. char* asciiChar[ ] = {
  88. " ", " ", " ", " ", " ", " ", " ", " ",
  89. " ", " ", " ", " ", " ", " ", " ", " ",
  90. " ", " ", " ", " ", " ", " ", " ", " ",
  91. " ", " ", " ", " ", " ", " ", " ", " ",
  92. " ", "! ", "\" ", "# ", "$ ", "% ", "& ", "' ",
  93. "( ", ") ", "* ", "+ ", "' ", "- ", ". ", "/ ",
  94. "0 ", "1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ",
  95. "8 ", "9 ", ": ", "; ", "< ", "= ", "> ", "? ",
  96. "@ ", "A ", "B ", "C ", "D ", "E ", "F ", "G ",
  97. "H ", "I ", "J ", "K ", "L ", "M ", "N ", "O ",
  98. "P ", "Q ", "R ", "S ", "T ", "U ", "V ", "W ",
  99. "X ", "Y ", "Z ", "[ ", "\\ ", "] ", "^ ", "_ ",
  100. "` ", "a ", "b ", "c ", "d ", "e ", "f ", "g ",
  101. "h ", "i ", "j ", "k ", "l ", "m ", "n ", "o ",
  102. "p ", "q ", "r ", "s ", "t ", "u ", "v ", "w ",
  103. "x ", "y ", "z ", "{ ", "| ", "} ", "~ ", "_ ",
  104. "", "", "", "", "", "", "", "",
  105. "", "", "", "", "", "", "", "",
  106. "", "", "", "", "", "", "", "",
  107. "", "", "", "", "", "", "", "",
  108. "", "", "", "", "", "", "", "",
  109. "", "", "", "", "", "", "", "",
  110. "", "", "", "", "", "", "", "",
  111. "", "", "", "", "", "", "", "",
  112. "", "", "", "", "", "", "", "",
  113. "", "", "", "", "", "", "", "",
  114. "", "", "", "", "", "", "", "",
  115. "", "", "", "", "", "", "", "",
  116. "", "", "", "", "", "", "", "",
  117. "", "", "", "", "", "", "", "",
  118. "", "", "", "", "", "", "", "",
  119. "", "", "", "", "", "", "", " "
  120. };
  121. char* asciiC[ ] = {
  122. " ", " ", " ", " ", " ", " ", " ", "\\a ",
  123. "\\b ", "\\t ", "\\n ", "\\v ", "\\f ", " ", " ", " ",
  124. " ", " ", " ", " ", " ", " ", " ", " ",
  125. " ", " ", " ", " ", " ", " ", " ", " ",
  126. " ", "! ", "\\\" ", "# ", "$ ", "% ", "& ", "\' ",
  127. "( ", ") ", "* ", "+ ", "' ", "- ", ". ", "/ ",
  128. "0 ", "1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ",
  129. "8 ", "9 ", ": ", "; ", "< ", "= ", "> ", "? ",
  130. "@ ", "A ", "B ", "C ", "D ", "E ", "F ", "G ",
  131. "H ", "I ", "J ", "K ", "L ", "M ", "N ", "O ",
  132. "P ", "Q ", "R ", "S ", "T ", "U ", "V ", "W ",
  133. "X ", "Y ", "Z ", "[ ", "\\\\ ", "] ", "^ ", "_ ",
  134. "` ", "a ", "b ", "c ", "d ", "e ", "f ", "g ",
  135. "h ", "i ", "j ", "k ", "l ", "m ", "n ", "o ",
  136. "p ", "q ", "r ", "s ", "t ", "u ", "v ", "w ",
  137. "x ", "y ", "z ", "{ ", "| ", "} ", "~ ", "_ ",
  138. "", "", "", "", "", "", "", "",
  139. "", "", "", "", "", "", "", "",
  140. "", "", "", "", "", "", "", "",
  141. "", "", "", "", "", "", "", "",
  142. "", "", "", "", "", "", "", "",
  143. "", "", "", "", "", "", "", "",
  144. "", "", "", "", "", "", "", "",
  145. "", "", "", "", "", "", "", "",
  146. "", "", "", "", "", "", "", "",
  147. "", "", "", "", "", "", "", "",
  148. "", "", "", "", "", "", "", "",
  149. "", "", "", "", "", "", "", "",
  150. "", "", "", "", "", "", "", "",
  151. "", "", "", "", "", "", "", "",
  152. "", "", "", "", "", "", "", "",
  153. "", "", "", "", "", "", "", " "
  154. };
  155. char* asciiCode[ ] = {
  156. "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
  157. "BS ", "HT ", "LF ", "VT ", "FF ", "CR ", "SO ", "SI ",
  158. "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
  159. "CAN", "EM ", "SUB", "ESC", "FS ", "GS ", "RS ", "US ",
  160. " ", "! ", "\" ", "# ", "$ ", "% ", "& ", "' ",
  161. "( ", ") ", "* ", "+ ", "' ", "- ", ". ", "/ ",
  162. "0 ", "1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ",
  163. "8 ", "9 ", ": ", "; ", "< ", "= ", "> ", "? ",
  164. "@ ", "A ", "B ", "C ", "D ", "E ", "F ", "G ",
  165. "H ", "I ", "J ", "K ", "L ", "M ", "N ", "O ",
  166. "P ", "Q ", "R ", "S ", "T ", "U ", "V ", "W ",
  167. "X ", "Y ", "Z ", "[ ", "\\ ", "] ", "^ ", "_ ",
  168. "` ", "a ", "b ", "c ", "d ", "e ", "f ", "g ",
  169. "h ", "i ", "j ", "k ", "l ", "m ", "n ", "o ",
  170. "p ", "q ", "r ", "s ", "t ", "u ", "v ", "w ",
  171. "x ", "y ", "z ", "{ ", "| ", "} ", "~ ", "_ ",
  172. "", "", "", "", "", "", "", "",
  173. "", "", "", "", "", "", "", "",
  174. "", "", "", "", "", "", "", "",
  175. "", "", "", "", "", "", "", "",
  176. "", "", "", "", "", "", "", "",
  177. "", "", "", "", "", "", "", "",
  178. "", "", "", "", "", "", "", "",
  179. "", "", "", "", "", "", "", "",
  180. "", "", "", "", "", "", "", "",
  181. "", "", "", "", "", "", "", "",
  182. "", "", "", "", "", "", "", "",
  183. "", "", "", "", "", "", "", "",
  184. "", "", "", "", "", "", "", "",
  185. "", "", "", "", "", "", "", "",
  186. "", "", "", "", "", "", "", "",
  187. "", "", "", "", "", "", "", " "
  188. };
  189. char* asciiCtrl[ ] = {
  190. "^@ ", "^A ", "^B ", "^C ", "^D ", "^E ", "^F ", "^G ",
  191. "^H ", "^I ", "^J ", "^K ", "^L ", "^M ", "^N ", "^O ",
  192. "^P ", "^Q ", "^R ", "^S ", "^T ", "^U ", "^V ", "^W ",
  193. "^X ", "^Y ", "^Z ", "^[ ", "^\\ ", "^] ", "^^ ", "^_ ",
  194. " ", "! ", "\" ", "# ", "$ ", "% ", "& ", "' ",
  195. "( ", ") ", "* ", "+ ", "' ", "- ", ". ", "/ ",
  196. "0 ", "1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ",
  197. "8 ", "9 ", ": ", "; ", "< ", "= ", "> ", "? ",
  198. "@ ", "A ", "B ", "C ", "D ", "E ", "F ", "G ",
  199. "H ", "I ", "J ", "K ", "L ", "M ", "N ", "O ",
  200. "P ", "Q ", "R ", "S ", "T ", "U ", "V ", "W ",
  201. "X ", "Y ", "Z ", "[ ", "\\ ", "] ", "^ ", "_ ",
  202. "` ", "a ", "b ", "c ", "d ", "e ", "f ", "g ",
  203. "h ", "i ", "j ", "k ", "l ", "m ", "n ", "o ",
  204. "p ", "q ", "r ", "s ", "t ", "u ", "v ", "w ",
  205. "x ", "y ", "z ", "{ ", "| ", "} ", "~ ", "_ ",
  206. "", "", "", "", "", "", "", "",
  207. "", "", "", "", "", "", "", "",
  208. "", "", "", "", "", "", "", "",
  209. "", "", "", "", "", "", "", "",
  210. "", "", "", "", "", "", "", "",
  211. "", "", "", "", "", "", "", "",
  212. "", "", "", "", "", "", "", "",
  213. "", "", "", "", "", "", "", "",
  214. "", "", "", "", "", "", "", "",
  215. "", "", "", "", "", "", "", "",
  216. "", "", "", "", "", "", "", "",
  217. "", "", "", "", "", "", "", "",
  218. "", "", "", "", "", "", "", "",
  219. "", "", "", "", "", "", "", "",
  220. "", "", "", "", "", "", "", "",
  221. "", "", "", "", "", "", "", " "
  222. };
  223. void
  224. ConvertASCII (
  225. char line[],
  226. unsigned char buf[],
  227. unsigned long cb,
  228. char* pTable[]
  229. )
  230. /*++
  231. Routine Description:
  232. This routine converts the bytes received in a buffer
  233. into an ASCII representation (Char, C, Code or CTRL).
  234. Arguments:
  235. line - Buffer that will receive the converted characters.
  236. buf - A buffer that contains the data to be converted.
  237. cb - Number of bytes in the buffer
  238. pTable - Pointer to the table to be used in the conversion
  239. Return Value:
  240. None
  241. --*/
  242. {
  243. unsigned long ulIndex;
  244. sprintf( line,
  245. MSG_DATA_ASCII_FMT,
  246. pTable[ buf[ 0 ]], pTable[ buf[ 1 ]],
  247. pTable[ buf[ 2 ]], pTable[ buf[ 3 ]],
  248. pTable[ buf[ 4 ]], pTable[ buf[ 5 ]],
  249. pTable[ buf[ 6 ]], pTable[ buf[ 7 ]],
  250. pTable[ buf[ 8 ]], pTable[ buf[ 9 ]],
  251. pTable[ buf[ 10 ]], pTable[ buf[ 11 ]],
  252. pTable[ buf[ 12 ]], pTable[ buf[ 13 ]],
  253. pTable[ buf[ 14 ]], pTable[ buf[ 15 ]]);
  254. //
  255. // If the number of bytes in the buffer is less than the maximum size
  256. // of the record, then delete the characters that were converted
  257. // but are not to be displayed.
  258. //
  259. if (cb < RECORD_SIZE) {
  260. //
  261. // -1: to eliminate the \0
  262. // +1: to count the SPACE character between two strings
  263. //
  264. ulIndex = (sizeof( MSG_ADDR_FIELD ) - 1 ) + cb*(cStringSize + 1);
  265. while ( line[ ulIndex ] != NUL ) {
  266. line[ ulIndex ] = SPACE;
  267. ulIndex++;
  268. }
  269. }
  270. }
  271. void
  272. ConvertBYTE (
  273. char line[],
  274. unsigned char buf[],
  275. unsigned long cb,
  276. unsigned long ulBase
  277. )
  278. /*++
  279. Routine Description:
  280. This routine converts each byte received in a buffer
  281. into a number. The base used in the conversion is received as
  282. parameter.
  283. Arguments:
  284. line - Buffer that will receive the converted characters.
  285. buf - A buffer that contains the data to be converted.
  286. cb - Number of bytes in the buffer
  287. ulBase - Defines the base to be used in the conversion
  288. Return Value:
  289. None
  290. --*/
  291. {
  292. unsigned long ulIndex;
  293. char* pchMsg;
  294. unsigned long ulNumberOfDigits;
  295. switch( ulBase ) {
  296. case DEC:
  297. ulNumberOfDigits = 3; // needs 3 decimal digits to
  298. // represent a byte
  299. pchMsg = MSG_DATA_BYTE_DEC_FMT; // message that contains the format
  300. break;
  301. case HEX:
  302. ulNumberOfDigits = 2; // needs 2 hexdigits to
  303. // represent a byte
  304. pchMsg = MSG_DATA_BYTE_HEX_FMT; // message that contains the format
  305. break;
  306. default:
  307. printf( "Unknown base\n" );
  308. assert( FALSE );
  309. break;
  310. }
  311. sprintf( line,
  312. pchMsg,
  313. buf[ 0 ], buf[ 1 ],
  314. buf[ 2 ], buf[ 3 ],
  315. buf[ 4 ], buf[ 5 ],
  316. buf[ 6 ], buf[ 7 ],
  317. buf[ 8 ], buf[ 9 ],
  318. buf[ 10 ], buf[ 11 ],
  319. buf[ 12 ], buf[ 13 ],
  320. buf[ 14 ], buf[ 15 ]);
  321. //
  322. // If this is the last record to be displayed, then delete the
  323. // characters that were translated but are not to be displayed.
  324. //
  325. if (cb < RECORD_SIZE) {
  326. ulIndex = (sizeof( MSG_ADDR_FIELD ) - 1 ) +
  327. cb*(ulNumberOfDigits + 1 );
  328. while ( line[ ulIndex ] != NUL ) {
  329. line[ ulIndex ] = SPACE;
  330. ulIndex++;
  331. }
  332. }
  333. }
  334. void
  335. ConvertWORD (
  336. char line[],
  337. unsigned char buf[],
  338. unsigned long cb,
  339. unsigned long ulBase
  340. )
  341. /*++
  342. Routine Description:
  343. This routine converts the data received in a buffer
  344. into numbers. The data in the buffer are interpreted as words.
  345. If the buffer contains an odd number of bytes, then the last byte
  346. is converted as a byte, not as word.
  347. The base used in the conversion is received as parameter.
  348. Arguments:
  349. line - Buffer that will receive the converted characters.
  350. buf - A buffer that contains the data to be converted.
  351. cb - Number of bytes in the buffer
  352. ulBase - Defines the base to be used in the conversion
  353. Return Value:
  354. None
  355. --*/
  356. {
  357. unsigned long ulIndex;
  358. char* pchMsg;
  359. char* pchMsgHalf;
  360. unsigned long ulNumberOfDigits;
  361. switch( ulBase ) {
  362. case DEC:
  363. ulNumberOfDigits = 5; // needs 5 decimal digits to
  364. // represent a word
  365. pchMsg = MSG_DATA_WORD_DEC_FMT; // message with the string
  366. // format
  367. pchMsgHalf = MSG_SINGLE_BYTE_DEC_FMT; // message with the format of
  368. break; // half a word in decimal
  369. case HEX:
  370. ulNumberOfDigits = 4; // needs 4 hex digits to
  371. // represent a word
  372. pchMsg = MSG_DATA_WORD_HEX_FMT; // message the string format
  373. pchMsgHalf = MSG_SINGLE_BYTE_HEX_FMT; // message with the format of
  374. // half a word in hex
  375. break;
  376. default:
  377. printf( "Unknown base\n" );
  378. assert( FALSE );
  379. break;
  380. }
  381. sprintf( line,
  382. pchMsg,
  383. (( unsigned short* ) ( buf )) [ 0 ],
  384. (( unsigned short* ) ( buf )) [ 1 ],
  385. (( unsigned short* ) ( buf )) [ 2 ],
  386. (( unsigned short* ) ( buf )) [ 3 ],
  387. (( unsigned short* ) ( buf )) [ 4 ],
  388. (( unsigned short* ) ( buf )) [ 5 ],
  389. (( unsigned short* ) ( buf )) [ 6 ],
  390. (( unsigned short* ) ( buf )) [ 7 ]);
  391. //
  392. // If this record contains less bytes than the maximum record size,
  393. // then it is the last record to be displayed. In this case we have
  394. // to verify if the record contains an even number of bytes. If it
  395. // doesn't, then the last byte must be interpreted as a byte and not
  396. // as a word.
  397. // Also, the characters that were converted but are not to be displayed,
  398. // have to be deleted.
  399. //
  400. if (cb < RECORD_SIZE) {
  401. ulIndex = (sizeof( MSG_ADDR_FIELD ) - 1 ) +
  402. (cb/2)*(ulNumberOfDigits + 1 );
  403. if (cb%2 != 0) {
  404. ulIndex += sprintf( line + ulIndex,
  405. pchMsgHalf,
  406. buf[ cb-1 ]);
  407. line[ ulIndex ] = SPACE;
  408. }
  409. //
  410. // Delete characters that are not to be displayed
  411. //
  412. while ( line[ ulIndex ] != NUL ) {
  413. line[ ulIndex ] = SPACE;
  414. ulIndex++;
  415. }
  416. }
  417. }
  418. void
  419. ConvertDWORD (
  420. char line[],
  421. unsigned char buf[],
  422. unsigned long cb,
  423. unsigned long ulBase
  424. )
  425. /*++
  426. Routine Description:
  427. This routine converts the data received in a buffer
  428. into numbers. The data in the buffer is interpreted as double words.
  429. If the buffer contains less bytes than the maximum size of the record,
  430. then it is the last record, and we may need to convert again the last
  431. 3 bytes in the buffer.
  432. If the number of bytes in the buffer is not multiple of 4, then the
  433. last bytes in the buffer are converted as a byte, word, or word and
  434. byte, as appropriate.
  435. The characters that were converted but are not to be displayed have to
  436. be removed from the buffer.
  437. The base used in the conversion is received as parameter.
  438. Arguments:
  439. line - Buffer that will receive the converted characters.
  440. buf - A buffer that contains the data to be converted.
  441. cb - Number of bytes in the buffer
  442. ulBase - Defines the base to be used in the conversion
  443. Return Value:
  444. None
  445. --*/
  446. {
  447. unsigned long ulIndex;
  448. char* pchMsg;
  449. char* pchMsgByte;
  450. char* pchMsgWord;
  451. char* pchMsgWordByte;
  452. unsigned long ulNumberOfDigits;
  453. switch( ulBase ) {
  454. case DEC:
  455. ulNumberOfDigits = 10; // needs 10 decimal digits to
  456. // represent a dword
  457. pchMsg = MSG_DATA_DWORD_DEC_FMT; // message with the string
  458. // format
  459. pchMsgByte = MSG_SINGLE_BYTE_DEC_FMT; // message with the format
  460. // of a single byte in
  461. // decimal
  462. pchMsgWord = MSG_SINGLE_WORD_DEC_FMT; // message that contains
  463. // the format of a single
  464. // word in decimal
  465. pchMsgWordByte = MSG_WORD_BYTE_DEC_FMT;
  466. break;
  467. case HEX:
  468. ulNumberOfDigits = 8; // needs 8 hex digits to
  469. // represent a dword
  470. pchMsg = MSG_DATA_DWORD_HEX_FMT; // message the string format
  471. pchMsgByte = MSG_SINGLE_BYTE_HEX_FMT; // message with the format
  472. // of a single byte in hex
  473. pchMsgWord = MSG_SINGLE_WORD_HEX_FMT; // message with the format
  474. // of a single word in hex
  475. pchMsgWordByte = MSG_WORD_BYTE_HEX_FMT;
  476. break;
  477. default:
  478. printf( "Unknown base\n" );
  479. assert( FALSE );
  480. break;
  481. }
  482. sprintf( line,
  483. pchMsg,
  484. (( unsigned long* ) ( buf )) [ 0 ],
  485. (( unsigned long* ) ( buf )) [ 1 ],
  486. (( unsigned long* ) ( buf )) [ 2 ],
  487. (( unsigned long* ) ( buf )) [ 3 ]);
  488. //
  489. // If the buffer contains less bytes than the maximum record size,
  490. // the it is the last buffer to be displayed. In this case, check if
  491. // if the buffer contains a number o bytes that is multiple of 4.
  492. // If it doesn't, then converts the last bytes as a byte, a word, or
  493. // a word and a byte, as appropriate.
  494. //
  495. if (cb < RECORD_SIZE) {
  496. ulIndex = (sizeof( MSG_ADDR_FIELD ) - 1 ) +
  497. (cb/4)*(ulNumberOfDigits + 1 );
  498. switch( cb%4 ) {
  499. case 1:
  500. ulIndex += sprintf( line + ulIndex,
  501. pchMsgByte,
  502. buf[ cb-1 ]);
  503. line[ ulIndex ] = SPACE;
  504. break;
  505. case 2:
  506. ulIndex += sprintf( line + ulIndex,
  507. pchMsg,
  508. (( unsigned short* ) ( buf )) [ (cb/2) - 1 ]);
  509. line[ ulIndex ] = SPACE;
  510. break;
  511. case 3:
  512. ulIndex += sprintf( line + ulIndex,
  513. pchMsgWordByte,
  514. (( unsigned short* ) ( buf )) [ (cb/2) - 1],
  515. buf[ cb-1 ]);
  516. line[ ulIndex ] = SPACE;
  517. break;
  518. default: // buf contains multiple of 4 bytes
  519. break;
  520. }
  521. //
  522. // Delete the charecters that were converted but are not to be
  523. // displayed.
  524. //
  525. while ( line[ ulIndex ] != NUL) {
  526. line[ ulIndex ] = SPACE;
  527. ulIndex++;
  528. }
  529. }
  530. }
  531. void
  532. ConvertPRINT (
  533. char line[],
  534. unsigned char buf[],
  535. unsigned long cb
  536. )
  537. /*++
  538. Routine Description:
  539. This routine converts each byte received in a buffer into a
  540. printable character.
  541. Arguments:
  542. line - Buffer that will receive the converted characters.
  543. buf - A buffer that contains the data to be converted.
  544. cb - Number of bytes in the buffer
  545. Return Value:
  546. None
  547. --*/
  548. {
  549. sprintf( line,
  550. MSG_PRINT_CHAR_FMT,
  551. isprint( buf[ 0 ] ) ? buf[ 0 ] : DOT,
  552. isprint( buf[ 1 ] ) ? buf[ 1 ] : DOT,
  553. isprint( buf[ 2 ] ) ? buf[ 2 ] : DOT,
  554. isprint( buf[ 3 ] ) ? buf[ 3 ] : DOT,
  555. isprint( buf[ 4 ] ) ? buf[ 4 ] : DOT,
  556. isprint( buf[ 5 ] ) ? buf[ 5 ] : DOT,
  557. isprint( buf[ 6 ] ) ? buf[ 6 ] : DOT,
  558. isprint( buf[ 7 ] ) ? buf[ 7 ] : DOT,
  559. isprint( buf[ 8 ] ) ? buf[ 8 ] : DOT,
  560. isprint( buf[ 9 ] ) ? buf[ 9 ] : DOT,
  561. isprint( buf[ 10 ] ) ? buf[ 10 ] : DOT,
  562. isprint( buf[ 11 ] ) ? buf[ 11 ] : DOT,
  563. isprint( buf[ 12 ] ) ? buf[ 12 ] : DOT,
  564. isprint( buf[ 13 ] ) ? buf[ 13 ] : DOT,
  565. isprint( buf[ 14 ] ) ? buf[ 14 ] : DOT,
  566. isprint( buf[ 15 ] ) ? buf[ 15 ] : DOT);
  567. //
  568. // If the buffer contains less characters than the maximum record size,
  569. // then delete the characters that were converted but are not to be
  570. // displayed
  571. //
  572. if (cb < RECORD_SIZE) {
  573. while ( line[ cb ] != NUL ) {
  574. line[ cb ] = SPACE;
  575. cb++;
  576. }
  577. }
  578. }
  579. void
  580. Translate (
  581. FORMAT fmt,
  582. unsigned char buf[ ],
  583. unsigned long cb,
  584. char line[ ]
  585. )
  586. /*++
  587. Routine Description:
  588. This function converts the bytes received in a buffer
  589. into a printable representation, that corresponds to one
  590. of the formats specified by the parameter fmt.
  591. Arguments:
  592. fmt - The format to be used in the conversion
  593. buf - A buffer that contains the data to be converted.
  594. cb - Number of bytes in the buffer
  595. line - Buffer that will receive the converted characters.
  596. Return Value:
  597. None
  598. --*/
  599. {
  600. assert( buf );
  601. assert( line );
  602. switch( fmt ) {
  603. case ASCII_CHAR:
  604. ConvertASCII( line, buf, cb, asciiChar );
  605. break;
  606. case ASCII_C:
  607. ConvertASCII( line, buf, cb, asciiC );
  608. break;
  609. case ASCII_CODE:
  610. ConvertASCII( line, buf, cb, asciiCode );
  611. break;
  612. case ASCII_CTRL:
  613. ConvertASCII( line, buf, cb, asciiCtrl );
  614. break;
  615. case BYTE_DEC:
  616. ConvertBYTE( line, buf, cb, DEC );
  617. break;
  618. case BYTE_HEX:
  619. ConvertBYTE( line, buf, cb, HEX );
  620. break;
  621. case WORD_DEC:
  622. ConvertWORD( line, buf, cb, DEC );
  623. break;
  624. case WORD_HEX:
  625. ConvertWORD( line, buf, cb, HEX );
  626. break;
  627. case DWORD_DEC:
  628. ConvertDWORD( line, buf, cb, DEC );
  629. break;
  630. case DWORD_HEX:
  631. ConvertDWORD( line, buf, cb, HEX );
  632. break;
  633. case PRINT_CHAR:
  634. ConvertPRINT( line, buf, cb );
  635. break;
  636. default:
  637. printf( "Bad Format\n" );
  638. assert( FALSE );
  639. break;
  640. }
  641. }
  642. void
  643. PutAddress (
  644. char line[],
  645. unsigned long ulAddress,
  646. BASE Base
  647. )
  648. /*++
  649. Routine Description:
  650. This routine adds to the buffer received the offset of the first
  651. byte (or character) already in the buffer. This offset represents
  652. the position of the byte in the file, relatively to the begining
  653. of the file.
  654. Arguments:
  655. Base - The base to be used to represent the offset.
  656. line - Buffer containing the converted characters to be displayed in
  657. the screen
  658. ulAddress - Offset to be added to the begining of the buffer
  659. Return Value:
  660. None
  661. --*/
  662. {
  663. unsigned long ulIndex;
  664. assert( line);
  665. switch( Base ) {
  666. case DEC:
  667. ulIndex = sprintf( line,
  668. MSG_ADDR_DEC_FMT,
  669. ulAddress );
  670. break;
  671. case HEX:
  672. ulIndex = sprintf( line,
  673. MSG_ADDR_HEX_FMT,
  674. ulAddress);
  675. break;
  676. default:
  677. printf( "Bad Address Base\n" );
  678. assert( FALSE );
  679. break;
  680. }
  681. line[ ulIndex ] = SPACE; // Get rid of the NUL added by sprintf
  682. }
  683. void
  684. PutTable (
  685. char line[],
  686. unsigned char buf[],
  687. unsigned long cb
  688. )
  689. /*++
  690. Routine Description:
  691. This routine adds to the end of the buffer received, the ASCII
  692. representation of all printable characters already in the buffer.
  693. Characters that are not printable (smaller than 0x20 or greater than
  694. 0x7f) are displayed as a dot.
  695. Arguments:
  696. line - Buffer containing the characters to be displayed in one line
  697. of the screen
  698. buf - The buffer that contains a record of bytes (maximum of 16)
  699. read from the file being displayed.
  700. ulAddress - Number of bytes in buf.
  701. Return Value:
  702. None
  703. --*/
  704. {
  705. unsigned long ulIndex;
  706. assert( line );
  707. assert( buf );
  708. ulIndex = strlen (line);
  709. Translate( PRINT_CHAR, buf, cb, (line + ulIndex));
  710. }
  711. void
  712. InterpretArgument (
  713. char* pchPointer
  714. )
  715. /*++
  716. Routine Description:
  717. This routine interprets an argument typed by the user (exept -n
  718. and -s) and initializes some variables accordingly.
  719. Arguments:
  720. pchPointer - Pointer to the argument to be interpreted.
  721. Return Value:
  722. None
  723. --*/
  724. {
  725. //
  726. // pchPointer will point to the character that follows '-'
  727. //
  728. pchPointer++;
  729. if( strcmp( pchPointer, "ax" ) == 0 ) {
  730. AddrFormat = HEX;
  731. }
  732. else if( strcmp( pchPointer, "ad" ) == 0 ) {
  733. AddrFormat = DEC;
  734. }
  735. else if( strcmp( pchPointer, "ch" ) == 0 ) {
  736. DispFormat = ASCII_CHAR;
  737. cStringSize = strlen( asciiChar[0] );
  738. DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
  739. }
  740. else if( strcmp( pchPointer, "cC" ) == 0 ) {
  741. DispFormat = ASCII_C;
  742. cStringSize = strlen( asciiC[0] );
  743. DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
  744. }
  745. else if( strcmp( pchPointer, "ce" ) == 0 ) {
  746. DispFormat = ASCII_CODE;
  747. cStringSize = strlen( asciiCode[0] );
  748. DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
  749. }
  750. else if( strcmp( pchPointer, "cr" ) == 0 ) {
  751. DispFormat = ASCII_CTRL;
  752. cStringSize = strlen( asciiCtrl[0] );
  753. DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
  754. }
  755. else if( strcmp( pchPointer, "bd" ) == 0 ) {
  756. DispFormat = BYTE_DEC;
  757. DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
  758. }
  759. else if( strcmp( pchPointer, "bx" ) == 0 ) {
  760. DispFormat = BYTE_HEX;
  761. DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
  762. }
  763. else if( strcmp( pchPointer, "wd" ) == 0 ) {
  764. DispFormat = WORD_DEC;
  765. DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
  766. }
  767. else if( strcmp( pchPointer, "wx" ) == 0 ) {
  768. DispFormat = WORD_HEX;
  769. DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
  770. }
  771. else if( strcmp( pchPointer, "ld" ) == 0 ) {
  772. DispFormat = DWORD_DEC;
  773. DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
  774. }
  775. else if( strcmp( pchPointer, "lx" ) == 0 ) {
  776. DispFormat = DWORD_HEX;
  777. DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
  778. }
  779. else if( strcmp( pchPointer, "A" ) == 0 ) {
  780. DumpAscii = YES;
  781. }
  782. else if( strcmp( pchPointer, "i" ) == 0 ) {
  783. IgnoreRedundantLines = 1;
  784. }
  785. else if( strcmp( pchPointer, "?" ) || strcmp( pchPointer, "h" ) ||
  786. strcmp( pchPointer, "H" ) ) {
  787. puts( HELP_MESSAGE );
  788. exit( 0 );
  789. }
  790. else {
  791. fprintf( stderr, "hd: error: invalid argument '%s'\n", --pchPointer );
  792. exit( - 1 );
  793. }
  794. }
  795. unsigned long
  796. GetRecord (
  797. unsigned char* puchRecord,
  798. FILE* pf
  799. )
  800. /*++
  801. Routine Description:
  802. This routine fills the buffer whose pointer was received as parameter,
  803. with characters read from the file being displayed. Blocks of data
  804. are initially read from the file being displayed, and kept in a buffer.
  805. A record is filled with characters obtained from this buffer.
  806. Whenever this buffer gets empty, a new access to file is performed
  807. in order to fill this buffer.
  808. Arguments:
  809. puchRecord - Pointer to the record to be filled
  810. pf - Pointer to the file that is being displayed
  811. Return Value:
  812. Total number of characters put in the record.
  813. --*/
  814. {
  815. unsigned long cbBytesCopied;
  816. //
  817. // If the buffer contains enogh characters to fill the record, then
  818. // copy the appropriate number of bytes.
  819. //
  820. if( cbBytesInBuffer >= RECORD_SIZE ) {
  821. for( cbBytesCopied = 0; cbBytesCopied < RECORD_SIZE; cbBytesCopied++ ) {
  822. *puchRecord++ = *puchPointer++;
  823. cbBytesInBuffer--;
  824. }
  825. }
  826. //
  827. // else, the buffer does not contain enough characters to fill the record
  828. //
  829. else {
  830. //
  831. // Copy to the remaining characters in the buffer to the record
  832. //
  833. for( cbBytesCopied = 0; cbBytesInBuffer > 0; cbBytesInBuffer-- ) {
  834. *puchRecord++ = *puchPointer++;
  835. cbBytesCopied++;
  836. }
  837. //
  838. // Read more data from the file and fill the record
  839. //
  840. if( !feof( pf ) ) {
  841. cbBytesInBuffer = fread( auchBuffer,
  842. sizeof( char ),
  843. BUFFER_SIZE,
  844. pf );
  845. puchPointer = auchBuffer;
  846. while( ( cbBytesInBuffer != 0 ) && (cbBytesCopied < RECORD_SIZE) ) {
  847. *puchRecord++ = *puchPointer++;
  848. cbBytesInBuffer--;
  849. cbBytesCopied++;
  850. }
  851. }
  852. }
  853. return( cbBytesCopied );
  854. }
  855. int
  856. hd(
  857. FILE * pf
  858. )
  859. /*++ hd
  860. *
  861. * Routine Description:
  862. * takes the file/stream pointed to by pf and `hd's it to stdout.
  863. *
  864. * Arguments:
  865. * FILE * pf -
  866. *
  867. * Return Value:
  868. * int - to be determined, always zero for now
  869. * Warnings:
  870. --*/
  871. {
  872. unsigned char buf[ RECORD_SIZE ];
  873. char line[ LINE_SIZE ];
  874. char Previousline[ LINE_SIZE ];
  875. int printedstar;
  876. unsigned long CurrentAddress;
  877. unsigned long cNumberOfBlocks;
  878. unsigned cLastBlockSize;
  879. unsigned long cb;
  880. //
  881. // Determine number of records to be displayed, and size of
  882. // last record
  883. //
  884. CurrentAddress = Offset;
  885. cNumberOfBlocks = Count / RECORD_SIZE;
  886. cLastBlockSize = Count % RECORD_SIZE;
  887. if( cLastBlockSize ) {
  888. cNumberOfBlocks++;
  889. }
  890. else {
  891. cLastBlockSize = RECORD_SIZE;
  892. }
  893. //
  894. // Initialize global variables related to auchBuffer
  895. //
  896. cbBytesInBuffer = 0;
  897. puchPointer = auchBuffer;
  898. //
  899. // Position the file in the correct place, and display
  900. // its contents according to the arguments specified by the
  901. // user
  902. //
  903. if ( pf != stdin ) {
  904. if (fseek( pf, Offset, SEEK_SET ) == -1) return 0;
  905. }
  906. //...maybe enable skipping Offset number of bytes for stdin...
  907. printedstar = 0;
  908. while( ( (cb = GetRecord( buf, pf )) != 0) && cNumberOfBlocks ) {
  909. cNumberOfBlocks--;
  910. if ( cNumberOfBlocks == 0 ) {
  911. cb = ( cb < cLastBlockSize ) ? cb : cLastBlockSize;
  912. }
  913. Translate( DispFormat, buf, cb, line );
  914. if (IgnoreRedundantLines && (strcmp( Previousline, line ) == 0)) {
  915. if (!printedstar) { printf("*\n"); }
  916. printedstar = 1;
  917. } else {
  918. printedstar = 0;
  919. strcpy( Previousline, line );
  920. PutAddress( line, CurrentAddress, AddrFormat );
  921. if ( (DumpAscii == YES) || (DumpAscii == NOT_DEFINED) )
  922. {
  923. PutTable ( line, buf, cb );
  924. }
  925. puts( line );
  926. }
  927. CurrentAddress += RECORD_SIZE;
  928. }
  929. return 0;
  930. }
  931. /* end of "int hd()" */
  932. void
  933. __cdecl main(
  934. int argc,
  935. char* argv[ ]
  936. )
  937. /*++
  938. Routine Description:
  939. This routine interprets all arguments entered by the user, and
  940. displays the files specified in the appropriate format.
  941. The contents of each file is displayed interpreted as a set of
  942. record containing 16 bytes each.
  943. Arguments:
  944. argc - number of arguments in the command line
  945. argv[] - array of pointers to the arguments entered by the user
  946. Return Value:
  947. None
  948. --*/
  949. {
  950. FILE* pf;
  951. //. unsigned char buf[ RECORD_SIZE ];
  952. //. char line[ LINE_SIZE ];
  953. int ArgIndex;
  954. int status;
  955. //. unsigned long CurrentAddress;
  956. //. unsigned long cNumberOfBlocks;
  957. //. unsigned cLastBlockSize;
  958. //. unsigned long cb;
  959. unsigned long Value;
  960. unsigned char* pPtrString;
  961. //. printf( "\n\n" ); //.gratuitous newlines removed
  962. // Initialization of global variables
  963. Offset = 0;
  964. Count = (unsigned long)-1; // Maximum file size
  965. AddrFormat = HEX;
  966. DispFormat = BYTE_HEX;
  967. DumpAscii = NOT_DEFINED;
  968. IgnoreRedundantLines = 0;
  969. ArgIndex = 1;
  970. while ( (ArgIndex < argc) && (( *argv[ ArgIndex ] == '-' )) ) {
  971. //
  972. // Determine the type of argument
  973. //
  974. if( (*(argv[ ArgIndex ] + 1) == 's') ||
  975. (*(argv[ ArgIndex ] + 1) == 'n') ) {
  976. //
  977. // If argument is -s or -n, interprets the number that
  978. // follows the argument
  979. //
  980. if ( (ArgIndex + 1) >= argc ) {
  981. fprintf(stderr,
  982. "hd: error: missing count/offset value after -%c\n",
  983. *(argv[ ArgIndex ] + 1) );
  984. exit (-1);
  985. }
  986. Value = strtoul( argv[ ArgIndex + 1 ], &pPtrString, 0 );
  987. if( *pPtrString != 0 ) {
  988. fprintf(stderr,
  989. "hd: error: invalid count/offset value after -%c\n",
  990. *(argv[ ArgIndex ] + 1) );
  991. exit( -1 );
  992. }
  993. if( *(argv[ ArgIndex ] + 1) == 's' ) {
  994. Offset = Value;
  995. }
  996. else {
  997. Count = Value;
  998. }
  999. ArgIndex += 2;
  1000. }
  1001. else {
  1002. //
  1003. // Interprets argument other than -s or -n
  1004. //
  1005. InterpretArgument ( argv[ ArgIndex ] );
  1006. ArgIndex++;
  1007. }
  1008. }
  1009. if ( ArgIndex >= argc ) {
  1010. //. printf ( "Error: file name is missing \n" );
  1011. status = hd( stdin );
  1012. exit( 0 );
  1013. }
  1014. //
  1015. // For each file, do
  1016. //
  1017. while ( ArgIndex < argc ) {
  1018. //
  1019. // Open file
  1020. //
  1021. if ( !( pf = fopen( argv[ ArgIndex ], "rb" ) ) ) {
  1022. fprintf(stderr, "hd: error: invalid file name '%s'\n",
  1023. argv[ ArgIndex ] );
  1024. ArgIndex++;
  1025. continue; //. don't abort if it's only a bad filename
  1026. //. exit( -1 );
  1027. }
  1028. //
  1029. // Print file name
  1030. //
  1031. //. printf( "\n\n" );
  1032. printf( "%s: \n", argv[ ArgIndex ] );
  1033. ArgIndex++;
  1034. status = hd( pf );
  1035. //. //
  1036. //. // Determine number of records to be displayed, and size of
  1037. //. // last record
  1038. //. //
  1039. //.
  1040. //. CurrentAddress = Offset;
  1041. //. cNumberOfBlocks = Count / RECORD_SIZE;
  1042. //. cLastBlockSize = Count % RECORD_SIZE;
  1043. //. if( cLastBlockSize ) {
  1044. //. cNumberOfBlocks++;
  1045. //. }
  1046. //. else {
  1047. //. cLastBlockSize = RECORD_SIZE;
  1048. //. }
  1049. //.
  1050. //. //
  1051. //. // Initialize global variables related to auchBuffer
  1052. //. //
  1053. //.
  1054. //. cbBytesInBuffer = 0;
  1055. //. puchPointer = auchBuffer;
  1056. //.
  1057. //. //
  1058. //. // Position the file in the correct place, and display
  1059. //. // its contents according to the arguments specified by the
  1060. //. // user
  1061. //. //
  1062. //.
  1063. //. fseek( pf, Offset, SEEK_SET );
  1064. //. while( ( (cb = GetRecord( buf, pf )) != 0) && cNumberOfBlocks ) {
  1065. //. cNumberOfBlocks--;
  1066. //. if ( cNumberOfBlocks == 0 ) {
  1067. //. cb = ( cb < cLastBlockSize ) ? cb : cLastBlockSize;
  1068. //. }
  1069. //. Translate( DispFormat, buf, cb, line );
  1070. //. PutAddress( line, CurrentAddress, AddrFormat );
  1071. //. if ( (DumpAscii == YES) || (DumpAscii == NOT_DEFINED) )
  1072. //. {
  1073. //. PutTable ( line, buf, cb );
  1074. //. }
  1075. //. puts( line );
  1076. //.
  1077. //. CurrentAddress += RECORD_SIZE;
  1078. //. }
  1079. }
  1080. }
  1081. /* end of "void main()" */