Industrial Training




DOSkey Imitated



MS-DOS provides a popular TSR called DOSkey which allows you to view, edit and carry out DOS commands that you have used previously, The DOSkey program is essentially a TSR. When installed, the first time you press up arrow key DOSkey displays the most recent command. For example, suppose DOSkey has stored the three commands:

COPY C:\DOC\*.* D:\BACKUP

DIR D:\BACKUP

DEL C:\DOC

DOSkey displays the following command the first time you press the Up arrow key:

DEL C:\DOC

At this time we can either reuse the command by pressing ENTER or we can edit the command and then press ENTER.

If you press the Up arrow key more than once, DOSkey displays commands further back in the list. For example, to move to the first command you will have to press the Up arrow key thrice.

DOSkey offers several more features like creating macros, saving the list of commands in a batch file, etc. Here we would concentrate only on the history feature of the DOSkey program. To begin with, we would write a TSR which would store the commands typed at DOS prompt into a buffer. The TSR would allow the user to access the stored commands by hitting the Up arrow keys. Likewise, on hitting the Down arrow key the next command (with respect to the currently displayed command) would get displayed. On obtaining the command using Up or Down arrow key, if the user so desires he may edit the command and then execute it by hitting the Enter key.

To write this TSR we will have to first understand how DOS normally processes the input at the DOS prompt.

When idling at the DOS prompt it is COMMAND.COM which is in overall control of the things. At this time COMMAND.COM calls the DOS buffered keyboard input function (interrupt 21h, function 0Ah). Thus while idling at the prompt waiting for you to type something the control is parked inside interrupt 21h function 0Ah. As we now supply the input the following actions are performed:

  1. Every key that we press is collected in a special buffer provided by COMMAND.COM. In fact when COMMAND.COM calls this service it provides the segment:offset address of this special buffer in DS:DX.

  2. The 0 th byte of this buffer contains the buffer size, whereas byte number 1 contains the number of characters actually read. If the size of our input exceeds the buffer size the subsequent input is ignored.

On hitting the Enter key the control is now returned to COMMAND.COM which then executes the command.

Since our TSR proposes to do something at the command prompt we must capture interrupt 21h function 0Ah. To keep track of earlier commands our TSR would also need a buffer to stack these commands. Now when an Up arrow key is hit the TSR should pick up the topmost command from this command stack, place it in the special buffer and handover the control to COMMAND.COM the moment the Enter key is hit. COMMAND.COM would then take the necessary action to execute the command.

Here is the program which achieves all this...

# pragma inline

# include "dos.h"

#define ENTER 13

#define ESCAPE 27

#define BACKSPACE 8

#define TAB 9

#define UP_ARROW 72

#define DOWN_ARROW 80

#define LEFT_ARROW 75

#define F7 65

#define STACKSIZE 512

struct INTERRUPT

{

unsigned bp, di, si, ds, es, dx, cx, bx, ax, ip, cs, fl ;

} ;

union REGS i, o ;

void interrupt ( *prev )( ) ;

void interrupt our ( struct INTERRUPT ) ;

unsigned char far *buffer, string[128] ;

char far *scr = ( char far * ) 0xb8000000L ;

char stk[STACKSIZE], row, col, startrow, startcol, ascii,

scan ;

int maxlen, stk_count, count, prev_count, j, brk_flag,

tab, end, remove ;

main( )

{

prev = getvect ( 0x21 ) ;

setvect ( 0x21, our ) ;

keep ( 0, 1000 ) ;

}

void interrupt our ( struct INTERRUPT r )

{

if ( _AH == 0x0A )

{

enable( ) ;

count = 0 ;

brk_flag = 0 ;

/* get cursor position */

getcursorposition( ) ;

buffer = MK_FP ( r.ds, r.dx ) ; /* ds:dx holds segment:offset of buffer */

/* save the maximum length of the command */

maxlen = *buffer ;

/* read command until enter is pressed */

while ( !brk_flag )

{

/* read character from keyboard */

getkey( ) ;

switch ( ascii )

{

case 0 :

if ( stk_count == 0 )

continue ;

switch ( scan )

{

case UP_ARROW :

up( ) ;

break ;

case DOWN_ARROW :

down( ) ;

break ;

case LEFT_ARROW :

backspace( ) ;

break ;

case F7 :

escape( ) ;

printstack( ) ;

}

break ;

case ENTER :

enter( ) ;

break ;

case ESCAPE :

escape( ) ;

break ;

case BACKSPACE :

backspace( ) ;

break ;

case TAB :

puttab( ) ;

break ;

default :

if ( count == ( maxlen - 1 ) )

continue ;

* ( buffer + 2 + count ) = ascii ;

/* display character at cursor */

writechar ( ascii, row, col ) ;

count++ ;

col++ ;

checkcol( ) ;

setxy ( col ) ;

}

}



Hi I am Pluto.