;/////////////////////////////////////////////////// ; ; GOTO / GOSUB / RETURN. Jumps inside a BAT-file by ; ":label", MS-DOS / 4DOS style. ; ; GOTO label - jump to ":label" ; GOSUB label - call subroutine at ":label" ; RETURN - return to the line after the GOSUB ; ;/////////////////////////////////////////////////// GOTO_LABEL_MAX EQU 15 ; max label name length GOSUB_MAX EQU 16 ; max GOSUB nesting depth ;------------------------------------------------- ; GOTO label ; in: de -> argument string (label, may start with ':') ;------------------------------------------------- cmd_goto: ex de,hl ; hl -> argument text call GOTO_PARSE ; -> goto_label (upper, 0-term) ld a,(goto_label) or a jp z,.empty ; no label name jp GOTO_START ; rewind + start the label search .empty: ld de,MAIN_MSG.LABEL_NOT_FOUND jp gAbort ;------------------------------------------------- ; GOSUB label ; in: de -> argument string (label, may start with ':') ;------------------------------------------------- cmd_gosub: ex de,hl ; hl -> argument text call GOTO_PARSE ; -> goto_label (saved in memory) ld a,(goto_label) or a jp z,cmd_goto.empty call GOSUB_PUSH ; remember the return position jp GOTO_START ; then jump like GOTO ;------------------------------------------------- ; RETURN - resume after the matching GOSUB ;------------------------------------------------- cmd_return: ld a,(gosub_sp) or a jr z,.empty ; RETURN without GOSUB dec a ld (gosub_sp),a add a,a add a,a ; a = sp*4 (byte offset in stack) ld e,a ld d,0 ld hl,gosub_stk add hl,de ld e,(hl) ; saved offset (low word) inc hl ld d,(hl) inc hl ld (gosub_lo),de ld e,(hl) ; saved offset (high word) inc hl ld d,(hl) ld (gosub_hi),de ld a,(BAT_FM) ; bat-file handle ld hl,(gosub_hi) ; HL = offset high 16 bits ld ix,(gosub_lo) ; IX = offset low 16 bits ld bc,Dss.Move_FP.FrStart ; B=0 (from start), C=#15 RST ToDSS jr c,.io xor a ld (MOVWORD.count),a ; force re-read from saved position ret ; back to NEWLINE -> line after GOSUB .empty: ld de,MAIN_MSG.RET_NO_GOSUB jp gAbort .io: call print_err_message jp gAbort.silent ;------------------------------------------------- ; Parse a label argument into goto_label ; in: hl -> text (optional spaces/TAB, optional ':') ; out: goto_label = upper-cased, 0-terminated token ;------------------------------------------------- GOTO_PARSE: .sp0: ld a,(hl) ; skip leading blanks (space / TAB) cp " " jr z,.sp0i cp "\t" jr nz,.nosp0 .sp0i: inc hl jr .sp0 .nosp0: cp ":" ; allow "GOTO :label" jr nz,.sp1 inc hl .sp1: ld a,(hl) ; skip blanks after ':' cp " " jr z,.sp1i cp "\t" jr nz,.copy .sp1i: inc hl jr .sp1 .copy: ld de,goto_label ld b,GOTO_LABEL_MAX .cloop: ld a,(hl) cp " "+1 ; a <= ' ' -> end of token jr c,.cend call COMPARE.cmp_AZ ; -> upper case ld (de),a inc hl inc de djnz .cloop .cend: xor a ld (de),a ; 0-terminate ret ;------------------------------------------------- ; Rewind the BAT-file and start the label search ;------------------------------------------------- GOTO_START: ld a,(BAT_FM) ; bat-file handle ld hl,0 ; offset low ld ix,0 ; offset high ld bc,Dss.Move_FP.FrStart ; B=0 (from start), C=#15 RST ToDSS jr c,.io xor a ld (MOVWORD.count),a ; invalidate NEWLINE read buffer ld a,1 ld (goto_active),a ; activate the label search ret .io: call print_err_message jp gAbort.silent ;------------------------------------------------- ; Push the return position (file offset of the line ; that follows the current GOSUB) onto the stack. ;------------------------------------------------- GOSUB_PUSH: ld a,(gosub_sp) cp GOSUB_MAX jr nc,.deep ; stack overflow ; current file pointer (tell): FrCurrent, offset 0 ld a,(BAT_FM) ld hl,0 ld ix,0 ld bc,Dss.Move_FP.FrCurrent ; B=1, C=#15 RST ToDSS jr c,.io ; on return: IX = pointer low 16, HL = pointer high 16 ld (gosub_hi),hl ; save high word push ix pop hl ; hl = pointer low 16 ; offset = pointer - (bytes still unparsed in buffer1) ld a,(MOVWORD.count) ld e,a ld d,0 or a ; CF=0 sbc hl,de ; hl = low - count ld (gosub_lo),hl jr nc,.nob ld hl,(gosub_hi) ; borrow into high word dec hl ld (gosub_hi),hl .nob: ; store at gosub_stk[gosub_sp] ld a,(gosub_sp) ld c,a ; c = old depth add a,a add a,a ; a = sp*4 ld e,a ld d,0 ld hl,gosub_stk add hl,de ld de,(gosub_lo) ld (hl),e inc hl ld (hl),d inc hl ld de,(gosub_hi) ld (hl),e inc hl ld (hl),d ld a,c inc a ld (gosub_sp),a ; depth++ ret .deep: ld de,MAIN_MSG.GOSUB_DEEP jp gAbort .io: call print_err_message jp gAbort.silent ;------------------------------------------------- ; Print message (de=index) and abort the BAT-file ;------------------------------------------------- gAbort: call ECHO_MESSAGE .silent: xor a ld (goto_active),a ; don't double-print in cmd_break.exit jp cmd_break.exit ;------------------------------------------------- ; Called from CMDMODE for every BAT-file line. ; Handles ":label" lines and the GOTO/GOSUB search. ; ; out: CF=1 - skip this line (label line, or searching) ; CF=0 - execute this line normally ;------------------------------------------------- BAT_CHECK_LABEL: ld hl,Buffers.input_line.Path .sp: ld a,(hl) ; skip leading blanks (space / TAB) cp " " jr z,.spi cp "\t" jr nz,.first .spi: inc hl jr .sp .first: cp ":" ; is it a label line ? jr z,.label ; not a label line ld a,(goto_active) or a ret z ; CF=0 -> run normally scf ; searching -> skip line ret ; .label: ld a,(goto_active) or a jr nz,.match ; not searching: ":label" -> skip (no echo, no exec) scf ret ; searching: does this label match goto_label ? .match: inc hl ; skip ':' .msp: ld a,(hl) ; skip blanks after ':' cp " " jr z,.mspi cp "\t" jr nz,.mcmp .mspi: inc hl jr .msp .mcmp: ld de,goto_label .mlp: ld a,(de) ; target char (upper, 0-term) or a jr z,.mend ; target consumed ld c,a ld a,(hl) cp " "+1 ; line token ended too early ? jr c,.skip ; -> no match call COMPARE.cmp_AZ cp c jr nz,.skip inc hl inc de jr .mlp .mend: ld a,(hl) ; target ended: line token must end here cp " "+1 ; a <= ' ' -> full match jr nc,.skip ; line label is longer -> no match ; match ! stop searching, skip the label line itself xor a ld (goto_active),a scf ret ; .skip: scf ; keep searching, skip this line ret ; goto_active: db 0 ; 1 = searching for a label goto_label: ds GOTO_LABEL_MAX+1,0 ; target label (upper, 0-term) gosub_sp: db 0 ; GOSUB nesting depth gosub_lo: dw 0 ; scratch (offset low) gosub_hi: dw 0 ; scratch (offset high) gosub_stk: ds GOSUB_MAX*4,0 ; return offsets (32-bit each)