This commit is contained in:
Bill Chatfield 2018-11-12 21:27:27 -05:00
parent caf1b7bce5
commit 332f067b2e
14 changed files with 280 additions and 103 deletions

View File

@ -8,10 +8,28 @@ ifndef CC65_TARGET
CC65_TARGET:=apple2enh
endif
ifeq ($(OS),Windows_NT)
ifndef MERLIN_DIR
MERLIN_DIR=C:/opt/Merlin32_v1.0
endif
MERLIN_LIB=$(MERLIN_DIR)/Library
MERLIN=$(MERLIN_DIR)/Windows/Merlin32
COPY=copy
APPLEWIN="c:\opt\AppleWin1.26.2.3\applewin.exe"
else
ifndef MERLIN_DIR
MERLIN_DIR=$(HOME)/opt/Merlin32_v1.0
endif
MERLIN_LIB=$(MERLIN_DIR)/Library
MERLIN=$(MERLIN_DIR)/Linux64/Merlin32
COPY=cp
APPLEWIN=applewin
endif
CC=cl65
AS=ca65
OBJS=copy.o cui.o fileinfo.o prodos.o
HDRS=fileinfo.h cui.h prodos.h
OBJS=copy.o cui.o prodos.o prodosext.o libgen.o
HDRS=cui.h prodos.h prodosext.h libgen.h
CFLAGS=-O -t $(CC65_TARGET) -DTRACE
# The -S $6000 makes the start address $6000 so that both hi-res
# pages are available.
@ -31,14 +49,22 @@ BIN_LOAD_ADDR=0x0803
all: $(DISK)
$(DISK): $(PGM)
$(DISK): $(PGM) libgentest
$(RM) $(DISK)
$(AC) -pro140 $(DISK) $(DISK_VOL)
$(AC) -as $(DISK) $(PGM) BIN < $(PGM)
$(AC) -as $(DISK) libgentest BIN < libgentest
$(PGM): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^
libgentest: libgen.o libgentest.o
$(CC) $(LDFLAGS) -o $@ $^
test: $(DISK)
$(APPLEWIN) -d1 $(DISK)
#$(APPLEWIN) -s7 empty -d1 $(DISK)
clean:
$(RM) *.o $(PGM) $(DISK)

53
copy.c
View File

@ -1,54 +1,59 @@
#include <stdio.h> /* fopen, fread, fwrite, fclose */
#include <stdbool.h>
#include <stdlib.h> /* atexit */
#include <string.h>
#include "libgen.h" /* basename */
#include "fileinfo.h"
#include "prodos.h"
#include "prodosext.h"
#include "cui.h"
#define BUFFER_SIZE 2048
#define BF_SIZ 2048
void cleanup(void);
FILE *openFile(const char *name, const char *mode);
void closeFile(FILE *f, const char *name);
void concatPath(char *dest, const char *src);
char sourceName[PRODOS_PATH_MAX + 1];
char srcName[PRODOS_PATH_MAX + 1];
char destName[PRODOS_PATH_MAX + 1];
FILE *sourceFile = NULL;
FILE *destFile = NULL;
struct FileInfo sourceInfo;
struct FileInfo destInfo;
FILE *src = NULL;
FILE *dest = NULL;
struct GetFileInfoParams srcInfo;
struct GetFileInfoParams destInfo;
size_t n;
char buffer[BUFFER_SIZE];
char buf[BF_SIZ];
size_t bytesRead;
void main(void)
{
atexit(cleanup);
inputFileName("Source file or directory:", sourceName, sizeof(sourceName), &sourceInfo);
inputFileName("Destination file or directory:", destName, sizeof(destName), &destInfo);
if (! inputFileName("Source file or directory:", srcName,
sizeof(srcName), &srcInfo))
return;
sourceFile = openFile(sourceName, "r");
if (! inputFileName("Destination file or directory:", destName,
sizeof(destName), &destInfo))
return;
if (isDir(&destInfo)) {
concatPath(destName, basename(sourceName));
}
src = openFile(srcName, "r");
destFile = openFile(destName, "w");
if (isDirectory(&destInfo))
concatPath(destName, basename(srcName));
while ((bytesRead = fread(buffer, 1, sizeof(buffer), sourceFile)) == BUFFER_SIZE) {
if (fwrite(buffer, 1, bytesRead, destFile) < bytesRead) {
dest = openFile(destName, "w");
while ((bytesRead = fread(buf, 1, sizeof(buf), src)) == BF_SIZ)
if (fwrite(buf, 1, bytesRead, dest) < bytesRead) {
perror(destName);
break;
}
}
if (bytesRead > 0 && !feof(destFile) && !ferror(destFile)) {
if (fwrite(buffer, 1, bytesRead, destFile) < bytesRead) {
if (bytesRead > 0 && !feof(dest) && !ferror(dest))
if (fwrite(buf, 1, bytesRead, dest) < bytesRead)
perror(destName);
}
}
cleanup();
}
@ -83,7 +88,7 @@ void concatPath(char *dest, const char *src)
void cleanup(void)
{
closeFile(destFile, destName);
closeFile(sourceFile, sourceName);
closeFile(dest, destName);
closeFile(src, srcName);
}

38
cui.c
View File

@ -3,27 +3,44 @@
#include <string.h> /* strlen */
#include "cui.h"
#include "fileinfo.h"
#include "prodos.h"
#include "prodosext.h"
#define ESC '\x1b'
static char *readLine(char *line, size_t capacity);
static void chomp(char *line);
static bool complete;
static uint8_t result;
void inputFileName(const char *prompt, char *name, size_t capacity, struct FileInfo *f)
bool inputFileName(const char *prompt, char *name,
size_t capacity,
struct GetFileInfoParams *params)
{
complete = false;
while (! complete) {
printf(prompt);
readLine(name, capacity);
initFileInfo(f, name);
if (exists(f)) {
if (strlen(name) == 0) {
puts("Aborting");
break;
}
else if (name[0] == ESC) {
puts("Escaping");
break;
}
params->param_count = GET_FILE_INFO_PARAM_COUNT;
params->pathname = name;
printf("params address = %x\n", &(params->param_count));
printf("params address = %x\n", params);
result = get_file_info(params);
if (result == PRODOS_E_NONE)
complete = true;
}
else {
fprintf(stderr, "File '%s' does not exist\n", name);
}
else
fprintf(stderr, "%s: %s (code %d)\n", name, getMessage(result), result);
}
return complete;
}
char *readLine(char *line, size_t capacity)
@ -32,9 +49,8 @@ char *readLine(char *line, size_t capacity)
if ((result = fgets(line, capacity, stdin)) != NULL)
chomp(line);
else
if (ferror(stdin))
perror("stdin");
else if (ferror(stdin))
perror("stdin");
return result;
}

3
cui.h
View File

@ -1,7 +1,8 @@
#ifndef CUI_H
#define CUI_H
extern void inputFileName(const char *prompt, char *name, size_t capacity, struct FileInfo *f);
extern bool inputFileName(const char *prompt, char *name, size_t capacity,
struct GetFileInfoParams *params);
#endif

View File

@ -1,27 +0,0 @@
#include <apple2_filetype.h> /* 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;
}

View File

@ -1,18 +0,0 @@
#ifndef MY_FILE_H
#define MY_FILE_H
#include <stdbool.h>
#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

23
libgen.c Normal file
View File

@ -0,0 +1,23 @@
#include <string.h>
char *basename(char *path)
{
char *ptr;
/* If path is NULL or the empty string, return "." */
if (path == NULL || path[0] == '\0')
return ".";
/* If path is "/", return "/" */
if (path[0] == '/' && path[1] == '\0')
return path;
/* If path does not contain a '/' then return path */
if ((ptr = strrchr(path, '/')) == NULL)
return path;
/* Path contains a slash so return the string following the last
slash. */
return ++ptr;
}

9
libgen.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef GUNGWALDS_LIBGEN_H
#define GUNGWALDS_LIBGEN_H
/* Conforms to POSIX but does not modify path. A pointer into path
or a constant string value is returned. So don't attempt to
modify the return value. */
char *basename(char *path);
#endif

BIN
libgentest Normal file

Binary file not shown.

20
libgentest.c Normal file
View File

@ -0,0 +1,20 @@
#include <stdio.h>
#include <string.h>
#include "libgen.h"
void assertStringEquals(char *s, char *t, char *name)
{
if (strcmp(s, t) == 0)
printf("Success - %s\n", name);
else
printf("FAILURE - %s\n", name);
}
void main(void)
{
assertStringEquals(basename(NULL), ".", "NULL");
assertStringEquals(basename(""), ".", "Empty");
assertStringEquals(basename("/"), "/", "Slash");
assertStringEquals(basename("/blah/"),"","Trailing slash");
assertStringEquals(basename("/blah"), "blah", "Blah");
}

View File

@ -4,20 +4,41 @@
#include <stdint.h>
/* 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. */
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_NONE 0x00
#define PRODOS_E_BAD_SYS_CALL_NUM 0x01
#define PRODOS_E_BAD_SYS_PARAM_COUNT 0x04
#define PRODOS_E_INTERRUPT_VECTOR_TABLE_FULL 0x25
#define PRODOS_E_IO_ERROR 0x27
#define PRODOS_E_NO_DEVICE 0x28
#define PRODOS_E_DISK_WRITE_PROTECTED 0x2b
#define PRODOS_E_DISK_SWITCHED 0x2e
#define PRODOS_E_INVALID_PATH_SYNTAX 0x40
#define PRODOS_E_FILE_CTRL_BLK_TABLE_FULL 0x42
#define PRODOS_E_INVALID_REF_NUM 0x43
#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_DUPLICATE_FILE_NAME 0x47
#define PRODOS_E_OVERRUN_ERROR 0x48
#define PRODOS_E_VOLUME_DIR_FULL 0x49
#define PRODOS_E_INCOMPATIBLE_FILE_FORMAT 0x4A
#define PRODOS_E_UNSUPPORTED_STORAGE_TYPE 0x4B
#define PRODOS_E_END_OF_FILE 0x4C
#define PRODOS_E_POSITION_OUT_OF_RANGE 0x4D
#define PRODOS_E_ACCESS_ERROR 0x4E
#define PRODOS_E_FILE_IS_OPEN 0x50
#define PRODOS_E_DIR_COUNT_ERROR 0x51
#define PRODOS_E_NOT_PRODOS_DISK 0x52
#define PRODOS_E_INVALID_PARAM 0x53
#define PRODOS_E_VOLUME_CTRL_BLK_TABLE_FULL 0x55
#define PRODOS_E_BAD_BUFFER_ADDR 0x56
#define PRODOS_E_DUPLICATE_VOLUME 0x57
#define PRODOS_E_BITMAP_ADDR_IMPOSSIBLE 0x5A
#define GET_FILE_INFO_PARAM_COUNT 0x0a

View File

@ -1,33 +1,46 @@
.export _get_file_info
MLI = $bf00
GET_FILE_INFO = $c4
COUT = $FDED ;SUB TO OUTPUT A CHARACTER
PRBYTE = $FDDA ;SUB TO PRINT A BYTE
CROUT = $FD8E ;SUB TO OUTPUT CARRIAGE RETURN
.bss
_file_info_addr: .word $00
.code
.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
.proc _get_file_info
sta params
stx params+1
; Switch in ROM
bit $c082
lda params
jsr PRBYTE
jsr CROUT
lda params+1
jsr PRBYTE
jsr CROUT
jsr MLI
.byte GET_FILE_INFO
.word _file_info_addr
params: .word 0
; The system call leaves the error status in the Accumulator.
; The "fastcall" calling convention returns the A register,
; which is what we want.
rts
.endproc
.bss
file_info_addr: .res 2

78
prodosext.c Normal file
View File

@ -0,0 +1,78 @@
#include <stdbool.h>
#include <apple2_filetype.h>
#include "prodos.h"
#include "prodosext.h"
bool isDirectory(struct GetFileInfoParams *params)
{
return params->file_type == PRODOS_T_DIR;
}
const char *getMessage(uint8_t errorCode)
{
switch (errorCode) {
case PRODOS_E_NONE:
return "No error";
case PRODOS_E_BAD_SYS_CALL_NUM:
return "Bad system call number";
case PRODOS_E_BAD_SYS_PARAM_COUNT:
return "Bad system call parameter count";
case PRODOS_E_INTERRUPT_VECTOR_TABLE_FULL:
return "Interrupt vector table full";
case PRODOS_E_IO_ERROR:
return "I/O error";
case PRODOS_E_NO_DEVICE:
return "No device detected/connected";
case PRODOS_E_DISK_WRITE_PROTECTED:
return "Disk is write protected";
case PRODOS_E_DISK_SWITCHED:
return "Disk switched";
case PRODOS_E_INVALID_PATH_SYNTAX:
return "Invalid path syntax";
case PRODOS_E_FILE_CTRL_BLK_TABLE_FULL:
return "File control block table full";
case PRODOS_E_INVALID_REF_NUM:
return "Invalid reference number";
case PRODOS_E_PATH_NOT_FOUND:
return "Path not found";
case PRODOS_E_VOLUME_DIR_NOT_FOUND:
return "Volume directory not found";
case PRODOS_E_FILE_NOT_FOUND:
return "File not found";
case PRODOS_E_DUPLICATE_FILE_NAME:
return "Duplicate file name";
case PRODOS_E_OVERRUN_ERROR:
return "No space left on device";
case PRODOS_E_VOLUME_DIR_FULL:
return "No entries left in volume directory";
case PRODOS_E_INCOMPATIBLE_FILE_FORMAT:
return "Incompatible file format";
case PRODOS_E_UNSUPPORTED_STORAGE_TYPE:
return "Unsupported storage type";
case PRODOS_E_END_OF_FILE:
return "End of file reached";
case PRODOS_E_POSITION_OUT_OF_RANGE:
return "File position out of range";
case PRODOS_E_ACCESS_ERROR:
return "File attribute forbids operation";
case PRODOS_E_FILE_IS_OPEN:
return "File is open";
case PRODOS_E_DIR_COUNT_ERROR:
return "Directory header / file entry mismatch";
case PRODOS_E_NOT_PRODOS_DISK:
"Not a ProDOS disk";
case PRODOS_E_INVALID_PARAM:
return "Invalid value in parameter";
case PRODOS_E_VOLUME_CTRL_BLK_TABLE_FULL:
return "Volume control block table full";
case PRODOS_E_BAD_BUFFER_ADDR:
return "Bad buffer address";
case PRODOS_E_DUPLICATE_VOLUME:
return "Duplicate volume";
case PRODOS_E_BITMAP_ADDR_IMPOSSIBLE:
return "Bitmap address impossible";
default:
return "Unknown error";
}
}

10
prodosext.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef PRODOSEXT_H
#define PRODOSEXT_H
#include <stdbool.h>
#include <stdint.h>
extern bool isDirectory(struct GetFileInfoParams *params);
extern const char *getMessage(uint8_t errorCode);
#endif