#define _BSD_SOURCE #include #include #include #include #include "defc.h" #include "gsos.h" #include "fst.h" #ifdef _WIN32 #include #endif #ifdef _MSC_VER #define strcasecmp stricmp #define strncasecmp strnicmp #endif #include "host_common.h" char *host_root = NULL; char *g_cfg_host_path = ""; // must not be null. int g_cfg_host_read_only = 0; int g_cfg_host_crlf = 1; int g_cfg_host_merlin = 0; /* * simple malloc pool to simplify code. Should never need > 4 allocations. * */ static void *gc[16]; static void **gc_ptr = &gc[0]; void *host_gc_malloc(size_t size) { if (gc_ptr == &gc[16]) { errno = ENOMEM; return NULL; } void *ptr = malloc(size); if (ptr) { *gc_ptr++ = ptr; } return ptr; } void host_gc_free(void) { while (gc_ptr > gc) free(*--gc_ptr); } char *host_gc_strdup(const char *src) { if (!src) return ""; if (!*src) return ""; int len = strlen(src) + 1; char *cp = host_gc_malloc(len); memcpy(cp, src, len); return cp; } char *host_gc_append_path(const char *a, const char *b) { /* strip all leading /s from b) */ while (*b == '/') ++b; int aa = strlen(a); int bb = strlen(b); char *cp = host_gc_malloc(aa + bb + 2); if (!cp) return NULL; memcpy(cp, a, aa); int len = aa; /* strip all trailing /s from b */ while (len > 2 && cp[len-1] == '/') --len; cp[len++] = '/'; memcpy(cp + len, b, bb); len += bb; cp[len] = 0; return cp; } char *host_gc_append_string(const char *a, const char *b) { int aa = strlen(a); int bb = strlen(b); char *cp = host_gc_malloc(aa + bb + 2); if (!cp) return NULL; memcpy(cp, a, aa); int len = aa; memcpy(cp + len, b, bb); len += bb; cp[len] = 0; return cp; } /* * text conversion. */ void host_cr_to_lf(byte *buffer, size_t size) { size_t i; for (i = 0; i < size; ++i) { if (buffer[i] == '\r') buffer[i] = '\n'; } } void host_lf_to_cr(byte *buffer, size_t size) { size_t i; for (i = 0; i < size; ++i) { if (buffer[i] == '\n') buffer[i] = '\r'; } } void host_merlin_to_text(byte *buffer, size_t size) { size_t i; for (i = 0; i < size; ++i) { byte b = buffer[i]; if (b == 0xa0) b = '\t'; b &= 0x7f; if (b == '\r') b = '\n'; buffer[i] = b; } } void host_text_to_merlin(byte *buffer, size_t size) { size_t i; for (i = 0; i < size; ++i) { byte b = buffer[i]; if (b == '\t') b = 0xa0; if (b == '\n') b = '\r'; if (b != ' ') b |= 0x80; buffer[i] = b; } } const char *host_error_name(word16 error) { static char *errors[] = { "", "badSystemCall", "", "", "invalidPcount", "", "", "gsosActive", "", "", "", "", "", "", "", "", // 0x10 "devNotFound", "invalidDevNum", "", "", "", "", "", "", "", "", "", "", "", "", "", "", // 0x20 "drvrBadReq", "drvrBadCode", "drvrBadParm", "drvrNotOpen", "drvrPriorOpen", "irqTableFull", "drvrNoResrc", "drvrIOError", "drvrNoDevice", "drvrBusy", "", "drvrWrtProt", "drvrBadCount", "drvrBadBlock", "drvrDiskSwitch", "drvrOffLine", // 0x30 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", // 0x40 "badPathSyntax", "", "tooManyFilesOpen", "invalidRefNum", "pathNotFound", "volNotFound", "fileNotFound", "dupPathname", "volumeFull", "volDirFull", "badFileFormat", "badStoreType", "eofEncountered", "outOfRange", "invalidAccess", "buffTooSmall", // 0x50 "fileBusy", "dirError", "unknownVol", "paramRangeErr", "outOfMem", "", "badBufferAddress", /* P8 MLI only */ "dupVolume", "notBlockDev", "invalidLevel", "damagedBitMap", "badPathNames", "notSystemFile", "osUnsupported", "", "stackOverflow", // 0x60 "dataUnavail", "endOfDir", "invalidClass", "resForkNotFound", "invalidFSTID", "invalidFSTop", "fstCaution", "devNameErr", "defListFull", "supListFull", "fstError", "", "", "", "", "", //0x70 "resExistsErr", "resAddErr", "", "", "", "", "", "", "", "", "", "", "", "", "", "", //0x80 "", "", "", "", "", "", "", "", "networkError" }; if (error < sizeof(errors) / sizeof(errors[0])) return errors[error]; return ""; } /* * File info. */ static int hex(byte c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c + 10 - 'a'; if (c >= 'A' && c <= 'F') return c + 10 - 'A'; return 0; } int host_finder_info_to_filetype(const byte *buffer, word16 *file_type, word32 *aux_type) { if (!memcmp("pdos", buffer + 4, 4)) { if (buffer[0] == 'p') { *file_type = buffer[1]; *aux_type = (buffer[2] << 8) | buffer[3]; return 0; } if (!memcmp("PSYS", buffer, 4)) { *file_type = 0xff; *aux_type = 0x0000; return 0; } if (!memcmp("PS16", buffer, 4)) { *file_type = 0xb3; *aux_type = 0x0000; return 0; } // old mpw method for encoding. if (!isxdigit(buffer[0]) && isxdigit(buffer[1]) && buffer[2] == ' ' && buffer[3] == ' ') { *file_type = (hex(buffer[0]) << 8) | hex(buffer[1]); *aux_type = 0; return 0; } } if (!memcmp("TEXT", buffer, 4)) { *file_type = 0x04; *aux_type = 0x0000; return 0; } if (!memcmp("BINA", buffer, 4)) { *file_type = 0x00; *aux_type = 0x0000; return 0; } if (!memcmp("dImgdCpy", buffer, 8)) { *file_type = 0xe0; *aux_type = 0x0005; return 0; } if (!memcmp("MIDI", buffer, 4)) { *file_type = 0xd7; *aux_type = 0x0000; return 0; } if (!memcmp("AIFF", buffer, 4)) { *file_type = 0xd8; *aux_type = 0x0000; return 0; } if (!memcmp("AIFC", buffer, 4)) { *file_type = 0xd8; *aux_type = 0x0001; return 0; } return -1; } int host_file_type_to_finder_info(byte *buffer, word16 file_type, word32 aux_type) { if (file_type > 0xff || aux_type > 0xffff) return -1; if (!file_type && aux_type == 0x0000) { memcpy(buffer, "BINApdos", 8); return 0; } if (file_type == 0x04 && aux_type == 0x0000) { memcpy(buffer, "TEXTpdos", 8); return 0; } if (file_type == 0xff && aux_type == 0x0000) { memcpy(buffer, "PSYSpdos", 8); return 0; } if (file_type == 0xb3 && aux_type == 0x0000) { memcpy(buffer, "PS16pdos", 8); return 0; } if (file_type == 0xd7 && aux_type == 0x0000) { memcpy(buffer, "MIDIpdos", 8); return 0; } if (file_type == 0xd8 && aux_type == 0x0000) { memcpy(buffer, "AIFFpdos", 8); return 0; } if (file_type == 0xd8 && aux_type == 0x0001) { memcpy(buffer, "AIFCpdos", 8); return 0; } if (file_type == 0xe0 && aux_type == 0x0005) { memcpy(buffer, "dImgdCpy", 8); return 0; } memcpy(buffer, "p pdos", 8); buffer[1] = (file_type) & 0xff; buffer[2] = (aux_type >> 8) & 0xff; buffer[3] = (aux_type) & 0xff; return 0; } #undef _ #define _(a, b, c) { a, sizeof(a) - 1, b, c } struct ftype_entry { char *ext; unsigned length; unsigned file_type; unsigned aux_type; }; static struct ftype_entry suffixes[] = { _("c", 0xb0, 0x0008), _("cc", 0xb0, 0x0008), _("h", 0xb0, 0x0008), _("rez", 0xb0, 0x0015), _("asm", 0xb0, 0x0003), _("mac", 0xb0, 0x0003), _("pas", 0xb0, 0x0005), _("txt", 0x04, 0x0000), _("text", 0x04, 0x0000), _("s", 0x04, 0x0000), { 0, 0, 0, 0} }; static struct ftype_entry prefixes[] = { _("m16.", 0xb0, 0x0003), _("e16.", 0xb0, 0x0003), { 0, 0, 0, 0} }; #undef _ void host_synthesize_file_xinfo(const char *path, struct file_info *fi) { /* guess the file type / auxtype based on extension */ int n; const char *dot = NULL; const char *slash = NULL; for(n = 0;; ++n) { char c = path[n]; if (c == 0) break; else if (c == '/') { slash = path + n + 1; dot = NULL; } else if (c == '.') dot = path + n + 1; } if (dot && *dot) { for (n = 0; n < sizeof(suffixes) / sizeof(suffixes[0]); ++n) { if (!suffixes[n].ext) break; if (!strcasecmp(dot, suffixes[n].ext)) { fi->file_type = suffixes[n].file_type; fi->aux_type = suffixes[n].aux_type; return; } } } return; } void host_hexdump(word32 address, int size) { const char *HexMap = "0123456789abcdef"; char buffer1[16 * 3 + 1 + 1]; char buffer2[16 + 1]; unsigned i, j; printf("\n"); while (size > 0) { memset(buffer1, ' ', sizeof(buffer1)); memset(buffer2, ' ', sizeof(buffer2)); int linelen = size; if (linelen > 16) linelen = 16; for (i = 0, j = 0; i < linelen; i++) { unsigned x = get_memory_c(address + i, 0); buffer1[j++] = HexMap[x >> 4]; buffer1[j++] = HexMap[x & 0x0f]; j++; if (i == 7) j++; x &= 0x7f; // isascii not part of std:: and may be a macro. buffer2[i] = isascii(x) && isprint(x) ? x : '.'; } buffer1[sizeof(buffer1) - 1] = 0; buffer2[sizeof(buffer2) - 1] = 0; printf("%06x:\t%s\t%s\n", address, buffer1, buffer2); address += 16; size -= 16; } printf("\n"); } void host_hexdump_native(void *data, unsigned address, int size) { const char *HexMap = "0123456789abcdef"; char buffer1[16 * 3 + 1 + 1]; char buffer2[16 + 1]; unsigned i, j; printf("\n"); while (size > 0) { memset(buffer1, ' ', sizeof(buffer1)); memset(buffer2, ' ', sizeof(buffer2)); int linelen = size; if (linelen > 16) linelen = 16; for (i = 0, j = 0; i < linelen; i++) { unsigned x = ((byte *)data)[address + i]; buffer1[j++] = HexMap[x >> 4]; buffer1[j++] = HexMap[x & 0x0f]; j++; if (i == 7) j++; x &= 0x7f; // isascii not part of std:: and may be a macro. buffer2[i] = isascii(x) && isprint(x) ? x : '.'; } buffer1[sizeof(buffer1) - 1] = 0; buffer2[sizeof(buffer2) - 1] = 0; printf("%06x:\t%s\t%s\n", address, buffer1, buffer2); address += 16; size -= 16; } printf("\n"); } void host_free_directory(char **data, size_t count) { for (int i = 0; i < count; ++i) free(data[i]); free(data); }