; ; Christian Groessler, 12-Jun-2016 ; ; int __fastcall__ exec (const char* progname, const char* cmdline); ; ; supports only XDOS at the moment .export _exec .import popax .import __dos_type .import findfreeiocb .import incsp2 .import excexit ; from crt0.s .import SP_save ; from crt0.s .ifdef UCASE_FILENAME .import ucase_fn .import addysp .endif .include "zeropage.inc" .include "errno.inc" .include "atari.inc" ; area $0100 to $0128 might be in use (e.g. Hias' high speed patch) CMDLINE_BUFFER = $0129 ; put progname + cmdline as one single string there ; alternatively: ;CMDLINE_BUFFER = $0480 ; put progname + cmdline as one single string there CMDLINE_MAX = 40+3 ; max. length of drive + progname + cmdline .code notsupp:lda #ENOSYS ; "unsupported system call" .byte $2C ; bit opcode, eats the next 2 bytes noiocb: lda #EMFILE ; "too many open files" jsr incsp2 ; clean up stack seterr: jmp __directerrno ; entry point _exec: ; save cmdline sta ptr3 stx ptr3+1 ldy __dos_type cpy #XDOS bne notsupp jsr findfreeiocb bne noiocb stx tmp4 ; remember IOCB index ; get program name jsr popax .ifdef UCASE_FILENAME .ifdef DEFAULT_DEVICE ldy #$80 .else ldy #$00 .endif sty tmp2 ; set flag for ucase_fn jsr ucase_fn bcc ucok1 invret: lda #EINVAL ; file name is too long bne seterr ucok1: .endif ; defined UCASE_FILENAME ; copy program name and arguments to CMDLINE_BUFFER sta ptr4 ; ptr4: pointer to program name stx ptr4+1 ldy #0 ; TODO: check stack ptr and and use min(CMDLINE_MAX,available_stack) copyp: lda (ptr4),y beq copypd sta CMDLINE_BUFFER,y iny cpy #CMDLINE_MAX bne copyp ; programe name too long beq invret .ifndef UCASE_FILENAME invret: lda #EINVAL bne seterr .endif ; file name copied, check for args copypd: tya ; put Y into X (index into CMDLINE_BUFFER) tax lda ptr3 ora ptr3+1 ; do we have arguments? beq copycd ; no ldy #0 lda (ptr3),y ; get first byte of cmdline parameter beq copycd ; nothing there... lda #' ' ; add a space btw. progname and cmdline bne copyc1 ; copy args copyc: lda (ptr3),y beq copycd iny copyc1: sta CMDLINE_BUFFER,x inx cpx #CMDLINE_MAX bne copyc ; progname + arguments too long beq invret invexe: jsr close lda #XNTBIN bne setmerr copycd: lda #ATEOL sta CMDLINE_BUFFER,x ; open the program file, read the first two bytes and compare them to $FF ldx tmp4 ; get IOCB index lda ptr4 ; ptr4 points to progname sta ICBAL,x lda ptr4+1 sta ICBAH,x lda #OPNIN ; open for input sta ICAX1,x lda #OPEN sta ICCOM,x jsr CIOV tya .ifdef UCASE_FILENAME ldy tmp3 ; get size jsr addysp ; free used space on the stack ; the following 'bpl' depends on 'addysp' restoring A as last command before 'rts' .endif ; defined UCASE_FILENAME bpl openok pha ; remember error code jsr close ; close the IOCB (required even if open failed) pla ; put error code back into A setmerr:jmp __mappederrno ; update errno from OS specific error code in A openok: lda #>buf sta ICBAH,x ; set buffer address lda #CMDLINE_BUFFER sta ICBAH,x lda #0 sta ICBLL,x ; length shouldn't be random, but 0 is ok sta ICBLH,x sta ICAX1,x sta ICAX2,x lda #80 ; XDOS: run DUP command sta ICCOM,x jmp CIOV_org ; no way to display an error message in case of failure, and we will return to DOS ; close IOCB, index in X .proc close lda #CLOSE sta ICCOM,x jmp CIOV ; close IOCB .endproc .bss buf: .res 2