diff --git a/convert.c b/convert.c deleted file mode 100644 index 20dc613..0000000 --- a/convert.c +++ /dev/null @@ -1,59 +0,0 @@ -// convert.c - Conversion helper functions. -#include "convert.h" - -#include "defs.h" -#include "mac_from_unix_data.h" - -#include -#include -#include -#include - -int convert_read(short ref, long *count, void *data) { - OSErr err; - - SpinCursor(1); - err = FSRead(ref, count, data); - switch (err) { - case noErr: - return kConvertOK; - case eofErr: - return kConvertEOF; - default: - print_errcode(err, "could not read source file"); - return kConvertError; - } -} - -int convert_write(short ref, long count, const void *data) { - OSErr err; - - SpinCursor(1); - err = FSWrite(ref, &count, data); - if (err == noErr) { - return kConvertOK; - } - print_errcode(err, "could not write temp file"); - return kConvertError; -} - -static unsigned short *gFromUnixData; - -// Get the table for converting from Unix to Macintosh. -unsigned short *mac_from_unix_data(void) { - Ptr ptr, src, dest; - - if (gFromUnixData != NULL) { - return gFromUnixData; - } - ptr = NewPtr(FROM_UNIX_DATALEN); - if (ptr == NULL) { - print_memerr(FROM_UNIX_DATALEN); - return NULL; - } - src = (void *)kFromUnixData; - dest = ptr; - UnpackBits(&src, &dest, FROM_UNIX_DATALEN); - gFromUnixData = (void *)ptr; - return gFromUnixData; -} diff --git a/convert.h b/convert.h deleted file mode 100644 index fa80d6c..0000000 --- a/convert.h +++ /dev/null @@ -1,53 +0,0 @@ -// These helper functions are written so the conversion functions can be written -// for a standard C environment without using Macintosh Toolbox functions. - -enum { - // Base size of temporary buffer for converting files, not counting the - // "extra". - kBufferBaseSize = 16 * 1024, - - // Extra space past the end of the buffer for converting files. - kBufferExtraSize = 16, - - // Total size of a buffer. - kBufferTotalSize = kBufferBaseSize + kBufferExtraSize, -}; - -// ============================================================================= -// Helper functions -// ============================================================================= - -// Result codes for convert_read and convert_write. -enum { - kConvertOK, - kConvertError, - kConvertEOF, -}; - -// Read data from a file. -int convert_read(short ref, long *count, void *data); - -// Write data to a file. -int convert_write(short ref, long count, const void *data); - -// Get the table for converting from Unix to Macintosh. -unsigned short *mac_from_unix_data(void); - -// ============================================================================= -// Conversion functions -// ============================================================================= - -// Convert Macintosh encoding with CR line endings to UTF-8 with LF. The source -// and destinations are file handles. The buffers have size buf -int mac_to_unix(short srcRef, short destRef, void *srcBuf, void *destBuf); - -// Convert UTF-8 with LF line endings to Macintosh encoding with CR. The source -// and destinations are file handles. The buffers have size kBufferTotalSize. -int mac_from_unix(short srcRef, short destRef, void *srcBuf, void *destBuf); - -// Raw data copy. -int copy_data(short srcRef, short destRef, void *buf); - -// Convert line endings but don't change encoding. -int convert_line_endings(short srcRef, short destRef, void *buf, - unsigned char srcEnding, unsigned char destEnding); diff --git a/convert_line_endings.c b/convert_line_endings.c deleted file mode 100644 index b7d01f9..0000000 --- a/convert_line_endings.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "convert.h" - -int convert_line_endings(short srcRef, short destRef, void *buf, - unsigned char srcEnding, unsigned char destEnding) { - unsigned char *ptr, *end; - long count; - int r, r2; - - do { - count = kBufferBaseSize; - r = convert_read(srcRef, &count, buf); - if (r == kConvertError) { - return 1; - } - for (ptr = buf, end = ptr + count; ptr != end; ptr++) { - if (*ptr == srcEnding) { - *ptr = destEnding; - } - } - r2 = convert_write(destRef, count, buf); - if (r2 != kConvertOK) { - return 1; - } - } while (r != kConvertEOF); - return 0; -} diff --git a/convert_test.c b/convert_test.c deleted file mode 100644 index edbe3b6..0000000 --- a/convert_test.c +++ /dev/null @@ -1,235 +0,0 @@ -#include "convert.h" - -#include -#include -#include -#include - -#include "mac_from_unix_data.h" - -static noreturn void malloc_fail(size_t sz) { - fprintf(stderr, "Error: malloc(%zu) failed\n", sz); - exit(1); -} - -static void *xmalloc(size_t sz) { - void *ptr = malloc(sz); - if (ptr == NULL) { - malloc_fail(sz); - } - return ptr; -} - -struct buf { - char *data; - size_t size; - size_t alloc; -}; - -static void buf_put(struct buf *buf, const void *data, size_t length) { - if (length > buf->alloc - buf->size) { - size_t nalloc = buf->alloc; - if (nalloc == 0) { - nalloc = 1024; - } - while (length > nalloc - buf->size) { - nalloc <<= 1; - } - void *narr = realloc(buf->data, nalloc); - if (narr == NULL) { - malloc_fail(nalloc); - } - buf->data = narr; - buf->alloc = nalloc; - } - memcpy(buf->data + buf->size, data, length); - buf->size += length; -} - -// ============================================================================= - -static unsigned short *gMacFromUnixData; - -static noreturn void bad_unpackbits(void) { - fputs("Error: invalid unpackbits data\n", stderr); - exit(1); -} - -static void unpackbits(void *dest, size_t destsz, const void *src, - size_t srcsz) { - const unsigned char *ip = src, *ie = ip + srcsz; - unsigned char *op = dest, *oe = op + destsz; - while (op < oe) { - if (ip >= ie) { - bad_unpackbits(); - } - int c = (signed char)*ip++; - if (c >= 0) { - int len = c + 1; - if (len > ie - ip || len > oe - op) { - bad_unpackbits(); - } - memcpy(op, ip, len); - op += len; - ip += len; - } else { - int len = -c + 1; - if (ip >= ie || len > oe - op) { - bad_unpackbits(); - } - memset(op, *ip, len); - op += len; - ip += 1; - } - } - if (ip != ie) { - bad_unpackbits(); - } -} - -unsigned short *mac_from_unix_data(void) { - unsigned short *ptr = gMacFromUnixData; - if (ptr == NULL) { - unsigned char *bytes = xmalloc(FROM_UNIX_DATALEN); - unpackbits(bytes, FROM_UNIX_DATALEN, kFromUnixData, - sizeof(kFromUnixData)); - ptr = xmalloc(FROM_UNIX_DATALEN); - for (int i = 0; i < FROM_UNIX_DATALEN / 2; i++) { - ptr[i] = (bytes[i * 2] << 8) | bytes[i * 2 + 1]; - } - free(bytes); - gMacFromUnixData = ptr; - } - return ptr; -} - -// ============================================================================= - -enum { - kSrcRef = 1234, - kDestRef = 5678, -}; - -static const char *gReadBuf; -static size_t gReadSize; -static size_t gReadPos; -static size_t gReadChunk; -static struct buf gWriteBuf; - -int convert_read(short ref, long *count, void *data) { - if (ref != kSrcRef) { - fputs("Wrong ref\n", stderr); - exit(1); - } - size_t amt = *count; - size_t rem = gReadSize - gReadPos; - if (amt > rem) { - amt = rem; - } - if (gReadChunk != 0 && amt > gReadChunk) { - amt = gReadChunk; - } - *count = amt; - memcpy(data, gReadBuf + gReadPos, amt); - gReadPos += amt; - if (gReadPos == gReadSize) { - return kConvertEOF; - } - return kConvertOK; -} - -int convert_write(short ref, long count, const void *data) { - if (ref != kDestRef) { - fputs("Wrong ref\n", stderr); - exit(1); - } - buf_put(&gWriteBuf, data, count); - return kConvertOK; -} - -// ============================================================================= - -enum { - kInputSize = 64 * 1024 - 2, -}; - -static char *gen_input(void) { - char *ptr = xmalloc(kInputSize); - unsigned state = 0x12345678; - for (int i = 0; i < kInputSize; i++) { - // Relatively common LCG. - state = (state * 1103515245 + 12345) & 0x7fffffff; - ptr[i] = state >> 23; - } - return ptr; -} - -int main(int argc, char **argv) { - (void)argc; - (void)argv; - - int r; - - void *sbuf = xmalloc(kBufferTotalSize); - void *dbuf = xmalloc(kBufferTotalSize); - - // Generate input. - char *input = gen_input(); - - // Convert Macintosh -> UTF-8. - gReadBuf = input; - gReadSize = kInputSize; - gReadPos = 0; - r = mac_to_unix(kSrcRef, kDestRef, sbuf, dbuf); - if (r != 0) { - fputs("mac_to_unix failed\n", stderr); - return 1; - } - - // Check that we have no CR. - { - const char *data = gWriteBuf.data; - size_t size = gWriteBuf.size; - for (size_t i = 0; i < size; i++) { - if (data[i] == 0x0d) { - fprintf(stderr, "Error: CR at offset %zu\n", i); - return 1; - } - } - } - - // Convert back. - gReadBuf = gWriteBuf.data; - gReadSize = gWriteBuf.size; - gReadPos = 0; - gWriteBuf = (struct buf){NULL, 0, 0}; - r = mac_from_unix(kSrcRef, kDestRef, sbuf, dbuf); - if (r != 0) { - fputs("mac_from_unix failed\n", stderr); - return 1; - } - - // Check that this is equal to original, except with LF changed to CR. - { - const char *data = gWriteBuf.data; - size_t size = gWriteBuf.size; - if (kInputSize != size) { - fprintf(stderr, "Error: size = %zu, expect %d\n", size, kInputSize); - return 1; - } - for (size_t i = 0; i < kInputSize; i++) { - unsigned char x = input[i]; - if (x == 0x0a) { - x = 0x0d; - } - unsigned char y = data[i]; - if (x != y) { - fprintf(stderr, "Error: data[%zu] = 0x%02x, expect 0x%02x\n", i, - y, x); - return 1; - } - } - } - - return 0; -} diff --git a/copy.c b/copy.c deleted file mode 100644 index 6d1f03f..0000000 --- a/copy.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "convert.h" - -int copy_data(short srcRef, short destRef, void *buf) { - long count; - int r, r2; - - do { - count = kBufferBaseSize; - r = convert_read(srcRef, &count, buf); - if (r == kConvertError) { - return 1; - } - r2 = convert_write(destRef, count, buf); - if (r2 != kConvertOK) { - return 1; - } - } while (r != kConvertEOF); - return 0; -} diff --git a/defs.h b/defs.h deleted file mode 100644 index dee147b..0000000 --- a/defs.h +++ /dev/null @@ -1,106 +0,0 @@ -#include - -typedef unsigned char bool; - -#define ARRAY_COUNT(x) (sizeof(x) / sizeof(*x)) - -// ============================================================================= -// util.c -// ============================================================================= - -// Message log level. -typedef enum { - kLogWarn, - kLogInfo, - kLogVerbose, -} log_level; - -// Global log verbosity. -extern log_level gLogLevel; - -// -f / -force flag: if true, all destination files are replaced, regardless of -// timestamp. -extern bool gFlagForce; - -// -n / -dry-run flag: if true, no actions are taken, but the actions are -// printed out. -extern bool gFlagDryRun; - -// -d / -delete flag: if true, destination files are deleted if there is no -// corresponding source file. -extern bool gFlagDelete; - -// Print an error message. -void print_err(const char *msg, ...); - -// Print an error message with a Macintosh toolbox error code. -void print_errcode(OSErr err, const char *msg, ...); - -// Print an out-of-memory error. -void print_memerr(unsigned long size); - -// Log the error result of a function call. -void log_call(OSErr err, const char *function); - -// Convert a C string to Pascal string. Returns nonzero on failure. -int c2pstr(unsigned char *ostr, const char *istr); - -// Convert a Pascall string (maximum 31 characters) to a C string. -void p2cstr(char *ostr, const unsigned char *istr); - -// Global operation mode -typedef enum { - kModeUnknown, - kModePush, - kModePull, -} operation_mode; - -// ============================================================================= -// file.c -// ============================================================================= - -enum { - kSrcDir, - kDestDir, -}; - -// Metadata for a file in the source or destination. -struct file_meta { - Boolean exists; - long modTime; -}; - -// An action to take for a particular file. -typedef enum { - kActionNone, // Leave file alone. - kActionNew, // Copy src to dest, dest does not exist. - kActionReplace, // Replace existing file in dest. - kActionDelete, // Delete dest file. -} file_action; - -// A general type of file. Affects the type code and conversions applied. -typedef enum { - kTypeUnknown, - kTypeText, // Text file: convert CR/LF and encoding. - kTypeTextUTF8, // Text file: convert CR/LF only. - kTypeResource, // Resource file: copy resource fork to data fork. -} file_type; - -// Information about a file present in the source or destination directory (or -// both). -struct file_info { - // Filename, Pascal string. - Str31 name; - // Metadata indexed by kSrcDir or kDestDir. - struct file_meta meta[2]; - // The action to apply to this file. - file_action action; - // The type of file. Used to select type codes and converters. - file_type type; -}; - -// Synchronize a file according to the action in the action field. The temporary -// directory must be a valid directory on the destination volume. -int sync_file(struct file_info *file, operation_mode mode, short srcVol, - long srcDir, short destVol, long destDir, short tempVol, - long tempDir); diff --git a/file.c b/file.c deleted file mode 100644 index 7d4cc6a..0000000 --- a/file.c +++ /dev/null @@ -1,345 +0,0 @@ -#include "defs.h" - -#include "convert.h" - -#include -#include - -#include - -// Make an FSSpec for a temporary file. -static int make_temp(FSSpec *temp, short vRefNum, long dirID, - const unsigned char *name) { - Str31 tname; - unsigned pfxlen, maxpfx = 31 - 4; - OSErr err; - - pfxlen = name[0]; - if (pfxlen > maxpfx) { - pfxlen = maxpfx; - } - memcpy(tname + 1, name + 1, pfxlen); - memcpy(tname + 1 + pfxlen, ".tmp", 4); - tname[0] = pfxlen + 4; - err = FSMakeFSSpec(vRefNum, dirID, tname, temp); - if (err != 0 && err != fnfErr) { - print_errcode(err, "could not create temp file spec"); - return 1; - } - return 0; -} - -// Set the modification time for a file. -static int set_modtime(FSSpec *spec, long modTime) { - CInfoPBRec ci; - Str31 name; - OSErr err; - - memset(&ci, 0, sizeof(ci)); - memcpy(name, spec->name, spec->name[0] + 1); - ci.hFileInfo.ioNamePtr = name; - ci.hFileInfo.ioVRefNum = spec->vRefNum; - ci.hFileInfo.ioDirID = spec->parID; - err = PBGetCatInfoSync(&ci); - if (err != 0) { - print_errcode(err, "could not get temp file info"); - return 1; - } - memcpy(name, spec->name, spec->name[0] + 1); - ci.hFileInfo.ioNamePtr = name; - ci.hFileInfo.ioVRefNum = spec->vRefNum; - ci.hFileInfo.ioDirID = spec->parID; - ci.hFileInfo.ioFlMdDat = modTime; - err = PBSetCatInfoSync(&ci); - if (err != 0) { - print_errcode(err, "could not set temp file info"); - return 1; - } - return 0; -} - -// Move a temp file over a destination file. This may modify the temp file spec -// if it moves in multiple stages. -static int replace_file(FSSpec *temp, FSSpec *dest, file_action action) { - HParamBlockRec pb; - CMovePBRec cm; - OSErr err; - bool mustMove, mustRename; - - // First, try to exchange files if destination exists. - if (action == kActionReplace) { - err = FSpExchangeFiles(temp, dest); - if (gLogLevel >= kLogVerbose) { - log_call(err, "FSpExchangeFiles"); - } - if (err == 0) { - err = FSpDelete(temp); - if (err != 0) { - print_errcode(err, "could not remove temporary file"); - return 1; - } - return 0; - } - // paramErr: function not supported by volume. - if (err != paramErr) { - print_errcode(err, "could not exchange files"); - return 1; - } - // Otherwise, delete destination and move temp file over. - err = FSpDelete(dest); - if (err != 0) { - print_errcode(err, "could not remove destination file"); - return 1; - } - } - - mustMove = dest->parID != temp->parID; - mustRename = memcmp(dest->name, temp->name, dest->name[0] + 1) != 0; - - // Next, try MoveRename. - if (mustMove && mustRename) { - memset(&pb, 0, sizeof(pb)); - pb.copyParam.ioNamePtr = temp->name; - pb.copyParam.ioVRefNum = temp->vRefNum; - pb.copyParam.ioNewName = dest->name; - pb.copyParam.ioNewDirID = dest->parID; - pb.copyParam.ioDirID = temp->parID; - err = PBHMoveRenameSync(&pb); - if (gLogLevel >= kLogVerbose) { - log_call(err, "PBHMoveRename"); - } - if (err == 0) { - return 0; - } - // paramErr: function not supported by volume. - if (err != paramErr) { - print_errcode(err, "could not rename temporary file"); - return 1; - } - } - - // Finally, try move and then rename. - if (mustMove) { - memset(&cm, 0, sizeof(cm)); - cm.ioNamePtr = temp->name; - cm.ioVRefNum = temp->vRefNum; - cm.ioNewDirID = dest->parID; - cm.ioDirID = temp->parID; - err = PBCatMoveSync(&cm); - if (gLogLevel >= kLogVerbose) { - log_call(err, "PBCatMove"); - } - if (err != 0) { - print_errcode(err, "could not move temporary file"); - return 1; - } - temp->parID = dest->parID; - } - if (mustRename) { - err = FSpRename(temp, dest->name); - if (gLogLevel >= kLogVerbose) { - log_call(err, "FSpRename"); - } - if (err != 0) { - print_errcode(err, "could not rename temporary file"); - return 1; - } - } - - return 0; -} - -static Ptr gSrcBuffer; -static Ptr gDestBuffer; - -int sync_file(struct file_info *file, operation_mode mode, short srcVol, - long srcDir, short destVol, long destDir, short tempVol, - long tempDir) { - OSType creator, fileType; - FSSpec src, dest, temp; - short srcRef = 0, destRef = 0; - bool has_temp = false; - int r; - OSErr err; - - // Handle actions which don't involve conversion. - if (file->action == kActionNone) { - return 0; - } - if (file->action == kActionDelete) { - err = FSMakeFSSpec(destVol, destDir, file->name, &dest); - if (err != 0) { - print_errcode(err, "could not create destination spec"); - return 1; - } - err = FSpDelete(&dest); - if (err != 0) { - print_errcode(err, "could not delete destination file"); - return 1; - } - return 0; - } - - // Create file specs. - err = FSMakeFSSpec(srcVol, srcDir, file->name, &src); - if (err != 0) { - print_errcode(err, "could not create source spec"); - return 1; - } - err = FSMakeFSSpec(destVol, destDir, file->name, &dest); - if (err != 0 && err != fnfErr) { - print_errcode(err, "could not create destination spec"); - return 1; - } - r = make_temp(&temp, tempVol, tempDir, dest.name); - if (r != 0) { - return 1; - } - - // Create the temporary file. - switch (file->type) { - case kTypeText: - case kTypeTextUTF8: - creator = 'MPS '; - fileType = 'TEXT'; - break; - case kTypeResource: - creator = 'RSED'; - fileType = 'rsrc'; - break; - default: - print_err("invalid type"); - return 1; - } - err = FSpCreate(&temp, creator, fileType, smSystemScript); - if (err == dupFNErr) { - err = FSpDelete(&temp); - if (err != 0) { - print_errcode(err, "could not delete existing temp file"); - goto error; - } - err = FSpCreate(&temp, creator, fileType, smSystemScript); - } - if (err != 0) { - print_errcode(err, "could not create file"); - goto error; - } - has_temp = true; - - // Get buffers for conversion. - if (gSrcBuffer == NULL) { - gSrcBuffer = NewPtr(kBufferTotalSize); - if (gSrcBuffer == NULL) { - print_memerr(kBufferTotalSize); - goto error; - } - } - if (gDestBuffer == NULL) { - gDestBuffer = NewPtr(kBufferTotalSize); - if (gDestBuffer == NULL) { - print_memerr(kBufferTotalSize); - goto error; - } - } - - // Open the source file for reading. - if (file->type == kTypeResource && mode == kModePush) { - err = FSpOpenRF(&src, fsRdPerm, &srcRef); - } else { - err = FSpOpenDF(&src, fsRdPerm, &srcRef); - } - if (err != 0) { - print_errcode(err, "could not open file"); - goto error; - } - if (file->type == kTypeResource && mode == kModePull) { - err = FSpOpenRF(&temp, fsRdWrPerm, &destRef); - } else { - err = FSpOpenDF(&temp, fsRdWrPerm, &destRef); - } - if (err != 0) { - print_errcode(err, "could not open temp file"); - goto error; - } - - // Convert data. - switch (file->type) { - case kTypeText: - if (mode == kModePush) { - r = mac_to_unix(srcRef, destRef, gSrcBuffer, gDestBuffer); - } else { - r = mac_from_unix(srcRef, destRef, gSrcBuffer, gDestBuffer); - } - break; - case kTypeTextUTF8: { - unsigned char srcEnding, destEnding; - if (mode == kModePush) { - srcEnding = 0x0d; - destEnding = 0x0a; - } else { - srcEnding = 0x0a; - destEnding = 0x0d; - } - r = convert_line_endings(srcRef, destRef, gSrcBuffer, srcEnding, - destEnding); - } break; - case kTypeResource: - r = copy_data(srcRef, destRef, gSrcBuffer); - break; - default: - print_err("invalid type"); - goto error; - } - if (r != 0) { - goto error; - } - - // Close files. - err = FSClose(srcRef); - srcRef = 0; - if (err != 0) { - print_errcode(err, "could not close source file"); - goto error; - } - err = FSClose(destRef); - destRef = 0; - if (err != 0) { - print_errcode(err, "could not close temp file"); - goto error; - } - - // Set modification time. - r = set_modtime(&temp, file->meta[kSrcDir].modTime); - if (r != 0) { - goto error; - } - - // Overwrite destination. - r = replace_file(&temp, &dest, file->action); - if (r != 0) { - goto error; - } - return 0; - -error: - // Clean up. - if (srcRef != 0) { - err = FSClose(srcRef); - if (err != 0) { - print_errcode(err, "could not close source file"); - } - } - if (destRef != 0) { - err = FSClose(destRef); - if (err != 0) { - print_errcode(err, "could not close destination file"); - } - } - if (has_temp) { - err = FSpDelete(&temp); - if (err != 0) { - print_errcode(err, "could not delete temp file"); - } - } - return 1; -} diff --git a/mac_from_unix.c b/mac_from_unix.c deleted file mode 100644 index e24e5e6..0000000 --- a/mac_from_unix.c +++ /dev/null @@ -1,150 +0,0 @@ -#include "convert.h" - -#include - -int mac_from_unix(short srcRef, short destRef, void *srcBuf, void *destBuf) { - unsigned char *op, *oe; // Output ptr, end. - unsigned char *ip, *ie; // Input ptr, end. - unsigned char *tmp, *curpos; - const unsigned short *table; // Conversion table. - unsigned entry, value, state, c, last, curvalue; - long count, i; - int has_eof = 0, need_input = 1, do_unput; - int lineno = 1, r; - - table = mac_from_unix_data(); - if (table == NULL) { - return 1; - } - - // Initialize buffer pointers. - ip = srcBuf; - ie = ip; - need_input = 1; - op = destBuf; - // The destination buffer has an extra byte which may be combined with a - // diacritic. - oe = op + kBufferBaseSize + 1; - - for (;;) { - if (need_input || ip >= ie) { - if (has_eof && ip == ie) { - break; - } - - // Save unprocessed input, move to beginning of buffer. - count = ie - ip; - if (count > kBufferExtraSize) { - fputs("## Internal error\n", stderr); - return 1; - } - tmp = ip; - ip = (unsigned char *)srcBuf + kBufferExtraSize - count; - for (i = 0; i < count; i++) { - ip[i] = tmp[i]; - } - - // Try to fill remainder of buffer. - count = kBufferBaseSize; - - r = convert_read(srcRef, &count, (char *)srcBuf + kBufferExtraSize); - if (r != kConvertOK) { - if (r == kConvertEOF) { - has_eof = 1; - if (count == 0) { - break; - } - } else { - return 1; - } - } - ie = (unsigned char *)srcBuf + kBufferExtraSize + count; - need_input = 0; - } - - // If output buffer has a full chunk and an extra byte, write out the - // chunk and keep the extra byte. - if (op >= oe) { - count = kBufferBaseSize; - r = convert_write(destRef, count, destBuf); - if (r != 0) { - return 1; - } - tmp = destBuf; - tmp[0] = tmp[kBufferBaseSize]; - op -= kBufferBaseSize; - } - - while (ip < ie && op < oe) { - c = *ip; - if (c < 128) { - ip++; - // Note: \r = 0x0a, \n = 0x0d on old Mac compilers. - if (c == 0x0a || c == 0x0d) { - c = 0x0d; - lineno++; - } - *op++ = c; - last = c; - } else { - // Find the longest matching Unicode character. - // curpos: ip after longest match. - // curvalue: output character after longest match. - state = table[last] & 0xff00; - if (state != 0) { - // Continue from previous character. - do_unput = 1; - curpos = ip; - curvalue = last; - } else { - // Continue with new character. - do_unput = 0; - curpos = NULL; - curvalue = 0; - } - tmp = ip; - do { - entry = table[state | *tmp++]; - state = entry & 0xff00; - value = entry & 0xff; - if (value != 0) { - curpos = tmp; - curvalue = value; - } - } while (state != 0 && tmp < ie); - if (state == 0 || has_eof) { - // We cannot consume more bytes. When state == 0, the state - // machine will not consume any more characters. When ip == - // ie && has_eof, there are no more bytes available. - if (curvalue == 0) { - fprintf(stderr, - "## Error: line %d: invalid character\n", - lineno); - return 1; - } - ip = curpos; - if (do_unput) { - op--; - } - *op++ = curvalue; - last = 0; - } else { - // We can consume more bytes. Get more, and come back. - need_input = 1; - break; - } - } - } - } - - // Write remainder of output buffer. - if (op != destBuf) { - count = op - (unsigned char *)destBuf; - r = convert_write(destRef, count, destBuf); - if (r != 0) { - return 1; - } - } - - return 0; -} diff --git a/mac_from_unix_data.h b/mac_from_unix_data.h deleted file mode 100644 index 3d7281d..0000000 --- a/mac_from_unix_data.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is automatically generated. */ -// clang-format off -#define FROM_UNIX_DATALEN 28160 -static const unsigned char kFromUnixData[1268] = { -254,0,127,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,13,0,11,0,12,1,13,0,14,0,15,0,16, -0,17,0,18,0,19,0,20,0,21,0,22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,30,0,31,0,32, -0,33,0,34,0,35,0,36,0,37,0,38,0,39,0,40,0,41,0,42,0,43,0,44,0,45,0,46,0,47,0,48, -0,49,0,50,0,51,0,52,0,53,0,54,0,55,0,56,0,57,0,58,0,59,0,60,2,61,0,62,0,63,0,64, -4,124,65,0,66,6,67,0,68,8,69,0,70,0,71,0,72,10,73,0,74,0,75,0,76,0,77,12,78,14, -79,0,80,0,81,0,82,0,83,0,84,16,85,0,86,0,87,0,88,18,89,0,90,0,91,0,92,0,93,0,94, -0,95,0,96,20,97,0,98,22,99,0,100,24,101,0,102,0,103,0,104,26,105,0,106,0,107,0, -108,0,109,28,110,30,111,0,112,0,113,0,114,0,115,0,116,32,117,0,118,0,119,0,120, -34,121,0,122,0,123,0,124,0,125,0,126,0,127,129,0,253,0,8,36,0,37,0,38,0,39,0,40, -248,0,0,41,252,0,2,42,0,43,220,0,0,44,232,0,0,52,203,0,0,13,129,0,129,0,129,0, -129,0,129,0,129,0,129,0,255,0,0,3,129,0,129,0,129,0,169,0,0,173,129,0,129,0,129, -0,129,0,219,0,0,5,129,0,129,0,153,0,6,203,0,231,0,229,0,204,248,0,0,128,254,0,0, -129,129,0,129,0,129,0,129,0,129,0,255,0,0,7,129,0,129,0,129,0,203,0,0,130,129,0, -129,0,129,0,129,0,185,0,0,9,129,0,129,0,153,0,4,233,0,131,0,230,246,0,0,232,129, -0,129,0,129,0,129,0,129,0,251,0,0,11,129,0,129,0,153,0,4,237,0,234,0,235,246,0, -0,236,129,0,129,0,129,0,129,0,129,0,251,0,0,13,129,0,129,0,147,0,0,132,129,0, -129,0,129,0,129,0,129,0,241,0,0,15,129,0,129,0,153,0,6,241,0,238,0,239,0,205, -248,0,0,133,129,0,129,0,129,0,129,0,129,0,251,0,0,17,129,0,129,0,153,0,4,244,0, -242,0,243,246,0,0,134,129,0,129,0,129,0,129,0,129,0,251,0,0,19,129,0,129,0,137, -0,0,217,129,0,129,0,129,0,129,0,129,0,251,0,0,21,129,0,129,0,153,0,6,136,0,135, -0,137,0,139,248,0,0,138,254,0,0,140,129,0,129,0,129,0,129,0,129,0,255,0,0,23, -129,0,129,0,129,0,203,0,0,141,129,0,129,0,129,0,129,0,185,0,0,25,129,0,129,0, -153,0,4,143,0,142,0,144,246,0,0,145,129,0,129,0,129,0,129,0,129,0,251,0,0,27, -129,0,129,0,153,0,4,147,0,146,0,148,246,0,0,149,129,0,129,0,129,0,129,0,129,0, -251,0,0,29,129,0,129,0,147,0,0,150,129,0,129,0,129,0,129,0,129,0,241,0,0,31,129, -0,129,0,153,0,6,152,0,151,0,153,0,155,248,0,0,154,129,0,129,0,129,0,129,0,129,0, -251,0,0,33,129,0,129,0,153,0,4,157,0,156,0,158,246,0,0,159,129,0,129,0,129,0, -129,0,129,0,251,0,0,35,129,0,129,0,137,0,0,216,129,0,129,0,129,0,129,0,210,0,6, -202,0,193,0,162,0,163,254,0,0,180,254,0,10,164,0,172,0,169,0,187,0,199,0,194, -254,0,6,168,0,248,0,161,0,177,252,0,8,171,0,181,0,166,0,225,0,252,254,0,2,188,0, -200,250,0,1,192,0,129,0,129,0,129,0,30,203,0,231,0,229,0,204,0,128,0,129,0,174, -0,130,0,233,0,131,0,230,0,232,0,237,0,234,0,235,0,236,254,0,10,132,0,241,0,238, -0,239,0,205,0,133,254,0,8,175,0,244,0,242,0,243,0,134,252,0,32,167,0,136,0,135, -0,137,0,139,0,138,0,140,0,190,0,141,0,143,0,142,0,144,0,145,0,147,0,146,0,148,0, -149,254,0,22,150,0,152,0,151,0,153,0,155,0,154,0,214,0,191,0,157,0,156,0,158,0, -159,252,0,0,216,129,0,129,0,129,0,158,0,0,245,129,0,129,0,129,0,192,0,2,206,0, -207,184,0,0,217,129,0,129,0,129,0,206,0,0,196,129,0,129,0,129,0,154,0,2,246,0, -255,224,0,10,249,0,250,0,251,0,254,0,247,0,253,129,0,129,0,129,0,129,0,234,0,0, -189,129,0,129,0,129,0,212,0,0,185,129,0,129,0,129,0,131,0,4,45,0,46,0,47,254,0, -0,48,250,0,2,49,0,50,230,0,0,51,129,0,129,0,129,0,137,0,2,208,0,209,250,0,4,212, -0,213,0,226,254,0,4,210,0,211,0,227,254,0,4,160,0,224,0,165,250,0,0,201,238,0,0, -228,240,0,2,220,0,221,129,0,129,0,129,0,238,0,0,218,129,0,129,0,129,0,129,0,178, -0,0,219,129,0,129,0,129,0,150,0,0,170,129,0,129,0,129,0,194,0,0,182,250,0,0,198, -240,0,0,184,254,0,0,183,240,0,0,195,250,0,0,176,232,0,0,186,129,0,129,0,129,0, -200,0,0,197,210,0,0,173,250,0,2,178,0,179,129,0,129,0,129,0,184,0,0,215,129,0, -129,0,129,0,129,0,209,0,0,53,240,0,0,54,129,0,129,0,129,0,129,0,219,0,0,240,129, -0,129,0,129,0,254,0,2,222,0,223,129,0,135,0, -}; diff --git a/mac_to_unix.c b/mac_to_unix.c deleted file mode 100644 index 109760e..0000000 --- a/mac_to_unix.c +++ /dev/null @@ -1,108 +0,0 @@ -#include "convert.h" - -// Table that converts Macintosh Roman characters to UTF-8, and CR to LF. -static const unsigned short kToUnixTable[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 10, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 196, 197, 199, 201, - 209, 214, 220, 225, 224, 226, 228, 227, 229, 231, 233, 232, - 234, 235, 237, 236, 238, 239, 241, 243, 242, 244, 246, 245, - 250, 249, 251, 252, 8224, 176, 162, 163, 167, 8226, 182, 223, - 174, 169, 8482, 180, 168, 8800, 198, 216, 8734, 177, 8804, 8805, - 165, 181, 8706, 8721, 8719, 960, 8747, 170, 186, 937, 230, 248, - 191, 161, 172, 8730, 402, 8776, 8710, 171, 187, 8230, 160, 192, - 195, 213, 338, 339, 8211, 8212, 8220, 8221, 8216, 8217, 247, 9674, - 255, 376, 8260, 8364, 8249, 8250, 64257, 64258, 8225, 183, 8218, 8222, - 8240, 194, 202, 193, 203, 200, 205, 206, 207, 204, 211, 212, - 63743, 210, 218, 219, 217, 305, 710, 732, 175, 728, 729, 730, - 184, 733, 731, 711, -}; - -int mac_to_unix(short srcRef, short destRef, void *srcBuf, void *destBuf) { - unsigned char *op, *oe, *tmp; // Output ptr, end. - const unsigned char *ip, *ie; // Input ptr, end. - unsigned cp; // Code point. - int r; - long count; - int has_eof = 0; - - // Initialize buffer pointers. - ip = srcBuf; - ie = ip; - op = destBuf; - oe = op + kBufferBaseSize; - - for (;;) { - // If input buffer is consumed, read more. - if (ip >= ie) { - if (has_eof) { - break; - } - count = kBufferBaseSize; - r = convert_read(srcRef, &count, srcBuf); - if (r != kConvertOK) { - if (r == kConvertEOF) { - has_eof = 1; - if (count == 0) { - break; - } - } else { - return 1; - } - } - ip = srcBuf; - ie = ip + count; - } - - // If output buffer has a full chunk, write it out. - if (op >= oe) { - count = kBufferBaseSize; - r = convert_write(destRef, count, destBuf); - if (r != 0) { - return 1; - } - tmp = destBuf; - tmp[0] = tmp[kBufferBaseSize]; - tmp[1] = tmp[kBufferBaseSize + 1]; - op -= kBufferBaseSize; - } - - // Convert as much as possible. Note that the "extra" past the end of - // the destination buffer may be used, just to simplify bounds checking. - while (ip < ie && op < oe) { - cp = kToUnixTable[*ip++]; - if (cp < 0x80) { - op[0] = cp; - op += 1; - } else if (cp < 0x400) { - op[0] = (cp >> 6) | 0xc0; - op[1] = (cp & 0x3f) | 0x80; - op += 2; - } else { - op[0] = (cp >> 12) | 0xe0; - op[1] = ((cp >> 6) & 0x3f) | 0x80; - op[2] = (cp & 0x3f) | 0x80; - op += 3; - } - } - } - - // Write remainder of output buffer. - if (op != destBuf) { - count = op - (unsigned char *)destBuf; - r = convert_write(destRef, count, destBuf); - if (r != 0) { - return 1; - } - } - - return 0; -} diff --git a/sync.c b/sync.c deleted file mode 100644 index 0faa0ff..0000000 --- a/sync.c +++ /dev/null @@ -1,429 +0,0 @@ -#include "defs.h" - -#include -#include -#include -#include -#include - -#include -#include - -log_level gLogLevel; -bool gFlagForce; -bool gFlagDryRun; -bool gFlagDelete; - -static const char *kActionName[] = { - "no action", - "new", - "replace", - "delete", -}; - -// Array of metadata entries for files. -static Handle gFiles; -static unsigned gFileCount; -static unsigned gFileAlloc; - -// Get the metadata entry for a file with the given name. -static struct file_info *get_file(const unsigned char *name) { - unsigned i, n = gFileCount, len, newAlloc; - struct file_info *file, *array; - Handle newFiles; - OSErr err; - - len = name[0]; - if (len > 31) { - fputs("## Error: name too long\n", stderr); - return NULL; - } - if (gFiles == NULL) { - newAlloc = 8; - newFiles = NewHandle(newAlloc * sizeof(struct file_info)); - err = MemError(); - if (err != noErr) { - fputs("## Error: out of memory\n", stderr); - return NULL; - } - gFiles = newFiles; - gFileAlloc = newAlloc; - } else { - array = (struct file_info *)*gFiles; - for (i = 0; i < n; i++) { - file = &array[i]; - if (memcmp(file->name, name, len + 1) == 0) { - return file; - } - } - if (n >= gFileAlloc) { - newAlloc = n * 2; - SetHandleSize(gFiles, newAlloc * sizeof(struct file_info)); - err = MemError(); - if (err != noErr) { - fputs("## Error: out of memory\n", stderr); - return NULL; - } - gFileAlloc = newAlloc; - } - } - array = (struct file_info *)*gFiles; - file = &array[n]; - gFileCount = n + 1; - memset(file, 0, sizeof(*file)); - memcpy(file->name, name, len + 1); - return file; -} - -// Get the volume and directory ID for a directory from its path. -static int dir_from_path(short *vRefNum, long *dirID, const char *dirpath) { - Str255 ppath; - FSSpec spec; - CInfoPBRec ci; - OSErr err; - - if (c2pstr(ppath, dirpath)) { - return 1; - } - err = FSMakeFSSpec(0, 0, ppath, &spec); - if (err != 0) { - if (err == fnfErr) { - print_err("does not exist: %s", dirpath); - } else { - print_errcode(err, "FSMakeFSSpec"); - } - return 1; - } - memset(&ci, 0, sizeof(ci)); - ci.dirInfo.ioNamePtr = spec.name; - ci.dirInfo.ioVRefNum = spec.vRefNum; - ci.dirInfo.ioDrDirID = spec.parID; - err = PBGetCatInfoSync(&ci); - if (err != 0) { - print_errcode(err, "PBGetCatInfoSync"); - return 1; - } - if ((ci.dirInfo.ioFlAttrib & kioFlAttribDirMask) == 0) { - print_err("not a directory: %s", dirpath); - return 1; - } - *vRefNum = ci.dirInfo.ioVRefNum; - *dirID = ci.dirInfo.ioDrDirID; - return 0; -} - -struct extension_info { - unsigned long extension; - file_type type; -}; - -// clang-format off -static const struct extension_info kExtensions1[] = { - {'c', kTypeText}, - {'h', kTypeText}, - {'r', kTypeText}, -}; - -static const struct extension_info kExtensions2[] = { - {'cc', kTypeText}, - {'cp', kTypeText}, - {'hh', kTypeText}, -}; - -static const struct extension_info kExtensions3[] = { - {'cpp', kTypeText}, - {'cxx', kTypeText}, - {'hpp', kTypeText}, - {'hxx', kTypeText}, - {'txt', kTypeText}, - {'xml', kTypeTextUTF8}, -}; - -static const struct extension_info kExtensions4[] = { - {'rsrc', kTypeResource}, -}; -// clang-format on - -static file_type file_type_from_extension(unsigned long extension, - const struct extension_info *info, - int info_count) { - int i; - for (i = 0; i < info_count; i++) { - if (extension == info[i].extension) { - return info[i].type; - } - } - return kTypeUnknown; -} - -// Get the file type for a file with the given name. -static file_type file_type_from_name(const unsigned char *name) { - int len, i, stem; - const unsigned char *ext; - - stem = 0; - len = name[0]; - for (i = 1; i <= len; i++) { - if (name[i] == '.') { - stem = i; - } - } - if (stem == 0) { - if (EqualString(name, "\pmakefile", false, true)) { - return kTypeText; - } - } - ext = name + stem + 1; - switch (len - stem) { - case 1: - return file_type_from_extension(ext[0], kExtensions1, - ARRAY_COUNT(kExtensions1)); - case 2: - return file_type_from_extension((ext[0] << 8) | ext[1], kExtensions2, - ARRAY_COUNT(kExtensions2)); - case 3: - return file_type_from_extension( - ((unsigned long)ext[0] << 16) | (ext[1] << 8) | ext[2], - kExtensions3, ARRAY_COUNT(kExtensions3)); - case 4: - return file_type_from_extension( - ((unsigned long)ext[0] << 24) | ((unsigned long)ext[1] << 16) | - (ext[2] << 8) | ext[3], - kExtensions4, ARRAY_COUNT(kExtensions4)); - } - return kTypeUnknown; -} - -// List files in a directory, filter them, and add the files matching the filter -// to the file list. The value of 'which' should be kSrcDir or kDestDir. -static int list_dir(short vRefNum, long dirID, int which) { - Str255 ppath; - CInfoPBRec ci; - struct file_info *file; - OSErr err; - int i; - file_type type; - - for (i = 1; i < 100; i++) { - memset(&ci, 0, sizeof(ci)); - ci.dirInfo.ioNamePtr = ppath; - ci.dirInfo.ioVRefNum = vRefNum; - ci.dirInfo.ioDrDirID = dirID; - ci.dirInfo.ioFDirIndex = i; - err = PBGetCatInfoSync(&ci); - if (err != 0) { - if (err == fnfErr) { - break; - } - print_errcode(err, "could not list directory"); - continue; - } - if ((ci.hFileInfo.ioFlAttrib & kioFlAttribDirMask) == 0) { - type = file_type_from_name(ppath); - if (type != kTypeUnknown) { - ppath[ppath[0] + 1] = '\0'; - file = get_file(ppath); - file->meta[which].exists = true; - file->meta[which].modTime = ci.hFileInfo.ioFlMdDat; - file->type = type; - } - } - } - - return 0; -} - -static int command_main(char *localPath, char *remotePath, - operation_mode mode) { - short localVol, remoteVol, srcVol, destVol, tempVol; - long localDir, remoteDir, srcDir, destDir, tempDir; - struct file_info *array, *file; - OSErr err; - int r, i, n; - char name[32]; - bool hasAction; - - // Get handles to local and remote directories. - if (localPath == NULL) { - err = HGetVol(NULL, &localVol, &localDir); - if (err != 0) { - print_errcode(err, "HGetVol"); - return 1; - } - } else { - r = dir_from_path(&localVol, &localDir, localPath); - if (r != 0) { - return 1; - } - } - r = dir_from_path(&remoteVol, &remoteDir, remotePath); - if (r != 0) { - return 1; - } - if (localVol == remoteVol && localDir == remoteDir) { - print_err("local and remote are the same directory"); - return 1; - } - - // Get source and destination directories. - if (mode == kModePull) { - srcVol = remoteVol; - srcDir = remoteDir; - destVol = localVol; - destDir = localDir; - } else { - srcVol = localVol; - srcDir = localDir; - destVol = remoteVol; - destDir = remoteDir; - } - - // List files in src and dest directories. - r = list_dir(srcVol, srcDir, kSrcDir); - if (r != 0) { - return 1; - } - if (gFileCount == 0) { - print_err("no files in source directory"); - return 1; - } - r = list_dir(destVol, destDir, kDestDir); - if (r != 0) { - return 1; - } - - HLock(gFiles); - array = (struct file_info *)*gFiles; - n = gFileCount; - - // Assign actions to each file. - hasAction = false; - for (i = 0; i < n; i++) { - file = &array[i]; - file->action = kActionNone; - if (!file->meta[kSrcDir].exists) { - if (gFlagDelete) { - file->action = kActionDelete; - hasAction = true; - } - } else if (!file->meta[kDestDir].exists) { - file->action = kActionNew; - hasAction = true; - } else if (gFlagForce || - file->meta[kSrcDir].modTime > file->meta[kDestDir].modTime) { - file->action = kActionReplace; - hasAction = true; - } else if (file->meta[kDestDir].modTime < - file->meta[kDestDir].modTime) { - p2cstr(name, file->name); - fprintf(stderr, "## Warning: destination file is newer: %s\n", - name); - } - } - - // Early exit if there are no actions. - if (!hasAction) { - fputs("## No actions\n", stderr); - return 0; - } - - // Print actions for a dry run. - if (gFlagDryRun) { - for (i = 0; i < n; i++) { - file = &array[i]; - p2cstr(name, file->name); - fprintf(stderr, "## %s: %s\n", kActionName[file->action], name); - } - return 0; - } - - // Synchronize the files. - InitCursorCtl(NULL); - if (mode == kModePull) { - err = - FindFolder(destVol, kTemporaryFolderType, true, &tempVol, &tempDir); - if (err != 0) { - print_errcode(err, "could not find temporary folder"); - return 1; - } - } else { - // When pushing, we use the destination directory as the temporary - // folder, to avoid crossing filesystem boundaries on the host. - tempVol = destVol; - tempDir = destDir; - } - for (i = 0; i < n; i++) { - file = &array[i]; - p2cstr(name, file->name); - if (gLogLevel >= kLogInfo) { - fprintf(stderr, "## %s: %s\n", kActionName[file->action], name); - } - SpinCursor(32); - r = sync_file(&array[i], mode, srcVol, srcDir, destVol, destDir, - tempVol, tempDir); - if (r != 0) { - print_err("failed to synchronize file: %s", name); - return 1; - } - } - - return 0; -} - -int main(int argc, char **argv) { - char *remoteDir = NULL, *localDir = NULL, *arg, *opt; - int i, r, mode = kModeUnknown; - - for (i = 1; i < argc; i++) { - arg = argv[i]; - if (*arg == '-') { - opt = arg + 1; - if (*opt == '-') { - opt++; - } - if (strcmp(opt, "push") == 0) { - mode = kModePush; - } else if (strcmp(opt, "pull") == 0) { - mode = kModePull; - } else if (strcmp(opt, "verbose") == 0 || strcmp(opt, "v") == 0) { - gLogLevel = kLogVerbose; - } else if (strcmp(opt, "quiet") == 0 || strcmp(opt, "q") == 0) { - gLogLevel = kLogWarn; - } else if (strcmp(opt, "force") == 0 || strcmp(opt, "f") == 0) { - gFlagForce = true; - } else if (strcmp(opt, "dir") == 0) { - if (i + 1 >= argc) { - print_err("expected argument for -dir"); - return 1; - } - localDir = argv[++i]; - } else if (strcmp(opt, "dry-run") == 0 || strcmp(opt, "n") == 0) { - gFlagDryRun = true; - } else if (strcmp(opt, "delete") == 0 || strcmp(opt, "d") == 0) { - gFlagDelete = true; - } else { - print_err("unknown flag: %s", arg); - return 1; - } - } else { - if (remoteDir != NULL) { - print_err("unexpected argument: %s", arg); - return 1; - } - remoteDir = arg; - } - } - if (mode == kModeUnknown) { - print_err("either -push or -pull is required"); - return 1; - } - - r = command_main(localDir, remoteDir, mode); - if (gFiles != NULL) { - DisposeHandle(gFiles); - } - if (gLogLevel >= kLogVerbose) { - fputs("## Done\n", stderr); - } - return r; -} diff --git a/util.c b/util.c deleted file mode 100644 index 894c5a2..0000000 --- a/util.c +++ /dev/null @@ -1,121 +0,0 @@ -#include "defs.h" - -#include -#include -#include - -#include -#include -#include - -void print_err(const char *msg, ...) { - va_list ap; - fputs("## Error: ", stderr); - va_start(ap, msg); - vfprintf(stderr, msg, ap); - va_end(ap); - fputc('\n', stderr); -} - -// Map from OSErr codes to messages. As a heuristic, this should include error -// codes caused by toolbox calls in this program which are readily understood by -// the user. It can exclude error codes that are likely to indicate a -// programming error. -struct error_message { - OSErr err; - const char *msg; -}; -#define E(e, m) \ - { e, m "\0" #e } -static const struct error_message kErrorMessages[] = { - E(dirFulErr, "directory full"), // -33 - E(dskFulErr, "disk full"), // -34 - E(ioErr, "I/O error"), // -36 - E(bdNamErr, "bad name"), // -37 - E(fnfErr, "file not found"), // -43 - E(wPrErr, "disk is write-protected"), // -44 - E(fLckdErr, "file is locked"), // -45 - E(vLckdErr, "volume is locked"), // -46 - E(fBsyErr, "file is busy"), // -47 - E(dupFNErr, "destination already exists"), // -48 - E(opWrErr, "file already open for writing"), // -49 - E(paramErr, "parameter error"), // -50 - E(permErr, "cannot write to locked file"), // -54 - E(dirNFErr, "directory not found"), // -120 - E(wrgVolTypErr, "not an HFS volume"), // -123 - E(diffVolErr, "files on different volumes"), // -1303 - E(afpAccessDenied, "user does not have access privileges (AFP)"), // -5000 - E(afpObjectTypeErr, - "file/directory specified where directory/file expected"), // -5025 - E(afpSameObjectErr, "objects are the same"), // -5038 -}; -#undef E - -// Return the error message for a Macintosh toolbox error code. Returns NULL if -// the error is not known. -static const char *mac_strerror(OSErr err) { - int i, n = sizeof(kErrorMessages) / sizeof(*kErrorMessages); - for (i = 0; i < n; i++) { - if (kErrorMessages[i].err == err) { - return kErrorMessages[i].msg; - } - } - return NULL; -} - -void print_errcode(OSErr err, const char *msg, ...) { - va_list ap; - const char *emsg; - - fputs("## Error: ", stderr); - va_start(ap, msg); - vfprintf(stderr, msg, ap); - va_end(ap); - emsg = mac_strerror(err); - if (emsg != NULL) { - fprintf(stderr, ": %s (%d)\n", emsg, err); - } else { - fprintf(stderr, ": err=%d\n", err); - } -} - -void print_memerr(unsigned long size) { - OSErr err; - - err = MemError(); - print_errcode(err, "out of memory; size=%lu", size); -} - -void log_call(OSErr err, const char *function) { - const char *emsg; - - if (err == 0) { - fprintf(stderr, "## %s: noErr\n", function); - return; - } - emsg = mac_strerror(err); - if (emsg != NULL) { - emsg += strlen(emsg) + 1; - fprintf(stderr, "## %s: %s (%d)\n", function, emsg, err); - } else { - fprintf(stderr, "## %s: %d\n", function, err); - } -} - -int c2pstr(Str255 ostr, const char *istr) { - size_t n = strlen(istr); - if (n > 255) { - print_err("path too long: %s", istr); - return 1; - } - ostr[0] = n; - memcpy(ostr + 1, istr, n); - memset(ostr + 1 + n, 0, 255 - n); - return 0; -} - -void p2cstr(char *ostr, const unsigned char *istr) { - unsigned len = istr[0]; - memcpy(ostr, istr + 1, len); - ostr[len] = '\0'; -}