getrandstring(): use HAVE_POSIX_RANDOM if available (Bob Tennent)..
[s-mailx.git] / auxlily.c
blobda21d078598f8aa2648f518d440a1fe2161b9249
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Auxiliary functions.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
6 */
7 /*
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
39 #undef n_FILE
40 #define n_FILE auxlily
42 #ifndef HAVE_AMALGAMATION
43 # include "nail.h"
44 #endif
46 #include <sys/utsname.h>
48 #include <ctype.h>
49 #include <dirent.h>
51 #ifdef HAVE_SOCKETS
52 # ifdef HAVE_GETADDRINFO
53 # include <sys/socket.h>
54 # endif
56 # include <netdb.h>
57 #endif
59 #ifndef HAVE_POSIX_RANDOM
60 union rand_state {
61 struct rand_arc4 {
62 ui8_t __pad[6];
63 ui8_t _i;
64 ui8_t _j;
65 ui8_t _dat[256];
66 } a;
67 ui8_t b8[sizeof(struct rand_arc4)];
68 ui32_t b32[sizeof(struct rand_arc4) / sizeof(ui32_t)];
70 #endif
72 #ifdef HAVE_NYD
73 struct nyd_info {
74 char const *ni_file;
75 char const *ni_fun;
76 ui32_t ni_chirp_line;
77 ui32_t ni_level;
79 #endif
81 #ifdef HAVE_DEBUG
82 struct mem_chunk {
83 struct mem_chunk *mc_prev;
84 struct mem_chunk *mc_next;
85 char const *mc_file;
86 ui16_t mc_line;
87 ui8_t mc_isfree;
88 ui8_t __dummy;
89 ui32_t mc_size;
92 union mem_ptr {
93 void *p_p;
94 struct mem_chunk *p_c;
95 char *p_cp;
96 ui8_t *p_ui8p;
98 #endif
100 #ifndef HAVE_POSIX_RANDOM
101 static union rand_state *_rand;
102 #endif
104 /* {hold,rele}_all_sigs() */
105 static size_t _alls_depth;
106 static sigset_t _alls_nset, _alls_oset;
108 /* {hold,rele}_sigs() */
109 static size_t _hold_sigdepth;
110 static sigset_t _hold_nset, _hold_oset;
112 /* NYD, memory pool debug */
113 #ifdef HAVE_NYD
114 static ui32_t _nyd_curr, _nyd_level;
115 static struct nyd_info _nyd_infos[NYD_CALLS_MAX];
116 #endif
118 #ifdef HAVE_DEBUG
119 static size_t _mem_aall, _mem_acur, _mem_amax,
120 _mem_mall, _mem_mcur, _mem_mmax;
122 static struct mem_chunk *_mem_list, *_mem_free;
123 #endif
125 /* Our ARC4 random generator with its completely unacademical pseudo
126 * initialization (shall /dev/urandom fail) */
127 #ifndef HAVE_POSIX_RANDOM
128 static void _rand_init(void);
129 static ui32_t _rand_weak(ui32_t seed);
130 SINLINE ui8_t _rand_get8(void);
131 #endif
133 /* Create an ISO 6429 (ECMA-48/ANSI) terminal control escape sequence */
134 #ifdef HAVE_COLOUR
135 static char * _colour_iso6429(char const *wish);
136 #endif
138 #ifdef HAVE_NYD
139 static void _nyd_print(int fd, struct nyd_info *nip);
140 #endif
142 #ifndef HAVE_POSIX_RANDOM
143 static void
144 _rand_init(void)
146 # ifdef HAVE_CLOCK_GETTIME
147 struct timespec ts;
148 # else
149 struct timeval ts;
150 # endif
151 union {int fd; size_t i;} u;
152 ui32_t seed, rnd;
153 NYD2_ENTER;
155 _rand = smalloc(sizeof *_rand);
157 if ((u.fd = open("/dev/urandom", O_RDONLY)) != -1) {
158 bool_t ok = (sizeof *_rand == (size_t)read(u.fd, _rand, sizeof *_rand));
160 close(u.fd);
161 if (ok)
162 goto jleave;
165 for (seed = (uintptr_t)_rand & UI32_MAX, rnd = 21; rnd != 0; --rnd) {
166 for (u.i = NELEM(_rand->b32); u.i-- != 0;) {
167 size_t t, k;
169 # ifdef HAVE_CLOCK_GETTIME
170 clock_gettime(CLOCK_REALTIME, &ts);
171 t = (ui32_t)ts.tv_nsec;
172 # else
173 gettimeofday(&ts, NULL);
174 t = (ui32_t)ts.tv_usec;
175 # endif
176 if (rnd & 1)
177 t = (t >> 16) | (t << 16);
178 _rand->b32[u.i] ^= _rand_weak(seed ^ t);
179 _rand->b32[t % NELEM(_rand->b32)] ^= seed;
180 if (rnd == 7 || rnd == 17)
181 _rand->b32[u.i] ^= _rand_weak(seed ^ (ui32_t)ts.tv_sec);
182 k = _rand->b32[u.i] % NELEM(_rand->b32);
183 _rand->b32[k] ^= _rand->b32[u.i];
184 seed ^= _rand_weak(_rand->b32[k]);
185 if ((rnd & 3) == 3)
186 seed ^= nextprime(seed);
190 for (u.i = 11 * sizeof(_rand->b8); u.i != 0; --u.i)
191 _rand_get8();
192 jleave:
193 NYD2_LEAVE;
196 static ui32_t
197 _rand_weak(ui32_t seed)
199 /* From "Random number generators: good ones are hard to find",
200 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
201 * October 1988, p. 1195.
202 * (In fact: FreeBSD 4.7, /usr/src/lib/libc/stdlib/random.c.) */
203 ui32_t hi;
205 if (seed == 0)
206 seed = 123459876;
207 hi = seed / 127773;
208 seed %= 127773;
209 seed = (seed * 16807) - (hi * 2836);
210 if ((si32_t)seed < 0)
211 seed += SI32_MAX;
212 return seed;
215 SINLINE ui8_t
216 _rand_get8(void)
218 ui8_t si, sj;
220 si = _rand->a._dat[++_rand->a._i];
221 sj = _rand->a._dat[_rand->a._j += si];
222 _rand->a._dat[_rand->a._i] = sj;
223 _rand->a._dat[_rand->a._j] = si;
224 return _rand->a._dat[(ui8_t)(si + sj)];
226 #endif /* HAVE_POSIX_RANDOM */
228 #ifdef HAVE_COLOUR
229 static char *
230 _colour_iso6429(char const *wish)
232 char const * const wish_orig = wish;
233 char *xwish, *cp, cfg[3] = {0, 0, 0};
234 NYD_ENTER;
236 /* Since we use salloc(), reuse the n_strsep() buffer also for the return
237 * value, ensure we have enough room for that */
239 size_t i = strlen(wish) +1;
240 xwish = salloc(MAX(i, sizeof("\033[1;30;40m")));
241 memcpy(xwish, wish, i);
242 wish = xwish;
245 /* Iterate over the colour spec */
246 while ((cp = n_strsep(&xwish, ',', TRU1)) != NULL) {
247 char *y, *x = strchr(cp, '=');
248 if (x == NULL) {
249 jbail:
250 fprintf(stderr, _(
251 "Invalid colour specification \"%s\": >>> %s <<<\n"),
252 wish_orig, cp);
253 continue;
255 *x++ = '\0';
257 /* TODO convert the ft/fg/bg parser into a table-based one! */
258 if (!asccasecmp(cp, "ft")) {
259 if (!asccasecmp(x, "bold"))
260 cfg[0] = '1';
261 else if (!asccasecmp(x, "inverse"))
262 cfg[0] = '7';
263 else if (!asccasecmp(x, "underline"))
264 cfg[0] = '4';
265 else
266 goto jbail;
267 } else if (!asccasecmp(cp, "fg")) {
268 y = cfg + 1;
269 goto jiter_colour;
270 } else if (!asccasecmp(cp, "bg")) {
271 y = cfg + 2;
272 jiter_colour:
273 if (!asccasecmp(x, "black"))
274 *y = '0';
275 else if (!asccasecmp(x, "blue"))
276 *y = '4';
277 else if (!asccasecmp(x, "green"))
278 *y = '2';
279 else if (!asccasecmp(x, "red"))
280 *y = '1';
281 else if (!asccasecmp(x, "brown"))
282 *y = '3';
283 else if (!asccasecmp(x, "magenta"))
284 *y = '5';
285 else if (!asccasecmp(x, "cyan"))
286 *y = '6';
287 else if (!asccasecmp(x, "white"))
288 *y = '7';
289 else
290 goto jbail;
291 } else
292 goto jbail;
295 /* Restore our salloc() buffer, create return value */
296 xwish = UNCONST(wish);
297 if (cfg[0] || cfg[1] || cfg[2]) {
298 xwish[0] = '\033';
299 xwish[1] = '[';
300 xwish += 2;
301 if (cfg[0])
302 *xwish++ = cfg[0];
303 if (cfg[1]) {
304 if (cfg[0])
305 *xwish++ = ';';
306 xwish[0] = '3';
307 xwish[1] = cfg[1];
308 xwish += 2;
310 if (cfg[2]) {
311 if (cfg[0] || cfg[1])
312 *xwish++ = ';';
313 xwish[0] = '4';
314 xwish[1] = cfg[2];
315 xwish += 2;
317 *xwish++ = 'm';
319 *xwish = '\0';
320 NYD_LEAVE;
321 return UNCONST(wish);
323 #endif /* HAVE_COLOUR */
325 #ifdef HAVE_NYD
326 static void
327 _nyd_print(int fd, struct nyd_info *nip)
329 char buf[80];
330 union {int i; size_t z;} u;
332 u.i = snprintf(buf, sizeof buf,
333 "%c [%2" PRIu32 "] %.25s (%.16s:%" PRIu32 ")\n",
334 "=><"[(nip->ni_chirp_line >> 29) & 0x3], nip->ni_level, nip->ni_fun,
335 nip->ni_file, (nip->ni_chirp_line & 0x1FFFFFFFu));
336 if (u.i > 0) {
337 u.z = u.i;
338 if (u.z > sizeof buf)
339 u.z = sizeof buf - 1; /* (Skip \0) */
340 write(fd, buf, u.z);
343 #endif
345 FL void
346 n_raise(int signo)
348 NYD2_ENTER;
349 kill(getpid(), signo);
350 NYD2_LEAVE;
353 FL void
354 panic(char const *format, ...)
356 va_list ap;
357 NYD2_ENTER;
359 fprintf(stderr, _("Panic: "));
361 va_start(ap, format);
362 vfprintf(stderr, format, ap);
363 va_end(ap);
365 fputs("\n", stderr);
366 fflush(stderr);
367 NYD2_LEAVE;
368 abort(); /* Was exit(EXIT_ERR); for a while, but no */
371 FL void
372 alert(char const *format, ...)
374 va_list ap;
375 NYD2_ENTER;
377 fprintf(stderr, _("Panic: "));
379 va_start(ap, format);
380 vfprintf(stderr, format, ap);
381 va_end(ap);
383 fputs("\n", stderr);
384 fflush(stderr);
385 NYD2_LEAVE;
388 FL sighandler_type
389 safe_signal(int signum, sighandler_type handler)
391 struct sigaction nact, oact;
392 sighandler_type rv;
393 NYD2_ENTER;
395 nact.sa_handler = handler;
396 sigemptyset(&nact.sa_mask);
397 nact.sa_flags = 0;
398 #ifdef SA_RESTART
399 nact.sa_flags |= SA_RESTART;
400 #endif
401 rv = (sigaction(signum, &nact, &oact) != 0) ? SIG_ERR : oact.sa_handler;
402 NYD2_LEAVE;
403 return rv;
406 FL void
407 hold_all_sigs(void)
409 NYD2_ENTER;
410 if (_alls_depth++ == 0) {
411 sigfillset(&_alls_nset);
412 sigdelset(&_alls_nset, SIGABRT);
413 #ifdef SIGBUS
414 sigdelset(&_alls_nset, SIGBUS);
415 #endif
416 sigdelset(&_alls_nset, SIGCHLD);
417 sigdelset(&_alls_nset, SIGFPE);
418 sigdelset(&_alls_nset, SIGILL);
419 sigdelset(&_alls_nset, SIGKILL);
420 sigdelset(&_alls_nset, SIGSEGV);
421 sigdelset(&_alls_nset, SIGSTOP);
422 sigprocmask(SIG_BLOCK, &_alls_nset, &_alls_oset);
424 NYD2_LEAVE;
427 FL void
428 rele_all_sigs(void)
430 NYD2_ENTER;
431 if (--_alls_depth == 0)
432 sigprocmask(SIG_SETMASK, &_alls_oset, (sigset_t*)NULL);
433 NYD2_LEAVE;
436 FL void
437 hold_sigs(void)
439 NYD2_ENTER;
440 if (_hold_sigdepth++ == 0) {
441 sigemptyset(&_hold_nset);
442 sigaddset(&_hold_nset, SIGHUP);
443 sigaddset(&_hold_nset, SIGINT);
444 sigaddset(&_hold_nset, SIGQUIT);
445 sigprocmask(SIG_BLOCK, &_hold_nset, &_hold_oset);
447 NYD2_LEAVE;
450 FL void
451 rele_sigs(void)
453 NYD2_ENTER;
454 if (--_hold_sigdepth == 0)
455 sigprocmask(SIG_SETMASK, &_hold_oset, NULL);
456 NYD2_LEAVE;
459 #ifdef HAVE_NYD
460 FL void
461 _nyd_chirp(ui8_t act, char const *file, ui32_t line, char const *fun)
463 struct nyd_info *nip = _nyd_infos;
465 if (_nyd_curr != NELEM(_nyd_infos))
466 nip += _nyd_curr++;
467 else
468 _nyd_curr = 1;
469 nip->ni_file = file;
470 nip->ni_fun = fun;
471 nip->ni_chirp_line = ((ui32_t)(act & 0x3) << 29) | (line & 0x1FFFFFFFu);
472 nip->ni_level = ((act == 0) ? _nyd_level
473 : (act == 1) ? ++_nyd_level : _nyd_level--);
476 FL void
477 _nyd_oncrash(int signo)
479 char s2ibuf[32], *fname, *cp;
480 struct sigaction xact;
481 sigset_t xset;
482 size_t fnl, i;
483 int fd;
484 struct nyd_info *nip;
486 xact.sa_handler = SIG_DFL;
487 sigemptyset(&xact.sa_mask);
488 xact.sa_flags = 0;
489 sigaction(signo, &xact, NULL);
491 fnl = strlen(UAGENT);
492 i = strlen(tempdir);
493 cp =
494 fname = ac_alloc(i + 1 + fnl + 1 + sizeof(".dat"));
495 memcpy(cp , tempdir, i);
496 cp[i++] = '/'; /* xxx pathsep */
497 memcpy(cp += i, UAGENT, fnl);
498 i += fnl;
499 memcpy(cp += fnl, ".dat", sizeof(".dat"));
500 fnl = i + sizeof(".dat") -1;
502 if ((fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0666)) == -1)
503 fd = STDERR_FILENO;
505 # undef _X
506 # define _X(X) (X), sizeof(X) -1
507 write(fd, _X("\n\nNYD: program dying due to signal "));
509 cp = s2ibuf + sizeof(s2ibuf) -1;
510 *cp = '\0';
511 i = signo;
512 do {
513 *--cp = "0123456789"[i % 10];
514 i /= 10;
515 } while (i != 0);
516 write(fd, cp, PTR2SIZE((s2ibuf + sizeof(s2ibuf) -1) - cp));
518 write(fd, _X(":\n"));
520 if (_nyd_infos[NELEM(_nyd_infos) - 1].ni_file != NULL)
521 for (i = _nyd_curr, nip = _nyd_infos + i; i < NELEM(_nyd_infos); ++i)
522 _nyd_print(fd, nip++);
523 for (i = 0, nip = _nyd_infos; i < _nyd_curr; ++i)
524 _nyd_print(fd, nip++);
526 write(fd, _X("----------\nCome up to the lab and see what's on the slab\n"));
528 if (fd != STDERR_FILENO) {
529 write(STDERR_FILENO, _X("Crash NYD listing written to "));
530 write(STDERR_FILENO, fname, fnl);
531 write(STDERR_FILENO, _X("\n"));
532 # undef _X
534 close(fd);
537 ac_free(fname);
539 sigemptyset(&xset);
540 sigaddset(&xset, signo);
541 sigprocmask(SIG_UNBLOCK, &xset, NULL);
542 n_raise(signo);
543 for (;;)
544 _exit(EXIT_ERR);
546 #endif /* HAVE_NYD */
548 FL void
549 touch(struct message *mp)
551 NYD_ENTER;
552 mp->m_flag |= MTOUCH;
553 if (!(mp->m_flag & MREAD))
554 mp->m_flag |= MREAD | MSTATUS;
555 NYD_LEAVE;
558 FL bool_t
559 is_dir(char const *name)
561 struct stat sbuf;
562 bool_t rv;
563 NYD_ENTER;
565 for (rv = FAL0;;)
566 if (!stat(name, &sbuf)) {
567 rv = (S_ISDIR(sbuf.st_mode) != 0);
568 break;
569 } else if (errno != EINTR)
570 break;
571 NYD_LEAVE;
572 return rv;
575 FL int
576 argcount(char **argv)
578 char **ap;
579 NYD_ENTER;
581 for (ap = argv; *ap++ != NULL;)
583 NYD_LEAVE;
584 return (int)PTR2SIZE(ap - argv - 1);
587 FL int
588 screensize(void)
590 int s;
591 char *cp;
592 NYD_ENTER;
594 if ((cp = ok_vlook(screen)) == NULL || (s = atoi(cp)) <= 0)
595 s = scrnheight - 4; /* XXX no magics */
596 NYD_LEAVE;
597 return s;
600 FL char const *
601 get_pager(char const **env_addon)
603 char const *cp;
604 NYD_ENTER;
606 cp = ok_vlook(PAGER);
607 if (cp == NULL || *cp == '\0')
608 cp = XPAGER;
610 if (env_addon != NULL) {
611 *env_addon = NULL;
612 if (strstr(cp, "less") != NULL) {
613 if (!env_blook("LESS", TRU1))
614 *env_addon = "LESS=FRSXi";
615 } else if (strstr(cp, "lv") != NULL) {
616 if (!env_blook("LV", TRU1))
617 *env_addon = "LV=-c";
620 NYD_LEAVE;
621 return cp;
624 FL void
625 page_or_print(FILE *fp, size_t lines)
627 int c;
628 size_t rows;
629 NYD_ENTER;
631 fflush_rewind(fp);
633 rows = 0;
634 if (IS_TTY_SESSION()) {
635 char const *cp;
637 if ((cp = ok_vlook(crt)) != NULL) {
638 char *eptr;
639 sl_i sli = strtol(cp, &eptr, 0);
640 rows = (*cp != '\0' && *eptr == '\0')
641 ? (size_t)sli : (size_t)scrnheight;
644 if (rows > 0 && lines == 0) {
645 while ((c = getc(fp)) != EOF)
646 if (c == '\n' && ++lines > rows)
647 break;
648 really_rewind(fp);
652 if (lines >= rows)
653 run_command(get_pager(NULL), 0, fileno(fp), -1, NULL, NULL, NULL);
654 else
655 while ((c = getc(fp)) != EOF)
656 putchar(c);
657 NYD_LEAVE;
660 FL enum protocol
661 which_protocol(char const *name) /* XXX (->URL (yet auxlily.c)) */
663 struct stat st;
664 char const *cp;
665 char *np;
666 size_t sz;
667 enum protocol rv = PROTO_UNKNOWN;
668 NYD_ENTER;
670 temporary_protocol_ext = NULL;
672 if (name[0] == '%' && name[1] == ':')
673 name += 2;
674 for (cp = name; *cp && *cp != ':'; cp++)
675 if (!alnumchar(*cp))
676 goto jfile;
678 if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
679 if (!strncmp(name, "pop3://", 7)) {
680 #ifdef HAVE_POP3
681 rv = PROTO_POP3;
682 #else
683 fprintf(stderr, _("No POP3 support compiled in.\n"));
684 #endif
685 } else if (!strncmp(name, "pop3s://", 8)) {
686 #if defined HAVE_POP3 && defined HAVE_SSL
687 rv = PROTO_POP3;
688 #else
689 # ifndef HAVE_POP3
690 fprintf(stderr, _("No POP3 support compiled in.\n"));
691 # endif
692 # ifndef HAVE_SSL
693 fprintf(stderr, _("No SSL support compiled in.\n"));
694 # endif
695 #endif
696 } else if (!strncmp(name, "imap://", 7)) {
697 #ifdef HAVE_IMAP
698 rv = PROTO_IMAP;
699 #else
700 fprintf(stderr, _("No IMAP support compiled in.\n"));
701 #endif
702 } else if (!strncmp(name, "imaps://", 8)) {
703 #if defined HAVE_IMAP && defined HAVE_SSL
704 rv = PROTO_IMAP;
705 #else
706 # ifndef HAVE_IMAP
707 fprintf(stderr, _("No IMAP support compiled in.\n"));
708 # endif
709 # ifndef HAVE_SSL
710 fprintf(stderr, _("No SSL support compiled in.\n"));
711 # endif
712 #endif
714 goto jleave;
717 /* TODO This is the de facto maildir code and thus belongs into there!
718 * TODO and: we should have maildir:// and mbox:// pseudo-protos, instead of
719 * TODO or (more likely) in addition to *newfolders*) */
720 jfile:
721 rv = PROTO_FILE;
722 np = ac_alloc((sz = strlen(name)) + 4 +1);
723 memcpy(np, name, sz + 1);
724 if (!stat(name, &st)) {
725 if (S_ISDIR(st.st_mode) &&
726 (memcpy(np+sz, "/tmp", 5), !stat(np, &st) && S_ISDIR(st.st_mode)) &&
727 (memcpy(np+sz, "/new", 5), !stat(np, &st) && S_ISDIR(st.st_mode)) &&
728 (memcpy(np+sz, "/cur", 5), !stat(np, &st) && S_ISDIR(st.st_mode)))
729 rv = PROTO_MAILDIR;
730 } else {
731 if ((memcpy(np+sz, cp=".gz", 4), !stat(np, &st) && S_ISREG(st.st_mode)) ||
732 (memcpy(np+sz, cp=".xz",4), !stat(np,&st) && S_ISREG(st.st_mode)) ||
733 (memcpy(np+sz, cp=".bz2",5), !stat(np, &st) && S_ISREG(st.st_mode)))
734 temporary_protocol_ext = cp;
735 else if ((cp = ok_vlook(newfolders)) != NULL && !strcmp(cp, "maildir"))
736 rv = PROTO_MAILDIR;
738 ac_free(np);
739 jleave:
740 NYD_LEAVE;
741 return rv;
744 FL ui32_t
745 torek_hash(char const *name)
747 /* Chris Torek's hash.
748 * NOTE: need to change *at least* create-okey-map.pl when changing the
749 * algorithm!! */
750 ui32_t h = 0;
751 NYD_ENTER;
753 while (*name != '\0') {
754 h *= 33;
755 h += *name++;
757 NYD_LEAVE;
758 return h;
761 FL unsigned
762 pjw(char const *cp) /* TODO obsolete that -> torek_hash */
764 unsigned h = 0, g;
765 NYD_ENTER;
767 cp--;
768 while (*++cp) {
769 h = (h << 4 & 0xffffffff) + (*cp&0377);
770 if ((g = h & 0xf0000000) != 0) {
771 h = h ^ g >> 24;
772 h = h ^ g;
775 NYD_LEAVE;
776 return h;
779 FL ui32_t
780 nextprime(ui32_t n)
782 static ui32_t const primes[] = {
783 5, 11, 23, 47, 97, 157, 283,
784 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521,
785 131071, 262139, 524287, 1048573, 2097143, 4194301,
786 8388593, 16777213, 33554393, 67108859, 134217689,
787 268435399, 536870909, 1073741789, 2147483647
790 ui32_t i, mprime;
791 NYD_ENTER;
793 i = (n < primes[NELEM(primes) / 4] ? 0
794 : (n < primes[NELEM(primes) / 2] ? NELEM(primes) / 4
795 : NELEM(primes) / 2));
797 if ((mprime = primes[i]) > n)
798 break;
799 while (++i < NELEM(primes));
800 if (i == NELEM(primes) && mprime < n)
801 mprime = n;
802 NYD_LEAVE;
803 return mprime;
806 FL int
807 expand_shell_escape(char const **s, bool_t use_nail_extensions)
809 char const *xs;
810 int c, n;
811 NYD2_ENTER;
813 xs = *s;
815 if ((c = *xs & 0xFF) == '\0')
816 goto jleave;
817 ++xs;
818 if (c != '\\')
819 goto jleave;
821 switch ((c = *xs & 0xFF)) {
822 case '\\': break;
823 case 'a': c = '\a'; break;
824 case 'b': c = '\b'; break;
825 case 'c': c = PROMPT_STOP; break;
826 case 'f': c = '\f'; break;
827 case 'n': c = '\n'; break;
828 case 'r': c = '\r'; break;
829 case 't': c = '\t'; break;
830 case 'v': c = '\v'; break;
831 case '0':
832 for (++xs, c = 0, n = 4; --n > 0 && octalchar(*xs); ++xs) {
833 c <<= 3;
834 c |= *xs - '0';
836 goto jleave;
837 /* S-nail extension for nice (get)prompt(()) support */
838 case '&':
839 case '?':
840 case '$':
841 case '@':
842 if (use_nail_extensions) {
843 switch (c) {
844 case '&': c = ok_blook(bsdcompat) ? '&' : '?'; break;
845 case '?': c = (pstate & PS_EVAL_ERROR) ? '1' : '0'; break;
846 case '$': c = PROMPT_DOLLAR; break;
847 case '@': c = PROMPT_AT; break;
849 break;
851 /* FALLTHRU */
852 case '\0':
853 /* A sole <backslash> at EOS is treated as-is! */
854 /* FALLTHRU */
855 default:
856 c = '\\';
857 goto jleave;
859 ++xs;
860 jleave:
861 *s = xs;
862 NYD2_LEAVE;
863 return c;
866 FL char *
867 getprompt(void) /* TODO evaluate only as necessary (needs a bit) */
869 static char buf[PROMPT_BUFFER_SIZE];
871 char *cp;
872 char const *ccp_base, *ccp;
873 size_t NATCH_CHAR( cclen_base COMMA cclen COMMA ) maxlen, dfmaxlen;
874 bool_t run2;
875 NYD_ENTER;
877 cp = buf;
878 if ((ccp_base = ok_vlook(prompt)) == NULL || *ccp_base == '\0')
879 goto jleave;
880 NATCH_CHAR( cclen_base = strlen(ccp_base); )
882 dfmaxlen = 0; /* keep CC happy */
883 run2 = FAL0;
884 jredo:
885 ccp = ccp_base;
886 NATCH_CHAR( cclen = cclen_base; )
887 maxlen = sizeof(buf) -1;
889 for (;;) {
890 size_t l;
891 int c;
893 if (maxlen == 0)
894 goto jleave;
895 #ifdef HAVE_NATCH_CHAR
896 c = mblen(ccp, cclen); /* TODO use mbrtowc() */
897 if (c <= 0) {
898 mblen(NULL, 0);
899 if (c < 0) {
900 *buf = '?';
901 cp = buf + 1;
902 goto jleave;
904 break;
905 } else if ((l = c) > 1) {
906 if (run2) {
907 memcpy(cp, ccp, l);
908 cp += l;
910 ccp += l;
911 maxlen -= l;
912 continue;
913 } else
914 #endif
915 if ((c = expand_shell_escape(&ccp, TRU1)) > 0) {
916 if (run2)
917 *cp++ = (char)c;
918 --maxlen;
919 continue;
921 if (c == 0 || c == PROMPT_STOP)
922 break;
924 if (run2) {
925 char const *a = (c == PROMPT_DOLLAR) ? account_name : displayname;
926 if (a == NULL)
927 a = "";
928 if ((l = field_put_bidi_clip(cp, dfmaxlen, a, strlen(a))) > 0) {
929 cp += l;
930 maxlen -= l;
931 dfmaxlen -= l;
936 if (!run2) {
937 run2 = TRU1;
938 dfmaxlen = maxlen;
939 goto jredo;
941 jleave:
942 *cp = '\0';
943 NYD_LEAVE;
944 return buf;
947 FL char *
948 nodename(int mayoverride)
950 static char *sys_hostname, *hostname; /* XXX free-at-exit */
952 struct utsname ut;
953 char *hn;
954 #ifdef HAVE_SOCKETS
955 # ifdef HAVE_GETADDRINFO
956 struct addrinfo hints, *res;
957 # else
958 struct hostent *hent;
959 # endif
960 #endif
961 NYD_ENTER;
963 if (mayoverride && (hn = ok_vlook(hostname)) != NULL && *hn != '\0') {
965 } else if ((hn = sys_hostname) == NULL) {
966 uname(&ut);
967 hn = ut.nodename;
968 #ifdef HAVE_SOCKETS
969 # ifdef HAVE_GETADDRINFO
970 memset(&hints, 0, sizeof hints);
971 hints.ai_family = AF_UNSPEC;
972 hints.ai_flags = AI_CANONNAME;
973 if (getaddrinfo(hn, NULL, &hints, &res) == 0) {
974 if (res->ai_canonname != NULL) {
975 size_t l = strlen(res->ai_canonname) +1;
977 hn = ac_alloc(l);
978 memcpy(hn, res->ai_canonname, l);
980 freeaddrinfo(res);
982 # else
983 hent = gethostbyname(hn);
984 if (hent != NULL)
985 hn = hent->h_name;
986 # endif
987 #endif
988 sys_hostname = sstrdup(hn);
989 #if defined HAVE_SOCKETS && defined HAVE_GETADDRINFO
990 if (hn != ut.nodename)
991 ac_free(hn);
992 #endif
993 hn = sys_hostname;
996 if (hostname != NULL && hostname != sys_hostname)
997 free(hostname);
998 hostname = sstrdup(hn);
999 NYD_LEAVE;
1000 return hostname;
1003 FL char *
1004 getrandstring(size_t length)
1006 struct str b64;
1007 char *data;
1008 size_t i;
1009 NYD_ENTER;
1011 #ifndef HAVE_POSIX_RANDOM
1012 if (_rand == NULL)
1013 _rand_init();
1014 #endif
1016 data = ac_alloc(length);
1018 #ifndef HAVE_POSIX_RANDOM
1019 for (i = length; i-- > 0;)
1020 data[i] = (char)_rand_get8();
1021 #else
1022 for (i = length; i > 0;) {
1023 union {ui32_t i4; char c[4];} r;
1024 size_t j;
1026 r.i4 = (ui32_t)arc4random();
1027 switch ((j = i & 3)) {
1028 case 3: data[3] = r.c[3];
1029 case 2: data[2] = r.c[2];
1030 case 1: data[1] = r.c[1];
1031 default: data[0] = r.c[0]; break;
1033 data += j;
1034 i -= j;
1036 #endif
1038 b64_encode_buf(&b64, data, length, B64_SALLOC | B64_RFC4648URL);
1039 ac_free(data);
1040 NYD_LEAVE;
1041 return b64.s;
1044 FL enum okay
1045 makedir(char const *name)
1047 struct stat st;
1048 enum okay rv = STOP;
1049 NYD_ENTER;
1051 if (!mkdir(name, 0700))
1052 rv = OKAY;
1053 else {
1054 int e = errno;
1055 if ((e == EEXIST || e == ENOSYS) && !stat(name, &st) &&
1056 S_ISDIR(st.st_mode))
1057 rv = OKAY;
1059 NYD_LEAVE;
1060 return rv;
1063 #ifdef HAVE_FCHDIR
1064 FL enum okay
1065 cwget(struct cw *cw)
1067 enum okay rv = STOP;
1068 NYD_ENTER;
1070 if ((cw->cw_fd = open(".", O_RDONLY)) == -1)
1071 goto jleave;
1072 if (fchdir(cw->cw_fd) == -1) {
1073 close(cw->cw_fd);
1074 goto jleave;
1076 rv = OKAY;
1077 jleave:
1078 NYD_LEAVE;
1079 return rv;
1082 FL enum okay
1083 cwret(struct cw *cw)
1085 enum okay rv = STOP;
1086 NYD_ENTER;
1088 if (!fchdir(cw->cw_fd))
1089 rv = OKAY;
1090 NYD_LEAVE;
1091 return rv;
1094 FL void
1095 cwrelse(struct cw *cw)
1097 NYD_ENTER;
1098 close(cw->cw_fd);
1099 NYD_LEAVE;
1102 #else /* !HAVE_FCHDIR */
1103 FL enum okay
1104 cwget(struct cw *cw)
1106 enum okay rv = STOP;
1107 NYD_ENTER;
1109 if (getcwd(cw->cw_wd, sizeof cw->cw_wd) != NULL && !chdir(cw->cw_wd))
1110 rv = OKAY;
1111 NYD_LEAVE;
1112 return rv;
1115 FL enum okay
1116 cwret(struct cw *cw)
1118 enum okay rv = STOP;
1119 NYD_ENTER;
1121 if (!chdir(cw->cw_wd))
1122 rv = OKAY;
1123 NYD_LEAVE;
1124 return rv;
1127 FL void
1128 cwrelse(struct cw *cw)
1130 NYD_ENTER;
1131 UNUSED(cw);
1132 NYD_LEAVE;
1134 #endif /* !HAVE_FCHDIR */
1136 FL size_t
1137 field_detect_clip(size_t maxlen, char const *buf, size_t blen)/*TODO mbrtowc()*/
1139 size_t rv;
1140 NYD_ENTER;
1142 #ifdef HAVE_NATCH_CHAR
1143 maxlen = MIN(maxlen, blen);
1144 for (rv = 0; maxlen > 0;) {
1145 int ml = mblen(buf, maxlen);
1146 if (ml <= 0) {
1147 mblen(NULL, 0);
1148 break;
1150 buf += ml;
1151 rv += ml;
1152 maxlen -= ml;
1154 #else
1155 rv = MIN(blen, maxlen);
1156 #endif
1157 NYD_LEAVE;
1158 return rv;
1161 FL size_t
1162 field_put_bidi_clip(char *store, size_t maxlen, char const *buf, size_t blen)
1164 NATCH_CHAR( struct bidi_info bi; )
1165 size_t rv NATCH_CHAR( COMMA i );
1166 NYD_ENTER;
1168 rv = 0;
1169 if (maxlen-- == 0)
1170 goto j_leave;
1172 #ifdef HAVE_NATCH_CHAR
1173 bidi_info_create(&bi);
1174 if (bi.bi_start.l == 0 || !bidi_info_needed(buf, blen)) {
1175 bi.bi_end.l = 0;
1176 goto jnobidi;
1179 if (maxlen >= (i = bi.bi_pad + bi.bi_end.l + bi.bi_start.l))
1180 maxlen -= i;
1181 else
1182 goto jleave;
1184 if ((i = bi.bi_start.l) > 0) {
1185 memcpy(store, bi.bi_start.s, i);
1186 store += i;
1187 rv += i;
1190 jnobidi:
1191 while (maxlen > 0) {
1192 int ml = mblen(buf, blen);
1193 if (ml <= 0) {
1194 mblen(NULL, 0);
1195 break;
1197 if (UICMP(z, maxlen, <, ml))
1198 break;
1199 if (ml == 1)
1200 *store = *buf;
1201 else
1202 memcpy(store, buf, ml);
1203 store += ml;
1204 buf += ml;
1205 rv += ml;
1206 maxlen -= ml;
1209 if ((i = bi.bi_end.l) > 0) {
1210 memcpy(store, bi.bi_end.s, i);
1211 store += i;
1212 rv += i;
1214 jleave:
1215 *store = '\0';
1217 #else
1218 rv = MIN(blen, maxlen);
1219 memcpy(store, buf, rv);
1220 store[rv] = '\0';
1221 #endif
1222 j_leave:
1223 NYD_LEAVE;
1224 return rv;
1227 FL char *
1228 colalign(char const *cp, int col, int fill, int *cols_decr_used_or_null)
1230 NATCH_CHAR( struct bidi_info bi; )
1231 int col_orig = col, n, sz;
1232 bool_t isbidi, isuni, istab, isrepl;
1233 char *nb, *np;
1234 NYD_ENTER;
1236 /* Bidi only on request and when there is 8-bit data */
1237 isbidi = isuni = FAL0;
1238 #ifdef HAVE_NATCH_CHAR
1239 isuni = ((options & OPT_UNICODE) != 0);
1240 bidi_info_create(&bi);
1241 if (bi.bi_start.l == 0)
1242 goto jnobidi;
1243 if (!(isbidi = bidi_info_needed(cp, strlen(cp))))
1244 goto jnobidi;
1246 if ((size_t)col >= bi.bi_pad)
1247 col -= bi.bi_pad;
1248 else
1249 col = 0;
1250 jnobidi:
1251 #endif
1253 np = nb = salloc(mb_cur_max * strlen(cp) +
1254 ((fill ? col : 0)
1255 NATCH_CHAR( + (isbidi ? bi.bi_start.l + bi.bi_end.l : 0) )
1256 +1));
1258 #ifdef HAVE_NATCH_CHAR
1259 if (isbidi) {
1260 memcpy(np, bi.bi_start.s, bi.bi_start.l);
1261 np += bi.bi_start.l;
1263 #endif
1265 while (*cp != '\0') {
1266 istab = FAL0;
1267 #ifdef HAVE_C90AMEND1
1268 if (mb_cur_max > 1) {
1269 wchar_t wc;
1271 n = 1;
1272 isrepl = TRU1;
1273 if ((sz = mbtowc(&wc, cp, mb_cur_max)) == -1)
1274 sz = 1;
1275 else if (wc == L'\t') {
1276 cp += sz - 1; /* Silly, no such charset known (.. until S-Ctext) */
1277 isrepl = FAL0;
1278 istab = TRU1;
1279 } else if (iswprint(wc)) {
1280 # ifndef HAVE_WCWIDTH
1281 n = 1 + (wc >= 0x1100u); /* TODO use S-CText isfullwidth() */
1282 # else
1283 if ((n = wcwidth(wc)) == -1)
1284 n = 1;
1285 else
1286 # endif
1287 isrepl = FAL0;
1289 } else
1290 #endif
1292 n = sz = 1;
1293 istab = (*cp == '\t');
1294 isrepl = !(istab || isprint((uc_i)*cp));
1297 if (n > col)
1298 break;
1299 col -= n;
1301 if (isrepl) {
1302 if (isuni) {
1303 np[0] = (char)0xEFu;
1304 np[1] = (char)0xBFu;
1305 np[2] = (char)0xBDu;
1306 np += 3;
1307 } else
1308 *np++ = '?';
1309 cp += sz;
1310 } else if (istab || (sz == 1 && spacechar(*cp))) {
1311 *np++ = ' ';
1312 ++cp;
1313 } else
1314 while (sz--)
1315 *np++ = *cp++;
1318 if (fill && col != 0) {
1319 if (fill > 0) {
1320 memmove(nb + col, nb, PTR2SIZE(np - nb));
1321 memset(nb, ' ', col);
1322 } else
1323 memset(np, ' ', col);
1324 np += col;
1325 col = 0;
1328 #ifdef HAVE_NATCH_CHAR
1329 if (isbidi) {
1330 memcpy(np, bi.bi_end.s, bi.bi_end.l);
1331 np += bi.bi_end.l;
1333 #endif
1335 *np = '\0';
1336 if (cols_decr_used_or_null != NULL)
1337 *cols_decr_used_or_null -= col_orig - col;
1338 NYD_LEAVE;
1339 return nb;
1342 FL void
1343 makeprint(struct str const *in, struct str *out)
1345 static int print_all_chars = -1;
1347 char const *inp, *maxp;
1348 char *outp;
1349 DBG( size_t msz; )
1350 NYD_ENTER;
1352 if (print_all_chars == -1)
1353 print_all_chars = ok_blook(print_all_chars);
1355 out->s = outp = smalloc(DBG( msz = ) in->l*mb_cur_max + 2u*mb_cur_max +1);
1356 inp = in->s;
1357 maxp = inp + in->l;
1359 if (print_all_chars) {
1360 out->l = in->l;
1361 memcpy(outp, inp, out->l);
1362 goto jleave;
1365 #ifdef HAVE_NATCH_CHAR
1366 if (mb_cur_max > 1) {
1367 char mbb[MB_LEN_MAX + 1];
1368 wchar_t wc;
1369 int i, n;
1370 bool_t isuni = ((options & OPT_UNICODE) != 0);
1372 out->l = 0;
1373 while (inp < maxp) {
1374 if (*inp & 0200)
1375 n = mbtowc(&wc, inp, PTR2SIZE(maxp - inp));
1376 else {
1377 wc = *inp;
1378 n = 1;
1380 if (n == -1) {
1381 /* FIXME Why mbtowc() resetting here?
1382 * FIXME what about ISO 2022-JP plus -- those
1383 * FIXME will loose shifts, then!
1384 * FIXME THUS - we'd need special "known points"
1385 * FIXME to do so - say, after a newline!!
1386 * FIXME WE NEED TO CHANGE ALL USES +MBLEN! */
1387 mbtowc(&wc, NULL, mb_cur_max);
1388 wc = isuni ? 0xFFFD : '?';
1389 n = 1;
1390 } else if (n == 0)
1391 n = 1;
1392 inp += n;
1393 if (!iswprint(wc) && wc != '\n' && wc != '\r' && wc != '\b' &&
1394 wc != '\t') {
1395 if ((wc & ~(wchar_t)037) == 0)
1396 wc = isuni ? 0x2400 | wc : '?';
1397 else if (wc == 0177)
1398 wc = isuni ? 0x2421 : '?';
1399 else
1400 wc = isuni ? 0x2426 : '?';
1402 if ((n = wctomb(mbb, wc)) <= 0)
1403 continue;
1404 out->l += n;
1405 assert(out->l < msz);
1406 for (i = 0; i < n; ++i)
1407 *outp++ = mbb[i];
1409 } else
1410 #endif /* NATCH_CHAR */
1412 int c;
1413 while (inp < maxp) {
1414 c = *inp++ & 0377;
1415 if (!isprint(c) && c != '\n' && c != '\r' && c != '\b' && c != '\t')
1416 c = '?';
1417 *outp++ = c;
1419 out->l = in->l;
1421 jleave:
1422 out->s[out->l] = '\0';
1423 NYD_LEAVE;
1426 FL size_t
1427 delctrl(char *cp, size_t len)
1429 size_t x, y;
1430 NYD_ENTER;
1432 for (x = y = 0; x < len; ++x)
1433 if (!cntrlchar(cp[x]))
1434 cp[y++] = cp[x];
1435 cp[y] = '\0';
1436 NYD_LEAVE;
1437 return y;
1440 FL char *
1441 prstr(char const *s)
1443 struct str in, out;
1444 char *rp;
1445 NYD_ENTER;
1447 in.s = UNCONST(s);
1448 in.l = strlen(s);
1449 makeprint(&in, &out);
1450 rp = savestrbuf(out.s, out.l);
1451 free(out.s);
1452 NYD_LEAVE;
1453 return rp;
1456 FL int
1457 prout(char const *s, size_t sz, FILE *fp)
1459 struct str in, out;
1460 int n;
1461 NYD_ENTER;
1463 in.s = UNCONST(s);
1464 in.l = sz;
1465 makeprint(&in, &out);
1466 n = fwrite(out.s, 1, out.l, fp);
1467 free(out.s);
1468 NYD_LEAVE;
1469 return n;
1472 FL size_t
1473 putuc(int u, int c, FILE *fp)
1475 size_t rv;
1476 NYD_ENTER;
1477 UNUSED(u);
1479 #ifdef HAVE_NATCH_CHAR
1480 if ((options & OPT_UNICODE) && (u & ~(wchar_t)0177)) {
1481 char mbb[MB_LEN_MAX];
1482 int i, n;
1484 if ((n = wctomb(mbb, u)) > 0) {
1485 rv = wcwidth(u);
1486 for (i = 0; i < n; ++i)
1487 if (putc(mbb[i] & 0377, fp) == EOF) {
1488 rv = 0;
1489 break;
1491 } else if (n == 0)
1492 rv = (putc('\0', fp) != EOF);
1493 else
1494 rv = 0;
1495 } else
1496 #endif
1497 rv = (putc(c, fp) != EOF);
1498 NYD_LEAVE;
1499 return rv;
1502 FL bool_t
1503 bidi_info_needed(char const *bdat, size_t blen)
1505 bool_t rv = FAL0;
1506 NYD_ENTER;
1508 #ifdef HAVE_NATCH_CHAR
1509 if (options & OPT_UNICODE)
1510 while (blen > 0) {
1511 /* TODO Checking for BIDI character: use S-CText fromutf8
1512 * TODO plus isrighttoleft (or whatever there will be)! */
1513 ui32_t c = n_utf8_to_utf32(&bdat, &blen);
1514 if (c == UI32_MAX)
1515 break;
1517 if (c <= 0x05BE)
1518 continue;
1520 /* (Very very fuzzy, awaiting S-CText for good) */
1521 if ((c >= 0x05BE && c <= 0x08E3) ||
1522 (c >= 0xFB1D && c <= 0xFEFC) ||
1523 (c >= 0x10800 && c <= 0x10C48) ||
1524 (c >= 0x1EE00 && c <= 0x1EEF1)) {
1525 rv = TRU1;
1526 break;
1529 #endif /* HAVE_NATCH_CHAR */
1530 NYD_LEAVE;
1531 return rv;
1534 FL void
1535 bidi_info_create(struct bidi_info *bip)
1537 /* Unicode: how to isolate RIGHT-TO-LEFT scripts via *headline-bidi*
1538 * 1.1 (Jun 1993): U+200E (E2 80 8E) LEFT-TO-RIGHT MARK
1539 * 6.3 (Sep 2013): U+2068 (E2 81 A8) FIRST STRONG ISOLATE,
1540 * U+2069 (E2 81 A9) POP DIRECTIONAL ISOLATE
1541 * Worse results seen for: U+202D "\xE2\x80\xAD" U+202C "\xE2\x80\xAC" */
1542 NATCH_CHAR( char const *hb; )
1543 NYD_ENTER;
1545 memset(bip, 0, sizeof *bip);
1546 bip->bi_start.s = bip->bi_end.s = UNCONST("");
1548 #ifdef HAVE_NATCH_CHAR
1549 if ((options & OPT_UNICODE) && (hb = ok_vlook(headline_bidi)) != NULL) {
1550 switch (*hb) {
1551 case '3':
1552 bip->bi_pad = 2;
1553 /* FALLTHRU */
1554 case '2':
1555 bip->bi_start.s = bip->bi_end.s = UNCONST("\xE2\x80\x8E");
1556 break;
1557 case '1':
1558 bip->bi_pad = 2;
1559 /* FALLTHRU */
1560 default:
1561 bip->bi_start.s = UNCONST("\xE2\x81\xA8");
1562 bip->bi_end.s = UNCONST("\xE2\x81\xA9");
1563 break;
1565 bip->bi_start.l = bip->bi_end.l = 3;
1567 #endif
1568 NYD_LEAVE;
1571 #ifdef HAVE_COLOUR
1572 FL void
1573 colour_table_create(bool_t pager_used)
1575 union {char *cp; char const *ccp; void *vp; struct colour_table *ctp;} u;
1576 size_t i;
1577 struct colour_table *ct;
1578 NYD_ENTER;
1580 if (ok_blook(colour_disable) || (pager_used && !ok_blook(colour_pager)))
1581 goto jleave;
1582 else {
1583 char *term, *okterms;
1585 if ((term = env_vlook("TERM", FAL0)) == NULL)
1586 goto jleave;
1587 /* terminfo rocks: if we find "color", assume it's right */
1588 if (strstr(term, "color") != NULL)
1589 goto jok;
1590 if ((okterms = ok_vlook(colour_terms)) == NULL)
1591 okterms = UNCONST(COLOUR_TERMS);
1592 okterms = savestr(okterms);
1594 i = strlen(term);
1595 while ((u.cp = n_strsep(&okterms, ',', TRU1)) != NULL)
1596 if (!strncmp(u.cp, term, i))
1597 goto jok;
1598 goto jleave;
1601 jok:
1602 colour_table = ct = salloc(sizeof *ct); /* XXX lex.c yet resets (FILTER!) */
1603 { static struct {
1604 enum okeys okey;
1605 enum colourspec cspec;
1606 char const *defval;
1607 } const map[] = {
1608 {ok_v_colour_msginfo, COLOURSPEC_MSGINFO, COLOUR_MSGINFO},
1609 {ok_v_colour_partinfo, COLOURSPEC_PARTINFO, COLOUR_PARTINFO},
1610 {ok_v_colour_from_, COLOURSPEC_FROM_, COLOUR_FROM_},
1611 {ok_v_colour_header, COLOURSPEC_HEADER, COLOUR_HEADER},
1612 {ok_v_colour_uheader, COLOURSPEC_UHEADER, COLOUR_UHEADER}
1615 for (i = 0; i < NELEM(map); ++i) {
1616 if ((u.cp = _var_oklook(map[i].okey)) == NULL)
1617 u.ccp = map[i].defval;
1618 u.cp = _colour_iso6429(u.ccp);
1619 ct->ct_csinfo[map[i].cspec].l = strlen(u.cp);
1620 ct->ct_csinfo[map[i].cspec].s = u.cp;
1623 ct->ct_csinfo[COLOURSPEC_RESET].l = sizeof("\033[0m") -1;
1624 ct->ct_csinfo[COLOURSPEC_RESET].s = UNCONST("\033[0m");
1626 if ((u.cp = ok_vlook(colour_user_headers)) == NULL)
1627 u.ccp = COLOUR_USER_HEADERS;
1628 ct->ct_csinfo[COLOURSPEC_RESET + 1].l = i = strlen(u.ccp);
1629 ct->ct_csinfo[COLOURSPEC_RESET + 1].s = (i == 0) ? NULL : savestr(u.ccp);
1630 jleave:
1631 NYD_LEAVE;
1634 FL void
1635 colour_put(FILE *fp, enum colourspec cs)
1637 NYD_ENTER;
1638 if (colour_table != NULL) {
1639 struct str const *cp = colour_get(cs);
1641 fwrite(cp->s, cp->l, 1, fp);
1643 NYD_LEAVE;
1646 FL void
1647 colour_put_header(FILE *fp, char const *name)
1649 enum colourspec cs = COLOURSPEC_HEADER;
1650 struct str const *uheads;
1651 char *cp, *cp_base, *x;
1652 size_t namelen;
1653 NYD_ENTER;
1655 if (colour_table == NULL)
1656 goto j_leave;
1657 /* Normal header colours if there are no user headers */
1658 uheads = colour_table->ct_csinfo + COLOURSPEC_RESET + 1;
1659 if (uheads->s == NULL)
1660 goto jleave;
1662 /* Iterate over all entries in the *colour-user-headers* list */
1663 cp = ac_alloc(uheads->l +1);
1664 memcpy(cp, uheads->s, uheads->l +1);
1665 cp_base = cp;
1666 namelen = strlen(name);
1667 while ((x = n_strsep(&cp, ',', TRU1)) != NULL) {
1668 size_t l = (cp != NULL) ? PTR2SIZE(cp - x) - 1 : strlen(x);
1669 if (l == namelen && !ascncasecmp(x, name, namelen)) {
1670 cs = COLOURSPEC_UHEADER;
1671 break;
1674 ac_free(cp_base);
1675 jleave:
1676 colour_put(fp, cs);
1677 j_leave:
1678 NYD_LEAVE;
1681 FL void
1682 colour_reset(FILE *fp)
1684 NYD_ENTER;
1685 if (colour_table != NULL)
1686 fwrite("\033[0m", 4, 1, fp);
1687 NYD_LEAVE;
1690 FL struct str const *
1691 colour_get(enum colourspec cs)
1693 struct str const *rv = NULL;
1694 NYD_ENTER;
1696 if (colour_table != NULL)
1697 if ((rv = colour_table->ct_csinfo + cs)->s == NULL)
1698 rv = NULL;
1699 NYD_LEAVE;
1700 return rv;
1702 #endif /* HAVE_COLOUR */
1704 FL si8_t
1705 boolify(char const *inbuf, uiz_t inlen, si8_t emptyrv)
1707 char *dat, *eptr;
1708 sl_i sli;
1709 si8_t rv;
1710 NYD_ENTER;
1712 assert(inlen == 0 || inbuf != NULL);
1714 if (inlen == UIZ_MAX)
1715 inlen = strlen(inbuf);
1717 if (inlen == 0)
1718 rv = (emptyrv >= 0) ? (emptyrv == 0 ? 0 : 1) : -1;
1719 else {
1720 if ((inlen == 1 && *inbuf == '1') ||
1721 !ascncasecmp(inbuf, "true", inlen) ||
1722 !ascncasecmp(inbuf, "yes", inlen) ||
1723 !ascncasecmp(inbuf, "on", inlen))
1724 rv = 1;
1725 else if ((inlen == 1 && *inbuf == '0') ||
1726 !ascncasecmp(inbuf, "false", inlen) ||
1727 !ascncasecmp(inbuf, "no", inlen) ||
1728 !ascncasecmp(inbuf, "off", inlen))
1729 rv = 0;
1730 else {
1731 dat = ac_alloc(inlen +1);
1732 memcpy(dat, inbuf, inlen);
1733 dat[inlen] = '\0';
1735 sli = strtol(dat, &eptr, 0);
1736 if (*dat != '\0' && *eptr == '\0')
1737 rv = (sli != 0);
1738 else
1739 rv = -1;
1741 ac_free(dat);
1744 NYD_LEAVE;
1745 return rv;
1748 FL si8_t
1749 quadify(char const *inbuf, uiz_t inlen, char const *prompt, si8_t emptyrv)
1751 si8_t rv;
1752 NYD_ENTER;
1754 assert(inlen == 0 || inbuf != NULL);
1756 if (inlen == UIZ_MAX)
1757 inlen = strlen(inbuf);
1759 if (inlen == 0)
1760 rv = (emptyrv >= 0) ? (emptyrv == 0 ? 0 : 1) : -1;
1761 else if ((rv = boolify(inbuf, inlen, -1)) < 0 &&
1762 !ascncasecmp(inbuf, "ask-", 4) &&
1763 (rv = boolify(inbuf + 4, inlen - 4, -1)) >= 0 &&
1764 (options & OPT_INTERACTIVE)) {
1765 if (prompt != NULL)
1766 fputs(prompt, stdout);
1767 rv = getapproval(NULL, rv);
1769 NYD_LEAVE;
1770 return rv;
1773 FL void
1774 time_current_update(struct time_current *tc, bool_t full_update)
1776 NYD_ENTER;
1777 tc->tc_time = time(NULL);
1778 if (full_update) {
1779 memcpy(&tc->tc_gm, gmtime(&tc->tc_time), sizeof tc->tc_gm);
1780 memcpy(&tc->tc_local, localtime(&tc->tc_time), sizeof tc->tc_local);
1781 sstpcpy(tc->tc_ctime, ctime(&tc->tc_time));
1783 NYD_LEAVE;
1786 static void
1787 _out_of_memory(void)
1789 panic("no memory");
1792 #ifndef HAVE_DEBUG
1793 FL void *
1794 smalloc(size_t s SMALLOC_DEBUG_ARGS)
1796 void *rv;
1797 NYD2_ENTER;
1799 if (s == 0)
1800 s = 1;
1801 if ((rv = malloc(s)) == NULL)
1802 _out_of_memory();
1803 NYD2_LEAVE;
1804 return rv;
1807 FL void *
1808 srealloc(void *v, size_t s SMALLOC_DEBUG_ARGS)
1810 void *rv;
1811 NYD2_ENTER;
1813 if (s == 0)
1814 s = 1;
1815 if (v == NULL)
1816 rv = smalloc(s);
1817 else if ((rv = realloc(v, s)) == NULL)
1818 _out_of_memory();
1819 NYD2_LEAVE;
1820 return rv;
1823 FL void *
1824 scalloc(size_t nmemb, size_t size SMALLOC_DEBUG_ARGS)
1826 void *rv;
1827 NYD2_ENTER;
1829 if (size == 0)
1830 size = 1;
1831 if ((rv = calloc(nmemb, size)) == NULL)
1832 _out_of_memory();
1833 NYD2_LEAVE;
1834 return rv;
1837 #else /* !HAVE_DEBUG */
1838 CTA(sizeof(char) == sizeof(ui8_t));
1840 # define _HOPE_SIZE (2 * 8 * sizeof(char))
1841 # define _HOPE_SET(C) \
1842 do {\
1843 union mem_ptr __xl, __xu;\
1844 struct mem_chunk *__xc;\
1845 __xl.p_p = (C).p_p;\
1846 __xc = __xl.p_c - 1;\
1847 __xu.p_p = __xc;\
1848 (C).p_cp += 8;\
1849 __xl.p_ui8p[0]=0xDE; __xl.p_ui8p[1]=0xAA;\
1850 __xl.p_ui8p[2]=0x55; __xl.p_ui8p[3]=0xAD;\
1851 __xl.p_ui8p[4]=0xBE; __xl.p_ui8p[5]=0x55;\
1852 __xl.p_ui8p[6]=0xAA; __xl.p_ui8p[7]=0xEF;\
1853 __xu.p_ui8p += __xc->mc_size - 8;\
1854 __xu.p_ui8p[0]=0xDE; __xu.p_ui8p[1]=0xAA;\
1855 __xu.p_ui8p[2]=0x55; __xu.p_ui8p[3]=0xAD;\
1856 __xu.p_ui8p[4]=0xBE; __xu.p_ui8p[5]=0x55;\
1857 __xu.p_ui8p[6]=0xAA; __xu.p_ui8p[7]=0xEF;\
1858 } while (0)
1859 # define _HOPE_GET_TRACE(C,BAD) \
1860 do {\
1861 (C).p_cp += 8;\
1862 _HOPE_GET(C, BAD);\
1863 (C).p_cp += 8;\
1864 } while(0)
1865 # define _HOPE_GET(C,BAD) \
1866 do {\
1867 union mem_ptr __xl, __xu;\
1868 struct mem_chunk *__xc;\
1869 ui32_t __i;\
1870 __xl.p_p = (C).p_p;\
1871 __xl.p_cp -= 8;\
1872 (C).p_cp = __xl.p_cp;\
1873 __xc = __xl.p_c - 1;\
1874 (BAD) = FAL0;\
1875 __i = 0;\
1876 if (__xl.p_ui8p[0] != 0xDE) __i |= 1<<0;\
1877 if (__xl.p_ui8p[1] != 0xAA) __i |= 1<<1;\
1878 if (__xl.p_ui8p[2] != 0x55) __i |= 1<<2;\
1879 if (__xl.p_ui8p[3] != 0xAD) __i |= 1<<3;\
1880 if (__xl.p_ui8p[4] != 0xBE) __i |= 1<<4;\
1881 if (__xl.p_ui8p[5] != 0x55) __i |= 1<<5;\
1882 if (__xl.p_ui8p[6] != 0xAA) __i |= 1<<6;\
1883 if (__xl.p_ui8p[7] != 0xEF) __i |= 1<<7;\
1884 if (__i != 0) {\
1885 (BAD) = TRU1;\
1886 alert("%p: corrupt lower canary: 0x%02X: %s, line %d",\
1887 __xl.p_p, __i, mdbg_file, mdbg_line);\
1889 __xu.p_p = __xc;\
1890 __xu.p_ui8p += __xc->mc_size - 8;\
1891 __i = 0;\
1892 if (__xu.p_ui8p[0] != 0xDE) __i |= 1<<0;\
1893 if (__xu.p_ui8p[1] != 0xAA) __i |= 1<<1;\
1894 if (__xu.p_ui8p[2] != 0x55) __i |= 1<<2;\
1895 if (__xu.p_ui8p[3] != 0xAD) __i |= 1<<3;\
1896 if (__xu.p_ui8p[4] != 0xBE) __i |= 1<<4;\
1897 if (__xu.p_ui8p[5] != 0x55) __i |= 1<<5;\
1898 if (__xu.p_ui8p[6] != 0xAA) __i |= 1<<6;\
1899 if (__xu.p_ui8p[7] != 0xEF) __i |= 1<<7;\
1900 if (__i != 0) {\
1901 (BAD) = TRU1;\
1902 alert("%p: corrupt upper canary: 0x%02X: %s, line %d",\
1903 __xl.p_p, __i, mdbg_file, mdbg_line);\
1905 if (BAD)\
1906 alert(" ..canary last seen: %s, line %" PRIu16 "",\
1907 __xc->mc_file, __xc->mc_line);\
1908 } while (0)
1910 FL void *
1911 (smalloc)(size_t s SMALLOC_DEBUG_ARGS)
1913 union mem_ptr p;
1914 NYD2_ENTER;
1916 if (s == 0)
1917 s = 1;
1918 if (s > UI32_MAX - sizeof(struct mem_chunk) - _HOPE_SIZE)
1919 panic("smalloc(): allocation too large: %s, line %d\n",
1920 mdbg_file, mdbg_line);
1921 s += sizeof(struct mem_chunk) + _HOPE_SIZE;
1923 if ((p.p_p = (malloc)(s)) == NULL)
1924 _out_of_memory();
1925 p.p_c->mc_prev = NULL;
1926 if ((p.p_c->mc_next = _mem_list) != NULL)
1927 _mem_list->mc_prev = p.p_c;
1928 p.p_c->mc_file = mdbg_file;
1929 p.p_c->mc_line = (ui16_t)mdbg_line;
1930 p.p_c->mc_isfree = FAL0;
1931 p.p_c->mc_size = (ui32_t)s;
1933 _mem_list = p.p_c++;
1934 _HOPE_SET(p);
1936 ++_mem_aall;
1937 ++_mem_acur;
1938 _mem_amax = MAX(_mem_amax, _mem_acur);
1939 _mem_mall += s;
1940 _mem_mcur += s;
1941 _mem_mmax = MAX(_mem_mmax, _mem_mcur);
1942 NYD2_LEAVE;
1943 return p.p_p;
1946 FL void *
1947 (srealloc)(void *v, size_t s SMALLOC_DEBUG_ARGS)
1949 union mem_ptr p;
1950 bool_t isbad;
1951 NYD2_ENTER;
1953 if ((p.p_p = v) == NULL) {
1954 p.p_p = (smalloc)(s, mdbg_file, mdbg_line);
1955 goto jleave;
1958 _HOPE_GET(p, isbad);
1959 --p.p_c;
1960 if (p.p_c->mc_isfree) {
1961 fprintf(stderr, "srealloc(): region freed! At %s, line %d\n"
1962 "\tLast seen: %s, line %" PRIu16 "\n",
1963 mdbg_file, mdbg_line, p.p_c->mc_file, p.p_c->mc_line);
1964 goto jforce;
1967 if (p.p_c == _mem_list)
1968 _mem_list = p.p_c->mc_next;
1969 else
1970 p.p_c->mc_prev->mc_next = p.p_c->mc_next;
1971 if (p.p_c->mc_next != NULL)
1972 p.p_c->mc_next->mc_prev = p.p_c->mc_prev;
1974 --_mem_acur;
1975 _mem_mcur -= p.p_c->mc_size;
1976 jforce:
1977 if (s == 0)
1978 s = 1;
1979 if (s > UI32_MAX - sizeof(struct mem_chunk) - _HOPE_SIZE)
1980 panic("srealloc(): allocation too large: %s, line %d\n",
1981 mdbg_file, mdbg_line);
1982 s += sizeof(struct mem_chunk) + _HOPE_SIZE;
1984 if ((p.p_p = (realloc)(p.p_c, s)) == NULL)
1985 _out_of_memory();
1986 p.p_c->mc_prev = NULL;
1987 if ((p.p_c->mc_next = _mem_list) != NULL)
1988 _mem_list->mc_prev = p.p_c;
1989 p.p_c->mc_file = mdbg_file;
1990 p.p_c->mc_line = (ui16_t)mdbg_line;
1991 p.p_c->mc_isfree = FAL0;
1992 p.p_c->mc_size = (ui32_t)s;
1993 _mem_list = p.p_c++;
1994 _HOPE_SET(p);
1996 ++_mem_aall;
1997 ++_mem_acur;
1998 _mem_amax = MAX(_mem_amax, _mem_acur);
1999 _mem_mall += s;
2000 _mem_mcur += s;
2001 _mem_mmax = MAX(_mem_mmax, _mem_mcur);
2002 jleave:
2003 NYD2_LEAVE;
2004 return p.p_p;
2007 FL void *
2008 (scalloc)(size_t nmemb, size_t size SMALLOC_DEBUG_ARGS)
2010 union mem_ptr p;
2011 NYD2_ENTER;
2013 if (size == 0)
2014 size = 1;
2015 if (nmemb == 0)
2016 nmemb = 1;
2017 if (size > UI32_MAX - sizeof(struct mem_chunk) - _HOPE_SIZE)
2018 panic("scalloc(): allocation size too large: %s, line %d\n",
2019 mdbg_file, mdbg_line);
2020 if ((UI32_MAX - sizeof(struct mem_chunk) - _HOPE_SIZE) / nmemb < size)
2021 panic("scalloc(): allocation count too large: %s, line %d\n",
2022 mdbg_file, mdbg_line);
2024 size *= nmemb;
2025 size += sizeof(struct mem_chunk) + _HOPE_SIZE;
2027 if ((p.p_p = (malloc)(size)) == NULL)
2028 _out_of_memory();
2029 memset(p.p_p, 0, size);
2030 p.p_c->mc_prev = NULL;
2031 if ((p.p_c->mc_next = _mem_list) != NULL)
2032 _mem_list->mc_prev = p.p_c;
2033 p.p_c->mc_file = mdbg_file;
2034 p.p_c->mc_line = (ui16_t)mdbg_line;
2035 p.p_c->mc_isfree = FAL0;
2036 p.p_c->mc_size = (ui32_t)size;
2037 _mem_list = p.p_c++;
2038 _HOPE_SET(p);
2040 ++_mem_aall;
2041 ++_mem_acur;
2042 _mem_amax = MAX(_mem_amax, _mem_acur);
2043 _mem_mall += size;
2044 _mem_mcur += size;
2045 _mem_mmax = MAX(_mem_mmax, _mem_mcur);
2046 NYD2_LEAVE;
2047 return p.p_p;
2050 FL void
2051 (sfree)(void *v SMALLOC_DEBUG_ARGS)
2053 union mem_ptr p;
2054 bool_t isbad;
2055 NYD2_ENTER;
2057 if ((p.p_p = v) == NULL) {
2058 fprintf(stderr, "sfree(NULL) from %s, line %d\n", mdbg_file, mdbg_line);
2059 goto jleave;
2062 _HOPE_GET(p, isbad);
2063 --p.p_c;
2064 if (p.p_c->mc_isfree) {
2065 fprintf(stderr, "sfree(): double-free avoided at %s, line %d\n"
2066 "\tLast seen: %s, line %" PRIu16 "\n",
2067 mdbg_file, mdbg_line, p.p_c->mc_file, p.p_c->mc_line);
2068 goto jleave;
2071 if (p.p_c == _mem_list)
2072 _mem_list = p.p_c->mc_next;
2073 else
2074 p.p_c->mc_prev->mc_next = p.p_c->mc_next;
2075 if (p.p_c->mc_next != NULL)
2076 p.p_c->mc_next->mc_prev = p.p_c->mc_prev;
2077 p.p_c->mc_isfree = TRU1;
2078 /* Trash contents (also see [21c05f8]) */
2079 memset(v, 0377, p.p_c->mc_size - sizeof(struct mem_chunk) - _HOPE_SIZE);
2081 --_mem_acur;
2082 _mem_mcur -= p.p_c->mc_size;
2084 if (options & (OPT_DEBUG | OPT_MEMDEBUG)) {
2085 p.p_c->mc_next = _mem_free;
2086 _mem_free = p.p_c;
2087 } else
2088 (free)(p.p_c);
2089 jleave:
2090 NYD2_LEAVE;
2093 FL void
2094 smemreset(void)
2096 union mem_ptr p;
2097 size_t c = 0, s = 0;
2098 NYD_ENTER;
2100 smemcheck();
2102 for (p.p_c = _mem_free; p.p_c != NULL;) {
2103 void *vp = p.p_c;
2104 ++c;
2105 s += p.p_c->mc_size;
2106 p.p_c = p.p_c->mc_next;
2107 (free)(vp);
2109 _mem_free = NULL;
2111 if (options & (OPT_DEBUG | OPT_MEMDEBUG))
2112 fprintf(stderr, "smemreset: freed %" PRIuZ " chunks/%" PRIuZ " bytes\n",
2113 c, s);
2114 NYD_LEAVE;
2117 FL int
2118 c_smemtrace(void *v)
2120 /* For _HOPE_GET() */
2121 char const * const mdbg_file = "smemtrace()";
2122 int const mdbg_line = -1;
2123 FILE *fp;
2124 union mem_ptr p, xp;
2125 bool_t isbad;
2126 size_t lines;
2127 NYD_ENTER;
2129 v = (void*)0x1;
2130 if ((fp = Ftmp(NULL, "memtr", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
2131 NULL) {
2132 perror("tmpfile");
2133 goto jleave;
2136 fprintf(fp, "Memory statistics:\n"
2137 " Count cur/peek/all: %7" PRIuZ "/%7" PRIuZ "/%10" PRIuZ "\n"
2138 " Bytes cur/peek/all: %7" PRIuZ "/%7" PRIuZ "/%10" PRIuZ "\n\n",
2139 _mem_acur, _mem_amax, _mem_aall, _mem_mcur, _mem_mmax, _mem_mall);
2141 fprintf(fp, "Currently allocated memory chunks:\n");
2142 for (lines = 0, p.p_c = _mem_list; p.p_c != NULL;
2143 ++lines, p.p_c = p.p_c->mc_next) {
2144 xp = p;
2145 ++xp.p_c;
2146 _HOPE_GET_TRACE(xp, isbad);
2147 fprintf(fp, "%s%p (%5" PRIuZ " bytes): %s, line %" PRIu16 "\n",
2148 (isbad ? "! CANARY ERROR: " : ""), xp.p_p,
2149 (size_t)(p.p_c->mc_size - sizeof(struct mem_chunk)), p.p_c->mc_file,
2150 p.p_c->mc_line);
2153 if (options & (OPT_DEBUG | OPT_MEMDEBUG)) {
2154 fprintf(fp, "sfree()d memory chunks awaiting free():\n");
2155 for (p.p_c = _mem_free; p.p_c != NULL; ++lines, p.p_c = p.p_c->mc_next) {
2156 xp = p;
2157 ++xp.p_c;
2158 _HOPE_GET_TRACE(xp, isbad);
2159 fprintf(fp, "%s%p (%5" PRIuZ " bytes): %s, line %" PRIu16 "\n",
2160 (isbad ? "! CANARY ERROR: " : ""), xp.p_p,
2161 (size_t)(p.p_c->mc_size - sizeof(struct mem_chunk)),
2162 p.p_c->mc_file, p.p_c->mc_line);
2166 page_or_print(fp, lines);
2167 Fclose(fp);
2168 v = NULL;
2169 jleave:
2170 NYD_LEAVE;
2171 return (v != NULL);
2174 # ifdef HAVE_DEVEL
2175 FL bool_t
2176 _smemcheck(char const *mdbg_file, int mdbg_line)
2178 union mem_ptr p, xp;
2179 bool_t anybad = FAL0, isbad;
2180 size_t lines;
2181 NYD_ENTER;
2183 for (lines = 0, p.p_c = _mem_list; p.p_c != NULL;
2184 ++lines, p.p_c = p.p_c->mc_next) {
2185 xp = p;
2186 ++xp.p_c;
2187 _HOPE_GET_TRACE(xp, isbad);
2188 if (isbad) {
2189 anybad = TRU1;
2190 fprintf(stderr,
2191 "! CANARY ERROR: %p (%5" PRIuZ " bytes): %s, line %" PRIu16 "\n",
2192 xp.p_p, (size_t)(p.p_c->mc_size - sizeof(struct mem_chunk)),
2193 p.p_c->mc_file, p.p_c->mc_line);
2197 if (options & (OPT_DEBUG | OPT_MEMDEBUG)) {
2198 for (p.p_c = _mem_free; p.p_c != NULL; ++lines, p.p_c = p.p_c->mc_next) {
2199 xp = p;
2200 ++xp.p_c;
2201 _HOPE_GET_TRACE(xp, isbad);
2202 if (isbad) {
2203 anybad = TRU1;
2204 fprintf(stderr,
2205 "! CANARY ERROR: %p (%5" PRIuZ " bytes): %s, line %" PRIu16 "\n",
2206 xp.p_p, (size_t)(p.p_c->mc_size - sizeof(struct mem_chunk)),
2207 p.p_c->mc_file, p.p_c->mc_line);
2211 NYD_LEAVE;
2212 return anybad;
2214 # endif /* HAVE_DEVEL */
2216 # undef _HOPE_SIZE
2217 # undef _HOPE_SET
2218 # undef _HOPE_GET_TRACE
2219 # undef _HOPE_GET
2220 #endif /* HAVE_DEBUG */
2222 /* s-it-mode */