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; -}