現在課題でオプション付16進ダンプツールを作成しているのですが、部分部分でうまくいきません。
ダンプツール詳細
・コマンドラインから実行
・ファイルの内容をすべてダンプする通常ダンプの他、開始アドレス・終了アドレスを指定して任意の部分でダンプ(開始、終了どちらかのみの指定も可)、24行単位でページ表示するviewerモードがある
・コマンドライン上のファイル名、オプションは順不同
・viewerオプション(-v)が指定された場合は開始・終了アドレスは無視
・同じオプションが複数指定された場合は後から指定された方を有効とする
・終了アドレスがファイルサイズを超えている場合は、指定を無効としファイル の最後までダンプ
・開始アドレスがファイルサイズ、終了アドレスより大きい場合は、ダンプせ ずに終了
・開始アドレスや終了アドレスが16バイト境界と合わない場合その分を空白で埋める
・Viewer オプションで データ数が 1 ページに満たない場合はアドレスのみ表示してデータは空白で埋める。 ページの先頭にデータが無い場合は、ページの移動を行わない
Viewer モード 詳細
・1 ページ(24 行)分のデータをダンプした後、コマンド入力を受け付け る
・コマンドはf,b,q,?
f … 次のページを表示。 次のページの先頭がファイルサイズを超えている場合は ページ移動をしない
b … 前のページを表示。 前のページがファイルの先頭より前になる場合は、ペー ジ移動しない
q … プログラムを終了
? … Viewer モードで使用可能なコマンドを表示。 enter を押すとダンプ表示を 再開
表示フォーマット
aaaaaaaa:xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx |zzzzzzzzzzzzzzzz
(zzzz.....はASCIIダンプ)
以上のプログラムを作成しているのですが、現状
・開始、終了アドレス指定時はうまくいく
・開始、終了アドレスの指定がない場合最後の方の表示が崩れる
・終了アドレスのみ指定の場合もうまくいく
・開始アドレスのみ指定の場合暴走?する(プログラムが止まらまい)
・vオプション時、bコマンドがうまく動作しない
・vオプション時、コマンド入力を促す「enter command('?')for help:」の分が一行多く表示される
・vオプション時のf,bコマンドについて、次のページ、前のページがない場合の処理がわからない
という状態です。
以上の問題となっている部分、また気づいていない間違っている部分の改善法を教えていただきたいです。
環境は
OS:win8.1
コンパイラ:GCC
です。
よろしくお願いします。
以下コード
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void HexDumping(int page,int begin,int end,FILE *fp);
void Vmode(FILE *fp);
void HowToUse();
int menu();
//グローバル変数
int begin=0; //開始アドレスを保存
int end; //終了アドレスを保存
int addr=0;
int flsz=0; //ファイルサイズ
int main(int argc,char *argv[])
{
char a1[64];
char a2[64];
FILE *fp;
int e=1; //実行プログラム名はスキップするため0でなく1
for(;e<argc;e++){ //コマンドライン解析
if(*argv[e]!='-'){ //'-'が先頭についてない→ファイルかどうか判断
if((fp=fopen(argv[e],"rb"))==NULL){
printf("need input filename \n");
HowToUse();
exit(1);
}
}
if(*argv[e]=='-'){ //'-'が先頭に付いている→オプション解析
if(argv[e][1]=='b'){ //bなら後ろについている数値を保存
strncpy(a1,argv[e]+2,64);
begin=strtol(a1,NULL,16);
}
else if(argv[e][1]=='e'){ //eなら後ろについている数値を保存
strncpy(a2,argv[e]+2,64);
end=strtol(a2,NULL,16);
}
else if(argv[e][1]=='v'){ //vならviewermodeへ(ファイルかどうかの判別の前にオプション解析に入った時のためにこちらでもファイルオープン)
int y=1;
for(;y<argc;y++){ //コマンドラインからファイルを探す
if(*argv[y]!='-'){
if((fp=fopen(argv[y],"rb"))==NULL){
printf("need input filename \n");
HowToUse();
exit(1);
}
fseek(fp,0,SEEK_END); //ファイルサイズ取得
flsz=ftell(fp);
rewind(fp);
}
}
Vmode(fp);
}
else
HowToUse();
}
}
fseek(fp,0,SEEK_END); //ファイルサイズ取得
flsz=ftell(fp);
rewind(fp);
if(argc==2)HexDumping(1365,0,flsz,fp);
else if(end>flsz)HexDumping(1365,begin,flsz,fp);
else HexDumping(1365,begin,end,fp); //1365*24でintの最大値
fclose(fp);
return 0;
}
void HexDumping(int page,int begin,int end,FILE *fp)
{
int data;
int a,i;
int p=0;
int w=0;
char buff[256];
int cnt=0;
for(;addr<=page*24;addr++){ //24行(-vモードでなければpageに大きい数値代入、-vなら1代入)
printf("%08x: ",addr);
for(a=0;a<16;a++){
data=fgetc(fp);
cnt++;
if(cnt==end){
buff[a]='\0';
for(;a<16;a++)printf(" ");
printf("|%s\n",buff);
fclose(fp);
return;
}
if(w!=begin){ //開始アドレスまでの部分を空白で埋める
buff[a]=' ';
w++;
}
else{
if(data<=0x20||data>=0x7F) buff[a]='.'; //ASCII範囲か判定、範囲外なら'.'に置き換え
else buff[a]=data; //ASCII範囲内ならそのまま
}
if(p!=begin){ //開始アドレスまでの部分を空白で埋める
printf(" ");
p++;
}
else printf("%02X ",data);
}
buff[a]='\0';
printf("|%s\n",buff); //ASCIIダンプ表示
fseek(fp,1,SEEK_CUR);
}
}
void Vmode(FILE *fp)
{
HexDumping(1,0,flsz,fp); //まず24行ダンプ
int z=2;
char command;
do{
command=menu();
switch(command){
case 'f':
//次ページがあるかどうかの判断と処理をいれたい
HexDumping(z,0,flsz,fp);
z++;
break;
case 'b':
//前ページがあるかどうかの判断と処理をいれたい
fseek(fp,-16*24*2,SEEK_CUR);
HexDumping(1,0,flsz,fp);
break;
case 'q':
exit(1);
case '?':
printf("'f':forward page\n'b':back page\n'q'quit binview\n'?'display this\npress enter...\n");
getchar();
break;
}
}while(command!='q');
}
int menu()
{
int command=0;
char str[64];
do{
printf("enter command('?' for help):");
command=getchar();
printf("\n");
}while((command!='f')&&(command!='b')&&(command!='q')&&(command!='?'));
return command;
}
void HowToUse()
{
printf("usage: binview <filename> [-b<address(hex)>] [-e<address(hex)>] [-v]\n<filename> ... input filename\n-b<address> ... begin address\n-e<address> ... end address\n-v ... viewer mode \n");
return;
}