page 66,132 ;======================================================================= ; STRINGS.COM - a set of string handling functions for batch files. ; ; Syntax: ; STRINGS [/H][/M][/Pc ][var = ] function arg1 [, arg2] [, arg3] ; ; /? - Print help message ; /M - Use master environment block ; /Q - Suppress output to console ; /Pc - Use c as parse character instead of ',' ; /Bxx - Use xx as for base (base 10 default) ; /I - Install as TSR ; /U - Uninstall ; ; Revision History: ; ; Version 2.0 New version with many more commands. ; Version 2.1 Fixed READ bug ; Fixed Parse bug ; Added check for 386Max mem arenas ; Changed env search default ; ; Version 2.2 Fixed 2FCheck bug ; Fixed ASK bug ; Fixed FILENAME bug ; Fixed Install check ; ; Version 2.3 Added sharing flags to file operations ; Added check for internal cmd hook ; Fixed read across boundry bug ; ; Version 2.4 Fixed print time at 12 noon bug. ; Added xlate from graphics = to char = on cmdline ; ; Version 2.5 Mod file open code to handle CD-ROMs ; ;======================================================================= ; ;Equates ; RES_STACK equ offset end_of_resident+512 TRANS_STACK equ offset end_of_code+512 VAR_SIZE equ 128 ;Max size of variables DATABUFF_SIZE equ 2048 ;Size of file data buffer MAX_PARAMS equ 10 ;Max number of parameters DEF_PARSE_CHAR equ "," ;Default parse character ;------------------------------------------------------------------------ ;Code segment ;------------------------------------------------------------------------ code segment assume cs:code org 2ch local_environment dw ? ;Word containing the seg ; of the prog's env. blk. org 80h command_tail db ? ;Offset of the cmd tail. org 100h entry: jmp initialize program db 13,10,"STRINGS " version db "2.5 " copyright db "Copyright 1991-1993, 1995 " db "Douglas Boling",10,13 db "First published in PC Magazine," db " December 29, 1992",13,10,0,"$",1Ah even ;Start data on word bndry dos_version dw 0 ems_version dw -1 xms_version dw -1 databuff_ptr dw 0 ;Ptr to file data buffer saved_ss dw 0 ;SS:SP saved on during saved_sp dw 0 ; multiplex execution saved_ssint dw 0 ;SS:SP saved on during saved_spint dw 0 ; interrupt function. int2fh dd -1 ;Old mux int vector xms_serv dd -1 ;Entry pt for ext mem drvr masterenv_seg dw 0 ;Segment of master env localenv_seg dw 0 ;Segment of local env num_params dw 0 ;Number of parameters passed dest_var_val dw 0 dest_var_name dw 0 ;Buffer pointers to parsed cmd_value dw 0 ; command line variables. var1_value dw 0 ; These pointers must be var2_value dw 0 ; kept in this order. var3_value dw 0 var4_value dw 0 var5_value dw 0 var6_value dw 0 var7_value dw 0 var8_value dw 0 var9_value dw 0 var10_value dw 0 get_cmd db 0 ;Claim command flag multiplex_id db 0dbh ;Mux id number_base dw 10 ;Base for num conversion parse_char db DEF_PARSE_CHAR ;Char used to parse command quiet_flag db 0 ;Flag to suppress output console_out db 1 ;Flag for con out. use_mastenv db 0 ;Flag to use master env help_flag db 0 ;Forces help message install_flag db 0 ;Install as TSR remove_flag db 0 ;Remove installed db 0 ;Installed as TSR flag fill_char db " " ;Char used to fill zeros equalsub_char db 0cdh strings_namelen dw 7 ;Length of strings name strings_name db "STRINGS",0,0 ;Name of program shell_var db "COMSPEC",0,0 ;Extra zero needed, don't del shell_name db "COMMAND",0,0 ;Cmd shell file name shell_namlen db 7 ;Length of shell filename ems_header db 'EMMXXXX0' ;Expanded mem drvr header ; ; Table of command line switches and the corrsponding jump table ; cmd_switches db "h?mqpbiu" ;Letters of valid commands. cmd_switch_end = $ cmd_jmp_tbl dw offset switch_help ;This jump table is used to dw offset switch_help ; call the routines that dw offset switch_master ; process the command line dw offset switch_quiet ; arguments dw offset switch_pchar dw offset switch_base dw offset switch_install dw offset switch_remove ; ; Table of commands ; command_table db "LEFT",0 ;String functions db "RIGHT",0 db "MID",0 db "LENGTH",0 db "FIND",0 db "FINDC",0 db "LOWER",0 db "UPPER",0 db "CHAR",0 db "VAL",0 db "FILEDRIVE",0 db "FILEDIR",0 db "FILENAME",0 db "FILEEXT",0 db "PARSE",0 db "ADDCOMMAS",0 db "REPEAT",0 db "READ",0 ;File functions db "WRITE",0 db "FILESIZE",0 db "LINESIZE",0 db "TRUENAME",0 db "FILEDATE",0 db "FILETIME",0 db "VER",0 ;System functions db "ASK",0 db "INWIN",0 db "2FCHECK",0 db "ENVFREE",0 db "ENVSIZE",0 db "MASTERVAR",0 db "LOCALVAR",0 db "TRUEVER",0 db "FILES",0 db "LASTDRIVE",0 db "CODEPAGE",0 db "COUNTRY",0 db "BIOSDATE",0 db "GETKEY",0 db "LOCALENV",0 db "MASTERENV",0 db "ADD",0 ;Math functions db "SUB",0 db "MUL",0 db "DIV",0 db "AND",0 db "OR",0 db "XOR",0 db "NOT",0 db "CONVERT",0 db "PEEK",0 ;Progamming functions db "POKE",0 db "IN",0 db "OUT",0 db "INTERRUPT",0 db "SCAN",0 db "DAY",0 ;Time/Date functions db "MONTH",0 db "DATE",0 db "TIME",0 db "MEMTOTAL",0 ;Memory status functions db "MEMFREE",0 db "XMSTOTAL",0 db "XMSFREE",0 db "XMSVER",0 db "EMSTOTAL",0 db "EMSFREE",0 db "EMSVER",0 db "UMBLARGE",0 db "STRINGSVER",0 ;Support functions db "INSTALLED",0 db "HELP",0 db 0 ;End of list flag ; ; Jump table for commands ; jump_table dw offset left_str dw offset right_str dw offset mid_str dw offset length_str dw offset find_str dw offset findc_str dw offset lower_str dw offset upper_str dw offset char_str dw offset val_str dw offset filedrive_str dw offset filedir_str dw offset filename_str dw offset fileext_str dw offset parse_str ;New dw offset commas_str ;New dw offset repeat_str ;New dw offset readrec_file dw offset writerec_file dw offset filesize_file dw offset numrec_file dw offset truename_file dw offset filedate_file ;New dw offset filetime_file ;New dw offset ver_sys dw offset ask2_sys dw offset inwin_sys dw offset int2fcheck_sys dw offset envfree_sys dw offset envsize_sys dw offset mastervar_sys dw offset localvar_sys dw offset truever_sys ;New dw offset files_sys ;New dw offset lastdrive_sys ;New dw offset codepage_sys ;New dw offset country_sys ;New dw offset biosdate_sys ;New dw offset getkey_sys ;New dw offset localenv_sys ;New dw offset masterenv_sys ;New dw offset add_num dw offset sub_num dw offset mul_num dw offset div_num dw offset and_num ;New dw offset or_num ;New dw offset xor_num ;New dw offset not_num ;New dw offset convert_num ;New dw offset peek_prog ;New dw offset poke_prog ;New dw offset in_prog ;New dw offset out_prog ;New dw offset interrupt_prog ;New dw offset scan_prog ;New dw offset day_time ;New dw offset month_time ;New dw offset date_time ;New dw offset time_time ;New dw offset totalmem_mem ;New dw offset freemem_mem ;New dw offset totalext_mem ;New dw offset freeext_mem ;New dw offset extver_mem ;New dw offset totalems_mem ;New dw offset freeems_mem ;New dw offset emsver_mem ;New dw offset freeumb_mem ;New dw offset ver_strings ;New dw offset inst_strings ;New dw offset help_strings ;New jump_table_end = $ int2fname_tbl db "PRINT",0 ;Alias table for multiplex db "ASSIGN",0 ; interrupt install check db "DRIVER",0 db "SHARE",0 db "NET",0 db "NLS",0 db "ANSI",0 db "DOSBOX",0 db "HIMEM",0 db "DOSKEY",0 db "DISPLAY",0 db "GRAPHTBL",0 db "APPEND",0 db 0 ;End of list flag int2falias_tbl db 1 ;ID numbers of DOS programs db 6 ; that use the multiplex db 8 ; interrupt. db 10h db 11h db 14h db 1Ah db 40h db 43h db 48h db 0ADh db 0B0h db 0B7h day_list db "Sunday",0 db "Monday",0 db "Tuesday",0 db "Wednesday",0 db "Thursday",0 db "Friday",0 db "Saturday",0,0 month_list db "January",0 db "February",0 db "March",0 db "April",0 db "May",0 db "June",0 db "July",0 db "August",0 db "September",0 db "October",0 db "November",0 db "December",0,0 infomsg2 db "Removed",0 errmsg0 db "Need DOS " errmsg0ver db "2.0" db " or greater",0 errmsg1 db "Usage: STRINGS [/?][/M][/Q][/Pc][/Bn][/I][/U]" db " [env var =]" db " FUNCTION [Params]",13,10,10 db " /M - Use master environment",13,10 db " /Q - Suppress output to screen",13,10 db " /Pc - Use char c instead of ',' as the" db " parse character",13,10 db " /Bn - Use n as the number base",13,10 db " /I - Installs as resident code." db " DOS 3.3 or later required",13,10 db " /U - Uninstalls if resident",13,10 db 10,"For a list of commands type STRINGS /?",0 errmsg2 db "Not enought memory",0 errmsg3 db "Unknown command line switch",0 errmsg6 db "Illegal filename",0 errmsg7 db "Line numbers must be greater than 0",0 errmsg8 db "Line not found",0 errmsg10 db "Multiply overflow error",0 errmsg11 db "Divide by zero error",0 errmsg12 db "Addition overflow",0 errmsg13 db "Subtraction underflow",0 errmsg14 db "Number too large",0 errmsg15 db "Out of environment space",0 errmsg16 db "Can't find environment",0 errmsg17 db "No Expanded memory",0 errmsg18 db "Required parameter missing",0 errmsg19 db "No Extended memory",0 errmsg20 db "String not found",0 errmsg21 db "Not Installed",0 errmsg22 db "Can",39,"t remove",0 errmsg23 db "Already installed",0 errmsg24 db "Base must be within 2-16",0 endmsg db 13,10,0 doserr_tbl dw offset doserr_00 dw offset doserr_00 dw offset doserr_02 dw offset doserr_03 dw offset doserr_04 dw offset doserr_05 dw offset doserr_00 dw offset doserr_07 dw offset doserr_00 dw offset doserr_00 dw offset doserr_10 dw offset doserr_00 dw offset doserr_12 dw offset doserr_13 dw offset doserr_00 dw offset doserr_15 dw offset doserr_00 dw offset doserr_17 dw offset doserr_18 dw offset doserr_19 dw offset doserr_20 dw offset doserr_21 dw offset doserr_22 dw offset doserr_23 dw offset doserr_00 dw offset doserr_25 dw offset doserr_26 dw offset doserr_27 dw offset doserr_00 dw offset doserr_29 dw offset doserr_30 dw offset doserr_31 dw offset doserr_32 dw offset doserr_33 dw offset doserr_34 doserr_tblend = $ doserr_00 db "DOS Error",0 doserr_02 db "File not found",0 doserr_03 db "Path not found",0 doserr_04 db "Too many open files",0 doserr_05 db "Access denied",0 doserr_07 db "Memory Corrupted",0 doserr_10 db "Bad Environment block",0 doserr_12 db "File Access Invalid",0 doserr_13 db "Data Invalid",0 doserr_15 db "Not a proper Disk",0 doserr_17 db "Not same device",0 doserr_18 db "No more files",0 doserr_19 db "Disk Write Protected",0 doserr_20 db "Unknown unit",0 doserr_21 db "Drive not ready",0 doserr_22 db "Unknown command",0 doserr_23 db "CRC Data Error",0 doserr_25 db "Disk Seek error",0 doserr_26 db "Not a DOS disk",0 doserr_27 db "Sector not found",0 doserr_29 db "File Write fault",0 doserr_30 db "File Read fault",0 doserr_31 db "General failure",0 doserr_32 db "File sharing violation",0 doserr_33 db "File lock violation",0 doserr_34 db "Illegal Disk change",0 ;============================================================================ ; Multiplex Interrupt handler ;============================================================================ muxint proc far assume cs:code,ds:nothing,es:nothing cmp ax,0ae00h ;Chk for installed cmd je mux_chkcmd cmp ax,0ae01h ;Chk for installed cmd je mux_execute cmp ah,cs:multiplex_id je mux_instchk mux_jmp: jmp cs:[int2fh] ;Jump to old interrupt mux_instchk: mov ax,-1 push cs pop es iret ; ; This routine checks the cmd line for a valid Strings command. ; mux_chkcmd: cld push cx push di push si push es lodsb ;Load cmd length mov cl,al xor ch,ch mov di,cs ;ES:DI points to my cmd mov es,di ; line buff mov di,offset strings_name repe cmpsb jne mux_chk1 cmp byte ptr es:[di],0 jne mux_chk1 mov al,-1 ;Claim command mov di,81h ;Copy to my cmd buff mov si,bx ;Point to cmd line inc si mov cl,ds:[si] ;Get length of cmd line inc si ;Load cmd line length inc cx cmp cl,7fh ;Only allow 127 chars ja mux_chk1 rep movsb jmp short mux_chkexit mux_chk1: xor al,al ;Don't want command mux_chkexit: pop es pop si pop di pop cx or al,al ;See if we like cmd je mux_jmp ;No, pass on. mov cs:get_cmd,1 ;Set accept cmd flag jmp short mux_iret ;Yes, return. ; ; This routine executes the command line. ; mux_execute: dec cs:get_cmd ;See if Strings claimed jnz mux_jmp ; the command. push ax mov cs:saved_ss,ss mov cs:saved_sp,sp mov ax,cs cli mov ss,ax mov sp,RES_STACK sti push bx push cx push dx push di push si push bp push ds push es mov ax,cs mov ds,ax mov es,ax assume ds:code,es:code mov si,offset 81h ;Remove name of program mov di,si ; from the command xor bl,bl ; line. 1st, find the call scan4char ; name, the move the add si,strings_namelen ; ptr past it. xor cx,cx mux_x1: lodsb stosb inc cx cmp al,13 jne mux_x1 mov ds:[80h],cl call main ;Showtime! cmp remove_flag,0 ;See if we should je mux_xexit ; remove the program call remove jnc mux_xexit call print_strcr ;Print error message mux_xexit: pop es pop ds pop bp pop si pop di pop dx pop cx pop bx cli mov ss,cs:saved_ss mov sp,cs:saved_sp cmp cs:remove_flag,0 ;If remove, discard je mux_xexit1 ; mem segment at the push es ; last moment. push cs pop es ;Get code segment mov ah,49h ;Free mem int 21h pop es mux_xexit1: pop ax mov byte ptr ds:[si],0 ;Tell cmd.com not to ex mux_iret: iret muxint endp ;---------------------------------------------------------------------------- ; Start of code. ;---------------------------------------------------------------------------- main proc near assume cs:code,ds:code,es:code cld ;Set string operations 'up.' call parse_cmdline ;Parse command line jc main_error mov si,dest_var_name ;Point to dest env var name call caps_string mov si,cmd_value ;Point to command buffer call caps_string cmp help_flag,0 ;If help flag set, call je main_1 ; help function to call help_strings ; interpet command. jmp short main_6 main_1: inc cx mov di,offset command_table ;Search cmd table call findstr mov si,offset errmsg1 jc main_error shl bx,1 ;Compute offset of routine to call [bx+offset jump_table] ; call, then call routine jc main_error mov si,dest_var_val cmp console_out,0 ;See how to return result je main_3 cmp byte ptr [si],0 ;If no result, exit je main_6 call print_strcr ;Print result to screen jmp short main_6 main_3: mov di,dest_var_name xchg di,si call setenv ;Set environemnt variable. jc main_7 main_6: xor al,al ;Return code = 0 main_exit: ret ;Return ; ;Display error message. ; main_7: mov si,offset errmsg15 ;Out of environment space main_error: push cs pop ds assume ds:code push si mov si,offset program ;Print copyright msg call print_strcr pop si call print_strcr ;print string main_9: mov al,01 ;Terminate with RC = 1 jmp short main_exit main endp ;============================================================================= ; String Functions ;============================================================================= ;----------------------------------------------------------------------------- ; RIGHT STR returns the right n characters of the source string ;----------------------------------------------------------------------------- right_str proc near assume cs:code,ds:code,es:code mov si,var2_value ;Convert 2nd parameter to hex call asc2hex call truncnum ;Truncate number to string len push ax mov di,var1_value ;Scan to end of string call find_end pop ax right_str_2: sub di,ax dec di cmp di,var1_value ja right_str_3 mov di,var1_value right_str_3: mov si,dest_var_val xchg di,si call copy_string ;Copy string to dest buffer clc ret right_str endp ;----------------------------------------------------------------------------- ; LEFT STR Returns the left n characters of the source string ;----------------------------------------------------------------------------- left_str proc near assume cs:code,ds:code,es:code mov si,var2_value ;Convert 2nd parameter to hex call asc2hex call truncnum ;Truncate number to string len mov si,var1_value mov bx,ax mov byte ptr [si+bx],0 mov di,dest_var_val call copy_string ;Copy string to dest buffer clc ret left_str endp ;----------------------------------------------------------------------------- ; MID STR Returns a string of n characters starting m characters from the ; left of the source string ;----------------------------------------------------------------------------- mid_str proc near assume cs:code,ds:code,es:code mov si,var2_value ;Convert 2nd parameter to hex call asc2hex dec ax call truncnum ;Truncate num mov cx,ax ;Copy second parameter mov si,var3_value ;Convert 3rd param to hex cmp byte ptr [si],0 ;See if no parameter je mid_str_0 call asc2hex ;If no number, return max jnc mid_str_1 ; value to insure remainder mid_str_0: mov ax,VAR_SIZE ; of string returned. mid_str_1: call truncnum ;Truncate num push ax ;Save length of substring xor ax,ax cmp al,1 ;Clear zero flag mov di,var1_value ;Scan to new start of string jcxz mid_str_11 repne scasb mid_str_11: pop cx ;Pop length of substring mov si,di ;Copy ptr to start of substr je mid_str_2 ;If end of str found, end repne scasb ;Scan until end of substring mov byte ptr [di],0 mid_str_2: mov di,dest_var_val call copy_string ;Copy string to dest buffer clc ret mid_str endp ;----------------------------------------------------------------------------- ; LENGTH STR Computes the length of the source string ;----------------------------------------------------------------------------- length_str proc near assume cs:code,ds:code,es:code mov di,var1_value ;Find_end also returns the call find_end ; length of the string in mov ax,cx ; CX. xor dx,dx mov di,dest_var_val ;Convert value to ASCII call hex2asc clc ret length_str endp ;----------------------------------------------------------------------------- ; UPPER STR Convert the source string to upper case ;----------------------------------------------------------------------------- upper_str proc near assume cs:code,ds:code,es:code mov di,dest_var_val mov si,var1_value push di call copy_string ;Copy string to dest buffer pop si call caps_string ;Convert to upper case. clc ret upper_str endp ;----------------------------------------------------------------------------- ; LOWER STR Convert the source string to lower case ;----------------------------------------------------------------------------- lower_str proc near assume cs:code,ds:code,es:code mov di,dest_var_val mov si,var1_value push di call copy_string ;Copy string to dest buffer pop si call lc_string ;Convert to lower case. clc ret lower_str endp ;----------------------------------------------------------------------------- ; CHAR STR Convert the source number to a ASCII character ; Revised in ver 2.0 to handle up to 10 numbers ;----------------------------------------------------------------------------- char_str proc near assume cs:code,ds:code,es:code push bp mov di,dest_var_val ;Get ptr to output buff mov bp,offset var1_value ;Get ptr to var array mov cx,num_params ;Get number of parameters or cx,cx jne charstr_1 mov cx,1 charstr_1: mov si,[bp] ;Get ptr to variable inc bp ;Point BP to next var inc bp call asc2hex ;Convert ASCII num to stosb ; hex num and store. loop charstr_1 xor al,al ;Write number directly to stosb ; dest string. Include clc ; zero for termination. pop bp ret char_str endp ;----------------------------------------------------------------------------- ; VAL STR Convert the source character to its HEX equivalent ; Revised in ver 2.0 to handle more than one character ;----------------------------------------------------------------------------- val_str proc near assume cs:code,ds:code,es:code mov di,dest_var_val ;Get ptr to output buff mov si,var1_value ;Get ptr to char string valstr_1: lodsb ;Get character or al,al je valstr_2 xor ah,ah xor dx,dx call hex2asc ;Convert character to mov byte ptr [di-1],' ' ; ascii num and store. jmp short valstr_1 dec di valstr_2: xor al,al ;Write number directly to stosb ; dest string. Include clc ; zero for termination. ret val_str endp ;----------------------------------------------------------------------------- ; FILEDRIVE STR Return only the directory from a filename string ;----------------------------------------------------------------------------- filedrive_str proc near assume cs:code,ds:code,es:code mov si,var1_value ;Fully qualify filename mov di,dest_var_val ;Point string to dest buff call parse_filename mov byte ptr [di+2],0 ;Terminate after drive spec clc ret filedrive_str endp ;----------------------------------------------------------------------------- ; FILEDIR STR Return only the directory from a filename string ;----------------------------------------------------------------------------- filedir_str proc near assume cs:code,ds:code,es:code mov si,var1_value ;Fully qualify filename mov di,databuff_ptr ;Use data buff as temp buff call parse_filename mov si,dest_var_val xchg si,di add si,2 ;Skip past drive stuff mov bx,di mov dx,bx inc dx filedir_1: lodsb stosb cmp al,'\' ;Mark start of filename or jne filedir_2 ; directory. mov bx,di filedir_2: or al,al ;See if at end of string jne filedir_1 filedir_3: cmp bx,dx ;If root dir, don't delete je filedir_4 ; lone \. dec bx filedir_4: mov byte ptr [bx],0 ;Terminate string at end of clc ; directory ret filedir_str endp ;----------------------------------------------------------------------------- ; FILENAME STR Return only the filename from a filename string ;----------------------------------------------------------------------------- filename_str proc near assume cs:code,ds:code,es:code mov si,var1_value ;Fully qualify filename mov di,databuff_ptr ;Use data buff as temp buff call get_filename mov di,dest_var_val ;Pt to dest buff rep movsb xor al,al ;Terminate filename and stosb ; clear error flag ret filename_str endp ;----------------------------------------------------------------------------- ; FILEEXT STR Return only the filename extension from a filename string ;----------------------------------------------------------------------------- fileext_str proc near assume cs:code,ds:code,es:code mov si,var1_value ;Fully qualify filename mov di,databuff_ptr ;Use 2nd buff as temp buff call parse_filename mov si,di xor bx,bx fileext_1: lodsb cmp al,'.' ;Mark start of filename or jne fileext_2 ; directory. mov bx,si fileext_2: or al,al jne fileext_1 or bx,bx je fileext_3 mov cx,si sub cx,bx ;Compute length mov di,dest_var_val mov si,bx rep movsb xor al,al ;Terminate string stosb fileext_3: clc ret fileext_str endp ;----------------------------------------------------------------------------- ; FIND STR finds a string within another string. ; Exit: AL - Return code if string not found ; CF - Set if string not found ;----------------------------------------------------------------------------- find_str proc near mov si,var1_value ;To ignore case, capitalize call caps_string ; both strings, then call mov si,var2_value ; the findc function. call caps_string call findc_str ret find_str endp ;----------------------------------------------------------------------------- ; FINDC STR finds a string within another string, respects case. ; Exit: AL - Return code if string not found ; CF - Set if string not found ;----------------------------------------------------------------------------- findc_str proc near mov di,var1_value ;Get ptr to 1st string push di call find_end ;Compute length pop si push cx ;Save length mov di,var2_value mov dx,di call find_end mov bx,cx ;Save length of search string pop cx ;Restore length of trg string sub cx,bx ;Sub length of search string. jb find_str_not_found inc cx find_str_1: push cx mov cx,bx ;Restore search str length mov di,dx ;Restore ptr to search str push si repe cmpsb ;Compare command pop si pop cx je find_str_found inc si ;Inc target string ptr loop find_str_1 find_str_not_found: xor ax,ax ;Set bad return code jmp short find_str_2 find_str_found: mov ax,si ;Copy offset sub ax,var1_value ;Sub starting offset inc ax find_str_2: xor dx,dx mov di,dest_var_val ;Convert value to ASCII call hex2asc clc find_str_exit: ret findc_str endp ;----------------------------------------------------------------------------- ; PARSE STR Returns the nth token in a string ;----------------------------------------------------------------------------- parse_str proc near assume cs:code,ds:code,es:code mov si,var2_value ;Convert 2nd param to hex call asc2hex mov di,100h mov cx,ax ;Save count sub cx,1 jb parse_str_3 mov bx,var3_value mov dl,[bx] ;Get parse char or dl,dl jne parse_str_0 mov dl,' ' parse_str_0: mov si,var1_value ;Get ptr to string or cx,cx ;Check count for 0 je parse_str_2 parse_str_1: mov bl,4 ;Scan for char in DL call scan4char jc parse_str_exit inc si loop parse_str_1 parse_str_2: mov di,si mov bl,4 ;Scan for char in DL call scan4char mov byte ptr [si],0 ;Term string parse_str_3: mov si,dest_var_val ;Get ptr to output buff xchg si,di call copy_string parse_str_exit: clc ret parse_str endp ;----------------------------------------------------------------------------- ; COMMAS STR Returns the nth token in a string ;----------------------------------------------------------------------------- commas_str proc near assume cs:code,ds:code,es:code mov di,var1_value call find_end mov ax,cx mov cl,3 div cl mov cl,ah ;Copy remainder xor ch,ch mov ah,al ;Save quotient mov al,',' mov si,var1_value mov di,dest_var_val ;Get ptr to output buff jcxz commas_1 rep movsb jmp commas_2 commas_1: mov cl,ah jcxz commas_str_exit jmp short commas_4 commas_2: mov cl,ah ;Get number of commas jcxz commas_str_exit commas_3: stosb ;Insert comma commas_4: movsw ;Copy 3 digits movsb loop commas_3 commas_str_exit: xor al,al stosb clc ret commas_str endp ;----------------------------------------------------------------------------- ; REPEAT STR Returns a string with n number of a character ;----------------------------------------------------------------------------- repeat_str proc near assume cs:code,ds:code,es:code mov si,var2_value ;Get character to repeat mov al,[si] push ax mov si,var1_value ;Convert 2nd param to hex call asc2hex mov cx,ax pop ax ;Get back repeat char or dx,dx jne repeat_error ;See if repeat number too cmp cx,VAR_SIZE ; big. jae repeat_error mov di,dest_var_val rep stosb xor al,al stosb clc repeat_exit: ret repeat_error: mov si,offset errmsg14 ;Number too large stc jmp short repeat_exit repeat_str endp ;============================================================================= ; File Functions ;============================================================================= ;----------------------------------------------------------------------------- ; READ REC returns record n from a file. ;----------------------------------------------------------------------------- readrec_file proc near assume cs:code,ds:code,es:code mov al,40h ;Read only, deny none call filename_open jc readrec_error mov si,var2_value ;Convert 2nd param to record call asc2hex ; number. mov si,offset errmsg8 ;Record not found. sub ax,1 sbb dx,0 jc readrec_error1 call findrec_file ;Find record. mov ax,si ;Copy end of file flag. mov si,offset errmsg8 ;Record not found. jc readrec_error1 ;Error if record not found. mov si,dest_var_val xchg di,si jcxz readrec_2 readrec_1: lodsb ;Copy record to destination cmp al,13 ; buffer. je readrec_3 stosb loop readrec_1 readrec_2: or ah,ah ;Check end of file flag jne readrec_3 mov dx,databuff_ptr ;If at end of data buffer. mov cx,VAR_SIZE ; read enough to complete call read_file ; record. jc readrec_error mov cx,ax ;Copy number of bytes read. mov si,dx ;Point to start of buffer jmp short readrec_1 readrec_3: xor al,al ;Append terminating zero stosb call close_file ;Close file jc readrec_error readrec_exit: ret readrec_error: call parse_doserr jmp short readrec_exit readrec_error1: call close_file stc jmp short readrec_exit readrec_file endp ;----------------------------------------------------------------------------- ; WRITE REC appends a string to the end of a file. ;----------------------------------------------------------------------------- writerec_file proc near assume cs:code,ds:code,es:code mov al,22h ;Read/Write, deny write call filename_open ;Parse name. open file jnc writerec_0 ; no exist, create file. call create_file jc writerec_error mov si,1 jmp short writerec_1 writerec_0: xor ax,ax ;Move file ptr to end of file cwd mov cx,2 ;Move pointer from end. call move_fileptr ;Move file pointer jc writerec_error mov si,1 or dx,dx jne writerec_01 or ax,ax je writerec_1 writerec_01: mov ax,-1 ;Move file ptr to last byte cwd mov cx,2 ;Move pointer from end. call move_fileptr ;Move file pointer jc writerec_error dec si ;Clear EOF marker flag mov dx,dest_var_val ;Read last char to check for mov cx,1 ; EOF marker call read_file jc writerec_error mov di,dx cmp byte ptr [di],1Ah jne writerec_1 mov ax,-1 ;See if last byte 1A EOF mark cwd mov cx,2 ;Move pointer from end. call move_fileptr ;Move file pointer jc writerec_error inc si ;Set EOF marker flag writerec_1: mov di,var2_value ;Get length of string mov dx,di call find_end dec di ;Backup before zero mov ax,0a0dh stosw inc cx inc cx or si,si je writerec_2 mov al,1ah ;Append EOF marker stosb inc cx writerec_2: call write_file jc writerec_error call close_file ;Close file jc writerec_error writerec_exit: mov di,dest_var_val ;Clear dest value. mov byte ptr [di],0 ret writerec_error: call parse_doserr ;Get msg for DOS error jmp short writerec_exit writerec_error1: call close_file stc jmp short writerec_exit writerec_file endp ;----------------------------------------------------------------------------- ; NUMREC FILE returns the number of records in a file. ;----------------------------------------------------------------------------- numrec_file proc near assume cs:code,ds:code,es:code call filename_open ;Parse name. open file jc numrec_error mov ax,-1 ;Try to find large rec num mov dx,ax call findrec_file ;Find record. jnc numrec_error1 ;Error if record found. not ax ;Compliment line count. not dx sub ax,1 sbb dx,0 mov di,dest_var_val ;Convert rec number to ASCII call hex2asc call close_file ;Close file jc numrec_error numrec_exit: ret numrec_error: call parse_doserr ;Get msg for DOS error jmp short numrec_exit numrec_error1: call close_file jc numrec_error stc jmp short numrec_exit numrec_file endp ;----------------------------------------------------------------------------- ; FIND REC returns an offset to the Nth record of a file. ; Entry: DX,AX - Record to find ; BX - Source File handle ; Exit: DX,AX - Records remaing if end of file ; CF - Set if record not found. ; DI - Points to record. ; CX - Number of bytes to end of data buffer ; SI - Points to error message if CF set. ;----------------------------------------------------------------------------- findrec_numl equ word ptr [bp-2] findrec_numh equ word ptr [bp-4] findrec_eof equ byte ptr [bp-5] findrec_file proc near assume cs:code,ds:code,es:code push bp mov bp,sp sub sp,6 mov si,offset errmsg8 ;Record not found mov findrec_eof,0 ;Clear end of file flag. mov findrec_numl,ax ;Save record number. mov findrec_numh,dx findrec_1: mov cx,databuff_ptr xchg cx,dx mov cx,DATABUFF_SIZE ;Get size of data buffer call read_file ;Read data from file. jc findrec_error cmp ax,cx ;See if buffer filled. If je findrec_2 ; not, end of file. mov findrec_eof,1 ;Set end of file flag. findrec_2: mov cx,ax ;Copy num bytes read. mov di,dx ;Copy buffer ptr mov al,13 ;Scan for CR mov dx,findrec_numl ;Check for end or dx,findrec_numh je findrec_5 jmp short findrec_4 findrec_3: mov dx,cx ;Save position in buffer sub findrec_numl,1 ;Decriment record count sbb findrec_numh,0 jne findrec_4 ;See if record count = 0 cmp findrec_numl,0 je findrec_5 findrec_4: repne scasb je findrec_3 cmp findrec_eof,1 ;If end of buffer, see if jne findrec_1 ; end of file. Yes = exit stc jmp short findrec_exit findrec_5: cmp byte ptr [di],0ah ;discard Line feed jne findrec_6 inc di dec cx findrec_6: clc findrec_exit: mov ah,findrec_eof mov al,0 mov si,ax ;Save end of file flag mov ax,findrec_numl ;Get record number. mov dx,findrec_numh mov sp,bp pop bp ret findrec_error: call parse_doserr ;Get msg for DOS error findrec_error1: stc jmp short findrec_exit findrec_file endp ;----------------------------------------------------------------------------- ; FILE SIZE returns the size of a file ;----------------------------------------------------------------------------- filesize_file proc near assume cs:code,ds:code,es:code mov al,40h ;Read only, deny none. call filename_open ;Parse name. open file mov di,dest_var_val ;Point DI to result buffer. jc filesize_error xor ax,ax ;Zero offset. xor dx,dx mov cl,2 ;Move pointer from end. call move_fileptr ;Move file pointer jc filesize_error call hex2asc ;Convert size to ASCII call close_file ;Close file jc filesize_error filesize_exit: ret filesize_error: call parse_doserr ;Get msg for DOS error jmp short filesize_exit filesize_file endp ;----------------------------------------------------------------------------- ; TRUENAME FILE returns the fully qualified name of a file. ;----------------------------------------------------------------------------- truename_file proc near assume cs:code,ds:code,es:code mov si,var1_value ;Fully qualify filename mov di,dest_var_val ;Use dest buff as temp buff call parse_filename jnc truename_1 mov si,offset errmsg6 ;Illegal filename msg truename_1: ret truename_file endp ;----------------------------------------------------------------------------- ; FILE DATE returns the date of a file ;----------------------------------------------------------------------------- filedate_file proc near assume cs:code,ds:code,es:code mov al,40h ;Read only, deny none. call filename_open jc filedate_error mov ax,5700h ;Get file date/time int 21h jc filedate_error push bx ;Save file handle mov ax,dx ;DX: yyyy yyym mmmd dddd shl dx,1 shl dx,1 shl dx,1 mov dl,al ;DH:Months, DL:days and dx,0f1fh ;Clear off unneeded bits shr ah,1 ;Align years mov cx,1980 ;Set starting year add cl,ah ;This fails in year 2048 mov di,dest_var_val call print_date ;Write date pop bx ;Restore file handle call close_file ;Close file jc filedate_error filedate_exit: ret filedate_error: call parse_doserr ;Get msg for DOS error jmp short filedate_exit filedate_file endp ;----------------------------------------------------------------------------- ; FILE TIME returns the time of a file ;----------------------------------------------------------------------------- filetime_file proc near assume cs:code,ds:code,es:code mov al,40h ;Read only, deny none. call filename_open ;Parse name. open file jc filetime_error mov ax,5700h ;Get file date/time int 21h jc filetime_error push bx ;Save file handle mov dh,cl ;CX: hhhh hmmm mmms ssss shl dh,1 ;Mul seconds by 2 and dh,3fh ;Mask off other bits rol cx,1 ;Roll hours to low byte rol cx,1 ; but stop at 3 to rol cx,1 ; copy now aligned mov al,ch ; minute bits. rol cx,1 rol cx,1 mov ch,al ;Get back minutes xchg ch,cl and cx,1f3fh ;Mask off sec bits mov di,dest_var_val call print_time pop bx ;Restore file handle call close_file ;Close file jc filetime_error filetime_exit: ret filetime_error: call parse_doserr ;Get msg for DOS error jmp short filetime_exit filetime_file endp ;============================================================================= ; System Functions ;============================================================================= ;----------------------------------------------------------------------------- ; VER SYS returns the DOS version number ;----------------------------------------------------------------------------- ver_sys proc near assume cs:code,ds:code,es:code mov ax,dos_version ;Get DOS verison mov di,dest_var_val call printver ;Print version clc ret ver_sys endp ;----------------------------------------------------------------------------- ; ASK2 SYS prints a string then returns the user response. ;----------------------------------------------------------------------------- ask2_sys proc near assume cs:code,ds:code,es:code mov al,quiet_flag ;Save state of quiet flag push ax mov quiet_flag,0 ;Clear quiet flag xor bx,bx ;Clear password flag mov cx,VAR_SIZE - 1 cmp num_params,1 jb ask2_3 je ask2_2 mov si,var3_value ;Chk for password flag call asc2hex cmp ax,2 ja ask2_1 mov bx,ax ;Copy password flag ask2_1: mov si,var2_value ;Get max num of chars call asc2hex mov cx,ax cmp cx,VAR_SIZE - 1 mov si,offset errmsg14 ;Number too large ja ask2_error ask2_2: mov si,var1_value call print_str ;Print prompt string ask2_3: mov di,dest_var_val call read_console mov si,offset endmsg call print_str ;Insert a CR-LF clc ask2_exit: pop ax mov quiet_flag,al ret ask2_error: stc jmp short ask2_exit ask2_sys endp ;----------------------------------------------------------------------------- ; ENVFREE SYS returns the number of bytes free in the environment. ;----------------------------------------------------------------------------- envfree_sys proc near assume cs:code,ds:code,es:code push es mov ax,masterenv_seg cmp use_mastenv,0 jne envfree_0 mov ax,localenv_seg envfree_0: push ax dec ax mov es,ax mov dx,es:[3] ;Get size of env segment mov cl,4 ;Convert paragraphs to bytes shl dx,cl pop es mov cx,dx xor ax,ax xor di,di envfree_1: repne scasb ;Loop through the environment cmp byte ptr es:[di],al ; until the end of the loopne envfree_1 ; env strings is found. jcxz envfree_2 mov ax,dx sub ax,di dec ax ;Sub byte for extra zero envfree_2: xor dx,dx pop es mov di,dest_var_val call hex2asc clc envfree_exit: ret envfree_sys endp ;----------------------------------------------------------------------------- ; ENVSIZE SYS returns the size of the environment. ;----------------------------------------------------------------------------- envsize_sys proc near assume cs:code,ds:code,es:code push es mov ax,masterenv_seg cmp use_mastenv,0 jne envsize_1 mov ax,localenv_seg envsize_1: push ax dec ax mov es,ax mov ax,es:[3] ;Get size of env segment mov cl,4 ;Convert paragraphs to bytes shl ax,cl pop es xor dx,dx pop es mov di,dest_var_val call hex2asc clc ret envsize_sys endp ;----------------------------------------------------------------------------- ; MASTERVAR SYS returns the value from a variable in the master environment. ;----------------------------------------------------------------------------- mastervar_sys proc near assume cs:code,ds:code,es:code push ds push es mov ax,masterenv_seg mov di,var1_value ;Point to env var name call getenvvar ;Get ptr to env var value jc mastervar_exit ;CF = 1, var not found. mov di,cs:dest_var_val ;Copy var value to dest string call copy_string clc mastervar_exit: pop ds pop es ret mastervar_sys endp ;----------------------------------------------------------------------------- ; LOCALVAR SYS returns the value from a variable in the local environment. ;----------------------------------------------------------------------------- localvar_sys proc near assume cs:code,ds:code,es:code push ds push es mov ax,localenv_seg mov di,var1_value ;Point to env var name call getenvvar ;Get ptr to env var value jc localvar_exit ;CF = 1, var not found. mov di,cs:dest_var_val ;Copy var value to dest string call copy_string clc localvar_exit: pop ds pop es ret localvar_sys endp ;----------------------------------------------------------------------- ; INWIN SYS returns 1 if Windows currently running. ;----------------------------------------------------------------------- inwin_sys proc near assume cs:code,ds:code,es:code mov ax,1600h ;See if enhanced mode Win int 2fh or al,al jne inwin_1 mov ax,4680h ;See if std or real Win int 2fh or al,al mov al,0 jne inwin_2 inwin_1: mov al,1 ;Indicate Windows active inwin_2: xor ah,ah xor dx,dx mov di,dest_var_val call hex2asc ;Convert result to ASCII clc ret inwin_sys endp ;----------------------------------------------------------------------- ; INT2FCHECK Calls Interupt 2F (Multiplex) to determine if a program is ; loaded. ;----------------------------------------------------------------------- int2fcheck_sys proc near assume cs:code,ds:code,es:code xor ax,ax cmp dos_version,300h ;Don't call 2F if DOS 2.x jb int2fcheck_3 mov si,var1_value ;Point to 1st parameter call caps_string mov di,offset int2fname_tbl ;See if an alias is used in call findstr ; place of a number. jc int2fcheck_1 mov al,[bx+offset int2falias_tbl] jmp short int2fcheck_2 int2fcheck_1: mov si,var1_value ;Convert 1st parameter to hex call asc2hex mov si,offset errmsg14 ;Number too large or dx,dx jne int2fcheck_error ;Make sure the number is or ah,ah ; less than 256 jne int2fcheck_error int2fcheck_2: xor ah,ah xchg ah,al ;Device number in AH 0 in AL cmp ah,13h ;Don't call for device 13 je int2fcheck_3 push si push bp pushf mov saved_spint,sp int 2fh cli mov bx,cs ;Assume nothing after blind mov ds,bx ; Int 2F call. Restore stack mov es,bx ; and other registers. mov ss,bx mov sp,saved_spint sti popf pop bp pop si int2fcheck_3: xor ah,ah xor dx,dx mov di,dest_var_val call hex2asc ;Convert result to ASCII clc int2fcheck_exit: ret int2fcheck_error: stc jmp short int2fcheck_exit int2fcheck_sys endp ;----------------------------------------------------------------------- ; FILES SYS Returns the number of files that can be opened ;----------------------------------------------------------------------- files_sys proc near assume cs:code,ds:code,es:code push es mov ah,52h ;Get list of lists int 21h les bx,es:[bx+4] ;Get ptr to Sys File Table xor ax,ax ;Clear count files_1: mov cx,es ;If ptr -1, no more cmp bx,-1 ; entries. je files_3 files_2: add ax,es:[bx+4] ;Add num of files in tbl les bx,es:[bx] ;Get ptr to next file tbl jmp short files_1 files_3: pop es xor dx,dx mov di,dest_var_val call hex2asc ;Convert result to ASCII clc ret files_sys endp ;----------------------------------------------------------------------- ; LASTDRIVE SYS Returns the last drive letter allowed by system ;----------------------------------------------------------------------- lastdrive_sys proc near push es mov ah,52h ;Get list of lists int 21h mov si,10h ;Assume 2.x offset cmp dos_version,300h jb lastdrive_1 mov si,1bh ;Assume 3.0 offset cmp dos_version,310h jb lastdrive_1 mov si,1bh ;Assume 3.1,2,3 offset cmp dos_version,400h jb lastdrive_1 mov si,21h ;Assume 4.x, 5.x offset lastdrive_1: mov al,es:[bx+si] ;Get lastdrive value add ax,'@' ;Convert to letter pop es mov di,dest_var_val mov ah,':' stosw xor al,al ;Append terminating 0 stosb clc ret lastdrive_sys endp ;------------------------------------------------------------------------ ; TRUEVER SYS returns the real DOS version number. DOS 5 or later ;------------------------------------------------------------------------ truever_sys proc near assume cs:code,ds:code,es:code mov ax,dos_version ;Get std DOS version cmp ax,500h jb truever_1 mov ax,3306h ;Get real DOS version int 21h mov ax,bx xchg al,ah truever_1: mov di,dest_var_val call printver ;Print version clc truever_exit: ret truever_sys endp ;------------------------------------------------------------------------ ; CODEPAGE SYS returns the active code page ;------------------------------------------------------------------------ codepage_sys proc near assume cs:code,ds:code,es:code mov ax,31eh cmp ax,dos_version ;See if DOS 3.3 ja codepage_error mov ax,6601h ;Get global code page int 21h mov ax,bx ;Get code page xor dx,dx mov di,dest_var_val call hex2asc ;Print code page clc codepage_exit: ret codepage_error: call seterr0msg ;Error, not DOS 3.3 jmp short codepage_exit codepage_sys endp ;------------------------------------------------------------------------ ; COUNTRY SYS returns the active code page ;------------------------------------------------------------------------ country_tbl db 0,2,7,9,11,13,15,16,17,22 country_sys proc near assume cs:code,ds:code,es:code mov ax,3800h ;Get country info mov dx,databuff_ptr ;Point to data buffer int 21h xor ah,ah cmp al,-1 jne countrysys_1 mov ax,bx ;Get country code countrysys_1: cmp num_params,0 je countrysys_4 mov si,var1_value call asc2hex mov si,databuff_ptr cmp ax,9 ja countrysys_error countrysys_2: mov cl,al mov bx,offset country_tbl xlat add si,ax mov ax,[si] ;Get word or cl,cl je countrysys_4 xor ah,ah ;Other than 0, byte cmp cl,5 ;1,2,3,4,9 are jbe countrysys_3 ; ASCIIZ strings cmp cl,9 je countrysys_3 jmp short countrysys_4 countrysys_3: mov di,dest_var_val ;Copy string call copy_string jmp short countrysys_exit countrysys_4: xor dx,dx mov di,dest_var_val call hex2asc ;Print code page countrysys_exit: clc countrysys_exit1: ret countrysys_error: stc mov si,offset errmsg14 ;Number too large jmp short countrysys_exit1 country_sys endp ;------------------------------------------------------------------------ ; BIOSDATE SYS returns the date of the ROM BIOS ;------------------------------------------------------------------------ biosdate_sys proc near assume cs:code,ds:code,es:code push ds mov si,0f000h ;ROM segment mov ds,si mov si,0fff5h ;Offset of date mov di,cs:dest_var_val mov cx,4 ;Copy 8 bytes rep movsw pop ds xor al,al ;Add terminating 0 stosb clc ret biosdate_sys endp ;------------------------------------------------------------------------ ; GETKEY SYS Waits for a key and returns the ASCII code and scan code ;------------------------------------------------------------------------ getkey_sys proc near assume cs:code,ds:code,es:code call getkey mov di,dest_var_val push ax xor ah,ah xor dx,dx call hex2asc mov byte ptr [di-1],' ' ;Replace term 0 with space pop ax xor al,al xchg al,ah call hex2asc clc ret getkey_sys endp ;------------------------------------------------------------------------ ; LOCALENV SYS Returns the segment of the local env ;------------------------------------------------------------------------ localenv_sys proc near assume cs:code,ds:code,es:code mov ax,localenv_seg xor dx,dx mov di,dest_var_val call hex2asc clc ret localenv_sys endp ;------------------------------------------------------------------------ ; MASTERENV SYS Returns the segment of the master env ;------------------------------------------------------------------------ masterenv_sys proc near assume cs:code,ds:code,es:code mov ax,masterenv_seg xor dx,dx mov di,dest_var_val call hex2asc clc ret masterenv_sys endp ;======================================================================== ; Number Functions ;======================================================================== ;------------------------------------------------------------------------ ; ADD NUM returns the sum of a series of numbers ;------------------------------------------------------------------------ add_num proc near assume cs:code,ds:code,es:code mov bx,offset addnum_callback call process_nums ;Process vars mov si,offset errmsg12 ;Overflow message ret addnum_callback: add si,ax ;Add number to running adc di,dx ; sum. ret add_num endp ;------------------------------------------------------------------------ ; SUB NUM returns the difference of two numbers ;------------------------------------------------------------------------ sub_num proc near assume cs:code,ds:code,es:code mov bx,offset subnum_callback call process_nums ;Process vars mov si,offset errmsg13 ;Underflow message ret subnum_callback: sub si,ax ;Add number to running sbb di,dx ; sum. ret sub_num endp ;------------------------------------------------------------------------ ; MUL NUM returns the product of two numbers ;------------------------------------------------------------------------ mul_num proc near assume cs:code,ds:code,es:code mov bx,offset mulnum_callback call process_nums ;Process vars mov si,offset errmsg13 ;Overflow message mulnum_exit: ret mul_num_error: stc mov si,offset errmsg10 ;Multiply overflow stc jmp short mulnum_exit mulnum_callback: push bx push cx push dx push bp mov cx,dx ;Copy numbers mov bx,ax mul cx ;32 bit multiply. jc mulcb_exit ;Param 1 in DI,SI mov bp,ax ;Param 2 in CX,BX mov ax,di mul cx ; DI SI or ax,dx ; CX BX jnz mulcb_exit ; --------------------- mov ax,di ; (BX * SI) mul bx ; (BX * DI) jc mulcb_exit ; (CX * SI) add bp,ax ; + (CX * DI) mov ax,si ; --------------------- mul bx ; DX AX add dx,bp mov si,ax mov di,dx mulcb_exit: pop bp pop dx pop cx pop bx ret mul_num endp ;------------------------------------------------------------------------ ; DIV NUM returns the quotient of two numbers ;------------------------------------------------------------------------ div_num proc near assume cs:code,ds:code,es:code call conv2num ;Convert first two parms to jc div_num_exit ; 32 bit numbers. push cx or cx,bx ;Prevent divide by zero pop cx jz div_num_error div_num_1: or cx,cx ;Divide both numbers by 2 je div_num_2 ; until high word of shr dx,1 ; divisor (CX) is zero. rcr ax,1 shr cx,1 rcr bx,1 jmp short div_num_1 div_num_2: push ax ;Save low word mov ax,dx xor dx,dx div bx ;Divide high word mov cx,ax ;Save high quotent pop ax div bx ;Divide low word mov dx,cx mov di,dest_var_val call hex2asc ;Convert result to ASCII div_num_exit: ret div_num_error: mov si,offset errmsg11 stc jmp short div_num_exit div_num endp ;------------------------------------------------------------------------ ; AND NUM returns the logical AND of two numbers ;------------------------------------------------------------------------ and_num proc near assume cs:code,ds:code,es:code mov bx,offset andnum_callback call process_nums ;Process vars mov si,offset errmsg14 ;Number too large ret andnum_callback: and si,ax ;AND number and di,dx ; ret and_num endp ;------------------------------------------------------------------------ ; OR NUM returns the logical OR of two numbers ;------------------------------------------------------------------------ or_num proc near assume cs:code,ds:code,es:code mov bx,offset ornum_callback call process_nums ;Process vars mov si,offset errmsg14 ;Number too large ret ornum_callback: or si,ax ;OR number or di,dx ; ret or_num endp ;------------------------------------------------------------------------ ; XOR NUM returns the logical exclusive OR of two numbers ;------------------------------------------------------------------------ xor_num proc near assume cs:code,ds:code,es:code call conv2num ;Convert first two parms to jc xor_num_exit ; 32 bit numbers. Carry xor ax,bx ; set, overflow. xor dx,cx mov di,dest_var_val call hex2asc ;Convert result to ASCII xor_num_exit: ret xor_num endp ;------------------------------------------------------------------------ ; NOT NUM returns the inverse of a number ;------------------------------------------------------------------------ not_num proc near assume cs:code,ds:code,es:code mov si,var1_value ;Convert 1st parameter to hex call asc2hex mov si,offset errmsg14 ;Number too large jc not_num_exit ;If error, exit not ax not dx mov di,dest_var_val call hex2asc ;Convert result to ASCII not_num_exit: ret not_num endp ;------------------------------------------------------------------------ ; CONVERT NUM converts a number to the base specified by 2nd param ;------------------------------------------------------------------------ convert_num proc near assume cs:code,ds:code,es:code call conv2num ;Convert first two parms or cx,cx jne convertnum_error cmp bx,16 ja convertnum_error cmp bl,1 jbe convertnum_error mov number_base,bx mov di,dest_var_val call hex2asc ;Convert result to ASCII convertnum_exit: ret convertnum_error: mov si,offset errmsg14 ;Number too large stc jmp short convertnum_exit convert_num endp ;======================================================================== ; Programming Functions ;======================================================================== ;------------------------------------------------------------------------ ; PEEK PROG Returns byte(s) from memory ;------------------------------------------------------------------------ peek_prog proc near assume cs:code,ds:code,es:code push bp call conv2num ;Convert first two parms to jc peek_prog_exit ; 32 bit numbers. mov si,offset errmsg14 or dx,cx ;Check to see that neither jne peek_prog_err1 ; number > 64K mov cx,1 ;Assume 1 byte peek mov bp,0 ;Assume byte size peek mov di,dest_var_val ;Pt to output buff mov si,ax ;Save seg value cmp num_params,3 ;If 3rd param, it is the jb peek_prog_1 ; number of bytes to push ax ; return push bx push si mov si,var3_value call asc2hex mov cx,ax pop si pop bx pop ax cmp num_params,4 ;If 4th param, it signals jb peek_prog_1 ; word size peek mov bp,1 shr cx,1 peek_prog_1: and cx,003fh ;Allow only 64 bytes out jne peek_prog_2 mov cx,1 peek_prog_2: push es mov es,si mov ax,es:[bx] pop es or bp,bp ;If word size, print je peek_prog_3 ; high byte first. push ax xor al,al xchg ah,al xor dx,dx call lead_zero call hex2asc ;Convert result to ASCII inc bx dec di pop ax peek_prog_3: xor ah,ah xor dx,dx call lead_zero call hex2asc ;Convert result to ASCII inc bx mov byte ptr [di-1],' ' ;Replace term 0 with space loop peek_prog_1 mov byte ptr [di-1],0 ;Restore term 0 peek_prog_exit: pop bp ret peek_prog_err1: stc jmp short peek_prog_exit peek_prog endp ;------------------------------------------------------------------------ ; POKE PROG Writes a string of bytes to memory ;------------------------------------------------------------------------ poke_prog proc near assume cs:code,ds:code,es:code call conv2num ;Convert first two parms to jc poke_prog_exit ; 32 bit numbers. mov si,offset errmsg14 ;Number too large or dx,cx ;Check to see that neither jne poke_prog_error ; number > 64K mov si,offset errmsg18 ;Not enough parameters mov cx,num_params sub cx,2 jbe poke_prog_error mov si,offset var3_value push es mov es,ax ;Load segment mov di,bx ;Load offset cli poke_prog_1: push si mov si,[si] ;Get ptr to next var call asc2hex pop si jnc poke_prog_3 poke_prog_2: sti pop es mov si,offset errmsg14 ;Number too large stc jmp poke_prog_exit poke_prog_3: or dx,dx ;Check to see if poke jne poke_prog_2 ; val > 256 or ah,ah jne poke_prog_2 stosb inc si ;Move ptr to next var inc si loop poke_prog_1 pop es mov di,dest_var_val ;Zero return value mov byte ptr [di],0 clc poke_prog_exit: ret poke_prog_error: stc jmp short poke_prog_exit poke_prog endp ;------------------------------------------------------------------------ ; IN PROG Returns a byte from an IO port. ;------------------------------------------------------------------------ in_prog proc near assume cs:code,ds:code,es:code mov si,var1_value ;Convert 1st param to hex call asc2hex mov si,offset errmsg14 ;Number too large jc in_prog_exit ;If error, exit or dx,dx ;Make sure number not too jne in_prog_error ; big. mov dx,ax in al,dx xor ah,ah xor dx,dx mov di,dest_var_val call hex2asc ;Convert result to ASCII in_prog_exit: ret in_prog_error: stc jmp short in_prog_exit in_prog endp ;------------------------------------------------------------------------ ; OUT PROG Outputs a byte to an IO port. ;------------------------------------------------------------------------ out_prog proc near assume cs:code,ds:code,es:code call conv2num ;Convert first two parms to jc out_prog_exit ; 32 bit numbers. mov si,offset errmsg14 ;Number too large or dx,dx ;Check to see that neither jne out_prog_error ; number > 64K or cx,cx jne poke_prog_error or bh,bh jne poke_prog_error mov dl,bl xchg ax,dx out dx,al mov di,dest_var_val ;Zero output mov byte ptr [di],0 out_prog_exit: ret out_prog_error: stc jmp short out_prog_exit out_prog endp ;------------------------------------------------------------------------ ; INTERRUPT PROG Performs an system interrupt ; NOTE: This routine contains self modifying code!!! ;------------------------------------------------------------------------ interrupt_prog proc near assume cs:code,ds:code,es:code push bp mov si,var1_value ;Convert 1st param to hex call asc2hex jnc intprog_0 intprog_error: mov si,offset errmsg14 ;Number too large stc jmp short intprog_error intprog_0: or dl,dh ;Make sure number not too or dl,ah ; big. jne intprog_error mov si,offset intprog_opcode mov [si+1],al ;Set interrupt number mov bp,offset var1_value ;Get ptr to array mov cx,9 intprog_1: inc bp inc bp mov si,[bp] ;Get ptr to next param call asc2hex ;Convert to hex or dx,dx ;Limit test jne intprog_error mov [bp],ax ;Save hex value loop intprog_1 std ;Set direction down! mov si,bp ;copy ptr to array lodsw mov es,ax assume es:nothing lodsw push ax ;Save DS for later lodsw mov bp,ax lodsw push ax ;Save SI for later lodsw mov di,ax lodsw mov dx,ax lodsw mov cx,ax lodsw mov bx,ax lodsw pop si pop ds intprog_2: cld ;For neatness assume ds:nothing mov cs:saved_ssint,ss mov cs:saved_spint,sp intprog_opcode: int 2fh ;Perform interrupt cli mov ss,cs:saved_ssint ;Restore stack mov sp,cs:saved_spint sti pushf cld ;Set dir flag UP push es push di push cs pop es assume es:code mov di,offset var1_value stosw ;Save AX mov ax,bx stosw mov ax,cx stosw mov ax,dx stosw pop ax ;Get returned DI stosw mov ax,si stosw mov ax,bp stosw mov ax,ds stosw pop ax ;Get returned ES stosw pop ax ;Get returned flags stosw push cs ;Reset DS = CS pop ds assume ds:code mov si,offset var1_value mov di,dest_var_val ;Zero output mov cx,10 intprog_3: lodsw ;Get reg value xor dx,dx call hex2asc ;Convert number mov byte ptr [di-1],' ' loop intprog_3 mov byte ptr [di-1],0 ;Restore last 0 clc intprog_exit: pop bp ret interrupt_prog endp ;------------------------------------------------------------------------ ; SCAN PROG Returns byte(s) from memory ;------------------------------------------------------------------------ scan_prog proc near assume cs:code,ds:code,es:code push bp mov bp,offset var3_value ;Get ptr to scan bytes mov di,databuff_ptr ;Use file data buff mov cx,num_params sub cx,2 jbe scan_prog_error mov bx,cx ;Save byte count scan_prog_0: mov si,[bp] ;Get ptr to variable inc bp ;Point BP to next var inc bp call asc2hex ;Convert ASCII num to stosb ; hex num and store. or dx,dx jne scan_prog_err1 or ah,ah jne scan_prog_err1 loop scan_prog_0 xor al,al ;Term string stosb mov bp,bx ;Save scan str length call conv2num ;Convert first two parms to jc scan_prog_exit ; 32 bit numbers. mov si,offset errmsg14 or dx,cx ;Check to see that neither jne scan_prog_err1 ; number > 64K push es mov es,ax ;Get segment mov dx,databuff_ptr ;DX pts to scan string mov cx,bx ;Scan remaining segment neg cx scan_prog_2: push cx mov di,bx ;Get mem offset mov si,dx ;Get scan str offset mov cx,bp ;Get scan str length rep cmpsb pop cx je scan_prog_3 inc bx loop scan_prog_2 pop es mov si,offset errmsg20 ;String not found jmp short scan_prog_error scan_prog_3: pop es xor dx,dx mov di,dest_var_val call hex2asc mov byte ptr [di-1],' ' ;Replace 0 with space mov ax,bx call hex2asc clc scan_prog_exit: pop bp ret scan_prog_err1: mov si,offset errmsg14 ;Number too large scan_prog_error: stc jmp short scan_prog_exit scan_prog endp ;======================================================================== ; Time and Date Functions ;======================================================================== ;------------------------------------------------------------------------ ; DAY TIME Returns the name of the current day ;------------------------------------------------------------------------ day_time proc near assume cs:code,ds:code,es:code cmp num_params,1 jae day_time_1 mov ah,2ah ;Get system day int 21h xor ah,ah jmp short day_time_2 day_time_1: mov si,var1_value ;Convert 1st parameter to hex call asc2hex mov si,offset errmsg14 ;Number too large jc day_time_exit ;If error, exit or dx,dx jne day_time_error or ax,ax je day_time_error cmp ax,7 ja day_time_error dec ax day_time_2: mov bx,ax mov di,offset day_list call get_string mov si,cs:dest_var_val xchg si,di call copy_string clc day_time_exit: ret day_time_error: stc jmp short day_time_exit day_time endp ;------------------------------------------------------------------------ ; MONTH TIME Returns the name of the current month ;------------------------------------------------------------------------ month_time proc near assume cs:code,ds:code,es:code cmp num_params,1 jae month_time_1 mov ah,2ah ;Get system date int 21h mov bl,dh xor bh,bh jmp short month_time_2 month_time_1: mov si,var1_value ;Convert 1st parameter to hex call asc2hex mov si,offset errmsg14 ;Number too large jc month_time_exit ;If error, exit or dx,dx jne month_time_error or ax,ax je month_time_error cmp ax,12 ja month_time_error mov bx,ax month_time_2: dec bx mov di,offset month_list call get_string mov si,cs:dest_var_val xchg si,di call copy_string clc month_time_exit: ret month_time_error: stc jmp short month_time_exit month_time endp ;----------------------------------------------------------------------- ; DATE TIME Returns the current date. The date is returned either ; as Month xx, 199x or as mm-dd-yyyy depending on params. ;----------------------------------------------------------------------- date_time proc near assume cs:code,ds:code,es:code xor ax,ax ;Clear style flag cmp num_params,1 jb date_time_1 mov si,var1_value ;Convert 1st parameter to hex call asc2hex jc date_time_error mov si,offset errmsg14 ;Number too large or dx,dx jne date_time_error cmp al,1 ja date_time_error date_time_1: push ax mov ah,2ah ;Get system date int 21h xor ah,ah pop bx ;Get back style param cmp bl,1 je date_time_2 push cx ;Save year push dx ;Save day of the month mov bl,dh ;Copy month dec bx mov di,offset month_list call get_string mov si,dest_var_val xchg si,di call copy_string mov byte ptr [di-1],' ' ;Change term 0 to space pop ax ;Get day xor ah,ah xor dx,dx call hex2asc ;Convert day to ASCII mov word ptr [di-1],' ,' ;Change term 0 to , space inc di pop ax ;Get year xor dx,dx call hex2asc ;Convert year to ASCII jmp short date_time_exit date_time_2: mov di,dest_var_val call print_date ;Print in mm-dd-yyyy fmt date_time_exit: clc date_time_exit1: ret date_time_error: stc jmp short date_time_exit1 date_time endp ;----------------------------------------------------------------------- ; TIME TIME Returns the current time. ;----------------------------------------------------------------------- time_time proc near assume cs:code,ds:code,es:code mov ah,2ch ;Get system date int 21h mov di,dest_var_val call print_time ;Print in hh:mm:ss fmt time_time_exit: clc time_time_exit1: ret time_time_error: stc jmp short time_time_exit1 time_time endp ;======================================================================= ; Memory functions ;======================================================================= ;----------------------------------------------------------------------- ; TOTALMEM MEM Returns the size of the largest blk of free conv mem ;----------------------------------------------------------------------- totalmem_mem proc near assume cs:code,ds:code,es:code int 12h ;Get conv mem size totalmem_2: mov cx,1024 ;Convert Kbytes mul cx ; to bytes mov di,dest_var_val call hex2asc clc ret totalmem_mem endp ;----------------------------------------------------------------------- ; FREEMEM MEM Returns the size of the largest blk of free conv mem ;----------------------------------------------------------------------- freemem_mem proc near assume cs:code,ds:code,es:code cmp installed,0 je freemem_1 mov ah,48h mov bx,-1 ;Ask for all mem int 21h mov ax,bx jmp short freemem_2 freemem_1: mov ax,ds:[2] ;Get end of mem ptr mov bx,cs sub ax,bx freemem_2: mov cx,16 ;Convert paragraphs mul cx ; to bytes mov di,dest_var_val call hex2asc clc ret freemem_mem endp ;----------------------------------------------------------------------- ; FREEEXT MEM Returns the size of extended memory ;----------------------------------------------------------------------- freeext_mem proc near assume cs:code,ds:code,es:code cmp xms_version,0 ;See if mem driver je freeext_1 mov ah,8 call ds:[xms_serv] ;Call driver jmp short freeext_2 freeext_1: mov ah,88h ;Get ext mem size int 15h ; BIOS call jnc freeext_2 xor ax,ax freeext_2: mov cx,1024 ;Convert 1K to bytes mul cx mov di,dest_var_val call hex2asc clc freeext_exit: ret freeext_mem endp ;----------------------------------------------------------------------- ; TOTALEXT MEM Returns the size of extended memory ;----------------------------------------------------------------------- totalext_mem proc near assume cs:code,ds:code,es:code cmp xms_version,0 ;See if mem driver je totalext_1 mov ah,8 call ds:[xms_serv] ;Call driver mov ax,dx jmp short totalext_2 totalext_1: mov ah,88h ;Get ext mem size int 15h ; BIOS call jnc totalext_2 xor ax,ax totalext_2: mov cx,1024 ;Convert 1K to bytes mul cx mov di,dest_var_val call hex2asc clc totalext_exit: ret totalext_mem endp ;----------------------------------------------------------------------- ; EXTVER MEM Returns the version of the extended memory driver ; Check version again, since some driver change version reporting ; depending on the system environment. ;----------------------------------------------------------------------- extver_mem proc near assume cs:code,ds:code,es:code mov ax,xms_version ;See if mem driver or ax,ax je extver_1 xor ax,ax call ds:[xms_serv] ;Get version number mov bx,ax ;Version num returned shr al,1 ; as BCD. Convert shr al,1 ; to std DOS format shr al,1 ; of maj in AH and shr al,1 ; minor in AL mov ah,10 mul ah and bl,0fh add al,bl mov ah,bh extver_1: mov di,dest_var_val call printver clc extver_exit: ret extver_mem endp ;----------------------------------------------------------------------- ; TOTALEMS MEM Returns the size of Expanded memory ;----------------------------------------------------------------------- totalems_mem proc near assume cs:code,ds:code,es:code xor ax,ax or ax,ems_version je totalems_1 mov ah,42h ;Get EMS Mem amounts int 67h ;Call driver mov ax,dx mov cx,16384 ;Convert 16K pages mul cx ; to bytes totalems_1: mov di,dest_var_val call hex2asc clc totalems_exit: ret totalems_mem endp ;----------------------------------------------------------------------- ; FREEEMS MEM Returns the amount of free Expanded memory ;----------------------------------------------------------------------- freeems_mem proc near assume cs:code,ds:code,es:code xor ax,ax or ax,ems_version je freeems_1 mov ah,42h ;Get EMS Mem amounts int 67h ;Call driver mov ax,bx mov cx,16384 ;Convert 16K pages mul cx ; to bytes freeems_1: mov di,dest_var_val call hex2asc clc freeems_exit: ret freeems_mem endp ;----------------------------------------------------------------------- ; EMSVER MEM Returns the version of the extended memory driver ; Check version again, since some driver change version reporting ; depending on the system environment. ;----------------------------------------------------------------------- emsver_mem proc near assume cs:code,ds:code,es:code mov ax,ems_version ;See if mem driver or ax,ax je emsver_1 mov ah,46h ;Get version int 67h or ah,ah je emsver_0 xor ax,ax emsver_0: mov bl,al ;Convert ver number shl ax,1 shl ax,1 shl ax,1 shl ax,1 mov al,bl and ax,0f0fh emsver_1: mov di,dest_var_val call printver clc emsver_exit: ret emsver_mem endp ;----------------------------------------------------------------------- ; FREEUMB MEM Returns the size of the largest free upper memory block ;----------------------------------------------------------------------- freeumb_mem proc near assume cs:code,ds:code,es:code cmp dos_version,500h jae freeumb_0 cmp xms_version,0 mov cx,0 je freeumb_3 mov dx,-1 mov ah,10h ;Request umb from drvr call ds:[xms_serv] mov cx,dx ;Save largest available jmp short freeumb_3 freeumb_0: mov ax,5800h ;Get allocation strat int 21h push ax ;Save strategy mov ax,5802h ;Get UMB link state int 21h xor ah,ah push ax ;Save link state mov ax,5803h ;Link UMBs mov bx,1 int 21h jnc freeumb_1 call check4xms ;See for ext mem drvr mov cx,0 jc freeumb_2 mov dx,-1 mov ah,10h ;Request umb from drvr call ds:[xms_serv] mov cx,dx ;Save largest available jmp short freeumb_2 freeumb_1: mov ax,5801h ;Set mem alloc strat mov bx,41h ;Best fit high only int 21h mov ah,48h ;Alloc mem mov bx,-1 int 21h mov cx,bx ;Save largest block freeumb_2: pop bx ;Get UMB link state mov ax,5803h int 21h pop bx ;Get mem alloc strat mov ax,5801h int 21h freeumb_3: mov ax,cx mov cx,16 mul cx mov di,dest_var_val call hex2asc clc freeumb_exit: ret freeumb_error: call seterr0msg ;Error, not DOS 5.0 jmp short freeumb_exit freeumb_mem endp ;======================================================================= ; Program Support Functions ;======================================================================= ;----------------------------------------------------------------------- ; HELP STRINGS Help function for the program ### ;----------------------------------------------------------------------- help_tag1 db "Function: ",0 help_tag2 db " - Returns ",0 help_tag3 db 13,10,"Syntax: STRINGS [dest var =] ",0 help_tag4 db " ",0 help_tag5 db "This is a list of the available commands" help_tag7 db ".",13,10,0 help_tag6 db 13,10,"For help on a specific command type: " db "STRINGS HELP Command",0 help_error db "Command Help not available once installed",0 help_strings proc near assume cs:code,ds:code,es:code push bp mov si,offset program ;Print copyright msg call print_strcr mov si,cmd_value ;Point to command buffer cmp help_flag,0 jne help_1 mov si,var1_value help_1: mov bp,si call caps_string ;Search cmd table for inc cx ; function. If not mov di,offset command_table ; found, print general call findstr ; help message. jc help_3 cmp installed,0 ;If installed, cmd help je help_2 ; not loaded. mov si,offset help_error jmp short help_7 help_2: mov si,offset help_tag1 ;Print lead in. call print_str mov si,bp call print_str ;Print function name mov si,offset help_tag2 ;Print sep call print_str shl bx,1 ;Convert index into shl bx,1 ; offset into help tbl mov si,[bx+offset help_tbl] ;Print description call print_str mov si,offset help_tag7 ;Print usage for fun call print_str mov si,offset help_tag3 ;Print usage for fun call print_str mov si,bp ;Get ptr to command call print_str ;Print function name mov si,offset help_tag4 ;Print sep call print_str mov si,[bx + offset help_tbl + 2] call print_strcr ;Print syntax jmp short help_exit help_3: mov si,offset help_tag5 ;Print global help msg call print_strcr mov si,offset command_table ;Print every cmd in xor bl,bl ; the command table. help_4: mov di,dest_var_val mov cx,6 help_5: push cx call copy_string ;Copy command dec di mov al,' ' ;Print a cmd every neg cx ; 15 columns. Fill add cx,13 ; in the space with rep stosb ; blanks. pop cx mov bl,[si] ;See if end of list or bl,bl je help_6 loop help_5 help_6: xor al,al stosb push si mov si,dest_var_val call print_strcr pop si or bl,bl jne help_4 cmp installed,0 ;If installed, don't tell jne help_exit ; user about cmd help. mov si,offset help_tag6 ;Print global help msg help_7: call print_strcr help_exit: mov di,dest_var_val xor al,al stosb clc pop bp ret help_strings endp ;----------------------------------------------------------------------- ; STRINGSVER Returns the Strings version ;----------------------------------------------------------------------- ver_strings proc near mov si,offset version lodsb mov ah,[si+1] mov di,dest_var_val stosw mov ax,0030h ;Add ASCII 0 and term stosw clc ret ver_strings endp ;----------------------------------------------------------------------- ; STRINGSINST Checks to see if Strings installed as TSR ;----------------------------------------------------------------------- inst_strings proc near xor ax,ax mov dx,ax mov al,installed mov di,dest_var_val call hex2asc clc ret inst_strings endp ;======================================================================= ; Support Procedures ;======================================================================= ;----------------------------------------------------------------------- ;Read Console Gets input from the user ; Entry: CX - Max number of characters to read ; BL - Set to prevent echo of input ; DI - Ptr to output buffer ;----------------------------------------------------------------------- readcon_keys dw 27,4b00h,8,0 READCON_KEYCNT equ 4 readcon_jmptbl dw offset readcon_echo dw offset readcon_bs dw offset readcon_bs dw offset readcon_esc readcon_scur equ word ptr [bp-2] readcon_sptr equ word ptr [bp-4] readcon_cpos equ word ptr [bp-6] readcon_scnt equ word ptr [bp-8] readcon_pswf equ word ptr [bp-10] read_console proc near push bp mov bp,sp sub sp,10 push cx mov ah,0fh ;Get display mode/page int 10h mov ah,3 ;Get init cursor pos int 10h pop cx mov readcon_scur,dx ;Save init cursor pos mov readcon_cpos,0 ;Position inside str mov readcon_sptr,di ;Ptr to output buff mov readcon_scnt,cx ;Num chars to read mov readcon_pswf,bx ;Password flag readcon_0: call prog_idle ;Indicate idle mov ah,6 mov dl,-1 ;Get keyboard input int 21h jz readcon_0 ;No key, wait xor ah,ah or al,al ;If extended key get jne readcon_1 ; another. mov ah,6 mov dl,-1 ;Get extended key int 21h ; code. xor ah,ah xchg ah,al readcon_1: cmp al,13 ;See if CR je readcon_exit jcxz readcon_3 push cx push di mov di,offset readcon_keys mov cx,READCON_KEYCNT repne scasw mov si,cx pop di pop cx je readcon_2 dec cx stosb ;Write char to buff xor si,si cmp readcon_pswf,0 je readcon_2 mov al,'*' cmp readcon_pswf,1 je readcon_2 mov al,' ' readcon_2: shl si,1 call [si+offset readcon_jmptbl] jmp short readcon_0 readcon_3: mov al,7 call readcon_echo ;Beep the speaker jmp short readcon_0 readcon_exit: xor al,al ;Terminate string stosb clc mov sp,bp pop bp ret ; ; Process backspace ; readcon_bs proc near cmp cx,readcon_scnt ;If at start of buff, je readcon_bsexit ; ignore. push ax call readcon_lcur ;Backup cursor mov al,' ' call readcon_echo ;Print space pop ax call readcon_lcur dec di inc cx readcon_bsexit: stc ret readcon_bs endp ; ; Process left cursor ; readcon_lcur proc near or cx,cx je readcon_lcurexit mov al,8 ;Backspace char call readcon_echo readcon_lcurexit: stc ret readcon_lcur endp ; ; Process escape ; readcon_esc proc near cmp cx,readcon_scnt je readcon_escexit mov ah,3 ;Get cursor pos int 10h mov cx,readcon_scur ;Get init cur pos sub dl,cl ;Compute difference sub dh,ch push es mov ax,40h mov es,ax mov al,es:[4Ah] pop es mov ah,dh mul ah xor dh,dh add ax,dx push ax mov dx,readcon_scur ;Get initial pos call setcursor pop cx jcxz readcon_esc2 readcon_esc1: mov al,' ' call readcon_echo loop readcon_esc1 readcon_esc2: mov dx,readcon_scur ;Get initial pos call setcursor mov di,readcon_sptr mov cx,readcon_scnt readcon_escexit: ret readcon_esc endp ; ; Echo character in AL to screen. ; readcon_echo proc near push ax push dx mov dl,al ;Echo character mov ah,2 int 21h pop dx pop ax ret readcon_echo endp read_console endp ;----------------------------------------------------------------------- ; SETCURSOR Sets the position of the cursor ; Entry: DX - New cursor position ; BH - Video page ;----------------------------------------------------------------------- setcursor proc near mov ah,2 int 10h setcursor endp ;----------------------------------------------------------------------- ; PRINTVER Prints the version number in AX to buff ; Entry: AX - Version number. AH = Major ver, AL = Minor ver ; DI - Pointer to output buffer ;----------------------------------------------------------------------- printver proc near push ax mov al,100 xchg al,ah ;Copy major ver number mul ah pop bx xor bh,bh add ax,bx xor dx,dx call hex2asc ret printver endp ;----------------------------------------------------------------------- ; PRINT DATE Prints a date in mm-dd-yyyy format ; Entry: DH - Month 1 - 12 ; DL - Day 1 - 31 ; CX - Year ; DI - Ptr to output buffer ;----------------------------------------------------------------------- print_date proc near push cx ;Save year push dx ;Save day of the month mov al,dh ;Copy month xor ah,ah xor dx,dx call lead_zero ;Add leading zero call hex2asc ;Convert month to ASCII mov byte ptr [di-1],'-' ;Change term 0 to - pop ax ;Get day xor ah,ah call lead_zero ;Add leading 0 call hex2asc ;Convert to ASCII mov byte ptr [di-1],'-' ;Change term 0 to - pop ax xor dx,dx call hex2asc ;Convert year to ASCII ret print_date endp ;----------------------------------------------------------------------- ; PRINT TIME Prints the time in hh:mm:ss AM/PM format ; Entry: CH - Hour ; CL - Minutes ; DH - Seconds ; DI - Ptr to output buffer ;----------------------------------------------------------------------- print_time proc near mov bx,"ma" ;Assume AM cmp ch,12 jbe print_time_1 sub ch,12 mov bl,'p' print_time_1: push bx ;Save AM/PM flag push dx ;Save seconds push cx ;Save minutes mov al,ch ;Copy hours xor ah,ah xor dx,dx call lead_zero ;Add leading zero call hex2asc ;Convert month to ASCII mov byte ptr [di-1],':' ;Change term 0 to : pop ax ;Get minutes xor ah,ah xor dx,dx call lead_zero ;Add leading 0 call hex2asc ;Convert to ASCII mov byte ptr [di-1],':' ;Change term 0 to : pop ax ;Get seconds mov al,ah xor ah,ah xor dx,dx call lead_zero ;Add leading 0 call hex2asc ;Convert seconds mov byte ptr [di-1],' ' ;Change term 0 to space pop ax ;Get AM/PM tag stosw xor al,al ;Term string stosb clc ret print_time endp ;----------------------------------------------------------------------- ; Lead Zero - Adds a leading zero if number less than 10 ; Entry: DI - Ptr to buffer ; AL - Number to check ;----------------------------------------------------------------------- lead_zero proc near push bx mov bx,number_base cmp al,bl jae lead_zero_exit mov byte ptr es:[di],'0' inc di lead_zero_exit: pop bx ret lead_zero endp ;----------------------------------------------------------------------------- ; GETSTRING Returns a pointer to a string in a list from depending ; on an input index value. ; Entry: ES:DI - Pointer to start of list ; BX - Index into list ; Exit: DI - Pointer to string ; CF - Set if index too big ;----------------------------------------------------------------------------- get_string proc near assume cs:code,ds:code or bx,bx ;CF = 0 je getstring_exit call find_endl dec bx cmp byte ptr es:[di],0 jne get_string stc getstring_exit: ret get_string endp ;----------------------------------------------------------------------- ; PROCESS NUMS Converts each parameter to a number then calls back ; to a routine for specific processing. ; Entry: BX - Ptr to callback procedure ; ; Exit: CF - Set if number too large ; ; Callback: ; Called with: DX AX - Number from parameter ; SI DI - Running sum/product/logical number ; Return: CF - Set if processing should terminate; ;----------------------------------------------------------------------- process_nums proc near push bp mov si,var1_value ;Get ptr to variable call asc2hex mov si,ax ;Init vars mov di,dx mov bp,offset var2_value ;Get ptr to var array mov cx,num_params dec cx jbe procnum_exit procnum_1: push si mov si,[bp] ;Get ptr to variable call asc2hex pop si jc procnum_exit call bx ;Call callback function jc procnum_exit inc bp ;Point BP to next var inc bp loop procnum_1 mov ax,si ;Copy number mov dx,di mov di,dest_var_val call hex2asc ;Convert result to ASCII clc procnum_exit: pop bp ret process_nums endp ;----------------------------------------------------------------------- ; CONV2NUM converts the first two parameters to hex numbers. ; Exit: DX AX - Number from 1st parameter ; CX BX - Number from 2nd parameter ; CF - Set if either number too large ; SI - Set to error message if CF set ;----------------------------------------------------------------------- conv2num proc near mov si,var2_value ;Convert 2nd param to hex call asc2hex jc conv2num_error mov bx,ax ;Copy second parameter mov cx,dx mov si,var1_value ;Convert 1st param to hex call asc2hex jc conv2num_error conv2num_exit: ret conv2num_error: mov si,offset errmsg14 ;Number too large jmp short conv2num_exit conv2num endp ;----------------------------------------------------------------------- ; PARSE CMDLINE Parse the cmd line into seperate strings for each param ; Exit: CF - Set if error. ; SI - Points to error message if CF set. ;----------------------------------------------------------------------- parse_cmdline proc near xor cx,cx mov num_params,cx ;Init flags with zeros mov quiet_flag,cl mov use_mastenv,cl mov help_flag,cl mov number_base,10 mov console_out,1 mov parse_char,DEF_PARSE_CHAR mov cl,MAX_PARAMS + 2 ;Init ptrs to zero string mov di,offset dest_var_name mov ax,offset entry ;Point to zero byte rep stosw mov si,offset command_tail cmp byte ptr [si],0 ;See if cmdline = 0 jne parse_cmdline_0 ;If zero, report error parse_error: cmp help_flag,0 je parse_error1 jmp parse_cmdline_exit parse_error1: mov si,offset errmsg1 ;Syntax error message mov al,install_flag or al,remove_flag je parse_error2 mov si,100h parse_error2: stc jmp parse_cmdline_exit1 parse_cmdline_0: ; ; Added in 2.4 to untranslate graphic equals to =. ; xor cx,cx mov cl,[si] inc si mov di,si mov al,equalsub_char parse_cmdline_01: repne scasb jne parse_cmdline_1 mov byte ptr [di-1],'=' or cx,cx jnz parse_cmdline_01 parse_cmdline_1: xor bx,bx call scan4char ;Find 1st char jc parse_error cmp al,'/' ;See if cmdline switch jne parse_cmdline_2 call parse_switch ;Parse cmd line switch jnc parse_cmdline_1 jmp parse_cmdline_exit1 parse_cmdline_2: mov dest_var_name,si mov cmd_value,si mov bl,3 ;Scan for space or = call scan4char mov byte ptr [si],0 ;Term 1st string jc parse_cmdline_exit cmp al,'=' ;If = found, first word je parse_cmdline_3 ; was dest env var xor bl,bl call scan4char jc parse_cmdline_exit cmp al,'=' jne parse_cmdline_4 parse_cmdline_3: inc si ;Move past = xor bx,bx ;Find next char call scan4char jc parse_error mov cmd_value,si ;Save ptr to cmd mov console_out,0 ;No screen output mov bl,1 call scan4char ;Find end of command mov byte ptr [si],0 ;Term cmd name jc parse_cmdline_exit xor bl,bl call scan4char ;Find 1st param jc parse_cmdline_exit parse_cmdline_4: mov bp,offset var1_value mov cx,MAX_PARAMS parse_cmdline_5: mov [bp],si ;Save ptr to param add bp,2 inc num_params mov bl,4 ;Scan until parse char mov dl,parse_char call scan4char mov byte ptr [si],0 ;Term param jc parse_cmdline_exit cmp [si+1],dl jne parse_cmdline_6 inc si inc si jmp short parse_cmdline_7 parse_cmdline_6: xor bl,bl ;Scan until 1st char of call scan4char ; next param parse_cmdline_7: loop parse_cmdline_5 parse_cmdline_exit: clc parse_cmdline_exit1: ret parse_cmdline endp ;----------------------------------------------------------------------- ; PARSE SWITCH Parse command line switches ; Entry: SI - Pointer to / chararacter ; Exit: CF - Set if error ; SI - If error, points to error message string ;----------------------------------------------------------------------- parse_switch proc near assume cs:code,ds:code inc si ;Skip past '/'. lodsb ;Get cmdline switch mov di,offset cmd_switches mov cx,offset cmd_switch_end - offset cmd_switches mov bx,offset cmd_switch_end - offset cmd_switches - 1 or al,20h ;Make switch lower case repne scasb mov dx,offset errmsg3 ;Command not found msg stc jne switch_exit sub bx,cx ;Compute offset into list shl bx,1 ;Convert to word offset clc ;Assume pass call cs:[bx+offset cmd_jmp_tbl] ;Call command routine. switch_exit: ret switch_master: mov use_mastenv,1 ;Set use master env flag ret switch_quiet: mov quiet_flag,1 ;Set to suppress output ret switch_pchar: lodsb mov parse_char,al ;Set new parse character ret switch_base: call asc2hex ;Base at 10 right now dec si or dx,dx ;Check for proper range jne switch_base1 cmp ax,1 jbe switch_base1 cmp ax,16 ja switch_base1 mov number_base,ax ;Set new base clc ret switch_base1: mov si,offset errmsg24 ;Base outside range stc ret switch_help: mov help_flag,1 ;Set help flag ret switch_install: cmp installed,0 je switch_install1 mov si,offset errmsg23 stc jmp short switch_install2 switch_install1: mov install_flag,1 ;Set to install as TSR clc switch_install2: ret switch_remove: cmp installed,0 jne switch_remove1 mov si,offset errmsg21 stc jmp short switch_remove2 switch_remove1: mov remove_flag,1 ;Set to remove as TSR clc switch_remove2: ret parse_switch endp ;----------------------------------------------------------------------- ; GETCOMSPEC returns the name of the command processor from the env ;----------------------------------------------------------------------- getcomspec proc near push ds mov ax,ds:[2ch] ;Get prog environment segment mov di,offset shell_var ;Point to COMSPEC var name call getenvvar ;Get ptr to env var value jc getcomspec_exit ;CF = 1, var not found. mov di,cs:dest_var_val ;Copy var value to dest string push di call copy_string pop si pop ds mov di,databuff_ptr ;Use 2nd buff as temp buff call parse_filename mov si,di mov bx,di getcomspec_1: lodsb cmp al,'\' ;Mark start of filename or jne getcomspec_2 ; directory. mov bx,si getcomspec_2: or al,al je getcomspec_3 cmp al,'.' jne getcomspec_1 dec si getcomspec_3: mov cx,si sub cx,bx ;Compute length cmp cx,8 jb getcomspec_4 mov cx,8 getcomspec_4: mov shell_namlen,cl ;Save length of comspec name mov di,offset shell_name mov si,bx rep movsb xor al,al stosb getcomspec_exit: xor ax,ax mov di,dest_var_val ;ReZero the buffer. This is mov cx,VAR_SIZE ; what caused the FILENAME rep stosb ; and FILEEXT bugs in 1.1 clc ret getcomspec endp ;----------------------------------------------------------------------------- ; FILENAME STR Return only the filename from a filename string ; Entry: SI - Partial filename ; DI - Working buffer ; Exit: SI - Points to file name ; CX - Length of filename ;----------------------------------------------------------------------------- get_filename proc near assume cs:code,ds:code,es:code call parse_filename mov si,di mov bx,di getfname_1: lodsb cmp al,'\' ;Mark start of filename or jne getfname_2 ; directory. mov bx,si getfname_2: cmp al,'.' ;Mark end of filename or jne getfname_3 ; dir name. mov di,si getfname_3: or al,al jne getfname_1 cmp di,bx ja getfname_4 mov di,si getfname_4: dec di mov byte ptr ds:[di],0 ;Terminate mov cx,di sub cx,bx ;Compute length mov si,bx ret get_filename endp ;----------------------------------------------------------------------- ; FILENAME OPEN Does std parsing of name and opens file ; Entry: AL - File open flags ;----------------------------------------------------------------------- filename_open proc near assume cs:code,ds:code,es:code push ax mov si,var1_value ;Fully qualify filename mov di,dest_var_val ;Use dest buff as temp buff call parse_filename mov dx,di ;Copy filename pointer pop ax push ax call open_file jnc filename_open_exit mov di,dest_var_val ;Use dest buff as temp buff call parse_filename1 mov dx,di ;Copy filename pointer pop ax push ax call open_file filename_open_exit: pop ax ret ret filename_open endp ;----------------------------------------------------------------------- ; PARSE FILENAME creates a proper pathname for a filename ; Entry: SI - Pointer to ASCIIZ filename ; DI - Pointer to buffer to hold resulting pathname ;----------------------------------------------------------------------- parse_filename proc near assume cs:code,ds:code,es:code push di push si cmp dos_version,300h ;See if DOS 3.x or greater. jb parse_fname_0 ;If not, parse the old way. mov ah,60h ;DOS Resolve Path int 21h jmp short parse_fname_7 parse_filename1: push di ;2nd Entry pt w/o using push si ; int cmd. parse_fname_0: cmp byte ptr [si+1],":" ;See if disk specified je parse_fname_1 ;Yes, skip disk assignment mov ah,19h ;Get default disk int 21h inc al mov dl,al ;Save default disk number add al,40h ;Make ASCII mov ah,":" jmp short parse_fname_2 parse_fname_1: lodsw ;Get disk specified and al,0DFh ;Convert to caps mov dl,al sub dl,40h ;Convert to hex parse_fname_2: stosw ;Load disk specification ;Look for directory specification. mov bx,di ;save start of path mov al,"\" cmp byte ptr [si],al ;See if starting from root je parse_fname_3 ;Yes, skip append of path stosb ;Start at root push si ;Save current pointer mov si,di ;Point to dest buffer mov ah,47h ;Get default path int 21h pop si cmp byte ptr [di],0 ;See if NULL path je parse_fname_3 call find_end ;Scan to end of path string dec di ;move back before zero mov al,"\" ;Append path string with stosb ; a \. CX = length of path parse_fname_3: add cx,2 ;Append filename to path. mov ax,VAR_SIZE ;Compute space remaining in sub ax,cx ; the destination buffer. xchg cx,ax xor ah,ah ;Clear last char holder parse_fname_4: lodsb ;Get filename character. If or al,al ; end of string, exit. jz parse_fname_6 ;Else, write char. stosb cmp ax,".." ;If last two chars are .., jne parse_fname_5 ; scan backwards to delete std ; last directory. sub di,4 ;First, backup past '\..' mov al,"\" ;Look for directory sep push cx mov cx,di ;Compute length of path sub cx,bx repne scasb ;Now, past last directory pop cx cld ;Scan forwards again inc di ;Move back past \ parse_fname_5: mov ah,al ;Save last character read. loop parse_fname_4 parse_fname_6: xor al,al ;Terminate string with 0 stosb parse_fname_7: pop si pop di ret parse_filename endp ;----------------------------------------------------------------------------- ; CREATE FILE Creates a new file. ; Entry: DX - Pointer to ASCIIZ filename. ; Exit: BX - File handle ; CF - Set if error ;----------------------------------------------------------------------------- create_file proc near push cx mov ah,3ch ;Create file xor cx,cx ;Normal attributes int 21h mov bx,ax ;Copy file handle pop cx ret create_file endp ;----------------------------------------------------------------------------- ; OPEN FILE Opens a file. ; Entry: AL - Access flags ; DX - Pointer to ASCIIZ filename. ; Exit: BX - File handle ; CF - Set if error ;----------------------------------------------------------------------------- open_file proc near mov ah,3dh ;Open file int 21h mov bx,ax ;Copy file handle ret open_file endp ;----------------------------------------------------------------------------- ; CLOSE FILE Closes a file. ; Entry: BX - File handle ; Exit: CF - Set if error ;----------------------------------------------------------------------------- close_file proc near mov ah,3eh ;Close file int 21h ret close_file endp ;----------------------------------------------------------------------------- ; READ FILE Reads data from a file ; Entry: BX - File handle ; CX - Number of bytes to read ; DX - Pointer to data buffer ; Exit: CF - Set if error ; AX - bytes read. ;----------------------------------------------------------------------------- read_file proc near mov ah,3fh ;Read file data int 21h ret read_file endp ;----------------------------------------------------------------------------- ; WRITE FILE Writes data to a file ; Entry: BX - File handle ; CX - Number of bytes to write ; DX - Pointer to data buffer ; Exit: CF - Set if error ;----------------------------------------------------------------------------- write_file proc near mov ah,40h ;Write file data int 21h ret write_file endp ;----------------------------------------------------------------------------- ; MOVE FILEPTR Moves the file read pointer of a file. ; Entry: AX,DX - Offset of file pointer ; BX - File handle ; CL - Move type, 0 = from start, 1 = cur pos, 2 = from end. ; Exit: CF - Set if error ;----------------------------------------------------------------------------- move_fileptr proc near xchg cx,dx ;Copy most sig word xchg dx,ax ;Copy least sig word mov ah,42h ;Move file pointer int 21h ret move_fileptr endp ;----------------------------------------------------------------------------- ; PARSE DOSERR Points SI to the proper DOS error string ; Entry: AL - DOS error number ; Exit: SI - Pointer to ASCIIZ string ;----------------------------------------------------------------------------- parse_doserr proc near xor ah,ah cmp al,34 jbe parse_doserr_1 xor al,al parse_doserr_1: shl ax,1 mov si,offset doserr_tbl add si,ax mov si,[si] stc ;Set error flag ret parse_doserr endp ;----------------------------------------------------------------------------- ; TRUNCNUM truncates a number to the max length of a string ; Entry: AX - Number to truncate ; Exit: AX - Truncated number ;----------------------------------------------------------------------------- truncnum proc near cmp ax,VAR_SIZE ;VAR_SIZE = max string length jb trunc_1 mov ax,VAR_SIZE trunc_1: ret truncnum endp ;----------------------------------------------------------------------------- ; FINDSTR determines if a string is in a list. ; Entry: DS:SI - Pointer to ASCII string to find. ; ES:DI - Pointer to list of ASCIIZ strings. ; CX - Size of string ; Exit: DI - Pointer to entry in list ; CF - Clear if string found ; BX - If CF clear, index into list ;----------------------------------------------------------------------------- findstr proc near push cx push dx xor dx,dx or dx,cx ;Save length of string je finds_3 xor bx,bx ;Zero index counter finds_1: push di push si push cx repe cmpsb ;Compare command pop cx pop si pop di clc je findstr_exit inc bx ;Inc string count push cx call find_endl ;Find end of string. pop cx jne finds_3 cmp byte ptr es:[di],0 ;See if second zero. If so jne finds_1 ; end of list. finds_3: stc ;Indicate string not found findstr_exit: pop dx pop cx ret findstr endp ;----------------------------------------------------------------------------- ; FIND END scans to the end of an ASCIIZ string. ; Entry: ES:DI - Pointer to ASCII string ; Exit: ES:DI - Pointers to character after string. ; CX - Length of string ; ZF - Clear if end not found in MAX length of characters ;----------------------------------------------------------------------------- find_end proc near push ax mov cx,VAR_SIZE xor al,al repne scasb pushf mov ax,VAR_SIZE sub ax,cx xchg ax,cx dec cx popf pop ax ret find_end endp ;----------------------------------------------------------------------------- ; FIND ENDL scans to the end of an ASCIIZ string. String can be up to 32K ; Entry: ES:DI - Pointer to ASCII string ; Exit: ES:DI - Pointers to character after string. ; CX - Length of string ; ZF - Clear if end not found in MAX length of characters ;----------------------------------------------------------------------------- find_endl proc near push ax mov cx,8000h xor al,al repne scasb pushf mov ax,8000h sub ax,cx xchg ax,cx dec cx popf pop ax ret find_endl endp ;----------------------------------------------------------------------------- ; CAPS STRING capitalizes ASCIIZ string ; Entry: SI - Pointer to ASCII string to capitalize ; Exit: CX - Length of string ;----------------------------------------------------------------------------- caps_string proc near assume ds:code,es:code push bx push dx mov bx,"za" ;Set filter limits mov dx,0df00h ;Set character filter call filter_string pop dx pop bx ret caps_string endp ;----------------------------------------------------------------------------- ; LC STRING makes an ASCIIZ string lower case ; Entry: SI - Pointer to ASCII ; Exit: CX - Length of string ;----------------------------------------------------------------------------- lc_string proc near assume ds:code,es:code push bx push dx mov bx,"ZA" ;Set filter limits mov dx,0ff20h ;Set character filter call filter_string pop dx pop bx ret lc_string endp ;----------------------------------------------------------------------------- ; FILTER STRING filters an ASCIIZ string ; Entry: DS:SI - Pointer to ASCII string ; BL - Lower limit of char range ; BH - Upper limit of char range ; DL - OR filter ; DH - AND filter ; Exit: CX - Length of string ;----------------------------------------------------------------------------- filter_string proc near assume ds:code,es:code push si push di push es mov di,si push ds pop es xor cx,cx ;Clear byte counter. filter_1: lodsb ;Get character or al,al ;Allow any non-space character je filter_exit cmp al,bl ;If between lower and upper jb filter_2 ; char limit it. cmp al,bh ja filter_2 or al,dl ;Apply OR filter and al,dh ;Apply AND filter filter_2: stosb ;Save character inc cx ;Inc byte counter jmp short filter_1 filter_exit: pop es pop di pop si ret filter_string endp ;----------------------------------------------------------------------------- ; COPY STRING copies an ASCIIZ string ; Entry: DS:SI - Pointer to source ASCIIZ string ; ES:DI - Pointer to destination buffer ; Exit: CX - Length of string ;----------------------------------------------------------------------------- copy_string proc near assume ds:code,es:code xor cx,cx copy_string_1: lodsb ;Move character stosb or al,al ;See if end of string je copy_string_exit ;If so, exit inc cx ;Inc count jmp short copy_string_1 copy_string_exit: ret copy_string endp ;----------------------------------------------------------------------------- ; PRINT STRCR prints an ASCIIZ string then appends a CR LF to the end ; Entry: SI - pointer to ASCIIZ string. ;----------------------------------------------------------------------------- print_strcr proc near assume ds:nothing,es:nothing call print_str mov si,offset endmsg call print_str ret print_strcr endp ;----------------------------------------------------------------------------- ; PRINT STR prints an ASCIIZ string to the std output device ; Entry: SI - Pointer to ASCIIZ string. ;----------------------------------------------------------------------------- print_str proc near cmp cs:quiet_flag,0 jne print_str_exit lodsb ;Get character or al,al ;See if end of string je print_str_exit mov ah,2 ;DOS print character mov dl,al int 21h ;Call DOS jmp short print_str print_str_exit: ret print_str endp ;----------------------------------------------------------------------------- ; HEX2ASC converts number in DX AX to ASCII ; Entry: DX AX - Number ; DI - Destination buffer ; CF - Clear ; Exit: Di - Points to byte past terminating 0 ;----------------------------------------------------------------------------- hex2asc proc near assume ds:nothing,es:nothing push ax push bx push cx push dx push si mov si,cs:number_base ;Load number base mov bx,ax mov cx,dx mov dx,-1 ;Load end of number flag push dx hex_loop1: xchg ax,cx ;Get high word in AX xor dx,dx ;Clear high word div si ;Divide by base (10) xchg cx,ax ;Save result of high divide xchg ax,bx ;Get low word, leave remainder div si ; in DX. xchg bx,ax ;Save result of low divide add dl,30h ;Convert to ascii cmp dl,'9' jbe hex_1 add dl,7 hex_1: push dx ;Save digit on stack or bx,bx jne hex_loop1 ;See if number = 0. If not, or cx,cx ; continue divide loop. jne hex_loop1 mov bl,"0" ;Set leading zero flag hex_loop2: pop dx ;Get digit off stack cmp dx,-1 ;See if end flag je hex_2 or bl,dl ;Don't print leading zeros. cmp bl,"0" ;The first non zero will je hex_loop2 ; change bl to non-zero. mov al,dl ;Write to buffer stosb jmp short hex_loop2 hex_2: cmp bl,"0" ;If number zero, write last jne hex_exit ; zero. mov al,bl stosb hex_exit: xor al,al ;Termainate with zero stosb pop si pop dx pop cx pop bx pop ax ret hex2asc endp ;------------------------------------------------------------------------ ; ASC2HEX converts an ASCII number to hex ; Entry: SI - Pointer to ASCIIZ string ; Exit: DX,AX - Number ; CF - Set if overflow ;------------------------------------------------------------------------ asc2hex proc near assume ds:nothing,es:nothing push bx push cx push di xor cx,cx ;Zero result xor di,di xor bx,bx ;Keep BH clear asc_loop1: mov bl,[si] ;Get next digit inc si cmp bl,"9" jbe asc_1 and bl,0dfh ;Make upper case sub bl,7 asc_1: sub bl,"0" ;Convert digit from ASCII to jb asc_exit ; hex. If digit illegal cmp bx,cs:number_base ; char, exit. jae asc_exit asc_2: xchg ax,di ;Shift result in DI CX by mul cs:number_base ; the base. jc asc_exit1 xchg di,ax xchg ax,cx mul cs:number_base xchg cx,ax add di,dx jc asc_exit1 add cx,bx ;Add new number to result. adc di,0 jnc short asc_loop1 asc_exit1: mov ax,cx ;Copy result mov dx,di pop di pop cx pop bx ret asc_exit: clc jmp short asc_exit1 asc2hex endp ;----------------------------------------------------------------------- ; SCAN4CHAR scans a string to find the first character. ; Entry: SI - pointer to ASCII string ; BL - 0 = find next char, ; 1 = find next space, ; 2 = find end of line, ; 3 = find next space or =. ; 4 = find character in DL. ; Exit: AL - matching character ; SI - pointer to matching character ; CF - set if carriage return or EOF found ;----------------------------------------------------------------------- scan4char proc near assume ds:nothing,es:nothing scan4loop: lodsb cmp al,13 ;Check for CR jne scan4_1 scan4_eol: stc jmp short scan4_exit1 scan4_1: cmp bl,4 je scan4_dl cmp bl,3 je scan4_equal cmp bl,1 ;Check if searching for je scan4_space ; space, char, or EOL. ja scan4loop cmp al," " ;Check for space or other jbe scan4loop ; 'white' characters. jmp short scan4_exit scan4_dl: cmp al,dl ;Check for parse character je scan4_exit or al,al je scan4_eol jmp short scan4loop scan4_equal: cmp al,"=" ;Check for exit je scan4_exit scan4_space: cmp al," " ;Check for characters. ja scan4loop scan4_exit: clc scan4_exit1: dec si ;Back up before char ret scan4char endp ;----------------------------------------------------------------------- ; GETKEY Waits for a keypress and returns the key. ;----------------------------------------------------------------------- getkey proc near call prog_idle ;yield mov ah,1 ;Check key status int 16h jz getkey ;No key, loop cld ;Reset dir flag due to yield mov ah,2 ;Get shift status int 16h push ax mov ax,12ffh ;Get extended shift status int 16h pop bx cmp bl,al ;See if same jne getkey_1 ;No, assume old keyboard mov ah,11h ;Get extended key status xor al,al ;Clear zero flag int 16h jz getkey_1 mov ax,1000h ;Extended keyboard read int 16h jmp short getkey_2 getkey_1: xor ax,ax ;Get key from buffer int 16h getkey_2: ret getkey endp ;----------------------------------------------------------------------- ;PROG IDLE Indicates to the system that we are idle ;----------------------------------------------------------------------- prog_idle proc near push ax int 28h ;Call Idle interrupt cmp dos_version,300h jb prog_idleexit mov ax,1680h ;Mux DOS idle int 2fh prog_idleexit: pop ax ret prog_idle endp ;----------------------------------------------------------------------- ; GETENVVAR returns a pointer to the value of an environment variable. ; Entry: AX - Segment of environment ; DS:DI - Pointer to ASCIIZ string containing the name of env var. ; Exit: DS:SI - If CF = 0, Pointer to value of environment variable ; DI - If CF = 0, Pointer to start of var name in environment ; CF - Set if variable not found ;----------------------------------------------------------------------- getenvvar proc near push ax push es push ax ;Save env segment push di ;Append = sign to the end of call find_end ; the variable. mov word ptr es:[di-1],003dh pop si call caps_string pop es ;Use find string routine to xor di,di ; find the variable name. call findstr jnc getenvvar_1 stc jmp short getenvvar_exit getenvvar_1: push es ;DS:SI = ES:DI pop ds xchg si,di getenvvar_2: lodsb ;Find end of var name. cmp al,'=' jne getenvvar_2 clc getenvvar_exit: pop es pop ax ret getenvvar endp ;----------------------------------------------------------------------------- ; SETENV Sets environment variables. ; ; Entry: DS:SI - pointer to env var name ; ES:DI - pointer to env var value ;----------------------------------------------------------------------------- setenv proc near push bp push ds push es push di ;Save ptr to var value push es call find_end ;Get length of var value mov dx,cx ;Copy length mov di,si push ds ;Add length of var name plus pop es ; room for the equals sign. call find_end mov word ptr es:[di-1],003dh ;Append = sign inc cx ;Add byte for = add dx,cx inc dx ;Add byte for terminating 0 mov ax,masterenv_seg cmp use_mastenv,0 jne setenv_0 mov ax,localenv_seg setenv_0: push ax dec ax mov es,ax mov bp,es:[3] ;Get size of env segment push cx mov cl,4 ;Convert paragraphs to bytes shl bp,cl pop cx pop es xor di,di ;Use find string routine to call findstr ; find the variable name. push si push ds jc setenv_2 ;Var not found, skip erase push es pop ds mov si,di ;Erase current var value by call find_endl ; copying the next env var xchg si,di ; over the current one. setenv_1: cmp byte ptr [si],0 je setenv_2 setenv_11: lodsb stosb or al,al jne setenv_11 jmp short setenv_1 setenv_2: pop ax ;Get ptr to var name pop cx pop ds ;Get ptr to var value pop si cmp byte ptr ds:[si],0 ;See if NULL variable, If so, je setenv_31 ; don't add to env block mov bx,di ;Get offset of end of env add bx,dx ;Add length of value inc bx ;Add length of terminating byte cmp bp,bx ja setenv_3 push ax ;Save ptr to var name push cx mov dx,es dec dx mov es,dx push es:[1] ;Save current owner segment inc dx mov es,dx add bx,15 ;If no room in environemnt, mov cl,4 ; see if env segment can be shr bx,cl ; resized to make room for mov ah,4ah ; new variable. int 21h ;Reallocate memory pop bx ;Get old owner pop cx pop ax jc setenv_5 push es dec dx mov es,dx mov es:[1],bx ;Restore old owner pop es setenv_3: push si push ds mov si,cx mov ds,ax call copy_string ;Copy var name to env dec di ;Back up over last zero pop ds pop si mov bl,"=" ;Since env vars can't have mov bh,bl ; the char '=', filter mov dl,-1 ; string to change = to mov dh,equalsub_char ; graphic char that looks call filter_string ; similar. call copy_string ;Copy var value to env setenv_31: xor al,al stosb ;Add 2 zeros to end env. setenv_4: clc ;Set pass flag setenv_5: pop es pop ds pop bp ret setenv endp ;----------------------------------------------------------------------- ; SETERR0MSG Sets the Bad version error message to the ver in AX ; Entry: AX - Required DOS version ; Exit: SI - Pointer to bad DOS ver message ; CF - Set ;----------------------------------------------------------------------- seterr0msg proc near mov di,offset errmsg0ver ;Print version number call printver mov ax,[di-3] ;Insert decimal pt mov byte ptr [di-3],'.' ; so it looks nice mov ah,' ' mov [di-2],ax mov si,offset errmsg0 ;Point to start of msg stc ;Set error flag ret seterr0msg endp ;----------------------------------------------------------------------------- ; REMOVE uninstalls the installed program from memory. ;----------------------------------------------------------------------------- remove proc near assume cs:code,ds:code,es:code push es mov ax,352fh ;Get MUX vector int 21h mov cx,cs ;Get CS mov ax,es ;Check to make sure MUX cmp ax,cx ; vector not modified. jne remove_error push ds mov ax,252fh ;Set interrupt lds dx,[int2fh] ;Get old int 2F vector int 21h pop ds mov es,ds:[2ch] ;Get env segment mov ah,49h ;Free mem int 21h mov si,offset infomsg2 ;Removed message call print_strcr remove_exit: pop es ret remove_error: mov remove_flag,0 mov si,offset errmsg22 ;Can't remove error msg stc jmp short remove_exit remove endp even end_of_resident = $ ;======================================================================= ;Start of nonresident data ;======================================================================= ;----------------------------------------------------------------------- ; FINAL INSTALL Last part of install process. Must be less that ; the resident stack size. (512 bytes) ;----------------------------------------------------------------------- final_install proc near mov sp,di ;Set stack to res stack rep stosb ;Clear buffer mov databuff_ptr,di add di,DATABUFF_SIZE+15 mov cl,4 shr di,cl mov dx,di mov ax,3100h ;TSR int 21h mov ax,4c01h ;This should never happen int 21h final_install endp ;----------------------------------------------------------------------- ; Lookup table for help messages. Each command has two help strings. ; 1. The descripion of the function. The word 'Returns' is ; automatically added to the start of the string. ; 2. A syntax message that describes the arguements for the function. ; ; This table MUST be in the same order as the command table at the ; start of the program. ;----------------------------------------------------------------------- help_tbl dw offset left_help dw offset left_syntax dw offset right_help dw offset left_syntax dw offset mid_help dw offset mid_syntax dw offset length_help dw offset length_syntax dw offset find_help dw offset find_syntax dw offset findc_help dw offset findc_syntax dw offset lower_help dw offset length_syntax dw offset upper_help dw offset length_syntax dw offset char_help dw offset char_syntax dw offset val_help dw offset add_syntax dw offset filedrive_help dw offset filename_syntax dw offset filedir_help dw offset filename_syntax dw offset filename_help dw offset filename_syntax dw offset fileext_help dw offset filename_syntax dw offset parse_help dw offset parse_syntax dw offset commas_help dw offset not_syntax dw offset repeat_help dw offset repeat_syntax dw offset read_help dw offset read_syntax dw offset write_help dw offset write_syntax dw offset filesize_help dw offset filename_syntax dw offset linesize_help dw offset filename_syntax dw offset truename_help dw offset filename_syntax dw offset filedate_help dw offset filename_syntax dw offset filetime_help dw offset filename_syntax dw offset ver_help dw offset no_syntax dw offset ask_help dw offset ask_syntax dw offset inwin_help dw offset no_syntax dw offset twoFcheck_help dw offset twoFcheck_syntax dw offset envfree_help dw offset no_syntax dw offset envsize_help dw offset no_syntax dw offset mastervar_help dw offset mastervar_syntax dw offset localvar_help dw offset mastervar_syntax dw offset truever_help dw offset no_syntax dw offset files_help dw offset no_syntax dw offset lastdrive_help dw offset no_syntax dw offset codepage_help dw offset no_syntax dw offset country_help dw offset no_syntax dw offset biosdate_help dw offset no_syntax dw offset getkey_help dw offset no_syntax dw offset locenv_help dw offset no_syntax dw offset masenv_help dw offset no_syntax dw offset add_help dw offset add_syntax dw offset sub_help dw offset add_syntax dw offset mul_help dw offset add_syntax dw offset div_help dw offset div_syntax dw offset and_help dw offset add_syntax dw offset or_help dw offset add_syntax dw offset xor_help dw offset div_syntax dw offset not_help dw offset not_syntax dw offset convert_help dw offset convert_syntax dw offset peek_help dw offset peek_syntax dw offset poke_help dw offset poke_syntax dw offset in_help dw offset in_syntax dw offset out_help dw offset out_syntax dw offset interrupt_help dw offset interrupt_syntax dw offset scan_help dw offset scan_syntax dw offset day_help dw offset day_syntax dw offset month_help dw offset month_syntax dw offset date_help dw offset date_syntax dw offset time_help dw offset no_syntax dw offset totalmem_help dw offset no_syntax dw offset freemem_help dw offset no_syntax dw offset totalxms_help dw offset no_syntax dw offset freexms_help dw offset no_syntax dw offset xmsver_help dw offset no_syntax dw offset totalems_help dw offset no_syntax dw offset freeems_help dw offset no_syntax dw offset emsver_help dw offset no_syntax dw offset freeumb_help dw offset no_syntax dw offset strver_help dw offset no_syntax dw offset strinst_help dw offset no_syntax dw offset help_help dw offset help_syntax ;----------------------------------------------------------------------- ;Help text ;----------------------------------------------------------------------- left_help db "left n characters",0 left_syntax db "String, Number of chars",0 right_help db "right n characters",0 mid_help db "middle n chars",0 mid_syntax db "String, Start char, Length",0 length_help db "String length",0 length_syntax db "String",0 find_help db "the position of Findstring in String",0 find_syntax db "String, Findstring",0 findc_help db "the position of Findstring in String. Case sen",0 findc_syntax db "String, Findstring",0 lower_help db "string all lowercase",0 upper_help db "string all uppercase",0 char_help db "ASCII number of character",0 char_syntax db "Char[Char][char][char][char][char][char][char]",0 val_help db "ASCII char for a number",0 filedrive_help db "the drive of a filename",0 filedir_help db "the directory of a filename",0 filename_help db "the file name",0 filename_syntax db "Filename",0 fileext_help db "the file extension",0 parse_help db "the Nth token from a string",0 parse_syntax db "String, Token number, Token seperator char",0 commas_help db "a number parsed with commas every 3 digits",0 repeat_help db "a string of n number of characters",0 repeat_syntax db "Number of chars, Char to repeat",0 read_help db "a line from a file",0 read_syntax db "Filename, line number",0 write_help db "nothing. Appends a string to the end of a file",0 write_syntax db "Filename, String",0 filesize_help db "the size of a file",0 linesize_help db "the number of lines",0 truename_help db "the complete filename",0 filedate_help db "the date of a file",0 filetime_help db "the time of a file",0 ask_help db "a response from a user",0 ask_syntax db "[Prompt string][, Max chars][, 1=* echo 2=No echo]",0 ver_help db "the DOS version number",0 inwin_help db "1 if Windows running",0 twoFcheck_help db "status of programs hooked to the Multiplex int",0 envfree_help db "the bytes free in the environment",0 envsize_help db "the size of the environment",0 mastervar_help db "a variable from the Master env ",0 mastervar_syntax db "Variable Name",0 localvar_help db "a variable from the Local env ",0 truever_help db "the true DOS verison. Requires DOS 5.0 or later",0 files_help db "the total number of files that can be open",0 lastdrive_help db "the letter of the last possible drive",0 ask2_help db "a response from the user",0 ask2_syntax db "[Prompt [,max number of chars [,no echo flag]]",0 codepage_help db "the active code page. Requires DOS 3.3 or later",0 country_help db "the country code for the system",0 biosdate_help db "the date for the ROM BIOS",0 getkey_help db "the scan code and ASCII value of the next" db " key pressed",0 locenv_help db "the segment of the active environment",0 masenv_help db "the segment of the master environment",0 add_help db "the sum of the parameters",0 add_syntax db "Num1, Num2 [,Num3][,Num4][,Num5][,Num6]" db 13,10,9,9,9,9," [,Num7][,Num8][,Num9][,Num10]",0 sub_help db "the difference of two numbers",0 mul_help db "the product of the parameters",0 div_help db "the quotient of two numbers",0 div_syntax db "Number, Number",0 and_help db "the logical AND of the parameters",0 or_help db "the logical OR of the parameters",0 xor_help db "the exclusive OR of two numbers",0 not_help db "the logical NOT of a number",0 not_syntax db "Number",0 convert_help db "a number with the base specified",0 convert_syntax db "Number, New Base",0 peek_help db "a series of bytes from memory",0 peek_syntax db "Segment, Offset [, Number of bytes [,Word flag]]",0 poke_help db "nothing. Writes up to 8 bytes to memory",0 poke_syntax db "Segment, Offset , Byte1[,Byte2][,Byte3][,Byte4]" db "[,Byte5][,Byte6][,Byte7][,Byte8]",0 in_help db "a byte from an I/O port",0 in_syntax db "Port number",0 out_help db "nothing. Writes a byte to an I/O port",0 out_syntax db "Port number, Output byte",0 interrupt_help db "registers from an interrupt. Dangerous!",0 interrupt_syntax db "Interrupt number, AX, BX, CX, DX,",13,10 db 9,9,9,9,9," DI, SI, BP, DS, ES",0 scan_help db "the offset of a series of bytes in memory",0 scan_syntax db "Segment to search, Starting Offset,",13,10 db 9,9,9,9," Byte1 [,Byte2] [,Byte3] [Byte4]",13,10 db 9,9,9,9," [,Byte5] [,Byte6] [,Byte7] [,Byte8]",0 day_help db "the name of the current day of the week,",13,10 db " or corresponding to the index value",0 day_syntax db "[Index (1=Sunday, 2=Monday 3=Tuesday...]",0 month_help db "the name of the current month or the month",13,10 db "corresponding to the index value",0 month_syntax db "[Index (1=January, 2=February...]",0 date_help db "the current date in Mmmmmmmm dd, yyyy format",0 date_syntax db "[If parm added, date ret in mm-dd-yyyy fmt]",0 time_help db "the current time",0 totalmem_help db "the amount of conventional memory",0 freemem_help db "the largest block of free conventional memory",0 totalxms_help db "the amount of extended memory",0 freexms_help db "the amount of free extended memory",0 xmsver_help db "the version of the extended memory driver",0 totalems_help db "the amount of expanded memory",0 freeems_help db "the amount of free expanded memory",0 emsver_help db "the version of the expanded memory driver",0 freeumb_help db "the largest block of free Upper Memory",0 strver_help db "the version of Strings",0 strinst_help db "a non-zero number if Strings installed as TSR",0 help_help db "help text for the specified Strings command",0 help_syntax db "[Strings Command]" no_syntax db 0 twoFcheck_syntax db "Number or Alias",13,10,10 db " Interrupt 2F, the multiplex interrupt," db " is used by many programs to",13,10 db "signal that they are installed. 2FCHECK" db " calls interrupt 2F with a device",13,10 db "number between 0 and 255. 2FCHECK returns a" db " 0 if no program responds to",13,10 db "this device ID. If a program does respond," db " a non-zero number is returned.",13,10 db " To prevent users from remembering a series of" db " device IDs, one of the",13,10 db "following aliases can be used in place of the" db " device number.",13,10,10 db " PRINT - PRINT resident code " db " ASSIGN - ASSIGN resident code",13,10 db " DRIVER - DRIVER.SYS device driver " db " SHARE - SHARE resident code",13,10 db " NET - Network redirector code " db " NLS - NLSFUNC resident code",13,10 db " ANSI - ANSI.SYS device driver " db " DOSBOX - OS/2 or Win DOS box",13,10 db " HIMEM - HIMEM.SYS memory manager " db " DOSKEY - DOSKEY resident code",13,10 db " GRAPHTBL - GRAFTABL resident code " db " APPEND - APPEND resident code",13,10 db " DISPLAY - DISPLAY.SYS",0 infomsg1 db "Installed",0 errmsg25 db "No multiplex IDs available",0 ;----------------------------------------------------------------------- ;INITIALIZE - Start of non resident code. ;----------------------------------------------------------------------- initialize proc near assume cs:code,ds:code,es:code cld ;Set string ops 'up.' mov word ptr [entry],0 mov ah,30h ;Get DOS version, run only int 21h ; if 2.0 or greater. xchg al,ah ;Swap major, minor numbers mov dos_version,ax cmp ah,2 jae init_1 mov si,offset program call print_strcr mov si,offset errmsg0 ;Bad DOS version mov al,1 jmpinit_error: jmp init_error init_1: call check4xms ;Chk extended mem mgr mov xms_version,ax call check4ems ;Chk expanded mem mgr mov ems_version,ax call chk_installed jc jmpinit_error mov bx,cs cmp ax,bx je init_11 mov installed,1 init_11: mov di,TRANS_STACK ;Set up data buffers mov sp,di ;Set stack mov dest_var_val,di xor ax,ax mov cx,VAR_SIZE rep stosb mov databuff_ptr,di add di,DATABUFF_SIZE+15 mov cl,4 shr di,cl mov bx,di mov ah,4ah ;Reduce memory allocation int 21h jnc init_21 mov si,offset errmsg2 mov al,-1 ;Set out of memory code jmp short init_exit init_21: push es mov ax,352eh ;Get cmd proc hook. If int 21h ; our normal search mov ax,es:[2ch] ; fails, use this method. mov bx,ax dec ax mov es,ax cmp byte ptr es:[0],'M' je init_30 cmp byte ptr es:[0],'Z' je init_30 mov bx,ds:[2ch] ;If 2E fails use our env. init_30: pop es mov localenv_seg,bx mov masterenv_seg,bx call getcomspec ;Get the name of the shell call getname ;Get the name of the prog call findenv ;Use parent's env by def jc init_4 mov localenv_seg,ax init_4: call findmaster ;Find master env jc init_5 mov masterenv_seg,ax init_5: call main ;Program, do your stuff cmp install_flag,0 ;See if we should install je init_exit call install ;If we return, error init_error: push ax call print_strcr ;Print error pop ax init_exit: mov ah,4Ch ;Terminate int 21h initialize endp ;----------------------------------------------------------------------- ; INSTALL Installs Strings as a TSR ;----------------------------------------------------------------------- install proc near assume cs:code,ds:code,es:code mov ax,31eh cmp ax,dos_version ;See if DOS 3.3 jbe install_1 call seterr0msg ;Error, not DOS 3.3 ret install_1: mov ax,352fh ;Get interrupt 2F (MUX) int 21h ; vector. mov word ptr [int2fh],bx mov word ptr [int2fh+2],es push cs pop es mov ax,252fh ;Point int 2F to internal mov dx,offset muxint ; routine. int 21h mov si,offset infomsg1 call print_strcr mov installed,1 ;Set installed flag mov di,RES_STACK ;Set up data buffers mov dest_var_val,di xor ax,ax mov cx,VAR_SIZE jmp final_install install endp ;----------------------------------------------------------------------- ;See if a copy is already resident in memory. If > DOS 3.0, use int 2Fh. ;----------------------------------------------------------------------- chk_installed proc near push es mov byte ptr [entry+2],0 ;Initialize fingerprint cmp dos_version,300h ;See if DOS 3.0 or later jb find_copy1 ;No, search the old way. mov cx,16 ;Try 16 different IDs. find_copy: xor ax,ax mov es,ax mov ah,multiplex_id ;Load ID. Use Int 2Fh to int 2fh ; reach installed code so or al,al ; that we are compatible jne find_copy0 ; with 386 memory managers. push cs pop es ;If AL not changed, Strings jmp short find_copy3 ; not installed. find_copy0: push cx call cmpheader ;See if really Strings by pop cx ; comparing file headers. je find_copy3 inc multiplex_id ;ID used by another program. loop find_copy ; Change and try again. mov dx,offset errmsg25 ;All IDs taken, print error find_copy_fail: stc jmp short find_copy_exit ; ;For DOS 2.x find the installed code the old fashioned way by scanning ;the memory control blocks. ; find_copy1: xor bx,bx ;zero BX for start mov ax,cs ;keep CS value in AX find_copy2: inc bx ;increment search segment value mov es,bx assume es:nothing cmp ax,bx ;not installed if current je find_copy3 ; segment is found. call cmpheader jne find_copy2 ;loop back if not found find_copy3: mov ax,es ;Save seg of installed code clc find_copy_exit: pop es ret chk_installed endp ;----------------------------------------------------------------------------- ; CMPHEADER compares the first 16 bytes of this file with the segment ; pointed to by ES. ; Entry: DS - code segment ; ES - pointer to segment to compare ; Exit: ZF - 0 = segments match. ;----------------------------------------------------------------------------- cmpheader proc near mov si,offset entry+2 ;Search this segment for ASCII mov di,si ; fingerprint. mov cx,16 repe cmpsb ret cmpheader endp ;----------------------------------------------------------------------- ; GETNAME Copies the name of the program to the name buffer ;----------------------------------------------------------------------- getname proc near assume cs:code,ds:code,es:code push es mov ax,300h cmp dos_version,300h ;See if DOS 3.0 or later jb getname_exit mov ax,ds:[2ch] ;Get env segment push ax dec ax mov es,ax assume es:nothing mov cx,es:[3] ;Get env seg size shl cx,1 shl cx,1 shl cx,1 shl cx,1 pop es ;Get back env seg xor ax,ax mov di,ax getname_1: repnz scasb ;Scan env for 00 jne getname_exit cmp byte ptr es:[di],0 jne getname_1 add di,3 ;Move past cnt byte mov si,databuff_ptr ;Use file buffer xchg di,si assume ds:nothing push ds ;Copy the filename push es ; into a local pop ds ; buffer to avoid pop es ; segment probs call copy_string ; with called procs. mov ax,cs mov ds,ax mov es,ax assume ds:code,es:code mov si,databuff_ptr mov di,si add di,100h call get_filename mov strings_namelen,cx ;Save length mov di,offset strings_name call copy_string getname_exit: pop es ret getname endp ;----------------------------------------------------------------------- ; CHKARENA Verifys a memory arena header. ; Entry: AX - Memory block to verify ; Exit: BX - Owner of memory block ; CX - Size of memory block ; CF - Clear if valid arena header ; ZF - Clear if last memory block ;----------------------------------------------------------------------- chkarena proc near assume cs:code,ds:code,es:code,ss:code push ax push es dec ax mov es,ax mov cx,es:[3] ;Get size of block mov bx,es:[1] ;Get owner of block cmp bx,0fff0h ;Check for illegal owner, jae chkarena_error ; stupid 386Max fix. cmp byte ptr es:[0],"M" ;See if proper signature je chkarena_exit ;ZF set, CF clear if match cmp byte ptr es:[0],"Z" ;See if last blk sig jne chkarena_error or ax,ax ;Clear ZF, Clear CF chkarena_exit: pop es pop ax ret chkarena_error: stc jmp short chkarena_exit chkarena endp ;----------------------------------------------------------------------- ; FINDCMDPSP Finds the PSP of the command processor ; Exit: AX - Segment of command processor PSP ;----------------------------------------------------------------------- findcmdpsp proc near assume cs:code,ds:code,es:code,ss:code push dx push es findcmdpsp_1: mov ax,es:[16h] ;Get parent's PSP call chkarena ;See if valid memory block jc findcmdpsp_error mov es,ax cmp ax,es:[16h] ;See if PSP is own parent jne findcmdpsp_1 ;No, keep looking clc findcmdpsp_exit: pop es pop dx ret findcmdpsp_error: stc jmp short findcmdpsp_exit findcmdpsp endp ;----------------------------------------------------------------------- ; FINDPSPENV Finds the environment block for a COMMAND.COM PSP ; Entry: AX - Segment of PSP ; Exit: AX - Segment of environment ;----------------------------------------------------------------------- findpspenv proc near assume cs:code,ds:code,es:code,ss:code push bx push es mov dx,ax ;Save PSP segment mov es,ax mov ax,es:[2ch] ;Get ptr to environment call chkarena ;See if valid memory block jc findpspenv_1 cmp dx,bx ;See if owned by cmd.com je findpspenv_3 findpspenv_1: mov ax,dx ;Get original PSP call chkarena ;Compute size of segment jc findpspenv_error findpspenv_2: add ax,cx ;Add size of memory block inc ax call chkarena jc findpspenv_error jnz findpspenv_error ;Env never last env block cmp bx,dx ;See if owned by CMD.COM jne findpspenv_2 ;Yes, exit findpspenv_3: clc findpspenv_exit: pop es pop bx ret findpspenv_error: stc jmp short findpspenv_exit findpspenv endp ;----------------------------------------------------------------------- ; FINDENV Finds the parent's environment block. ; Exit: AX - Segment of local command processor environment. ;----------------------------------------------------------------------- findenv proc near assume cs:code,ds:code,es:code,ss:code call findcmdpsp ;Get PSP of command.com jc findenv_error call findpspenv ;Find environment for PSP jc findenv_error findenv_exit: ret findenv_error: mov si,offset errmsg16 ;Environment not found jmp short findenv_exit findenv endp ;----------------------------------------------------------------------- ; FINDMASTER Finds the master environment block. ; Exit: AX - Segment of master environment block. ;----------------------------------------------------------------------- findmaster proc near assume cs:code,ds:code,es:code,ss:code push di push es mov ah,52h ;Get address of first MCB int 21h mov ax,es:[bx-2] ;point ES to MCB findmaster_1: inc ax call chkarena ;See if valid mem block jc findmaster_error jnz findmaster_error cmp ax,bx ;See if PSP block je findmaster_2 add ax,cx ;No, add size to move 2 next jmp short findmaster_1 findmaster_2: cmp dos_version,0a00h ;If OS/2, use DOS 3.3 method. jae findmaster_3 cmp dos_version,0400h ;If DOS 4.00 or greater, jb findmaster_3 ; COMMAND.COM may not be the push ax dec ax mov es,ax ; first program loaded. Look pop ax push si mov si,offset shell_name ; at the name of the program mov di,8 ; stored in the last 8 bytes xor cx,cx ; of the memory control mov cl,shell_namlen ; block. If the name of the repe cmpsb ; command processor isn't pop si jne findmaster_1 ; found, keep looking. cmp shell_namlen,8 ;If name shorter than 8 chars je findmaster_3 ; check for trailing zero. cmp byte ptr es:[di],0 jne findmaster_1 findmaster_3: call findpspenv ;Find environment for PSP findmaster_exit: pop es pop di ret findmaster_error: mov si,offset errmsg16 ;Environment not found stc jmp short findmaster_exit findmaster endp ;----------------------------------------------------------------------- ; CHECK4XMS Checks to see if an extended memory driver is loaded ; Exit: CF - Clear if ext driver found ; AX - EXT Version if CF clear ; SI - Points to error message if CF set ;----------------------------------------------------------------------- check4xms proc near mov ax,4300h ;Extended mem drvr chk int 2fh or al,al ;See if loaded je check4xms_error push es mov ax,4310h ;Get driver entry pt int 2fh mov word ptr [xms_serv],bx mov word ptr [xms_serv+2],es pop es xor ax,ax call ds:[xms_serv] ;Get version number mov bx,ax ;Version num returned shr al,1 ; as BCD. Convert shr al,1 ; to std DOS format shr al,1 ; of maj in AH and shr al,1 ; minor in AL mov ah,10 mul ah and bl,0fh add al,bl mov ah,bh clc check4xms_exit: ret check4xms_error: stc xor ax,ax mov si,offset errmsg19 ;ext mem not available jmp short check4xms_exit check4xms endp ;----------------------------------------------------------------------- ; CHECK4EMS Checks to see if an expanded memory driver is loaded ; Exit: CF - Clear if EMS driver found ; AX - EMS Version if CF clear ; SI - Points to error message if CF set ;----------------------------------------------------------------------- check4ems proc near push es push di mov ax,3567h ;Get interrupt 67 vector int 21h mov di,0ah mov si,offset ems_header mov cx,8 repe cmpsb pop di pop es jne check4ems_error mov ah,40h ;Get status int 67h or ah,ah jne check4ems_error mov ah,46h ;Get version int 67h or ah,ah jne check4ems_error mov bl,al ;Convert ver number shl ax,1 shl ax,1 shl ax,1 shl ax,1 mov al,bl and ax,0f0fh clc check4ems_exit: ret check4ems_error: stc xor ax,ax mov si,offset errmsg17 ;EMS not available jmp short check4ems_exit check4ems endp even ;Set stack on word boundry end_of_code = $ code ends end entry 4
file: /Techref/DOS/command/strings/STRINGS.ASM, 167KB, , updated: 1995/3/27 11:10, local time: 2024/11/9 17:30,
3.128.172.185:LOG IN ©2024 PLEASE DON'T RIP! THIS SITE CLOSES OCT 28, 2024 SO LONG AND THANKS FOR ALL THE FISH!
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://ecomorder.com/techref/DOS/command/strings/STRINGS.ASM"> DOS command strings STRINGS</A> |
Did you find what you needed? |
Welcome to ecomorder.com! |
Ashley Roll has put together a really nice little unit here. Leave off the MAX232 and keep these handy for the few times you need true RS232! |
.