<--- Turn the page     (contents page)     Turn the page --->


Basic

Getting the actual command line




Have you ever wanted to get the actual command line in Basic? You know, the one that isn't upper case. Sure you have seen it done by calling an external assembler routine that you have to link to your program, but you don't like those because you can't see what is happening and could modify it if you tried.

How about a routine in basic. The only assembler code used is to get the current PSP (program segment prefix) and it is in-line assembly called by CALL ABSOLUTE. If you know DEBUG, you can modify it all you want, and there is no external program to link to your code. All you have to do is load the QB.QLB at start up. If you compile your program within the IDE, then basic does it all for you.

Well, lets get started. First we need to get the address of the Program Prefix Segment. The command line is at offset 0080h with in the PSP (If you need more info on the PSP, see last issue). We must use inline assembler and CALL ABSOLUTE to get the PSP. So we need to set up our assembler code and then call it. (for more information on inline assembler in basic, see here. Here is our assembler code in DATA form.

DATA &H55           : '  PUSH BP
DATA &H53           : '  PUSH BX
DATA &H89,&HE5      : '  MOV  BP,SP
DATA &HB4,&H62      : '  MOV  AH,62h
DATA &HCD,&H21      : '  INT  21h
DATA &H93           : '  XCHG BX,AX
DATA &H8B,&H5E,&H08 : '  MOV  BX,[BP+08]
DATA &H89,&H07      : '  MOV  [BX],AX
DATA &H5B           : '  POP  BX
DATA &H5D           : '  POP  BP
DATA &HCB,&H02,&H00 : '  RET  2


Now that we have the PSP, we can get the command line. The length of the command line is at offset 0080h. This length includes the space after the program name and before the command line.
  DEF SEG = PSP
    Cnt% = PEEK(&H80)
    .
    .
    .
  DEF SEG

Now the command line starts at offset 0082h.
  DEF SEG = PSP
    Cnt% = PEEK(&H80)
    IF Cnt% > 0 THEN
      PRINT "Command line length:  "; Cnt% - 1
      FOR i% = 2 TO Cnt%
        Cmnd$ = Cmnd$ + CHR$(PEEK(&H80 + i%))
      NEXT
    END IF
  DEF SEG

Now you can do what you want with Cmnd$. I just print it in the demo code below.

Be sure to load the code with the /L switch:
QB filename.bas /L
If you don't compile it in the IDE, make sure to link the QB.LIB library included with QB45. ¥




' load the QB.QLB at start up:
'   QB filename /L

'$DYNAMIC
DECLARE SUB ABSOLUTE (Par1 AS INTEGER, address AS INTEGER)
DECLARE FUNCTION GetPSPa% ()

CONST SizeofAsm = 19

' get the PSP address (segment)
PSP = GetPSPa%
PRINT "PSP address:  "; HEX$(PSP); "h"

DEF SEG = PSP
	Cnt% = PEEK(&H80)                          ' length is at PSP:[0080h]
	IF Cnt% > 0 THEN                           ' if 0 then we don't want whats there
		PRINT "Command line length:  "; Cnt% - 1 '
		FOR i% = 2 TO Cnt%                       ' start with 2 (skip over space)
			Cmnd$ = Cmnd$ + CHR$(PEEK(&H80 + i%))  ' get it
		NEXT
	END IF
DEF SEG

PRINT
' print QBs command line
PRINT "Quick Basic command line: ", COMMAND$
' print actual command line
PRINT "     Actual command line: ", Cmnd$

END


GetPSPd:
' Get PSP address of program
'   on entry:  nothing
'  on return:  PSP address
DATA &H55           : '  PUSH BP      ; let's set up our own BP
DATA &H53           : '  PUSH BX
DATA &H89,&HE5      : '  MOV  BP,SP   ;
DATA &HB4,&H62      : '  MOV  AH,62h  ; get PSP
DATA &HCD,&H21      : '  INT  21h   ; do it
DATA &H93           : '  XCHG BX,AX
DATA &H8B,&H5E,&H08 : '  MOV  BX,[BP+08]  ; put RC = first param passed
DATA &H89,&H07      : '  MOV  [BX],AX   ;
DATA &H5B           : '  POP  BX
DATA &H5D           : '  POP  BP    ; restore base pointer
DATA &HCB,&H02,&H00 : '  RET  2   ; Restore stack for 1 param passed
' end code

REM $STATIC
'  This function returns the current PSP address
'   Using inline assembly
'
FUNCTION GetPSPa%

' An array of 256 bytes  (more than plenty)
	REDIM GetPSP%(1 TO 256 \ 2)
 
	P% = VARPTR(GetPSP%(1))
	DEF SEG = VARSEG(GetPSP%(1))  ' point DS to the array
	RESTORE GetPSPd                ' start 'reading' DATA at our asm code section
	FOR i% = 0 TO SizeofAsm - 1    ' and put it in the array a byte at a time
		READ J%
		POKE (P% + i%), J%
	NEXT i%
	CALL ABSOLUTE(RC%, P%)  ' now call it
	DEF SEG                   ' restore DS

	ERASE GetPSP%

	GetPSPa% = RC%
END FUNCTION



<--- Turn the page     (contents page)     Turn the page --->

Page 10