jcs
/wallops
/amendments
/31
util: Sync with upstream, work with THINK C ANSI library
jcs made amendment 31 over 2 years ago
--- util.c Thu Feb 10 15:30:58 2022
+++ util.c Tue Sep 6 12:34:51 2022
@@ -1,5 +1,8 @@
/*
* Copyright (c) 2020-2022 joshua stein <jcs@jcs.org>
+ * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org>
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +17,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/* THINK C Project must have a header of "#include <MacHeaders>" */
+
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -31,7 +36,7 @@ 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[] = {
+static const 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,
@@ -43,7 +48,7 @@ static char alert_ditl[] = {
static Handle alert_ditl_h = NULL;
/* DITL with a Yes button (1), No button (2), text (3), and icon (4) */
-static char ask_ditl[] = {
+static const char ask_ditl[] = {
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46,
0x00, 0xE6, 0x00, 0x5A, 0x01, 0x20, 0x04, 0x03,
0x59, 0x65, 0x73, 0x21, 0x00, 0x00, 0x00, 0x00,
@@ -57,7 +62,7 @@ static char ask_ditl[] = {
static Handle ask_ditl_h = NULL;
/* DITL with just a text view */
-static char progress_ditl[] = {
+static const char progress_ditl[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14,
0x00, 0x1E, 0x00, 0x32, 0x01, 0x3B, 0x08, 0x02,
0x5E, 0x30
@@ -65,79 +70,218 @@ static char progress_ditl[] = {
static Handle progress_ditl_h = NULL;
static DialogPtr progress_dialog = NULL;
+static TEHandle track_control_te = NULL;
+
enum {
STOP_ALERT,
CAUTION_ALERT,
NOTE_ALERT
};
-static TEHandle track_control_te = NULL;
+/*
+ * Define to audit each malloc and free and verify that a pointer isn't
+ * double-freed. The list of outstanding allocations can be checked by
+ * looking through malloc_map.
+ */
+//#define MALLOC_DEBUG
+#ifdef MALLOC_DEBUG
+/*
+ * List of allocations, updated at xmalloc() and xfree(). If an address
+ * passed to xfree() isn't in the list, it indicates a double-free.
+ */
+#define MALLOC_MAP_CHUNK_SIZE 1024
+struct malloc_map_e {
+ unsigned long addr;
+ unsigned long size;
+ char note[MALLOC_NOTE_SIZE];
+} *malloc_map = NULL;
+unsigned long malloc_map_size = 0;
+static bool malloc_map_compact = false;
+#endif
+
void vwarn(short alert_func, const char *format, va_list ap);
/*
+ * Util helper needed to be called at program startup, to pre-allocate
+ * some things that we can't do during errors.
+ */
+
+void
+util_init(void)
+{
+ alert_ditl_h = xNewHandle(sizeof(alert_ditl));
+ HLock(alert_ditl_h);
+ memcpy(*alert_ditl_h, alert_ditl, sizeof(alert_ditl));
+ HUnlock(alert_ditl_h);
+
+#ifdef MALLOC_DEBUG
+ malloc_map_size = MALLOC_MAP_CHUNK_SIZE;
+ malloc_map = (struct malloc_map_e *)NewPtr(malloc_map_size *
+ sizeof(struct malloc_map_e));
+ if (malloc_map == NULL)
+ panic("NewPtr(%lu) failed", MALLOC_MAP_CHUNK_SIZE);
+ memset(malloc_map, 0, malloc_map_size);
+#endif
+}
+
+/*
* Memory functions
*/
-
+
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
void *
-xmalloc(size_t size)
+xmalloc(size_t size, char *note)
{
void *ptr;
-
+#ifdef MALLOC_DEBUG
+ struct malloc_map_e *new_malloc_map;
+ unsigned short n, j;
+#endif
+
if (size == 0)
panic("xmalloc: zero size");
- ptr = malloc(size);
+
+ ptr = NewPtr(size);
if (ptr == NULL)
panic("xmalloc(%lu) failed", size);
+
+#ifdef MALLOC_DEBUG
+ if (malloc_map_compact) {
+ for (n = 0; n < malloc_map_size; n++) {
+ if (malloc_map[n].addr != 0)
+ continue;
+
+ for (j = n + 1; j < malloc_map_size; j++) {
+ if (malloc_map[j].addr == 0)
+ continue;
+
+ malloc_map[n] = malloc_map[j];
+ memset(&malloc_map[j], 0, sizeof(struct malloc_map_e));
+ break;
+ }
+ }
+
+ malloc_map_compact = false;
+ }
+
+ for (n = 0; n <= malloc_map_size; n++) {
+ if (n == malloc_map_size) {
+ malloc_map_size += MALLOC_MAP_CHUNK_SIZE;
+ warn("xmalloc(%lu): out of malloc map entries, maybe a "
+ "memory leak, resizing to %ld", size, malloc_map_size);
+ new_malloc_map = (struct malloc_map_e *)NewPtr(
+ malloc_map_size * sizeof(struct malloc_map_e));
+ if (new_malloc_map == NULL)
+ panic("out of memory resizing malloc map");
+ memcpy(new_malloc_map, malloc_map,
+ (malloc_map_size - MALLOC_MAP_CHUNK_SIZE) *
+ sizeof(struct malloc_map_e));
+ DisposePtr(malloc_map);
+ malloc_map = new_malloc_map;
+ }
+ if (malloc_map[n].addr == 0) {
+ malloc_map[n].addr = (unsigned long)ptr;
+ malloc_map[n].size = size;
+ strlcpy(malloc_map[n].note, note, sizeof(malloc_map[n].note));
+ break;
+ }
+ n = n;
+ }
+#endif
+
return ptr;
}
+void
+xfree(void *ptrptr)
+{
+ unsigned long *addr = (unsigned long *)ptrptr;
+ void *ptr = (void *)*addr;
+#ifdef MALLOC_DEBUG
+ unsigned long n;
+
+ for (n = 0; n <= malloc_map_size; n++) {
+ if (n == malloc_map_size)
+ panic("xfree(0x%lx): can't find in alloc map, likely "
+ "double free()", *addr);
+ if (malloc_map[n].addr == *addr) {
+ malloc_map[n].addr = 0;
+ malloc_map[n].size = 0;
+ malloc_map[n].note[0] = '\0';
+ break;
+ }
+ }
+#endif
+
+ DisposePtr(ptr);
+
+ *addr = 0L;
+}
+
void *
-xmalloczero(size_t size)
+xmalloczero(size_t size, char *note)
{
- void *ptr = xmalloc(size);
+ void *ptr;
+
+ ptr = xmalloc(size, note);
memset(ptr, 0, size);
+
return ptr;
}
void *
-xcalloc(size_t nmemb, size_t size)
+xcalloc(size_t nmemb, size_t size, char *note)
{
void *ptr;
- ptr = calloc(nmemb, size);
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && SIZE_MAX / nmemb < size)
+ panic("xcalloc(%lu, %lu) overflow", nmemb, size);
+ ptr = xmalloczero(nmemb * size, note);
if (ptr == NULL)
panic("xcalloc(%lu, %lu) failed", nmemb, size);
+
return ptr;
}
void *
xrealloc(void *src, size_t size)
{
- void *ret;
+ void *ptr, *tsrc;
+ unsigned long n;
+ char note[MALLOC_NOTE_SIZE] = "realloc from null";
- ret = realloc(src, size);
- if (ret == NULL)
- panic("realloc(%lu) failed", size);
- return ret;
-}
+#ifdef MALLOC_DEBUG
+ if (src != NULL) {
+ for (n = 0; n <= malloc_map_size; n++) {
+ if (n == malloc_map_size) {
+ panic("xrealloc(%lu): can't find in alloc map, likely "
+ "double free()", (unsigned long)src);
+ return NULL;
+ }
+ if (malloc_map[n].addr == (unsigned long)src) {
+ strlcpy(note, malloc_map[n].note, sizeof(note));
+ break;
+ }
+ }
+ }
+#endif
-#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+ ptr = xmalloc(size, note);
+ if (src != NULL) {
+ memcpy(ptr, src, size);
+ tsrc = src;
+ xfree(&tsrc);
+ }
-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(%lu, %lu) failed", nmemb, size);
- return xmalloc(size * nmemb);
+ return ptr;
}
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)
panic("xreallocarray(%lu, %lu) failed", nmemb, size);
@@ -145,19 +289,38 @@ xreallocarray(void *optr, size_t nmemb, size_t size)
}
char *
-xstrdup(const char *str)
+xstrdup(const char *str, char *note)
{
char *cp;
size_t len;
len = strlen(str);
- cp = xmalloc(len + 1);
+ cp = xmalloc(len + 1, note);
strlcpy(cp, str, len + 1);
return cp;
}
+char *
+xstrndup(const char *str, size_t maxlen, char *note)
+{
+ char *copy;
+ const char *cp;
+ size_t len;
+
+ /* strnlen */
+ for (cp = str; maxlen != 0 && *cp != '\0'; cp++, maxlen--)
+ ;
+
+ len = (size_t)(cp - str);
+ copy = xmalloc(len + 1, note);
+ (void)memcpy(copy, str, len);
+ copy[len] = '\0';
+
+ return copy;
+}
+
/*
* String functions
*/
@@ -170,7 +333,7 @@ getline(char *str, size_t len, char **ret)
for (i = 0; i < len; i++) {
if (str[i] == '\r' || i == len - 1) {
if (*ret == NULL)
- *ret = xmalloc(i + 1);
+ *ret = xmalloc(i + 1, "getline");
memcpy(*ret, str, i + 1);
(*ret)[i] = '\0';
return i + 1;
@@ -202,6 +365,30 @@ ordinal(unsigned short n)
}
}
+size_t
+rtrim(char *str, char *chars)
+{
+ size_t len, rlen, n, j;
+
+ rlen = len = strlen(str);
+
+ for (n = len; n > 0; n--) {
+ for (j = 0; chars[j] != '\0'; j++) {
+ if (str[n - 1] == chars[j]) {
+ rlen--;
+ str[n - 1] = '\0';
+ goto next_in_str;
+ }
+ }
+
+ break;
+next_in_str:
+ continue;
+ }
+
+ return rlen;
+}
+
long
strpos_quoted(char *str, char c)
{
@@ -251,31 +438,17 @@ OSTypeToString(OSType type)
void
vwarn(short alert_func, const char *format, va_list ap)
{
- Rect bounds, irect;
- short quit = 0, height, width, hit;
+ Rect bounds;
+ short hit;
WindowPtr win, dialog;
- OSType itype;
- Handle ihandle;
GetPort(&win);
vsnprintf(err_str, ERROR_STRING_SIZE, format, ap);
- 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);
-
+ center_in_screen(300, 100, false, &bounds);
dialog = NewDialog(nil, &bounds, "\p", false, dBoxProc,
(WindowPtr)-1L, false, 0, alert_ditl_h);
@@ -303,12 +476,21 @@ vwarn(short alert_func, const char *format, va_list ap
break;
}
DisposDialog(dialog);
- DisposHandle(alert_ditl_h);
- SetPort(win);
-
- if (quit)
+ /*
+ * Pre-allocate for the next one while we have memory. We can't use
+ * xNewHandle because we might already be alerting about an OOM
+ * condition.
+ */
+ DisposHandle(alert_ditl_h);
+ alert_ditl_h = NewHandle(sizeof(alert_ditl));
+ if (alert_ditl_h == NULL)
ExitToShell();
+ HLock(alert_ditl_h);
+ memcpy(*alert_ditl_h, alert_ditl, sizeof(alert_ditl));
+ HUnlock(alert_ditl_h);
+
+ SetPort(win);
}
void
@@ -368,11 +550,9 @@ note(const char *format, ...)
short
ask(const char *format, ...)
{
- Rect bounds, irect;
- short height, width, hit;
+ Rect bounds;
+ short hit;
WindowPtr win, dialog;
- OSType itype;
- Handle ihandle;
va_list ap;
GetPort(&win);
@@ -381,14 +561,6 @@ ask(const char *format, ...)
vsnprintf(err_str, ERROR_STRING_SIZE, format, ap);
va_end(ap);
- 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");
ask_ditl_h = xNewHandle(sizeof(ask_ditl));
@@ -396,6 +568,7 @@ ask(const char *format, ...)
memcpy(*ask_ditl_h, ask_ditl, sizeof(ask_ditl));
HUnlock(ask_ditl_h);
+ center_in_screen(300, 100, false, &bounds);
dialog = NewDialog(nil, &bounds, "\p", false, dBoxProc,
(WindowPtr)-1L, false, 0, ask_ditl_h);
@@ -406,7 +579,7 @@ ask(const char *format, ...)
break;
}
DisposDialog(dialog);
- DisposHandle(alert_ditl_h);
+ DisposHandle(ask_ditl_h);
SetPort(win);
@@ -419,9 +592,8 @@ progress(char *format, ...)
static Str255 progress_s;
Handle thandle;
va_list argptr;
- Rect bounds = { 100, 90, 160, 420 }; /* tlbr */
+ Rect bounds;
Rect trect;
- static WindowPtr progress_win;
short ttype;
if (format == NULL) {
@@ -430,7 +602,6 @@ progress(char *format, ...)
DisposHandle(progress_ditl_h);
progress_dialog = NULL;
}
- SetPort(progress_win);
return;
}
@@ -440,13 +611,12 @@ progress(char *format, ...)
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);
+ center_in_screen(330, 60, false, &bounds);
progress_dialog = NewDialog(nil, &bounds, "\p", false, dBoxProc,
(WindowPtr)-1L, false, 0, progress_ditl_h);
}
@@ -458,6 +628,27 @@ progress(char *format, ...)
DrawDialog(progress_dialog);
}
+void
+window_rect(WindowPtr win, Rect *ret)
+{
+ *ret = (*(((WindowPeek)win)->strucRgn))->rgnBBox;
+ ret->left += 1;
+ ret->right -= 2;
+ ret->top -= 1;
+ ret->bottom -= 1;
+}
+
+void
+center_in_screen(short width, short height, bool titlebar, Rect *b)
+{
+ b->left = ((screenBits.bounds.right - screenBits.bounds.left) / 2) -
+ (width / 2);
+ b->top = ((screenBits.bounds.bottom - screenBits.bounds.top) / 2) -
+ (height / 2) + (titlebar ? GetMBarHeight() : 0);
+ b->right = b->left + width;
+ b->bottom = b->top + height;
+}
+
/*
* General Mac-specific non-GUI functions
*/
@@ -521,18 +712,18 @@ xGetString(short id)
char *
xGetStringAsChar(short id)
{
- StringHandle h = xGetString(id);
+ StringHandle h;
char *out;
size_t l;
+ h = xGetString(id);
HLock(h);
-
l = (*h)[0];
- out = xmalloc(l + 1);
+ out = xmalloc(l + 1, "xGetStringAsChar");
memcpy((void *)out, (void *)(*h + 1), l);
out[l] = '\0';
+ ReleaseResource(h);
- DisposHandle(h);
return out;
}
@@ -544,7 +735,7 @@ xGetStringAsLong(short id)
c = xGetStringAsChar(id);
r = atol(c);
- free(c);
+ xfree(&c);
return r;
}
@@ -566,9 +757,9 @@ getpath(short vRefNum, Str255 fileName, Str255 *ret, b
WDPBRec wdir;
HVolumeParam wvol;
DirInfo wcinfo;
- Str255 name;
+ char *name = NULL;
size_t retlen = 0, len;
- char tmpret[256], tmp[256];
+ char *tmpret = NULL, *tmp = NULL;
char *lastcolon;
if (strchr((char *)fileName + 1, ':') != NULL) {
@@ -583,35 +774,43 @@ getpath(short vRefNum, Str255 fileName, Str255 *ret, b
return 0;
}
+ name = xmalloc(FILENAME_MAX, "getpath");
+
wdir.ioVRefNum = wdir.ioWDVRefNum = vRefNum;
wdir.ioWDIndex = 0;
wdir.ioWDProcID = 0;
- wdir.ioNamePtr = (StringPtr)&name;
+ wdir.ioNamePtr = (StringPtr)name;
if (PBGetWDInfo(&wdir, 0) != noErr) {
warn("Failed looking up directory");
+ xfree(&name);
return 1;
}
- wvol.ioNamePtr = (StringPtr)&name;
+ wvol.ioNamePtr = (StringPtr)name;
wvol.ioVRefNum = vRefNum;
wvol.ioVolIndex = 0;
if (PBHGetVInfoSync((HParmBlkPtr)&wvol) != noErr) {
warn("Failed getting volume info");
+ xfree(&name);
return 1;
}
if (wvol.ioVSigWord != 0x4244) {
warn("Unknown filesystem type 0x%x", wvol.ioVSigWord);
+ xfree(&name);
return 1;
}
wcinfo.ioVRefNum = vRefNum;
- wcinfo.ioNamePtr = (StringPtr)&name;
+ wcinfo.ioNamePtr = (StringPtr)name;
wcinfo.ioFDirIndex = -1;
wcinfo.ioDrParID = wdir.ioWDDirID;
wcinfo.ioDrDirID = wdir.ioWDDirID;
+ tmp = xmalloc(FILENAME_MAX, "getpath");
+ tmpret = xmalloc(FILENAME_MAX, "getpath");
+
/* go backwards, prepending each folder's parent */
while (wcinfo.ioDrParID != 1) {
wcinfo.ioDrDirID = wcinfo.ioDrParID; /* .. */
@@ -623,31 +822,37 @@ getpath(short vRefNum, Str255 fileName, Str255 *ret, b
PtoCstr(name);
if (retlen == 0) {
retlen = len;
- strlcpy(tmpret, (char *)name, sizeof(tmpret));
+ strlcpy(tmpret, (char *)name, FILENAME_MAX);
} else {
- strlcpy(tmp, tmpret, sizeof(tmp));
- snprintf(tmpret, sizeof(tmpret), "%s:%s", name, tmp);
+ strlcpy(tmp, tmpret, FILENAME_MAX);
+ snprintf(tmpret, FILENAME_MAX, "%s:%s", name, tmp);
}
}
if (include_file) {
/* append the original path */
- memcpy(name, fileName, sizeof(name));
+ memcpy(name, fileName, FILENAME_MAX);
PtoCstr(name);
if (retlen == 0)
- strlcpy(tmpret, (char *)name, sizeof(tmpret));
+ strlcpy(tmpret, name, FILENAME_MAX);
else {
- strlcat(tmpret, ":", sizeof(tmpret));
- strlcat(tmpret, (char *)name, sizeof(tmpret));
+ strlcat(tmpret, ":", FILENAME_MAX);
+ strlcat(tmpret, name, FILENAME_MAX);
}
} else if (retlen == 0) {
(*ret)[0] = 0;
+ xfree(&tmp);
+ xfree(&tmpret);
+ xfree(&name);
return 0;
}
CtoPstr(tmpret);
- memcpy(*ret, tmpret, sizeof(tmpret));
-
+ memcpy(*ret, tmpret, FILENAME_MAX);
+ xfree(&tmp);
+ xfree(&tmpret);
+ xfree(&name);
+
return 0;
}
@@ -657,10 +862,10 @@ stat(char *path, struct stat *sb)
char *ppath;
short ret;
- ppath = xstrdup(path);
+ ppath = xstrdup(path, "stat");
CtoPstr(ppath);
ret = FStat((unsigned char *)ppath, sb);
- free(ppath);
+ xfree(&ppath);
return ret;
}
@@ -692,8 +897,8 @@ FIsDir(Str255 path)
struct stat st;
short ret;
- if ((ret = FStat(path, &st)) != 0)
- return ret;
+ if (FStat(path, &st) != 0)
+ return false;
/* bit 4 is set in ioFlAttrib if the item is a directory */
if (st.st_flags & (1 << 4))
@@ -785,7 +990,7 @@ copy_file(Str255 source, Str255 dest, bool overwrite)
OSErr
copy_file_contents(short source_ref, short dest_ref)
{
- char buf[1024];
+ char *buf;
short error;
long source_size, count;
@@ -799,19 +1004,24 @@ copy_file_contents(short source_ref, short dest_ref)
error = SetFPos(dest_ref, fsFromStart, 0);
if (error)
return error;
+
+ buf = xmalloc(1024, "copy_file_contents");
+
while (source_size > 0) {
- count = sizeof(buf);
+ count = 1024;
if (count > source_size)
count = source_size;
- error = FSRead(source_ref, &count, &buf);
+ error = FSRead(source_ref, &count, buf);
if (error && error != eofErr)
break;
source_size -= count;
- error = FSWrite(dest_ref, &count, &buf);
+ error = FSWrite(dest_ref, &count, buf);
if (error && error != eofErr)
break;
}
+ xfree(&buf);
+
if (error && error != eofErr)
return error;
@@ -824,7 +1034,7 @@ FSReadLine(short frefnum, char *buf, size_t buflen)
{
char tbuf;
size_t pos, fsize, rlen = 1, total_read = 0;
- short error, found = -1, i;
+ short error;
GetFPos(frefnum, &pos);
GetEOF(frefnum, &fsize);
@@ -994,8 +1204,7 @@ UpdateScrollbarForTE(ControlHandle control, TEHandle t
{
size_t vlines, telines;
TERec *ter;
- short fheight, fwidth, max, val, per_page, per_line, horiz, max_chars,
- n;
+ short fheight, fwidth, max, val, per_line, horiz, max_chars, n;
HLock(te);
ter = *te;
@@ -1205,8 +1414,7 @@ pascal bool
PasswordDialogFieldFilter(DialogPtr dlg, EventRecord *event, short *hit)
{
DialogPeek dlgp;
- WindowPtr event_win;
- short event_in, sel_start, sel_end;
+ short sel_start, sel_end;
char key;
dlgp = (DialogPeek)dlg;
@@ -1274,4 +1482,518 @@ NullCaretHook(void)
move.l (a7)+,d0
rts
}
+}
+
+static bool menu_bar_hidden = false;
+static short old_mbar_height;
+static Rect mbar_rect;
+static RgnHandle mbar_save_region;
+
+void
+HideMenuBar(void)
+{
+ RgnHandle mbar_region;
+ WindowPeek win;
+
+ old_mbar_height = GetMBarHeight();
+ SetRect(&mbar_rect, screenBits.bounds.left, screenBits.bounds.top,
+ screenBits.bounds.right, screenBits.bounds.top + old_mbar_height);
+
+ mbar_save_region = NewRgn();
+ mbar_region = NewRgn();
+
+ MBarHeight = 0;
+ CopyRgn(GetGrayRgn(), mbar_save_region);
+ RectRgn(mbar_region, &mbar_rect);
+ UnionRgn(GetGrayRgn(), mbar_region, GetGrayRgn());
+
+ win = (WindowPeek)FrontWindow();
+ PaintOne(win, mbar_region);
+ PaintBehind(win, mbar_region);
+ CalcVis(win);
+ CalcVisBehind(win, mbar_region);
+ DisposeRgn(mbar_region);
+
+ menu_bar_hidden = true;
+}
+
+void
+RestoreHiddenMenuBar(void)
+{
+ WindowPeek win;
+
+ if (!menu_bar_hidden)
+ return;
+
+ CopyRgn(mbar_save_region, GetGrayRgn());
+ MBarHeight = old_mbar_height;
+
+ RectRgn(mbar_save_region, &mbar_rect);
+ win = (WindowPeek)FrontWindow();
+ CalcVis(win);
+ CalcVisBehind(win, mbar_save_region);
+ DisposeRgn(mbar_save_region);
+
+ menu_bar_hidden = false;
+
+ HiliteMenu(0);
+ DrawMenuBar();
+}
+
+/* C Extensions */
+
+/*
+ * Appends src to string dst of size dsize (unlike strncat, dsize is the
+ * full size of dst, not space left). At most dsize-1 characters
+ * will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
+ * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
+ * If retval >= dsize, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t dsize)
+{
+ const char *odst = dst;
+ const char *osrc = src;
+ size_t n = dsize;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end. */
+ while (n-- != 0 && *dst != '\0')
+ dst++;
+ dlen = dst - odst;
+ n = dsize - dlen;
+
+ if (n-- == 0)
+ return(dlen + strlen(src));
+ while (*src != '\0') {
+ if (n != 0) {
+ *dst++ = *src;
+ n--;
+ }
+ src++;
+ }
+ *dst = '\0';
+
+ return(dlen + (src - osrc)); /* count does not include NUL */
+}
+
+/*
+ * Copy string src to buffer dst of size dsize. At most dsize-1
+ * chars will be copied. Always NUL terminates (unless dsize == 0).
+ * Returns strlen(src); if retval >= dsize, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t dsize)
+{
+ const char *osrc = src;
+ size_t nleft = dsize;
+
+ /* Copy as many bytes as will fit. */
+ if (nleft != 0) {
+ while (--nleft != 0) {
+ if ((*dst++ = *src++) == '\0')
+ break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src. */
+ if (nleft == 0) {
+ if (dsize != 0)
+ *dst = '\0'; /* NUL-terminate dst */
+ while (*src++)
+ ;
+ }
+
+ return(src - osrc - 1); /* count does not include NUL */
+}
+
+char *
+strndup(const char *str, size_t maxlen)
+{
+ char *copy;
+ const char *cp;
+ size_t len;
+
+ /* strnlen */
+ for (cp = str; maxlen != 0 && *cp != '\0'; cp++, maxlen--)
+ ;
+
+ len = (size_t)(cp - str);
+ copy = malloc(len + 1);
+ if (copy != NULL) {
+ (void)memcpy(copy, str, len);
+ copy[len] = '\0';
+ }
+
+ return copy;
+}
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim)
+{
+ char *s;
+ const char *spanp;
+ int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ return (NULL);
+}
+
+static struct format {
+ unsigned leftJustify : 1;
+ unsigned forceSign : 1;
+ unsigned altForm : 1;
+ unsigned zeroPad : 1;
+ unsigned havePrecision : 1;
+ unsigned hSize : 1;
+ unsigned lSize : 1;
+ unsigned LSize : 1;
+ char sign;
+ char exponent;
+ int fieldWidth;
+ int precision;
+} default_format;
+
+int bounded_vfprintf(FILE *fp, const char *fmt, va_list arg);
+static int nullio(FILE *fp, int i);
+
+int
+bounded_vfprintf(FILE *fp, const char *fmt, va_list arg)
+{
+ register int c, i, j, nwritten = 0;
+ register unsigned long n;
+ long double x;
+ register char *s;
+#define VFPRINTF_BUFLEN 512
+ char buf[VFPRINTF_BUFLEN], *digits, *t;
+ struct format F;
+
+ for (c = *fmt; c; c = *++fmt) {
+ if (c != '%')
+ goto copy1;
+ F = default_format;
+
+ /* decode flags */
+
+ for (;;) {
+ c = *++fmt;
+ if (c == '-')
+ F.leftJustify = TRUE;
+ else if (c == '+')
+ F.forceSign = TRUE;
+ else if (c == ' ')
+ F.sign = ' ';
+ else if (c == '#')
+ F.altForm = TRUE;
+ else if (c == '0')
+ F.zeroPad = TRUE;
+ else
+ break;
+ }
+
+ /* decode field width */
+
+ if (c == '*') {
+ if ((F.fieldWidth = va_arg(arg, int)) < 0) {
+ F.leftJustify = TRUE;
+ F.fieldWidth = -F.fieldWidth;
+ }
+ c = *++fmt;
+ }
+ else {
+ for (; c >= '0' && c <= '9'; c = *++fmt)
+ F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
+ }
+
+ /* decode precision */
+
+ if (c == '.') {
+ if ((c = *++fmt) == '*') {
+ F.precision = va_arg(arg, int);
+ c = *++fmt;
+ }
+ else {
+ for (; c >= '0' && c <= '9'; c = *++fmt)
+ F.precision = (10 * F.precision) + (c - '0');
+ }
+ if (F.precision >= 0)
+ F.havePrecision = TRUE;
+ }
+
+ /* perform appropriate conversion */
+
+ s = &buf[VFPRINTF_BUFLEN];
+ if (F.leftJustify)
+ F.zeroPad = FALSE;
+conv: switch (c) {
+
+ /* 'h' size modifier */
+
+ case 'h':
+ F.hSize = TRUE;
+ c = *++fmt;
+ goto conv;
+
+ /* 'l' size modifier */
+
+ case 'l':
+ F.lSize = TRUE;
+ c = *++fmt;
+ goto conv;
+
+ /* 'L' size modifier */
+
+ case 'L':
+ F.LSize = TRUE;
+ c = *++fmt;
+ goto conv;
+
+ /* decimal (signed) */
+
+ case 'd':
+ case 'i':
+ if (F.lSize)
+ n = va_arg(arg, long);
+ else
+ n = va_arg(arg, int);
+ if (F.hSize)
+ n = (short) n;
+ if ((long) n < 0) {
+ n = -n;
+ F.sign = '-';
+ }
+ else if (F.forceSign)
+ F.sign = '+';
+ goto decimal;
+
+ /* decimal (unsigned) */
+
+ case 'u':
+ if (F.lSize)
+ n = va_arg(arg, unsigned long);
+ else
+ n = va_arg(arg, unsigned int);
+ if (F.hSize)
+ n = (unsigned short) n;
+ F.sign = 0;
+ goto decimal;
+
+ /* decimal (common code) */
+
+ decimal:
+ if (!F.havePrecision) {
+ if (F.zeroPad) {
+ F.precision = F.fieldWidth;
+ if (F.sign)
+ --F.precision;
+ }
+ if (F.precision < 1)
+ F.precision = 1;
+ }
+ for (i = 0; n; n /= 10, i++)
+ *--s = n % 10 + '0';
+ for (; i < F.precision; i++)
+ *--s = '0';
+ if (F.sign) {
+ *--s = F.sign;
+ i++;
+ }
+ break;
+
+ /* octal (unsigned) */
+
+ case 'o':
+ if (F.lSize)
+ n = va_arg(arg, unsigned long);
+ else
+ n = va_arg(arg, unsigned int);
+ if (F.hSize)
+ n = (unsigned short) n;
+ if (!F.havePrecision) {
+ if (F.zeroPad)
+ F.precision = F.fieldWidth;
+ if (F.precision < 1)
+ F.precision = 1;
+ }
+ for (i = 0; n; n /= 8, i++)
+ *--s = n % 8 + '0';
+ if (F.altForm && i && *s != '0') {
+ *--s = '0';
+ i++;
+ }
+ for (; i < F.precision; i++)
+ *--s = '0';
+ break;
+
+ /* hexadecimal (unsigned) */
+
+ case 'p':
+ F.havePrecision = F.lSize = TRUE;
+ F.precision = 8;
+ /* ... */
+ case 'X':
+ digits = "0123456789ABCDEF";
+ goto hexadecimal;
+ case 'x':
+ digits = "0123456789abcdef";
+ /* ... */
+ hexadecimal:
+ if (F.lSize)
+ n = va_arg(arg, unsigned long);
+ else
+ n = va_arg(arg, unsigned int);
+ if (F.hSize)
+ n = (unsigned short) n;
+ if (!F.havePrecision) {
+ if (F.zeroPad) {
+ F.precision = F.fieldWidth;
+ if (F.altForm)
+ F.precision -= 2;
+ }
+ if (F.precision < 1)
+ F.precision = 1;
+ }
+ for (i = 0; n; n /= 16, i++)
+ *--s = digits[n % 16];
+ for (; i < F.precision; i++)
+ *--s = '0';
+ if (F.altForm) {
+ *--s = c;
+ *--s = '0';
+ i += 2;
+ }
+ break;
+
+ /* character */
+
+ case 'c':
+ *--s = va_arg(arg, int);
+ i = 1;
+ break;
+
+ /* string */
+
+ case 's':
+ s = va_arg(arg, char *);
+ if (F.altForm) {
+ i = (unsigned char) *s++;
+ if (F.havePrecision && i > F.precision)
+ i = F.precision;
+ }
+ else {
+ if (!F.havePrecision)
+ i = strlen(s);
+ else if (t = memchr(s, '\0', F.precision))
+ i = t - s;
+ else
+ i = F.precision;
+ }
+ break;
+
+ /* store # bytes written so far */
+
+ case 'n':
+ s = va_arg(arg, void *);
+ if (F.hSize)
+ * (short *) s = nwritten;
+ else if (F.lSize)
+ * (long *) s = nwritten;
+ else
+ * (int *) s = nwritten;
+ continue;
+
+ /* oops - unknown conversion, abort */
+
+ default:
+ if (c != '%')
+ goto done;
+ copy1:
+ putc(c, fp); /* disregard EOF */
+ ++nwritten;
+ continue;
+ }
+
+ /* pad on the left */
+
+ if (i < F.fieldWidth && !F.leftJustify) {
+ do {
+ putc(' ', fp); /* disregard EOF */
+ ++nwritten;
+ } while (i < --F.fieldWidth);
+ }
+
+ /* write the converted result */
+
+ fwrite(s, 1, i, fp); /* disregard EOF */
+ nwritten += i;
+
+ /* pad on the right */
+
+ for (; i < F.fieldWidth; i++) {
+ putc(' ', fp); /* disregard EOF */
+ ++nwritten;
+ }
+ }
+
+ /* all done! */
+
+done:
+ return(nwritten);
+}
+
+int
+snprintf(char *s, size_t size, const char *fmt, ...)
+{
+ return(vsnprintf(s, size, fmt, __va(fmt)));
+}
+
+static int
+nullio(FILE *fp, int i)
+{
+ return(EOF);
+}
+
+int
+vsnprintf(char *s, size_t size, const char *fmt, void *p)
+{
+ FILE f;
+ int n;
+
+ memset(&f, 0, sizeof(f));
+ f.refnum = -1;
+ f.ptr = (unsigned char *) s;
+ f.cnt = size;
+ f.proc = nullio;
+ f.dirty = 1;
+
+ if ((n = bounded_vfprintf(&f, fmt, p)) >= 0)
+ s[n] = 0;
+ return(n);
}
--- util.h Mon Feb 7 21:18:17 2022
+++ util.h Tue Sep 6 12:34:32 2022
@@ -28,6 +28,8 @@
#define nitems(what) (sizeof((what)) / sizeof((what)[0]))
#define member_size(type, member) sizeof(((type *)0)->member)
+#define MALLOC_NOTE_SIZE 32
+
#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)))
@@ -41,28 +43,43 @@
} \
}
+#define CHARS_TO_LONG(a,b,c,d) (unsigned long)(\
+ ((unsigned long)((unsigned char)(a)) << 24) | \
+ ((unsigned long)((unsigned char)(b)) << 16) | \
+ ((unsigned long)((unsigned char)(c)) << 8) | \
+ (unsigned long)((unsigned char)(d)) )
+#define CHARS_TO_SHORT(a,b) (unsigned short)(\
+ ((unsigned short)((unsigned char)(a)) << 8) | \
+ (unsigned short)((unsigned char)(b)) )
+
#define SCROLLBAR_WIDTH 16
/* GetMBarHeight() is not very useful */
#define MENUBAR_HEIGHT 20
+#define TICKS_PER_SEC 60L
+
#define MAX_TEXTEDIT_SIZE 32767L
#ifndef bool
typedef Boolean bool;
#endif
-
typedef signed long off_t;
typedef signed long ssize_t;
typedef unsigned char u_char;
typedef unsigned long u_int;
+typedef unsigned char u_int8_t;
+typedef unsigned short u_int16_t;
+typedef unsigned long u_int32_t;
+#define BYTE_ORDER BIG_ENDIAN
+
typedef struct {
short push[2], rts;
void *addr;
} tCodeStub;
-typedef struct stat {
+struct stat {
short st_mode;
ssize_t st_size;
time_t st_ctime;
@@ -70,18 +87,21 @@ typedef struct stat {
unsigned char st_flags;
};
-void * xmalloc(size_t);
-void * xmalloczero(size_t);
-void * xcalloc(size_t, size_t);
+void util_init(void);
+
+void * xmalloc(size_t, char *note);
+void xfree(void *ptrptr);
+void xfree_verify(void);
+void * xmalloczero(size_t, char *note);
+void * xcalloc(size_t, size_t, char *note);
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 *);
+char * xstrdup(const char *, char *note);
+char * xstrndup(const char *str, size_t maxlen, char *note);
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);
+size_t rtrim(char *str, char *chars);
long strpos_quoted(char *str, char c);
char * OSTypeToString(OSType type);
@@ -96,6 +116,8 @@ short ask(const char *format, ...);
#define ASK_YES 1
#define ASK_NO 2
void progress(char *format, ...);
+void window_rect(WindowPtr win, Rect *ret);
+void center_in_screen(short width, short height, bool titlebar, Rect *b);
Handle xNewHandle(size_t size);
Handle xGetResource(ResType type, short id);
@@ -129,5 +151,15 @@ pascal bool PasswordDialogFieldFilter(DialogPtr dlg, E
short *hit);
void PasswordDialogFieldFinish(void);
pascal void NullCaretHook(void);
+void HideMenuBar(void);
+void RestoreHiddenMenuBar(void);
+
+size_t strlcat(char *dst, const char *src, size_t dsize);
+size_t strlcpy(char *dst, const char *src, size_t dsize);
+char * strndup(const char *str, size_t maxlen);
+char * strsep(char **stringp, const char *delim);
+int snprintf(char *s, size_t size, const char *fmt, ...);
+int vsnprintf(char *s, size_t size, const char *fmt, void *p);
+
#endif