jcs
/subtext
/amendments
/51
util: Sync with files from Amend
jcs made amendment 51 over 2 years ago
--- util.c Tue Jan 4 13:56:08 2022
+++ 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
@@ -25,6 +25,7 @@
#define ASK_ALERT_ID 130
#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
@@ -37,15 +38,22 @@ static char alert_ditl[] = {
0x00, 0x0A, 0x00, 0x2A, 0x00, 0x2A, 0xA0, 0x02,
0x00, 0x02
};
-static Handle alert_ditl_h;
+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 = NULL;
static TEHandle track_control_te = NULL;
void vwarn(short alert_func, const char *format, va_list ap);
@@ -60,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;
}
@@ -82,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;
}
@@ -93,7 +101,7 @@ 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;
}
@@ -104,7 +112,7 @@ xmallocarray(size_t nmemb, size_t size)
{
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size)
- err(2, "xmallocarray");
+ panic("xmallocarray");
return xmalloc(size * nmemb);
}
@@ -115,7 +123,7 @@ xreallocarray(void *optr, size_t nmemb, size_t size)
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size)
- err(2, "xreallocarray");
+ panic("xreallocarray");
return xrealloc(optr, size * nmemb);
}
@@ -128,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;
}
@@ -178,24 +185,24 @@ ordinal(unsigned short n)
}
}
-/*
- * BSD err(3) and warn(3) functions, must call err_init() before using
- */
-
-void
-err_init(void)
+static char ostype_s[5];
+
+char *
+OSTypeToString(OSType type)
{
- if (!(err_str = NewHandle(ERROR_STRING_SIZE))) {
- SysBeep(20);
- ExitToShell();
- }
+ 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;
- alert_ditl_h = xNewHandle(sizeof(alert_ditl));
- HLock(alert_ditl_h);
- memcpy(*alert_ditl_h, alert_ditl, sizeof(alert_ditl));
- HUnlock(alert_ditl_h);
+ return ostype_s;
}
+/*
+ * BSD err(3) and warn(3) functions
+ */
+
void
vwarn(short alert_func, const char *format, va_list ap)
{
@@ -207,10 +214,7 @@ vwarn(short alert_func, const char *format, va_list ap
GetPort(&win);
- if (err_str == NULL)
- err_init();
- HLock(err_str);
- vsnprintf(*err_str, ERROR_STRING_SIZE, format, ap);
+ vsnprintf(err_str, ERROR_STRING_SIZE, format, ap);
width = 300;
height = 100;
@@ -220,8 +224,13 @@ vwarn(short alert_func, const char *format, va_list ap
((screenBits.bounds.bottom - height) / 2.5);
bounds.bottom = bounds.top + height;
- ParamText(CtoPstr(*err_str), "\p", "\p", "\p");
-
+ 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);
@@ -249,9 +258,8 @@ vwarn(short alert_func, const char *format, va_list ap
break;
}
DisposDialog(dialog);
-
- HUnlock(err_str);
-
+ DisposHandle(alert_ditl_h);
+
SetPort(win);
if (quit)
@@ -322,22 +330,62 @@ 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
*/
@@ -360,16 +408,16 @@ xorshift32(void)
*/
Handle
-xNewHandle(unsigned long size)
+xNewHandle(size_t size)
{
Handle h;
- if (size < 1)
- err(1, "Bogus xNewHandle size %lu", size);
+ 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;
}
@@ -381,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;
}
@@ -393,97 +441,62 @@ 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;
}
-void
-xSetHandleSize(Handle h, Size s)
-{
- SetHandleSize(h, s);
- if (MemError())
- err(1, "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)
+xGetStringAsChar(short id)
{
- Point pt = { 75, 75 };
- SFReply reply;
- HParamBlockRec hpbr;
- Str63 fName = { 0 };
- char *ret = NULL;
+ StringHandle h = xGetString(id);
+ char *out;
+ size_t l;
- 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));
- }
+ HLock(h);
- getpath(reply.vRefNum, reply.fName, &ret, true);
+ l = (*h)[0];
+ out = xmalloc(l + 1);
+ memcpy((void *)out, (void *)(*h + 1), l);
+ out[l] = '\0';
- return ret;
+ DisposHandle(h);
+ return out;
}
-pascal short
-open_dialog_hook(short theItem, DialogPtr theDialog)
+long
+xGetStringAsLong(short id)
{
- short item_type;
- Handle item;
- Rect item_rect;
- Point mouse;
+ char *c;
+ long r;
- if (theItem == sfHookOpenFolder) {
- GetDItem(theDialog, getOpen, &item_type, &item, &item_rect);
- GetMouse(&mouse);
-
- if (PtInRect(mouse, &item_rect)) {
- /* clicked open */
- return getOpen;
- }
- }
-
- return theItem;
+ c = xGetStringAsChar(id);
+ r = atol(c);
+ free(c);
+ return r;
}
+void
+xSetHandleSize(Handle h, Size s)
+{
+ SetHandleSize(h, s);
+ if (MemError())
+ panic("Failed to SetHandleSize to %ld", s);
+}
+
+/*
+ * Filesystem utilities
+ */
+
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;
@@ -521,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);
}
}
@@ -540,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;
@@ -579,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 */
@@ -594,6 +617,122 @@ is_dir(char *path)
return false;
}
+OSErr
+copy_file(Str255 source, Str255 dest, bool overwrite)
+{
+ FInfo fi;
+ IOParam pb;
+ short error, source_ref, dest_ref;
+
+ /* copy data fork */
+
+ error = GetFInfo(source, 0, &fi);
+ if (error)
+ return error;
+
+ error = Create(dest, 0, fi.fdCreator, fi.fdType);
+ if (error == dupFNErr && overwrite) {
+ error = FSDelete(dest, 0);
+ if (error)
+ return error;
+ error = Create(dest, 0, fi.fdCreator, fi.fdType);
+ }
+ if (error)
+ return error;
+
+ 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) {
+ FSClose(source_ref);
+ return error;
+ }
+
+ error = copy_file_contents(source_ref, dest_ref);
+
+ FSClose(source_ref);
+ FSClose(dest_ref);
+
+ if (error)
+ return error;
+
+ /*
+ * Copy resource fork, open source as shared read/write in case it's
+ * 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()) {
+ FSClose(source_ref);
+ return ResError();
+ }
+ error = OpenRF(dest, 0, &dest_ref);
+ if (error) {
+ FSClose(source_ref);
+ return error;
+ }
+
+ error = copy_file_contents(source_ref, dest_ref);
+
+ FSClose(source_ref);
+ FSClose(dest_ref);
+
+ return error;
+}
+
+OSErr
+copy_file_contents(short source_ref, short dest_ref)
+{
+ char buf[1024];
+ short error;
+ long source_size, count;
+
+ GetEOF(source_ref, &source_size);
+ error = SetFPos(source_ref, fsFromStart, 0);
+ if (error)
+ return error;
+ error = SetEOF(dest_ref, source_size);
+ if (error)
+ return error;
+ error = SetFPos(dest_ref, fsFromStart, 0);
+ if (error)
+ return error;
+ while (source_size > 0) {
+ count = sizeof(buf);
+ if (count > source_size)
+ count = source_size;
+ error = FSRead(source_ref, &count, &buf);
+ if (error && error != eofErr)
+ break;
+ source_size -= count;
+ error = FSWrite(dest_ref, &count, &buf);
+ if (error && error != eofErr)
+ break;
+ }
+
+ if (error && error != eofErr)
+ return error;
+
+ return 0;
+}
+
/* read a \r-terminated line or the final non-line bytes of an open file */
OSErr
FSReadLine(short frefnum, char *buf, size_t buflen)
@@ -724,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 Sat Dec 25 21:21:12 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
@@ -72,15 +72,10 @@ short getline(char *str, size_t len, char **ret);
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);
-#if 0
-/* from strnatcmp.c */
-int strnatcmp(char const *a, char const *b);
-int strnatcasecmp(char const *a, char const *b);
-#endif
+char *OSTypeToString(OSType type);
unsigned long xorshift32(void);
-void err_init(void);
void panic(const char *format, ...);
void err(short ret, const char *format, ...);
void warnx(const char *format, ...);
@@ -89,22 +84,22 @@ 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);
+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);
short FontHeight(short font_id, short size);