From: Oliver Schmidt
Date: Wed, 8 May 2013 23:12:26 +0000 (+0200)
Subject: Added support for building targetutils.
X-Git-Tag: V2.14~11
X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=092653cb5b038e51b1b439dece01e521750810ab;p=cc65
Added support for building targetutils.
---
diff --git a/libsrc/Makefile b/libsrc/Makefile
index 6208d37b9..ea4864994 100644
--- a/libsrc/Makefile
+++ b/libsrc/Makefile
@@ -74,6 +74,9 @@ MKINC = $(GEOS) \
atari \
nes
+TARGETUTIL = apple2 \
+ geos-apple
+
GEOSDIRS = common \
conio \
disk \
@@ -90,59 +93,65 @@ GEOSDIRS = common \
ifeq ($(TARGET),apple2enh)
OBJPFX = a2
DRVPFX = a2e
- DIRS = apple2
+ SRCDIR = apple2
else
- DIRS = $(TARGET)
+ SRCDIR = $(TARGET)
endif
+SRCDIRS = $(SRCDIR)
+
ifeq ($(TARGET),$(filter $(TARGET),$(CBMS)))
- DIRS += cbm
+ SRCDIRS += cbm
endif
ifeq ($(TARGET),$(filter $(TARGET),$(GEOS)))
- DIRS += $(addprefix $(TARGET)/, $(GEOSDIRS))
- DIRS += $(addprefix geos-common/,$(GEOSDIRS))
+ SRCDIRS += $(addprefix $(TARGET)/, $(GEOSDIRS))
+ SRCDIRS += $(addprefix geos-common/,$(GEOSDIRS))
endif
-DIRS += common \
- conio \
- dbg \
- em \
- joystick \
- mouse \
- runtime \
- serial \
- tgi \
- zlib
+SRCDIRS += common \
+ conio \
+ dbg \
+ em \
+ joystick \
+ mouse \
+ runtime \
+ serial \
+ tgi \
+ zlib
-vpath %.s $(DIRS)
-vpath %.c $(DIRS)
+vpath %.s $(SRCDIRS)
+vpath %.c $(SRCDIRS)
-OBJS := $(patsubst %.s,%.o,$(foreach dir,$(DIRS),$(wildcard $(dir)/*.s)))
-OBJS += $(patsubst %.c,%.o,$(foreach dir,$(DIRS),$(wildcard $(dir)/*.c)))
+OBJS := $(patsubst %.s,%.o,$(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.s)))
+OBJS += $(patsubst %.c,%.o,$(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c)))
OBJS := $(addprefix ../wrk/$(TARGET)/,$(sort $(notdir $(OBJS))))
DEPS = $(OBJS:.o=.d)
-EXTRA_SRCPAT = $(firstword $(DIRS))/extra/%.s
+EXTRA_SRCPAT = $(SRCDIR)/extra/%.s
EXTRA_OBJPAT = ../lib/$(TARGET)-%.o
-EXTRA_OBJS := $(patsubst $(EXTRA_SRCPAT),$(EXTRA_OBJPAT),$(wildcard $(firstword $(DIRS))/extra/*.s))
+EXTRA_OBJS := $(patsubst $(EXTRA_SRCPAT),$(EXTRA_OBJPAT),$(wildcard $(SRCDIR)/extra/*.s))
ZPOBJ = ../wrk/$(TARGET)/zeropage.o
ifeq ($(TARGET),$(filter $(TARGET),$(EXTZP)))
ZPOBJ += ../wrk/$(TARGET)/extzp.o
endif
-ifeq ($(TARGET),$(filter $(TARGET),$(MKINC)))
- include $(TARGET)/Makefile.inc
+ifeq ($(SRCDIR),$(filter $(SRCDIR),$(MKINC)))
+ include $(SRCDIR)/Makefile.inc
+endif
+
+ifeq ($(SRCDIR),$(filter $(SRCDIR),$(TARGETUTIL)))
+ include $(SRCDIR)/targetutil/Makefile.inc
endif
##########
define DRVTYPE_template
-$1_SRCDIR = $$(firstword $$(DIRS))/$1
+$1_SRCDIR = $$(SRCDIR)/$1
$1_OBJDIR = ../wrk/$$(TARGET)/$1
$1_DRVDIR = ../$1
@@ -158,14 +167,11 @@ $1_STCS = $$(patsubst $$($1_DRVPAT),$$($1_STCPAT),$$($1_DRVS))
$$($1_OBJS): | $$($1_OBJDIR)
-$$($1_OBJDIR):
- @$$(call MKDIR,$$@)
-
$$($1_DRVPAT): $$($1_OBJPAT) $$(ZPOBJ) | $$($1_DRVDIR)
@echo $$(TARGET) - $$(@F)
@$$(LD) -o $$@ -t module $$^
-$$($1_DRVDIR):
+$$($1_OBJDIR) $$($1_DRVDIR):
@$$(call MKDIR,$$@)
$(TARGET): $$($1_DRVS)
@@ -191,17 +197,32 @@ CC = $(if $(wildcard ../bin/cc65*),../bin/cc65,cc65)
CO = $(if $(wildcard ../bin/co65*),../bin/co65,co65)
LD = $(if $(wildcard ../bin/ld65*),../bin/ld65,ld65)
+##########
+
+define ASSEMBLE_recipe
+
+@echo $(TARGET) - $<
+@$(CA) -t $(TARGET) $(AFLAGS) --create-dep $(@:.o=.d) -o $@ $<
+
+endef
+
+##########
+
+define COMPILE_recipe
+
+@echo $(TARGET) - $<
+@$(CC) -t $(TARGET) $(CFLAGS) --create-dep $(@:.o=.d) -o $(@:.o=.s) $<
+@$(CA) -t $(TARGET) -o $@ $(@:.o=.s)
+
+endef
+
+##########
+
../wrk/$(TARGET)/%.o: %.s | ../wrk/$(TARGET)
- @echo $(TARGET) - $<
- @$(CA) -t $(TARGET) $(AFLAGS) --create-dep $(@:.o=.d) -o $@ $<
+ $(ASSEMBLE_recipe)
../wrk/$(TARGET)/%.o: %.c | ../wrk/$(TARGET)
- @echo $(TARGET) - $<
- @$(CC) -t $(TARGET) $(CFLAGS) --create-dep $(@:.o=.d) -o $(@:.o=.s) $<
- @$(CA) -t $(TARGET) -o $@ $(@:.o=.s)
-
-../wrk/$(TARGET):
- @$(call MKDIR,$@)
+ $(COMPILE_recipe)
$(EXTRA_OBJPAT): $(EXTRA_SRCPAT) | ../lib
@echo $(TARGET) - $<
@@ -210,7 +231,7 @@ $(EXTRA_OBJPAT): $(EXTRA_SRCPAT) | ../lib
../lib/$(TARGET).lib: $(OBJS) | ../lib
$(AR) a $@ $?
-../lib:
+../wrk/$(TARGET) ../lib ../targetutil:
@$(call MKDIR,$@)
$(TARGET): $(EXTRA_OBJS) ../lib/$(TARGET).lib
diff --git a/libsrc/apple2/targetutil/Makefile.inc b/libsrc/apple2/targetutil/Makefile.inc
new file mode 100644
index 000000000..37fec5d39
--- /dev/null
+++ b/libsrc/apple2/targetutil/Makefile.inc
@@ -0,0 +1,7 @@
+../wrk/$(TARGET)/loader.o: $(SRCDIR)/targetutil/loader.s | ../wrk/$(TARGET)
+ $(ASSEMBLE_recipe)
+
+../targetutil/loader.system: ../wrk/$(TARGET)/loader.o $(SRCDIR)/targetutil/loader.cfg | ../targetutil
+ $(LD) -o $@ -C $(filter %.cfg,$^) $(filter-out %.cfg,$^)
+
+$(TARGET): ../targetutil/loader.system
diff --git a/libsrc/apple2/targetutil/loader.cfg b/libsrc/apple2/targetutil/loader.cfg
new file mode 100644
index 000000000..aa7a8c437
--- /dev/null
+++ b/libsrc/apple2/targetutil/loader.cfg
@@ -0,0 +1,17 @@
+#################################################################################
+# #
+# LOADER.SYSTEM - an Apple][ ProDOS 8 loader for cc65 programs (Oliver Schmidt) #
+# #
+#################################################################################
+
+MEMORY {
+ MEMORY_2000: start = $2000, size = $0200, file = %O;
+ MEMORY_0300: start = $0300, size = $0100;
+}
+
+SEGMENTS {
+ CODE_2000: load = MEMORY_2000, type = ro;
+ DATA_2000: load = MEMORY_2000, type = rw;
+ CODE_0300: load = MEMORY_2000, run = MEMORY_0300, type = ro, define = yes;
+ DATA_0300: load = MEMORY_2000, run = MEMORY_0300, type = rw, define = yes;
+}
diff --git a/libsrc/apple2/targetutil/loader.o b/libsrc/apple2/targetutil/loader.o
new file mode 100644
index 000000000..5c18e0ea0
Binary files /dev/null and b/libsrc/apple2/targetutil/loader.o differ
diff --git a/libsrc/apple2/targetutil/loader.s b/libsrc/apple2/targetutil/loader.s
new file mode 100644
index 000000000..71d79140e
--- /dev/null
+++ b/libsrc/apple2/targetutil/loader.s
@@ -0,0 +1,234 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; LOADER.SYSTEM - an Apple][ ProDOS 8 loader for cc65 programs (Oliver Schmidt) ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+A1L := $3C
+A1H := $3D
+STACK := $0100
+BUF := $0200
+PATHNAME := $0280
+MLI := $BF00
+VERSION := $FBB3
+RDKEY := $FD0C
+PRBYTE := $FDDA
+COUT := $FDED
+
+QUIT_CALL = $65
+GET_FILE_INFO_CALL = $C4
+OPEN_CALL = $C8
+READ_CALL = $CA
+CLOSE_CALL = $CC
+FILE_NOT_FOUND_ERR = $46
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ .import __CODE_0300_SIZE__, __DATA_0300_SIZE__
+ .import __CODE_0300_LOAD__, __CODE_0300_RUN__
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+.segment "DATA_2000"
+
+GET_FILE_INFO_PARAM:
+ .byte $0A ;PARAM_COUNT
+ .addr PATHNAME ;PATHNAME
+ .byte $00 ;ACCESS
+ .byte $00 ;FILE_TYPE
+FILE_INFO_ADDR: .word $0000 ;AUX_TYPE
+ .byte $00 ;STORAGE_TYPE
+ .word $0000 ;BLOCKS_USED
+ .word $0000 ;MOD_DATE
+ .word $0000 ;MOD_TIME
+ .word $0000 ;CREATE_DATE
+ .word $0000 ;CREATE_TIME
+
+OPEN_PARAM:
+ .byte $03 ;PARAM_COUNT
+ .addr PATHNAME ;PATHNAME
+ .addr MLI - 1024 ;IO_BUFFER
+OPEN_REF: .byte $00 ;REF_NUM
+
+LOADING:
+ .byte $0D
+ .asciiz "Loading "
+
+ELLIPSES:
+ .byte " ...", $0D, $0D, $00
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+.segment "DATA_0300"
+
+READ_PARAM:
+ .byte $04 ;PARAM_COUNT
+READ_REF: .byte $00 ;REF_NUM
+READ_ADDR: .addr $0000 ;DATA_BUFFER
+ .word $FFFF ;REQUEST_COUNT
+ .word $0000 ;TRANS_COUNT
+
+CLOSE_PARAM:
+ .byte $01 ;PARAM_COUNT
+CLOSE_REF: .byte $00 ;REF_NUM
+
+QUIT_PARAM:
+ .byte $04 ;PARAM_COUNT
+ .byte $00 ;QUIT_TYPE
+ .word $0000 ;RESERVED
+ .byte $00 ;RESERVED
+ .word $0000 ;RESERVED
+
+FILE_NOT_FOUND:
+ .asciiz "... File Not Found"
+
+ERROR_NUMBER:
+ .asciiz "... Error $"
+
+PRESS_ANY_KEY:
+ .asciiz " - Press Any Key "
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+.segment "CODE_2000"
+
+ jmp :+
+ .byte $EE
+ .byte $EE
+ .byte 65
+STARTUP:.res 65
+
+ ; Reset stack
+: ldx #$FF
+ txs
+
+ ; Relocate CODE_0300 and DATA_0300
+ ldx #<(__CODE_0300_SIZE__ + __DATA_0300_SIZE__)
+: lda __CODE_0300_LOAD__ - 1,x
+ sta __CODE_0300_RUN__ - 1,x
+ dex
+ bne :-
+
+ ; Remove ".SYSTEM" from pathname
+ lda PATHNAME
+ sec
+ sbc #.strlen(".SYSTEM")
+ sta PATHNAME
+
+ ; Add trailing '\0' to pathname
+ tax
+ lda #$00
+ sta PATHNAME + 1,x
+
+ ; Copy ProDOS startup filename and trailing '\0' to stack
+ ldx STARTUP
+ lda #$00
+ beq :++ ; bra
+: lda STARTUP + 1,x
+: sta STACK,x
+ dex
+ bpl :--
+
+ ; Provide some user feedback
+ lda #LOADING
+ jsr PRINT
+ lda #<(PATHNAME + 1)
+ ldx #>(PATHNAME + 1)
+ jsr PRINT
+ lda #ELLIPSES
+ jsr PRINT
+
+ jsr MLI
+ .byte GET_FILE_INFO_CALL
+ .word GET_FILE_INFO_PARAM
+ bcc :+
+ jmp ERROR
+
+: jsr MLI
+ .byte OPEN_CALL
+ .word OPEN_PARAM
+ bcc :+
+ jmp ERROR
+
+ ; Copy file reference number
+: lda OPEN_REF
+ sta READ_REF
+ sta CLOSE_REF
+
+ ; Get load address from aux-type
+ lda FILE_INFO_ADDR
+ ldx FILE_INFO_ADDR + 1
+ sta READ_ADDR
+ stx READ_ADDR + 1
+
+ ; It's high time to leave this place
+ jmp __CODE_0300_RUN__
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+.segment "CODE_0300"
+
+ jsr MLI
+ .byte READ_CALL
+ .word READ_PARAM
+ bcs ERROR
+
+ jsr MLI
+ .byte CLOSE_CALL
+ .word CLOSE_PARAM
+ bcs ERROR
+
+ ; Copy REM token and startup filename to BASIC input buffer
+ ldx #$00
+ lda #$B2
+ bne :++ ; bra
+: inx
+ lda a:STACK - 1,x
+: sta BUF,x
+ bne :--
+
+ ; Go for it ...
+ jmp (READ_ADDR)
+
+PRINT:
+ sta A1L
+ stx A1H
+ ldx VERSION
+ ldy #$00
+: lda (A1L),y
+ beq :++
+ cpx #$06 ; //e ?
+ beq :+
+ cmp #$60 ; lowercase ?
+ bcc :+
+ and #$5F ; -> uppercase
+: ora #$80
+ jsr COUT
+ iny
+ bne :-- ; bra
+: rts
+
+ERROR:
+ cmp #FILE_NOT_FOUND_ERR
+ bne :+
+ lda #FILE_NOT_FOUND
+ jsr PRINT
+ beq :++ ; bra
+: pha
+ lda #ERROR_NUMBER
+ jsr PRINT
+ pla
+ jsr PRBYTE
+: lda #PRESS_ANY_KEY
+ jsr PRINT
+ jsr RDKEY
+ jsr MLI
+ .byte QUIT_CALL
+ .word QUIT_PARAM
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/libsrc/apple2/targetutil/loader.txt b/libsrc/apple2/targetutil/loader.txt
new file mode 100644
index 000000000..d3ec87266
--- /dev/null
+++ b/libsrc/apple2/targetutil/loader.txt
@@ -0,0 +1,80 @@
+LOADER.SYSTEM - an Apple][ ProDOS 8 loader for cc65 programs (Oliver Schmidt)
+=============================================================================
+
+
+Background
+----------
+
+Apple][ ProDOS 8 system programs (filetype SYS) are always loaded into memory
+starting at location $2000. This poses the problem of how to make efficient
+use of the memory in the range $0800-$2000. The usual approach of relocation
+has two downsides:
+- Relocating e.g. 30 kB from $2000-$9800 to $0800-$8000 takes a considerable
+ amount of time.
+- Really large programs just don't fit into memory when loaded starting at
+ location $2000.
+
+The relocation can be eliminated by loading the major part(s) of the program
+from disk right to the final location by a rather small system program.
+
+LOADER.SYSTEM is such a small program. In fact it's so small that it fits into
+a single block in the ProDOS 8 file system making it a so-called seedling file,
+which are loaded really fast. LOADER.SYSTEM can load cc65 programs into memory
+anywhere in the range $0800-$BB00 (44,75 kB).
+
+
+Usage
+-----
+
+Link the cc65 program to the start address $0803 (or any other address) and
+store it as binary program (filetype BIN). This is in fact no different from
+a binary program to be run by BASIC.SYSTEM's BRUN command in the usual way.
+
+If however the cc65 program isn't run by BASIC.SYSTEM but is rather run by
+LOADER.SYSTEM then it behaves like a system program which means:
+- It uses memory up to the ProDOS 8 system global page located at $BF00.
+- It supports the ProDOS 8 startup file mechanism (mapped to argv[1]).
+- It quits to the ProDOS 8 dispatcher.
+
+Obviously LOADER.SYSTEM has to be told which cc65 program to run. Unfortunately
+the ProDOS 8 dispatcher has no notion of system program parameters so the usual
+approach would have been to make LOADER.SYSTEM bring up yet another menu to
+select the cc65 program to run.
+
+But to allow to select the cc65 program directly from the ProDOS 8 dispatcher
+anyway LOADER.SYSTEM detects the path to the cc65 program from its own path by
+just removing the '.SYSTEM' from its name. So if you want to run the cc65
+program MYPROGRAM you'll need a copy of LOADER.SYSTEM in the same directory
+being renamed to MYPROGRAM.SYSTEM.
+
+This means you will end up with a copy of LOADER.SYSTEM for every cc65 program
+to be run by it. But as LOADER.SYSTEM is a ProDOS 8 seedling file using up only
+a single block in the ProDOS 8 file system this should be no issue.
+
+
+Build
+-----
+
+In case you want to build 'loader.system' from the source code yourself you can
+do so using the following commands:
+
+ca65 loader.s
+ld65 -C loader.cfg -o loader.system loader.o
+
+
+Installation
+------------
+
+The file 'loader.system' as generated by the cc65 linker with the command above
+does NOT include the 4-byte address/length header that is generated for Apple][
+programs by default. This is because ProDOS 8 system programs are always loaded
+into memory starting at location $2000.
+
+The recommended way to transfer 'loader.system' from your native file system to
+a ProDOS 8 file system disk image is to use AppleCommander which is available at
+http://applecommander.sourceforge.net/
+
+If you want to put the file 'loader.system' onto a disk image 'mydisk.dsk' as
+system program MYPROGRAM.SYSTEM you can do so using the following command:
+
+java -jar ac.jar -p mydisk.dsk MYPROGRAM.SYSTEM sys < loader.system
diff --git a/libsrc/geos-apple/targetutil/Makefile.inc b/libsrc/geos-apple/targetutil/Makefile.inc
new file mode 100644
index 000000000..ff9429691
--- /dev/null
+++ b/libsrc/geos-apple/targetutil/Makefile.inc
@@ -0,0 +1,9 @@
+../wrk/$(TARGET)/convert.o: TARGET = apple2enh
+
+../wrk/$(TARGET)/convert.o: $(SRCDIR)/targetutil/convert.c | ../wrk/$(TARGET)
+ $(COMPILE_recipe)
+
+../targetutil/convert.system: ../wrk/$(TARGET)/convert.o | ../targetutil
+ $(LD) -o $@ -C apple2enh-system.cfg $^ apple2enh.lib
+
+$(TARGET): ../targetutil/convert.system
diff --git a/libsrc/geos-apple/targetutil/convert.c b/libsrc/geos-apple/targetutil/convert.c
new file mode 100644
index 000000000..ea9273fc3
--- /dev/null
+++ b/libsrc/geos-apple/targetutil/convert.c
@@ -0,0 +1,346 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+unsigned char info_signature[3] = {3, 21, 63 | 0x80};
+
+dhandle_t dhandle;
+
+struct dir_entry_t {
+ struct {
+ unsigned name_length :4;
+ unsigned storage_type :4;
+ } storage_length;
+ char file_name[15];
+ unsigned char file_type;
+ unsigned key_pointer;
+ unsigned blocks_used;
+ unsigned char size[3];
+ unsigned long creation;
+ unsigned char version;
+ unsigned char min_version;
+ unsigned char access;
+ unsigned aux_type;
+ unsigned long last_mod;
+ unsigned header_pointer;
+}* dir_entry;
+
+union {
+ unsigned char bytes[512];
+ struct {
+ unsigned prev_block;
+ unsigned next_block;
+ unsigned char entries[1];
+ } content;
+} dir_block;
+
+union {
+ unsigned char bytes[512];
+ struct {
+ unsigned char addr_lo[254];
+ unsigned char size_lo[2];
+ unsigned char addr_hi[254];
+ unsigned char size_hi[2];
+ } content;
+} index_block, master_block, vlir_block;
+
+union {
+ unsigned char bytes[512];
+ struct {
+ unsigned reserved;
+ unsigned char info_block[254];
+ unsigned char vlir_records[128];
+ struct dir_entry_t dir_entry;
+ } content;
+} header_block;
+
+
+static void err_exit(char *operation, unsigned char oserr)
+{
+ if (oserr) {
+ fprintf(stderr, "%s - err:%02x - %s",
+ operation, (int)_oserror, _stroserror(_oserror));
+ } else {
+ fprintf(stderr, "%s",
+ operation);
+ }
+ getchar();
+ exit(EXIT_FAILURE);
+}
+
+
+static unsigned get_dir_entry(char* p_name)
+{
+ char* d_name;
+ char* f_name;
+ size_t f_namelen;
+ DIR* dir;
+ struct dirent* dirent;
+ unsigned cur_addr;
+ unsigned char entry_length;
+ unsigned char entries_per_block;
+ unsigned char cur_entry;
+
+ /* Split path name into directory name and file name */
+ f_name = strrchr(p_name, '/');
+ if (f_name) {
+ d_name = p_name;
+ *f_name++ = '\0';
+ } else {
+ d_name = ".";
+ f_name = p_name;
+ }
+ f_namelen = strlen(f_name);
+
+ /* Start with high level functions to get handling
+ of relative path and current drive for free */
+ dir = opendir(d_name);
+ if (!dir) {
+ err_exit("opendir", 1);
+ }
+ dirent = readdir(dir);
+ if (!dirent) {
+ err_exit("readdir", 1);
+ }
+
+ /* Field header_pointer directly follows field last_mod */
+ cur_addr = *(unsigned*)(&dirent->d_mtime.hour + 1);
+
+ dhandle = dio_open(getcurrentdevice());
+ if (!dhandle) {
+ err_exit("dio_open", 1);
+ }
+
+ if (dio_read(dhandle, cur_addr, &dir_block)) {
+ err_exit("dio_read.1", 1);
+ }
+
+ /* Get directory entry infos from directory header */
+ entry_length = dir_block.bytes[0x23];
+ entries_per_block = dir_block.bytes[0x24];
+
+ /* Skip directory header entry */
+ cur_entry = 1;
+
+ do {
+
+ /* Search for next active directory entry */
+ do {
+
+ /* Check if next directory block is necessary */
+ if (cur_entry == entries_per_block) {
+
+ /* Check if another directory block is present */
+ cur_addr = dir_block.content.next_block;
+ if (!cur_addr) {
+ _mappederrno(0x46);
+ err_exit("dio_read.2", 1);
+ }
+
+ /* Read next directory block */
+ if (dio_read(dhandle, cur_addr, &dir_block)) {
+ err_exit("dio_read.3", 1);
+ }
+
+ /* Start with first entry in next block */
+ cur_entry = 0;
+ }
+
+ /* Compute pointer to current entry */
+ dir_entry = (struct dir_entry_t*)(dir_block.content.entries +
+ cur_entry * entry_length);
+
+ /* Switch to next entry */
+ ++cur_entry;
+ } while (!dir_entry->storage_length.storage_type);
+
+ } while (dir_entry->storage_length.name_length != f_namelen ||
+ strncasecmp(dir_entry->file_name, f_name, f_namelen));
+
+ return cur_addr;
+}
+
+
+int main(int argc, char* argv[])
+{
+ char input[80];
+ char* p_name;
+ unsigned dir_addr;
+ unsigned header_addr;
+ unsigned char index;
+ unsigned long size;
+
+ if (argc > 1) {
+ p_name = argv[1];
+ } else {
+ printf("\n"
+ "Apple GEOS Convert 1.0\n"
+ "----------------------\n"
+ "\n"
+ "Pathname:");
+ p_name = gets(input);
+ }
+
+ dir_addr = get_dir_entry(p_name);
+
+ /* Read index block */
+ if (dio_read(dhandle, dir_entry->key_pointer, &index_block)) {
+ err_exit("dio_read.4", 1);
+ }
+
+ /* First pointer is header block */
+ header_addr = index_block.content.addr_lo[0] |
+ index_block.content.addr_hi[0] << 8;
+
+ /* Read header block */
+ if (dio_read(dhandle, header_addr, &header_block)) {
+ err_exit("dio_read.5", 1);
+ }
+
+ /* Do some sanity check */
+ for (index = 0; index < sizeof(info_signature); ++index) {
+ if (header_block.content.info_block[index] != info_signature[index]) {
+ err_exit("file signature mismatch", 0);
+ }
+ }
+
+ /* Check ProDOS storage type in directory entry template */
+ if (header_block.content.dir_entry.storage_length.storage_type == 2)
+ {
+
+ /* ProDOS sapling file means GEOS Sequential file*/
+ printf("\nSequential file\n");
+
+ /* Remove header block pointer from pointer list */
+ memmove(&index_block.content.addr_lo[0],
+ &index_block.content.addr_lo[1], sizeof(index_block.content.addr_lo) - 1);
+ memmove(&index_block.content.addr_hi[0],
+ &index_block.content.addr_hi[1], sizeof(index_block.content.addr_hi) - 1);
+
+ /* Get file size from ProDOS directory entry template */
+ size = (unsigned long)(header_block.content.dir_entry.size[0]) |
+ (unsigned long)(header_block.content.dir_entry.size[1]) << 8 |
+ (unsigned long)(header_block.content.dir_entry.size[2]) << 16;
+
+ } else {
+
+ /* ProDOS tree file means GEOS VLIR file */
+ unsigned vlir_addr;
+ unsigned long vlir_size;
+ unsigned char vlir_blocks;
+ unsigned char record = 0;
+
+ printf("\nVLIR file\n");
+
+ /* Skip header block pointer */
+ index = 1;
+ size = 0;
+
+ while (1) {
+
+ /* Get next VLIR index pointer from index block */
+ vlir_addr = index_block.content.addr_lo[index] |
+ index_block.content.addr_hi[index] << 8;
+ ++index;
+
+ /* Check for end of pointer list */
+ if (vlir_addr == 0) {
+ break;
+ }
+
+ /* Check for empty VLIRs */
+ while (header_block.content.vlir_records[record] == 0xFF) {
+
+ /* Add empty VLIR index pointer to to master index block */
+ master_block.content.addr_lo[record] = 0xFF;
+ master_block.content.addr_hi[record] = 0xFF;
+ ++record;
+ }
+
+ /* Add VLIR index pointer to master index block */
+ master_block.content.addr_lo[record] = (unsigned char)(vlir_addr );
+ master_block.content.addr_hi[record] = (unsigned char)(vlir_addr >> 8);
+ ++record;
+
+ /* Read VLIR index block */
+ if (dio_read(dhandle, vlir_addr, &vlir_block)) {
+ err_exit("dio_read.6", 1);
+ }
+
+ /* Get VLIR size from VLIR index block */
+ vlir_size = (unsigned long)(vlir_block.content.size_lo[1]) |
+ (unsigned long)(vlir_block.content.size_hi[1]) << 8 |
+ (unsigned long)(vlir_block.content.size_lo[0]) << 16 |
+ (unsigned long)(vlir_block.content.size_hi[0]) << 24;
+
+ printf("VLIR %u size %lu bytes\n", record - 1, vlir_size);
+
+ /* Compute VLIR block size */
+ vlir_blocks = (unsigned char)((vlir_size + 511) / 512);
+
+ /* Copy VLIR block pointers from index block to VLIR index block */
+ memcpy(&vlir_block.content.addr_lo[0],
+ &index_block.content.addr_lo[index], vlir_blocks);
+ memcpy(&vlir_block.content.addr_hi[0],
+ &index_block.content.addr_hi[index], vlir_blocks);
+ index += vlir_blocks;
+
+ /* Write back VLIR index block */
+ if (dio_write(dhandle, vlir_addr, &vlir_block)) {
+ err_exit("dio_write.1", 1);
+ }
+
+ /* Add VLIR size to file size */
+ size += vlir_size;
+ }
+
+ /* Replace (by now completely read) index block with
+ (by now completely created) master index block */
+ index_block = master_block;
+ }
+
+ printf("File size %lu bytes\n\n", size);
+
+ /* Set file size in index block */
+ index_block.content.size_lo[1] = (unsigned char)(size );
+ index_block.content.size_hi[1] = (unsigned char)(size >> 8);
+ index_block.content.size_lo[0] = (unsigned char)(size >> 16);
+ index_block.content.size_hi[0] = (unsigned char)(size >> 24);
+
+ /* Write index block */
+ if (dio_write(dhandle, dir_entry->key_pointer, &index_block)) {
+ err_exit("dio_write.2", 1);
+ }
+
+ /* Copy selected fields from directory entry template to directory block */
+ dir_entry->storage_length = header_block.content.dir_entry.storage_length;
+ memcpy(dir_entry->file_name, header_block.content.dir_entry.file_name, 15);
+ dir_entry->file_type = header_block.content.dir_entry.file_type;
+ dir_entry->size[0] = (unsigned char)(size );
+ dir_entry->size[1] = (unsigned char)(size >> 8);
+ dir_entry->size[2] = (unsigned char)(size >> 16);
+ dir_entry->creation = header_block.content.dir_entry.creation;
+ dir_entry->version = header_block.content.dir_entry.version;
+ dir_entry->min_version = header_block.content.dir_entry.min_version;
+ dir_entry->aux_type = header_addr;
+ dir_entry->last_mod = header_block.content.dir_entry.last_mod;
+
+ /* Write directory block */
+ if (dio_write(dhandle, dir_addr, &dir_block)) {
+ err_exit("dio_write.3", 1);
+ }
+
+ /* We're done */
+ if (dio_close(dhandle)) {
+ err_exit("dio_close", 1);
+ }
+
+ printf("Convert to '%.*s' successful", dir_entry->storage_length.name_length,
+ dir_entry->file_name);
+ getchar();
+ return EXIT_SUCCESS;
+}
diff --git a/targetutil/Makefile b/targetutil/Makefile
deleted file mode 100644
index ef20b64b0..000000000
--- a/targetutil/Makefile
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Makefile
-#
-
-# --------------------------------------------------------------------------
-# Programs
-
-# Subdirectories
-SUBDIRS = apple2 geos-apple
-
-# --------------------------------------------------------------------------
-# List of executables. This list could be made target dependent by checking
-# $(SYS).
-
-.PHONY: all
-all:
- @for DIR in $(SUBDIRS); do \
- $(MAKE) -C $${DIR} $(MAKEOPTS); \
- done
-
-.PHONY: clean
-clean:
- @for DIR in $(SUBDIRS); do \
- $(MAKE) -C $${DIR} $(MAKEOPTS) clean; \
- done
-
-.PHONY: zap
-zap:
- @for DIR in $(SUBDIRS); do \
- $(MAKE) -C $${DIR} $(MAKEOPTS) zap; \
- done
-
diff --git a/targetutil/apple2/Makefile b/targetutil/apple2/Makefile
deleted file mode 100644
index 03596189e..000000000
--- a/targetutil/apple2/Makefile
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-# Makefile
-#
-
-# --------------------------------------------------------------------------
-# Programs
-CC = ../../src/cc65/cc65
-AS = ../../src/ca65/ca65
-LD = ../../src/ld65/ld65
-
-# Directories
-CFGDIR = ../../src/ld65/cfg
-INCDIR = ../../include
-LIBDIR = ../../libsrc
-
-# --------------------------------------------------------------------------
-# List of executables.
-
-EXELIST = loader.system
-
-
-# --------------------------------------------------------------------------
-# Targets
-
-
-.PHONY: all
-all: $(EXELIST)
-
-
-loader.system: loader.s Makefile
- $(AS) -t apple2 --forget-inc-paths loader.s
- $(LD) -o $@ -C loader.cfg loader.o $(LIBDIR)/apple2.lib
-
-
-# --------------------------------------------------------------------------
-# Cleanup rules
-
-.PHONY: clean
-clean:
- $(RM) *~ *.map *.o *.lbl
-
-.PHONY: zap
-zap: clean
- $(RM) $(EXELIST)
-
-
-
diff --git a/targetutil/apple2/loader.cfg b/targetutil/apple2/loader.cfg
deleted file mode 100644
index aa7a8c437..000000000
--- a/targetutil/apple2/loader.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
-#################################################################################
-# #
-# LOADER.SYSTEM - an Apple][ ProDOS 8 loader for cc65 programs (Oliver Schmidt) #
-# #
-#################################################################################
-
-MEMORY {
- MEMORY_2000: start = $2000, size = $0200, file = %O;
- MEMORY_0300: start = $0300, size = $0100;
-}
-
-SEGMENTS {
- CODE_2000: load = MEMORY_2000, type = ro;
- DATA_2000: load = MEMORY_2000, type = rw;
- CODE_0300: load = MEMORY_2000, run = MEMORY_0300, type = ro, define = yes;
- DATA_0300: load = MEMORY_2000, run = MEMORY_0300, type = rw, define = yes;
-}
diff --git a/targetutil/apple2/loader.s b/targetutil/apple2/loader.s
deleted file mode 100644
index 71d79140e..000000000
--- a/targetutil/apple2/loader.s
+++ /dev/null
@@ -1,234 +0,0 @@
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; ;
-; LOADER.SYSTEM - an Apple][ ProDOS 8 loader for cc65 programs (Oliver Schmidt) ;
-; ;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-A1L := $3C
-A1H := $3D
-STACK := $0100
-BUF := $0200
-PATHNAME := $0280
-MLI := $BF00
-VERSION := $FBB3
-RDKEY := $FD0C
-PRBYTE := $FDDA
-COUT := $FDED
-
-QUIT_CALL = $65
-GET_FILE_INFO_CALL = $C4
-OPEN_CALL = $C8
-READ_CALL = $CA
-CLOSE_CALL = $CC
-FILE_NOT_FOUND_ERR = $46
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- .import __CODE_0300_SIZE__, __DATA_0300_SIZE__
- .import __CODE_0300_LOAD__, __CODE_0300_RUN__
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-.segment "DATA_2000"
-
-GET_FILE_INFO_PARAM:
- .byte $0A ;PARAM_COUNT
- .addr PATHNAME ;PATHNAME
- .byte $00 ;ACCESS
- .byte $00 ;FILE_TYPE
-FILE_INFO_ADDR: .word $0000 ;AUX_TYPE
- .byte $00 ;STORAGE_TYPE
- .word $0000 ;BLOCKS_USED
- .word $0000 ;MOD_DATE
- .word $0000 ;MOD_TIME
- .word $0000 ;CREATE_DATE
- .word $0000 ;CREATE_TIME
-
-OPEN_PARAM:
- .byte $03 ;PARAM_COUNT
- .addr PATHNAME ;PATHNAME
- .addr MLI - 1024 ;IO_BUFFER
-OPEN_REF: .byte $00 ;REF_NUM
-
-LOADING:
- .byte $0D
- .asciiz "Loading "
-
-ELLIPSES:
- .byte " ...", $0D, $0D, $00
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-.segment "DATA_0300"
-
-READ_PARAM:
- .byte $04 ;PARAM_COUNT
-READ_REF: .byte $00 ;REF_NUM
-READ_ADDR: .addr $0000 ;DATA_BUFFER
- .word $FFFF ;REQUEST_COUNT
- .word $0000 ;TRANS_COUNT
-
-CLOSE_PARAM:
- .byte $01 ;PARAM_COUNT
-CLOSE_REF: .byte $00 ;REF_NUM
-
-QUIT_PARAM:
- .byte $04 ;PARAM_COUNT
- .byte $00 ;QUIT_TYPE
- .word $0000 ;RESERVED
- .byte $00 ;RESERVED
- .word $0000 ;RESERVED
-
-FILE_NOT_FOUND:
- .asciiz "... File Not Found"
-
-ERROR_NUMBER:
- .asciiz "... Error $"
-
-PRESS_ANY_KEY:
- .asciiz " - Press Any Key "
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-.segment "CODE_2000"
-
- jmp :+
- .byte $EE
- .byte $EE
- .byte 65
-STARTUP:.res 65
-
- ; Reset stack
-: ldx #$FF
- txs
-
- ; Relocate CODE_0300 and DATA_0300
- ldx #<(__CODE_0300_SIZE__ + __DATA_0300_SIZE__)
-: lda __CODE_0300_LOAD__ - 1,x
- sta __CODE_0300_RUN__ - 1,x
- dex
- bne :-
-
- ; Remove ".SYSTEM" from pathname
- lda PATHNAME
- sec
- sbc #.strlen(".SYSTEM")
- sta PATHNAME
-
- ; Add trailing '\0' to pathname
- tax
- lda #$00
- sta PATHNAME + 1,x
-
- ; Copy ProDOS startup filename and trailing '\0' to stack
- ldx STARTUP
- lda #$00
- beq :++ ; bra
-: lda STARTUP + 1,x
-: sta STACK,x
- dex
- bpl :--
-
- ; Provide some user feedback
- lda #LOADING
- jsr PRINT
- lda #<(PATHNAME + 1)
- ldx #>(PATHNAME + 1)
- jsr PRINT
- lda #ELLIPSES
- jsr PRINT
-
- jsr MLI
- .byte GET_FILE_INFO_CALL
- .word GET_FILE_INFO_PARAM
- bcc :+
- jmp ERROR
-
-: jsr MLI
- .byte OPEN_CALL
- .word OPEN_PARAM
- bcc :+
- jmp ERROR
-
- ; Copy file reference number
-: lda OPEN_REF
- sta READ_REF
- sta CLOSE_REF
-
- ; Get load address from aux-type
- lda FILE_INFO_ADDR
- ldx FILE_INFO_ADDR + 1
- sta READ_ADDR
- stx READ_ADDR + 1
-
- ; It's high time to leave this place
- jmp __CODE_0300_RUN__
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-.segment "CODE_0300"
-
- jsr MLI
- .byte READ_CALL
- .word READ_PARAM
- bcs ERROR
-
- jsr MLI
- .byte CLOSE_CALL
- .word CLOSE_PARAM
- bcs ERROR
-
- ; Copy REM token and startup filename to BASIC input buffer
- ldx #$00
- lda #$B2
- bne :++ ; bra
-: inx
- lda a:STACK - 1,x
-: sta BUF,x
- bne :--
-
- ; Go for it ...
- jmp (READ_ADDR)
-
-PRINT:
- sta A1L
- stx A1H
- ldx VERSION
- ldy #$00
-: lda (A1L),y
- beq :++
- cpx #$06 ; //e ?
- beq :+
- cmp #$60 ; lowercase ?
- bcc :+
- and #$5F ; -> uppercase
-: ora #$80
- jsr COUT
- iny
- bne :-- ; bra
-: rts
-
-ERROR:
- cmp #FILE_NOT_FOUND_ERR
- bne :+
- lda #FILE_NOT_FOUND
- jsr PRINT
- beq :++ ; bra
-: pha
- lda #ERROR_NUMBER
- jsr PRINT
- pla
- jsr PRBYTE
-: lda #PRESS_ANY_KEY
- jsr PRINT
- jsr RDKEY
- jsr MLI
- .byte QUIT_CALL
- .word QUIT_PARAM
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/targetutil/apple2/loader.txt b/targetutil/apple2/loader.txt
deleted file mode 100644
index d3ec87266..000000000
--- a/targetutil/apple2/loader.txt
+++ /dev/null
@@ -1,80 +0,0 @@
-LOADER.SYSTEM - an Apple][ ProDOS 8 loader for cc65 programs (Oliver Schmidt)
-=============================================================================
-
-
-Background
-----------
-
-Apple][ ProDOS 8 system programs (filetype SYS) are always loaded into memory
-starting at location $2000. This poses the problem of how to make efficient
-use of the memory in the range $0800-$2000. The usual approach of relocation
-has two downsides:
-- Relocating e.g. 30 kB from $2000-$9800 to $0800-$8000 takes a considerable
- amount of time.
-- Really large programs just don't fit into memory when loaded starting at
- location $2000.
-
-The relocation can be eliminated by loading the major part(s) of the program
-from disk right to the final location by a rather small system program.
-
-LOADER.SYSTEM is such a small program. In fact it's so small that it fits into
-a single block in the ProDOS 8 file system making it a so-called seedling file,
-which are loaded really fast. LOADER.SYSTEM can load cc65 programs into memory
-anywhere in the range $0800-$BB00 (44,75 kB).
-
-
-Usage
------
-
-Link the cc65 program to the start address $0803 (or any other address) and
-store it as binary program (filetype BIN). This is in fact no different from
-a binary program to be run by BASIC.SYSTEM's BRUN command in the usual way.
-
-If however the cc65 program isn't run by BASIC.SYSTEM but is rather run by
-LOADER.SYSTEM then it behaves like a system program which means:
-- It uses memory up to the ProDOS 8 system global page located at $BF00.
-- It supports the ProDOS 8 startup file mechanism (mapped to argv[1]).
-- It quits to the ProDOS 8 dispatcher.
-
-Obviously LOADER.SYSTEM has to be told which cc65 program to run. Unfortunately
-the ProDOS 8 dispatcher has no notion of system program parameters so the usual
-approach would have been to make LOADER.SYSTEM bring up yet another menu to
-select the cc65 program to run.
-
-But to allow to select the cc65 program directly from the ProDOS 8 dispatcher
-anyway LOADER.SYSTEM detects the path to the cc65 program from its own path by
-just removing the '.SYSTEM' from its name. So if you want to run the cc65
-program MYPROGRAM you'll need a copy of LOADER.SYSTEM in the same directory
-being renamed to MYPROGRAM.SYSTEM.
-
-This means you will end up with a copy of LOADER.SYSTEM for every cc65 program
-to be run by it. But as LOADER.SYSTEM is a ProDOS 8 seedling file using up only
-a single block in the ProDOS 8 file system this should be no issue.
-
-
-Build
------
-
-In case you want to build 'loader.system' from the source code yourself you can
-do so using the following commands:
-
-ca65 loader.s
-ld65 -C loader.cfg -o loader.system loader.o
-
-
-Installation
-------------
-
-The file 'loader.system' as generated by the cc65 linker with the command above
-does NOT include the 4-byte address/length header that is generated for Apple][
-programs by default. This is because ProDOS 8 system programs are always loaded
-into memory starting at location $2000.
-
-The recommended way to transfer 'loader.system' from your native file system to
-a ProDOS 8 file system disk image is to use AppleCommander which is available at
-http://applecommander.sourceforge.net/
-
-If you want to put the file 'loader.system' onto a disk image 'mydisk.dsk' as
-system program MYPROGRAM.SYSTEM you can do so using the following command:
-
-java -jar ac.jar -p mydisk.dsk MYPROGRAM.SYSTEM sys < loader.system
diff --git a/targetutil/geos-apple/Makefile b/targetutil/geos-apple/Makefile
deleted file mode 100644
index b2dcc967f..000000000
--- a/targetutil/geos-apple/Makefile
+++ /dev/null
@@ -1,49 +0,0 @@
-#
-# Makefile
-#
-
-# --------------------------------------------------------------------------
-# Programs
-CC = ../../src/cc65/cc65
-AS = ../../src/ca65/ca65
-LD = ../../src/ld65/ld65
-
-# Directories
-CFGDIR = ../../src/ld65/cfg
-INCDIR = ../../include
-LIBDIR = ../../libsrc
-
-# --------------------------------------------------------------------------
-# List of executables.
-
-EXELIST = convert.system
-
-
-
-# --------------------------------------------------------------------------
-# Targets
-
-
-.PHONY: all
-all: $(EXELIST)
-
-
-convert.system: convert.c Makefile
- $(CC) --forget-inc-paths -I $(INCDIR) -t apple2enh -O convert.c
- $(AS) --forget-inc-paths convert.s
- $(LD) -o $@ -C $(CFGDIR)/apple2enh-system.cfg convert.o $(LIBDIR)/apple2enh.lib
-
-
-# --------------------------------------------------------------------------
-# Cleanup rules
-
-.PHONY: clean
-clean:
- $(RM) *~ *.map *.o *.s *.lbl
-
-.PHONY: zap
-zap: clean
- $(RM) $(EXELIST)
-
-
-
diff --git a/targetutil/geos-apple/convert.c b/targetutil/geos-apple/convert.c
deleted file mode 100644
index ea9273fc3..000000000
--- a/targetutil/geos-apple/convert.c
+++ /dev/null
@@ -1,346 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-unsigned char info_signature[3] = {3, 21, 63 | 0x80};
-
-dhandle_t dhandle;
-
-struct dir_entry_t {
- struct {
- unsigned name_length :4;
- unsigned storage_type :4;
- } storage_length;
- char file_name[15];
- unsigned char file_type;
- unsigned key_pointer;
- unsigned blocks_used;
- unsigned char size[3];
- unsigned long creation;
- unsigned char version;
- unsigned char min_version;
- unsigned char access;
- unsigned aux_type;
- unsigned long last_mod;
- unsigned header_pointer;
-}* dir_entry;
-
-union {
- unsigned char bytes[512];
- struct {
- unsigned prev_block;
- unsigned next_block;
- unsigned char entries[1];
- } content;
-} dir_block;
-
-union {
- unsigned char bytes[512];
- struct {
- unsigned char addr_lo[254];
- unsigned char size_lo[2];
- unsigned char addr_hi[254];
- unsigned char size_hi[2];
- } content;
-} index_block, master_block, vlir_block;
-
-union {
- unsigned char bytes[512];
- struct {
- unsigned reserved;
- unsigned char info_block[254];
- unsigned char vlir_records[128];
- struct dir_entry_t dir_entry;
- } content;
-} header_block;
-
-
-static void err_exit(char *operation, unsigned char oserr)
-{
- if (oserr) {
- fprintf(stderr, "%s - err:%02x - %s",
- operation, (int)_oserror, _stroserror(_oserror));
- } else {
- fprintf(stderr, "%s",
- operation);
- }
- getchar();
- exit(EXIT_FAILURE);
-}
-
-
-static unsigned get_dir_entry(char* p_name)
-{
- char* d_name;
- char* f_name;
- size_t f_namelen;
- DIR* dir;
- struct dirent* dirent;
- unsigned cur_addr;
- unsigned char entry_length;
- unsigned char entries_per_block;
- unsigned char cur_entry;
-
- /* Split path name into directory name and file name */
- f_name = strrchr(p_name, '/');
- if (f_name) {
- d_name = p_name;
- *f_name++ = '\0';
- } else {
- d_name = ".";
- f_name = p_name;
- }
- f_namelen = strlen(f_name);
-
- /* Start with high level functions to get handling
- of relative path and current drive for free */
- dir = opendir(d_name);
- if (!dir) {
- err_exit("opendir", 1);
- }
- dirent = readdir(dir);
- if (!dirent) {
- err_exit("readdir", 1);
- }
-
- /* Field header_pointer directly follows field last_mod */
- cur_addr = *(unsigned*)(&dirent->d_mtime.hour + 1);
-
- dhandle = dio_open(getcurrentdevice());
- if (!dhandle) {
- err_exit("dio_open", 1);
- }
-
- if (dio_read(dhandle, cur_addr, &dir_block)) {
- err_exit("dio_read.1", 1);
- }
-
- /* Get directory entry infos from directory header */
- entry_length = dir_block.bytes[0x23];
- entries_per_block = dir_block.bytes[0x24];
-
- /* Skip directory header entry */
- cur_entry = 1;
-
- do {
-
- /* Search for next active directory entry */
- do {
-
- /* Check if next directory block is necessary */
- if (cur_entry == entries_per_block) {
-
- /* Check if another directory block is present */
- cur_addr = dir_block.content.next_block;
- if (!cur_addr) {
- _mappederrno(0x46);
- err_exit("dio_read.2", 1);
- }
-
- /* Read next directory block */
- if (dio_read(dhandle, cur_addr, &dir_block)) {
- err_exit("dio_read.3", 1);
- }
-
- /* Start with first entry in next block */
- cur_entry = 0;
- }
-
- /* Compute pointer to current entry */
- dir_entry = (struct dir_entry_t*)(dir_block.content.entries +
- cur_entry * entry_length);
-
- /* Switch to next entry */
- ++cur_entry;
- } while (!dir_entry->storage_length.storage_type);
-
- } while (dir_entry->storage_length.name_length != f_namelen ||
- strncasecmp(dir_entry->file_name, f_name, f_namelen));
-
- return cur_addr;
-}
-
-
-int main(int argc, char* argv[])
-{
- char input[80];
- char* p_name;
- unsigned dir_addr;
- unsigned header_addr;
- unsigned char index;
- unsigned long size;
-
- if (argc > 1) {
- p_name = argv[1];
- } else {
- printf("\n"
- "Apple GEOS Convert 1.0\n"
- "----------------------\n"
- "\n"
- "Pathname:");
- p_name = gets(input);
- }
-
- dir_addr = get_dir_entry(p_name);
-
- /* Read index block */
- if (dio_read(dhandle, dir_entry->key_pointer, &index_block)) {
- err_exit("dio_read.4", 1);
- }
-
- /* First pointer is header block */
- header_addr = index_block.content.addr_lo[0] |
- index_block.content.addr_hi[0] << 8;
-
- /* Read header block */
- if (dio_read(dhandle, header_addr, &header_block)) {
- err_exit("dio_read.5", 1);
- }
-
- /* Do some sanity check */
- for (index = 0; index < sizeof(info_signature); ++index) {
- if (header_block.content.info_block[index] != info_signature[index]) {
- err_exit("file signature mismatch", 0);
- }
- }
-
- /* Check ProDOS storage type in directory entry template */
- if (header_block.content.dir_entry.storage_length.storage_type == 2)
- {
-
- /* ProDOS sapling file means GEOS Sequential file*/
- printf("\nSequential file\n");
-
- /* Remove header block pointer from pointer list */
- memmove(&index_block.content.addr_lo[0],
- &index_block.content.addr_lo[1], sizeof(index_block.content.addr_lo) - 1);
- memmove(&index_block.content.addr_hi[0],
- &index_block.content.addr_hi[1], sizeof(index_block.content.addr_hi) - 1);
-
- /* Get file size from ProDOS directory entry template */
- size = (unsigned long)(header_block.content.dir_entry.size[0]) |
- (unsigned long)(header_block.content.dir_entry.size[1]) << 8 |
- (unsigned long)(header_block.content.dir_entry.size[2]) << 16;
-
- } else {
-
- /* ProDOS tree file means GEOS VLIR file */
- unsigned vlir_addr;
- unsigned long vlir_size;
- unsigned char vlir_blocks;
- unsigned char record = 0;
-
- printf("\nVLIR file\n");
-
- /* Skip header block pointer */
- index = 1;
- size = 0;
-
- while (1) {
-
- /* Get next VLIR index pointer from index block */
- vlir_addr = index_block.content.addr_lo[index] |
- index_block.content.addr_hi[index] << 8;
- ++index;
-
- /* Check for end of pointer list */
- if (vlir_addr == 0) {
- break;
- }
-
- /* Check for empty VLIRs */
- while (header_block.content.vlir_records[record] == 0xFF) {
-
- /* Add empty VLIR index pointer to to master index block */
- master_block.content.addr_lo[record] = 0xFF;
- master_block.content.addr_hi[record] = 0xFF;
- ++record;
- }
-
- /* Add VLIR index pointer to master index block */
- master_block.content.addr_lo[record] = (unsigned char)(vlir_addr );
- master_block.content.addr_hi[record] = (unsigned char)(vlir_addr >> 8);
- ++record;
-
- /* Read VLIR index block */
- if (dio_read(dhandle, vlir_addr, &vlir_block)) {
- err_exit("dio_read.6", 1);
- }
-
- /* Get VLIR size from VLIR index block */
- vlir_size = (unsigned long)(vlir_block.content.size_lo[1]) |
- (unsigned long)(vlir_block.content.size_hi[1]) << 8 |
- (unsigned long)(vlir_block.content.size_lo[0]) << 16 |
- (unsigned long)(vlir_block.content.size_hi[0]) << 24;
-
- printf("VLIR %u size %lu bytes\n", record - 1, vlir_size);
-
- /* Compute VLIR block size */
- vlir_blocks = (unsigned char)((vlir_size + 511) / 512);
-
- /* Copy VLIR block pointers from index block to VLIR index block */
- memcpy(&vlir_block.content.addr_lo[0],
- &index_block.content.addr_lo[index], vlir_blocks);
- memcpy(&vlir_block.content.addr_hi[0],
- &index_block.content.addr_hi[index], vlir_blocks);
- index += vlir_blocks;
-
- /* Write back VLIR index block */
- if (dio_write(dhandle, vlir_addr, &vlir_block)) {
- err_exit("dio_write.1", 1);
- }
-
- /* Add VLIR size to file size */
- size += vlir_size;
- }
-
- /* Replace (by now completely read) index block with
- (by now completely created) master index block */
- index_block = master_block;
- }
-
- printf("File size %lu bytes\n\n", size);
-
- /* Set file size in index block */
- index_block.content.size_lo[1] = (unsigned char)(size );
- index_block.content.size_hi[1] = (unsigned char)(size >> 8);
- index_block.content.size_lo[0] = (unsigned char)(size >> 16);
- index_block.content.size_hi[0] = (unsigned char)(size >> 24);
-
- /* Write index block */
- if (dio_write(dhandle, dir_entry->key_pointer, &index_block)) {
- err_exit("dio_write.2", 1);
- }
-
- /* Copy selected fields from directory entry template to directory block */
- dir_entry->storage_length = header_block.content.dir_entry.storage_length;
- memcpy(dir_entry->file_name, header_block.content.dir_entry.file_name, 15);
- dir_entry->file_type = header_block.content.dir_entry.file_type;
- dir_entry->size[0] = (unsigned char)(size );
- dir_entry->size[1] = (unsigned char)(size >> 8);
- dir_entry->size[2] = (unsigned char)(size >> 16);
- dir_entry->creation = header_block.content.dir_entry.creation;
- dir_entry->version = header_block.content.dir_entry.version;
- dir_entry->min_version = header_block.content.dir_entry.min_version;
- dir_entry->aux_type = header_addr;
- dir_entry->last_mod = header_block.content.dir_entry.last_mod;
-
- /* Write directory block */
- if (dio_write(dhandle, dir_addr, &dir_block)) {
- err_exit("dio_write.3", 1);
- }
-
- /* We're done */
- if (dio_close(dhandle)) {
- err_exit("dio_close", 1);
- }
-
- printf("Convert to '%.*s' successful", dir_entry->storage_length.name_length,
- dir_entry->file_name);
- getchar();
- return EXIT_SUCCESS;
-}