AmendHub

Download:

jcs

/

wallops

/

amendments

/

52

util: Sync with upstream, fold in strcasecmp


jcs made amendment 52 about 1 month 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