模拟dos下面的Debug下子命令D的功能,显示内存数据的程序
还有子命令错误位置提示的功能和 d 命令的 l 参数没有实现;l 后面接数字表示要显示的个数,
在解析子命令的时候本想用语法和此法分析的方法,但功力不够,《the c++ language 》里面的那个词法语法分析的简单计算的代码都看不懂,只能进行字符串判断来处理了。代码写的很冗余·············
#define unit(m,n) (*(unsigned char far *)( m*0x10000 + n))
int showNum = 0x80 ; /*要显示的数字的个数*/
int sec = 0; /*要现实的段地址,在getToken里面如果没有给定的话,会赋予DS的值*/
int offset = 0; /*当前偏移地址*/
int dcount = 0,ccount = 0; /*记录已经输出了的内存字节和对应的字符的个数*/
int errorppos=1; /*出错位置标记,没有实现*/
int str2Hex( char *pstr); /*将十六进制字符串转化为数字*/
void show(); /*从当前偏移地址开始,显示showNum个字符*/
void showLine( unsigned int o); /*根据传入的便宜地址显示内存数据,以及对应的ascii值*/
int getToken(char *); /*分析d子命令,将结果写给全局变量sec和offset*/
void Driver(char *); /*根据用户的输入的字符串,调用子命令分析函数,根据返回结果做出相应的操作*/
int valueLegal(char *); /*传入的参数应该是分离出来的段地址或者偏移地址,判断要转换的十六进制字符串是否合法*/
main()
{
char buf[100];
sec=_DS; /*默认偏移地址*/
offset=0x0080; /*因为按下d,偏移地址会自加 showNum*/
printf("-----------------------------------Lee'S Debug---------------------------------\n");
while(1) /*showLine(_DS,0x1009);*/
{
printf("-");
gets(buf);
Driver(buf);
memset(buf,0,100);
}
}
void Driver(char * pstr)
{
showNum = 0x80 ;
if( strlen(pstr) == 0)
return;
if( getToken(pstr) )
show();
else
printf("Error Comand\n");
}
int getToken(char * pstr)
{
char *pt = pstr;
char buf[64] = {0};
char secbuf[8] = {0};
char offbuf[8] = {0};
int i = 0,j = 0,sPos = -1,oPos = -1;
int pos[4]={0};
int havesec = 0,flag=0;
if( pstr == 0)
return 0;
strcpy(buf,pstr);
/*找到第一个符号:命令的位置,排除空格*/
while( buf[i] )
{
if( buf[i] != ' ' )
{
pos[j++]=i++;
break;
}
i++;
}
/**/
while( buf[i] && j<4 )
{
flag=1;
while( buf[i] && buf[i] != ' ' && j<4)
{
if( flag )
{
pos[j++]=i;
flag=0;
}
i++;
}
i++;
}
/*如果第一个非空格字符是q 则退出*/
if( ('q' == buf[pos[0]] || 'Q' == buf[pos[0]]) )
exit(0);
/*如果第一个非空格字符不是d,则返回0,error*/
if( ! ('d' == buf[pos[0]] || 'D' == buf[pos[0]]) )
return 0;
/*pos[1]是第二个非空格字符的开始,如果为0表示没有赋值,直接输出DS:0x100*/
if( 0 == pos[1] )
{
offset += showNum;
return 1;
}
/*pos[1]是第二个非空格字符的开始*/
i=sPos=oPos=pos[1];
/*取地址值*/
do
{
i++;
if( buf[i] == ' ' || buf[i] == '\0')
{
strncpy(&offbuf,&buf[oPos],i-oPos);
}
if( buf[i] == ':')
{
strncpy(&secbuf,&buf[sPos],i-sPos);
oPos=i+1;
}
}while( buf[i] != ' ' && buf[i] != '\0');
sPos=valueLegal(secbuf);
oPos=valueLegal(offbuf);
if( sPos == -1 || oPos == -1)
return 0;
if( sPos == 0 && oPos > 0 && oPos < 0xa )
{
sec = 0x1000;
offset = str2Hex(offbuf);
return 1;
}
if( sPos > 0 && oPos > 0)
{
sec = str2Hex(secbuf);
offset = str2Hex(offbuf);
return 1;
}
return 0;
}
/* 传入的参数应该是分离出来的段地址或者偏移地址
判断要转换的十六进制字符串是否合法
如果是es或者ds就返回0xD或0xE
错误的表达式返回-1
否则返回表达式的长度
返回0表示字符串长度为0
*/
int valueLegal(char * pstr)
{
int i=0;
char *pt=pstr;
/*空字符串就返回1,表示可以转换*/
if( strlen(pt) == 0 )
return 0;
if( 0 == strcmp(pt,"ES") || 0 == strcmp(pt,"es") || 0 == strcmp(pt,"Es") || 0 == strcmp(pt,"eS") )
{
return 0x0d;
}
if( 0 == strcmp(pt,"DS") || 0 == strcmp(pt,"ds") || 0 == strcmp(pt,"Ds") || 0 == strcmp(pt,"dS") )
{
return 0x0e;
}
while(*pt)
{
if(!( ( *pt >= '0' && *pt <= '9' )
|| ( *pt >= 'A' && *pt <= 'F' )
|| ( *pt >= 'a' && *pt <= 'f' )
) )
return -1;
i++;
pt++;
}
if( i > 4) /*如果长度超过四就返回错误代码*/
return -1;
return i;
}
/**/
void show()
{
int n = 0;
int line = 0;
int toff = 0;
toff = offset;
line = (toff%16) == 0?8:9; /*判断是否为16的整数,两种显示的行数不一样,一个为8行,一个为9行*/
dcount = 0,ccount = 0;
for( n = 0 ; n < line ; n++)
{
showLine(toff);
toff += 0x10 - toff%16;
}
}
/*根据传入的便宜地址显示内存数据,以及对应的ascii值*/
void showLine(unsigned int off)
{
unsigned int m = 0;
unsigned int toff = 0,moff = 0;
moff = off ; /*记录实际要开始的内存位置*/
toff = off - off%16; /*toff作为内存为16倍数的地址边界的起始位置*/
printf("%04X:%04X ",sec,toff);
/*显示前面八个,如果要现实的不是从16边界开始,前面显示空格,
dcount < showNum 控制显示数据不超过*/
for( m = 0; m < 8; m++,toff++)
{
if( toff >= moff && dcount < showNum )
{
printf(" %02X",unit(sec,toff));
dcount++;
}
else
printf(" ");
}
/*显示中间的横杠,如果开始处是16的边界后八位,则不现实横杠,*/
if( off%16 < 8 && dcount<showNum)
printf("-");
else
printf(" ");
/*显示后面八位,同理,超过范围就显示空格*/
for( m = 0; m < 8; m++, toff++)
{
if( toff >= moff && dcount<showNum )
{
printf("%02X ",unit(sec,toff));
dcount++;
}
else
printf(" ");
}
printf(" ");
toff = off - off%16; /*数据显示又开始从16边界开始*/
/*显示内存字节对应的ascii符号,不在范围内就显示空格*/
for( m = 0; m < 16; m++, toff++)
{
/**/
if( toff >= moff && ccount<showNum )
{
if( unit(sec,toff) > 32 && unit(sec,toff) < 126)
printf("%c",unit(sec,toff));
else
printf(".");
ccount++;
}
else
printf(" ");
}
printf(" ");
}
/*将十六进制字符串转化为数字*/
int str2Hex( char *pstr)
{
int ans = 0;
char *pt;
pt = pstr;
if( 0 == strcmp(pt,"ds") || 0 == strcmp(pt,"DS") || 0 == strcmp(pt,"Ds") || 0 == strcmp(pt,"dS") )
{
return _DS;
}
else if( 0 == strcmp(pt,"ES") || 0 == strcmp(pt,"es") || 0 == strcmp(pt,"Es") || 0 == strcmp(pt,"eS") )
{
return _ES;
}
while( *pt )
{
ans = ans<<4;
if( ( *pt >= 'A' && *pt <= 'F' ) || ( *pt >= 'a' && *pt <= 'f' ) )
ans = ans | ((*pt & 0x5f) -0x37);
else
ans = ans | (*pt) -0x30;
pt++;
}
return ans;
}
运行效果