home *** CD-ROM | disk | FTP | other *** search
- /*
- INSTCMD.C
-
- The "Installable Command" function is _not_ called by a program that
- wants to extend COMMAND.COM's repertoire. Instead, you hook the
- function and wait for COMMAND.COM to call you ("don't call us, we'll
- call you"). Function AE00h lets you tell COMMAND.COM whether you
- want to handle the command, and function AE01h is where you actually
- handle it (similar to device driver division of labor between
- Strategy and Interrupt).
-
- Note that AE01h is called with only the name of the command: not with
- any arguments. Therefore, arguments must be saved away in AE00h. Yuk!
-
- Furthermore, while redirection _is_ handled in the normal way in
- AE01, in AE00 we get the entire command string, including any
- redirection or piping. Therefore, these must be stripped off before
- saving away the args during AE00 processing.
-
- Problem with following 2FAE00 and 2FAE01 handlers: they should
- chain to previous handler. For example, with existing code, INTRSPY program
- won't see 2FAE00 and 2FAE01 calls once INSTCMD is installed.
-
- The sample COMMAND.COM extension used here is FULLNAME, based on the
- undocumented TRUENAME command in DOS 4.x. We simply run undocumented
- Function 60h in order to provide FULLNAME. Actually, not _quite_ so
- simple, since Function 60h doesn't like leading or trailing spaces.
- These are handled inside function fullname().
-
- The following INTRSPY script was helpful in debugging 2FAE:
-
- ; INSTCMD.SCR
- structure cmdline fields
- max (byte)
- text (byte,string,64)
-
- intercept 2fh
- function 0aeh
- subfunction 00h
- on_entry
- if (dx == 0FFFFh)
- output "AE00"
- output (DS:BX->cmdline)
- output CH ; FFh first time, 0 second time
- output ""
- subfunction 01h
- on_entry
- if (dx == 0FFFFh)
- output "AE01"
- output (DS:SI->byte,string,64)
-
- requires Microsoft C 6.0+, or Quick C 2.0+
- cl -qc instcmd.c
- */
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <conio.h>
- #include <dos.h>
-
- #pragma pack(1)
-
- typedef struct {
- unsigned es,ds,di,si,bp,sp,bx,dx,cx,ax;
- unsigned ip,cs,flags;
- } REG_PARAMS;
-
- typedef unsigned char BYTE;
-
- typedef struct {
- BYTE len;
- BYTE txt[1];
- } STRING;
-
- typedef struct {
- BYTE max;
- STRING s;
- } CMDLINE;
-
- void interrupt far handler_2f(REG_PARAMS r);
-
- void (interrupt far *old)();
-
- void fail(char *s) { puts(s); exit(1); }
-
- main(void)
- {
- /* hook INT 2F */
- old = _dos_getvect(0x2f);
- _dos_setvect(0x2f, handler_2f);
-
- puts("This demo of installable commands isn't a TSR.");
- puts("Instead, it just creates a subshell from which you can EXIT");
- puts("when done. In the subshell, one new command has been added:");
- puts("FULLNAME [filename].");
-
- system(getenv("COMSPEC"));
-
- /* unhook INT 2F */
- _dos_setvect(0x2f, old);
- }
-
- char far *fullname(char far *s, char far *d)
- {
- char far *s2;
-
- /* INT 21h AH=60h doesn't like leading or trailing blanks */
- while (isspace(*s))
- s++;
- s2 = s;
- while (*s2) s2++;
- s2--;
- while (isspace(*s2))
- *s2-- = 0;
-
- _asm {
- push di
- push si
- les di, d
- lds si, s
- mov ah, 60h
- int 21h
- pop si
- pop di
- jc error
- }
-
- return d;
- error:
- return (char far *) 0;
- }
-
- void fcputs(char far *s)
- {
- /* can't use stdio (e.g., putchar) inside 2FAE01 handler? */
- while (*s)
- putch(*s++);
- putch(0x0d); putch(0x0a);
- }
-
- char buf[128]; /* not reentrant */
- char args[128];
-
- #define CMD_LEN 8
-
- void interrupt far handler_2f(REG_PARAMS r)
- {
- if ((r.ax == 0xAE00) && (r.dx == 0xFFFF))
- {
- CMDLINE far *cmdline;
- int len;
- FP_SEG(cmdline) = r.ds;
- FP_OFF(cmdline) = r.bx;
- len = min(CMD_LEN, cmdline->s.len);
- if ((_fmemicmp(cmdline->s.txt, "fullname", len) == 0) ||
- (_fmemicmp(cmdline->s.txt, "FULLNAME", len) == 0))
- {
- char far *redir;
- int argslen = cmdline->s.len - CMD_LEN;
- _fmemcpy(args, cmdline->s.txt + CMD_LEN, argslen);
- args[argslen] = 0;
- /* yuk! we have to get rid of redirection ourselves! */
- /* it will still take effect in AE01 */
- /* the following is not really correct, but okay for now */
- if (redir = _fstrrchr(args, '>'))
- *redir = 0;
- if (redir = _fstrrchr(args, '<'))
- *redir = 0;
- if (redir = _fstrrchr(args, '|'))
- *redir = 0;
- r.ax = 0xAEFF; /* we will handle this one */
- }
- }
- else if ((r.ax == 0xAE01) && (r.dx == 0xFFFF))
- {
- STRING far *s;
- int len;
- FP_SEG(s) = r.ds;
- FP_OFF(s) = r.si;
- len = min(CMD_LEN, s->len);
- if ((_fmemicmp(s->txt, "fullname", len) == 0) ||
- (_fmemicmp(s->txt, "FULLNAME", len) == 0))
- {
- char far *d;
- if (! *args)
- d = "syntax: fullname [filename]";
- else if ((d = fullname(args, buf)) == 0)
- d = "invalid filename";
- fcputs(d);
- s->len = 0; /* we handled it; COMMAND.COM shouldn't */
- }
- }
- else
- _chain_intr(old);
- }
-