Category : Files from Magazines
Archive   : DDJ8612.ZIP
Filename : DUNCAN.DEC

Output of file : DUNCAN.DEC contained in archive : DDJ8612.ZIP

Listing One
; General string comparison routine for 8086
; by Ray Duncan, June 1986
; Call with: DS:SI = address of string1
; DX = length of string1
; ES:DI = address of string2
; BX = length of string2
; Returns: Z and S flags set appropriately:
; Z = True if strings are equal
; or
; Z = False if strings are not equal, and
; S = True if string1 < string2
; S = False if string1 > string2
strcmp proc near
mov cx,bx ; set length to compare
cmp dx,bx ; use shorter of two lengths
ja scmp1
mov cx,dx
scmp1: repz cmpsb ; now compare strings
jz scmp2 ; jump, strings equal so far
ret ; return, strings not equal, Z=False
scmp2: sub dx,bx ; compare original string lengths
ret ; return with S and Z flags set
strcmp endp

Listing Two
; General string comparison routine for 68000
; by Rick Wilton, June 1986
; Call with: A0 = address of string1
; D0 = length of string1
; A1 = address of string2
; D1 = length of string2
; Returns: D3 = flag (-1,0,1)
; -1 if string1 < string2
; 0 if string1 = string2
; 1 if string1 > string2
strcmp ; set d2 = shorter length
move.b d1,d2 ; d2 := length2
cmp.b d0,d1
blt.s strcmp1 ; branch if length2 < length1
move.b d0,d2 ; d2 := length1

strcmp1 subq.w #1,d2
bmi.s strcmp3 ; branch if string length=0

strcmp2 cmpm.b (a0)+,(a1)+ ; compare strings
dbne d2,strcmp2
bne.s strcmp4 ; branch if strings unequal

strcmp3 cmp.b d0,d1
bne.s strcmp4 ; branch if lengths unequal
moveq #0,d3 ; string1 = string2, return 0

strcmp4 bmi.s strcmp5 ; branch if d1 < d0
moveq #-1,d3 ; string1 < string2, return -1

strcmp5 moveq #1,d3 ; string1 > string2, return 1

Listing Three
Title EXEC program using undocumented MS-DOS Interrupt 2EH

; This little demonstration program illustrates the undocumented
; MS-DOS Int 2EH route to the command interpreter in COMMAND.COM.
; In this example we just pass the command tail of the line that
; loaded the EXEC2E program.
; by David Gwillim - 20 June 1986
; Appears to work on all current versions of MS-DOS (2.x-3.1)
; Adapted from Turbo Pascal program written by Russ Nelson, Potsdam, NY.

cseg segment

org 100H

assume cs:cseg,ds:nothing ; force assembler to provide
; CS overrides in the right places

begin: jmp start

db 20 dup ('STACK ')
stack equ $

stkseg dw 0 ; save SS register
stkptr dw 0 ; save SP register

msg1 db 'Beginning DOS Int 2Eh Exec',13,10,'$'

msg2 db 'Terminating DOS Int 2Eh Exec',13,10,'$'

start: push cs ;make our local data addressable
pop ds

mov dx,offset msg1 ;display sign-on message
mov ah,9
int 21h

mov sp,offset stack ;reset SP to our own internal stack

mov bx,offset cs:endcode ;Get the offset of the end of our code
shr bx,1 ;divide by 16 to get paragraphs
shr bx,1
shr bx,1
shr bx,1
inc bx ;round paragraphs up
mov ah,4ah ;shrink down this COM program's
int 21h ;memory allocation to what's needed

mov stkseg,ss ;save our current SS reg
mov stkptr,sp ; and SP reg values

mov si,80h ;let DS:SI point to the command
;to be executed

int 2eh ;undocumented DOS exec interrupt
; any error code is now in AX

mov ss,stkseg ;Restore SS and SP registers
mov sp,stkptr

push cs ;restore local addressing
pop ds

mov dx,offset msg2 ;say we're done
mov ah,9
int 21h

mov ax,4c00h ;exit to DOS
int 21h

endcode equ $

cseg ends

end begin

Listing Four

The following little program can set an environment variable
whose name is the first command line argument, and whose new
value is the second command line argument. For example, to
set environment variable XYZ to a value of HELLO, you would
run this program using the command SETVAR XYZ HELLO.

The *PURPOSE* of this piece of code is to illustrate an un-
documented DOS interrupt entry point (2Eh) that will execute
*ANY* DOS command *WITHOUT* having to load another copy of
COMMAND.COM. Not only is it faster, but it is the ONLY way
to set an environment variable (short of peeking and poking
around into memory). You *CAN'T* set an environment variable
with the command exec("COMMAND.COM", "/CSETXYZ=HELLO") because
when the second copy of COMMAND.COM is loaded, it gets its
very own environment (a duplicate of the parent's). Although
the SET command WILL modify that duplicate copy, it won't
modify the parent's!

When I said that interrupt 2Eh can be used to execute *ANY*
DOS command, I meant just that! You can leave off the filename
extension (as you normally do at the command line), and it will
perform the normal search for COM, EXE, and BAT files to execute,
or even execute built-in commands as we've seen above.


Dan Lewis, owner
Key Software Products
440 Ninth Avenue
Menlo Park, CA 94025
(415) 364-9847

P.S.- This *IS* an undocumented "feature" of DOS 2.xx. I have
NO idea if 3.xx etc support it!



main(argc, argv)
int argc ;
char *argv[] ;
Set_Var(argv[1], argv[2]) ;

Set_Var(variable, value)
char *variable, *value ;
char setbfr[100] ;

/* Build the command line: "SET =" */

strcpy(setbfr, "SET ") ;
strcat(setbfr, variable) ;
strcat(setbfr, "=") ;
strcat(setbfr, value) ;

/* Now use INT 2Eh to execute it! */

Execute_String(setbfr) ;

/* -------------------------------------------- */
/* The really interesting stuff starts here.... */
/* -------------------------------------------- */

char *s;
long vec22, vec23, vec24 ;
long Get_Vec(vector) ;
static char bfr[81];

/* Concatenate a carriage return onto end of command line */

strcpy(bfr + 1,s) ;
*bfr = strlen(bfr + 1) ;
strcat(bfr + 1,"\r") ;

/* preserve cntrl-break, terminate, and critical error vectors */
vec22 = Get_Vec(0x22) ;
vec23 = Get_Vec(0x23) ;
vec24 = Get_Vec(0x24) ;

Release_Memory() ; /* necessary! */
Exec(bfr) ; /* execute command */

/* reset cntrl-break, terminate, and critical error vectors */
Set_Vec(0x22,vec22) ;
Set_Vec(0x23,vec23) ;
Set_Vec(0x24,vec24) ;

char *s ;
; preserve ds, bp, ss, & sp

push ds
push bp
mov cs:WORD save_ss,ss
mov cs:WORD save_sp,sp

; ds:si ->CR/NULL-terminated command line string

mov si,[bp+4]
int 2Eh

; restore preserved registers

mov ss,cs:WORD save_ss
mov sp,cs:WORD save_sp
pop bp
pop ds

jmp Rtn

save_ss:dw 0
save_sp:dw 0
save_ds:dw 0
save_bp:dw 0


if (Release())
puts("Release Memory Failure\n") ;
exit(1) ;

mov ax,cs
sub ax,0010h
mov es,ax
mov bx,ds
add bx,1000h
sub bx,ax
mov ah,4Ah
int 21h
mov ax,0
jnc R_Rtn
inc ax

long Get_Vec(vector) /* Uses DOS function 35h to fetch an interrupt vctr */
unsigned vector ;
mov ah,35h
mov al,BYTE [bp+4]
int 21h
mov ax,bx
mov dx,es

Set_Vec(vector,addr) /* Uses DOS function 25h to set an interrupt vctr */
unsigned vector ;
long addr ;
mov ah,25h
mov al,BYTE [bp+4]
mov bx,WORD [bp+6]
mov es,WORD [bp+8]
int 21h

Listing Five
* Standard system definitions
* Ross P. Nelson

/* Expanded public/external syntax */
#define FORWARD extern
#define IMPORT extern
#define PUBLIC

#ifdef DEBUG /* Generate symbols if debugging, else don't export */
#define LOCAL
#define LOCAL static

/* System constants and data types */
#define TRUE 1
#define FALSE 0

typedef unsigned char byte;
typedef byte boolean;
typedef unsigned short word;
typedef unsigned short selector;

* STD.C Copyright (C) 1985 Ross P. Nelson
* Redirect stdin/stdout. Usually called before performing an
* EXEC, so that the child task will read or write via a file.
* Sample usage is in the MAIN routine below.


IMPORT word _PSP[2]; /* offset, segment */
IMPORT struct UFB _ufbs[];

* Set stdin or stdout to the file. Caller is responisble for
* having opened the file in the corrent mode and positioning it
* as necessary. Returns a value to be used when reseting stdio
* to original value.
PUBLIC int setstdio (stdfp, newfp)
FILE *stdfp, *newfp;
byte reset, save;
int handle, redir;

handle = _ufbs[fileno (newfp)].ufbfh;
redir = _ufbs[fileno (stdfp)].ufbfh;
save = 0xFF;
peek (_PSP[1], 0x18 + handle, &reset, 1);
poke (_PSP[1], 0x18 + handle, &save, 1);
peek (_PSP[1], 0x18 + redir, &save, 1);
poke (_PSP[1], 0x18 + redir, &reset, 1);
return (int) save;

* Must be called to reset stdio values to original. Caller is
* responsible for closing file after restdio.
PUBLIC void restdio (stdfp, newfp, reset)
FILE *stdfp, *newfp;
int reset;
byte direct, old;
int handle, redir;

handle = _ufbs[fileno (newfp)].ufbfh;
redir = _ufbs[fileno (stdfp)].ufbfh;
old = (byte) reset;
peek (_PSP[1], 0x18 + redir, &direct, 1);
poke (_PSP[1], 0x18 + redir, &old, 1);
poke (_PSP[1], 0x18 + handle, &direct, 1);

abort (s)
char *s;
fprintf (stderr, s);
exit (4);

main ()
FILE *f;
int reset;

puts ("Begin test - opening file TEST.XX");
f = fopen ("test.xx", "w");
if (f == NULL)
abort ("open failed");
reset = setstdio (stdout, f); /* stdout <- f */
fprintf (stderr, "invoking LS\n"); /* can't write to stdout */
if (forklp ("ls.exe", "ls", NULL)) { /* run LS */
restdio (stdout, f, reset); /* clean up if cant exec */
abort ("exec failed");
(void) wait (); /* wait til LS done */
restdio (stdout, f, reset); /* stdout <- original value */
fclose (f);
puts ("Test completed - LS results in TEST.XX");

Listing 6 December 86 16-Bit Column in DDJ

;* *
;* Wildcard filename expansion for MS-DOS 2.00 and later. *
;* *
;* By: Randy Langer, MicroSphere Technology *
;* *

ifndef model ; if default model (both small)

model equ 0 ; 0 = small code, small data
; 1 = large code, small data
; 2 = small code, large data
endif ; 3 = large code, large data

codeseg segment byte public 'code'
assume cs:codeseg

public wildcard_

if model and 1

wildcard_ proc far


wildcard_ proc near


push bp ; save frame pointer
mov bp,sp ; point to our stack

if model and 2

push ds ; save DS if large data
mov ds,[bp+6] ; and get segment of struct ptr


mov bx,[bp+4] ; get offset of struct ptr
mov al,[bx] ; get flag byte
or al,al ; see if high bit set
js rtn_null ; if so, no more to find
push es ; save reg used by DOS call
mov ah,47 ; get current DTA addr
int 21h ; do it
mov ax,es ; save DTA segment
pop es ; restore ES
push ds ; save for later restoration
push ax ; save addr of old DTA
push bx
mov dx,[bp+4] ; get ptr to user's struct
add dx,2 ; point past flag bytes
mov ah,26 ; set "new" DTA addr
int 21h
mov bx,[bp+4] ; get entry pointer again
mov cl,[bx+1] ; set search attributes
mov ah,79 ; set token for search next
test byte ptr [bx],1 ; if this is really search next
jnz not_1st ; branch
inc byte ptr [bx] ; else, set flag
dec ah ; and set token for search first
mov dx,[bx+45] ; get offset to filespec

if model and 2

mov ds,[bx+47]


int 21h ; do the search
pop dx ; get addr of old DTA
pop ds
push ax ; save return code from search
mov ah,26 ; restore DTA ptr
int 21h
pop ax ; restore return code
pop ds ; get back segment of user struct
mov bx,[bp+4] ; and its offest
or ax,ax ; see if search successful
jz rtn_name ; branch if so
mov byte ptr [bx],128 ; else, say no more
xor ax,ax ; return null ptr
mov dx,ax ; in case of large data

if model and 2

pop ds


pop bp ; restore frame pointer
ret ; and return
mov dx,ds ; in case of large data model
mov ax,32 ; offset to file name
add ax,bx ; add to struct base
jmp wild_end ; and exit

wildcard_ endp
codeseg ends


Listing 7 December 86 16-Bit Column in DDJ:


by Randy Langer, Microsphere Technology


typedef struct
char flag;
char att_sel;
char tempdata[21]; /* don't mess with this */
char f_atts;
long datetime;
long filesize;
char filename[13];
char *filespec;


char *wildcard();

Listing 8 December 1986 16-Bit Column in DDJ

* WILDTEST.C Program to demonstrate use of WILDCARD.ASM
* by Randy Langer, MicroSphere Technology.

#include "stdio.h"
#include "wildcard.h"

main(argc, argv)

int argc;
STR argv[];

STR s;

y.filespec = *++argv;
y.att_sel = 0x10;
y.flag = 0;
while(s = wildcard(&y))
printf("%s\n", s);