;************************************************************** ; Example CP/M Command Line Parsing Program Segment ;This sample expects the command line to include both a file ;name and some number of options, like this: ; ; MYPROG MYFILE /R /B4 /TA ; ;It will work with arbitrary spaces between options: ; ; MYPROG MYFILE /TB /B4 ; ;It does not require any spaces, except before the file name: ; ; MYPROG MYFILE/TA/B4/R/K23 ; ;The command parsing assumes that each command line option ;will set a variable in the table at the end, VARTAB. The ;table of legal options (OPTTAB) is a list of options, with ;the type of value (none, and ASCII character, or a 1- or ;2-digit ASCII number), the min and max value for such a ;number, and the location in VARTAB for the result. ;************************************************************** ;------- ;Equates ;------- COMBUF equ 80H ;command line buffer ;CP/M's Default File Control Block FCB equ 5CH FCBDD equ FCB ;Drive Descriptor FCBFN equ FCB+1 ;File name (8 chrs) FCBFT equ FCB+9 ;File Type (3 chrs) FCBEXT equ FCB+12 ;File extent within FCB FCBRCNT equ FCB+15 ;Record cnt within FCB FCBREC equ FCB+32 ;Record # within FCB ;************************************************************** ;========== ;Start Here ;========== ;----------------------------------- ;Point to command line options, and ;find the beginning of the file name ;----------------------------------- ld hl,COMBUF ;CP/M put 0-terminated ;...command line here ld b,(hl) ;b=byte count inc hl ;point to 1st command line chr call SSKIP ;skip initial spaces jp Z,HLPEXT ;no parameters? -->help screen ;------------------------------------- ;Skip past the file name, which CP/M ;already put in the FCB for us ; b = bytes remaining to see in COMBUF ; hl points to next chr in COMBUF ;------------------------------------- SKPFIL: call CMDCHR jr Z,OPTDON ;no options cp a,'/' ;option crammed jr Z,OPTLP2 ;..against file name? cp a,' ' ;hunt for a space jr NZ,SKPFIL ;space past filename ;----------------------------------------------- ;Parse all command line options and set ;variables accordingly. Each option must be ;preceeded by a '/' and followed by an ASCII, a ;1- or 2-digit numeric, or no value. Options may ;be preceed by any reasonable number of spaces. ;----------------------------------------------- OPTLUP: call SSKIP ;skip spaces jr Z,OPTDON cp a,'/' ;all start with / jp NZ, BADINP ;error:no slash OPTLP2: call CMDCHR ;Get an option chr jp Z,BADINP ;Error: nothing after / ld c,a ;save while we get val ;-------------------------------------- ;Set de=1 or 2 bytes that came with ;this option, if any. Set de=0 if none. ;-------------------------------------- ld de,0 ;assume no parameter call CMDVAL ;get 1st param chr jr Z,GV1 ;Z:no more chrs in param ld e,a ;1st param chr call CMDVAL ;get 2nd param chr jr Z,GV1 ;Z:no more chrs in param ld d,e ;shift 1st chr over ld e,a ;2nd param chr GV1: ;------------------------------------------------ ;Got a command line option in c and a value for ;that option in de. Loop through table of options, ;looking for a match. Bounds-check value using ;table entries. Update the appropriate option ;variable with the provided value. Error exit if ;no match, or if the value is out of bounds. ;------------------------------------------------ push hl ;Save COMBUF pointer ld hl,OPTTAB-3 CHKLUP: inc hl ;next table entry inc hl inc hl ld a,c ;option chr from user sub a,(hl) ;Match? (alpha order) inc hl ;point to min value jp C,BADPAR ;Carry: Not in table jr NZ,CHKLUP ;No match: keep looking ;Table match. Get and test min value from the table. ; a = 0 ; de = option value from user ; (hl) = min value from table add a,(hl) ;get min value & test ld c,a ;min value from table inc hl ;point to range jr NZ,CHK1 ;min=0 is special case ;deal with special case option that has no value ; a = 0 ; de = option value from user (should be 0) ; (hl) = range from table or a,e ;should have no value jp NZ,BADVAL ld c,(hl) ;get value from table jr CHK3 ;bounds-check value that came with option ; Sign bit set means ASCII decimal numbers in de ; otherwise, the user input value is in e ; c = min value from table ; (hl) = range from table CHK1: call M,DEC2BN ;Sign bit set: convert ;..de to binary in e ;..and clear d res 7,c ;clear msb flag ld a,e ;param from input sub a,c ;a=value - min cp a,(hl) ;compare to max range jp NC,BADVAL ;Error: value out of range ld a,d ;too many digits? or a CHK2: jp NZ,BADVAL ;Error: too many digits ld c,e ;parameter value ; c = paramater value ; d = 0 ; (hl) = range from table chk3: inc hl ;point to address offset ld e,(hl) ;get de=address offset ld hl,VARTAB ;base address of vars add hl,de ;address of variable ld (hl),c ;update variable pop hl ;Restore COMBUF pointer jr OPTLUP ;look for more OPTDON: ;---------------------------------------- ;Done parsing command line. Check to see ;if a file name at least existed. (CP/M ;won't put one here if it starts with /.) ;---------------------------------------- ld a,(FCBFN) ;1st chr of filename cp ' ' jp Z,BADINP ;Error: No file name present <<>> ;***Subroutine********************************** ;Skip over spaces in command line buffer until a ;non-space character is found ;On Entry: ; b = remaining COMBUF byte count ; hl points to the next chr in COMBUF ;On Exit: ; a = chr from COMBUF ; b (byte count) has been decremented ; hl has been advanced ; Z set means end of buffer (and a is not valid) ;************************************************ SSKIP: call CMDCHR ret Z ;Z set for nothing left cp a,' ' ;white space? jr Z,SSKIP ret ;chr in a, Z clear ;***Subroutine***************************** ;Get a command parameter byte ;On Entry: ; b = remaining COMBUF byte count ; hl points to the next command line chr ;On Exit: ; Z set if no more bytes in this parameter ; Z clear if another byte is present ; a = (hl) ; b (byte count) has been decremented ; hl incremented if Z clear ;****************************************** CMDVAL: ld a,(hl) ;get buffer chr cp a,' ' ;Space means end, but not error ret Z ;space: end of value cp a,'/' ;Next one crammed agaist this? ret Z ;y: end of value ;Fall into CMDCHR to get the chr and return ;or just return if end of input ;***Subroutine************************************* ;Get next chr from 0-terminated command line buffer ;On Entry: ; b = remaining COMBUF byte count ; hl points to the next chr in COMBUF ;On Exit: ; a = chr from COMBUF ; b (byte count) has been decremented ; hl has been advanced unless end ; Z set means end of buffer ; Carry = 0 ;************************************************** CMDCHR: ld a,b ;byte count or a,a ret Z ;end of command line? ld a,(hl) ;get buffer chr dec b ;One fewer chr inc hl ;bump buffer pointer ret ;with Z cleared ;***Table****************************************** ;Command Line Options ;Table entries must be in alphabetical order, and ;terminated with 0FFH ; ;Each entry is 4 bytes long: ; byte1 = uppercase legal option letter ; byte2 = min legal value for this parameter ; MSB set means ASCII numbers ; byte3 is the max range (Max-min) for this param+1 ; byte4 = variable table address offset ; ; if Byte2=0, then no parameters, and byte3 = value ;************************************************** OPTTAB: ;Baud Rate, 0-9 db 'B',80h,9,[BAUDRT-VARTAB] ;CRC Rx error check mode: puts 0 in CRCFLG db 'C',0,0,[CRCFLG-VARTAB] ;Number of K-bytes in the BUFFER db 'K',81h,64-1,[BKBYTS-VARTAB] ;Quiet mode (no pacifiers, etc.) db 'Q',0,0FFh,[PACCNT-VARTAB] ;Select receive mode: puts 1 in XMODE db 'R',0,1,[XMODE-VARTAB] ;Select send mode: puts 0 in XMODE db 'S',0,0,[XMODE-VARTAB] ;Transfer port: A=TU-ART port A, B=TU-ART port B ; C=Console port db 'T','A','C'-'A'+1,[TPORT-VARTAB] ;end-of-table marker is also the ;FFh at the beginning of BAUDTB ;---Table-------------------------------- ;Command line option variables ;(These examples from my XMODEM preogram) ;---------------------------------------- VARTAB: ;Basis for var. address offsets XMODE: db 0FFh ;00: send ;X1: Rx, not currently flushing ;X2: Rx, currently flushing ;01 or 02: no disk writes yet ;8x: disk writes have occured ;FFh: uninitialized PACCNT: db 0 ;Current column count-down for ;..pacifiers. Init for new line ;FF means quiet mode ;CRCFLG must follow PACCNT CRCFLG: db 0FFh ;0: cksum, 1: CRC, FF: uninit'd ;CRCFLG must follow PACCNT TPORT: db DEFPORT ;Transfer port: 'A' - 'C' BAUDRT: db DEFBAUD+80h ;current baud rate ;msb means defaulted BKBYTS: db DEFBSIZ ;K-bytes in the BUFFER