jcs
/subtext
/amendments
/246
util: Sync with upstream
jcs made amendment 246 over 2 years ago
--- logger.c Fri Jan 1 23:14:03 1904
+++ logger.c Thu Sep 8 22:08:48 2022
@@ -46,7 +46,7 @@ logger_init(void)
bounds.left = padding;
bounds.top = ((screenBits.bounds.bottom -
- screenBits.bounds.top) / 3) * 2;
+ screenBits.bounds.top) / 3);
bounds.right = screenBits.bounds.right - padding - 1;
bounds.bottom = screenBits.bounds.bottom - padding - 1;
@@ -379,7 +379,7 @@ no_overflow:
TEPinScroll(0, -INT_MAX, logger->messages_te);
SetCtlValue(logger->messages_scroller,
GetCtlMax(logger->messages_scroller));
- UpdateScrollbarForTE(logger->messages_scroller,
+ UpdateScrollbarForTE(logger->win, logger->messages_scroller,
logger->messages_te, false);
HUnlock(logger->messages_te);
--- settings.c Sun Jul 31 21:32:57 2022
+++ settings.c Thu Sep 8 22:14:05 2022
@@ -292,8 +292,6 @@ get_input:
}
}
- if (input != NULL)
- xfree(&input);
if (s->ending) {
any_changes = false;
goto done;
@@ -406,10 +404,10 @@ view_editor_show(size_t id, char *title)
focusable->close = view_editor_close;
add_focusable(focusable);
- UpdateScrollbarForTE(view_editor->vert_scroller, view_editor->te,
- false);
- UpdateScrollbarForTE(view_editor->horiz_scroller, view_editor->te,
- false);
+ UpdateScrollbarForTE(view_editor->win, view_editor->vert_scroller,
+ view_editor->te, false);
+ UpdateScrollbarForTE(view_editor->win, view_editor->horiz_scroller,
+ view_editor->te, false);
}
void
@@ -434,10 +432,10 @@ view_editor_key_down(struct focusable *focusable, Even
} else
TEKey(k, view_editor->te);
- UpdateScrollbarForTE(view_editor->vert_scroller, view_editor->te,
- false);
- UpdateScrollbarForTE(view_editor->horiz_scroller, view_editor->te,
- false);
+ UpdateScrollbarForTE(view_editor->win, view_editor->vert_scroller,
+ view_editor->te, false);
+ UpdateScrollbarForTE(view_editor->win, view_editor->horiz_scroller,
+ view_editor->te, false);
}
void
--- util.c Wed Aug 3 14:00:06 2022
+++ util.c Tue Sep 6 19:08:22 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>
@@ -30,29 +35,31 @@
static char err_str[ERROR_STRING_SIZE];
/* basic DITL with an ok button (1), text area (2), and icon (3) */
+#define ALERT_DITL_OK 1
#define ALERT_DITL_ICON 3
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,
- 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
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E,
+ 0x00, 0xFA, 0x00, 0x64, 0x01, 0x34, 0x04, 0x02,
+ 0x4F, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D,
+ 0x00, 0x4E, 0x00, 0x41, 0x01, 0x36, 0x08, 0x02,
+ 0x5E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D,
+ 0x00, 0x17, 0x00, 0x2D, 0x00, 0x37, 0xA0, 0x02,
+ 0x00, 0x01
};
static Handle alert_ditl_h = NULL;
+/* ICN# to show for APPICON_ALERT */
+#define APPICON_ICN_ID 128
+
/* DITL with a Yes button (1), No button (2), text (3), and icon (4) */
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,
- 0x00, 0x46, 0x00, 0xA0, 0x00, 0x5A, 0x00, 0xDA,
- 0x04, 0x02, 0x4E, 0x6F, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0A, 0x00, 0x32, 0x00, 0x41, 0x01, 0x22,
- 0x08, 0x02, 0x5E, 0x30, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x2A, 0x00, 0x2A,
- 0xA0, 0x02, 0x00, 0x01
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E,
+ 0x00, 0xFA, 0x00, 0x64, 0x01, 0x34, 0x04, 0x02,
+ 0x4F, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D,
+ 0x00, 0x4E, 0x00, 0x41, 0x01, 0x36, 0x08, 0x02,
+ 0x5E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D,
+ 0x00, 0x17, 0x00, 0x2D, 0x00, 0x37, 0xA0, 0x02,
+ 0x00, 0x01
};
static Handle ask_ditl_h = NULL;
@@ -70,33 +77,30 @@ static TEHandle track_control_te = NULL;
enum {
STOP_ALERT,
CAUTION_ALERT,
- NOTE_ALERT
+ NOTE_ALERT,
+ APPICON_ALERT
};
-#ifdef MALLOC_DEBUG
+/*
+ * 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_SIZE 512
+#define MALLOC_MAP_CHUNK_SIZE 1024
struct malloc_map_e {
unsigned long addr;
unsigned long size;
char note[MALLOC_NOTE_SIZE];
-} malloc_map[MALLOC_MAP_SIZE];
-
-/*
- * On xfree(&), the pointer will be updated to point here. xfree_verify()
- * should be called periodically to detect any writes to it, indicating
- * a use-after-free.
- */
-#define MALLOC_UAF_SIZE 256
-static const char malloc_uaf_zero[MALLOC_UAF_SIZE] = { 0 };
-static char malloc_uaf[MALLOC_UAF_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);
@@ -115,8 +119,12 @@ util_init(void)
HUnlock(alert_ditl_h);
#ifdef MALLOC_DEBUG
- memset(&malloc_map, 0, sizeof(malloc_map));
- memset(&malloc_uaf, 0, sizeof(malloc_uaf));
+ 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
}
@@ -131,6 +139,7 @@ xmalloc(size_t size, char *note)
{
void *ptr;
#ifdef MALLOC_DEBUG
+ struct malloc_map_e *new_malloc_map;
unsigned short n, j;
#endif
@@ -143,16 +152,16 @@ xmalloc(size_t size, char *note)
#ifdef MALLOC_DEBUG
if (malloc_map_compact) {
- for (n = 0; n < MALLOC_MAP_SIZE; n++) {
+ for (n = 0; n < malloc_map_size; n++) {
if (malloc_map[n].addr != 0)
continue;
- for (j = n + 1; j < MALLOC_MAP_SIZE; j++) {
+ 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(malloc_map[j]));
+ memset(&malloc_map[j], 0, sizeof(struct malloc_map_e));
break;
}
}
@@ -160,10 +169,21 @@ xmalloc(size_t size, char *note)
malloc_map_compact = false;
}
- for (n = 0; n <= MALLOC_MAP_SIZE; n++) {
- if (n == MALLOC_MAP_SIZE)
- panic("xmalloc(%lu): out of malloc map entries, likely a "
- "memory leak", size);
+ 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;
@@ -184,10 +204,10 @@ xfree(void *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(%lu): can't find %lu in alloc map, likely "
+
+ 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;
@@ -200,22 +220,9 @@ xfree(void *ptrptr)
DisposePtr(ptr);
-#ifdef MALLOC_DEBUG
- *addr = (unsigned long)&malloc_uaf;
-#else
*addr = 0L;
-#endif
}
-#ifdef MALLOC_DEBUG
-void
-xfree_verify(void)
-{
- if (memcmp(malloc_uaf, malloc_uaf_zero, sizeof(malloc_uaf)) != 0)
- panic("xfree_verify: use-after-free detected");
-}
-#endif
-
void *
xmalloczero(size_t size, char *note)
{
@@ -251,10 +258,12 @@ xrealloc(void *src, size_t size)
#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 %lu in alloc map, likely "
+ 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;
@@ -296,6 +305,26 @@ xstrdup(const char *str, char *note)
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
*/
@@ -414,28 +443,21 @@ void
vwarn(short alert_func, const char *format, va_list ap)
{
Rect bounds;
- short height, width, hit;
+ short hit, itype;
WindowPtr win, dialog;
-
+ Handle ihandle;
+ Rect irect;
+
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");
+ center_in_screen(320, 110, false, &bounds);
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:
@@ -444,19 +466,23 @@ vwarn(short alert_func, const char *format, va_list ap
case NOTE_ALERT:
ihandle = GetIcon(noteIcon);
break;
+ case APPICON_ALERT:
+ ihandle = GetResource('ICN#', APPICON_ICN_ID);
+ if (ihandle)
+ break;
default:
ihandle = GetIcon(stopIcon);
}
- ihandle = GetIcon(cautionIcon);
SetDItem(dialog, ALERT_DITL_ICON, itype, ihandle, &irect);
-#endif
-
+
ShowWindow(dialog);
+
for (;;) {
ModalDialog(0, &hit);
if (hit == ok)
break;
}
+ ReleaseResource(ihandle);
DisposDialog(dialog);
/*
@@ -529,11 +555,21 @@ note(const char *format, ...)
va_end(ap);
}
+void
+appicon_note(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vwarn(APPICON_ALERT, format, ap);
+ va_end(ap);
+}
+
short
ask(const char *format, ...)
{
Rect bounds;
- short height, width, hit;
+ short hit;
WindowPtr win, dialog;
va_list ap;
@@ -543,14 +579,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));
@@ -558,6 +586,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);
@@ -576,12 +605,44 @@ ask(const char *format, ...)
}
void
+about(char *program_name)
+{
+ VersRecHndl vers;
+ char vers_s[255];
+ char short_vers[255] = { 0 };
+ short vlen, n;
+
+ if ((vers = (VersRecHndl)GetResource('vers', 1))) {
+ /*
+ * vers "long version string" is a pascal string after the
+ * short version pascal string
+ */
+ HLock(vers);
+ vlen = (*vers)->shortVersion[0];
+ memcpy(short_vers, (*vers)->shortVersion + vlen + 1,
+ sizeof((*vers)->shortVersion) - vlen - 1);
+ PtoCstr(short_vers);
+ snprintf(vers_s, sizeof(vers_s), "%s %s", program_name,
+ short_vers);
+ for (n = 0; n < sizeof(vers_s); n++) {
+ if (vers_s[n] == '©') {
+ vers_s[n - 1] = '\r';
+ break;
+ }
+ }
+ ReleaseResource(vers);
+ appicon_note("%s", vers_s);
+ } else
+ warnx("Can't find version number!");
+}
+
+void
progress(char *format, ...)
{
static Str255 progress_s;
Handle thandle;
va_list argptr;
- Rect bounds = { 100, 90, 160, 420 }; /* tlbr */
+ Rect bounds;
Rect trect;
short ttype;
@@ -605,6 +666,7 @@ progress(char *format, ...)
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);
}
@@ -616,9 +678,45 @@ 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;
+}
+
+Point
+centered_sf_dialog(void)
+{
+ Point p;
+ Rect r;
+
+ center_in_screen(364, 216, false, &r);
+ p.h = r.left;
+ p.v = r.top;
+
+ return p;
+}
+
+
/*
* General Mac-specific non-GUI functions
*/
+
static unsigned long _xorshift_state = 0;
unsigned long
xorshift32(void)
@@ -798,7 +896,7 @@ getpath(short vRefNum, Str255 fileName, Str255 *ret, b
if (include_file) {
/* append the original path */
- memcpy(name, fileName, sizeof(name));
+ memcpy(name, fileName, FILENAME_MAX);
PtoCstr(name);
if (retlen == 0)
strlcpy(tmpret, name, FILENAME_MAX);
@@ -815,7 +913,7 @@ getpath(short vRefNum, Str255 fileName, Str255 *ret, b
}
CtoPstr(tmpret);
- memcpy(*ret, tmpret, sizeof(tmpret));
+ memcpy(*ret, tmpret, FILENAME_MAX);
xfree(&tmp);
xfree(&tmpret);
xfree(&name);
@@ -1167,12 +1265,14 @@ TEGetWidth(short off, TEHandle te)
#define ceildiv(a,b) ((a / b) + (!!(a % b)))
void
-UpdateScrollbarForTE(ControlHandle control, TEHandle te, bool reset)
+UpdateScrollbarForTE(GrafPtr win, ControlHandle control, TEHandle te, bool reset)
{
size_t vlines, telines;
TERec *ter;
+ RgnHandle rgn;
short fheight, fwidth, max, val, per_line, horiz, max_chars, n;
+ HLock(control);
HLock(te);
ter = *te;
@@ -1242,7 +1342,13 @@ UpdateScrollbarForTE(ControlHandle control, TEHandle t
(*control)->contrlMax = max;
SetCtlValue(control, val);
+ rgn = NewRgn();
+ RectRgn(rgn, &(*control)->contrlRect);
+ UpdtControl(win, rgn);
+ CloseRgn(rgn);
+
HUnlock(te);
+ HUnlock(control);
}
void
@@ -1505,4 +1611,462 @@ RestoreHiddenMenuBar(void)
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 Aug 1 15:38:41 2022
+++ util.h Thu Sep 8 21:52:06 2022
@@ -21,9 +21,6 @@
#include <limits.h>
#include <time.h>
-#define MALLOC_DEBUG
-#define MALLOC_NOTE_SIZE 32
-
#ifndef SIZE_MAX
#define SIZE_MAX ULONG_MAX
#endif
@@ -31,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)))
@@ -98,10 +97,9 @@ void * xcalloc(size_t, size_t, char *note);
void * xrealloc(void *src, size_t size);
void * xreallocarray(void *, size_t, size_t);
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);
@@ -114,10 +112,15 @@ void err(short ret, const char *format, ...);
void warnx(const char *format, ...);
void warn(const char *format, ...);
void note(const char *format, ...);
+void appicon_note(const char *format, ...);
short ask(const char *format, ...);
#define ASK_YES 1
#define ASK_NO 2
+void about(char *program_name);
void progress(char *format, ...);
+void window_rect(WindowPtr win, Rect *ret);
+void center_in_screen(short width, short height, bool titlebar, Rect *b);
+Point centered_sf_dialog(void);
Handle xNewHandle(size_t size);
Handle xGetResource(ResType type, short id);
@@ -140,7 +143,8 @@ char * get_version(bool long_version);
short FontHeight(short font_id, short size);
void DrawGrowIconOnly(WindowPtr win);
short TEGetWidth(short off, TEHandle te);
-void UpdateScrollbarForTE(ControlHandle scroller, TEHandle te, bool reset);
+void UpdateScrollbarForTE(GrafPtr win, ControlHandle scroller, TEHandle te,
+ bool reset);
void SetTrackControlTE(TEHandle te);
pascal void TrackMouseDownInControl(ControlHandle control, short part);
pascal bool ModalDialogFilter(DialogPtr dlg, EventRecord *event,
@@ -153,5 +157,12 @@ 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