]> git.sur5r.net Git - cc65/commitdiff
Merge pull request #12 from greg-king5/lightpen
authorOliver Schmidt <ol.sc@web.de>
Thu, 25 Jul 2013 20:29:46 +0000 (13:29 -0700)
committerOliver Schmidt <ol.sc@web.de>
Thu, 25 Jul 2013 20:29:46 +0000 (13:29 -0700)
Added Inkwell lightpen drivers for the C64 and the C128.

16 files changed:
asminc/atari.inc
cfg/atari.cfg
cfg/atarixl.cfg
libsrc/atari/crt0.s
libsrc/atari/graphics.s
libsrc/atari/open.s
libsrc/atari/posixdirent.s
libsrc/atari/syschdir.s
libsrc/atari/sysmkdir.s
libsrc/atari/sysremove.s
libsrc/atari/sysrename.s [new file with mode: 0644]
libsrc/atari/sysrmdir.s
libsrc/atari/ucase_fn.s
src/dbginfo/dbginfo.c
src/ld65/config.c
testcode/lib/tinyshell.c [new file with mode: 0644]

index 4992807f8e046c7183c40a9d279a7d3457836700..1fff3ebae1f57a1c05705082bed0417b7ee7a229 100644 (file)
@@ -55,6 +55,7 @@ NOTE    = $26           ;note sector
 GETFL   = $27           ;get file length
 CHDIR_MYDOS     = $29   ;change directory (MyDOS)
 MKDIR   = $2A           ;make directory (MyDOS/SpartaDOS)
+RMDIR   = $2B           ;remove directory (SpartaDOS)
 CHDIR_SPDOS     = $2C   ;change directory (SpartaDOS)
 FORMAT  = $FE           ;format
 
index 975d162131422bc35925b6c2bea87ce4fffea993..a82f64f74f1d85e7f077cfa8b5fc877c5a5a764b 100644 (file)
@@ -19,7 +19,6 @@ SEGMENTS {
     CODE:     load = RAM,     type = ro,  define = yes;
     RODATA:   load = RAM,     type = ro;
     DATA:     load = RAM,     type = rw;
-    ZPSAVE:   load = RAM,     type = bss, define = yes;
     BSS:      load = RAM,     type = bss, define = yes;
     ZEROPAGE: load = ZP,      type = zp;
     EXTZP:    load = ZP,      type = zp,                optional = yes;
index 975d162131422bc35925b6c2bea87ce4fffea993..a82f64f74f1d85e7f077cfa8b5fc877c5a5a764b 100644 (file)
@@ -19,7 +19,6 @@ SEGMENTS {
     CODE:     load = RAM,     type = ro,  define = yes;
     RODATA:   load = RAM,     type = ro;
     DATA:     load = RAM,     type = rw;
-    ZPSAVE:   load = RAM,     type = bss, define = yes;
     BSS:      load = RAM,     type = bss, define = yes;
     ZEROPAGE: load = ZP,      type = zp;
     EXTZP:    load = ZP,      type = zp,                optional = yes;
index f007e64ad9b3dfdf70f0c28f1fbae1ce24fd7aa4..85a3ffcde65b2cb1a4a4bdf9c26bdca92d25ab31 100644 (file)
@@ -13,7 +13,7 @@
 
         .import         initlib, donelib
         .import         callmain, zerobss
-        .import         __STARTUP_LOAD__, __ZPSAVE_LOAD__
+        .import         __STARTUP_LOAD__, __BSS_LOAD__
         .import         __RESERVED_MEMORY__
 
         .include        "zeropage.inc"
@@ -26,7 +26,7 @@
 
         .word   $FFFF
         .word   __STARTUP_LOAD__
-        .word   __ZPSAVE_LOAD__ - 1
+        .word   __BSS_LOAD__ - 1
 
 ; ------------------------------------------------------------------------
 ; Actual code
 
 ; Real entry point:
 
-; Save the zero page locations we need
-
-        ldx     #zpspace-1
-L1:     lda     sp,x
-        sta     zpsave,x
-        dex
-        bpl     L1
-
 ; Clear the BSS data
 
         jsr     zerobss
@@ -126,17 +118,9 @@ _exit:  jsr     donelib         ; Run module destructors
         lda     appmsav+1
         sta     APPMHI+1
 
-; Copy back the zero page stuff
-
-        ldx     #zpspace-1
-L2:     lda     zpsave,x
-        sta     sp,x
-        dex
-        bpl     L2
-
 ; Turn on cursor
 
-        inx
+        ldx     #0
         stx     CRSINH
 
 ; Back to DOS
@@ -147,12 +131,6 @@ L2:     lda     zpsave,x
 
 ; ------------------------------------------------------------------------
 
-.segment        "ZPSAVE"
-
-zpsave: .res    zpspace
-
-; ------------------------------------------------------------------------
-
 .bss
 
 spsave:         .res    1
@@ -160,7 +138,8 @@ appmsav:        .res    1
 old_shflok:     .res    1
 old_lmargin:    .res    1
 
-        .segment "AUTOSTRT"
-        .word   RUNAD                   ; defined in atari.h
+
+.segment "AUTOSTRT"
+        .word   RUNAD                   ; defined in atari.inc
         .word   RUNAD+1
         .word   __STARTUP_LOAD__ + 1
index 60f2ff7898196beb53b3260b00aed3bbabc9b743..1c68562960f03e892cc190619db03e3d7934c5c2 100644 (file)
@@ -10,7 +10,7 @@
         .export __graphics
 
         .import findfreeiocb
-        .import __do_oserror,__oserror
+        .import __oserror
         .import fddecusage
         .import clriocb
         .import fdtoiocb
@@ -96,8 +96,13 @@ doopen: txa
         stx     __oserror
         rts
 
-cioerr: jsr     fddecusage      ; decrement usage counter of fd as open failed
-        jmp     __do_oserror
+cioerr: sty     tmp3            ; remember error code
+        lda     #CLOSE
+        sta     ICCOM,x
+        jsr     CIOV            ; close IOCB again since open failed
+        jsr     fddecusage      ; and decrement usage counter of fd
+        lda     tmp3            ; put error code into A
+        jmp     __mappederrno
 
 .endproc        ; __graphics
 
index 8aeff9ed4d24ba4fabe3def1ddc9d151c9686225..2188257cb17d8f404d1131516cbaadf220d5cce0 100644 (file)
@@ -91,7 +91,10 @@ cont:   ldy     #3
         jsr     ldaxysp
 
 .ifdef  UCASE_FILENAME
-
+.ifdef  DEFAULT_DEVICE
+        ldy     #$80
+        sty     tmp2            ; set flag for ucase_fn
+.endif
         jsr     ucase_fn
         bcc     ucok1
 invret: lda     #<EINVAL        ; file name is too long
@@ -140,8 +143,12 @@ finish: php
         plp
 
         bpl     ok
-        jsr     fddecusage      ; decrement usage counter of fd as open failed
-        tya                     ; put error code into A
+        sty     tmp3            ; remember error code
+        lda     #CLOSE
+        sta     ICCOM,x
+        jsr     CIOV            ; close IOCB again since open failed
+        jsr     fddecusage      ; and decrement usage counter of fd
+        lda     tmp3            ; put error code into A
         jmp     __mappederrno
 
 ok:     lda     tmp2            ; get fd
index 3417e4bfc8229f3cba4f5ef8a984c7f6f85d1ad6..a722b3b06f74a58bdd3732cc5cca714c1d7d64ba 100644 (file)
@@ -63,6 +63,9 @@
 .endproc
 
 cioerr:         sty     __oserror
+                lda     #CLOSE
+                sta     ICCOM,x
+                jsr     CIOV            ; close IOCB again since open failed
                 jmp     return0
 
 .proc   _readdir
index 16cb3a1febcc9b94046f212521cadd35a4a729ff..d577083849136996613fcba3d892765ba46c6996 100644 (file)
@@ -15,6 +15,9 @@
         .importzp tmp3
         .import addysp
         .import ucase_fn
+.ifdef  DEFAULT_DEVICE
+        .importzp tmp2
+.endif
 .endif
         .export __syschdir
 
@@ -40,6 +43,10 @@ iocbok: stx     tmp4            ; remember IOCB index
 
 .ifdef  UCASE_FILENAME
 
+.ifdef  DEFAULT_DEVICE
+        ldy     #$80
+        sty     tmp2            ; set flag for ucase_fn
+.endif
         jsr     ucase_fn
         bcc     ucok1
 
index 56a0687576d1420c712155b86c4179a61dfb766a..cc1b3e2bfb4ebd205e07724bff533001a7691138 100644 (file)
@@ -15,6 +15,9 @@
 .ifdef  UCASE_FILENAME
         .importzp tmp3
         .import ucase_fn
+.ifdef  DEFAULT_DEVICE
+        .importzp tmp2
+.endif
 .endif
         .export __sysmkdir
 
@@ -46,6 +49,10 @@ iocbok: stx     tmp4            ; remember IOCB index
 
 .ifdef  UCASE_FILENAME
 
+.ifdef  DEFAULT_DEVICE
+        ldy     #$80
+        sty     tmp2            ; set flag for ucase_fn
+.endif
         jsr     ucase_fn
         bcc     ucok1
 
index 1e7b4760f6e7b885842f70919327d39c18c10e0c..15bc19e1cb25a3073132ae894b079d72b4448812 100644 (file)
@@ -12,6 +12,9 @@
         .importzp tmp3
         .import addysp
         .import ucase_fn
+.ifdef  DEFAULT_DEVICE
+        .importzp tmp2
+.endif
 .endif
         .export __sysremove
 
@@ -37,6 +40,10 @@ iocbok: stx     tmp4            ; remember IOCB index
 
 .ifdef  UCASE_FILENAME
 
+.ifdef  DEFAULT_DEVICE
+        ldy     #$80
+        sty     tmp2            ; set flag for ucase_fn
+.endif
         jsr     ucase_fn
         bcc     ucok1
 
diff --git a/libsrc/atari/sysrename.s b/libsrc/atari/sysrename.s
new file mode 100644 (file)
index 0000000..fef18bd
--- /dev/null
@@ -0,0 +1,185 @@
+;
+; Christian Groessler, 2013-07-24
+;
+; unsigned char __fastcall__ _sysrename (const char* oldname, const char* newname);
+;
+
+        .include "atari.inc"
+        .import findfreeiocb
+        .importzp tmp4, sp, ptr2, ptr3
+        .import incsp2, subysp, addysp, popax
+.ifdef  UCASE_FILENAME
+        .importzp tmp3
+        .import ucase_fn
+.ifdef  DEFAULT_DEVICE
+        .importzp tmp2
+.endif
+.endif
+        .export __sysrename
+
+.proc   __sysrename
+
+        pha                     ; save input parameter
+        txa
+        pha
+
+        jsr     findfreeiocb
+        beq     iocbok          ; we found one
+
+        pla
+        pla                     ; fix up stack
+        jsr     incsp2
+
+        lda     #TMOF           ; too many open files
+        rts
+
+iocbok: stx     tmp4            ; remember IOCB index
+
+        pla
+        sta     ptr2+1          ; remember newname
+        pla
+        sta     ptr2            ; ditto.
+
+        jsr     popax           ; get oldname
+
+        ldy     #0
+        sty     sspc+1          ; initialize stack space
+
+.ifndef  UCASE_FILENAME
+
+        sta     ptr3
+        stx     ptr3+1
+        sty     sspc
+
+.else
+
+; uppercase first (old) name and prepend device if needed
+
+.ifdef  DEFAULT_DEVICE
+        ldy     #$80
+        sty     tmp2            ; set flag for ucase_fn
+.endif
+        jsr     ucase_fn
+        bcc     ucok1
+
+        lda     #183            ; see oserror.s
+        rts
+
+ucok1:  sta     ptr3
+        stx     ptr3+1          ; remember pointer to uppercased old name
+        lda     tmp3            ; # of bytes reserved on the stack
+        sta     sspc            ; remember...
+
+; uppercase second (new) name and don't prepend device
+
+.ifdef  DEFAULT_DEVICE
+        ldy     #0
+        sty     tmp2            ; set flag for ucase_fn
+.endif
+        lda     ptr2
+        ldx     ptr2+1
+
+        jsr     ucase_fn
+        bcc     ucok2
+
+        ldy     tmp3            ; get size
+        jsr     addysp          ; free used space on the stack
+        lda     #183            ; see oserror.s
+        rts
+
+ucok2:  sta     ptr2            ; remember pointer to uppercased new name
+        stx     ptr2+1
+
+; update sspc -- # of bytes used on the stack
+
+        lda     sspc
+        clc
+        adc     tmp3
+        sta     sspc
+        bcc     ukok4
+        inc     sspc+1
+ukok4:
+
+.endif
+
+; create a string on the stack with the old filename and the new filename separated by an invalid character (space in our case)
+; ptr2 - pointer to new name
+; ptr3 - pointer to old name
+
+        lda     #128
+        tay
+        clc
+        adc     sspc
+        sta     sspc
+        bcc     L1
+        inc     sspc+1
+L1:     jsr     subysp          ; make room on the stack
+
+; copy old name
+        ldy     #0
+con:    lda     (ptr3),y
+        sta     (sp),y
+        beq     copyend
+        iny
+        bne     con
+
+copyend:lda     #$20            ; space
+        sta     (sp),y
+        iny
+        tya                     ; get current offset (beyond old name)
+        clc
+        adc     sp
+        sta     ptr3
+        lda     sp+1
+        adc     #0
+        sta     ptr3+1          ; ptr3 now contains pointer to space for new filename
+
+; copy new name
+        ldy     #0
+cnn:    lda     (ptr2),y
+        sta     (ptr3),y
+        beq     copend2
+        iny
+        bne     cnn
+
+copend2:ldx     tmp4
+        lda     sp
+        sta     ICBAL,x
+        lda     sp+1
+        sta     ICBAH,x
+        lda     #RENAME
+        sta     ICCOM,x
+        lda     #0
+        sta     ICAX1,x
+        sta     ICAX2,x
+        sta     ICBLL,x
+        sta     ICBLH,x
+        jsr     CIOV
+        tya
+        pha
+
+; clean up stack
+
+        lda     sp
+        clc
+        adc     sspc
+        sta     sp
+        lda     sp+1
+        adc     sspc+1
+        sta     sp+1
+
+; handle status
+
+        pla
+        tay
+        bmi     cioerr
+        lda     #0
+        rts
+cioerr: tya
+        rts
+
+.endproc        ; __sysrename
+
+        .bss
+
+sspc:   .res    2               ; stack space used
index 9c057ba44ea7b8a98f38e5f17104a6cc00041d52..126c11cca2cc1200f66049a7bfd603d982a38d23 100644 (file)
 ;
 ; Stefan Haubenthal, 2005-12-24
+; Christian Groessler, 2013-07-16
 ;
 ; unsigned char __fastcall__ _sysrmdir (const char* name);
+;
+; for SpartaDOS and MyDOS
 ;
 
+        .include        "atari.inc"
+        .include        "errno.inc"
         .export         __sysrmdir
         .import         __sysremove
+        .import         __dos_type
+        .import         findfreeiocb
+        .importzp       tmp4
+.ifdef  UCASE_FILENAME
+        .import         ucase_fn
+        .import         addysp
+        .importzp       sreg
+        .importzp       tmp3
+.ifdef  DEFAULT_DEVICE
+        .importzp tmp2
+.endif
+.endif
+
+.proc   __sysrmdir
+
+        pha
+        lda     __dos_type
+        beq     not_impl                ; AtariDOS
+        cmp     #OSADOS+1
+        bcc     do_sparta               ; OS/A and SpartaDOS
+        pla
+        jmp     __sysremove             ; MyDOS and others (TODO: check XDOS)
+
+not_impl:
+        pla
+        lda     #NVALID
+        rts
+
+iocberr:
+        pla                             ; cleanup stack
+        pla
+        lda     #TMOF
+        rts
+
+do_sparta:
+        txa
+        pha
+        jsr     findfreeiocb
+        bne     iocberr                 ; no IOCB available
+
+        stx     tmp4                    ; remember IOCB
+        pla
+        tax
+        pla
+
+.ifdef  UCASE_FILENAME
+
+.ifdef  DEFAULT_DEVICE
+        ldy     #$80
+        sty     tmp2            ; set flag for ucase_fn
+.endif
+        jsr     ucase_fn
+        bcc     ucok1
+
+        lda     #183                    ; see oserror.s
+        rts
+ucok1:
+
+.endif  ; defined UCASE_FILENAME
+
+        ldy     tmp4                    ; IOCB index
+        sta     ICBAL,y                 ; store pointer to filename
+        txa
+        sta     ICBAH,y
+        tya
+        tax
+        lda     #RMDIR
+        sta     ICCOM,x
+        lda     #0
+        sta     ICAX1,x
+        lda     #0
+        sta     ICAX2,x
+        sta     ICBLL,x
+        sta     ICBLH,x
+        jsr     CIOV
+
+.ifdef  UCASE_FILENAME
+        tya
+        pha
+        ldy     tmp3                    ; get size
+        jsr     addysp                  ; free used space on the stack
+        pla
+        tay
+.endif  ; defined UCASE_FILENAME
+
+        bmi     cioerr
+        lda     #0
+        rts
+
+cioerr: tya
+        rts
 
-__sysrmdir := __sysremove
+.endproc        ; __sysrmdir
index a32ddce23dbd0dc824b80b0f2afe5b0c1ff9cb1b..e53750e2997a850473b107ee324a91b88d343956 100644 (file)
@@ -7,6 +7,8 @@
 ;
 ; Calling parameters:
 ;       AX   - points to filename
+;       tmp2 - 0/$80 for don't/do prepend default device if no device
+;              is present in the passed string (only .ifdef DEFAULT_DEVICE)
 ; Return parameters:
 ;       C    - 0/1 for OK/Error (filename too long)
 ;       AX   - points to uppercased version of the filename on the stack
         stx     ptr4+1
 
 .ifdef  DEFAULT_DEVICE
+        ; bit #0 of tmp2 is used as a flag whether device name is present in passed string (1 = present, 0 = not present)
         ldy     #1
-        sty     tmp2            ; initialize flag: device present in passed string
+        inc     tmp2            ; initialize flag: device present
         lda     #':'
         cmp     (ptr4),y
         beq     hasdev
         iny
         cmp     (ptr4),y
         beq     hasdev
-        sta     tmp2            ; set flag: no device in passed string
+        dec     tmp2            ; set flag: no device in passed string
 hasdev:
 .endif
 
@@ -54,7 +57,7 @@ hasdev:
         sty     tmp3            ; save size
         jsr     subysp          ; make room on the stack
 
-        ; copy filename to the temp. place on the stack, also uppercasing it
+        ; copy filename to the temp. place on the stack, while uppercasing it
         ldy     #0
 
 loop2:  lda     (ptr4),y
@@ -77,9 +80,10 @@ L1:
 copy_end:
 
 .ifdef  DEFAULT_DEVICE
-        lda     tmp2
-        cmp     #1              ; was device present in passed string?
-        beq     hasdev2         ; yes, don't prepend something
+        lda     #1
+        bit     tmp2
+        bne     hasdev2         ; yes, don't prepend something
+        bpl     hasdev2
 
         ldy     #128+3          ; no, prepend "D:" (or other device)
         sty     tmp3            ; adjust stack size used
index 16bc9d9de44eef177bb3316cb7acf0d82ca31975..05951f6c6444a896c6bd1be23bf1db5a790b9a98 100644 (file)
@@ -2933,7 +2933,7 @@ static void ParseCSym (InputData* D)
     }
 
     /* Symbol only valid if storage class not auto */
-    if (((InfoBits & ibSymId) != 0) != (SC != CC65_CSYM_AUTO)) {
+    if (((InfoBits & ibSymId) != 0) && (SC == CC65_CSYM_AUTO)) {
         ParseError (D, CC65_ERROR, "Only non auto symbols can have a symbol attached");
         goto ErrorExit;
     }
index 76518cafdf5957a6205f80116dfa95d2bf4d9fcb..a5d6ff39ba53ecbc6ecde46b5ed228584e529ced 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2012, Ullrich von Bassewitz                                      */
+/* (c) 1998-2013, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
@@ -1959,8 +1959,11 @@ unsigned CfgProcess (void)
             /* Calculate the new address */
             Addr += S->Seg->Size;
 
-            /* If this segment goes out to the file, increase the file size */
-            if ((S->Flags & SF_BSS) == 0 && S->Load == M) {
+            /* If this segment will go out to the file, or its place
+             * in the file will be filled, then increase the file size.
+             */
+            if (S->Load == M &&
+                ((S->Flags & SF_BSS) == 0 || (M->Flags & MF_FILL) != 0)) {
                 M->F->Size += Addr - StartAddr;
             }
 
diff --git a/testcode/lib/tinyshell.c b/testcode/lib/tinyshell.c
new file mode 100644 (file)
index 0000000..f4a1812
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * Simple ("tiny") shell to test filename and directory functions.
+ * Copyright (c) 2013, Christian Groessler, chris@groessler.org
+ */
+
+#define VERSION_ASC "0.90"
+
+#define KEYB_BUFSZ 80
+#define PROMPT ">>> "
+#ifdef __ATARI__
+#define UPPERCASE      /* define (e.g. for Atari) to convert filenames etc. to upper case */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#ifndef __CC65__
+#include <sys/stat.h>
+#include <sys/param.h>
+#else
+#define MAXPATHLEN 64
+#endif
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#define CMD_NOTHING 0
+#define CMD_INVALID 1
+#define CMD_HELP    2
+#define CMD_QUIT    3
+#define CMD_LS      4
+#define CMD_MKDIR   5
+#define CMD_RMDIR   6
+#define CMD_CHDIR   7
+#define CMD_RM      8
+#define CMD_RENAME  9
+#define CMD_COPY    10
+#define CMD_PWD     11
+
+static unsigned char terminate;
+static unsigned char cmd;
+static unsigned char *cmd_asc, *arg1, *arg2, *arg3;
+static unsigned char keyb_buf[KEYB_BUFSZ];
+static size_t cpbuf_sz = 4096;
+
+struct cmd_table {
+    unsigned char *name;
+    unsigned char code;
+} cmd_table[] = {
+    { "help",  CMD_HELP },
+    { "quit",  CMD_QUIT },
+    { "q",     CMD_QUIT },
+    { "exit",  CMD_QUIT },
+    { "ls",    CMD_LS },
+    { "dir",   CMD_LS },
+    { "md",    CMD_MKDIR },
+    { "mkdir", CMD_MKDIR },
+    { "rd",    CMD_RMDIR },
+    { "rmdir", CMD_RMDIR },
+    { "cd",    CMD_CHDIR },
+    { "chdir", CMD_CHDIR },
+    { "rm",    CMD_RM },
+    { "del",   CMD_RM },
+    { "cp",    CMD_COPY },
+    { "copy",  CMD_COPY },
+    { "mv",    CMD_RENAME },
+    { "ren",   CMD_RENAME },
+    { "pwd",   CMD_PWD },
+    { NULL, 0 }
+};
+
+static void banner(void)
+{
+    puts("\"tiny\" command line shell, v" VERSION_ASC);
+    puts("written by chris@groessler.org");
+    puts("type 'help' for help\n");
+}
+
+static void get_command(void)
+{
+    unsigned char i = 0;
+
+    arg1 = arg2 = arg3 = NULL;
+
+    /* issue prompt */
+    printf(PROMPT);
+
+    /* get input from the user */
+    if (! fgets(keyb_buf, KEYB_BUFSZ, stdin)) {
+        puts("");
+        cmd = CMD_QUIT;
+        return;
+    }
+
+    /* split input into cmd, arg1, arg2, arg3 */
+
+    /* get and parse command */
+    cmd_asc = strtok(keyb_buf, " \t\n");
+    if (! cmd_asc) {
+        cmd = CMD_NOTHING;
+        return;
+    }
+    cmd = CMD_INVALID;
+    while (cmd_table[i].name) {
+        if (! strcmp(cmd_table[i].name, cmd_asc)) {
+            cmd = cmd_table[i].code;
+            break;
+        }
+        i++;
+    }
+
+    /* get arguments */
+    arg1 = strtok(NULL, " \t\n");
+    if (! arg1)
+        return;
+    arg2 = strtok(NULL, " \t\n");
+    if (! arg2)
+        return;
+    arg3 = strtok(NULL, " \t\n");
+}
+
+static void cmd_help(void)
+{
+    puts("quit, exit -  exit shell");
+    puts("ls, dir    -  display current directory");
+    puts("              and drive contents");
+    puts("rm, del    -  delete file");
+    puts("cp, copy   -  copy file");
+    puts("mv, ren    -  rename file");
+    puts("cd, chdir  -  change directory or drive");
+    puts("md, mkdir  -  make directory or drive");
+    puts("rd, rmdir  -  remove directory or drive");
+    puts("sorry, you cannot start programs here");
+}
+
+static void cmd_ls(void)
+{
+    DIR *dir;
+    unsigned char *arg;
+    struct dirent *dirent;
+#ifdef __ATARI__
+    char need_free = 0;
+#endif
+
+    if (arg2) {
+        puts("usage: ls [dir]");
+        return;
+    }
+
+    /* print directory listing */
+    if (arg1) {
+#ifdef UPPERCASE
+        strupr(arg1);
+#endif
+#ifdef __ATARI__
+        /* not sure if this shouldn't be done by the runtime lib */
+        if (*(arg1 + strlen(arg1) - 1) == ':' || *(arg1 + strlen(arg1) - 1) == '>') {
+            arg = malloc(strlen(arg1) + 4);
+            if (! arg) {
+                printf("malloc failed: %s", strerror(errno));
+                return;
+            }
+            need_free = 1;
+            memcpy(arg, arg1, strlen(arg1) + 1);
+            strcat(arg, "*.*");
+        }
+        else
+#endif
+            arg = arg1;
+    }
+    else
+        arg = ".";
+
+    dir = opendir(arg);
+#ifdef __ATARI__
+    if (need_free) free(arg);
+#endif
+    if (! dir) {
+        puts("opendir failed");
+        return;
+    }
+
+    while (dirent = readdir(dir))
+        puts(dirent->d_name);
+
+    closedir(dir);
+}
+
+static void cmd_rm(void)
+{
+    if (!arg1 || arg2) {
+        puts("usage: rm <file>");
+        return;
+    }
+
+#ifdef UPPERCASE
+    strupr(arg1);
+#endif
+
+    if (unlink(arg1))
+        printf("remove failed: %s\n", strerror(errno));
+}
+
+static void cmd_mkdir(void)
+{
+    if (!arg1 || arg2) {
+        puts("usage: mkdir <dir>");
+        return;
+    }
+
+#ifdef UPPERCASE
+    strupr(arg1);
+#endif
+
+    if (mkdir(arg1, 0777))
+        printf("mkdir failed: %s\n", strerror(errno));
+}
+
+static void cmd_rmdir(void)
+{
+    if (!arg1 || arg2) {
+        puts("usage: rmdir <dir>");
+        return;
+    }
+
+#ifdef UPPERCASE
+    strupr(arg1);
+#endif
+
+    if (rmdir(arg1))
+        printf("rmdir failed: %s\n", strerror(errno));
+}
+
+static void cmd_chdir(void)
+{
+    if (!arg1 || arg2) {
+        puts("usage: cddir <dir>");
+        return;
+    }
+
+#ifdef UPPERCASE
+    strupr(arg1);
+#endif
+
+    if (chdir(arg1))
+        printf("chdir failed: %s\n", strerror(errno));
+}
+
+static void cmd_pwd(void)
+{
+    char *buf;
+
+    if (arg1) {
+        puts("usage: pwd");
+        return;
+    }
+
+    buf = malloc(MAXPATHLEN);
+    if (! buf) {
+        printf("malloc %u bytes failed: %s\n", MAXPATHLEN, strerror(errno));
+        return;
+    }
+    if (!getcwd(buf, MAXPATHLEN)) {
+        printf("getcwd failed: %s\n", strerror(errno));
+        free(buf);
+        return;
+    }
+
+    puts(buf);
+    free(buf);
+}
+
+static void cmd_rename(void)
+{
+    if (!arg2 || arg3) {
+        puts("usage: mv <oldname> <newname>");
+        return;
+    }
+
+#ifdef UPPERCASE
+    strupr(arg1);
+    strupr(arg2);
+#endif
+
+    if (rename(arg1, arg2))
+        printf("rename failed: %s\n", strerror(errno));
+}
+
+static void cmd_copy(void)
+{
+    int srcfd = -1, dstfd = -1;
+    unsigned char *buf;
+    int readsz, writesz;
+
+    if (!arg2 || arg3) {
+        puts("usage: cp <src> <dest>");
+        return;
+    }
+
+#ifdef UPPERCASE
+    strupr(arg1);
+    strupr(arg2);
+#endif
+
+    buf = malloc(cpbuf_sz);
+    if (! buf) {
+        printf("malloc %u bytes failed: %s\n", cpbuf_sz, strerror(errno));
+        return;
+    }
+
+    while (1) {
+        if (srcfd == -1) {
+            srcfd = open(arg1, O_RDONLY);
+            if (srcfd < 0) {
+                printf("open(%s) failed: %s\n", arg1, strerror(errno));
+                break;
+            }
+        }
+
+        readsz = read(srcfd, buf, cpbuf_sz);
+        if (readsz < 0) {
+            printf("read error: %s\n", strerror(errno));
+            break;
+        }
+        if (! readsz)
+            break;
+
+        if (dstfd == -1) {
+            dstfd = open(arg2, O_WRONLY | O_CREAT | O_TRUNC, 0777);
+            if (dstfd < 0) {
+                printf("open(%s) failed: %s\n", arg2, strerror(errno));
+                break;
+            }
+        }
+
+        writesz = write(dstfd, buf, readsz);
+        if (writesz < 0 || writesz != readsz) {
+            printf("write error: %s\n", strerror(errno));
+            break;
+        }
+        if (readsz != cpbuf_sz)
+            break;
+    }
+
+    free(buf);
+    if (srcfd >= 0) close(srcfd);
+    if (dstfd >= 0) close(dstfd);
+}
+
+static void run_command(void)
+{
+    switch (cmd) {
+        default: puts("internal error"); return;
+        case CMD_NOTHING: return;
+        case CMD_INVALID: puts("invalid command"); return;
+        case CMD_HELP: cmd_help(); return;
+        case CMD_QUIT: terminate = 1; return;
+        case CMD_LS: cmd_ls(); return;
+        case CMD_RM: cmd_rm(); return;
+        case CMD_CHDIR: cmd_chdir(); return;
+        case CMD_MKDIR: cmd_mkdir(); return;
+        case CMD_RMDIR: cmd_rmdir(); return;
+        case CMD_PWD: cmd_pwd(); return;
+        case CMD_RENAME: cmd_rename(); return;
+        case CMD_COPY: cmd_copy(); return;
+    }
+}
+
+int main(void)
+{
+    banner();
+
+    while (! terminate) {
+        get_command();
+        run_command();
+    }
+    return 0;
+}
+
+/* Local Variables: */
+/* c-file-style: "cpg" */
+/* c-basic-offset: 4 */
+/* End: */