]> git.sur5r.net Git - cc65/commitdiff
Implement exec() for Atari XDOS.
authorChristian Groessler <chris@groessler.org>
Mon, 13 Jun 2016 18:40:01 +0000 (20:40 +0200)
committerChristian Groessler <chris@groessler.org>
Mon, 13 Jun 2016 18:40:01 +0000 (20:40 +0200)
- Adds new ENOEXEC error code, also used by Apple2 targets.
- Maximum command line length is 40, incl. program name. This is
  an XDOS restriction.
- testcode/lib/tinyshell.c has been extended to be able to run
  programs.

asminc/atari.inc
asminc/errno.inc
include/errno.h
libsrc/apple2/oserror.s
libsrc/atari/crt0.s
libsrc/atari/exec.s [new file with mode: 0644]
libsrc/atari/oserror.s
libsrc/common/errormsg.c
testcode/lib/tinyshell.c

index f7a7ab223b853357708bad05db457238c58a43c3..453c370f43f4b80ff262cf8a64e6a1dcb8d321d8 100644 (file)
@@ -183,6 +183,7 @@ FNTFND  = 170           ;($AA) file not found
 PNTINV  = 171           ;($AB) point invalid
 BADDSK  = 173           ;($AD) bad disk
 INCFMT  = 176           ;($B0) DOS 3: incompatible file system
+XNTBIN  = 180           ;($B4) XDOS: file not binary
 
 ; DCB Device Bus Equates
 
@@ -889,6 +890,10 @@ SETVBV_org  = $E45C     ;vector to set VBLANK parameters
 CIOV    = $E456         ;vector to CIO
 SIOV    = $E459         ;vector to SIO
 SETVBV  = $E45C         ;vector to set VBLANK parameters
+; aliases in order not to have to sprinkle common code with .ifdefs
+CIOV_org    = CIOV
+SIOV_org    = SIOV
+SETVBV_org  = SETVBV
 .endif
 SYSVBV  = $E45F         ;vector to process immediate VBLANK
 XITVBV  = $E462         ;vector to process deferred VBLANK
index 83cd9a75d785db39a5af88fd34e820fd5800fac9..6e5cce42b650fe18b40f495a32d62dfb16a180a2 100644 (file)
@@ -28,6 +28,7 @@
         ESPIPE                  ; Illegal seek
         ERANGE                  ; Range error
         EBADF                   ; Bad file number
+        ENOEXEC                 ; Exec format error
         EUNKNOWN                ; Unknown OS specific error - must be last!
 
         EMAX    = EUNKNOWN      ; Highest error code
index 0b3d67bc7f97d4310a9762f40c078a7ab88eef4a..ae76b6c05c06b43c8dd9c121a48cb98ce04d4532 100644 (file)
@@ -72,7 +72,8 @@ extern int _errno;
 #define ESPIPE          14      /* Illegal seek */
 #define ERANGE          15      /* Range error */
 #define EBADF           16      /* Bad file number */
-#define EUNKNOWN        17      /* Unknown OS specific error */
+#define ENOEXEC         17      /* Exec format error */
+#define EUNKNOWN        18      /* Unknown OS specific error */
 
 
 
index f16aa49601b1c6b16a22d992fd9c8afc47717e3a..ae3efcacc92101f6432980c219e884efa4318f70 100644 (file)
@@ -45,7 +45,7 @@ ErrTab: .byte   $01, ENOSYS     ; Bad system call number
         .byte   $47, EEXIST     ; Duplicate filename
         .byte   $48, ENOSPC     ; Volume full
         .byte   $49, ENOSPC     ; Volume directory full
-;       .byte   $4A, EUNKNOWN   ; Incompatible file format
+        .byte   $4A, ENOEXEC    ; Incompatible file format
         .byte   $4B, EINVAL     ; Unsupported storage_type
 ;       .byte   $4C, EUNKNOWN   ; End of file encountered
         .byte   $4D, ESPIPE     ; Position out of range
index 87d7d036f34e99f3a6934cd844a4e3d465149e1a..d14567491cb40e44069e2cb310e5350af2c3016d 100644 (file)
@@ -9,7 +9,7 @@
 ;
 
         .export         __STARTUP__ : absolute = 1      ; Mark as startup
-        .export         _exit, start
+        .export         _exit, start, excexit, SP_save
 
         .import         initlib, donelib
         .import         callmain, zerobss
@@ -109,12 +109,12 @@ start:
 
 ; Call the module destructors. This is also the exit() entry.
 
-_exit:  jsr     donelib         ; Run module destructors
+_exit:  ldx     SP_save
+        txs                     ; Restore stack pointer
 
 ; Restore the system stuff.
 
-        ldx     SP_save
-        txs                     ; Restore stack pointer
+excexit:jsr     donelib         ; Run module destructors; 'excexit' is called from the exec routine
 
 ; Restore the left margin.
 
diff --git a/libsrc/atari/exec.s b/libsrc/atari/exec.s
new file mode 100644 (file)
index 0000000..2835a22
--- /dev/null
@@ -0,0 +1,207 @@
+;
+; 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         __do_oserror
+        .import         excexit                 ; from crt0.s
+        .import         SP_save                 ; from crt0.s
+.ifdef  UCASE_FILENAME
+        .importzp       tmp3
+        .import         ucase_fn
+        .import         addysp
+.endif
+
+        .include        "zeropage.inc"
+        .include        "errno.inc"
+        .include        "atari.inc"
+
+CMDLINE_BUFFER          =       $0100           ; 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: jsr     __directerrno
+        lda     #$FF
+        tax
+        rts                     ; return -1
+
+; 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
+
+; 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     #<buf
+        sta     ICBAL,x
+        lda     #0              ; set buffer length
+        sta     ICBLH,x
+        lda     #2
+        sta     ICBLL,x
+        lda     #GETCHR         ; iocb command code
+        sta     ICCOM,x
+        jsr     CIOV            ; read it
+        bmi     invexe          ; read operation failed, return error
+
+        lda     ICBLL,x         ; # of bytes read
+        cmp     #2
+        bne     invexe
+        lda     #$FF            ; check file format (need $FFFF at the beginning)
+        cmp     buf
+        bne     invexe
+        cmp     buf+1
+        bne     invexe
+
+        jsr     close           ; close program file
+
+; program file appears to be available and good
+; here's the point of no return
+
+        lda     tmp4            ; get IOCB index
+        pha                     ; and save it ('excexit' calls destructors and they might destroy tmp4)
+        jsr     excexit
+        pla
+        ldx     SP_save
+        txs                     ; reset stack pointer
+        tax                     ; IOCB index in X
+
+        lda     #<CMDLINE_BUFFER
+        sta     ICBAL,x         ; 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
index a4ba07c0f0f50baacd5ef8cae0e975e122fc1290..1d95dbc36bd9aec715b7c31606dd577472c5c841 100644 (file)
@@ -95,7 +95,7 @@ maptable:
         .byte   EUNKNOWN        ; 177 - haven't found documentation
         .byte   EUNKNOWN        ; 178 - haven't found documentation
         .byte   EUNKNOWN        ; 179 - haven't found documentation
-        .byte   EUNKNOWN        ; 180 - not a binary file
+        .byte   ENOEXEC         ; 180 - not a binary file
         .byte   EUNKNOWN        ; 181 - [MYDOS] invalid address range
         .byte   EUNKNOWN        ; 182 - [XDOS] invalid parameter
 
index 162dad0854c0b2f01167870d7e769eab5345b125..e6df34ad3e244062a1991ed36013182de514339d 100644 (file)
@@ -24,6 +24,7 @@ const char* const _sys_errlist[] = {
     "Illegal seek",                 /* ESPIPE */
     "Range error",                  /* ERANGE */
     "Bad file number",              /* EBADF */
+    "Exec format error",            /* ENOEXEC */
     "Unknown OS error code",        /* EUNKNOWN */
 };
 
index de57a3d0e44155d9c61dc8978e9a69f54ad4f809..b5654983ecf2f9c4ab24f0b645e3664384372211 100644 (file)
@@ -1,9 +1,9 @@
 /*
 ** Simple ("tiny") shell to test filename and directory functions.
-** Copyright (c) 2013, Christian Groessler, chris@groessler.org
+** Copyright (c) 2013,2016 Christian Groessler, chris@groessler.org
 */
 
-#define VERSION_ASC "0.90"
+#define VERSION_ASC "0.91"
 
 #ifdef __ATARI__
 #define UPPERCASE      /* define (e.g. for Atari) to convert filenames etc. to upper case */
@@ -18,7 +18,7 @@
 #define CHECK_SP
 #endif
 
-#define KEYB_BUFSZ 80
+#define KEYB_BUFSZ 127
 #define PROMPT ">>> "
 
 #include <stdio.h>
@@ -55,12 +55,14 @@ extern unsigned int getsp(void);  /* comes from getsp.s */
 #define CMD_PWD     11
 #define CMD_CLS     12
 #define CMD_VERBOSE 13
+#define CMD_EXEC    14
 
 static unsigned char verbose;
 static unsigned char terminate;
 static unsigned char cmd;
-static unsigned char *cmd_asc, *arg1, *arg2, *arg3;
-static unsigned char keyb_buf[KEYB_BUFSZ];
+static unsigned char *cmd_asc, *arg1, *arg2, *arg3, *args;  /* 'args': everything after command */
+static unsigned char keyb_buf[KEYB_BUFSZ + 1];
+static unsigned char keyb_buf2[KEYB_BUFSZ + 1];
 static size_t cpbuf_sz = 4096;
 
 struct cmd_table {
@@ -88,6 +90,7 @@ struct cmd_table {
     { "mv",    CMD_RENAME },
     { "ren",   CMD_RENAME },
     { "pwd",   CMD_PWD },
+    { "exec",  CMD_EXEC },
 #ifdef __ATARI__
     { "cls",   CMD_CLS },
 #endif
@@ -134,6 +137,17 @@ static void get_command(void)
         return;
     }
 
+    /* put everything after first string into 'args' */
+
+    strcpy(keyb_buf2, keyb_buf);  /* use a backup copy for 'args' */
+
+    /* skip over the first non-whitespace item */
+    cmd_asc = strtok(keyb_buf2, " \t\n");
+    if (cmd_asc)
+        args = strtok(NULL, "");  /* get everything */
+    else
+        *args = 0;  /* no arguments */
+
     /* split input into cmd, arg1, arg2, arg3 */
 
     /* get and parse command */
@@ -172,11 +186,11 @@ static void cmd_help(void)
     puts("cd, chdir  -  change directory or drive");
     puts("md, mkdir  -  make directory or drive");
     puts("rd, rmdir  -  remove directory or drive");
+    puts("exec       -  run program");
 #ifdef __ATARI__
     puts("cls        -  clear screen");
 #endif
     puts("verbose    -  set verbosity level");
-    puts("sorry, you cannot start programs here");
 }
 
 static void cmd_ls(void)
@@ -340,6 +354,23 @@ static void cmd_rename(void)
         printf("rename failed: %s\n", strerror(errno));
 }
 
+static void cmd_exec(void)
+{
+    int st;
+    unsigned char *progname, *arguments;
+
+    progname = strtok(args, " \t\n");
+    if (! progname) {
+        puts("usage: exec <progname> [arguments]");
+        return;
+    }
+    arguments = strtok(NULL, "");
+
+    /*printf("exec: %s %s\n", progname, arguments ? arguments : "");*/
+    st = exec(progname, arguments);
+    printf("exec error: %s\n", strerror(errno));
+}
+
 static void cmd_copy(void)
 {
     int srcfd = -1, dstfd = -1;
@@ -446,6 +477,7 @@ static void run_command(void)
         case CMD_RMDIR: cmd_rmdir(); return;
         case CMD_PWD: cmd_pwd(); return;
 #endif
+        case CMD_EXEC: cmd_exec(); return;
         case CMD_RENAME: cmd_rename(); return;
         case CMD_COPY: cmd_copy(); return;
 #ifdef __ATARI__