AmendHub

Download:

jcs

/

wallops

/

amendments

/

31

util: Sync with upstream, work with THINK C ANSI library


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