Michael Webster Shell routine for TCB mfwebster@pdq.net 06-14-03 ( : ) TBC 187 4669 TBCSHELL.BAS* TBCSHELL.BAS is a TBC program that includes ã* a SHELL procedure and several related ã* procedures. ã* ã* Public Domain 2003 Michael Webster ã* : mfwebster@pdq.net ã* This was coded for the TOKIWA 8086 BASIC ã* compiler Ver. 5.55 *** Sample ***, ã* Copyright by Genjii OKADA. ã* ã* For testing, this program was compiled with ã* TBC TBCSHELL.BAS /A /O /#X for an EXE, and ã* TBC TBCSHELL.BAS /A /C /O /#X for a COM file. ã* ã* Likely error codes for the Load and Execute ã* Program function (Interrupt 21h, AX = 4B00h): ã* 0001h INVALID_FUNCTION ã* 0002h FILE_NOT_FOUND ã* 0003h PATH_NOT_FOUND ã* 0004h TOO_MANY_OPEN_FILES ã* 0005h ACCESS_DENIED ã* 0008h NOT_ENOUGH_MEMORY ã* 000Ah BAD_ENVIRONMENT ã* 000Bh BAD_FORMAT ã* If you fail to call FreeUnusedMemory first, ã* then the function will return error code 8. ã ã* These are global because I could find no ã* reasonable way to return a string from ã* a procedure. ãg_comspec$ = "" ãg_command$ = "" ã ã* This is global because it is accessed ã* from several procedures. ãinteger g_pspseg ã ã* This LOADEXEC structure is global because ã* I could not get LOC and OFFSET to work ã* correctly for local integers. ãinteger g_le_env ãinteger g_le_cmdoff ãinteger g_le_cmdseg ãinteger g_le_fcb1off ãinteger g_le_fcb1seg ãinteger g_le_fcb2off ãinteger g_le_fcb2seg ã ã*** Test code *** ã ãcall GetCommandLine ã*print g_command$ ãcall FreeUnusedMemory ãcall Shell(g_command$) ã*call Shell("mem /d/p") ã ã*** Procedures *** ã ãsubroutine InitPspSeg ã * Sets the global g_pspseg to the segment ã * address of the Program Segment Prefix. ã ã integer codeseg ã ã /mov ax,cs ã value = codeseg ã #c g_pspseg = codeseg ã #e g_pspseg = codeseg - 16 ã return ãsubend ã ãsubroutine InitComspec ã * Sets the global g_comspec$ to the value ã * of the COMSPEC environment variable. ã ã integer n, envseg ã character c ã ã call InitPspSeg ã envseg = dpeek(g_pspseg; &2c) ã n = 0 ã while peek(envseg; n) <> 0 ã g_comspec$ = "" ã while peek(envseg; n) <> 0 ã c = chr$(!) ã g_comspec$ = g_comspec$ + c ã n = n + 1 ã wend ã if instr(g_comspec$,"COMSPEC") = 1 then ã g_comspec$ = mid$(g_comspec$,instr(g_comspec$,"=") + 1) ã break ã endif ã n = n + 1 ã wend ã return ãsubend ã ãsubroutine GetCommandLine ã * Copies the program's command line to ã * the global g_command$. ã ã integer i, n ã character c ã ã call InitPspSeg ã ã g_command$ = "" ã ã n = peek(g_pspseg; &80) ã for i = &81 to n + &81 ã c = chr$(peek(g_pspseg; i)) ã g_command$ = g_command$ + c ã next i ã return ãsubend ã ãsubroutine FreeUnusedMemory ã * Resizes the program's memory block to ã * free unused memory above the program. ã ã integer stackseg, paragraphs ã ã call InitPspSeg ã /mov ax,ss ã value = stackseg ã paragraphs = stackseg + 4096 - g_pspseg ã /mov bx,paragraphs ã /mov ax,g_pspseg ã /mov es,ax ã /mov ax,&4a00 ã /int &21 ã /jnc @10 ã ã * Sophisticated error handling :) ã print ! ã10 return ãsubend ã ãsubroutine Shell(command$) ã * Starts a copy of the command processor and ã * passes it , formatted as a proper ã * command tail. ã ã integer g_comspec_off ã ã call InitPspSeg ã call InitComspec ã ã * This string must be initialized before ã * initializing LOADEXEC because TBC will ã * move it when it is initialized ! ã cmd_tail$ = " /C " ã cmd_tail$ = cmd_tail$ + command$ ã cmd_tail$ = chr$(len(cmd_tail$)) + cmd_tail$ + chr$(13) ã ã * Initialize LOADEXEC to use a copy of the ã * parent's environment and FCBs, and the ã * formatted command string. Note that the ã * storage order depends on the order in ã * which the variables are initialized rather ã * than the order in which they are declared. ã g_le_env = 0 ã g_le_cmdoff = dpeek(loc(cmd_tail$)) ã /mov ax,ds ã value = g_le_cmdseg ã g_le_fcb1off = &5c ã g_le_fcb1seg = g_pspseg ã g_le_fcb2off = &6c ã g_le_fcb1seg = g_pspseg ã ã g_comspec_off = dpeek(loc(g_comspec$)) ã ã /mov dx,g_comspec_off ã /push ds ã /pop es ã /mov bx,offset g_le_env ã /mov ax,bx ã /mov ax,&4b00 ã /int &21 ã /jnc @10 ã ã * Sophisticated error handling :) ã print ! ã10 return ãsubend ã ãend ãMichael Webster Free Unused Memory for TCB mfwebster@pdq.net 06-14-03 ( : ) TBC 34 891 MemFree.bas subroutine FreeUnusedMemory ã * Resizes the program's memory block to ã * free unused memory above the program. ã ã integer stackseg, extraseg, paragraphs ã ã call InitPspSeg ã /mov ax,ss ã value = stackseg ã /mov ax,es ã value = extraseg ã ã * If the value in ES is greater than the ã * value in SS, then at least one extended ã * array has been allocated. The value 4096 ã * assumes the maximum size (65536 bytes) ã * for the stack and extra segments. ã if extraseg > stackseg then ã paragraphs = extraseg + 4096 - g_pspseg ã else ã paragraphs = stackseg + 4096 - g_pspseg ã endif ã ã /mov bx,paragraphs ã /mov ax,g_pspseg ã /mov es,ax ã /mov ax,&4a00 ã /int &21 ã /jnc @10 ã ã * Sophisticated error handling :) ã print ! ã10 return ãsubend ã