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>.
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
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
40 #define n_FILE auxlily
42 #ifndef HAVE_AMALGAMATION
46 #include <sys/utsname.h>
52 # ifdef HAVE_GETADDRINFO
53 # include <sys/socket.h>
59 #ifndef HAVE_POSIX_RANDOM
67 ui8_t b8
[sizeof(struct rand_arc4
)];
68 ui32_t b32
[sizeof(struct rand_arc4
) / sizeof(ui32_t
)];
83 struct mem_chunk
*mc_prev
;
84 struct mem_chunk
*mc_next
;
94 struct mem_chunk
*p_c
;
100 #ifndef HAVE_POSIX_RANDOM
101 static union rand_state
*_rand
;
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 */
114 static ui32_t _nyd_curr
, _nyd_level
;
115 static struct nyd_info _nyd_infos
[NYD_CALLS_MAX
];
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
;
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);
133 /* Create an ISO 6429 (ECMA-48/ANSI) terminal control escape sequence */
135 static char * _colour_iso6429(char const *wish
);
139 static void _nyd_print(int fd
, struct nyd_info
*nip
);
142 #ifndef HAVE_POSIX_RANDOM
146 # ifdef HAVE_CLOCK_GETTIME
151 union {int fd
; size_t i
;} u
;
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
));
165 for (seed
= (uintptr_t)_rand
& UI32_MAX
, rnd
= 21; rnd
!= 0; --rnd
) {
166 for (u
.i
= NELEM(_rand
->b32
); u
.i
-- != 0;) {
169 # ifdef HAVE_CLOCK_GETTIME
170 clock_gettime(CLOCK_REALTIME
, &ts
);
171 t
= (ui32_t
)ts
.tv_nsec
;
173 gettimeofday(&ts
, NULL
);
174 t
= (ui32_t
)ts
.tv_usec
;
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
]);
186 seed
^= nextprime(seed
);
190 for (u
.i
= 11 * sizeof(_rand
->b8
); u
.i
!= 0; --u
.i
)
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.) */
209 seed
= (seed
* 16807) - (hi
* 2836);
210 if ((si32_t
)seed
< 0)
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 */
230 _colour_iso6429(char const *wish
)
232 char const * const wish_orig
= wish
;
233 char *xwish
, *cp
, cfg
[3] = {0, 0, 0};
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
);
245 /* Iterate over the colour spec */
246 while ((cp
= n_strsep(&xwish
, ',', TRU1
)) != NULL
) {
247 char *y
, *x
= strchr(cp
, '=');
251 "Invalid colour specification \"%s\": >>> %s <<<\n"),
257 /* TODO convert the ft/fg/bg parser into a table-based one! */
258 if (!asccasecmp(cp
, "ft")) {
259 if (!asccasecmp(x
, "bold"))
261 else if (!asccasecmp(x
, "inverse"))
263 else if (!asccasecmp(x
, "underline"))
267 } else if (!asccasecmp(cp
, "fg")) {
270 } else if (!asccasecmp(cp
, "bg")) {
273 if (!asccasecmp(x
, "black"))
275 else if (!asccasecmp(x
, "blue"))
277 else if (!asccasecmp(x
, "green"))
279 else if (!asccasecmp(x
, "red"))
281 else if (!asccasecmp(x
, "brown"))
283 else if (!asccasecmp(x
, "magenta"))
285 else if (!asccasecmp(x
, "cyan"))
287 else if (!asccasecmp(x
, "white"))
295 /* Restore our salloc() buffer, create return value */
296 xwish
= UNCONST(wish
);
297 if (cfg
[0] || cfg
[1] || cfg
[2]) {
311 if (cfg
[0] || cfg
[1])
321 return UNCONST(wish
);
323 #endif /* HAVE_COLOUR */
327 _nyd_print(int fd
, struct nyd_info
*nip
)
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
));
338 if (u
.z
> sizeof buf
)
339 u
.z
= sizeof buf
- 1; /* (Skip \0) */
349 kill(getpid(), signo
);
354 panic(char const *format
, ...)
359 fprintf(stderr
, _("Panic: "));
361 va_start(ap
, format
);
362 vfprintf(stderr
, format
, ap
);
368 abort(); /* Was exit(EXIT_ERR); for a while, but no */
372 alert(char const *format
, ...)
377 fprintf(stderr
, _("Panic: "));
379 va_start(ap
, format
);
380 vfprintf(stderr
, format
, ap
);
389 safe_signal(int signum
, sighandler_type handler
)
391 struct sigaction nact
, oact
;
395 nact
.sa_handler
= handler
;
396 sigemptyset(&nact
.sa_mask
);
399 nact
.sa_flags
|= SA_RESTART
;
401 rv
= (sigaction(signum
, &nact
, &oact
) != 0) ? SIG_ERR
: oact
.sa_handler
;
410 if (_alls_depth
++ == 0) {
411 sigfillset(&_alls_nset
);
412 sigdelset(&_alls_nset
, SIGABRT
);
414 sigdelset(&_alls_nset
, SIGBUS
);
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
);
431 if (--_alls_depth
== 0)
432 sigprocmask(SIG_SETMASK
, &_alls_oset
, (sigset_t
*)NULL
);
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
);
454 if (--_hold_sigdepth
== 0)
455 sigprocmask(SIG_SETMASK
, &_hold_oset
, NULL
);
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
))
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
--);
477 _nyd_oncrash(int signo
)
479 char s2ibuf
[32], *fname
, *cp
;
480 struct sigaction xact
;
484 struct nyd_info
*nip
;
486 xact
.sa_handler
= SIG_DFL
;
487 sigemptyset(&xact
.sa_mask
);
489 sigaction(signo
, &xact
, NULL
);
491 fnl
= strlen(UAGENT
);
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
);
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)
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;
513 *--cp
= "0123456789"[i
% 10];
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"));
540 sigaddset(&xset
, signo
);
541 sigprocmask(SIG_UNBLOCK
, &xset
, NULL
);
546 #endif /* HAVE_NYD */
549 touch(struct message
*mp
)
552 mp
->m_flag
|= MTOUCH
;
553 if (!(mp
->m_flag
& MREAD
))
554 mp
->m_flag
|= MREAD
| MSTATUS
;
559 is_dir(char const *name
)
566 if (!stat(name
, &sbuf
)) {
567 rv
= (S_ISDIR(sbuf
.st_mode
) != 0);
569 } else if (errno
!= EINTR
)
576 argcount(char **argv
)
581 for (ap
= argv
; *ap
++ != NULL
;)
584 return (int)PTR2SIZE(ap
- argv
- 1);
594 if ((cp
= ok_vlook(screen
)) == NULL
|| (s
= atoi(cp
)) <= 0)
595 s
= scrnheight
- 4; /* XXX no magics */
601 get_pager(char const **env_addon
)
606 cp
= ok_vlook(PAGER
);
607 if (cp
== NULL
|| *cp
== '\0')
610 if (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";
625 page_or_print(FILE *fp
, size_t lines
)
634 if (IS_TTY_SESSION()) {
637 if ((cp
= ok_vlook(crt
)) != NULL
) {
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
)
653 run_command(get_pager(NULL
), 0, fileno(fp
), -1, NULL
, NULL
, NULL
);
655 while ((c
= getc(fp
)) != EOF
)
661 which_protocol(char const *name
) /* XXX (->URL (yet auxlily.c)) */
667 enum protocol rv
= PROTO_UNKNOWN
;
670 temporary_protocol_ext
= NULL
;
672 if (name
[0] == '%' && name
[1] == ':')
674 for (cp
= name
; *cp
&& *cp
!= ':'; cp
++)
678 if (cp
[0] == ':' && cp
[1] == '/' && cp
[2] == '/') {
679 if (!strncmp(name
, "pop3://", 7)) {
683 fprintf(stderr
, _("No POP3 support compiled in.\n"));
685 } else if (!strncmp(name
, "pop3s://", 8)) {
686 #if defined HAVE_POP3 && defined HAVE_SSL
690 fprintf(stderr
, _("No POP3 support compiled in.\n"));
693 fprintf(stderr
, _("No SSL support compiled in.\n"));
696 } else if (!strncmp(name
, "imap://", 7)) {
700 fprintf(stderr
, _("No IMAP support compiled in.\n"));
702 } else if (!strncmp(name
, "imaps://", 8)) {
703 #if defined HAVE_IMAP && defined HAVE_SSL
707 fprintf(stderr
, _("No IMAP support compiled in.\n"));
710 fprintf(stderr
, _("No SSL support compiled in.\n"));
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*) */
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
)))
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"))
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
753 while (*name
!= '\0') {
762 pjw(char const *cp
) /* TODO obsolete that -> torek_hash */
769 h
= (h
<< 4 & 0xffffffff) + (*cp
&0377);
770 if ((g
= h
& 0xf0000000) != 0) {
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
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
)
799 while (++i
< NELEM(primes
));
800 if (i
== NELEM(primes
) && mprime
< n
)
807 expand_shell_escape(char const **s
, bool_t use_nail_extensions
)
815 if ((c
= *xs
& 0xFF) == '\0')
821 switch ((c
= *xs
& 0xFF)) {
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;
832 for (++xs
, c
= 0, n
= 4; --n
> 0 && octalchar(*xs
); ++xs
) {
837 /* S-nail extension for nice (get)prompt(()) support */
842 if (use_nail_extensions
) {
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;
853 /* A sole <backslash> at EOS is treated as-is! */
867 getprompt(void) /* TODO evaluate only as necessary (needs a bit) */
869 static char buf
[PROMPT_BUFFER_SIZE
];
872 char const *ccp_base
, *ccp
;
873 size_t NATCH_CHAR( cclen_base COMMA cclen COMMA
) maxlen
, dfmaxlen
;
878 if ((ccp_base
= ok_vlook(prompt
)) == NULL
|| *ccp_base
== '\0')
880 NATCH_CHAR( cclen_base
= strlen(ccp_base
); )
882 dfmaxlen
= 0; /* keep CC happy */
886 NATCH_CHAR( cclen
= cclen_base
; )
887 maxlen
= sizeof(buf
) -1;
895 #ifdef HAVE_NATCH_CHAR
896 c
= mblen(ccp
, cclen
); /* TODO use mbrtowc() */
905 } else if ((l
= c
) > 1) {
915 if ((c
= expand_shell_escape(&ccp
, TRU1
)) > 0) {
921 if (c
== 0 || c
== PROMPT_STOP
)
925 char const *a
= (c
== PROMPT_DOLLAR
) ? account_name
: displayname
;
928 if ((l
= field_put_bidi_clip(cp
, dfmaxlen
, a
, strlen(a
))) > 0) {
948 nodename(int mayoverride
)
950 static char *sys_hostname
, *hostname
; /* XXX free-at-exit */
955 # ifdef HAVE_GETADDRINFO
956 struct addrinfo hints
, *res
;
958 struct hostent
*hent
;
963 if (mayoverride
&& (hn
= ok_vlook(hostname
)) != NULL
&& *hn
!= '\0') {
965 } else if ((hn
= sys_hostname
) == NULL
) {
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;
978 memcpy(hn
, res
->ai_canonname
, l
);
983 hent
= gethostbyname(hn
);
988 sys_hostname
= sstrdup(hn
);
989 #if defined HAVE_SOCKETS && defined HAVE_GETADDRINFO
990 if (hn
!= ut
.nodename
)
996 if (hostname
!= NULL
&& hostname
!= sys_hostname
)
998 hostname
= sstrdup(hn
);
1004 getrandstring(size_t length
)
1011 #ifndef HAVE_POSIX_RANDOM
1016 data
= ac_alloc(length
);
1018 #ifndef HAVE_POSIX_RANDOM
1019 for (i
= length
; i
-- > 0;)
1020 data
[i
] = (char)_rand_get8();
1022 for (i
= length
; i
> 0;) {
1023 union {ui32_t i4
; char c
[4];} r
;
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;
1038 b64_encode_buf(&b64
, data
, length
, B64_SALLOC
| B64_RFC4648URL
);
1045 makedir(char const *name
)
1048 enum okay rv
= STOP
;
1051 if (!mkdir(name
, 0700))
1055 if ((e
== EEXIST
|| e
== ENOSYS
) && !stat(name
, &st
) &&
1056 S_ISDIR(st
.st_mode
))
1065 cwget(struct cw
*cw
)
1067 enum okay rv
= STOP
;
1070 if ((cw
->cw_fd
= open(".", O_RDONLY
)) == -1)
1072 if (fchdir(cw
->cw_fd
) == -1) {
1083 cwret(struct cw
*cw
)
1085 enum okay rv
= STOP
;
1088 if (!fchdir(cw
->cw_fd
))
1095 cwrelse(struct cw
*cw
)
1102 #else /* !HAVE_FCHDIR */
1104 cwget(struct cw
*cw
)
1106 enum okay rv
= STOP
;
1109 if (getcwd(cw
->cw_wd
, sizeof cw
->cw_wd
) != NULL
&& !chdir(cw
->cw_wd
))
1116 cwret(struct cw
*cw
)
1118 enum okay rv
= STOP
;
1121 if (!chdir(cw
->cw_wd
))
1128 cwrelse(struct cw
*cw
)
1134 #endif /* !HAVE_FCHDIR */
1137 field_detect_clip(size_t maxlen
, char const *buf
, size_t blen
)/*TODO mbrtowc()*/
1142 #ifdef HAVE_NATCH_CHAR
1143 maxlen
= MIN(maxlen
, blen
);
1144 for (rv
= 0; maxlen
> 0;) {
1145 int ml
= mblen(buf
, maxlen
);
1155 rv
= MIN(blen
, maxlen
);
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
);
1172 #ifdef HAVE_NATCH_CHAR
1173 bidi_info_create(&bi
);
1174 if (bi
.bi_start
.l
== 0 || !bidi_info_needed(buf
, blen
)) {
1179 if (maxlen
>= (i
= bi
.bi_pad
+ bi
.bi_end
.l
+ bi
.bi_start
.l
))
1184 if ((i
= bi
.bi_start
.l
) > 0) {
1185 memcpy(store
, bi
.bi_start
.s
, i
);
1191 while (maxlen
> 0) {
1192 int ml
= mblen(buf
, blen
);
1197 if (UICMP(z
, maxlen
, <, ml
))
1202 memcpy(store
, buf
, ml
);
1209 if ((i
= bi
.bi_end
.l
) > 0) {
1210 memcpy(store
, bi
.bi_end
.s
, i
);
1218 rv
= MIN(blen
, maxlen
);
1219 memcpy(store
, buf
, rv
);
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
;
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)
1243 if (!(isbidi
= bidi_info_needed(cp
, strlen(cp
))))
1246 if ((size_t)col
>= bi
.bi_pad
)
1253 np
= nb
= salloc(mb_cur_max
* strlen(cp
) +
1255 NATCH_CHAR( + (isbidi
? bi
.bi_start
.l
+ bi
.bi_end
.l
: 0) )
1258 #ifdef HAVE_NATCH_CHAR
1260 memcpy(np
, bi
.bi_start
.s
, bi
.bi_start
.l
);
1261 np
+= bi
.bi_start
.l
;
1265 while (*cp
!= '\0') {
1267 #ifdef HAVE_C90AMEND1
1268 if (mb_cur_max
> 1) {
1273 if ((sz
= mbtowc(&wc
, cp
, mb_cur_max
)) == -1)
1275 else if (wc
== L
'\t') {
1276 cp
+= sz
- 1; /* Silly, no such charset known (.. until S-Ctext) */
1279 } else if (iswprint(wc
)) {
1280 # ifndef HAVE_WCWIDTH
1281 n
= 1 + (wc
>= 0x1100u
); /* TODO use S-CText isfullwidth() */
1283 if ((n
= wcwidth(wc
)) == -1)
1293 istab
= (*cp
== '\t');
1294 isrepl
= !(istab
|| isprint((uc_i
)*cp
));
1303 np
[0] = (char)0xEFu
;
1304 np
[1] = (char)0xBFu
;
1305 np
[2] = (char)0xBDu
;
1310 } else if (istab
|| (sz
== 1 && spacechar(*cp
))) {
1318 if (fill
&& col
!= 0) {
1320 memmove(nb
+ col
, nb
, PTR2SIZE(np
- nb
));
1321 memset(nb
, ' ', col
);
1323 memset(np
, ' ', col
);
1328 #ifdef HAVE_NATCH_CHAR
1330 memcpy(np
, bi
.bi_end
.s
, bi
.bi_end
.l
);
1336 if (cols_decr_used_or_null
!= NULL
)
1337 *cols_decr_used_or_null
-= col_orig
- col
;
1343 makeprint(struct str
const *in
, struct str
*out
)
1345 static int print_all_chars
= -1;
1347 char const *inp
, *maxp
;
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);
1359 if (print_all_chars
) {
1361 memcpy(outp
, inp
, out
->l
);
1365 #ifdef HAVE_NATCH_CHAR
1366 if (mb_cur_max
> 1) {
1367 char mbb
[MB_LEN_MAX
+ 1];
1370 bool_t isuni
= ((options
& OPT_UNICODE
) != 0);
1373 while (inp
< maxp
) {
1375 n
= mbtowc(&wc
, inp
, PTR2SIZE(maxp
- inp
));
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 : '?';
1393 if (!iswprint(wc
) && wc
!= '\n' && wc
!= '\r' && wc
!= '\b' &&
1395 if ((wc
& ~(wchar_t)037) == 0)
1396 wc
= isuni
? 0x2400 | wc
: '?';
1397 else if (wc
== 0177)
1398 wc
= isuni
? 0x2421 : '?';
1400 wc
= isuni
? 0x2426 : '?';
1402 if ((n
= wctomb(mbb
, wc
)) <= 0)
1405 assert(out
->l
< msz
);
1406 for (i
= 0; i
< n
; ++i
)
1410 #endif /* NATCH_CHAR */
1413 while (inp
< maxp
) {
1415 if (!isprint(c
) && c
!= '\n' && c
!= '\r' && c
!= '\b' && c
!= '\t')
1422 out
->s
[out
->l
] = '\0';
1427 delctrl(char *cp
, size_t len
)
1432 for (x
= y
= 0; x
< len
; ++x
)
1433 if (!cntrlchar(cp
[x
]))
1441 prstr(char const *s
)
1449 makeprint(&in
, &out
);
1450 rp
= savestrbuf(out
.s
, out
.l
);
1457 prout(char const *s
, size_t sz
, FILE *fp
)
1465 makeprint(&in
, &out
);
1466 n
= fwrite(out
.s
, 1, out
.l
, fp
);
1473 putuc(int u
, int c
, FILE *fp
)
1479 #ifdef HAVE_NATCH_CHAR
1480 if ((options
& OPT_UNICODE
) && (u
& ~(wchar_t)0177)) {
1481 char mbb
[MB_LEN_MAX
];
1484 if ((n
= wctomb(mbb
, u
)) > 0) {
1486 for (i
= 0; i
< n
; ++i
)
1487 if (putc(mbb
[i
] & 0377, fp
) == EOF
) {
1492 rv
= (putc('\0', fp
) != EOF
);
1497 rv
= (putc(c
, fp
) != EOF
);
1503 bidi_info_needed(char const *bdat
, size_t blen
)
1508 #ifdef HAVE_NATCH_CHAR
1509 if (options
& OPT_UNICODE
)
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
);
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)) {
1529 #endif /* HAVE_NATCH_CHAR */
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
; )
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
) {
1555 bip
->bi_start
.s
= bip
->bi_end
.s
= UNCONST("\xE2\x80\x8E");
1561 bip
->bi_start
.s
= UNCONST("\xE2\x81\xA8");
1562 bip
->bi_end
.s
= UNCONST("\xE2\x81\xA9");
1565 bip
->bi_start
.l
= bip
->bi_end
.l
= 3;
1573 colour_table_create(bool_t pager_used
)
1575 union {char *cp
; char const *ccp
; void *vp
; struct colour_table
*ctp
;} u
;
1577 struct colour_table
*ct
;
1580 if (ok_blook(colour_disable
) || (pager_used
&& !ok_blook(colour_pager
)))
1583 char *term
, *okterms
;
1585 if ((term
= env_vlook("TERM", FAL0
)) == NULL
)
1587 /* terminfo rocks: if we find "color", assume it's right */
1588 if (strstr(term
, "color") != NULL
)
1590 if ((okterms
= ok_vlook(colour_terms
)) == NULL
)
1591 okterms
= UNCONST(COLOUR_TERMS
);
1592 okterms
= savestr(okterms
);
1595 while ((u
.cp
= n_strsep(&okterms
, ',', TRU1
)) != NULL
)
1596 if (!strncmp(u
.cp
, term
, i
))
1602 colour_table
= ct
= salloc(sizeof *ct
); /* XXX lex.c yet resets (FILTER!) */
1605 enum colourspec cspec
;
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
);
1635 colour_put(FILE *fp
, enum colourspec cs
)
1638 if (colour_table
!= NULL
) {
1639 struct str
const *cp
= colour_get(cs
);
1641 fwrite(cp
->s
, cp
->l
, 1, fp
);
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
;
1655 if (colour_table
== NULL
)
1657 /* Normal header colours if there are no user headers */
1658 uheads
= colour_table
->ct_csinfo
+ COLOURSPEC_RESET
+ 1;
1659 if (uheads
->s
== NULL
)
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);
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
;
1682 colour_reset(FILE *fp
)
1685 if (colour_table
!= NULL
)
1686 fwrite("\033[0m", 4, 1, fp
);
1690 FL
struct str
const *
1691 colour_get(enum colourspec cs
)
1693 struct str
const *rv
= NULL
;
1696 if (colour_table
!= NULL
)
1697 if ((rv
= colour_table
->ct_csinfo
+ cs
)->s
== NULL
)
1702 #endif /* HAVE_COLOUR */
1705 boolify(char const *inbuf
, uiz_t inlen
, si8_t emptyrv
)
1712 assert(inlen
== 0 || inbuf
!= NULL
);
1714 if (inlen
== UIZ_MAX
)
1715 inlen
= strlen(inbuf
);
1718 rv
= (emptyrv
>= 0) ? (emptyrv
== 0 ? 0 : 1) : -1;
1720 if ((inlen
== 1 && *inbuf
== '1') ||
1721 !ascncasecmp(inbuf
, "true", inlen
) ||
1722 !ascncasecmp(inbuf
, "yes", inlen
) ||
1723 !ascncasecmp(inbuf
, "on", inlen
))
1725 else if ((inlen
== 1 && *inbuf
== '0') ||
1726 !ascncasecmp(inbuf
, "false", inlen
) ||
1727 !ascncasecmp(inbuf
, "no", inlen
) ||
1728 !ascncasecmp(inbuf
, "off", inlen
))
1731 dat
= ac_alloc(inlen
+1);
1732 memcpy(dat
, inbuf
, inlen
);
1735 sli
= strtol(dat
, &eptr
, 0);
1736 if (*dat
!= '\0' && *eptr
== '\0')
1749 quadify(char const *inbuf
, uiz_t inlen
, char const *prompt
, si8_t emptyrv
)
1754 assert(inlen
== 0 || inbuf
!= NULL
);
1756 if (inlen
== UIZ_MAX
)
1757 inlen
= strlen(inbuf
);
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
)) {
1766 fputs(prompt
, stdout
);
1767 rv
= getapproval(NULL
, rv
);
1774 time_current_update(struct time_current
*tc
, bool_t full_update
)
1777 tc
->tc_time
= time(NULL
);
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
));
1787 _out_of_memory(void)
1794 smalloc(size_t s SMALLOC_DEBUG_ARGS
)
1801 if ((rv
= malloc(s
)) == NULL
)
1808 srealloc(void *v
, size_t s SMALLOC_DEBUG_ARGS
)
1817 else if ((rv
= realloc(v
, s
)) == NULL
)
1824 scalloc(size_t nmemb
, size_t size SMALLOC_DEBUG_ARGS
)
1831 if ((rv
= calloc(nmemb
, size
)) == NULL
)
1837 #else /* !HAVE_DEBUG */
1838 CTA(sizeof(char) == sizeof(ui8_t
));
1840 # define _HOPE_SIZE (2 * 8 * sizeof(char))
1841 # define _HOPE_SET(C) \
1843 union mem_ptr __xl, __xu;\
1844 struct mem_chunk *__xc;\
1845 __xl.p_p = (C).p_p;\
1846 __xc = __xl.p_c - 1;\
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;\
1859 # define _HOPE_GET_TRACE(C,BAD) \
1865 # define _HOPE_GET(C,BAD) \
1867 union mem_ptr __xl, __xu;\
1868 struct mem_chunk *__xc;\
1870 __xl.p_p = (C).p_p;\
1872 (C).p_cp = __xl.p_cp;\
1873 __xc = __xl.p_c - 1;\
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;\
1886 alert("%p: corrupt lower canary: 0x%02X: %s, line %d",\
1887 __xl.p_p, __i, mdbg_file, mdbg_line);\
1890 __xu.p_ui8p += __xc->mc_size - 8;\
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;\
1902 alert("%p: corrupt upper canary: 0x%02X: %s, line %d",\
1903 __xl.p_p, __i, mdbg_file, mdbg_line);\
1906 alert(" ..canary last seen: %s, line %" PRIu16 "",\
1907 __xc->mc_file, __xc->mc_line);\
1911 (smalloc
)(size_t s SMALLOC_DEBUG_ARGS
)
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
)
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
++;
1938 _mem_amax
= MAX(_mem_amax
, _mem_acur
);
1941 _mem_mmax
= MAX(_mem_mmax
, _mem_mcur
);
1947 (srealloc
)(void *v
, size_t s SMALLOC_DEBUG_ARGS
)
1953 if ((p
.p_p
= v
) == NULL
) {
1954 p
.p_p
= (smalloc
)(s
, mdbg_file
, mdbg_line
);
1958 _HOPE_GET(p
, isbad
);
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
);
1967 if (p
.p_c
== _mem_list
)
1968 _mem_list
= p
.p_c
->mc_next
;
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
;
1975 _mem_mcur
-= p
.p_c
->mc_size
;
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
)
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
++;
1998 _mem_amax
= MAX(_mem_amax
, _mem_acur
);
2001 _mem_mmax
= MAX(_mem_mmax
, _mem_mcur
);
2008 (scalloc
)(size_t nmemb
, size_t size SMALLOC_DEBUG_ARGS
)
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
);
2025 size
+= sizeof(struct mem_chunk
) + _HOPE_SIZE
;
2027 if ((p
.p_p
= (malloc
)(size
)) == NULL
)
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
++;
2042 _mem_amax
= MAX(_mem_amax
, _mem_acur
);
2045 _mem_mmax
= MAX(_mem_mmax
, _mem_mcur
);
2051 (sfree
)(void *v SMALLOC_DEBUG_ARGS
)
2057 if ((p
.p_p
= v
) == NULL
) {
2058 fprintf(stderr
, "sfree(NULL) from %s, line %d\n", mdbg_file
, mdbg_line
);
2062 _HOPE_GET(p
, isbad
);
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
);
2071 if (p
.p_c
== _mem_list
)
2072 _mem_list
= p
.p_c
->mc_next
;
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
);
2082 _mem_mcur
-= p
.p_c
->mc_size
;
2084 if (options
& (OPT_DEBUG
| OPT_MEMDEBUG
)) {
2085 p
.p_c
->mc_next
= _mem_free
;
2097 size_t c
= 0, s
= 0;
2102 for (p
.p_c
= _mem_free
; p
.p_c
!= NULL
;) {
2105 s
+= p
.p_c
->mc_size
;
2106 p
.p_c
= p
.p_c
->mc_next
;
2111 if (options
& (OPT_DEBUG
| OPT_MEMDEBUG
))
2112 fprintf(stderr
, "smemreset: freed %" PRIuZ
" chunks/%" PRIuZ
" bytes\n",
2118 c_smemtrace(void *v
)
2120 /* For _HOPE_GET() */
2121 char const * const mdbg_file
= "smemtrace()";
2122 int const mdbg_line
= -1;
2124 union mem_ptr p
, xp
;
2130 if ((fp
= Ftmp(NULL
, "memtr", OF_RDWR
| OF_UNLINK
| OF_REGISTER
, 0600)) ==
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
) {
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
,
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
) {
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
);
2176 _smemcheck(char const *mdbg_file
, int mdbg_line
)
2178 union mem_ptr p
, xp
;
2179 bool_t anybad
= FAL0
, isbad
;
2183 for (lines
= 0, p
.p_c
= _mem_list
; p
.p_c
!= NULL
;
2184 ++lines
, p
.p_c
= p
.p_c
->mc_next
) {
2187 _HOPE_GET_TRACE(xp
, isbad
);
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
) {
2201 _HOPE_GET_TRACE(xp
, isbad
);
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
);
2214 # endif /* HAVE_DEVEL */
2218 # undef _HOPE_GET_TRACE
2220 #endif /* HAVE_DEBUG */