jcs
/wallops
/amendments
/52
util: Sync with upstream, fold in strcasecmp
jcs made amendment 52 2 months ago
--- stdint.h Thu Mar 7 17:26:00 2024
+++ stdint.h Thu Mar 7 17:26:00 2024
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2024 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
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __STDINT_H__
+#define __STDINT_H__
+
+#include <limits.h>
+
+/* stdbool.h */
+typedef Boolean bool;
+
+/* our own types */
+typedef signed long off_t;
+typedef signed long ssize_t;
+
+/* ISO/IEC 988:1999, C99 */
+typedef unsigned long uint;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+
+#define SIZE_MAX ULONG_MAX
+
+#endif
\ No newline at end of file
--- strcasecmp.c Mon May 23 12:09:29 2022
+++ strcasecmp.c Wed Dec 4 13:20:18 1985
@@ -1,108 +0,0 @@
-/* $OpenBSD: strcasecmp.c,v 1.7 2015/08/31 02:53:57 guenther Exp $ */
-
-/*
- * Copyright (c) 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <string.h>
-
-typedef unsigned char u_char;
-
-short strcasecmp(const char *s1, const char *s2);
-short strncasecmp(const char *s1, const char *s2, size_t n);
-
-/*
- * This array is designed for mapping upper and lower case letter
- * together for a case independent comparison. The mappings are
- * based upon ascii character sequences.
- */
-static const u_char charmap[] = {
- '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
- '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
- '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
- '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
- '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
- '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
- '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
- '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
- '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
- '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
- '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
- '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
- '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
- '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
- '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
- '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
- '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
- '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
- '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
- '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
- '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
- '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
- '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
- '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
- '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
- '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
- '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
- '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
- '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
- '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
- '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
- '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
-};
-
-short
-strcasecmp(const char *s1, const char *s2)
-{
- const u_char *cm = charmap;
- const u_char *us1 = (const u_char *)s1;
- const u_char *us2 = (const u_char *)s2;
-
- while (cm[*us1] == cm[*us2++])
- if (*us1++ == '\0')
- return (0);
- return (cm[*us1] - cm[*--us2]);
-}
-
-short
-strncasecmp(const char *s1, const char *s2, size_t n)
-{
- if (n != 0) {
- const u_char *cm = charmap;
- const u_char *us1 = (const u_char *)s1;
- const u_char *us2 = (const u_char *)s2;
-
- do {
- if (cm[*us1] != cm[*us2++])
- return (cm[*us1] - cm[*--us2]);
- if (*us1++ == '\0')
- break;
- } while (--n != 0);
- }
- return (0);
-}
--- util.c Thu Feb 1 21:34:37 2024
+++ util.c Wed Aug 28 14:02:32 2024
@@ -17,17 +17,52 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/* strcasecmp and strncasecmp:
+ *
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
/* THINK C Project must have a header of "#include <MacHeaders>" */
+#include <GestaltEqu.h>
+#include <Folders.h>
+#include <Script.h>
+#include <SetUpA4.h>
+#include <Traps.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <GestaltEqu.h>
-#include <Script.h>
-#include <SetUpA4.h>
#include "util.h"
+/* ALRT resources */
+#define ASK_ALERT_ID 130
+
#define ERROR_STRING_SIZE 1024
static char err_str[ERROR_STRING_SIZE];
@@ -73,6 +108,46 @@ static DialogPtr progress_dialog = NULL;
static TEHandle track_control_te = NULL;
+/*
+ * strcasecmp: This array is designed for mapping upper and lower case
+ * letter together for a case independent comparison. The mappings are
+ * based upon ascii character sequences.
+ */
+static const unsigned char strcasecmp_charmap[] = {
+ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+ '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+ '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+ '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+ '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+ '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+ '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+ '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+ '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+ '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+ '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+ '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+ '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+ '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+ '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+ '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
enum {
STOP_ALERT,
CAUTION_ALERT,
@@ -80,28 +155,6 @@ enum {
APPICON_ALERT
};
-/*
- * 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);
/*
@@ -116,15 +169,6 @@ util_init(void)
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
}
/*
@@ -133,64 +177,141 @@ util_init(void)
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+#ifdef MALLOC_DEBUG
+/*
+ * malloc tracking, storing a stack trace of each xmalloc call and its
+ * size, which can be dumped with xalloc_print(). xfree also gains the
+ * ability to detect junk frees.
+ *
+ * Requires project options 'Always generate stack frames',
+ * 'Macsbug Names', and 'Long format' to be enabled.
+ */
+#if !__option(force_frame) || !__option(long_macsbug_names)
+#error
+#endif
+
+#define XALLOC_SYMBOL_SIZE 32
+#define XALLOC_NSYMBOLS 64
+#define XALLOC_MAX_STACK_DEPTH 10
+static char *symbols = NULL;
+struct xalloc {
+ char *stack[XALLOC_MAX_STACK_DEPTH];
+ unsigned long addr;
+ unsigned long size;
+};
+#define XALLOC_NXALLOCS 512
+static struct xalloc *xallocs = NULL;
+#endif
+
void *
-xmalloc(size_t size, char *note)
+xmalloc(size_t size)
{
void *ptr;
#ifdef MALLOC_DEBUG
- struct malloc_map_e *new_malloc_map;
- unsigned short n, j;
+ static char cursym[XALLOC_SYMBOL_SIZE], *tsym, *sym;
+ struct xalloc *xa;
+ unsigned long _a6, ret;
+ unsigned char *code;
+ size_t n, cn, j;
+ short nframe;
#endif
-
+
if (size == 0)
panic("xmalloc: zero size");
ptr = NewPtr(size);
if (ptr == NULL)
- panic("xmalloc(%lu) failed", size);
+ return NULL;
#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;
- }
+ asm {
+ move.l a6,_a6
+ };
+
+ if (symbols == NULL) {
+ symbols = NewPtr(n = XALLOC_SYMBOL_SIZE * XALLOC_NSYMBOLS);
+ if (symbols == NULL)
+ panic("NewPtr failed for xalloc symbols");
+ memset(symbols, 0, n);
+ }
+ if (xallocs == NULL) {
+ xallocs = (struct xalloc *)NewPtr(n = (XALLOC_NXALLOCS *
+ sizeof(struct xalloc)));
+ if (xallocs == NULL)
+ panic("NewPtr failed for xallocs");
+ memset(xallocs, 0, n);
+ }
+
+ xa = NULL;
+ for (n = 0; n < XALLOC_NXALLOCS; n++) {
+ if (xallocs[n].addr == 0) {
+ xa = &xallocs[n];
+ break;
}
-
- malloc_map_compact = false;
}
+ if (xa == NULL)
+ panic("out of xalloc space");
- 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;
+ /*
+ * A6 register points to previous stack A6. Above A6 is our return
+ * address. Walk the code after the return address looking for an RTS
+ * instruction, then walk 3 bytes after that and we should have that
+ * function's symbol. Then jump to the previous A6 that our A6 points
+ * to and do it again to find the previous function symbol, repeating
+ * until we hit "main" or "uthread_begin".
+ */
+ for (nframe = 0; nframe < XALLOC_MAX_STACK_DEPTH; nframe++) {
+ ret = *(unsigned long *)(_a6 + 4);
+ code = (unsigned char *)ret;
+
+ cursym[0] = '\0';
+ for (; ; code += 2) {
+ if (code[0] == 0x4e && code[1] == 0x75) { /* RTS */
+ code += 3;
+ strlcpy(cursym, (char *)code, sizeof(cursym));
+ break;
+ }
}
- 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));
+
+ if (!cursym[0])
break;
+
+ sym = NULL;
+ for (n = 0; n < XALLOC_NSYMBOLS; n++) {
+ tsym = symbols + (XALLOC_SYMBOL_SIZE * n);
+
+ if (tsym[0] == '\0')
+ break;
+ if (strcmp(tsym, cursym) == 0) {
+ sym = tsym;
+ break;
+ }
}
- n = n;
+ if (sym == NULL) {
+ for (n = 0; n < XALLOC_NSYMBOLS; n++) {
+ tsym = symbols + (XALLOC_SYMBOL_SIZE * n);
+ if (tsym[0] != '\0')
+ continue;
+
+ strlcpy(tsym, cursym, XALLOC_SYMBOL_SIZE);
+ sym = tsym;
+ break;
+ }
+ }
+ if (sym == NULL)
+ break;
+
+ xa->stack[nframe] = sym;
+
+ if (strcmp(sym, "main") == 0 || strcmp(sym, "uthread_begin") == 0)
+ break;
+
+ /* walk back up the chain */
+ _a6 = *(unsigned long *)_a6;
}
+
+ xa->addr = (unsigned long)ptr;
+ xa->size = size;
#endif
return ptr;
@@ -202,7 +323,7 @@ xfree(void *ptrptr)
unsigned long *addr = (unsigned long *)ptrptr;
void *ptr;
#ifdef MALLOC_DEBUG
- unsigned long n;
+ size_t n;
#endif
if (ptrptr == NULL)
@@ -211,77 +332,52 @@ xfree(void *ptrptr)
ptr = (void *)*addr;
if (ptr == NULL)
panic("xfree(&NULL) likely a double-free");
-
+
#ifdef MALLOC_DEBUG
- 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';
+ for (n = 0; n < XALLOC_NXALLOCS; n++) {
+ if (xallocs[n].addr == (unsigned long)ptr) {
+ memset(&xallocs[n], 0, sizeof(struct xalloc));
break;
}
}
+ if (n == XALLOC_NXALLOCS)
+ panic("xfree() without xalloc, possibly a junk free",
+ (unsigned long)ptr);
#endif
DisposePtr(ptr);
-
*addr = 0L;
}
void *
-xmalloczero(size_t size, char *note)
+xmalloczero(size_t size)
{
void *ptr;
- ptr = xmalloc(size, note);
- memset(ptr, 0, size);
+ ptr = xmalloc(size);
+ if (ptr != NULL)
+ memset(ptr, 0, size);
return ptr;
}
void *
-xcalloc(size_t nmemb, size_t size, char *note)
+xcalloc(size_t nmemb, size_t size)
{
- void *ptr;
-
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;
+
+ return xmalloczero(nmemb * size);
}
void *
xrealloc(void *src, size_t size)
{
void *ptr, *tsrc;
- unsigned long n;
- char note[MALLOC_NOTE_SIZE] = "realloc from null";
-#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
-
- ptr = xmalloc(size, note);
- if (src != NULL) {
+ ptr = xmalloc(size);
+ if (ptr != NULL && src != NULL) {
memcpy(ptr, src, size);
tsrc = src;
xfree(&tsrc);
@@ -296,25 +392,26 @@ xreallocarray(void *optr, size_t nmemb, size_t size)
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size)
panic("xreallocarray(%lu, %lu) failed", nmemb, size);
+
return xrealloc(optr, size * nmemb);
}
char *
-xstrdup(const char *str, char *note)
+xstrdup(const char *str)
{
char *cp;
size_t len;
len = strlen(str);
+ cp = xmalloc(len + 1);
+ if (cp != NULL)
+ strlcpy(cp, str, len + 1);
- cp = xmalloc(len + 1, note);
- strlcpy(cp, str, len + 1);
-
return cp;
}
char *
-xstrndup(const char *str, size_t maxlen, char *note)
+xstrndup(const char *str, size_t maxlen)
{
char *copy;
const char *cp;
@@ -325,14 +422,57 @@ xstrndup(const char *str, size_t maxlen, char *note)
;
len = (size_t)(cp - str);
- copy = xmalloc(len + 1, note);
- (void)memcpy(copy, str, len);
- copy[len] = '\0';
+ copy = xmalloc(len + 1);
+ if (copy != NULL) {
+ (void)memcpy(copy, str, len);
+ copy[len] = '\0';
+ }
return copy;
}
+#ifdef MALLOC_DEBUG
+void
+xalloc_print(size_t (*printer)(const char *, ...))
+{
+ ssize_t n, j, len;
+ size_t total = 0, nallocs = 0;
+ char chain[128];
+
+ for (n = 0; n < XALLOC_NXALLOCS; n++) {
+ if (xallocs[n].addr == 0)
+ continue;
+
+ total += xallocs[n].size;
+ nallocs++;
+
+ chain[0] = '\0';
+ len = 0;
+ for (j = XALLOC_MAX_STACK_DEPTH - 1; j >= 0; j--) {
+ if (xallocs[n].stack[j] == 0)
+ continue;
+
+ if (chain[0] != '\0') {
+ if (len >= sizeof(chain) - 2)
+ break;
+ chain[len++] = ' ';
+ chain[len++] = ':';
+ chain[len++] = ' ';
+ chain[len++] = '\0';
+ }
+
+ len = strlcat(chain, xallocs[n].stack[j], sizeof(chain));
+ if (len >= sizeof(chain))
+ break;
+ }
+ printer("%ld @ %s", xallocs[n].size, chain);
+ }
+
+ printer("%ld bytes in %ld allocations in use", total, nallocs);
+}
+#endif
+
/*
* String functions
*/
@@ -345,7 +485,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, "getline");
+ *ret = xmalloc(i + 1);
memcpy(*ret, str, i + 1);
(*ret)[i] = '\0';
return i + 1;
@@ -429,6 +569,49 @@ strpos_quoted(char *str, char c)
return -1;
}
+size_t
+hexify(unsigned char *input, size_t len, unsigned char *output)
+{
+ static const char hexchars[] = "0123456789abcdef";
+ size_t n, retlen = 0;
+
+ for (n = 0; n < len; n++) {
+ *output++ = hexchars[input[n] >> 4];
+ *output++ = hexchars[input[n] & 0xf];
+ retlen += 2;
+ }
+
+ return retlen;
+}
+
+size_t
+unhexify(unsigned char *input, size_t len, unsigned char *output)
+{
+ size_t n, retlen = 0;
+ uint8_t c;
+
+ for (n = 0; n < len; n++, input++) {
+ if (*input >= '0' && *input <= '9')
+ c = *input - '0';
+ else if (*input >= 'a' && *input <= 'f')
+ c = *input - 'a' + 10;
+ else if (*input >= 'A' && *input <= 'F')
+ c = *input - 'A' + 10;
+ else
+ continue;
+
+ if (n % 2 == 0)
+ *output = c << 4;
+ else {
+ *output |= c;
+ retlen++;
+ output++;
+ }
+ }
+
+ return retlen;
+}
+
char *
OSTypeToString(OSType type)
{
@@ -443,8 +626,39 @@ OSTypeToString(OSType type)
return ostype_s;
}
+short
+strcasecmp(const char *s1, const char *s2)
+{
+ const unsigned char *cm = strcasecmp_charmap;
+ const unsigned char *us1 = (const unsigned char *)s1;
+ const unsigned char *us2 = (const unsigned char *)s2;
+
+ while (cm[*us1] == cm[*us2++])
+ if (*us1++ == '\0')
+ return (0);
+ return (cm[*us1] - cm[*--us2]);
+}
+
+short
+strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ if (n != 0) {
+ const unsigned char *cm = strcasecmp_charmap;
+ const unsigned char *us1 = (const unsigned char *)s1;
+ const unsigned char *us2 = (const unsigned char *)s2;
+
+ do {
+ if (cm[*us1] != cm[*us2++])
+ return (cm[*us1] - cm[*--us2]);
+ if (*us1++ == '\0')
+ break;
+ } while (--n != 0);
+ }
+ return (0);
+}
+
/*
- * BSD err(3) and warn(3) functions
+ * BSD warn(3) functions
*/
void
@@ -453,13 +667,13 @@ vwarn(short alert_func, const char *format, va_list ap
Rect bounds;
short hit, itype;
WindowPtr win, dialog;
- Handle ihandle;
+ Handle ihandle, okhandle;
Rect irect;
+ progress(NULL);
GetPort(&win);
vsnprintf(err_str, ERROR_STRING_SIZE, format, ap);
-
ParamText(CtoPstr(err_str), "\p", "\p", "\p");
center_in_screen(320, 110, false, &bounds);
@@ -485,7 +699,9 @@ vwarn(short alert_func, const char *format, va_list ap
ShowWindow(dialog);
+ GetDItem(dialog, ok, &itype, &okhandle, &irect);
for (;;) {
+ outline_button((ControlHandle)okhandle);
ModalDialog(0, &hit);
if (hit == ok)
break;
@@ -522,18 +738,6 @@ panic(const char *format, ...)
}
void
-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;
@@ -544,16 +748,6 @@ warn(const char *format, ...)
}
void
-warnx(const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- vwarn(CAUTION_ALERT, format, ap);
- va_end(ap);
-}
-
-void
note(const char *format, ...)
{
va_list ap;
@@ -577,9 +771,11 @@ short
ask(const char *format, ...)
{
Rect bounds;
- short hit;
WindowPtr win, dialog;
va_list ap;
+ Handle ihandle;
+ Rect irect;
+ short hit, itype;
GetPort(&win);
@@ -599,7 +795,9 @@ ask(const char *format, ...)
(WindowPtr)-1L, false, 0, ask_ditl_h);
ShowWindow(dialog);
+ GetDItem(dialog, ok, &itype, &ihandle, &irect);
for (;;) {
+ outline_button((ControlHandle)ihandle);
ModalDialog(0, &hit);
if (hit == 1 || hit == 2)
break;
@@ -641,7 +839,7 @@ about(char *program_name)
ReleaseResource(vers);
appicon_note("%s", vers_s);
} else
- warnx("Can't find version number!");
+ warn("Can't find version number!");
}
void
@@ -708,7 +906,7 @@ center_in_screen(short width, short height, bool title
}
Point
-centered_sf_dialog(void)
+centered_sfget_dialog(void)
{
Point p;
Rect r;
@@ -720,7 +918,37 @@ centered_sf_dialog(void)
return p;
}
+Point
+centered_sfput_dialog(void)
+{
+ Point p;
+ Rect r;
+
+ center_in_screen(320, 200, false, &r);
+ p.h = r.left;
+ p.v = r.top;
+
+ return p;
+}
+void
+outline_button(ControlHandle button)
+{
+ PenState pen;
+ Rect rect;
+
+ SetPort((*button)->contrlOwner);
+ GetPenState(&pen);
+ PenNormal();
+
+ rect = (*button)->contrlRect;
+ InsetRect(&rect, -4, -4);
+ PenSize(3, 3);
+ FrameRoundRect(&rect, (rect.bottom - rect.top) / 2,
+ (rect.bottom - rect.top) / 2);
+ SetPenState(&pen);
+}
+
/*
* General Mac-specific non-GUI functions
*/
@@ -792,7 +1020,7 @@ xGetStringAsChar(short id)
h = xGetString(id);
HLock(h);
l = (*h)[0];
- out = xmalloc(l + 1, "xGetStringAsChar");
+ out = xmalloc(l + 1);
memcpy((void *)out, (void *)(*h + 1), l);
out[l] = '\0';
ReleaseResource(h);
@@ -847,7 +1075,7 @@ getpath(short vRefNum, Str255 fileName, Str255 *ret, b
return 0;
}
- name = xmalloc(FILENAME_MAX, "getpath");
+ name = xmalloc(FILENAME_MAX);
wdir.ioVRefNum = wdir.ioWDVRefNum = vRefNum;
wdir.ioWDIndex = 0;
@@ -881,8 +1109,8 @@ getpath(short vRefNum, Str255 fileName, Str255 *ret, b
wcinfo.ioDrParID = wdir.ioWDDirID;
wcinfo.ioDrDirID = wdir.ioWDDirID;
- tmp = xmalloc(FILENAME_MAX, "getpath");
- tmpret = xmalloc(FILENAME_MAX, "getpath");
+ tmp = xmalloc(FILENAME_MAX);
+ tmpret = xmalloc(FILENAME_MAX);
/* go backwards, prepending each folder's parent */
while (wcinfo.ioDrParID != 1) {
@@ -935,7 +1163,7 @@ stat(char *path, struct stat *sb)
char *ppath;
short ret;
- ppath = xstrdup(path, "stat");
+ ppath = xstrdup(path);
CtoPstr(ppath);
ret = FStat((unsigned char *)ppath, sb);
xfree(&ppath);
@@ -1078,7 +1306,7 @@ copy_file_contents(short source_ref, short dest_ref)
if (error)
return error;
- buf = xmalloc(1024, "copy_file_contents");
+ buf = xmalloc(1024);
while (source_size > 0) {
count = 1024;
@@ -1130,7 +1358,73 @@ FSReadLine(short frefnum, char *buf, size_t buflen)
return total_read;
}
+TrapType
+GetTrapType(unsigned long theTrap)
+{
+ if (BitAnd(theTrap, 0x0800) > 0)
+ return ToolTrap;
+ return OSTrap;
+}
+
+bool
+TrapAvailable(unsigned long trap)
+{
+ TrapType trapType = ToolTrap;
+ unsigned long numToolBoxTraps;
+
+ if (NGetTrapAddress(_InitGraf, ToolTrap) ==
+ NGetTrapAddress(0xAA6E, ToolTrap))
+ numToolBoxTraps = 0x200;
+ else
+ numToolBoxTraps = 0x400;
+
+ trapType = GetTrapType(trap);
+ if (trapType == ToolTrap) {
+ trap = BitAnd(trap, 0x07FF);
+ if (trap >= numToolBoxTraps)
+ trap = _Unimplemented;
+ }
+
+ return (NGetTrapAddress(trap, trapType) !=
+ NGetTrapAddress(_Unimplemented, ToolTrap));
+}
+
+void
+GetSystemFolder(short *vRefNumP, long *dirIDP)
+{
+ SysEnvRec info;
+ long wdProcID;
+
+ SysEnvirons(1, &info);
+ if (GetWDInfo(info.sysVRefNum, vRefNumP, dirIDP, &wdProcID) != noErr) {
+ *vRefNumP = 0;
+ *dirIDP = 0;
+ }
+}
+
+void
+GetSystemSubfolder(OSType folder, bool create, short *vRefNumP, long *dirIDP)
+{
+ bool hasFolderMgr = false;
+ long feature;
+
+ if (TrapAvailable(_GestaltDispatch) &&
+ Gestalt(gestaltFindFolderAttr, &feature) == noErr)
+ hasFolderMgr = true;
+
+ if (!hasFolderMgr) {
+ GetSystemFolder(vRefNumP, dirIDP);
+ return;
+ }
+
+ if (FindFolder(kOnSystemDisk, folder, create, vRefNumP,
+ dirIDP) != noErr) {
+ *vRefNumP = 0;
+ *dirIDP = 0;
+ }
+}
+
/*
* Gestalt functions
*/
@@ -1619,6 +1913,21 @@ RestoreHiddenMenuBar(void)
HiliteMenu(0);
DrawMenuBar();
+}
+
+bool
+CommandPeriodPressed(void)
+{
+ EventRecord event;
+
+ if (!GetNextEvent(keyDownMask | autoKeyMask, &event))
+ return false;
+
+ if ((event.modifiers & cmdKey) &&
+ ((event.message & charCodeMask) == '.'))
+ return true;
+
+ return false;
}
/* C Extensions */
--- util.h Thu Feb 1 21:34:50 2024
+++ util.h Tue Aug 27 19:47:13 2024
@@ -18,27 +18,19 @@
#define __UTIL_H__
#include <stdlib.h>
-#include <limits.h>
+#include "stdint.h"
#include <time.h>
-#ifndef SIZE_MAX
-#define SIZE_MAX ULONG_MAX
-#endif
+/* uncomment to enable malloc tracking */
+#define MALLOC_DEBUG
#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)))
-/*
- * If var of var_size (of which used_size is used) is not big enough to
- * hold add, expand it by grow_amount (to give headroom for subsequent
- * expansion).
- */
#define EXPAND_TO_FIT(var, var_size, used_size, add, grow_amount) { \
if ((used_size) + (add) >= (var_size)) { \
while ((used_size) + (add) >= (var_size)) { \
@@ -48,12 +40,12 @@
} \
}
-#define CHARS_TO_LONG(a,b,c,d) (unsigned long)(\
+#define BYTES_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)(\
+#define BYTES_TO_SHORT(a,b) (unsigned short)(\
((unsigned short)((unsigned char)(a)) << 8) | \
(unsigned short)((unsigned char)(b)) )
@@ -66,19 +58,6 @@
#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
-
/* singly-linked lists */
#define SLIST_HEAD(name, type) struct name { struct type *slh_first; }
#define SLIST_HEAD_INITIALIZER(head) { NULL }
@@ -154,27 +133,32 @@ struct stat {
void util_init(void);
-void * xmalloc(size_t, char *note);
+void * xmalloc(size_t);
void xfree(void *ptrptr);
void xfree_verify(void);
-void * xmalloczero(size_t, char *note);
-void * xcalloc(size_t, size_t, char *note);
+void * xmalloczero(size_t);
+void * xcalloc(size_t, size_t);
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);
+char * xstrdup(const char *);
+char * xstrndup(const char *str, size_t maxlen);
+#ifdef MALLOC_DEBUG
+void xalloc_print(size_t (*printer)(const char *, ...));
+#endif
short getline(char *str, size_t len, char **ret);
const char * ordinal(unsigned short n);
size_t rtrim(char *str, char *chars);
long strpos_quoted(char *str, char c);
+size_t hexify(unsigned char *input, size_t len, unsigned char *output);
+size_t unhexify(unsigned char *input, size_t len, unsigned char *output);
char * OSTypeToString(OSType type);
+short strcasecmp(const char *s1, const char *s2);
+short strncasecmp(const char *s1, const char *s2, size_t n);
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 note(const char *format, ...);
void appicon_note(const char *format, ...);
@@ -185,7 +169,9 @@ 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);
+Point centered_sfget_dialog(void);
+Point centered_sfput_dialog(void);
+void outline_button(ControlHandle button);
Handle xNewHandle(size_t size);
Handle xGetResource(ResType type, short id);
@@ -201,6 +187,11 @@ 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);
+TrapType GetTrapType(unsigned long theTrap);
+bool TrapAvailable(unsigned long trap);
+void GetSystemFolder(short *vRefNumP, long *dirIDP);
+void GetSystemSubfolder(OSType folder, bool create, short *vRefNumP,
+ long *dirIDP);
char * gestalt_machine_type(void);
char * get_version(bool long_version);
@@ -222,6 +213,7 @@ void PasswordDialogFieldFinish(void);
pascal void NullCaretHook(void);
void HideMenuBar(void);
void RestoreHiddenMenuBar(void);
+bool CommandPeriodPressed(void);
size_t strlcat(char *dst, const char *src, size_t dsize);
size_t strlcpy(char *dst, const char *src, size_t dsize);
@@ -229,8 +221,5 @@ char * strndup(const char *str, size_t maxlen);
char * strsep(char **stringp, const char *delim);
short snprintf(char *s, size_t size, const char *fmt, ...);
short vsnprintf(char *s, size_t size, const char *fmt, void *p);
-
-short strcasecmp(const char *s1, const char *s2);
-short strncasecmp(const char *s1, const char *s2, size_t n);
#endif
\ No newline at end of file