AmendHub

Download

cyberslak

/

lightsout

/

util.c

 

(View History)

cyberslak   Properly check for Thread Manager before using it Latest amendment: 25 on 2025-04-21

1 // SPDX-License-Identifier: MIT
2
3 #define _UTIL_IMPL_
4 #include "util.h"
5 #include <stdio.h>
6 #include <stdarg.h>
7 #include <string.h>
8 #include <stdlib.h>
9
10 #define kMessageAlert 128
11
12 bool have_thread_manager()
13 {
14 OSErr err;
15 static long resp = -1; // cache response
16
17 if (resp == -1) {
18 err = Gestalt(gestaltThreadMgrAttr, &resp);
19 if (err < 0) {
20 if (err != gestaltUndefSelectorErr)
21 warn("Gestalt failed: %d", err);
22 resp = 0;
23 }
24 }
25
26 return (resp & (1 << gestaltThreadMgrPresent));
27 }
28
29 void win_center(WindowPtr win)
30 {
31 short barHeight = GetMBarHeight() * 2; // menu + title bar
32 short screenWidth = rect_width(&qd.screenBits.bounds);
33 short screenHeight = rect_height(&qd.screenBits.bounds) - barHeight;
34 short winWidth = rect_width(&win->portRect);
35 short winHeight = rect_height(&win->portRect);
36
37 MoveWindow(win, (screenWidth - winWidth) / 2, barHeight + (screenHeight - winHeight) / 2, false);
38 }
39
40 void* xmalloc(size_t sz)
41 {
42 void* p = malloc(sz);
43 if (!p)
44 die("malloc failed");
45 return p;
46 }
47
48 void* xrealloc(void* ptr, size_t newlen)
49 {
50 void* p = realloc(ptr, newlen);
51 if (!p)
52 die("realloc failed");
53 return p;
54 }
55
56 void die(const char* fmt, ...)
57 {
58 va_list arg;
59 char str[255];
60 va_start(arg, fmt);
61
62 lo_vsnprintf(str, 255, fmt, arg);
63
64 va_end(arg);
65
66 ParamText(c2pstr(str), nil, nil, nil);
67 StopAlert(kMessageAlert, nil);
68 ExitToShell();
69 }
70
71 void warn(const char* fmt, ...)
72 {
73 va_list arg;
74 char str[255];
75 va_start(arg, fmt);
76
77 lo_vsnprintf(str, 255, fmt, arg);
78
79 va_end(arg);
80
81 ParamText(c2pstr(str), nil, nil, nil);
82 CautionAlert(kMessageAlert, nil);
83 }
84
85 void info(const char* fmt, ...)
86 {
87 va_list arg;
88 char str[255];
89 va_start(arg, fmt);
90
91 lo_vsnprintf(str, 255, fmt, arg);
92
93 va_end(arg);
94
95 ParamText(c2pstr(str), nil, nil, nil);
96 NoteAlert(kMessageAlert, nil);
97 }
98
99
100 void toolbox_init(void)
101 {
102 InitGraf(&qd.thePort);
103 InitFonts();
104 FlushEvents(everyEvent, 0);
105 InitWindows();
106 InitMenus();
107 TEInit();
108 InitDialogs(nil);
109 InitCursor();
110 }
111
112 void memory_init(void)
113 {
114 short i;
115 Ptr applLimit;
116
117 applLimit = GetApplLimit();
118 SetApplLimit(applLimit - 0x8000);
119
120 MaxApplZone();
121 for (i = 0; i < 5; ++i)
122 MoreMasters();
123 }
124
125 size_t lo_strlcpy(char* dest, const char* src, size_t len)
126 {
127 size_t srclen = strlen(src);
128 size_t copylen;
129
130 if (len == 0)
131 return srclen;
132
133 len--; // null terminator
134
135 copylen = (srclen > len) ? len : srclen;
136 memcpy(dest, src, copylen);
137 dest[copylen] = 0;
138 return srclen;
139 }
140
141 char* lo_strdup(const char* s)
142 {
143 size_t sz;
144 char *s2;
145 if (!s)
146 return NULL;
147
148 sz = strlen(s);
149 s2 = xmalloc(sz + 1);
150 memcpy(s2, s, sz + 1);
151 return s2;
152 }
153
154 // bounded *printf implementation
155 // taken from jcs' wallops, modified to
156 // take a generic output descriptor
157 // instead of a (mocked) FILE object.
158
159 static struct format {
160 unsigned leftJustify : 1;
161 unsigned forceSign : 1;
162 unsigned altForm : 1;
163 unsigned zeroPad : 1;
164 unsigned havePrecision : 1;
165 unsigned hSize : 1;
166 unsigned lSize : 1;
167 unsigned LSize : 1;
168 char sign;
169 char exponent;
170 short fieldWidth;
171 short precision;
172 } default_format;
173
174 /* Generic output object; can be used for FILE*
175 * or character array output as needed.
176 */
177 typedef struct
178 {
179 void (*putch)(char, void*);
180 void (*write)(char*, size_t, void*);
181 void *data;
182 size_t maxlen;
183 } output_descriptor;
184
185 short lo_vfprintf(output_descriptor *fp, const char *fmt, va_list arg);
186
187 short
188 lo_vfprintf(output_descriptor *fp, const char *fmt, va_list arg)
189 {
190 register int c, i, j, nwritten = 0;
191 register unsigned long n;
192 long double x;
193 register char *s;
194 #define VFPRINTF_BUFLEN 512
195 static char buf[VFPRINTF_BUFLEN], *digits, *t;
196 struct format F;
197
198 for (c = *fmt; c; c = *++fmt) {
199 if (c != '%')
200 goto copy1;
201 F = default_format;
202
203 /* decode flags */
204
205 for (;;) {
206 c = *++fmt;
207 if (c == '-')
208 F.leftJustify = TRUE;
209 else if (c == '+')
210 F.forceSign = TRUE;
211 else if (c == ' ')
212 F.sign = ' ';
213 else if (c == '#')
214 F.altForm = TRUE;
215 else if (c == '0')
216 F.zeroPad = TRUE;
217 else
218 break;
219 }
220
221 /* decode field width */
222
223 if (c == '*') {
224 if ((F.fieldWidth = va_arg(arg, int)) < 0) {
225 F.leftJustify = TRUE;
226 F.fieldWidth = -F.fieldWidth;
227 }
228 c = *++fmt;
229 }
230 else {
231 for (; c >= '0' && c <= '9'; c = *++fmt)
232 F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
233 }
234
235 /* decode precision */
236
237 if (c == '.') {
238 if ((c = *++fmt) == '*') {
239 F.precision = va_arg(arg, int);
240 c = *++fmt;
241 }
242 else {
243 for (; c >= '0' && c <= '9'; c = *++fmt)
244 F.precision = (10 * F.precision) + (c - '0');
245 }
246 if (F.precision >= 0)
247 F.havePrecision = TRUE;
248 }
249
250 /* perform appropriate conversion */
251
252 s = &buf[VFPRINTF_BUFLEN];
253 if (F.leftJustify)
254 F.zeroPad = FALSE;
255 conv: switch (c) {
256
257 /* 'h' size modifier */
258
259 case 'h':
260 F.hSize = TRUE;
261 c = *++fmt;
262 goto conv;
263
264 /* 'l' size modifier */
265
266 case 'l':
267 F.lSize = TRUE;
268 c = *++fmt;
269 goto conv;
270
271 /* 'L' size modifier */
272
273 case 'L':
274 F.LSize = TRUE;
275 c = *++fmt;
276 goto conv;
277
278 /* decimal (signed) */
279
280 case 'd':
281 case 'i':
282 if (F.lSize)
283 n = va_arg(arg, long);
284 else
285 n = va_arg(arg, int);
286 if (F.hSize)
287 n = (short) n;
288 if ((long) n < 0) {
289 n = -n;
290 F.sign = '-';
291 }
292 else if (F.forceSign)
293 F.sign = '+';
294 goto decimal;
295
296 /* decimal (unsigned) */
297
298 case 'u':
299 if (F.lSize)
300 n = va_arg(arg, unsigned long);
301 else
302 n = va_arg(arg, unsigned int);
303 if (F.hSize)
304 n = (unsigned short) n;
305 F.sign = 0;
306 goto decimal;
307
308 /* decimal (common code) */
309
310 decimal:
311 if (!F.havePrecision) {
312 if (F.zeroPad) {
313 F.precision = F.fieldWidth;
314 if (F.sign)
315 --F.precision;
316 }
317 if (F.precision < 1)
318 F.precision = 1;
319 }
320 for (i = 0; n; n /= 10, i++)
321 *--s = n % 10 + '0';
322 for (; i < F.precision; i++)
323 *--s = '0';
324 if (F.sign) {
325 *--s = F.sign;
326 i++;
327 }
328 break;
329
330 /* octal (unsigned) */
331
332 case 'o':
333 if (F.lSize)
334 n = va_arg(arg, unsigned long);
335 else
336 n = va_arg(arg, unsigned int);
337 if (F.hSize)
338 n = (unsigned short) n;
339 if (!F.havePrecision) {
340 if (F.zeroPad)
341 F.precision = F.fieldWidth;
342 if (F.precision < 1)
343 F.precision = 1;
344 }
345 for (i = 0; n; n /= 8, i++)
346 *--s = n % 8 + '0';
347 if (F.altForm && i && *s != '0') {
348 *--s = '0';
349 i++;
350 }
351 for (; i < F.precision; i++)
352 *--s = '0';
353 break;
354
355 /* hexadecimal (unsigned) */
356
357 case 'p':
358 F.havePrecision = F.lSize = TRUE;
359 F.precision = 8;
360 /* ... */
361 case 'X':
362 digits = "0123456789ABCDEF";
363 goto hexadecimal;
364 case 'x':
365 digits = "0123456789abcdef";
366 /* ... */
367 hexadecimal:
368 if (F.lSize)
369 n = va_arg(arg, unsigned long);
370 else
371 n = va_arg(arg, unsigned int);
372 if (F.hSize)
373 n = (unsigned short) n;
374 if (!F.havePrecision) {
375 if (F.zeroPad) {
376 F.precision = F.fieldWidth;
377 if (F.altForm)
378 F.precision -= 2;
379 }
380 if (F.precision < 1)
381 F.precision = 1;
382 }
383 for (i = 0; n; n /= 16, i++)
384 *--s = digits[n % 16];
385 for (; i < F.precision; i++)
386 *--s = '0';
387 if (F.altForm) {
388 *--s = c;
389 *--s = '0';
390 i += 2;
391 }
392 break;
393
394 /* character */
395
396 case 'c':
397 *--s = va_arg(arg, int);
398 i = 1;
399 break;
400
401 /* string */
402
403 case 's':
404 s = va_arg(arg, char *);
405 if (F.altForm) {
406 i = (unsigned char) *s++;
407 if (F.havePrecision && i > F.precision)
408 i = F.precision;
409 }
410 else {
411 if (!F.havePrecision)
412 i = strlen(s);
413 else if (t = memchr(s, '\0', F.precision))
414 i = t - s;
415 else
416 i = F.precision;
417 }
418 break;
419
420 /* store # bytes written so far */
421
422 case 'n':
423 s = va_arg(arg, void *);
424 if (F.hSize)
425 * (short *) s = nwritten;
426 else if (F.lSize)
427 * (long *) s = nwritten;
428 else
429 * (int *) s = nwritten;
430 continue;
431
432 /* oops - unknown conversion, abort */
433
434 default:
435 if (c != '%')
436 goto done;
437 copy1:
438 fp->putch(c, fp); /* disregard EOF */
439 ++nwritten;
440 continue;
441 }
442
443 /* pad on the left */
444
445 if (i < F.fieldWidth && !F.leftJustify) {
446 do {
447 fp->putch(' ', fp); /* disregard EOF */
448 ++nwritten;
449 } while (i < --F.fieldWidth);
450 }
451
452 /* write the converted result */
453
454 fp->write(s, i, fp); /* disregard EOF */
455 nwritten += i;
456
457 /* pad on the right */
458
459 for (; i < F.fieldWidth; i++) {
460 fp->putch(' ', fp); /* disregard EOF */
461 ++nwritten;
462 }
463 }
464
465 /* all done! */
466
467 done:
468 return(nwritten);
469 }
470
471 short
472 lo_snprintf(char *s, size_t size, const char *fmt, ...)
473 {
474 va_list l;
475 short res;
476
477 va_start(l, fmt);
478 res = lo_vsnprintf(s, size, fmt, l);
479 va_end(l);
480 return res;
481 }
482
483 void str_putch(char c, void* p);
484 void str_write(char* s, size_t len, void* p);
485
486 void str_putch(char c, void* p)
487 {
488 output_descriptor* f = p;
489 char* d = f->data;
490 if (f->maxlen)
491 {
492 *((char*)f->data) = c;
493 f->data = (char*)f->data + 1;
494 f->maxlen--;
495 }
496 }
497
498 void str_write(char* s, size_t len, void* p)
499 {
500 output_descriptor* f = p;
501 size_t to_write = MIN(f->maxlen, len);
502 memcpy(f->data, s, to_write);
503 f->data = (char*)f->data + to_write;
504 f->maxlen -= to_write;
505 }
506
507 short
508 lo_vsnprintf(char *s, size_t size, const char *fmt, void *p)
509 {
510 output_descriptor f;
511 int n;
512 int zb;
513
514 memset(&f, 0, sizeof(f));
515 f.putch = str_putch;
516 f.write = str_write;
517 f.data = s;
518 f.maxlen = size;
519
520 if (size == 0)
521 zb = s[0];
522
523 if ((n = lo_vfprintf(&f, fmt, p)) >= 0) {
524 if (n < size)
525 s[n] = 0;
526 else if (size > 0)
527 s[size - 1] = 0;
528 }
529
530 if (size == 0)
531 s[0] = zb;
532
533 return(n);
534 }