mirror of
https://github.com/cc65/cc65.git
synced 2025-01-10 19:29:45 +00:00
Merge pull request #310 from groessler/atari-exec-devel
Implement exec() for Atari XDOS.
This commit is contained in:
commit
d8dfc29297
@ -183,6 +183,7 @@ FNTFND = 170 ;($AA) file not found
|
|||||||
PNTINV = 171 ;($AB) point invalid
|
PNTINV = 171 ;($AB) point invalid
|
||||||
BADDSK = 173 ;($AD) bad disk
|
BADDSK = 173 ;($AD) bad disk
|
||||||
INCFMT = 176 ;($B0) DOS 3: incompatible file system
|
INCFMT = 176 ;($B0) DOS 3: incompatible file system
|
||||||
|
XNTBIN = 180 ;($B4) XDOS: file not binary
|
||||||
|
|
||||||
; DCB Device Bus Equates
|
; DCB Device Bus Equates
|
||||||
|
|
||||||
@ -889,6 +890,10 @@ SETVBV_org = $E45C ;vector to set VBLANK parameters
|
|||||||
CIOV = $E456 ;vector to CIO
|
CIOV = $E456 ;vector to CIO
|
||||||
SIOV = $E459 ;vector to SIO
|
SIOV = $E459 ;vector to SIO
|
||||||
SETVBV = $E45C ;vector to set VBLANK parameters
|
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
|
.endif
|
||||||
SYSVBV = $E45F ;vector to process immediate VBLANK
|
SYSVBV = $E45F ;vector to process immediate VBLANK
|
||||||
XITVBV = $E462 ;vector to process deferred VBLANK
|
XITVBV = $E462 ;vector to process deferred VBLANK
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
ESPIPE ; Illegal seek
|
ESPIPE ; Illegal seek
|
||||||
ERANGE ; Range error
|
ERANGE ; Range error
|
||||||
EBADF ; Bad file number
|
EBADF ; Bad file number
|
||||||
|
ENOEXEC ; Exec format error
|
||||||
EUNKNOWN ; Unknown OS specific error - must be last!
|
EUNKNOWN ; Unknown OS specific error - must be last!
|
||||||
|
|
||||||
EMAX = EUNKNOWN ; Highest error code
|
EMAX = EUNKNOWN ; Highest error code
|
||||||
|
@ -72,7 +72,8 @@ extern int _errno;
|
|||||||
#define ESPIPE 14 /* Illegal seek */
|
#define ESPIPE 14 /* Illegal seek */
|
||||||
#define ERANGE 15 /* Range error */
|
#define ERANGE 15 /* Range error */
|
||||||
#define EBADF 16 /* Bad file number */
|
#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 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ ErrTab: .byte $01, ENOSYS ; Bad system call number
|
|||||||
.byte $47, EEXIST ; Duplicate filename
|
.byte $47, EEXIST ; Duplicate filename
|
||||||
.byte $48, ENOSPC ; Volume full
|
.byte $48, ENOSPC ; Volume full
|
||||||
.byte $49, ENOSPC ; Volume directory 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 $4B, EINVAL ; Unsupported storage_type
|
||||||
; .byte $4C, EUNKNOWN ; End of file encountered
|
; .byte $4C, EUNKNOWN ; End of file encountered
|
||||||
.byte $4D, ESPIPE ; Position out of range
|
.byte $4D, ESPIPE ; Position out of range
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
;
|
;
|
||||||
|
|
||||||
.export __STARTUP__ : absolute = 1 ; Mark as startup
|
.export __STARTUP__ : absolute = 1 ; Mark as startup
|
||||||
.export _exit, start
|
.export _exit, start, excexit, SP_save
|
||||||
|
|
||||||
.import initlib, donelib
|
.import initlib, donelib
|
||||||
.import callmain, zerobss
|
.import callmain, zerobss
|
||||||
@ -109,12 +109,12 @@ start:
|
|||||||
|
|
||||||
; Call the module destructors. This is also the exit() entry.
|
; 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.
|
; Restore the system stuff.
|
||||||
|
|
||||||
ldx SP_save
|
excexit:jsr donelib ; Run module destructors; 'excexit' is called from the exec routine
|
||||||
txs ; Restore stack pointer
|
|
||||||
|
|
||||||
; Restore the left margin.
|
; Restore the left margin.
|
||||||
|
|
||||||
|
205
libsrc/atari/exec.s
Normal file
205
libsrc/atari/exec.s
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
;
|
||||||
|
; 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: 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
|
||||||
|
|
||||||
|
; 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
|
@ -95,7 +95,7 @@ maptable:
|
|||||||
.byte EUNKNOWN ; 177 - haven't found documentation
|
.byte EUNKNOWN ; 177 - haven't found documentation
|
||||||
.byte EUNKNOWN ; 178 - haven't found documentation
|
.byte EUNKNOWN ; 178 - haven't found documentation
|
||||||
.byte EUNKNOWN ; 179 - 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 ; 181 - [MYDOS] invalid address range
|
||||||
.byte EUNKNOWN ; 182 - [XDOS] invalid parameter
|
.byte EUNKNOWN ; 182 - [XDOS] invalid parameter
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ const char* const _sys_errlist[] = {
|
|||||||
"Illegal seek", /* ESPIPE */
|
"Illegal seek", /* ESPIPE */
|
||||||
"Range error", /* ERANGE */
|
"Range error", /* ERANGE */
|
||||||
"Bad file number", /* EBADF */
|
"Bad file number", /* EBADF */
|
||||||
|
"Exec format error", /* ENOEXEC */
|
||||||
"Unknown OS error code", /* EUNKNOWN */
|
"Unknown OS error code", /* EUNKNOWN */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
** Simple ("tiny") shell to test filename and directory functions.
|
** 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__
|
#ifdef __ATARI__
|
||||||
#define UPPERCASE /* define (e.g. for Atari) to convert filenames etc. to upper case */
|
#define UPPERCASE /* define (e.g. for Atari) to convert filenames etc. to upper case */
|
||||||
@ -18,7 +18,7 @@
|
|||||||
#define CHECK_SP
|
#define CHECK_SP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define KEYB_BUFSZ 80
|
#define KEYB_BUFSZ 127
|
||||||
#define PROMPT ">>> "
|
#define PROMPT ">>> "
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -55,12 +55,14 @@ extern unsigned int getsp(void); /* comes from getsp.s */
|
|||||||
#define CMD_PWD 11
|
#define CMD_PWD 11
|
||||||
#define CMD_CLS 12
|
#define CMD_CLS 12
|
||||||
#define CMD_VERBOSE 13
|
#define CMD_VERBOSE 13
|
||||||
|
#define CMD_EXEC 14
|
||||||
|
|
||||||
static unsigned char verbose;
|
static unsigned char verbose;
|
||||||
static unsigned char terminate;
|
static unsigned char terminate;
|
||||||
static unsigned char cmd;
|
static unsigned char cmd;
|
||||||
static unsigned char *cmd_asc, *arg1, *arg2, *arg3;
|
static unsigned char *cmd_asc, *arg1, *arg2, *arg3, *args; /* 'args': everything after command */
|
||||||
static unsigned char keyb_buf[KEYB_BUFSZ];
|
static unsigned char keyb_buf[KEYB_BUFSZ + 1];
|
||||||
|
static unsigned char keyb_buf2[KEYB_BUFSZ + 1];
|
||||||
static size_t cpbuf_sz = 4096;
|
static size_t cpbuf_sz = 4096;
|
||||||
|
|
||||||
struct cmd_table {
|
struct cmd_table {
|
||||||
@ -88,6 +90,7 @@ struct cmd_table {
|
|||||||
{ "mv", CMD_RENAME },
|
{ "mv", CMD_RENAME },
|
||||||
{ "ren", CMD_RENAME },
|
{ "ren", CMD_RENAME },
|
||||||
{ "pwd", CMD_PWD },
|
{ "pwd", CMD_PWD },
|
||||||
|
{ "exec", CMD_EXEC },
|
||||||
#ifdef __ATARI__
|
#ifdef __ATARI__
|
||||||
{ "cls", CMD_CLS },
|
{ "cls", CMD_CLS },
|
||||||
#endif
|
#endif
|
||||||
@ -134,6 +137,17 @@ static void get_command(void)
|
|||||||
return;
|
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 */
|
/* split input into cmd, arg1, arg2, arg3 */
|
||||||
|
|
||||||
/* get and parse command */
|
/* get and parse command */
|
||||||
@ -172,11 +186,11 @@ static void cmd_help(void)
|
|||||||
puts("cd, chdir - change directory or drive");
|
puts("cd, chdir - change directory or drive");
|
||||||
puts("md, mkdir - make directory or drive");
|
puts("md, mkdir - make directory or drive");
|
||||||
puts("rd, rmdir - remove directory or drive");
|
puts("rd, rmdir - remove directory or drive");
|
||||||
|
puts("exec - run program");
|
||||||
#ifdef __ATARI__
|
#ifdef __ATARI__
|
||||||
puts("cls - clear screen");
|
puts("cls - clear screen");
|
||||||
#endif
|
#endif
|
||||||
puts("verbose - set verbosity level");
|
puts("verbose - set verbosity level");
|
||||||
puts("sorry, you cannot start programs here");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cmd_ls(void)
|
static void cmd_ls(void)
|
||||||
@ -340,6 +354,22 @@ static void cmd_rename(void)
|
|||||||
printf("rename failed: %s\n", strerror(errno));
|
printf("rename failed: %s\n", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cmd_exec(void)
|
||||||
|
{
|
||||||
|
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 : "");*/
|
||||||
|
(void)exec(progname, arguments);
|
||||||
|
printf("exec error: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
static void cmd_copy(void)
|
static void cmd_copy(void)
|
||||||
{
|
{
|
||||||
int srcfd = -1, dstfd = -1;
|
int srcfd = -1, dstfd = -1;
|
||||||
@ -446,6 +476,7 @@ static void run_command(void)
|
|||||||
case CMD_RMDIR: cmd_rmdir(); return;
|
case CMD_RMDIR: cmd_rmdir(); return;
|
||||||
case CMD_PWD: cmd_pwd(); return;
|
case CMD_PWD: cmd_pwd(); return;
|
||||||
#endif
|
#endif
|
||||||
|
case CMD_EXEC: cmd_exec(); return;
|
||||||
case CMD_RENAME: cmd_rename(); return;
|
case CMD_RENAME: cmd_rename(); return;
|
||||||
case CMD_COPY: cmd_copy(); return;
|
case CMD_COPY: cmd_copy(); return;
|
||||||
#ifdef __ATARI__
|
#ifdef __ATARI__
|
||||||
|
Loading…
x
Reference in New Issue
Block a user