jcs
/amend
/amendments
/41
util: Lots of changes from other projects
Make all filesystem functions work on Str255s for filenames, not
char *s
Make vwarn() (and new progress() function) use new hard-coded DITLs
to avoid needing to have these in every project's resource fork
Use panic() instead of err(1, ...)
jcs made amendment 41 over 3 years ago
--- util.c Thu Dec 30 16:39:45 2021
+++ util.c Mon Jan 10 22:12:47 2022
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021 joshua stein <jcs@jcs.org>
+ * Copyright (c) 2020-2022 joshua stein <jcs@jcs.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -22,18 +22,38 @@
#include "util.h"
/* ALRT resources */
-#define ERROR_ALERT_ID 129
#define ASK_ALERT_ID 130
-#define ERROR_STRING_SIZE 1024
+#define ERROR_STRING_SIZE 1024
+static char err_str[ERROR_STRING_SIZE];
+/* basic DITL with an ok button (1), text area (2), and icon (3) */
+#define ALERT_DITL_ICON 3
+static char alert_ditl[] = {
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46,
+ 0x00, 0xE6, 0x00, 0x5A, 0x01, 0x20, 0x04, 0x02,
+ 0x4F, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
+ 0x00, 0x32, 0x00, 0x40, 0x01, 0x21, 0x08, 0x02,
+ 0x5E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
+ 0x00, 0x0A, 0x00, 0x2A, 0x00, 0x2A, 0xA0, 0x02,
+ 0x00, 0x02
+};
+static Handle alert_ditl_h = NULL;
+
+static char progress_ditl[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14,
+ 0x00, 0x1E, 0x00, 0x32, 0x01, 0x3B, 0x08, 0x02,
+ 0x5E, 0x30
+};
+static Handle progress_ditl_h = NULL;
+static DialogPtr progress_dialog = NULL;
+
enum {
STOP_ALERT,
CAUTION_ALERT,
NOTE_ALERT
};
-Handle err_str;
static TEHandle track_control_te = NULL;
void vwarn(short alert_func, const char *format, va_list ap);
@@ -48,10 +68,10 @@ xmalloc(size_t size)
void *ptr;
if (size == 0)
- err(2, "xmalloc: zero size");
+ panic("xmalloc: zero size");
ptr = malloc(size);
if (ptr == NULL)
- err(2, "xmalloc: allocating %zu bytes", size);
+ panic("xmalloc: allocating %zu bytes", size);
return ptr;
}
@@ -70,7 +90,7 @@ xcalloc(size_t nmemb, size_t size)
ptr = calloc(nmemb, size);
if (ptr == NULL)
- err(2, "xcalloc: allocating %zu * %zu bytes", nmemb, size);
+ panic("xcalloc: allocating %zu * %zu bytes", nmemb, size);
return ptr;
}
@@ -81,25 +101,30 @@ xrealloc(void *src, size_t size)
ret = realloc(src, size);
if (ret == NULL)
- err(2, "Couldn't realloc %lu bytes of memory", size);
+ panic("Couldn't realloc %lu bytes of memory", size);
return ret;
}
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
void *
+xmallocarray(size_t nmemb, size_t size)
+{
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && SIZE_MAX / nmemb < size)
+ panic("xmallocarray");
+ return xmalloc(size * nmemb);
+}
+
+void *
xreallocarray(void *optr, size_t nmemb, size_t size)
{
void *new_ptr;
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
- nmemb > 0 && SIZE_MAX / nmemb < size) {
- err(2, "reallocarray");
- }
- if ((new_ptr = realloc(optr, size * nmemb)) == NULL)
- err(2, "realloc");
-
- return new_ptr;
+ nmemb > 0 && SIZE_MAX / nmemb < size)
+ panic("xreallocarray");
+ return xrealloc(optr, size * nmemb);
}
char *
@@ -111,8 +136,7 @@ xstrdup(const char *str)
len = strlen(str);
cp = xmalloc(len + 1);
- strncpy(cp, str, len);
- cp[len] = '\0';
+ strlcpy(cp, str, len + 1);
return cp;
}
@@ -139,48 +163,103 @@ getline(char *str, size_t len, char **ret)
return 0;
}
-/*
- * BSD err(3) and warn(3) functions, must call err_init() before using
- */
-
-void
-err_init(void)
+const char *
+ordinal(unsigned short n)
{
- if (!(err_str = NewHandle(ERROR_STRING_SIZE))) {
- SysBeep(20);
- ExitToShell();
+ switch (n % 100) {
+ case 11:
+ case 12:
+ case 13:
+ return "th";
+ default:
+ switch (n % 10) {
+ case 1:
+ return "st";
+ case 2:
+ return "nd";
+ case 3:
+ return "rd";
+ default:
+ return "th";
+ }
}
}
+static char ostype_s[5];
+
+char *
+OSTypeToString(OSType type)
+{
+ ostype_s[0] = (unsigned char)((type >> 24) & 0xff);
+ ostype_s[1] = (unsigned char)((type >> 16) & 0xff);
+ ostype_s[2] = (unsigned char)((type >> 8) & 0xff);
+ ostype_s[3] = (unsigned char)(type & 0xff);
+ ostype_s[4] = 0;
+
+ return ostype_s;
+}
+
+/*
+ * BSD err(3) and warn(3) functions
+ */
+
void
vwarn(short alert_func, const char *format, va_list ap)
{
- size_t len;
- short quit = 0;
- WindowPtr win;
+ Rect bounds, irect;
+ short quit = 0, height, width, hit;
+ WindowPtr win, dialog;
+ OSType itype;
+ Handle ihandle;
GetPort(&win);
- HLock(err_str);
- len = vsprintf(*err_str, format, ap);
- if (len >= ERROR_STRING_SIZE) {
- sprintf(*err_str, "raise_error string overflow!");
- quit = 1;
- }
+ vsnprintf(err_str, ERROR_STRING_SIZE, format, ap);
- ParamText(CtoPstr(*err_str), "\p", "\p", "\p");
+ width = 300;
+ height = 100;
+ bounds.left = (screenBits.bounds.right - width) / 2;
+ bounds.right = bounds.left + width;
+ bounds.top = GetMBarHeight() +
+ ((screenBits.bounds.bottom - height) / 2.5);
+ bounds.bottom = bounds.top + height;
+
+ ParamText(CtoPstr(err_str), "\p", "\p", "\p");
+
+ alert_ditl_h = xNewHandle(sizeof(alert_ditl));
+ HLock(alert_ditl_h);
+ memcpy(*alert_ditl_h, alert_ditl, sizeof(alert_ditl));
+ HUnlock(alert_ditl_h);
+
+ dialog = NewDialog(nil, &bounds, "\p", false, dBoxProc,
+ (WindowPtr)-1L, false, 0, alert_ditl_h);
+
+#if 0
+ /* XXX: why doesn't changing this work? */
+ GetDItem(dialog, ALERT_DITL_ICON, &itype, &ihandle, &irect);
switch (alert_func) {
case CAUTION_ALERT:
- CautionAlert(ERROR_ALERT_ID, nil);
+ ihandle = GetIcon(cautionIcon);
break;
case NOTE_ALERT:
- NoteAlert(ERROR_ALERT_ID, nil);
+ ihandle = GetIcon(noteIcon);
break;
default:
- StopAlert(ERROR_ALERT_ID, nil);
+ ihandle = GetIcon(stopIcon);
}
- HUnlock(err_str);
-
+ ihandle = GetIcon(cautionIcon);
+ SetDItem(dialog, ALERT_DITL_ICON, itype, ihandle, &irect);
+#endif
+
+ ShowWindow(dialog);
+ for (;;) {
+ ModalDialog(0, &hit);
+ if (hit == ok)
+ break;
+ }
+ DisposDialog(dialog);
+ DisposHandle(alert_ditl_h);
+
SetPort(win);
if (quit)
@@ -188,35 +267,47 @@ vwarn(short alert_func, const char *format, va_list ap
}
void
-warn(const char *format, ...)
+panic(const char *format, ...)
{
va_list ap;
va_start(ap, format);
- vwarn(CAUTION_ALERT, format, ap);
+ vwarn(STOP_ALERT, format, ap);
va_end(ap);
+
+ ExitToShell();
}
void
-warnx(const char *format, ...)
+err(short ret, const char *format, ...)
{
va_list ap;
va_start(ap, format);
+ vwarn(STOP_ALERT, format, ap);
+ va_end(ap);
+
+ ExitToShell();
+}
+
+void
+warn(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
vwarn(CAUTION_ALERT, format, ap);
va_end(ap);
}
void
-err(short retcode, const char *format, ...)
+warnx(const char *format, ...)
{
va_list ap;
va_start(ap, format);
- vwarn(STOP_ALERT, format, ap);
+ vwarn(CAUTION_ALERT, format, ap);
va_end(ap);
-
- ExitToShell();
}
void
@@ -239,34 +330,94 @@ ask(const char *format, ...)
GetPort(&win);
- HLock(err_str);
va_start(ap, format);
- len = vsprintf(*err_str, format, ap);
+ len = vsnprintf(err_str, ERROR_STRING_SIZE, format, ap);
va_end(ap);
- if (len >= ERROR_STRING_SIZE)
- err(1, "ask string overflow!");
- ParamText(CtoPstr(*err_str), "\p", "\p", "\p");
+ ParamText(CtoPstr(err_str), "\p", "\p", "\p");
ret = StopAlert(ASK_ALERT_ID, nil);
- HUnlock(err_str);
SetPort(win);
return ret;
}
+void
+progress(char *format, ...)
+{
+ static Str255 progress_s;
+ Handle thandle;
+ va_list argptr;
+ Rect bounds = { 100, 90, 160, 420 }; /* tlbr */
+ Rect trect;
+ static WindowPtr progress_win;
+ short ttype;
+ if (format == NULL) {
+ if (progress_dialog != NULL) {
+ DisposDialog(progress_dialog);
+ DisposHandle(progress_ditl_h);
+ progress_dialog = NULL;
+ }
+ SetPort(progress_win);
+ return;
+ }
+
+ va_start(argptr, format);
+ vsnprintf((char *)progress_s, 256, format, argptr);
+ va_end(argptr);
+ CtoPstr(progress_s);
+
+ if (progress_dialog == NULL) {
+ GetPort(&progress_win);
+
+ progress_ditl_h = xNewHandle(sizeof(progress_ditl));
+ HLock(progress_ditl_h);
+ memcpy(*progress_ditl_h, progress_ditl, sizeof(progress_ditl));
+ HUnlock(progress_ditl_h);
+
+ progress_dialog = NewDialog(nil, &bounds, "\p", false, dBoxProc,
+ (WindowPtr)-1L, false, 0, progress_ditl_h);
+ }
+
+ GetDItem(progress_dialog, 1, &ttype, &thandle, &trect);
+ SetIText(thandle, progress_s);
+
+ ShowWindow(progress_dialog);
+ DrawDialog(progress_dialog);
+}
+
/*
+ * General Mac-specific non-GUI functions
+ */
+static unsigned long _xorshift_state = 0;
+unsigned long
+xorshift32(void)
+{
+ unsigned long x = _xorshift_state;
+ if (x == 0)
+ x = Ticks;
+ x ^= x << 13;
+ x ^= x >> 17;
+ x ^= x << 5;
+ return _xorshift_state = x;
+}
+
+
+/*
* Error checking wrappers for Mac toolkit functions
*/
Handle
-xNewHandle(unsigned long size)
+xNewHandle(size_t size)
{
Handle h;
+ if (size == 0)
+ panic("Zero xNewHandle size");
+
h = NewHandle(size);
if (h == NULL)
- err(1, "Failed to NewHandle(%lu)", size);
+ panic("Failed to NewHandle(%lu)", size);
return h;
}
@@ -278,7 +429,7 @@ xGetResource(ResType type, short id)
h = GetResource(type, id);
if (h == NULL)
- err(1, "Failed to find resource %d", id);
+ panic("Failed to find resource %d", id);
return h;
}
@@ -290,7 +441,7 @@ xGetString(short id)
h = GetString(id);
if (h == NULL)
- err(1, "Failed to find STR resource %d", id);
+ panic("Failed to find STR resource %d", id);
return h;
}
@@ -325,84 +476,27 @@ xGetStringAsLong(short id)
return r;
}
+void
+xSetHandleSize(Handle h, Size s)
+{
+ SetHandleSize(h, s);
+ if (MemError())
+ panic("Failed to SetHandleSize to %ld", s);
+}
+
/*
* Filesystem utilities
*/
-/*
- * With SFGetFile, when the user has a folder selected and clicks Open,
- * File Manager will change to the folder and expect the user to select a
- * file in it. This triggers sfHookOpenFolder, but when the user double-
- * clicks on a folder to browse into it, the same result code is returned.
- *
- * To be able to return the folder itself, we need to know whether the user
- * double-clicked a folder, or clicked Open. When we get our hook callback,
- * we check where the mouse is in relation to the Open button rect. If
- * the user clicked Open, we return the folder itself, otherwise we assume
- * the user double-clicked a folder and we should browse into it.
- *
- * Finally, we return the full path of the file/folder as a char *, rather
- * than just a ref id.
- */
-char *
-askfileordirpath(void)
-{
- Point pt = { 75, 75 };
- SFReply reply;
- HParamBlockRec hpbr;
- Str63 fName = { 0 };
- char *ret = NULL;
-
- SFGetFile(pt, "\p", NULL, -1, 0, open_dialog_hook, &reply);
- if (!reply.good)
- return NULL;
-
- if (reply.fName[0] == 0) {
- /* selected a folder, look it up */
- hpbr.fileParam.ioCompletion = 0;
- hpbr.fileParam.ioNamePtr = (StringPtr)&fName;
- hpbr.fileParam.ioVRefNum = reply.vRefNum;
- hpbr.fileParam.ioDirID = reply.fType;
- hpbr.fileParam.ioFDirIndex = -1;
- PBGetCatInfo(&hpbr, false);
- memcpy(reply.fName, fName, sizeof(fName));
- }
-
- getpath(reply.vRefNum, reply.fName, &ret, true);
-
- return ret;
-}
-
-pascal short
-open_dialog_hook(short theItem, DialogPtr theDialog)
-{
- short item_type;
- Handle item;
- Rect item_rect;
- Point mouse;
-
- if (theItem == sfHookOpenFolder) {
- GetDItem(theDialog, getOpen, &item_type, &item, &item_rect);
- GetMouse(&mouse);
-
- if (PtInRect(mouse, &item_rect)) {
- /* clicked open */
- return getOpen;
- }
- }
-
- return theItem;
-}
-
short
-getpath(short vRefNum, Str255 fileName, char **ret, bool include_file)
+getpath(short vRefNum, Str255 fileName, Str255 *ret, bool include_file)
{
WDPBRec wdir;
HVolumeParam wvol;
DirInfo wcinfo;
Str255 name;
- size_t retlen = 0;
- char *tmp;
+ size_t retlen = 0, len;
+ char tmpret[256], tmp[256];
wdir.ioVRefNum = wdir.ioWDVRefNum = vRefNum;
wdir.ioWDIndex = 0;
@@ -440,17 +534,14 @@ getpath(short vRefNum, Str255 fileName, char **ret, bo
if (PBGetCatInfo((CInfoPBPtr)&wcinfo, 0) != noErr)
break;
+ len = name[0];
+ PtoCstr(name);
if (retlen == 0) {
- retlen = name[0];
- *ret = xmalloc(retlen + 1);
- sprintf(*ret, "%s", PtoCstr(name));
+ retlen = len;
+ strlcpy(tmpret, (char *)name, sizeof(tmpret));
} else {
- tmp = xstrdup(*ret);
- free(*ret);
- *ret = xmalloc(retlen + 1 + name[0] + 1);
- retlen += 1 + name[0];
- sprintf(*ret, "%s:%s", PtoCstr(name), tmp);
- free(tmp);
+ strlcpy(tmp, tmpret, sizeof(tmp));
+ snprintf(tmpret, sizeof(tmpret), "%s:%s", name, tmp);
}
}
@@ -459,31 +550,44 @@ getpath(short vRefNum, Str255 fileName, char **ret, bo
memcpy(name, fileName, sizeof(name));
PtoCstr(name);
if (retlen == 0)
- *ret = xstrdup((char *)name);
+ strlcpy(tmpret, (char *)name, sizeof(tmpret));
else {
- *ret = xrealloc(*ret, retlen + 1 + fileName[0] + 1);
- sprintf(*ret + retlen, ":%s", (char *)name);
+ strlcat(tmpret, ":", sizeof(tmpret));
+ strlcat(tmpret, (char *)name, sizeof(tmpret));
}
} else if (retlen == 0) {
- *ret = NULL;
+ (*ret)[0] = 0;
+ return 0;
}
+ CtoPstr(tmpret);
+ memcpy(*ret, tmpret, sizeof(tmpret));
+
return 0;
}
short
-stat(const char *path, struct stat *sb)
+stat(char *path, struct stat *sb)
{
- CInfoPBRec catblock = { 0 };
+ char *ppath;
short ret;
- char *tpath;
- tpath = xstrdup(path);
- CtoPstr(tpath);
+ ppath = xstrdup(path);
+ CtoPstr(ppath);
+ ret = FStat((unsigned char *)ppath, sb);
+ free(ppath);
+
+ return ret;
+}
- catblock.hFileInfo.ioNamePtr = (StringPtr)tpath;
+short
+FStat(Str255 path, struct stat *sb)
+{
+ CInfoPBRec catblock = { 0 };
+ short ret;
+
+ catblock.hFileInfo.ioNamePtr = path;
ret = PBGetCatInfo(&catblock, 0);
- free(tpath);
if (ret != noErr)
return -1;
@@ -498,12 +602,12 @@ stat(const char *path, struct stat *sb)
}
bool
-is_dir(char *path)
+FIsDir(Str255 path)
{
struct stat st;
short ret;
- if ((ret = stat(path, &st)) != 0)
+ if ((ret = FStat(path, &st)) != 0)
return ret;
/* bit 4 is set in ioFlAttrib if the item is a directory */
@@ -514,10 +618,10 @@ is_dir(char *path)
}
OSErr
-copy_file(Str255 source, Str255 dest, bool overwrite,
- bool keep_source_open)
+copy_file(Str255 source, Str255 dest, bool overwrite)
{
FInfo fi;
+ IOParam pb;
short error, source_ref, dest_ref;
/* copy data fork */
@@ -536,21 +640,23 @@ copy_file(Str255 source, Str255 dest, bool overwrite,
if (error)
return error;
- error = FSOpen(source, 0, &source_ref);
+ memset(&pb, 0, sizeof(pb));
+ pb.ioNamePtr = source;
+ pb.ioPermssn = fsRdPerm;
+ error = PBOpen(&pb, false);
if (error)
return error;
-
+ source_ref = pb.ioRefNum;
+
error = FSOpen(dest, 0, &dest_ref);
if (error) {
- if (!keep_source_open)
- FSClose(source_ref);
+ FSClose(source_ref);
return error;
}
error = copy_file_contents(source_ref, dest_ref);
- if (!keep_source_open)
- FSClose(source_ref);
+ FSClose(source_ref);
FSClose(dest_ref);
if (error)
@@ -561,26 +667,31 @@ copy_file(Str255 source, Str255 dest, bool overwrite,
* an open resource file.
*/
source_ref = OpenRFPerm(source, 0, fsRdWrShPerm);
+
+ if (source_ref == -1 && ResError() == eofErr) {
+ /* no resource fork */
+ FSClose(source_ref);
+ FSClose(dest_ref);
+ return 0;
+ }
+
if (source_ref == -1)
return ResError();
CreateResFile(dest);
if (ResError()) {
- if (!keep_source_open)
- FSClose(source_ref);
+ FSClose(source_ref);
return ResError();
}
error = OpenRF(dest, 0, &dest_ref);
if (error) {
- if (!keep_source_open)
- FSClose(source_ref);
+ FSClose(source_ref);
return error;
}
error = copy_file_contents(source_ref, dest_ref);
- if (!keep_source_open)
- FSClose(source_ref);
+ FSClose(source_ref);
FSClose(dest_ref);
return error;
@@ -589,7 +700,7 @@ copy_file(Str255 source, Str255 dest, bool overwrite,
OSErr
copy_file_contents(short source_ref, short dest_ref)
{
- char buf[512];
+ char buf[1024];
short error;
long source_size, count;
@@ -651,6 +762,7 @@ FSReadLine(short frefnum, char *buf, size_t buflen)
return total_read;
}
+
/*
* General Mac-specific GUI functions
*/
@@ -751,7 +863,7 @@ TrackMouseDownInControl(ControlHandle control, short p
short page, val, adj, lheight;
if (track_control_te == NULL)
- err(1, "TrackMouseDownInControl without SetTrackControlTE");
+ panic("TrackMouseDownInControl without SetTrackControlTE");
lheight = TEGetHeight(0, 0, track_control_te);
--- util.h Thu Dec 30 16:24:50 2021
+++ util.h Mon Jan 10 16:40:54 2022
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021 joshua stein <jcs@jcs.org>
+ * Copyright (c) 2020-2022 joshua stein <jcs@jcs.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -25,12 +25,19 @@
#define SIZE_MAX ULONG_MAX
#endif
+#define nitems(what) (sizeof((what)) / sizeof((what)[0]))
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define BOUND(a, min, max) ((a) > (max) ? (max) : ((a) < (min) ? (min) : (a)))
+
#define SCROLLBAR_WIDTH 16
+/* GetMBarHeight() is not very useful */
+#define MENUBAR_HEIGHT 20
+
#define MAX_TEXTEDIT_SIZE 32767L
-#define nitems(what) (sizeof((what)) / sizeof((what)[0]))
-
#ifndef bool
typedef Boolean bool;
#endif
@@ -57,43 +64,43 @@ void *xmalloc(size_t);
void *xmalloczero(size_t);
void *xcalloc(size_t, size_t);
void *xrealloc(void *src, size_t size);
+void *xmallocarray(size_t nmemb, size_t size);
void *xreallocarray(void *, size_t, size_t);
char *xstrdup(const char *);
short getline(char *str, size_t len, char **ret);
-/* from strnatcmp.c */
-int strnatcmp(char const *a, char const *b);
-int strnatcasecmp(char const *a, char const *b);
+size_t strlcpy(char *dst, const char *src, size_t dsize);
+size_t strlcat(char *dst, const char *src, size_t dsize);
+const char *ordinal(unsigned short n);
+char *OSTypeToString(OSType type);
-void err_init(void);
+unsigned long xorshift32(void);
+
+void panic(const char *format, ...);
+void err(short ret, const char *format, ...);
void warnx(const char *format, ...);
void warn(const char *format, ...);
-void err(short retcode, const char *format, ...);
void note(const char *format, ...);
short ask(const char *format, ...);
#define ASK_YES 1
#define ASK_NO 2
+void progress(char *format, ...);
-Handle xNewHandle(unsigned long size);
+Handle xNewHandle(size_t size);
Handle xGetResource(ResType type, short id);
StringHandle xGetString(short id);
char *xGetStringAsChar(short id);
long xGetStringAsLong(short id);
+void xSetHandleSize(Handle h, Size s);
-char *askfileordirpath(void);
-short getpath(short vRefNum, Str255 fileName, char **ret,
+short getpath(short vRefNum, Str255 fileName, Str255 *ret,
bool include_file);
-pascal short open_dialog_hook(short theItem, DialogPtr theDialog);
-pascal Boolean open_dialog_filter(DialogPtr theDialog,
- EventRecord *theEvent, short *itemHit);
-bool is_dir(char *path);
-short stat(const char *path, struct stat *sb);
-OSErr copy_file(Str255 source, Str255 dest, bool overwrite,
- bool keep_source_open);
+bool FIsDir(Str255 path);
+short stat(char *path, struct stat *sb);
+short FStat(Str255 path, struct stat *sb);
+OSErr copy_file(Str255 source, Str255 dest, bool overwrite);
OSErr copy_file_contents(short source_ref, short dest_ref);
OSErr FSReadLine(short frefnum, char *buf, size_t buflen);
-
-Handle SetResSize(Handle res, size_t size);
short FontHeight(short font_id, short size);
void DrawGrowIconOnly(WindowPtr win);