home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 10 / 10.iso / l / l440 / 2.ddi / CHAP6 / INSTCMD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-14  |  5.5 KB  |  198 lines

  1. /*
  2. INSTCMD.C 
  3.  
  4. The "Installable Command" function is _not_ called by a program that
  5. wants to extend COMMAND.COM's repertoire. Instead, you hook the
  6. function and wait for COMMAND.COM to call you ("don't call us, we'll
  7. call you"). Function AE00h lets you tell COMMAND.COM whether you
  8. want to handle the command, and function AE01h is where you actually
  9. handle it (similar to device driver division of labor between
  10. Strategy and Interrupt).
  11.  
  12. Note that AE01h is called with only the name of the command: not with
  13. any arguments. Therefore, arguments must be saved away in AE00h. Yuk!
  14.  
  15. Furthermore, while redirection _is_ handled in the normal way in
  16. AE01, in AE00 we get the entire command string, including any
  17. redirection or piping. Therefore, these must be stripped off before
  18. saving away the args during AE00 processing.
  19.  
  20. Problem with following 2FAE00 and 2FAE01 handlers: they should
  21. chain to previous handler. For example, with existing code, INTRSPY program
  22. won't see 2FAE00 and 2FAE01 calls once INSTCMD is installed. 
  23.  
  24. The sample COMMAND.COM extension used here is FULLNAME, based on the
  25. undocumented TRUENAME command in DOS 4.x. We simply run undocumented
  26. Function 60h in order to provide FULLNAME. Actually, not _quite_ so
  27. simple, since Function 60h doesn't like leading or trailing spaces.
  28. These are handled inside function fullname().
  29.  
  30. The following INTRSPY script was helpful in debugging 2FAE:
  31.  
  32. ; INSTCMD.SCR
  33. structure cmdline fields
  34.     max (byte)
  35.     text (byte,string,64)
  36.  
  37. intercept 2fh
  38.     function 0aeh
  39.         subfunction 00h
  40.             on_entry
  41.                 if (dx == 0FFFFh)
  42.                     output "AE00" 
  43.                     output (DS:BX->cmdline)
  44.                     output CH        ; FFh first time, 0 second time
  45.                     output ""
  46.         subfunction 01h
  47.             on_entry
  48.                 if (dx == 0FFFFh)
  49.                     output "AE01"
  50.                     output (DS:SI->byte,string,64)
  51.                         
  52. requires Microsoft C 6.0+, or Quick C 2.0+
  53.     cl -qc instcmd.c
  54. */
  55.  
  56. #include <stdlib.h>
  57. #include <stdio.h>
  58. #include <string.h>
  59. #include <ctype.h>
  60. #include <conio.h>
  61. #include <dos.h>
  62.  
  63. #pragma pack(1)
  64.  
  65. typedef struct {
  66.     unsigned es,ds,di,si,bp,sp,bx,dx,cx,ax;
  67.     unsigned ip,cs,flags;
  68.     } REG_PARAMS;
  69.     
  70. typedef unsigned char BYTE;
  71.  
  72. typedef struct {
  73.     BYTE len;
  74.     BYTE txt[1];
  75.     } STRING;
  76.  
  77. typedef struct {
  78.     BYTE max;
  79.     STRING s;
  80.     } CMDLINE;
  81.  
  82. void interrupt far handler_2f(REG_PARAMS r);
  83.  
  84. void (interrupt far *old)();
  85.  
  86. void fail(char *s) { puts(s); exit(1); }
  87.  
  88. main(void)
  89. {
  90.     /* hook INT 2F */
  91.     old = _dos_getvect(0x2f);
  92.     _dos_setvect(0x2f, handler_2f);
  93.     
  94.     puts("This demo of installable commands isn't a TSR.");
  95.     puts("Instead, it just creates a subshell from which you can EXIT");
  96.     puts("when done. In the subshell, one new command has been added:");
  97.     puts("FULLNAME [filename].");
  98.     
  99.     system(getenv("COMSPEC"));
  100.     
  101.     /* unhook INT 2F */
  102.     _dos_setvect(0x2f, old);
  103. }
  104.  
  105. char far *fullname(char far *s, char far *d)
  106. {
  107.     char far *s2;
  108.     
  109.     /* INT 21h AH=60h doesn't like leading or trailing blanks */
  110.     while (isspace(*s))
  111.         s++;
  112.     s2 = s;
  113.     while (*s2) s2++;
  114.     s2--;
  115.     while (isspace(*s2))
  116.         *s2-- = 0;
  117.  
  118.     _asm {
  119.         push di
  120.         push si
  121.         les di, d
  122.         lds si, s
  123.         mov ah, 60h
  124.         int 21h
  125.         pop si
  126.         pop di
  127.         jc error
  128.         }
  129.  
  130.     return d;
  131. error:
  132.     return (char far *) 0;
  133. }
  134.  
  135. void fcputs(char far *s)
  136. {
  137.     /* can't use stdio (e.g., putchar) inside 2FAE01 handler? */
  138.     while (*s) 
  139.         putch(*s++); 
  140.     putch(0x0d); putch(0x0a);
  141. }
  142.  
  143. char buf[128];      /* not reentrant */
  144. char args[128];
  145.  
  146. #define CMD_LEN     8
  147.  
  148. void interrupt far handler_2f(REG_PARAMS r)
  149. {
  150.     if ((r.ax == 0xAE00) && (r.dx == 0xFFFF))
  151.     {
  152.         CMDLINE far *cmdline;
  153.         int len;
  154.         FP_SEG(cmdline) = r.ds;
  155.         FP_OFF(cmdline) = r.bx;
  156.         len = min(CMD_LEN, cmdline->s.len);
  157.         if ((_fmemicmp(cmdline->s.txt, "fullname", len) == 0) ||
  158.             (_fmemicmp(cmdline->s.txt, "FULLNAME", len) == 0))
  159.         {
  160.             char far *redir;
  161.             int argslen = cmdline->s.len - CMD_LEN;
  162.             _fmemcpy(args, cmdline->s.txt + CMD_LEN, argslen);
  163.             args[argslen] = 0;
  164.             /* yuk! we have to get rid of redirection ourselves! */
  165.             /* it will still take effect in AE01 */
  166.             /* the following is not really correct, but okay for now */
  167.             if (redir = _fstrrchr(args, '>'))
  168.                 *redir = 0;
  169.             if (redir = _fstrrchr(args, '<'))
  170.                 *redir = 0;
  171.             if (redir = _fstrrchr(args, '|'))
  172.                 *redir = 0;
  173.             r.ax = 0xAEFF;      /* we will handle this one */
  174.         }
  175.     }
  176.     else if ((r.ax == 0xAE01) && (r.dx == 0xFFFF))
  177.     {
  178.         STRING far *s;
  179.         int len;
  180.         FP_SEG(s) = r.ds;
  181.         FP_OFF(s) = r.si;
  182.         len = min(CMD_LEN, s->len);
  183.         if ((_fmemicmp(s->txt, "fullname", len) == 0) ||
  184.             (_fmemicmp(s->txt, "FULLNAME", len) == 0))
  185.         {
  186.             char far *d;
  187.             if (! *args)
  188.                 d = "syntax: fullname [filename]";
  189.             else if ((d = fullname(args, buf)) == 0)
  190.                 d = "invalid filename";
  191.             fcputs(d);
  192.             s->len = 0; /* we handled it; COMMAND.COM shouldn't */
  193.         }
  194.     }
  195.     else
  196.         _chain_intr(old);
  197. }
  198.