windows-nt/Source/XPSP1/NT/sdktools/hd/hd.c
2020-09-26 16:20:57 +08:00

1413 lines
48 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
hd.c
Abstract:
This module contains the functions that implement the hd program.
This program displays the contents of files in decimal, hexadecimal
and character formats. The contents of the files are displayed in
records of 16 bytes each. Associated to each record, there is an
address that represents the offset of the first byte in the
record relative to the begining of the file. Each record can also be
displayed as printable ASCII characters.
hd can be called with the following arguments:
-ad: displays the address of each record in decimal;
-ax: displays the address of each record in hex;
-ch: displays bytes as ASCII characters;
-cC: displays bytes as ASCII C characters (\n, \t, etc);
-ce: displays bytes as ASCII codes (EOT, CR, SOH, etc);
-cr: displays bytes as ASCII control characters (^A, ^N, etc);
-bd: interprets data in each record as byte, and displays
each byte as a decimal number;
-bx: interprets data in each record as byte, and displays
each byte as an hex number;
-wd: interprets data in each record as word, and displays
each word as a decimal number;
-wx: interprets data in each record as word, and displays
each word as an hex number;
-ld: interprets data in each record as double words, and displays
each double word as a decimal number;
-wx: interprets data in each record as a double word, and displays
each double word as an hex number;
-A: Displays data in each record also as printable ASCII
characters at the end of each line.
-s <offset>: defines the offset of the first byte to be displayed;
-n <bumber>: defines the number of bytes to be displayed;
-i does not print redundant lines;
-?, -h or -H: displays a help message.
If no argument is defined, hd assumes as default: -ax -A -bx
Authors:
Jaime F. Sasson (jaimes) 12-Nov-1990
David J. Gilman (davegi) 12-Nov-1990
Environment:
C run time library
Revision History:
--*/
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include "hd.h"
#define FALSE 0
/*************************************************************************
*
* G L O B A L V A R I A B L E S
*
*************************************************************************/
unsigned long Offset = 0; // -s option
unsigned Count = 0; // -n option
BASE AddrFormat; // -a option
FORMAT DispFormat; // -c, -b, -w or -l options
YESNO DumpAscii; // -A option
int IgnoreRedundantLines; // -i option
unsigned char auchBuffer[BUFFER_SIZE]; // Buffer that contains data read
// from the file being displayed
unsigned long cbBytesInBuffer; // Total number of bytes in the
// buffer
unsigned char* puchPointer; // Points to the next character in
// the buffer to be read
unsigned long cStringSize; // Size of a string pointed by a
// pointer in the ASCII table used
// for the translation (asciiChar,
// asciiC, asciiCode or asciiCtrl)
// The contents of this variable is
// meaningful only if -ch, -cC, -ce
// or -cr was specified.
// It is meaningless in all other
// cases (no ascii translation is
// being performed, and the ascii
// tables are not needed)
/*************************************************************************
*
* A S C I I C O N V E R S I O N T A B L E S
*
*************************************************************************/
char* asciiChar[ ] = {
" ", " ", " ", " ", " ", " ", " ", " ",
" ", " ", " ", " ", " ", " ", " ", " ",
" ", " ", " ", " ", " ", " ", " ", " ",
" ", " ", " ", " ", " ", " ", " ", " ",
" ", "! ", "\" ", "# ", "$ ", "% ", "& ", "' ",
"( ", ") ", "* ", "+ ", "' ", "- ", ". ", "/ ",
"0 ", "1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ",
"8 ", "9 ", ": ", "; ", "< ", "= ", "> ", "? ",
"@ ", "A ", "B ", "C ", "D ", "E ", "F ", "G ",
"H ", "I ", "J ", "K ", "L ", "M ", "N ", "O ",
"P ", "Q ", "R ", "S ", "T ", "U ", "V ", "W ",
"X ", "Y ", "Z ", "[ ", "\\ ", "] ", "^ ", "_ ",
"` ", "a ", "b ", "c ", "d ", "e ", "f ", "g ",
"h ", "i ", "j ", "k ", "l ", "m ", "n ", "o ",
"p ", "q ", "r ", "s ", "t ", "u ", "v ", "w ",
"x ", "y ", "z ", "{ ", "| ", "} ", "~ ", "_ ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", " "
};
char* asciiC[ ] = {
" ", " ", " ", " ", " ", " ", " ", "\\a ",
"\\b ", "\\t ", "\\n ", "\\v ", "\\f ", " ", " ", " ",
" ", " ", " ", " ", " ", " ", " ", " ",
" ", " ", " ", " ", " ", " ", " ", " ",
" ", "! ", "\\\" ", "# ", "$ ", "% ", "& ", "\' ",
"( ", ") ", "* ", "+ ", "' ", "- ", ". ", "/ ",
"0 ", "1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ",
"8 ", "9 ", ": ", "; ", "< ", "= ", "> ", "? ",
"@ ", "A ", "B ", "C ", "D ", "E ", "F ", "G ",
"H ", "I ", "J ", "K ", "L ", "M ", "N ", "O ",
"P ", "Q ", "R ", "S ", "T ", "U ", "V ", "W ",
"X ", "Y ", "Z ", "[ ", "\\\\ ", "] ", "^ ", "_ ",
"` ", "a ", "b ", "c ", "d ", "e ", "f ", "g ",
"h ", "i ", "j ", "k ", "l ", "m ", "n ", "o ",
"p ", "q ", "r ", "s ", "t ", "u ", "v ", "w ",
"x ", "y ", "z ", "{ ", "| ", "} ", "~ ", "_ ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", " "
};
char* asciiCode[ ] = {
"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
"BS ", "HT ", "LF ", "VT ", "FF ", "CR ", "SO ", "SI ",
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
"CAN", "EM ", "SUB", "ESC", "FS ", "GS ", "RS ", "US ",
" ", "! ", "\" ", "# ", "$ ", "% ", "& ", "' ",
"( ", ") ", "* ", "+ ", "' ", "- ", ". ", "/ ",
"0 ", "1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ",
"8 ", "9 ", ": ", "; ", "< ", "= ", "> ", "? ",
"@ ", "A ", "B ", "C ", "D ", "E ", "F ", "G ",
"H ", "I ", "J ", "K ", "L ", "M ", "N ", "O ",
"P ", "Q ", "R ", "S ", "T ", "U ", "V ", "W ",
"X ", "Y ", "Z ", "[ ", "\\ ", "] ", "^ ", "_ ",
"` ", "a ", "b ", "c ", "d ", "e ", "f ", "g ",
"h ", "i ", "j ", "k ", "l ", "m ", "n ", "o ",
"p ", "q ", "r ", "s ", "t ", "u ", "v ", "w ",
"x ", "y ", "z ", "{ ", "| ", "} ", "~ ", "_ ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", " "
};
char* asciiCtrl[ ] = {
"^@ ", "^A ", "^B ", "^C ", "^D ", "^E ", "^F ", "^G ",
"^H ", "^I ", "^J ", "^K ", "^L ", "^M ", "^N ", "^O ",
"^P ", "^Q ", "^R ", "^S ", "^T ", "^U ", "^V ", "^W ",
"^X ", "^Y ", "^Z ", "^[ ", "^\\ ", "^] ", "^^ ", "^_ ",
" ", "! ", "\" ", "# ", "$ ", "% ", "& ", "' ",
"( ", ") ", "* ", "+ ", "' ", "- ", ". ", "/ ",
"0 ", "1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ",
"8 ", "9 ", ": ", "; ", "< ", "= ", "> ", "? ",
"@ ", "A ", "B ", "C ", "D ", "E ", "F ", "G ",
"H ", "I ", "J ", "K ", "L ", "M ", "N ", "O ",
"P ", "Q ", "R ", "S ", "T ", "U ", "V ", "W ",
"X ", "Y ", "Z ", "[ ", "\\ ", "] ", "^ ", "_ ",
"` ", "a ", "b ", "c ", "d ", "e ", "f ", "g ",
"h ", "i ", "j ", "k ", "l ", "m ", "n ", "o ",
"p ", "q ", "r ", "s ", "t ", "u ", "v ", "w ",
"x ", "y ", "z ", "{ ", "| ", "} ", "~ ", "_ ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ",
"<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", "<EFBFBD> ", " "
};
void
ConvertASCII (
char line[],
unsigned char buf[],
unsigned long cb,
char* pTable[]
)
/*++
Routine Description:
This routine converts the bytes received in a buffer
into an ASCII representation (Char, C, Code or CTRL).
Arguments:
line - Buffer that will receive the converted characters.
buf - A buffer that contains the data to be converted.
cb - Number of bytes in the buffer
pTable - Pointer to the table to be used in the conversion
Return Value:
None
--*/
{
unsigned long ulIndex;
sprintf( line,
MSG_DATA_ASCII_FMT,
pTable[ buf[ 0 ]], pTable[ buf[ 1 ]],
pTable[ buf[ 2 ]], pTable[ buf[ 3 ]],
pTable[ buf[ 4 ]], pTable[ buf[ 5 ]],
pTable[ buf[ 6 ]], pTable[ buf[ 7 ]],
pTable[ buf[ 8 ]], pTable[ buf[ 9 ]],
pTable[ buf[ 10 ]], pTable[ buf[ 11 ]],
pTable[ buf[ 12 ]], pTable[ buf[ 13 ]],
pTable[ buf[ 14 ]], pTable[ buf[ 15 ]]);
//
// If the number of bytes in the buffer is less than the maximum size
// of the record, then delete the characters that were converted
// but are not to be displayed.
//
if (cb < RECORD_SIZE) {
//
// -1: to eliminate the \0
// +1: to count the SPACE character between two strings
//
ulIndex = (sizeof( MSG_ADDR_FIELD ) - 1 ) + cb*(cStringSize + 1);
while ( line[ ulIndex ] != NUL ) {
line[ ulIndex ] = SPACE;
ulIndex++;
}
}
}
void
ConvertBYTE (
char line[],
unsigned char buf[],
unsigned long cb,
unsigned long ulBase
)
/*++
Routine Description:
This routine converts each byte received in a buffer
into a number. The base used in the conversion is received as
parameter.
Arguments:
line - Buffer that will receive the converted characters.
buf - A buffer that contains the data to be converted.
cb - Number of bytes in the buffer
ulBase - Defines the base to be used in the conversion
Return Value:
None
--*/
{
unsigned long ulIndex;
char* pchMsg;
unsigned long ulNumberOfDigits;
switch( ulBase ) {
case DEC:
ulNumberOfDigits = 3; // needs 3 decimal digits to
// represent a byte
pchMsg = MSG_DATA_BYTE_DEC_FMT; // message that contains the format
break;
case HEX:
ulNumberOfDigits = 2; // needs 2 hexdigits to
// represent a byte
pchMsg = MSG_DATA_BYTE_HEX_FMT; // message that contains the format
break;
default:
printf( "Unknown base\n" );
assert( FALSE );
break;
}
sprintf( line,
pchMsg,
buf[ 0 ], buf[ 1 ],
buf[ 2 ], buf[ 3 ],
buf[ 4 ], buf[ 5 ],
buf[ 6 ], buf[ 7 ],
buf[ 8 ], buf[ 9 ],
buf[ 10 ], buf[ 11 ],
buf[ 12 ], buf[ 13 ],
buf[ 14 ], buf[ 15 ]);
//
// If this is the last record to be displayed, then delete the
// characters that were translated but are not to be displayed.
//
if (cb < RECORD_SIZE) {
ulIndex = (sizeof( MSG_ADDR_FIELD ) - 1 ) +
cb*(ulNumberOfDigits + 1 );
while ( line[ ulIndex ] != NUL ) {
line[ ulIndex ] = SPACE;
ulIndex++;
}
}
}
void
ConvertWORD (
char line[],
unsigned char buf[],
unsigned long cb,
unsigned long ulBase
)
/*++
Routine Description:
This routine converts the data received in a buffer
into numbers. The data in the buffer are interpreted as words.
If the buffer contains an odd number of bytes, then the last byte
is converted as a byte, not as word.
The base used in the conversion is received as parameter.
Arguments:
line - Buffer that will receive the converted characters.
buf - A buffer that contains the data to be converted.
cb - Number of bytes in the buffer
ulBase - Defines the base to be used in the conversion
Return Value:
None
--*/
{
unsigned long ulIndex;
char* pchMsg;
char* pchMsgHalf;
unsigned long ulNumberOfDigits;
switch( ulBase ) {
case DEC:
ulNumberOfDigits = 5; // needs 5 decimal digits to
// represent a word
pchMsg = MSG_DATA_WORD_DEC_FMT; // message with the string
// format
pchMsgHalf = MSG_SINGLE_BYTE_DEC_FMT; // message with the format of
break; // half a word in decimal
case HEX:
ulNumberOfDigits = 4; // needs 4 hex digits to
// represent a word
pchMsg = MSG_DATA_WORD_HEX_FMT; // message the string format
pchMsgHalf = MSG_SINGLE_BYTE_HEX_FMT; // message with the format of
// half a word in hex
break;
default:
printf( "Unknown base\n" );
assert( FALSE );
break;
}
sprintf( line,
pchMsg,
(( unsigned short* ) ( buf )) [ 0 ],
(( unsigned short* ) ( buf )) [ 1 ],
(( unsigned short* ) ( buf )) [ 2 ],
(( unsigned short* ) ( buf )) [ 3 ],
(( unsigned short* ) ( buf )) [ 4 ],
(( unsigned short* ) ( buf )) [ 5 ],
(( unsigned short* ) ( buf )) [ 6 ],
(( unsigned short* ) ( buf )) [ 7 ]);
//
// If this record contains less bytes than the maximum record size,
// then it is the last record to be displayed. In this case we have
// to verify if the record contains an even number of bytes. If it
// doesn't, then the last byte must be interpreted as a byte and not
// as a word.
// Also, the characters that were converted but are not to be displayed,
// have to be deleted.
//
if (cb < RECORD_SIZE) {
ulIndex = (sizeof( MSG_ADDR_FIELD ) - 1 ) +
(cb/2)*(ulNumberOfDigits + 1 );
if (cb%2 != 0) {
ulIndex += sprintf( line + ulIndex,
pchMsgHalf,
buf[ cb-1 ]);
line[ ulIndex ] = SPACE;
}
//
// Delete characters that are not to be displayed
//
while ( line[ ulIndex ] != NUL ) {
line[ ulIndex ] = SPACE;
ulIndex++;
}
}
}
void
ConvertDWORD (
char line[],
unsigned char buf[],
unsigned long cb,
unsigned long ulBase
)
/*++
Routine Description:
This routine converts the data received in a buffer
into numbers. The data in the buffer is interpreted as double words.
If the buffer contains less bytes than the maximum size of the record,
then it is the last record, and we may need to convert again the last
3 bytes in the buffer.
If the number of bytes in the buffer is not multiple of 4, then the
last bytes in the buffer are converted as a byte, word, or word and
byte, as appropriate.
The characters that were converted but are not to be displayed have to
be removed from the buffer.
The base used in the conversion is received as parameter.
Arguments:
line - Buffer that will receive the converted characters.
buf - A buffer that contains the data to be converted.
cb - Number of bytes in the buffer
ulBase - Defines the base to be used in the conversion
Return Value:
None
--*/
{
unsigned long ulIndex;
char* pchMsg;
char* pchMsgByte;
char* pchMsgWord;
char* pchMsgWordByte;
unsigned long ulNumberOfDigits;
switch( ulBase ) {
case DEC:
ulNumberOfDigits = 10; // needs 10 decimal digits to
// represent a dword
pchMsg = MSG_DATA_DWORD_DEC_FMT; // message with the string
// format
pchMsgByte = MSG_SINGLE_BYTE_DEC_FMT; // message with the format
// of a single byte in
// decimal
pchMsgWord = MSG_SINGLE_WORD_DEC_FMT; // message that contains
// the format of a single
// word in decimal
pchMsgWordByte = MSG_WORD_BYTE_DEC_FMT;
break;
case HEX:
ulNumberOfDigits = 8; // needs 8 hex digits to
// represent a dword
pchMsg = MSG_DATA_DWORD_HEX_FMT; // message the string format
pchMsgByte = MSG_SINGLE_BYTE_HEX_FMT; // message with the format
// of a single byte in hex
pchMsgWord = MSG_SINGLE_WORD_HEX_FMT; // message with the format
// of a single word in hex
pchMsgWordByte = MSG_WORD_BYTE_HEX_FMT;
break;
default:
printf( "Unknown base\n" );
assert( FALSE );
break;
}
sprintf( line,
pchMsg,
(( unsigned long* ) ( buf )) [ 0 ],
(( unsigned long* ) ( buf )) [ 1 ],
(( unsigned long* ) ( buf )) [ 2 ],
(( unsigned long* ) ( buf )) [ 3 ]);
//
// If the buffer contains less bytes than the maximum record size,
// the it is the last buffer to be displayed. In this case, check if
// if the buffer contains a number o bytes that is multiple of 4.
// If it doesn't, then converts the last bytes as a byte, a word, or
// a word and a byte, as appropriate.
//
if (cb < RECORD_SIZE) {
ulIndex = (sizeof( MSG_ADDR_FIELD ) - 1 ) +
(cb/4)*(ulNumberOfDigits + 1 );
switch( cb%4 ) {
case 1:
ulIndex += sprintf( line + ulIndex,
pchMsgByte,
buf[ cb-1 ]);
line[ ulIndex ] = SPACE;
break;
case 2:
ulIndex += sprintf( line + ulIndex,
pchMsg,
(( unsigned short* ) ( buf )) [ (cb/2) - 1 ]);
line[ ulIndex ] = SPACE;
break;
case 3:
ulIndex += sprintf( line + ulIndex,
pchMsgWordByte,
(( unsigned short* ) ( buf )) [ (cb/2) - 1],
buf[ cb-1 ]);
line[ ulIndex ] = SPACE;
break;
default: // buf contains multiple of 4 bytes
break;
}
//
// Delete the charecters that were converted but are not to be
// displayed.
//
while ( line[ ulIndex ] != NUL) {
line[ ulIndex ] = SPACE;
ulIndex++;
}
}
}
void
ConvertPRINT (
char line[],
unsigned char buf[],
unsigned long cb
)
/*++
Routine Description:
This routine converts each byte received in a buffer into a
printable character.
Arguments:
line - Buffer that will receive the converted characters.
buf - A buffer that contains the data to be converted.
cb - Number of bytes in the buffer
Return Value:
None
--*/
{
sprintf( line,
MSG_PRINT_CHAR_FMT,
isprint( buf[ 0 ] ) ? buf[ 0 ] : DOT,
isprint( buf[ 1 ] ) ? buf[ 1 ] : DOT,
isprint( buf[ 2 ] ) ? buf[ 2 ] : DOT,
isprint( buf[ 3 ] ) ? buf[ 3 ] : DOT,
isprint( buf[ 4 ] ) ? buf[ 4 ] : DOT,
isprint( buf[ 5 ] ) ? buf[ 5 ] : DOT,
isprint( buf[ 6 ] ) ? buf[ 6 ] : DOT,
isprint( buf[ 7 ] ) ? buf[ 7 ] : DOT,
isprint( buf[ 8 ] ) ? buf[ 8 ] : DOT,
isprint( buf[ 9 ] ) ? buf[ 9 ] : DOT,
isprint( buf[ 10 ] ) ? buf[ 10 ] : DOT,
isprint( buf[ 11 ] ) ? buf[ 11 ] : DOT,
isprint( buf[ 12 ] ) ? buf[ 12 ] : DOT,
isprint( buf[ 13 ] ) ? buf[ 13 ] : DOT,
isprint( buf[ 14 ] ) ? buf[ 14 ] : DOT,
isprint( buf[ 15 ] ) ? buf[ 15 ] : DOT);
//
// If the buffer contains less characters than the maximum record size,
// then delete the characters that were converted but are not to be
// displayed
//
if (cb < RECORD_SIZE) {
while ( line[ cb ] != NUL ) {
line[ cb ] = SPACE;
cb++;
}
}
}
void
Translate (
FORMAT fmt,
unsigned char buf[ ],
unsigned long cb,
char line[ ]
)
/*++
Routine Description:
This function converts the bytes received in a buffer
into a printable representation, that corresponds to one
of the formats specified by the parameter fmt.
Arguments:
fmt - The format to be used in the conversion
buf - A buffer that contains the data to be converted.
cb - Number of bytes in the buffer
line - Buffer that will receive the converted characters.
Return Value:
None
--*/
{
assert( buf );
assert( line );
switch( fmt ) {
case ASCII_CHAR:
ConvertASCII( line, buf, cb, asciiChar );
break;
case ASCII_C:
ConvertASCII( line, buf, cb, asciiC );
break;
case ASCII_CODE:
ConvertASCII( line, buf, cb, asciiCode );
break;
case ASCII_CTRL:
ConvertASCII( line, buf, cb, asciiCtrl );
break;
case BYTE_DEC:
ConvertBYTE( line, buf, cb, DEC );
break;
case BYTE_HEX:
ConvertBYTE( line, buf, cb, HEX );
break;
case WORD_DEC:
ConvertWORD( line, buf, cb, DEC );
break;
case WORD_HEX:
ConvertWORD( line, buf, cb, HEX );
break;
case DWORD_DEC:
ConvertDWORD( line, buf, cb, DEC );
break;
case DWORD_HEX:
ConvertDWORD( line, buf, cb, HEX );
break;
case PRINT_CHAR:
ConvertPRINT( line, buf, cb );
break;
default:
printf( "Bad Format\n" );
assert( FALSE );
break;
}
}
void
PutAddress (
char line[],
unsigned long ulAddress,
BASE Base
)
/*++
Routine Description:
This routine adds to the buffer received the offset of the first
byte (or character) already in the buffer. This offset represents
the position of the byte in the file, relatively to the begining
of the file.
Arguments:
Base - The base to be used to represent the offset.
line - Buffer containing the converted characters to be displayed in
the screen
ulAddress - Offset to be added to the begining of the buffer
Return Value:
None
--*/
{
unsigned long ulIndex;
assert( line);
switch( Base ) {
case DEC:
ulIndex = sprintf( line,
MSG_ADDR_DEC_FMT,
ulAddress );
break;
case HEX:
ulIndex = sprintf( line,
MSG_ADDR_HEX_FMT,
ulAddress);
break;
default:
printf( "Bad Address Base\n" );
assert( FALSE );
break;
}
line[ ulIndex ] = SPACE; // Get rid of the NUL added by sprintf
}
void
PutTable (
char line[],
unsigned char buf[],
unsigned long cb
)
/*++
Routine Description:
This routine adds to the end of the buffer received, the ASCII
representation of all printable characters already in the buffer.
Characters that are not printable (smaller than 0x20 or greater than
0x7f) are displayed as a dot.
Arguments:
line - Buffer containing the characters to be displayed in one line
of the screen
buf - The buffer that contains a record of bytes (maximum of 16)
read from the file being displayed.
ulAddress - Number of bytes in buf.
Return Value:
None
--*/
{
unsigned long ulIndex;
assert( line );
assert( buf );
ulIndex = strlen (line);
Translate( PRINT_CHAR, buf, cb, (line + ulIndex));
}
void
InterpretArgument (
char* pchPointer
)
/*++
Routine Description:
This routine interprets an argument typed by the user (exept -n
and -s) and initializes some variables accordingly.
Arguments:
pchPointer - Pointer to the argument to be interpreted.
Return Value:
None
--*/
{
//
// pchPointer will point to the character that follows '-'
//
pchPointer++;
if( strcmp( pchPointer, "ax" ) == 0 ) {
AddrFormat = HEX;
}
else if( strcmp( pchPointer, "ad" ) == 0 ) {
AddrFormat = DEC;
}
else if( strcmp( pchPointer, "ch" ) == 0 ) {
DispFormat = ASCII_CHAR;
cStringSize = strlen( asciiChar[0] );
DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
}
else if( strcmp( pchPointer, "cC" ) == 0 ) {
DispFormat = ASCII_C;
cStringSize = strlen( asciiC[0] );
DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
}
else if( strcmp( pchPointer, "ce" ) == 0 ) {
DispFormat = ASCII_CODE;
cStringSize = strlen( asciiCode[0] );
DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
}
else if( strcmp( pchPointer, "cr" ) == 0 ) {
DispFormat = ASCII_CTRL;
cStringSize = strlen( asciiCtrl[0] );
DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
}
else if( strcmp( pchPointer, "bd" ) == 0 ) {
DispFormat = BYTE_DEC;
DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
}
else if( strcmp( pchPointer, "bx" ) == 0 ) {
DispFormat = BYTE_HEX;
DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
}
else if( strcmp( pchPointer, "wd" ) == 0 ) {
DispFormat = WORD_DEC;
DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
}
else if( strcmp( pchPointer, "wx" ) == 0 ) {
DispFormat = WORD_HEX;
DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
}
else if( strcmp( pchPointer, "ld" ) == 0 ) {
DispFormat = DWORD_DEC;
DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
}
else if( strcmp( pchPointer, "lx" ) == 0 ) {
DispFormat = DWORD_HEX;
DumpAscii = ( DumpAscii == NOT_DEFINED ) ? NO : DumpAscii;
}
else if( strcmp( pchPointer, "A" ) == 0 ) {
DumpAscii = YES;
}
else if( strcmp( pchPointer, "i" ) == 0 ) {
IgnoreRedundantLines = 1;
}
else if( strcmp( pchPointer, "?" ) || strcmp( pchPointer, "h" ) ||
strcmp( pchPointer, "H" ) ) {
puts( HELP_MESSAGE );
exit( 0 );
}
else {
fprintf( stderr, "hd: error: invalid argument '%s'\n", --pchPointer );
exit( - 1 );
}
}
unsigned long
GetRecord (
unsigned char* puchRecord,
FILE* pf
)
/*++
Routine Description:
This routine fills the buffer whose pointer was received as parameter,
with characters read from the file being displayed. Blocks of data
are initially read from the file being displayed, and kept in a buffer.
A record is filled with characters obtained from this buffer.
Whenever this buffer gets empty, a new access to file is performed
in order to fill this buffer.
Arguments:
puchRecord - Pointer to the record to be filled
pf - Pointer to the file that is being displayed
Return Value:
Total number of characters put in the record.
--*/
{
unsigned long cbBytesCopied;
//
// If the buffer contains enogh characters to fill the record, then
// copy the appropriate number of bytes.
//
if( cbBytesInBuffer >= RECORD_SIZE ) {
for( cbBytesCopied = 0; cbBytesCopied < RECORD_SIZE; cbBytesCopied++ ) {
*puchRecord++ = *puchPointer++;
cbBytesInBuffer--;
}
}
//
// else, the buffer does not contain enough characters to fill the record
//
else {
//
// Copy to the remaining characters in the buffer to the record
//
for( cbBytesCopied = 0; cbBytesInBuffer > 0; cbBytesInBuffer-- ) {
*puchRecord++ = *puchPointer++;
cbBytesCopied++;
}
//
// Read more data from the file and fill the record
//
if( !feof( pf ) ) {
cbBytesInBuffer = fread( auchBuffer,
sizeof( char ),
BUFFER_SIZE,
pf );
puchPointer = auchBuffer;
while( ( cbBytesInBuffer != 0 ) && (cbBytesCopied < RECORD_SIZE) ) {
*puchRecord++ = *puchPointer++;
cbBytesInBuffer--;
cbBytesCopied++;
}
}
}
return( cbBytesCopied );
}
int
hd(
FILE * pf
)
/*++ hd
*
* Routine Description:
* takes the file/stream pointed to by pf and `hd's it to stdout.
*
* Arguments:
* FILE * pf -
*
* Return Value:
* int - to be determined, always zero for now
* Warnings:
--*/
{
unsigned char buf[ RECORD_SIZE ];
char line[ LINE_SIZE ];
char Previousline[ LINE_SIZE ];
int printedstar;
unsigned long CurrentAddress;
unsigned long cNumberOfBlocks;
unsigned cLastBlockSize;
unsigned long cb;
//
// Determine number of records to be displayed, and size of
// last record
//
CurrentAddress = Offset;
cNumberOfBlocks = Count / RECORD_SIZE;
cLastBlockSize = Count % RECORD_SIZE;
if( cLastBlockSize ) {
cNumberOfBlocks++;
}
else {
cLastBlockSize = RECORD_SIZE;
}
//
// Initialize global variables related to auchBuffer
//
cbBytesInBuffer = 0;
puchPointer = auchBuffer;
//
// Position the file in the correct place, and display
// its contents according to the arguments specified by the
// user
//
if ( pf != stdin ) {
if (fseek( pf, Offset, SEEK_SET ) == -1) return 0;
}
//...maybe enable skipping Offset number of bytes for stdin...
printedstar = 0;
while( ( (cb = GetRecord( buf, pf )) != 0) && cNumberOfBlocks ) {
cNumberOfBlocks--;
if ( cNumberOfBlocks == 0 ) {
cb = ( cb < cLastBlockSize ) ? cb : cLastBlockSize;
}
Translate( DispFormat, buf, cb, line );
if (IgnoreRedundantLines && (strcmp( Previousline, line ) == 0)) {
if (!printedstar) { printf("*\n"); }
printedstar = 1;
} else {
printedstar = 0;
strcpy( Previousline, line );
PutAddress( line, CurrentAddress, AddrFormat );
if ( (DumpAscii == YES) || (DumpAscii == NOT_DEFINED) )
{
PutTable ( line, buf, cb );
}
puts( line );
}
CurrentAddress += RECORD_SIZE;
}
return 0;
}
/* end of "int hd()" */
void
__cdecl main(
int argc,
char* argv[ ]
)
/*++
Routine Description:
This routine interprets all arguments entered by the user, and
displays the files specified in the appropriate format.
The contents of each file is displayed interpreted as a set of
record containing 16 bytes each.
Arguments:
argc - number of arguments in the command line
argv[] - array of pointers to the arguments entered by the user
Return Value:
None
--*/
{
FILE* pf;
//. unsigned char buf[ RECORD_SIZE ];
//. char line[ LINE_SIZE ];
int ArgIndex;
int status;
//. unsigned long CurrentAddress;
//. unsigned long cNumberOfBlocks;
//. unsigned cLastBlockSize;
//. unsigned long cb;
unsigned long Value;
unsigned char* pPtrString;
//. printf( "\n\n" ); //.gratuitous newlines removed
// Initialization of global variables
Offset = 0;
Count = (unsigned long)-1; // Maximum file size
AddrFormat = HEX;
DispFormat = BYTE_HEX;
DumpAscii = NOT_DEFINED;
IgnoreRedundantLines = 0;
ArgIndex = 1;
while ( (ArgIndex < argc) && (( *argv[ ArgIndex ] == '-' )) ) {
//
// Determine the type of argument
//
if( (*(argv[ ArgIndex ] + 1) == 's') ||
(*(argv[ ArgIndex ] + 1) == 'n') ) {
//
// If argument is -s or -n, interprets the number that
// follows the argument
//
if ( (ArgIndex + 1) >= argc ) {
fprintf(stderr,
"hd: error: missing count/offset value after -%c\n",
*(argv[ ArgIndex ] + 1) );
exit (-1);
}
Value = strtoul( argv[ ArgIndex + 1 ], &pPtrString, 0 );
if( *pPtrString != 0 ) {
fprintf(stderr,
"hd: error: invalid count/offset value after -%c\n",
*(argv[ ArgIndex ] + 1) );
exit( -1 );
}
if( *(argv[ ArgIndex ] + 1) == 's' ) {
Offset = Value;
}
else {
Count = Value;
}
ArgIndex += 2;
}
else {
//
// Interprets argument other than -s or -n
//
InterpretArgument ( argv[ ArgIndex ] );
ArgIndex++;
}
}
if ( ArgIndex >= argc ) {
//. printf ( "Error: file name is missing \n" );
status = hd( stdin );
exit( 0 );
}
//
// For each file, do
//
while ( ArgIndex < argc ) {
//
// Open file
//
if ( !( pf = fopen( argv[ ArgIndex ], "rb" ) ) ) {
fprintf(stderr, "hd: error: invalid file name '%s'\n",
argv[ ArgIndex ] );
ArgIndex++;
continue; //. don't abort if it's only a bad filename
//. exit( -1 );
}
//
// Print file name
//
//. printf( "\n\n" );
printf( "%s: \n", argv[ ArgIndex ] );
ArgIndex++;
status = hd( pf );
//. //
//. // Determine number of records to be displayed, and size of
//. // last record
//. //
//.
//. CurrentAddress = Offset;
//. cNumberOfBlocks = Count / RECORD_SIZE;
//. cLastBlockSize = Count % RECORD_SIZE;
//. if( cLastBlockSize ) {
//. cNumberOfBlocks++;
//. }
//. else {
//. cLastBlockSize = RECORD_SIZE;
//. }
//.
//. //
//. // Initialize global variables related to auchBuffer
//. //
//.
//. cbBytesInBuffer = 0;
//. puchPointer = auchBuffer;
//.
//. //
//. // Position the file in the correct place, and display
//. // its contents according to the arguments specified by the
//. // user
//. //
//.
//. fseek( pf, Offset, SEEK_SET );
//. while( ( (cb = GetRecord( buf, pf )) != 0) && cNumberOfBlocks ) {
//. cNumberOfBlocks--;
//. if ( cNumberOfBlocks == 0 ) {
//. cb = ( cb < cLastBlockSize ) ? cb : cLastBlockSize;
//. }
//. Translate( DispFormat, buf, cb, line );
//. PutAddress( line, CurrentAddress, AddrFormat );
//. if ( (DumpAscii == YES) || (DumpAscii == NOT_DEFINED) )
//. {
//. PutTable ( line, buf, cb );
//. }
//. puts( line );
//.
//. CurrentAddress += RECORD_SIZE;
//. }
}
}
/* end of "void main()" */