diff --git a/Makefile b/Makefile index a4c1c40..96c529b 100644 --- a/Makefile +++ b/Makefile @@ -1,30 +1,44 @@ -# Compiles with https://www.brutaldeluxe.fr/products/crossdevtools/merlin/ -# -ifeq ($(OS),Windows_NT) - MERLIN_DIR=C:/opt/Merlin32_v1.0 - MERLIN_LIB=$(MERLIN_DIR)/Library - MERLIN=$(MERLIN_DIR)/Windows/Merlin32 - RM=del /s -else - MERLIN_DIR=$(HOME)/opt/Merlin32_v1.0 - MERLIN_LIB=$(MERLIN_DIR)/Library - MERLIN=$(MERLIN_DIR)/Linux64/Merlin32 - RM=rm -f +# Builds copy command + +# Requirements: +# 1. Gmake must be used. +# 2. The cc65 compiler must be properly setup. + +ifndef CC65_TARGET + CC65_TARGET:=apple2enh endif -AC=java -jar AppleCommander-ac-1.4.0.jar -SRC=copy.s +CC=cl65 +AS=ca65 +OBJS=copy.o cui.o fileinfo.o prodos.o +HDRS=fileinfo.h cui.h prodos.h +CFLAGS=-O -t $(CC65_TARGET) -DTRACE +# The -S $6000 makes the start address $6000 so that both hi-res +# pages are available. +LDFLAGS=-t $(CC65_TARGET) PGM=copy -VOL=$(PGM) -DSK=$(PGM).dsk +DISK_VOL=$(PGM) +DISK=$(PGM).dsk +AC=java -jar AppleCommander-ac-1.4.0.jar -$(DSK): $(PGM) - $(AC) -pro140 $(DSK) $(VOL) - $(AC) -p $(DSK) $(PGM) SYS < $(PGM) +# Extra stuff +BASIC_AUX_TYPE=0x0801 +READ_TIME_LOAD_ADDR=0x0260 +SYS_LOAD_ADDR=0x2000 +BIN_LOAD_ADDR=0x0803 -$(PGM): $(SRC) - $(MERLIN) $(MERLIN_LIB) $(SRC) +######################################## + +all: $(DISK) + +$(DISK): $(PGM) + $(RM) $(DISK) + $(AC) -pro140 $(DISK) $(DISK_VOL) + $(AC) -as $(DISK) $(PGM) BIN < $(PGM) + +$(PGM): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ clean: - $(RM) $(DSK) $(PGM) + $(RM) *.o $(PGM) $(DISK) diff --git a/copy.c b/copy.c new file mode 100644 index 0000000..0c6a554 --- /dev/null +++ b/copy.c @@ -0,0 +1,24 @@ +#include +#include + +#include "fileinfo.h" +#include "prodos.h" +#include "cui.h" + +char sourceName[PRODOS_PATH_MAX + 1]; +char destName[PRODOS_PATH_MAX + 1]; +FILE *sourceFile; +FILE *destFile; +struct FileInfo sourceInfo; +struct FileInfo destInfo; + +void main(void) +{ + inputFileName("Source file or directory:", sourceName, sizeof(sourceName), &sourceInfo); + inputFileName("Destination file or directory:", destName, sizeof(destName), &destInfo); + + sourceFile = fopen(sourceName, "r"); + destFile = fopen(destName, "r"); +} + + diff --git a/cui.c b/cui.c new file mode 100644 index 0000000..516cf44 --- /dev/null +++ b/cui.c @@ -0,0 +1,55 @@ +#include +#include +#include /* strlen */ + +#include "cui.h" +#include "fileinfo.h" + +static char *readLine(char *line, size_t capacity); +static void chomp(char *line); +static bool complete; + +void inputFileName(const char *prompt, char *name, size_t capacity, struct FileInfo *f) +{ + complete = false; + + while (! complete) { + printf(prompt); + readLine(name, capacity); + initFileInfo(f, name); + if (exists(f)) { + complete = true; + } + else { + fprintf(stderr, "File '%s' does not exist\n", name); + } + } +} + +char *readLine(char *line, size_t capacity) +{ + char *result; + + if ((result = fgets(line, capacity, stdin)) != NULL) + chomp(line); + else + if (ferror(stdin)) + perror("stdin"); + + return result; +} + +void chomp(char *line) +{ + size_t i; + char c; + + for (i = strlen(line); i > 0; ) { + c = line[--i]; + if (c == '\r' || c == '\n') + line[i] = '\0'; + else + break; + } +} + diff --git a/cui.h b/cui.h new file mode 100644 index 0000000..bce173b --- /dev/null +++ b/cui.h @@ -0,0 +1,7 @@ +#ifndef CUI_H +#define CUI_H + +extern void inputFileName(const char *prompt, char *name, size_t capacity, struct FileInfo *f); + +#endif + diff --git a/fileinfo.c b/fileinfo.c new file mode 100644 index 0000000..da2a319 --- /dev/null +++ b/fileinfo.c @@ -0,0 +1,27 @@ +#include /* PRODOS_T_DIR */ +#include "fileinfo.h" +#include "prodos.h" + +static struct GetFileInfoParams *infoParams; + +void initFileInfo(struct FileInfo *f, const char *name) +{ + infoParams = &(f->infoParams); + infoParams->param_count = GET_FILE_INFO_PARAM_COUNT; + infoParams->pathname = name; + f->getFileInfoResult = get_file_info(infoParams); +} + +bool isDir(struct FileInfo *f) +{ + return f->infoParams.file_type == PRODOS_T_DIR; +} + +bool exists(struct FileInfo *f) +{ + if (f->getFileInfoResult == 0) + return true; + else + return false; +} + diff --git a/fileinfo.h b/fileinfo.h new file mode 100644 index 0000000..0db63d7 --- /dev/null +++ b/fileinfo.h @@ -0,0 +1,18 @@ +#ifndef MY_FILE_H +#define MY_FILE_H + +#include +#include "prodos.h" + +struct FileInfo +{ + struct GetFileInfoParams infoParams; + uint8_t getFileInfoResult; +}; + +extern void initFileInfo(struct FileInfo *f, const char *name); +extern bool isDir(struct FileInfo *f); +extern bool exists(struct FileInfo *f); + +#endif + diff --git a/Makefile.onl b/old/Makefile.onl similarity index 100% rename from Makefile.onl rename to old/Makefile.onl diff --git a/copy.s b/old/copy.s similarity index 100% rename from copy.s rename to old/copy.s diff --git a/errorhandler.s b/old/errorhandler.s similarity index 100% rename from errorhandler.s rename to old/errorhandler.s diff --git a/onlinesys.s b/old/mli-online.s similarity index 100% rename from onlinesys.s rename to old/mli-online.s diff --git a/online.c b/old/online2.c similarity index 97% rename from online.c rename to old/online2.c index 0e556f3..8cacd42 100644 --- a/online.c +++ b/old/online2.c @@ -22,6 +22,7 @@ void online(void) arguments.unitNumber = 0; // All units arguments.volumes = volumes; + __asm__(".byte 1"); __asm__("lda #%b", ON_LINE); __asm__("sta %g", l1); diff --git a/prodos.h b/prodos.h new file mode 100644 index 0000000..5f84bb9 --- /dev/null +++ b/prodos.h @@ -0,0 +1,53 @@ +#ifndef PRODOS_MLI_H +#define PRODOS_MLI_H + +#include + +/* PATH_MAX POSIX constant + ProDOS has a 64 char prefix that can be combined with partial + pathname of 64 characters. This is a total of 128 characters. */ +#define PRODOS_PATH_MAX 128 + +#define PRODOS_FILE_NAME_MAX 15 + +#define PRODOS_E_IO_ERROR 0x27 +#define PRODOS_E_INVALID_PATH_SYNTAX 0x40 +#define PRODOS_E_PATH_NOT_FOUND 0x44 +#define PRODOS_E_VOLUME_DIR_NOT_FOUND 0x45 +#define PRODOS_E_FILE_NOT_FOUND 0x46 +#define PRODOS_E_INCOMPAT_FILE_FORMAT 0x4A +#define PRODOS_E_UNSUP_STORAGE_TYPE 0x4B +#define PRODOS_E_INVALID_VALUE_IN_PARAM 0x53 +#define PRODOS_E_BITMAP_ADDR_IMPOSSIBLE 0x5A + +#define GET_FILE_INFO_PARAM_COUNT 0x0a +#define ON_LINE_PARAM_COUNT 0x02 +#define ON_LINE_VOLUME_SIZE 256 + +struct GetFileInfoParams +{ + uint8_t param_count; /* in */ + const char *pathname; /* in */ + uint8_t access; /* out */ + uint8_t file_type; /* out */ + uint16_t aux_type; /* out */ + uint8_t storage_type; /* out */ + uint16_t blocks_used; /* out */ + uint16_t mod_date; /* out */ + uint16_t mod_time; /* out */ + uint16_t create_date; /* out */ + uint16_t create_time; /* out */ +}; + +struct OnLineParams +{ + uint8_t param_count; + uint8_t unit_num; + char data_buffer[ON_LINE_VOLUME_SIZE]; +}; + +uint8_t on_line(struct OnLineParams *params); +uint8_t get_file_info(struct GetFileInfoParams *params); + +#endif + diff --git a/prodos.s b/prodos.s new file mode 100644 index 0000000..55d156f --- /dev/null +++ b/prodos.s @@ -0,0 +1,33 @@ + .export _get_file_info + + + +MLI = $bf00 +GET_FILE_INFO = $c4 + + + + .bss + +_file_info_addr: .word $00 + + + + .code + +; This function is defined as "fastcall" which puts the right-most +; parameter into A/X and the return value in A/X. + +_get_file_info: + sta _file_info_addr + stx _file_info_addr+1 + + jsr MLI + .byte GET_FILE_INFO + .word _file_info_addr + + ; The system call leaves the error status in the Accumulator. + ; The "fastcall" calling convention returns the A register, + ; which is what we want. + rts +