home *** CD-ROM | disk | FTP | other *** search
/ POINT Software Programming / PPROG1.ISO / misc / inter41 / int.c < prev    next >
Text File  |  1994-04-11  |  20KB  |  724 lines

  1. /*
  2.  * File:    int.c
  3.  *
  4.  * Synopsis:    PC interrupt caller, memory R/W, I/O port R/W
  5.  *
  6.  * System:    MSDOS - Turbo C or Borland C (other compilers need some work)
  7.  *
  8.  * A utility for PC systems programmers to:
  9.  *    - perform and visualise the results of interrupt calls
  10.  *    - use buffers (inc files) to set register pairs
  11.  *    - view the interrupt vector table
  12.  *    - read & write I/O ports
  13.  *
  14.  * NB: This utility must be used with EXTREME CARE. Using bad interrupt and/or
  15.  * I/O calls can destroy data on your memory/disk(s) and might crash your
  16.  * machine.
  17.  *
  18.  * Compatible with int.c ditributed with Ralf Brown's interrupt lists
  19.  * Comments/suggestions welcome on the email address below.
  20.  *
  21.  *
  22.  * Copyright (c) 1992-1994 Angelo Haritsis <ah@doc.ic.ac.uk>
  23.  *
  24.  * Redistribution and use in source and binary forms are permitted provided
  25.  * that the above copyright notice and this paragraph are duplicated in all
  26.  * such forms and that any documentation, advertising materials, and other
  27.  * materials related to such distribution and use acknowledge that the
  28.  * software was developed by Angelo Haritsis.
  29.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  30.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  31.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  32.  *
  33.  * TODO:
  34.  * > -fbuf filename (write mem with vals from a file)
  35.  */
  36.  
  37. #ifndef lint
  38. static char rcsid[] = "$Header: E:/SRC/MISC\RCS\int.c 1.2 1994/04/11 20:11:36 ah Exp ah $";
  39. #endif
  40.  
  41. #include <stdio.h>
  42. #include <io.h>
  43. #include <fcntl.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <assert.h>
  47. #include <ctype.h>
  48. #include <dos.h>
  49.  
  50. #define PROG "int"
  51. #define VERSION "1.0"
  52. #define NOTREACHED 0
  53.  
  54.  
  55. #define PARSE_JUSTARGS    0x01
  56. #define PARSE_NOACTION    0x02
  57.  
  58. /*
  59.  * Types
  60.  */
  61. typedef int (*fun_ptr) (char **, int *);
  62.  
  63. typedef struct s_opt {
  64.     char *opts;        /* option name */
  65.     int size;        /* bytes for the ptr element (1, 2, 4);
  66.                  * 0 means execute the function following
  67.                  * parsing (argv, &opt_now)
  68.                  */
  69.     void *ptr;        /* pointer to the data element to be loaded or a function if size = 0 */
  70. } OPTION;
  71.  
  72. typedef struct s_dbuff {
  73.     unsigned *ptr_to_seg;    /* the area where the segment is held */
  74.     unsigned *ptr_to_off;    /* the area where the offset is held */
  75.     void far *addr;     /* the address (when explicitly given) */
  76.     char logo[20];
  77. #define DBUFF_HEX 0x01
  78. #define DBUFF_ASC 0x02
  79. #define DBUFF_BIN 0x04
  80.     int mode;        /* display mode */
  81.     long bytes;        /* # of bytes to show */
  82. } DBUFFER;
  83.  
  84. typedef struct s_doserr {
  85.     int errno;
  86.     int class;
  87.     int action;
  88.     int locus;
  89. } DOS_ERROR;
  90.  
  91. /*
  92.  * Globals
  93.  */
  94. char switchchar[] = "-+/";
  95.  
  96. char usage[] =
  97. "usage: " PROG " [-h] [-q] [int=# | int# | -int #] [[-]reg[=]val] ...\n"
  98. "       [-buf sreg:reg=\"str\"]\n"
  99. "       [-d[a|b|hx] sreg:reg[:#bytes]] [-d[a|hx] faraddr[:#bytes]]\n"
  100. "       [-divt int#-int#]]\n"
  101. "       [-in[w] port#] [-out[w] port#,val]\n"
  102. "       str: printf fmt (%#s allowed to setup buffers)\n";
  103.  
  104. char help[] =
  105. " eg.\n"
  106. "     o Interrupts (+ buffer setup)\n"
  107. "       " PROG " 0x10 -ax 0x12 same as: int int=0x10 ax=0x12 (set VGA graphics mode)\n"
  108. "       " PROG " 0x10 ah=0x10 al=1 bh=9 (set VGA border color; use to adjust display)\n"
  109. "       " PROG " 0x21 -ah 9 -buf ds:dx=\"hello world\\n$\" -q (INT 21,9 'hello world')\n"
  110. "       " PROG " an_int -buf es:bx=\"%512s\" (creates a scratch buffer of 512 bytes)\n"
  111. "       " PROG " 0x33 ax=9 bx=0 cx=0 -fbuf es:bx=cursor.dat (mouse cursor from file)\n"
  112. "     o Memory (-d: display: called after interrupt)\n"
  113. "       " PROG " -q -dhx 0x400049:18 (BIOS video area data)\n"
  114. "       " PROG " -q es=0x40 -bx 0x49 -dhx es:bx:18 (same as above)\n"
  115. "       " PROG " -q -db 0xF8000000:512 >file (binary dump of AMIBIOS serial data)\n"
  116. "     o IVT\n"
  117. "       " PROG " -q -divt (display vectors from interrupt vector table = IVT)\n"
  118. "       " PROG " -q -divt 0x10-0x1F (display IVT slots 0x10 to 0x1F)\n"
  119. "     o I/O Ports\n"
  120. "       " PROG " -out 0x70,0 -in 0x71 (read seconds from CMOS)\n"
  121. "       " PROG " -out 0x70,0 -out 0x71,0 (zero-out seconds in CMOS)\n";
  122.  
  123. char *int_error[] = {
  124.     NULL,
  125.     "Parse",
  126. };
  127.  
  128. char str_flags[] = "0N..ODITSZ0A0P1C";  /* 80x86 flag register */
  129.  
  130. union REGS reg;
  131. struct SREGS sreg;
  132. unsigned int reg_bp, reg_sp, flags;
  133. int int_call;            /* the interrupt to be called */
  134. int dos_errno;
  135. int quiet_mode = 0;        /* quiet means just execute int - no reg display * /* does not apply on display
  136.                  * opts */
  137. int buff_now = 0;
  138. char *buff[10];         /* array of read buffer pointers */
  139.  
  140. int dbuff_now = 0;
  141. DBUFFER dbuff[10];        /* the buffers to show at end of intr */
  142.  
  143.  
  144. /* --- Prototypes --- */
  145. OPTION *parse_an_opt(char *argv[], int *opt_now, int mode);
  146. void doit(void);
  147. void reg_display(void);
  148. int set_int_val(char **argv, int *opt_now);
  149. int ivt_display(char **argv, int *opt_now);
  150. int ioport_out(char **argv, int *opt_now);
  151. int ioport_in(char **argv, int *opt_now);
  152. int read_escape(char **p);
  153. int set_buff(char **argv, int *opt_now);
  154. int set_fbuff(char **argv, int *opt_now);
  155. int set_dbuff(char **argv, int *opt_now);
  156. int dbuff_parse(void **ptr, char *tok);
  157. int set_dbuff(char **argv, int *opt_now);
  158. int show_help(char **argv, int *opt_now);
  159. int set_quiet(char **argv, int *opt_now);
  160. void error_exit(int err, char *s);
  161.  
  162. /* --- */
  163.  
  164. /*
  165.  * Structure with all the `action' to be done for an option
  166.  * NB: Care with matching prefixes (longer must come first)
  167.  */
  168. OPTION Opt[] = {
  169.  
  170.     /* NB: put the longer strings first ! */
  171.  
  172.     {"$DEFAULT", 0, (void *) set_int_val},
  173.     {"DIVT", 0, (void *) ivt_display},      /* display int vector table */
  174.     {"INT", 2, (void *) &int_call},
  175.  
  176.     {"OUTW", 0, (void *) ioport_out},       /* I/O port write, read */
  177.     {"OUT", 0, (void *) ioport_out},
  178.     {"INW", 0, (void *) ioport_in},
  179.     {"IN", 0, (void *) ioport_in},
  180.  
  181.     {"DBUF", 0, (void *) set_dbuff},
  182.     {"FBUF", 0, (void *) set_fbuff},
  183.     {"BUF", 0, (void *) set_buff},
  184.     {"DHX", 0, (void *) set_dbuff},         /* display mem contents (hex) */
  185.  
  186.     {"FL", 2, (void *) &(reg.x.flags)},     /* set flags (won't affect anything) */
  187.  
  188.     {"AX", 2, (void *) &(reg.x.ax)},        /* set general registers */
  189.     {"BX", 2, (void *) &(reg.x.bx)},
  190.     {"CX", 2, (void *) &(reg.x.cx)},
  191.     {"DX", 2, (void *) &(reg.x.dx)},
  192.     {"AH", 1, (void *) &(reg.h.ah)},
  193.     {"BH", 1, (void *) &(reg.h.bh)},
  194.     {"CH", 1, (void *) &(reg.h.ch)},
  195.     {"DH", 1, (void *) &(reg.h.dh)},
  196.     {"AL", 1, (void *) &(reg.h.al)},
  197.     {"BL", 1, (void *) &(reg.h.bl)},
  198.     {"CL", 1, (void *) &(reg.h.cl)},
  199.     {"DL", 1, (void *) &(reg.h.dl)},
  200.  
  201.     {"SI", 2, (void *) &(reg.x.si)},        /* set index, stack registers */
  202.     {"DI", 2, (void *) &(reg.x.di)},
  203.     {"BP", 0, 0},
  204.     {"SP", 0, 0},
  205.  
  206.     {"CS", 2, (void *) &(sreg.cs)},         /* set segment registers */
  207.     {"DS", 2, (void *) &(sreg.ds)},
  208.     {"ES", 2, (void *) &(sreg.es)},
  209.     {"SS", 2, (void *) &(sreg.ss)},
  210.  
  211.     {"DA", 0, (void *) set_dbuff},          /* display mem contents (ascii) */
  212.     {"D", 0, (void *) set_dbuff},           /* display mem contents (ascii+hex) */
  213.     {"Q", 0, (void *) set_quiet},           /* quiet (no disply of reg contents) */
  214.     {"H", 0, (void *) show_help},           /* help */
  215. };
  216.  
  217.  
  218. int cdecl
  219. main(int argc, char *argv[])
  220. {
  221.     int opt_now;
  222.  
  223.     if (argc == 1)
  224.         error_exit(0, NULL);
  225.  
  226.     /* parse the arguments and do proper action */
  227.     for (opt_now = 1; opt_now < argc; opt_now++)
  228.         if (parse_an_opt(argv, &opt_now, 0) == NULL)
  229.             error_exit(1, NULL);
  230.     doit();
  231.     return (0);
  232. }
  233.  
  234.  
  235. /*
  236.  * Parses an argument and calls proper function or assigns numbers
  237.  * accordingly. Reentrant.
  238.  */
  239. OPTION *
  240. parse_an_opt(char *argv[], int *opt_now, int mode)
  241. {
  242.     int i, arg_len, get_next_arg;
  243.     char *opts, *optarg, *p;
  244.     long val;
  245.  
  246.     opts = argv[*opt_now];
  247.     if (strchr(switchchar, opts[0]))    /* option starts with a switch char, skip it */
  248.         opts++, argv[*opt_now]++;
  249.     for (i = 0; i < (sizeof(Opt) / sizeof(OPTION)); i++) {
  250.         arg_len = strlen(Opt[i].opts);
  251.         get_next_arg = opts[arg_len] == 0;
  252.         if (strncmpi(opts, Opt[i].opts, arg_len) == 0) {
  253.             if (mode & PARSE_NOACTION)    /* do not perform action */
  254.                 return (&Opt[i]);    /* just return ptr to Opt slot */
  255.             switch (Opt[i].size) {
  256.  
  257.             case 0: /* call the function */
  258.                 if (!(mode & PARSE_JUSTARGS) && Opt[i].ptr != (void *) 0)
  259.                     if ((*((fun_ptr) Opt[i].ptr)) (argv, opt_now) == 0)
  260.                         return (NULL);    /* error */
  261.                 return (&Opt[i]);
  262.  
  263.             case 1: /* ptr is a byte, short, int */
  264.             case 2:
  265.             case 4:
  266.                 if (get_next_arg)
  267.                     optarg = argv[++(*opt_now)];    /* get next option */
  268.                 else
  269.                     optarg = opts + arg_len + 1;    /* skip a separator (eg =) */
  270.                 val = strtol(optarg, &p, 0);
  271.                 if (p == optarg)
  272.                     return (NULL);
  273.                 switch (Opt[i].size) {
  274.                 case 1:
  275.                     *((char *) Opt[i].ptr) = (char) val;
  276.                     break;
  277.                 case 2:
  278.                     *((short *) Opt[i].ptr) = (short) val;
  279.                     break;
  280.                 case 4:
  281.                     *((long *) Opt[i].ptr) = (long) val;
  282.                     break;
  283.                 }
  284.                 return (&Opt[i]);
  285.  
  286.             default:
  287.                 assert(NOTREACHED);
  288.             }
  289.         }
  290.     }
  291.     if (mode & PARSE_JUSTARGS)
  292.         return (&Opt[0]);    /* default */
  293.     else {
  294.         i = (*((fun_ptr) Opt[0].ptr)) (argv, opt_now);    /* default */
  295.         return (i == 0 ? NULL : &Opt[0]);
  296.     }
  297. }
  298.  
  299. /*
  300.  * Call the interrupt if asked and display the result buffers
  301.  */
  302. void
  303. doit(void)
  304. {
  305.     int i;
  306.     long j;
  307.     unsigned char far *ptr;
  308.     unsigned char b;
  309.  
  310.     dos_errno = 0;
  311.     if (int_call != -1) {
  312.         reg_bp = _BP;
  313.         reg_sp = _SP;
  314.         flags = _FLAGS;
  315.         reg_display();
  316.     }
  317.     if (int_call > 0 && int_call < 256) {
  318.         quiet_mode || printf("\nINT: 0x%02X\n", int_call);
  319.         int86x(int_call, ®, ®, &sreg);    /**/
  320.         if (reg.x.cflag != 0)    /* error occured */
  321.             dos_errno = _doserrno;
  322.         reg_bp = _BP;
  323.         reg_sp = _SP;
  324.         quiet_mode || printf("\n");
  325.         flags = reg.x.flags;
  326.         reg_display();
  327.         if (!quiet_mode && (int_call == 0x21 || int_call == 0x24))    /* dos call */
  328.             printf("DOSERR: %04X (%u)\n", dos_errno, dos_errno);
  329.     }
  330.     /* display dbuffers */
  331.  
  332.     for (i = 0; i < dbuff_now; i++) {
  333.         ptr = (unsigned char far *) MK_FP(*(dbuff[i].ptr_to_seg), *(dbuff[i].ptr_to_off));
  334.  
  335.         if (dbuff[i].mode & DBUFF_BIN)        /* binary */
  336.             setmode(1, O_BINARY);
  337.         else
  338.             printf("\n*<%s> {\n", dbuff[i].logo);
  339.         for (j = 0; j < dbuff[i].bytes; j++, ptr++) {
  340.             b = *ptr & 0x00FF;        /* byte to display */
  341.             if (dbuff[i].mode & DBUFF_BIN) {    /* binary */
  342.                 putchar(b);
  343.                 continue;    /* nothing else */
  344.             }
  345.             if (dbuff[i].mode & DBUFF_HEX)
  346.                 printf("%02X", b);
  347.             if (dbuff[i].mode == DBUFF_ASC)
  348.                 putchar(iscntrl(b) ? '.' : b);
  349.             else if (dbuff[i].mode & DBUFF_ASC)
  350.                 printf("(%c)", iscntrl(b) ? '.' : b);
  351.             if (dbuff[i].mode != DBUFF_ASC)
  352.                 printf(" ");
  353.         }
  354.         fflush(stdout);
  355.         if (dbuff[i].mode & DBUFF_BIN)           /* binary */
  356.             setmode(1, O_TEXT);
  357.         else
  358.             printf("}\n");
  359.     }
  360.     /* free the read buffers allocated */
  361.     for (i = 0; i < buff_now; i++)
  362.         free(buff[i]);
  363. }
  364.  
  365. void
  366. reg_display(void)
  367. {
  368.     char s[32];
  369.     int i, bit_on;
  370.  
  371.     if (quiet_mode)
  372.         return;
  373.     printf(
  374.            "AX=%04X   BX=%04X   CX=%04X   DX=%04X\n"
  375.            "SI=%04X   DI=%04X   BP=%04X   SP=%04X\n"
  376.            "CS=%04X   DS=%04X   ES=%04X   SS=%04X",
  377.            reg.x.ax, reg.x.bx, reg.x.cx, reg.x.dx,
  378.            reg.x.si, reg.x.di, reg_bp, reg_sp,
  379.            sreg.cs, sreg.ds, sreg.es, sreg.ss);
  380.     strncpy(s, str_flags, 32);    /* use a scratch copy */
  381.     /* and now the flags */
  382.     flags = reg.x.flags;
  383.     for (i = 0; i < 16; i++) {
  384.         bit_on = (flags & ((unsigned) 0x8000 >> i)) != 0;
  385.         if (s[i] == '.')
  386.             s[i] = bit_on ? '1' : '0';
  387.         else
  388.             s[i] = bit_on ? s[i] : tolower(s[i]);
  389.     }
  390.     printf("   CPU Flags: %16s\n", s);
  391. }
  392.  
  393. /*
  394.  * 'default' argument function - see if it is an interrupt
  395.  */
  396. int
  397. set_int_val(char **argv, int *opt_now)
  398. {
  399.     long val;
  400.     char *p;
  401.  
  402.     val = strtol(argv[*opt_now], &p, 0);
  403.     if (val <= 0 || val > 255 || p - argv[*opt_now] != strlen(argv[*opt_now]))
  404.         return (0);    /* problems */
  405.     int_call = (int) val;
  406.     return (1);
  407. }
  408.  
  409. /*
  410.  * Display a slot of the Interrupt Vector Table
  411.  */
  412. int
  413. ivt_display(char **argv, int *opt_now)
  414. {
  415.     char sfrom[20], sto[20];
  416.     int from, to, i;
  417.     void far *p;
  418.  
  419.     if ((i = sscanf(argv[*opt_now + 1], "%[0-9xX]-%s", sfrom, sto)) == 2) { /* is a range given ? */
  420.         (*opt_now)++;    /* consume next arg */
  421.         from = (int) strtol(sfrom, (char **) &sfrom, 0);
  422.         to = (int) strtol(sto, (char **) &sto, 0);
  423.     } else {
  424.         from = 0;
  425.         to = 255;
  426.     }
  427.     /* do it now */
  428.     printf("Interrupt Vector Table (0x%02X to 0x%02X)\n", from, to);
  429.     for (i = from; i <= to; i++) {
  430.         disable();    /* just in case ... */
  431.         p = (void far *) *((long far *) (4L * i));
  432.         enable();
  433.         printf(" * 0x%02X (%3u):  %Fp\n", i, i, p);
  434.     }
  435.     printf("\n");
  436.     return (1);
  437. }
  438.  
  439. int
  440. ioport_out(char **argv, int *opt_now)
  441. {
  442.     char *optarg, sport[10], sval[10];
  443.     int word_op, port, val;
  444.  
  445.     optarg = argv[*opt_now];
  446.     word_op = (toupper(optarg[3]) == 'W') ? 1 : 0;
  447.     if (isdigit(optarg[3 + word_op]))    /* arg follows with no delimiter */
  448.         optarg += 3 + word_op;
  449.     else
  450.         optarg = argv[++(*opt_now)];
  451.     if (sscanf(optarg, "%[^ ,;]%*[ ,;]%s", sport, sval) != 2)
  452.         return (0);
  453.     port = (int) strtol(sport, (char **) &sport, 0);
  454.     val = (int) strtol(sval, (char **) &sval, 0);
  455.     if (word_op)
  456.         outport(port, (unsigned) val);
  457.     else
  458.         outportb(port, val);
  459.     int_call = -1;
  460.     return (1);
  461. }
  462.  
  463. int
  464. ioport_in(char **argv, int *opt_now)
  465. {
  466.     char *optarg, sport[10];
  467.     int word_op, port, val;
  468.  
  469.     optarg = argv[*opt_now];
  470.     word_op = (toupper(optarg[2]) == 'W') ? 1 : 0;
  471.     if (isdigit(optarg[2 + word_op]))    /* arg follows with no delimiter */
  472.         optarg += 2 + word_op;
  473.     else
  474.         optarg = argv[++(*opt_now)];
  475.     if (sscanf(optarg, "%s", sport) != 1)
  476.         return (0);
  477.     port = (int) strtol(sport, (char **) &sport, 0);
  478.     if (word_op) {
  479.         val = inport(port);
  480.         quiet_mode || printf("INW 0x%04X (%5u):  0x%04X (%5u)\n", port, port, val, val);
  481.     } else {
  482.         val = inportb(port);
  483.         quiet_mode || printf("IN 0x%04X (%5u):  0x%02X (%3u)\n", port, port, val, val);
  484.     }
  485.     quiet_mode || printf("\n");
  486.     int_call = -1;
  487.     return (1);
  488. }
  489.  
  490. #define ESCAPES 10
  491. static int esc_to_code[ESCAPES][2] = {
  492.     {'n', '\n'},
  493.     {'t', '\t'},
  494.     {'v', '\v'},
  495.     {'b', 'b'},
  496.     {'r', '\r'},
  497.     {'f', '\f'},
  498.     {'a', '\a'},
  499.     {'\\', '\\'},
  500.     {'\?', '?'},
  501.     {'\'', '\''},
  502. };
  503.  
  504. /*
  505.  * returns with *p pointing to char after the one(s) consumed
  506.  */
  507. int
  508. read_escape(char **p)
  509. {
  510.     int i;
  511.  
  512.     if (isdigit(**p))    /* octal */
  513.         return ((int) strtol(*p, p, 8));
  514.     else if (**p == 'x')    /* hex */
  515.         return ((int) strtol(*p + 1, p, 16));
  516.     for (i = 0; i < ESCAPES; i++)
  517.         if (**p == esc_to_code[i][0]) {
  518.             (*p)++; /* consume it */
  519.             return (esc_to_code[i][1]);
  520.         }
  521.     /* otherwise, return the character un-translated */
  522.     (*p)++;         /* consume it */
  523.     return (**p);
  524. }
  525.  
  526.  
  527. /*
  528.  * load seg register values to point ot the created buffer
  529.  */
  530. void
  531. load_regpair(char *s_seg, char *s_off, void far *buff)
  532. {
  533.     int len;
  534.     char stmp[50], *argv_fake[3];
  535.  
  536.     /* load the regs */
  537.     argv_fake[0] = stmp;
  538.     argv_fake[1] = "";
  539.     len = 0;
  540.     sprintf(stmp, "-%s 0x%X", s_seg, FP_SEG(buff));
  541.     parse_an_opt(argv_fake, (int *) &len, PARSE_JUSTARGS);    /* make it think it's an option */
  542.     sprintf(stmp, "-%s 0x%X", s_off, FP_OFF(buff));
  543.     parse_an_opt(argv_fake, (int *) &len, PARSE_JUSTARGS);    /* and again for offs register */
  544. }
  545.  
  546. /*
  547.  * set registers accordingly
  548.  */
  549. int
  550. set_buff(char **argv, int *opt_now)
  551. {
  552.     char *optarg, *p, *dp;
  553.     char s_seg[10], s_off[10];
  554.     char stmp[50];
  555.     static char dummy[] = "";       /* for case of %s in fmt str */
  556.     unsigned int len;
  557.  
  558.     optarg = argv[++(*opt_now)];    /* s_off pair */
  559.     sscanf(optarg, "%[^:]:%s", &s_seg, &s_off);
  560.     if (s_off[2] == '=')
  561.         s_off[2] = 0;
  562.     optarg = argv[++(*opt_now)];    /* printf like string */
  563.     /* how big a buffer ? */
  564.     len = strlen(optarg);
  565.     /* add the %# lengths (extra buffer space) */
  566.     for (p = strchr(optarg, '%'); p != NULL; p = strchr(p + 1, '%'))
  567.         len += atoi(p + 1);
  568.  
  569.     if ((buff[buff_now] = (char *) malloc(len)) == NULL)
  570.         return (0);
  571.     /* create escape chars again (since cmd processing makes \ into \\) */
  572.     p = optarg, dp = stmp;
  573.     while (*p)
  574.         if (*p == '\\') {
  575.             p++;    /* consume \ */
  576.             *dp++ = read_escape(&p);
  577.         } else
  578.             *dp++ = *p++;
  579.  
  580.     /* load the buffer; 5 % fields are enough (XXX ..f func problem if \0 appears before end of fmt) */
  581.     sprintf(buff[buff_now], stmp, dummy, dummy, dummy, dummy, dummy);
  582.  
  583.     load_regpair(s_seg, s_off, (void far *) buff[buff_now]);
  584.     buff_now++;
  585.     return (1);
  586. }
  587.  
  588. /*
  589.  * set register pair to point to buffer with data from a file
  590.  */
  591. int
  592. set_fbuff(char **argv, int *opt_now)
  593. {
  594.     char *optarg, *fname;
  595.     char s_seg[10], s_off[80];
  596.     long len;
  597.     FILE *f;
  598.  
  599.     optarg = argv[++(*opt_now)];    /* s_off pair */
  600.     sscanf(optarg, "%[^:]:%s", &s_seg, &s_off);
  601.     if (s_off[2] == '=') {
  602.         s_off[2] = 0;
  603.         fname = &s_off[3];
  604.     } else
  605.         return (0);
  606.  
  607.     if ((f = fopen(fname, "rb")) == NULL)
  608.         return (0);
  609.     len = filelength(fileno(f));
  610.     if (len > 65500L || (buff[buff_now] = (char *) malloc((unsigned int)len)) == NULL)
  611.         return (0);
  612.     if (fread(buff[buff_now], (int) len, 1, f) != 1)
  613.         return (0);
  614.     load_regpair(s_seg, s_off, (void far *) buff[buff_now]);
  615.     buff_now++;
  616.     fclose(f);
  617.     return (1);
  618. }
  619.  
  620. int
  621. dbuff_parse(void **ptr, char *tok)
  622. {
  623.     char stmp[50], *argv_fake[3];
  624.     OPTION *p_opt;
  625.     int len = 0;
  626.  
  627.     argv_fake[0] = stmp;
  628.     argv_fake[1] = "";
  629.     sprintf(stmp, "-%s 0", tok);
  630.     p_opt = parse_an_opt(argv_fake, &len, PARSE_JUSTARGS | PARSE_NOACTION);
  631.     if (p_opt == NULL || p_opt == &Opt[0])
  632.         return (0);
  633.     *ptr = (unsigned *) p_opt->ptr;
  634.     return (1);
  635. }
  636.  
  637. /*
  638.  * add to the list of the buffers to be displayed at end
  639.  */
  640. int
  641. set_dbuff(char **argv, int *opt_now)
  642. {
  643.     char mode_char;
  644.     char *optarg, *p;
  645.     char tok[3][15];    /* max 3 tokens of 15 chars each */
  646.     int i;
  647.     long addr;
  648.     unsigned long num = 1L; /* number of bytes to display */
  649.     DBUFFER *dpb;
  650.  
  651.     dpb = &dbuff[dbuff_now];
  652.     dpb->mode = DBUFF_HEX | DBUFF_ASC;
  653.     mode_char = toupper(argv[*opt_now][1]);
  654.     dpb->mode &= (mode_char == 'A') ? ~DBUFF_HEX : ~0;
  655.     dpb->mode &= (mode_char == 'H') ? ~DBUFF_ASC : ~0;
  656.     if (mode_char == 'B') {         /* binary mode */
  657.         dpb->mode &= ~(DBUFF_HEX | DBUFF_ASC);
  658.         dpb->mode |= DBUFF_BIN;
  659.     }
  660.     optarg = argv[++(*opt_now)];    /* reg pair */
  661.     strncpy(dpb->logo, optarg, 20);
  662.     /* collect tokens */
  663.     for (i = 0, p = strtok(optarg, ":="); p; p = strtok(NULL, ":="))
  664.         strcpy(tok[i++], p);
  665.     if (i > 3)
  666.         return (0);
  667.     /* process them */
  668.     addr = strtoul(tok[0], &p, 0);
  669.     if ((p - tok[0]) > 0) { /* first is addr */
  670.         if (i > 1) {    /* there's a 2nd token */
  671.             num = strtoul(tok[1], &p, 0);
  672.             if ((p - tok[1]) == 0 || num == 0)
  673.                 return (0);    /* wrong argument */
  674.         }
  675.         dpb->addr = (void far *) addr;
  676.         dpb->ptr_to_off = (unsigned *) &(dpb->addr);
  677.         dpb->ptr_to_seg = ((unsigned *) &(dpb->addr)) + 1;
  678.     } else {        /* should be Reg:Reg[:#] format */
  679.         if (dbuff_parse((void **) &(dpb->ptr_to_seg), tok[0]) == 0)
  680.             return (0);
  681.         if (dbuff_parse((void **) &(dpb->ptr_to_off), tok[1]) == 0)
  682.             return (0);
  683.         if (i > 2) {    /* num argument */
  684.             num = strtoul(tok[2], &p, 0);
  685.             if ((p - tok[2]) == 0 || num == 0)
  686.                 return (0);    /* wrong argument */
  687.         }
  688.     }
  689.     dpb->bytes = num;
  690.     dbuff_now++;        /* have inserted an element */
  691.     return (1);
  692. }
  693.  
  694. int
  695. set_quiet(char **argv, int *opt_now)
  696. {
  697.     argv = argv, opt_now = opt_now; /* eliminate warning */
  698.     return (quiet_mode = 1);
  699. }
  700.  
  701. #define fmsg stdout        /* DOS stderr cannot be redir'ed >:-{ */
  702.  
  703. int
  704. show_help(char **argv, int *opt_now)
  705. {
  706.     argv = argv, opt_now = opt_now; /* eliminate warning */
  707.     fprintf(fmsg,
  708.         PROG ": Execute and investigate interrupts/system data (ver " VERSION ")\n"
  709.         "Copyright (c) 1992-1994 A. Haritsis <ah@doc.ic.ac.uk>. Distribute freely.\n");
  710.     error_exit(0, help);
  711.     return (1);
  712. }
  713.  
  714. void
  715. error_exit(int err, char *s)
  716. {
  717.     if (err > 0)
  718.         fprintf(fmsg, PROG ": %s error\n", int_error[err]);
  719.     fprintf(fmsg, "%s", usage);
  720.     if (s != NULL)
  721.         fprintf(fmsg, "%s", s);
  722.     exit(err);
  723. }
  724.