1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
; mainargs.s
;
; 2003-03-07, Ullrich von Bassewitz,
; based on code from Stefan A. Haubenthal, <polluks@web.de>
; 2005-02-26, Ullrich von Bassewitz
; 2014-09-10, Greg King
;
; Scan a group of arguments that are in BASIC's input-buffer.
; Build an array that points to the beginning of each argument.
; Send, to main(), that array and the count of the arguments.
;
; Command-lines look like these lines:
;
; run
; run : rem
; run:rem arg1 " arg 2 is quoted " arg3 "" arg5
;
; "run" and "rem" are entokenned; the args. are not. Leading and trailing
; spaces outside of quotes are ignored.
;
; TO-DO:
; - The "file-name" might be a path-name; don't copy the directory-components.
; - Add a control-character quoting mechanism.
.constructor initmainargs, 24
.import __argc, __argv
.import sys_bank, restore_bank
.import sysp0:zp, ptr1:zp
.include "cbm510.inc"
.macpack generic
MAXARGS = 10 ; Maximum number of arguments allowed
REM = $8f ; BASIC token-code
NAME_LEN = 16 ; Maximum length of command-name
; Get possible command-line arguments. Goes into the special ONCE segment,
; which may be reused after the startup code is run.
;
.segment "ONCE"
initmainargs:
; Assume that the program was loaded, a moment ago, by the traditional LOAD
; statement. Save the "most-recent filename" as argument #0.
; Because the buffer, that we're copying into, was zeroed out,
; we don't need to add a NUL character.
;
jsr sys_bank
ldy #FNAM
lda (sysp0),y ; Get file-name pointer from system bank
sta ptr1
iny
lda (sysp0),y
sta ptr1+1
iny ; FNAM_BANK
lda (sysp0),y
tax
ldy #FNAM_LEN
lda (sysp0),y
tay
lda #0 ; The terminating NUL character
stx IndReg ; Look for name in correct bank
cpy #NAME_LEN + 1
blt L1
ldy #NAME_LEN ; Limit the length
bne L1 ; Branch always
L0: lda (ptr1),y
L1: sta name,y
dey
bpl L0
jsr restore_bank
inc __argc ; argc always is equal to at least 1
; Find a "rem" token.
ldx #0
L2: lda BASIC_BUF,x
bze done ; No "rem," no args.
inx
cmp #REM
bne L2
ldy #1 * 2
; Find the next argument.
next: lda BASIC_BUF,x
bze done ; End of line reached
inx
cmp #' ' ; Skip leading spaces
beq next
; Found start of next argument. We've incremented the pointer in X already, so
; it points to the second character of the argument. That is useful because we
; will check now for a quoted argument; in which case, we will have to skip that
; first character.
found: cmp #'"' ; Is the argument quoted?
beq setterm ; Jump if so
dex ; Reset pointer to first argument character
lda #' ' ; A space ends the argument
setterm:sta term ; Set end-of-argument marker
; Now, store a pointer to the argument into the next slot.
txa ; Get low byte
add #<BASIC_BUF
sta argv,y ; argv[y]= &arg
lda #>$0000
adc #>BASIC_BUF
sta argv+1,y
iny
iny
inc __argc ; Found another arg
; Search for the end of the argument.
argloop:lda BASIC_BUF,x
bze done
inx
cmp term
bne argloop
; We've found the end of the argument. X points one character behind it, and
; A contains the terminating character. To make the argument a valid C string,
; replace the terminating character by a zero.
lda #$00
sta BASIC_BUF-1,x
; Check if the maximum number of command-line arguments is reached. If not,
; parse the next one.
;
lda __argc ; Get low byte of argument count
cmp #MAXARGS ; Maximum number of arguments reached?
blt next ; Parse next one if not
; (The last vector in argv[] already is NULL.)
done: lda #<argv
ldx #>argv
sta __argv
stx __argv + 1
rts
.segment "INIT"
term: .res 1
name: .res NAME_LEN + 1
.data
; char* argv[MAXARGS+1]={name};
argv: .addr name
.res MAXARGS * 2
|