724 lines
19 KiB
C
724 lines
19 KiB
C
/*
|
||
* File: int.c
|
||
*
|
||
* Synopsis: PC interrupt caller, memory R/W, I/O port R/W
|
||
*
|
||
* System: MSDOS - Turbo C or Borland C (other compilers need some work)
|
||
*
|
||
* A utility for PC systems programmers to:
|
||
* - perform and visualise the results of interrupt calls
|
||
* - use buffers (inc files) to set register pairs
|
||
* - view the interrupt vector table
|
||
* - read & write I/O ports
|
||
*
|
||
* NB: This utility must be used with EXTREME CARE. Using bad interrupt and/or
|
||
* I/O calls can destroy data on your memory/disk(s) and might crash your
|
||
* machine.
|
||
*
|
||
* Compatible with int.c ditributed with Ralf Brown's interrupt lists
|
||
* Comments/suggestions welcome on the email address below.
|
||
*
|
||
*
|
||
* Copyright (c) 1992-1994 Angelo Haritsis <ah@doc.ic.ac.uk>
|
||
*
|
||
* Redistribution and use in source and binary forms are permitted provided
|
||
* that the above copyright notice and this paragraph are duplicated in all
|
||
* such forms and that any documentation, advertising materials, and other
|
||
* materials related to such distribution and use acknowledge that the
|
||
* software was developed by Angelo Haritsis.
|
||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||
*
|
||
* TODO:
|
||
* > -fbuf filename (write mem with vals from a file)
|
||
*/
|
||
|
||
#ifndef lint
|
||
static char rcsid[] = "$Header: E:/SRC/MISC\RCS\int.c 1.2 1994/04/11 20:11:36 ah Exp ah $";
|
||
#endif
|
||
|
||
#include <stdio.h>
|
||
#include <io.h>
|
||
#include <fcntl.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <assert.h>
|
||
#include <ctype.h>
|
||
#include <dos.h>
|
||
|
||
#define PROG "int"
|
||
#define VERSION "1.0"
|
||
#define NOTREACHED 0
|
||
|
||
|
||
#define PARSE_JUSTARGS 0x01
|
||
#define PARSE_NOACTION 0x02
|
||
|
||
/*
|
||
* Types
|
||
*/
|
||
typedef int (*fun_ptr) (char **, int *);
|
||
|
||
typedef struct s_opt {
|
||
char *opts; /* option name */
|
||
int size; /* bytes for the ptr element (1, 2, 4);
|
||
* 0 means execute the function following
|
||
* parsing (argv, &opt_now)
|
||
*/
|
||
void *ptr; /* pointer to the data element to be loaded or a function if size = 0 */
|
||
} OPTION;
|
||
|
||
typedef struct s_dbuff {
|
||
unsigned *ptr_to_seg; /* the area where the segment is held */
|
||
unsigned *ptr_to_off; /* the area where the offset is held */
|
||
void far *addr; /* the address (when explicitly given) */
|
||
char logo[20];
|
||
#define DBUFF_HEX 0x01
|
||
#define DBUFF_ASC 0x02
|
||
#define DBUFF_BIN 0x04
|
||
int mode; /* display mode */
|
||
long bytes; /* # of bytes to show */
|
||
} DBUFFER;
|
||
|
||
typedef struct s_doserr {
|
||
int errno;
|
||
int class;
|
||
int action;
|
||
int locus;
|
||
} DOS_ERROR;
|
||
|
||
/*
|
||
* Globals
|
||
*/
|
||
char switchchar[] = "-+/";
|
||
|
||
char usage[] =
|
||
"usage: " PROG " [-h] [-q] [int=# | int# | -int #] [[-]reg[=]val] ...\n"
|
||
" [-buf sreg:reg=\"str\"]\n"
|
||
" [-d[a|b|hx] sreg:reg[:#bytes]] [-d[a|hx] faraddr[:#bytes]]\n"
|
||
" [-divt int#-int#]]\n"
|
||
" [-in[w] port#] [-out[w] port#,val]\n"
|
||
" str: printf fmt (%#s allowed to setup buffers)\n";
|
||
|
||
char help[] =
|
||
" eg.\n"
|
||
" o Interrupts (+ buffer setup)\n"
|
||
" " PROG " 0x10 -ax 0x12 same as: int int=0x10 ax=0x12 (set VGA graphics mode)\n"
|
||
" " PROG " 0x10 ah=0x10 al=1 bh=9 (set VGA border color; use to adjust display)\n"
|
||
" " PROG " 0x21 -ah 9 -buf ds:dx=\"hello world\\n$\" -q (INT 21,9 'hello world')\n"
|
||
" " PROG " an_int -buf es:bx=\"%512s\" (creates a scratch buffer of 512 bytes)\n"
|
||
" " PROG " 0x33 ax=9 bx=0 cx=0 -fbuf es:bx=cursor.dat (mouse cursor from file)\n"
|
||
" o Memory (-d: display: called after interrupt)\n"
|
||
" " PROG " -q -dhx 0x400049:18 (BIOS video area data)\n"
|
||
" " PROG " -q es=0x40 -bx 0x49 -dhx es:bx:18 (same as above)\n"
|
||
" " PROG " -q -db 0xF8000000:512 >file (binary dump of AMIBIOS serial data)\n"
|
||
" o IVT\n"
|
||
" " PROG " -q -divt (display vectors from interrupt vector table = IVT)\n"
|
||
" " PROG " -q -divt 0x10-0x1F (display IVT slots 0x10 to 0x1F)\n"
|
||
" o I/O Ports\n"
|
||
" " PROG " -out 0x70,0 -in 0x71 (read seconds from CMOS)\n"
|
||
" " PROG " -out 0x70,0 -out 0x71,0 (zero-out seconds in CMOS)\n";
|
||
|
||
char *int_error[] = {
|
||
NULL,
|
||
"Parse",
|
||
};
|
||
|
||
char str_flags[] = "0N..ODITSZ0A0P1C"; /* 80x86 flag register */
|
||
|
||
union REGS reg;
|
||
struct SREGS sreg;
|
||
unsigned int reg_bp, reg_sp, flags;
|
||
int int_call; /* the interrupt to be called */
|
||
int dos_errno;
|
||
int quiet_mode = 0; /* quiet means just execute int - no reg display * /* does not apply on display
|
||
* opts */
|
||
int buff_now = 0;
|
||
char *buff[10]; /* array of read buffer pointers */
|
||
|
||
int dbuff_now = 0;
|
||
DBUFFER dbuff[10]; /* the buffers to show at end of intr */
|
||
|
||
|
||
/* --- Prototypes --- */
|
||
OPTION *parse_an_opt(char *argv[], int *opt_now, int mode);
|
||
void doit(void);
|
||
void reg_display(void);
|
||
int set_int_val(char **argv, int *opt_now);
|
||
int ivt_display(char **argv, int *opt_now);
|
||
int ioport_out(char **argv, int *opt_now);
|
||
int ioport_in(char **argv, int *opt_now);
|
||
int read_escape(char **p);
|
||
int set_buff(char **argv, int *opt_now);
|
||
int set_fbuff(char **argv, int *opt_now);
|
||
int set_dbuff(char **argv, int *opt_now);
|
||
int dbuff_parse(void **ptr, char *tok);
|
||
int set_dbuff(char **argv, int *opt_now);
|
||
int show_help(char **argv, int *opt_now);
|
||
int set_quiet(char **argv, int *opt_now);
|
||
void error_exit(int err, char *s);
|
||
|
||
/* --- */
|
||
|
||
/*
|
||
* Structure with all the `action' to be done for an option
|
||
* NB: Care with matching prefixes (longer must come first)
|
||
*/
|
||
OPTION Opt[] = {
|
||
|
||
/* NB: put the longer strings first ! */
|
||
|
||
{"$DEFAULT", 0, (void *) set_int_val},
|
||
{"DIVT", 0, (void *) ivt_display}, /* display int vector table */
|
||
{"INT", 2, (void *) &int_call},
|
||
|
||
{"OUTW", 0, (void *) ioport_out}, /* I/O port write, read */
|
||
{"OUT", 0, (void *) ioport_out},
|
||
{"INW", 0, (void *) ioport_in},
|
||
{"IN", 0, (void *) ioport_in},
|
||
|
||
{"DBUF", 0, (void *) set_dbuff},
|
||
{"FBUF", 0, (void *) set_fbuff},
|
||
{"BUF", 0, (void *) set_buff},
|
||
{"DHX", 0, (void *) set_dbuff}, /* display mem contents (hex) */
|
||
|
||
{"FL", 2, (void *) &(reg.x.flags)}, /* set flags (won't affect anything) */
|
||
|
||
{"AX", 2, (void *) &(reg.x.ax)}, /* set general registers */
|
||
{"BX", 2, (void *) &(reg.x.bx)},
|
||
{"CX", 2, (void *) &(reg.x.cx)},
|
||
{"DX", 2, (void *) &(reg.x.dx)},
|
||
{"AH", 1, (void *) &(reg.h.ah)},
|
||
{"BH", 1, (void *) &(reg.h.bh)},
|
||
{"CH", 1, (void *) &(reg.h.ch)},
|
||
{"DH", 1, (void *) &(reg.h.dh)},
|
||
{"AL", 1, (void *) &(reg.h.al)},
|
||
{"BL", 1, (void *) &(reg.h.bl)},
|
||
{"CL", 1, (void *) &(reg.h.cl)},
|
||
{"DL", 1, (void *) &(reg.h.dl)},
|
||
|
||
{"SI", 2, (void *) &(reg.x.si)}, /* set index, stack registers */
|
||
{"DI", 2, (void *) &(reg.x.di)},
|
||
{"BP", 0, 0},
|
||
{"SP", 0, 0},
|
||
|
||
{"CS", 2, (void *) &(sreg.cs)}, /* set segment registers */
|
||
{"DS", 2, (void *) &(sreg.ds)},
|
||
{"ES", 2, (void *) &(sreg.es)},
|
||
{"SS", 2, (void *) &(sreg.ss)},
|
||
|
||
{"DA", 0, (void *) set_dbuff}, /* display mem contents (ascii) */
|
||
{"D", 0, (void *) set_dbuff}, /* display mem contents (ascii+hex) */
|
||
{"Q", 0, (void *) set_quiet}, /* quiet (no disply of reg contents) */
|
||
{"H", 0, (void *) show_help}, /* help */
|
||
};
|
||
|
||
|
||
int cdecl
|
||
main(int argc, char *argv[])
|
||
{
|
||
int opt_now;
|
||
|
||
if (argc == 1)
|
||
error_exit(0, NULL);
|
||
|
||
/* parse the arguments and do proper action */
|
||
for (opt_now = 1; opt_now < argc; opt_now++)
|
||
if (parse_an_opt(argv, &opt_now, 0) == NULL)
|
||
error_exit(1, NULL);
|
||
doit();
|
||
return (0);
|
||
}
|
||
|
||
|
||
/*
|
||
* Parses an argument and calls proper function or assigns numbers
|
||
* accordingly. Reentrant.
|
||
*/
|
||
OPTION *
|
||
parse_an_opt(char *argv[], int *opt_now, int mode)
|
||
{
|
||
int i, arg_len, get_next_arg;
|
||
char *opts, *optarg, *p;
|
||
long val;
|
||
|
||
opts = argv[*opt_now];
|
||
if (strchr(switchchar, opts[0])) /* option starts with a switch char, skip it */
|
||
opts++, argv[*opt_now]++;
|
||
for (i = 0; i < (sizeof(Opt) / sizeof(OPTION)); i++) {
|
||
arg_len = strlen(Opt[i].opts);
|
||
get_next_arg = opts[arg_len] == 0;
|
||
if (strncmpi(opts, Opt[i].opts, arg_len) == 0) {
|
||
if (mode & PARSE_NOACTION) /* do not perform action */
|
||
return (&Opt[i]); /* just return ptr to Opt slot */
|
||
switch (Opt[i].size) {
|
||
|
||
case 0: /* call the function */
|
||
if (!(mode & PARSE_JUSTARGS) && Opt[i].ptr != (void *) 0)
|
||
if ((*((fun_ptr) Opt[i].ptr)) (argv, opt_now) == 0)
|
||
return (NULL); /* error */
|
||
return (&Opt[i]);
|
||
|
||
case 1: /* ptr is a byte, short, int */
|
||
case 2:
|
||
case 4:
|
||
if (get_next_arg)
|
||
optarg = argv[++(*opt_now)]; /* get next option */
|
||
else
|
||
optarg = opts + arg_len + 1; /* skip a separator (eg =) */
|
||
val = strtol(optarg, &p, 0);
|
||
if (p == optarg)
|
||
return (NULL);
|
||
switch (Opt[i].size) {
|
||
case 1:
|
||
*((char *) Opt[i].ptr) = (char) val;
|
||
break;
|
||
case 2:
|
||
*((short *) Opt[i].ptr) = (short) val;
|
||
break;
|
||
case 4:
|
||
*((long *) Opt[i].ptr) = (long) val;
|
||
break;
|
||
}
|
||
return (&Opt[i]);
|
||
|
||
default:
|
||
assert(NOTREACHED);
|
||
}
|
||
}
|
||
}
|
||
if (mode & PARSE_JUSTARGS)
|
||
return (&Opt[0]); /* default */
|
||
else {
|
||
i = (*((fun_ptr) Opt[0].ptr)) (argv, opt_now); /* default */
|
||
return (i == 0 ? NULL : &Opt[0]);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Call the interrupt if asked and display the result buffers
|
||
*/
|
||
void
|
||
doit(void)
|
||
{
|
||
int i;
|
||
long j;
|
||
unsigned char far *ptr;
|
||
unsigned char b;
|
||
|
||
dos_errno = 0;
|
||
if (int_call != -1) {
|
||
reg_bp = _BP;
|
||
reg_sp = _SP;
|
||
flags = _FLAGS;
|
||
reg_display();
|
||
}
|
||
if (int_call > 0 && int_call < 256) {
|
||
quiet_mode || printf("\nINT: 0x%02X\n", int_call);
|
||
int86x(int_call, ®, ®, &sreg); /**/
|
||
if (reg.x.cflag != 0) /* error occured */
|
||
dos_errno = _doserrno;
|
||
reg_bp = _BP;
|
||
reg_sp = _SP;
|
||
quiet_mode || printf("\n");
|
||
flags = reg.x.flags;
|
||
reg_display();
|
||
if (!quiet_mode && (int_call == 0x21 || int_call == 0x24)) /* dos call */
|
||
printf("DOSERR: %04X (%u)\n", dos_errno, dos_errno);
|
||
}
|
||
/* display dbuffers */
|
||
|
||
for (i = 0; i < dbuff_now; i++) {
|
||
ptr = (unsigned char far *) MK_FP(*(dbuff[i].ptr_to_seg), *(dbuff[i].ptr_to_off));
|
||
|
||
if (dbuff[i].mode & DBUFF_BIN) /* binary */
|
||
setmode(1, O_BINARY);
|
||
else
|
||
printf("\n*<%s> {\n", dbuff[i].logo);
|
||
for (j = 0; j < dbuff[i].bytes; j++, ptr++) {
|
||
b = *ptr & 0x00FF; /* byte to display */
|
||
if (dbuff[i].mode & DBUFF_BIN) { /* binary */
|
||
putchar(b);
|
||
continue; /* nothing else */
|
||
}
|
||
if (dbuff[i].mode & DBUFF_HEX)
|
||
printf("%02X", b);
|
||
if (dbuff[i].mode == DBUFF_ASC)
|
||
putchar(iscntrl(b) ? '.' : b);
|
||
else if (dbuff[i].mode & DBUFF_ASC)
|
||
printf("(%c)", iscntrl(b) ? '.' : b);
|
||
if (dbuff[i].mode != DBUFF_ASC)
|
||
printf(" ");
|
||
}
|
||
fflush(stdout);
|
||
if (dbuff[i].mode & DBUFF_BIN) /* binary */
|
||
setmode(1, O_TEXT);
|
||
else
|
||
printf("}\n");
|
||
}
|
||
/* free the read buffers allocated */
|
||
for (i = 0; i < buff_now; i++)
|
||
free(buff[i]);
|
||
}
|
||
|
||
void
|
||
reg_display(void)
|
||
{
|
||
char s[32];
|
||
int i, bit_on;
|
||
|
||
if (quiet_mode)
|
||
return;
|
||
printf(
|
||
"AX=%04X BX=%04X CX=%04X DX=%04X\n"
|
||
"SI=%04X DI=%04X BP=%04X SP=%04X\n"
|
||
"CS=%04X DS=%04X ES=%04X SS=%04X",
|
||
reg.x.ax, reg.x.bx, reg.x.cx, reg.x.dx,
|
||
reg.x.si, reg.x.di, reg_bp, reg_sp,
|
||
sreg.cs, sreg.ds, sreg.es, sreg.ss);
|
||
strncpy(s, str_flags, 32); /* use a scratch copy */
|
||
/* and now the flags */
|
||
flags = reg.x.flags;
|
||
for (i = 0; i < 16; i++) {
|
||
bit_on = (flags & ((unsigned) 0x8000 >> i)) != 0;
|
||
if (s[i] == '.')
|
||
s[i] = bit_on ? '1' : '0';
|
||
else
|
||
s[i] = bit_on ? s[i] : tolower(s[i]);
|
||
}
|
||
printf(" CPU Flags: %16s\n", s);
|
||
}
|
||
|
||
/*
|
||
* 'default' argument function - see if it is an interrupt
|
||
*/
|
||
int
|
||
set_int_val(char **argv, int *opt_now)
|
||
{
|
||
long val;
|
||
char *p;
|
||
|
||
val = strtol(argv[*opt_now], &p, 0);
|
||
if (val <= 0 || val > 255 || p - argv[*opt_now] != strlen(argv[*opt_now]))
|
||
return (0); /* problems */
|
||
int_call = (int) val;
|
||
return (1);
|
||
}
|
||
|
||
/*
|
||
* Display a slot of the Interrupt Vector Table
|
||
*/
|
||
int
|
||
ivt_display(char **argv, int *opt_now)
|
||
{
|
||
char sfrom[20], sto[20];
|
||
int from, to, i;
|
||
void far *p;
|
||
|
||
if ((i = sscanf(argv[*opt_now + 1], "%[0-9xX]-%s", sfrom, sto)) == 2) { /* is a range given ? */
|
||
(*opt_now)++; /* consume next arg */
|
||
from = (int) strtol(sfrom, (char **) &sfrom, 0);
|
||
to = (int) strtol(sto, (char **) &sto, 0);
|
||
} else {
|
||
from = 0;
|
||
to = 255;
|
||
}
|
||
/* do it now */
|
||
printf("Interrupt Vector Table (0x%02X to 0x%02X)\n", from, to);
|
||
for (i = from; i <= to; i++) {
|
||
disable(); /* just in case ... */
|
||
p = (void far *) *((long far *) (4L * i));
|
||
enable();
|
||
printf(" * 0x%02X (%3u): %Fp\n", i, i, p);
|
||
}
|
||
printf("\n");
|
||
return (1);
|
||
}
|
||
|
||
int
|
||
ioport_out(char **argv, int *opt_now)
|
||
{
|
||
char *optarg, sport[10], sval[10];
|
||
int word_op, port, val;
|
||
|
||
optarg = argv[*opt_now];
|
||
word_op = (toupper(optarg[3]) == 'W') ? 1 : 0;
|
||
if (isdigit(optarg[3 + word_op])) /* arg follows with no delimiter */
|
||
optarg += 3 + word_op;
|
||
else
|
||
optarg = argv[++(*opt_now)];
|
||
if (sscanf(optarg, "%[^ ,;]%*[ ,;]%s", sport, sval) != 2)
|
||
return (0);
|
||
port = (int) strtol(sport, (char **) &sport, 0);
|
||
val = (int) strtol(sval, (char **) &sval, 0);
|
||
if (word_op)
|
||
outport(port, (unsigned) val);
|
||
else
|
||
outportb(port, val);
|
||
int_call = -1;
|
||
return (1);
|
||
}
|
||
|
||
int
|
||
ioport_in(char **argv, int *opt_now)
|
||
{
|
||
char *optarg, sport[10];
|
||
int word_op, port, val;
|
||
|
||
optarg = argv[*opt_now];
|
||
word_op = (toupper(optarg[2]) == 'W') ? 1 : 0;
|
||
if (isdigit(optarg[2 + word_op])) /* arg follows with no delimiter */
|
||
optarg += 2 + word_op;
|
||
else
|
||
optarg = argv[++(*opt_now)];
|
||
if (sscanf(optarg, "%s", sport) != 1)
|
||
return (0);
|
||
port = (int) strtol(sport, (char **) &sport, 0);
|
||
if (word_op) {
|
||
val = inport(port);
|
||
quiet_mode || printf("INW 0x%04X (%5u): 0x%04X (%5u)\n", port, port, val, val);
|
||
} else {
|
||
val = inportb(port);
|
||
quiet_mode || printf("IN 0x%04X (%5u): 0x%02X (%3u)\n", port, port, val, val);
|
||
}
|
||
quiet_mode || printf("\n");
|
||
int_call = -1;
|
||
return (1);
|
||
}
|
||
|
||
#define ESCAPES 10
|
||
static int esc_to_code[ESCAPES][2] = {
|
||
{'n', '\n'},
|
||
{'t', '\t'},
|
||
{'v', '\v'},
|
||
{'b', 'b'},
|
||
{'r', '\r'},
|
||
{'f', '\f'},
|
||
{'a', '\a'},
|
||
{'\\', '\\'},
|
||
{'\?', '?'},
|
||
{'\'', '\''},
|
||
};
|
||
|
||
/*
|
||
* returns with *p pointing to char after the one(s) consumed
|
||
*/
|
||
int
|
||
read_escape(char **p)
|
||
{
|
||
int i;
|
||
|
||
if (isdigit(**p)) /* octal */
|
||
return ((int) strtol(*p, p, 8));
|
||
else if (**p == 'x') /* hex */
|
||
return ((int) strtol(*p + 1, p, 16));
|
||
for (i = 0; i < ESCAPES; i++)
|
||
if (**p == esc_to_code[i][0]) {
|
||
(*p)++; /* consume it */
|
||
return (esc_to_code[i][1]);
|
||
}
|
||
/* otherwise, return the character un-translated */
|
||
(*p)++; /* consume it */
|
||
return (**p);
|
||
}
|
||
|
||
|
||
/*
|
||
* load seg register values to point ot the created buffer
|
||
*/
|
||
void
|
||
load_regpair(char *s_seg, char *s_off, void far *buff)
|
||
{
|
||
int len;
|
||
char stmp[50], *argv_fake[3];
|
||
|
||
/* load the regs */
|
||
argv_fake[0] = stmp;
|
||
argv_fake[1] = "";
|
||
len = 0;
|
||
sprintf(stmp, "-%s 0x%X", s_seg, FP_SEG(buff));
|
||
parse_an_opt(argv_fake, (int *) &len, PARSE_JUSTARGS); /* make it think it's an option */
|
||
sprintf(stmp, "-%s 0x%X", s_off, FP_OFF(buff));
|
||
parse_an_opt(argv_fake, (int *) &len, PARSE_JUSTARGS); /* and again for offs register */
|
||
}
|
||
|
||
/*
|
||
* set registers accordingly
|
||
*/
|
||
int
|
||
set_buff(char **argv, int *opt_now)
|
||
{
|
||
char *optarg, *p, *dp;
|
||
char s_seg[10], s_off[10];
|
||
char stmp[50];
|
||
static char dummy[] = ""; /* for case of %s in fmt str */
|
||
unsigned int len;
|
||
|
||
optarg = argv[++(*opt_now)]; /* s_off pair */
|
||
sscanf(optarg, "%[^:]:%s", &s_seg, &s_off);
|
||
if (s_off[2] == '=')
|
||
s_off[2] = 0;
|
||
optarg = argv[++(*opt_now)]; /* printf like string */
|
||
/* how big a buffer ? */
|
||
len = strlen(optarg);
|
||
/* add the %# lengths (extra buffer space) */
|
||
for (p = strchr(optarg, '%'); p != NULL; p = strchr(p + 1, '%'))
|
||
len += atoi(p + 1);
|
||
|
||
if ((buff[buff_now] = (char *) malloc(len)) == NULL)
|
||
return (0);
|
||
/* create escape chars again (since cmd processing makes \ into \\) */
|
||
p = optarg, dp = stmp;
|
||
while (*p)
|
||
if (*p == '\\') {
|
||
p++; /* consume \ */
|
||
*dp++ = read_escape(&p);
|
||
} else
|
||
*dp++ = *p++;
|
||
|
||
/* load the buffer; 5 % fields are enough (XXX ..f func problem if \0 appears before end of fmt) */
|
||
sprintf(buff[buff_now], stmp, dummy, dummy, dummy, dummy, dummy);
|
||
|
||
load_regpair(s_seg, s_off, (void far *) buff[buff_now]);
|
||
buff_now++;
|
||
return (1);
|
||
}
|
||
|
||
/*
|
||
* set register pair to point to buffer with data from a file
|
||
*/
|
||
int
|
||
set_fbuff(char **argv, int *opt_now)
|
||
{
|
||
char *optarg, *fname;
|
||
char s_seg[10], s_off[80];
|
||
long len;
|
||
FILE *f;
|
||
|
||
optarg = argv[++(*opt_now)]; /* s_off pair */
|
||
sscanf(optarg, "%[^:]:%s", &s_seg, &s_off);
|
||
if (s_off[2] == '=') {
|
||
s_off[2] = 0;
|
||
fname = &s_off[3];
|
||
} else
|
||
return (0);
|
||
|
||
if ((f = fopen(fname, "rb")) == NULL)
|
||
return (0);
|
||
len = filelength(fileno(f));
|
||
if (len > 65500L || (buff[buff_now] = (char *) malloc((unsigned int)len)) == NULL)
|
||
return (0);
|
||
if (fread(buff[buff_now], (int) len, 1, f) != 1)
|
||
return (0);
|
||
load_regpair(s_seg, s_off, (void far *) buff[buff_now]);
|
||
buff_now++;
|
||
fclose(f);
|
||
return (1);
|
||
}
|
||
|
||
int
|
||
dbuff_parse(void **ptr, char *tok)
|
||
{
|
||
char stmp[50], *argv_fake[3];
|
||
OPTION *p_opt;
|
||
int len = 0;
|
||
|
||
argv_fake[0] = stmp;
|
||
argv_fake[1] = "";
|
||
sprintf(stmp, "-%s 0", tok);
|
||
p_opt = parse_an_opt(argv_fake, &len, PARSE_JUSTARGS | PARSE_NOACTION);
|
||
if (p_opt == NULL || p_opt == &Opt[0])
|
||
return (0);
|
||
*ptr = (unsigned *) p_opt->ptr;
|
||
return (1);
|
||
}
|
||
|
||
/*
|
||
* add to the list of the buffers to be displayed at end
|
||
*/
|
||
int
|
||
set_dbuff(char **argv, int *opt_now)
|
||
{
|
||
char mode_char;
|
||
char *optarg, *p;
|
||
char tok[3][15]; /* max 3 tokens of 15 chars each */
|
||
int i;
|
||
long addr;
|
||
unsigned long num = 1L; /* number of bytes to display */
|
||
DBUFFER *dpb;
|
||
|
||
dpb = &dbuff[dbuff_now];
|
||
dpb->mode = DBUFF_HEX | DBUFF_ASC;
|
||
mode_char = toupper(argv[*opt_now][1]);
|
||
dpb->mode &= (mode_char == 'A') ? ~DBUFF_HEX : ~0;
|
||
dpb->mode &= (mode_char == 'H') ? ~DBUFF_ASC : ~0;
|
||
if (mode_char == 'B') { /* binary mode */
|
||
dpb->mode &= ~(DBUFF_HEX | DBUFF_ASC);
|
||
dpb->mode |= DBUFF_BIN;
|
||
}
|
||
optarg = argv[++(*opt_now)]; /* reg pair */
|
||
strncpy(dpb->logo, optarg, 20);
|
||
/* collect tokens */
|
||
for (i = 0, p = strtok(optarg, ":="); p; p = strtok(NULL, ":="))
|
||
strcpy(tok[i++], p);
|
||
if (i > 3)
|
||
return (0);
|
||
/* process them */
|
||
addr = strtoul(tok[0], &p, 0);
|
||
if ((p - tok[0]) > 0) { /* first is addr */
|
||
if (i > 1) { /* there's a 2nd token */
|
||
num = strtoul(tok[1], &p, 0);
|
||
if ((p - tok[1]) == 0 || num == 0)
|
||
return (0); /* wrong argument */
|
||
}
|
||
dpb->addr = (void far *) addr;
|
||
dpb->ptr_to_off = (unsigned *) &(dpb->addr);
|
||
dpb->ptr_to_seg = ((unsigned *) &(dpb->addr)) + 1;
|
||
} else { /* should be Reg:Reg[:#] format */
|
||
if (dbuff_parse((void **) &(dpb->ptr_to_seg), tok[0]) == 0)
|
||
return (0);
|
||
if (dbuff_parse((void **) &(dpb->ptr_to_off), tok[1]) == 0)
|
||
return (0);
|
||
if (i > 2) { /* num argument */
|
||
num = strtoul(tok[2], &p, 0);
|
||
if ((p - tok[2]) == 0 || num == 0)
|
||
return (0); /* wrong argument */
|
||
}
|
||
}
|
||
dpb->bytes = num;
|
||
dbuff_now++; /* have inserted an element */
|
||
return (1);
|
||
}
|
||
|
||
int
|
||
set_quiet(char **argv, int *opt_now)
|
||
{
|
||
argv = argv, opt_now = opt_now; /* eliminate warning */
|
||
return (quiet_mode = 1);
|
||
}
|
||
|
||
#define fmsg stdout /* DOS stderr cannot be redir'ed >:-{ */
|
||
|
||
int
|
||
show_help(char **argv, int *opt_now)
|
||
{
|
||
argv = argv, opt_now = opt_now; /* eliminate warning */
|
||
fprintf(fmsg,
|
||
PROG ": Execute and investigate interrupts/system data (ver " VERSION ")\n"
|
||
"Copyright (c) 1992-1994 A. Haritsis <ah@doc.ic.ac.uk>. Distribute freely.\n");
|
||
error_exit(0, help);
|
||
return (1);
|
||
}
|
||
|
||
void
|
||
error_exit(int err, char *s)
|
||
{
|
||
if (err > 0)
|
||
fprintf(fmsg, PROG ": %s error\n", int_error[err]);
|
||
fprintf(fmsg, "%s", usage);
|
||
if (s != NULL)
|
||
fprintf(fmsg, "%s", s);
|
||
exit(err);
|
||
}
|