// SPDX-License-Identifier: MIT #define _UTIL_IMPL_ #include "util.h" #include #include #include #include #define kMessageAlert 128 void win_center(WindowPtr win) { short barHeight = GetMBarHeight() * 2; // menu + title bar short screenWidth = rect_width(&qd.screenBits.bounds); short screenHeight = rect_height(&qd.screenBits.bounds) - barHeight; short winWidth = rect_width(&win->portRect); short winHeight = rect_height(&win->portRect); MoveWindow(win, (screenWidth - winWidth) / 2, barHeight + (screenHeight - winHeight) / 2, false); } void* xmalloc(size_t sz) { void* p = malloc(sz); if (!p) die("malloc failed"); return p; } void* xrealloc(void* ptr, size_t newlen) { void* p = realloc(ptr, newlen); if (!p) die("realloc failed"); return p; } void die(const char* fmt, ...) { va_list arg; char str[255]; va_start(arg, fmt); lo_vsnprintf(str, 255, fmt, arg); va_end(arg); ParamText(c2pstr(str), nil, nil, nil); StopAlert(kMessageAlert, nil); ExitToShell(); } void warn(const char* fmt, ...) { va_list arg; char str[255]; va_start(arg, fmt); lo_vsnprintf(str, 255, fmt, arg); va_end(arg); ParamText(c2pstr(str), nil, nil, nil); CautionAlert(kMessageAlert, nil); } void info(const char* fmt, ...) { va_list arg; char str[255]; va_start(arg, fmt); lo_vsnprintf(str, 255, fmt, arg); va_end(arg); ParamText(c2pstr(str), nil, nil, nil); NoteAlert(kMessageAlert, nil); } void toolbox_init(void) { InitGraf(&qd.thePort); InitFonts(); FlushEvents(everyEvent, 0); InitWindows(); InitMenus(); TEInit(); InitDialogs(nil); InitCursor(); } void memory_init(void) { short i; Ptr applLimit; applLimit = GetApplLimit(); SetApplLimit(applLimit - 0x8000); MaxApplZone(); for (i = 0; i < 5; ++i) MoreMasters(); } size_t lo_strlcpy(char* dest, const char* src, size_t len) { size_t srclen = strlen(src); size_t copylen; if (len == 0) return srclen; len--; // null terminator copylen = (srclen > len) ? len : srclen; memcpy(dest, src, copylen); dest[copylen] = 0; return srclen; } char* lo_strdup(const char* s) { size_t sz; char *s2; if (!s) return NULL; sz = strlen(s); s2 = xmalloc(sz + 1); memcpy(s2, s, sz + 1); return s2; } // bounded *printf implementation // taken from jcs' wallops, modified to // take a generic output descriptor // instead of a (mocked) FILE object. 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; short fieldWidth; short precision; } default_format; /* Generic output object; can be used for FILE* * or character array output as needed. */ typedef struct { void (*putch)(char, void*); void (*write)(char*, size_t, void*); void *data; size_t maxlen; } output_descriptor; short lo_vfprintf(output_descriptor *fp, const char *fmt, va_list arg); short lo_vfprintf(output_descriptor *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 static 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: fp->putch(c, fp); /* disregard EOF */ ++nwritten; continue; } /* pad on the left */ if (i < F.fieldWidth && !F.leftJustify) { do { fp->putch(' ', fp); /* disregard EOF */ ++nwritten; } while (i < --F.fieldWidth); } /* write the converted result */ fp->write(s, i, fp); /* disregard EOF */ nwritten += i; /* pad on the right */ for (; i < F.fieldWidth; i++) { fp->putch(' ', fp); /* disregard EOF */ ++nwritten; } } /* all done! */ done: return(nwritten); } short lo_snprintf(char *s, size_t size, const char *fmt, ...) { va_list l; short res; va_start(l, fmt); res = lo_vsnprintf(s, size, fmt, l); va_end(l); return res; } void str_putch(char c, void* p); void str_write(char* s, size_t len, void* p); void str_putch(char c, void* p) { output_descriptor* f = p; char* d = f->data; if (f->maxlen) { *((char*)f->data) = c; f->data = (char*)f->data + 1; f->maxlen--; } } void str_write(char* s, size_t len, void* p) { output_descriptor* f = p; size_t to_write = MIN(f->maxlen, len); memcpy(f->data, s, to_write); f->data = (char*)f->data + to_write; f->maxlen -= to_write; } short lo_vsnprintf(char *s, size_t size, const char *fmt, void *p) { output_descriptor f; int n; int zb; memset(&f, 0, sizeof(f)); f.putch = str_putch; f.write = str_write; f.data = s; f.maxlen = size; if (size == 0) zb = s[0]; if ((n = lo_vfprintf(&f, fmt, p)) >= 0) { if (n < size) s[n] = 0; else if (size > 0) s[size - 1] = 0; } if (size == 0) s[0] = zb; return(n); }