1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Auxiliary functions that don't fit anywhere else.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
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. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #define n_FILE auxlily
38 #ifndef HAVE_AMALGAMATION
42 #include <sys/utsname.h>
45 # ifdef HAVE_GETADDRINFO
46 # include <sys/socket.h>
52 #ifdef HAVE_NL_LANGINFO
53 # include <langinfo.h>
59 #if defined HAVE_GETRANDOM && !n_RANDOM_USE_XSSL
60 # include HAVE_GETRANDOM_HEADER
64 # if HAVE_IDNA == HAVE_IDNA_LIBIDNA
66 # include <idn-free.h>
67 # include <stringprep.h>
68 # elif HAVE_IDNA == HAVE_IDNA_IDNKIT
73 #if !defined HAVE_POSIX_RANDOM && !n_RANDOM_USE_XSSL
81 ui8_t b8
[sizeof(struct rand_arc4
)];
82 ui32_t b32
[sizeof(struct rand_arc4
) / sizeof(ui32_t
)];
87 struct a_aux_err_node
{
88 struct a_aux_err_node
*ae_next
;
89 struct n_string ae_str
;
94 ui32_t aem_hash
; /* Hash of name */
95 ui32_t aem_nameoff
; /* Into a_aux_err_names[] */
96 ui32_t aem_docoff
; /* Into a_aux_err docs[] */
97 si32_t aem_err_no
; /* The OS error value for this one */
100 static ui8_t
const a_aux_idec_atoi
[256] = {
101 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
102 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
103 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
104 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
105 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x01,
106 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,
107 0xFF,0xFF,0xFF,0xFF,0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,
108 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
109 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,
110 0x23,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0A,0x0B,0x0C,
111 0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
112 0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,
113 0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
114 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
115 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
116 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
117 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
118 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
119 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
120 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
121 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
122 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
123 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
124 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
125 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
126 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
129 #define a_X(X) ((ui64_t)-1 / (X))
130 static ui64_t
const a_aux_idec_cutlimit
[35] = {
131 a_X( 2), a_X( 3), a_X( 4), a_X( 5), a_X( 6), a_X( 7), a_X( 8),
132 a_X( 9), a_X(10), a_X(11), a_X(12), a_X(13), a_X(14), a_X(15),
133 a_X(16), a_X(17), a_X(18), a_X(19), a_X(20), a_X(21), a_X(22),
134 a_X(23), a_X(24), a_X(25), a_X(26), a_X(27), a_X(28), a_X(29),
135 a_X(30), a_X(31), a_X(32), a_X(33), a_X(34), a_X(35), a_X(36)
139 /* Include the constant make-errors.sh output */
140 #include <gen-errors.h>
142 /* And these things come from mk-config.h (config-time make-errors.sh output) */
143 static n__ERR_NUMBER_TYPE
const a_aux_err_no2mapoff
[][2] = {
145 #define a_X(N,I) {N,I},
146 n__ERR_NUMBER_TO_MAPOFF
150 #if !defined HAVE_POSIX_RANDOM && !n_RANDOM_USE_XSSL
151 static union rand_state
*a_aux_rand
;
154 /* Error ring, for `errors' */
156 static struct a_aux_err_node
*a_aux_err_head
, *a_aux_err_tail
;
157 static size_t a_aux_err_cnt
, a_aux_err_cnt_noted
;
159 static size_t a_aux_err_linelen
;
161 /* Our ARC4 random generator with its completely unacademical pseudo
162 * initialization (shall /dev/urandom fail) */
163 #if !defined HAVE_POSIX_RANDOM && !n_RANDOM_USE_XSSL
164 static void a_aux_rand_init(void);
165 n_INLINE ui8_t
a_aux_rand_get8(void);
166 # ifndef HAVE_GETRANDOM
167 static ui32_t
a_aux_rand_weak(ui32_t seed
);
171 /* Find the descriptive mapping of an error number, or _ERR_INVAL */
172 static struct a_aux_err_map
const *a_aux_err_map_from_no(si32_t eno
);
174 #if !defined HAVE_POSIX_RANDOM && !n_RANDOM_USE_XSSL
176 a_aux_rand_init(void){
177 # ifndef HAVE_GETRANDOM
178 # ifdef HAVE_CLOCK_GETTIME
183 union {int fd
; size_t i
;} u
;
188 a_aux_rand
= n_alloc(sizeof *a_aux_rand
);
190 # ifdef HAVE_GETRANDOM
191 /* getrandom(2) guarantees 256 without n_ERR_INTR..
192 * However, support sequential reading to avoid possible hangs that have
193 * been reported on the ML (2017-08-22, s-nail/s-mailx freezes when
194 * HAVE_GETRANDOM is #defined) */
195 n_LCTA(sizeof(a_aux_rand
->a
._dat
) <= 256,
196 "Buffer too large to be served without n_ERR_INTR error");
197 n_LCTA(sizeof(a_aux_rand
->a
._dat
) >= 256,
198 "Buffer too small to serve used array indices");
202 for(o
= 0, i
= sizeof a_aux_rand
->a
._dat
;;){
205 gr
= HAVE_GETRANDOM(&a_aux_rand
->a
._dat
[o
], i
);
206 a_aux_rand
->a
._i
= a_aux_rand
->a
._dat
[a_aux_rand
->a
._dat
[1] ^
207 a_aux_rand
->a
._dat
[84]];
208 a_aux_rand
->a
._j
= a_aux_rand
->a
._dat
[a_aux_rand
->a
._dat
[65] ^
209 a_aux_rand
->a
._dat
[42]];
210 /* ..but be on the safe side */
217 n_err(_("Not enough entropy for the PseudoRandomNumberGenerator, "
223 # else /* HAVE_GETRANDOM */
224 if((u
.fd
= open("/dev/urandom", O_RDONLY
)) != -1){
227 ok
= (sizeof(a_aux_rand
->a
._dat
) == (size_t)read(u
.fd
, a_aux_rand
->a
._dat
,
228 sizeof(a_aux_rand
->a
._dat
)));
231 a_aux_rand
->a
._i
= a_aux_rand
->a
._dat
[a_aux_rand
->a
._dat
[1] ^
232 a_aux_rand
->a
._dat
[84]];
233 a_aux_rand
->a
._j
= a_aux_rand
->a
._dat
[a_aux_rand
->a
._dat
[65] ^
234 a_aux_rand
->a
._dat
[42]];
239 for(seed
= (uintptr_t)a_aux_rand
& UI32_MAX
, rnd
= 21; rnd
!= 0; --rnd
){
240 for(u
.i
= n_NELEM(a_aux_rand
->b32
); u
.i
-- != 0;){
243 # ifdef HAVE_CLOCK_GETTIME
244 clock_gettime(CLOCK_REALTIME
, &ts
);
245 t
= (ui32_t
)ts
.tv_nsec
;
247 gettimeofday(&ts
, NULL
);
248 t
= (ui32_t
)ts
.tv_usec
;
251 t
= (t
>> 16) | (t
<< 16);
252 a_aux_rand
->b32
[u
.i
] ^= a_aux_rand_weak(seed
^ t
);
253 a_aux_rand
->b32
[t
% n_NELEM(a_aux_rand
->b32
)] ^= seed
;
254 if(rnd
== 7 || rnd
== 17)
255 a_aux_rand
->b32
[u
.i
] ^= a_aux_rand_weak(seed
^ (ui32_t
)ts
.tv_sec
);
256 k
= a_aux_rand
->b32
[u
.i
] % n_NELEM(a_aux_rand
->b32
);
257 a_aux_rand
->b32
[k
] ^= a_aux_rand
->b32
[u
.i
];
258 seed
^= a_aux_rand_weak(a_aux_rand
->b32
[k
]);
260 seed
^= n_prime_next(seed
);
264 for(u
.i
= 5 * sizeof(a_aux_rand
->b8
); u
.i
!= 0; --u
.i
)
267 # endif /* !HAVE_GETRANDOM */
272 a_aux_rand_get8(void){
275 si
= a_aux_rand
->a
._dat
[++a_aux_rand
->a
._i
];
276 sj
= a_aux_rand
->a
._dat
[a_aux_rand
->a
._j
+= si
];
277 a_aux_rand
->a
._dat
[a_aux_rand
->a
._i
] = sj
;
278 a_aux_rand
->a
._dat
[a_aux_rand
->a
._j
] = si
;
279 return a_aux_rand
->a
._dat
[(ui8_t
)(si
+ sj
)];
282 # ifndef HAVE_GETRANDOM
284 a_aux_rand_weak(ui32_t seed
){
285 /* From "Random number generators: good ones are hard to find",
286 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
287 * October 1988, p. 1195.
288 * (In fact: FreeBSD 4.7, /usr/src/lib/libc/stdlib/random.c.) */
295 seed
= (seed
* 16807) - (hi
* 2836);
300 # endif /* HAVE_GETRANDOM */
301 #endif /* !HAVE_POSIX_RANDOM && !n_RANDOM_USE_XSSL */
303 static struct a_aux_err_map
const *
304 a_aux_err_map_from_no(si32_t eno
){
307 n__ERR_NUMBER_TYPE
const (*adat
)[2], (*tmp
)[2];
308 struct a_aux_err_map
const *aemp
;
311 aemp
= &a_aux_err_map
[n__ERR_NUMBER_VOIDOFF
];
313 if(UICMP(z
, n_ABS(eno
), <=, (n__ERR_NUMBER_TYPE
)-1)){
314 for(adat
= a_aux_err_no2mapoff
, asz
= n_NELEM(a_aux_err_no2mapoff
);
315 asz
!= 0; asz
>>= 1){
316 tmp
= &adat
[asz
>> 1];
317 if((ecmp
= (si32_t
)((n__ERR_NUMBER_TYPE
)eno
- (*tmp
)[0])) == 0){
318 aemp
= &a_aux_err_map
[(*tmp
)[1]];
335 n_psonce
&= ~(n_PSO_UNICODE
| n_PSO_ENC_MBSTATE
);
337 #ifndef HAVE_SETLOCALE
340 setlocale(LC_ALL
, n_empty
);
341 n_mb_cur_max
= MB_CUR_MAX
;
342 # ifdef HAVE_NL_LANGINFO
346 if((cp
= nl_langinfo(CODESET
)) != NULL
)
347 /* (Will log during startup if user set that via -S) */
348 ok_vset(ttycharset
, cp
);
350 # endif /* HAVE_SETLOCALE */
352 # ifdef HAVE_C90AMEND1
353 if(n_mb_cur_max
> 1){
354 # ifdef HAVE_ALWAYS_UNICODE_LOCALE
355 n_psonce
|= n_PSO_UNICODE
;
358 if(mbtowc(&wc
, "\303\266", 2) == 2 && wc
== 0xF6 &&
359 mbtowc(&wc
, "\342\202\254", 3) == 3 && wc
== 0x20AC)
360 n_psonce
|= n_PSO_UNICODE
;
361 /* Reset possibly messed up state; luckily this also gives us an
362 * indication whether the encoding has locking shift state sequences */
363 if(mbtowc(&wc
, NULL
, n_mb_cur_max
))
364 n_psonce
|= n_PSO_ENC_MBSTATE
;
368 #endif /* HAVE_C90AMEND1 */
378 if((cp
= ok_vlook(screen
)) != NULL
){
379 n_idec_uiz_cp(&rv
, cp
, 0, NULL
);
392 n_pager_get(char const **env_addon
){
396 rv
= ok_vlook(PAGER
);
398 if(env_addon
!= NULL
){
400 /* Update the manual upon any changes:
401 * *colour-pager*, $PAGER */
402 if(strstr(rv
, "less") != NULL
){
403 if(getenv("LESS") == NULL
)
404 *env_addon
= "LESS=RXi";
405 }else if(strstr(rv
, "lv") != NULL
){
406 if(getenv("LV") == NULL
)
407 *env_addon
= "LV=-c";
415 page_or_print(FILE *fp
, size_t lines
)
423 if (n_go_may_yield_control() && (cp
= ok_vlook(crt
)) != NULL
) {
427 rows
= (size_t)n_scrnheight
;
429 n_idec_uiz_cp(&rows
, cp
, 0, NULL
);
431 if (rows
> 0 && lines
== 0) {
432 while ((c
= getc(fp
)) != EOF
)
433 if (c
== '\n' && ++lines
>= rows
)
439 char const *env_add
[2], *pager
;
441 pager
= n_pager_get(&env_add
[0]);
443 n_child_run(pager
, NULL
, fileno(fp
), n_CHILD_FD_PASS
, NULL
,NULL
,NULL
,
449 while ((c
= getc(fp
)) != EOF
)
456 which_protocol(char const *name
, bool_t check_stat
, bool_t try_hooks
,
457 char const **adjusted_or_null
)
459 /* TODO This which_protocol() sickness should be URL::new()->protocol() */
460 char const *cp
, *orig_name
;
461 enum protocol rv
= PROTO_UNKNOWN
;
464 if(name
[0] == '%' && name
[1] == ':')
468 for (cp
= name
; *cp
&& *cp
!= ':'; cp
++)
472 if(cp
[0] == ':' && cp
[1] == '/' && cp
[2] == '/'){
473 if(!strncmp(name
, "file", sizeof("file") -1) ||
474 !strncmp(name
, "mbox", sizeof("mbox") -1))
476 else if(!strncmp(name
, "maildir", sizeof("maildir") -1))
478 else if(!strncmp(name
, "pop3", sizeof("pop3") -1)){
482 n_err(_("No POP3 support compiled in\n"));
484 }else if(!strncmp(name
, "pop3s", sizeof("pop3s") -1)){
485 #if defined HAVE_POP3 && defined HAVE_SSL
488 n_err(_("No POP3S support compiled in\n"));
491 else if(!strncmp(name
, "imap", sizeof("imap") -1)){
495 n_err(_("No IMAP support compiled in\n"));
497 }else if(!strncmp(name
, "imaps", sizeof("imaps") -1)){
498 #if defined HAVE_IMAP && defined HAVE_SSL
501 n_err(_("No IMAPS support compiled in\n"));
511 if(check_stat
|| try_hooks
){
512 struct n_file_type ft
;
517 np
= n_lofi_alloc((sz
= strlen(name
)) + 4 +1);
518 memcpy(np
, name
, sz
+ 1);
520 if(!stat(name
, &stb
)){
521 if(S_ISDIR(stb
.st_mode
) &&
522 (memcpy(&np
[sz
], "/tmp", 5),
523 !stat(np
, &stb
) && S_ISDIR(stb
.st_mode
)) &&
524 (memcpy(&np
[sz
], "/new", 5),
525 !stat(np
, &stb
) && S_ISDIR(stb
.st_mode
)) &&
526 (memcpy(&np
[sz
], "/cur", 5),
527 !stat(np
, &stb
) && S_ISDIR(stb
.st_mode
)))
529 }else if(try_hooks
&& n_filetype_trial(&ft
, name
))
530 orig_name
= savecatsep(name
, '.', ft
.ft_ext_dat
);
531 else if((cp
= ok_vlook(newfolders
)) != NULL
&&
532 !asccasecmp(cp
, "maildir"))
538 if(adjusted_or_null
!= NULL
)
539 *adjusted_or_null
= orig_name
;
545 n_c_to_hex_base16(char store
[3], char c
){
546 static char const itoa16
[] = "0123456789ABCDEF";
550 store
[1] = itoa16
[(ui8_t
)c
& 0x0F];
551 c
= ((ui8_t
)c
>> 4) & 0x0F;
552 store
[0] = itoa16
[(ui8_t
)c
];
558 n_c_from_hex_base16(char const hex
[2]){
559 static ui8_t
const atoi16
[] = {
560 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x30-0x37 */
561 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x38-0x3F */
562 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, /* 0x40-0x47 */
563 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x48-0x4f */
564 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x50-0x57 */
565 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x58-0x5f */
566 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF /* 0x60-0x67 */
572 if ((i1
= (ui8_t
)hex
[0] - '0') >= n_NELEM(atoi16
) ||
573 (i2
= (ui8_t
)hex
[1] - '0') >= n_NELEM(atoi16
))
577 if ((i1
| i2
) & 0xF0u
)
591 n_idec_buf(void *resp
, char const *cbuf
, uiz_t clen
, ui8_t base
,
592 enum n_idec_mode idm
, char const **endptr_or_null
){
593 /* XXX Brute simple and */
596 enum n_idec_state rv
;
599 idm
&= n__IDEC_MODE_MASK
;
600 rv
= n_IDEC_STATE_NONE
| idm
;
609 assert(base
!= 1 && base
<= 36);
610 /*if(base == 1 || base > 36)
614 while(spacechar(*cbuf
))
615 if(*++cbuf
== '\0' || --clen
== 0)
621 rv
|= n_IDEC_STATE_SEEN_MINUS
;
624 if(*++cbuf
== '\0' || --clen
== 0)
629 /* Base detection/skip */
634 /* Support BASE#number prefix, where BASE is decimal 2-36.
635 * Enter this only if anything is to follow after that prefix*/
639 if(((c1
= cbuf
[0]) >= '0' && c1
<= '9') &&
640 (((c2
= cbuf
[1]) == '#') ||
641 (c2
>= '0' && c2
<= '9' && clen
> 3 && cbuf
[2] == '#'))){
642 base
= a_aux_idec_atoi
[(ui8_t
)c1
];
647 base
*= 10; /* xxx Inline atoi decimal base */
648 base
+= a_aux_idec_atoi
[(ui8_t
)c2
];
651 /* We do not interpret this as BASE#number at all if either we
652 * did not get a valid base or if the first char is not valid
653 * according to base, to comply to the latest interpretion of
654 * "prefix", see comment for standard prefixes below */
655 if(base
< 2 || base
> 36 || a_aux_idec_atoi
[(ui8_t
)c3
] >= base
)
658 clen
-= 2, cbuf
+= 2;
660 clen
-= 3, cbuf
+= 3;
665 /* Character must be valid for base */
666 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
670 /* 0 always valid as is, fallback base 10 */
671 if(*++cbuf
== '\0' || --clen
== 0)
674 /* Base "detection" */
675 if(base
== 0 || base
== 2 || base
== 16){
686 if((base
& 16) == 0){
688 /* Char after prefix must be valid. However, after some error
689 * in the tor software all libraries (which had to) turned to
690 * an interpretation of the C standard which says that the
691 * prefix may optionally precede an otherwise valid sequence,
692 * which means that "0x" is not a STATE_INVAL error but gives
693 * a "0" result with a "STATE_BASE" error and a rest of "x" */
696 if(clen
> 1 && a_aux_idec_atoi
[(ui8_t
)cbuf
[1]] < base
)
699 if(*++cbuf
== '\0' || --clen
== 0)
702 /* Character must be valid for base, invalid otherwise */
703 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
716 /* Character must be valid for base, _EBASE otherwise */
717 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
722 for(cut
= a_aux_idec_cutlimit
[base
- 2];;){
726 if(res
> UI64_MAX
- currc
)
736 if(*++cbuf
== '\0' || --clen
== 0)
739 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
748 switch(rv
& n__IDEC_MODE_LIMIT_MASK
){
749 case n_IDEC_MODE_LIMIT_8BIT
: uimask
= UI8_MAX
; break;
750 case n_IDEC_MODE_LIMIT_16BIT
: uimask
= UI16_MAX
; break;
751 case n_IDEC_MODE_LIMIT_32BIT
: uimask
= UI32_MAX
; break;
752 default: uimask
= UI64_MAX
; break;
754 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
758 if((rv
& (n_IDEC_MODE_SIGNED_TYPE
| n_IDEC_STATE_SEEN_MINUS
)
759 ) == (n_IDEC_MODE_SIGNED_TYPE
| n_IDEC_STATE_SEEN_MINUS
)){
760 if(res
> uimask
+ 1){
769 if(!(rv
& n_IDEC_MODE_LIMIT_NOERROR
))
770 rv
|= n_IDEC_STATE_EOVERFLOW
;
771 }else if(rv
& n_IDEC_STATE_SEEN_MINUS
)
775 switch(rv
& n__IDEC_MODE_LIMIT_MASK
){
776 case n_IDEC_MODE_LIMIT_8BIT
:
777 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
778 *(si8_t
*)resp
= (si8_t
)res
;
780 *(ui8_t
*)resp
= (ui8_t
)res
;
782 case n_IDEC_MODE_LIMIT_16BIT
:
783 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
784 *(si16_t
*)resp
= (si16_t
)res
;
786 *(ui16_t
*)resp
= (ui16_t
)res
;
788 case n_IDEC_MODE_LIMIT_32BIT
:
789 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
790 *(si32_t
*)resp
= (si32_t
)res
;
792 *(ui32_t
*)resp
= (ui32_t
)res
;
795 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
796 *(si64_t
*)resp
= (si64_t
)res
;
798 *(ui64_t
*)resp
= (ui64_t
)res
;
802 if(endptr_or_null
!= NULL
)
803 *endptr_or_null
= cbuf
;
804 if(*cbuf
== '\0' || clen
== 0)
805 rv
|= n_IDEC_STATE_CONSUMED
;
810 rv
|= n_IDEC_STATE_EINVAL
;
813 /* Not a base error for terminator and whitespace! */
814 if(*cbuf
!= '\0' && !spacechar(*cbuf
))
815 rv
|= n_IDEC_STATE_EBASE
;
819 /* Overflow error: consume input until bad character or length out */
821 if(*++cbuf
== '\0' || --clen
== 0)
823 currc
= a_aux_idec_atoi
[(ui8_t
)*cbuf
];
828 rv
|= n_IDEC_STATE_EOVERFLOW
;
830 if(rv
& n_IDEC_MODE_SIGNED_TYPE
)
831 res
= (rv
& n_IDEC_STATE_SEEN_MINUS
) ? (ui64_t
)SI64_MIN
835 rv
&= ~n_IDEC_STATE_SEEN_MINUS
;
840 n_torek_hash(char const *name
){
841 /* Chris Torek's hash */
846 for(h
= 0; (c
= *name
++) != '\0';)
853 n_torek_ihashn(char const *dat
, size_t len
){
854 /* See n_torek_hash() */
860 for(h
= 0; (c
= *dat
++) != '\0';)
861 h
= (h
* 33) + lowerconv(c
);
863 for(h
= 0; len
> 0; --len
){
865 h
= (h
* 33) + lowerconv(c
);
872 n_prime_next(ui32_t n
){
873 static ui32_t
const primes
[] = {
874 5, 11, 23, 47, 97, 157, 283,
875 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521,
876 131071, 262139, 524287, 1048573, 2097143, 4194301,
877 8388593, 16777213, 33554393, 67108859, 134217689,
878 268435399, 536870909, 1073741789, 2147483647
883 i
= (n
< primes
[n_NELEM(primes
) / 4] ? 0
884 : (n
< primes
[n_NELEM(primes
) / 2] ? n_NELEM(primes
) / 4
885 : n_NELEM(primes
) / 2));
887 do if((mprime
= primes
[i
]) > n
)
889 while(++i
< n_NELEM(primes
));
891 if(i
== n_NELEM(primes
) && mprime
< n
)
898 n_getdeadletter(void){
905 cp
= fexpand(ok_vlook(DEAD
), FEXP_LOCAL
| FEXP_NSHELL
);
906 if(cp
== NULL
|| strlen(cp
) >= PATH_MAX
){
908 n_err(_("Failed to expand *DEAD*, setting default (%s): %s\n"),
909 VAL_DEAD
, n_shexp_quote_cp((cp
== NULL
? n_empty
: cp
), FAL0
));
914 cp
= savecatsep(ok_vlook(TMPDIR
), '/', VAL_DEAD_BASENAME
);
915 n_err(_("Cannot expand *DEAD*, using: %s\n"), cp
);
923 n_nodename(bool_t mayoverride
){
924 static char *sys_hostname
, *hostname
; /* XXX free-at-exit */
929 # ifdef HAVE_GETADDRINFO
930 struct addrinfo hints
, *res
;
932 struct hostent
*hent
;
937 if(mayoverride
&& (hn
= ok_vlook(hostname
)) != NULL
&& *hn
!= '\0'){
939 }else if((hn
= sys_hostname
) == NULL
){
943 # ifdef HAVE_GETADDRINFO
944 memset(&hints
, 0, sizeof hints
);
945 hints
.ai_family
= AF_UNSPEC
;
946 hints
.ai_flags
= AI_CANONNAME
;
947 if(getaddrinfo(hn
, NULL
, &hints
, &res
) == 0){
948 if(res
->ai_canonname
!= NULL
){
951 l
= strlen(res
->ai_canonname
) +1;
952 hn
= n_lofi_alloc(l
);
953 memcpy(hn
, res
->ai_canonname
, l
);
958 hent
= gethostbyname(hn
);
963 sys_hostname
= sstrdup(hn
);
964 #if defined HAVE_SOCKETS && defined HAVE_GETADDRINFO
965 if(hn
!= ut
.nodename
)
971 if(hostname
!= NULL
&& hostname
!= sys_hostname
)
973 hostname
= sstrdup(hn
);
980 n_idna_to_ascii(struct n_string
*out
, char const *ibuf
, size_t ilen
){
985 if((rv
= (ilen
== 0)))
988 if(ibuf
[ilen
] != '\0') /* TODO n_idna_to_ascii: optimise */
989 ibuf
= savestrbuf(ibuf
, ilen
);
992 idna_utf8
= n_iconv_onetime_cp(n_ICONV_NONE
, "utf-8", ok_vlook(ttycharset
),
994 if(idna_utf8
== NULL
)
997 # if HAVE_IDNA == HAVE_IDNA_LIBIDNA
1001 if(idna_to_ascii_8z(idna_utf8
, &idna_ascii
, 0) == IDNA_SUCCESS
){
1002 out
= n_string_assign_cp(out
, idna_ascii
);
1003 idn_free(idna_ascii
);
1008 # elif HAVE_IDNA == HAVE_IDNA_IDNKIT
1009 ilen
= strlen(idna_utf8
);
1011 switch(idn_encodename((IDN_ENCODE_APP
& ~IDN_LOCALCONV
), idna_utf8
,
1012 n_string_resize(n_string_trunc(out
, 0), ilen
)->s_dat
, ilen
)){
1013 case idn_buffer_overflow
:
1014 ilen
+= HOST_NAME_MAX
+1;
1018 ilen
= strlen(out
->s_dat
);
1026 # error Unknown HAVE_IDNA
1029 out
= n_string_trunc(out
, ilen
);
1033 #endif /* HAVE_IDNA */
1036 n_random_create_buf(char *dat
, size_t len
, ui32_t
*reprocnt_or_null
){
1038 char *indat
, *cp
, *oudat
;
1039 size_t i
, inlen
, oulen
;
1042 if(!(n_psonce
& n_PSO_RANDOM_INIT
)){
1043 n_psonce
|= n_PSO_RANDOM_INIT
;
1045 if(n_poption
& n_PO_D_V
){
1048 #if n_RANDOM_USE_XSSL
1049 prngn
= "*SSL RAND_*";
1050 #elif defined HAVE_POSIX_RANDOM
1051 prngn
= "POSIX/arc4random";
1053 prngn
= "builtin ARC4";
1055 n_err(_("Setting up PseudoRandomNumberGenerator: %s\n"), prngn
);
1058 #if !defined HAVE_POSIX_RANDOM && !n_RANDOM_USE_XSSL
1063 /* We use our base64 encoder with _NOPAD set, so ensure the encoded result
1064 * with PAD stripped is still longer than what the user requests, easy way.
1065 * The relation of base64 is fixed 3 in = 4 out, and we do not want to
1066 * include the base64 PAD characters in our random string: give some pad */
1068 if((inlen
= i
% 3) != 0)
1077 inlen
= inlen
+ (inlen
<< 1);
1079 indat
= n_lofi_alloc(inlen
+1);
1081 if(!(n_psonce
& n_PSO_REPRODUCIBLE
) || reprocnt_or_null
== NULL
){
1082 #if n_RANDOM_USE_XSSL
1083 ssl_rand_bytes(indat
, inlen
);
1084 #elif !defined HAVE_POSIX_RANDOM
1085 for(i
= inlen
; i
-- > 0;)
1086 indat
[i
] = (char)a_aux_rand_get8();
1088 for(cp
= indat
, i
= inlen
; i
> 0;){
1089 union {ui32_t i4
; char c
[4];} r
;
1092 r
.i4
= (ui32_t
)arc4random();
1093 switch((j
= i
& 3)){
1094 case 0: cp
[3] = r
.c
[3]; j
= 4; /* FALLTHRU */
1095 case 3: cp
[2] = r
.c
[2]; /* FALLTHRU */
1096 case 2: cp
[1] = r
.c
[1]; /* FALLTHRU */
1097 default: cp
[0] = r
.c
[0]; break;
1104 for(cp
= indat
, i
= inlen
; i
> 0;){
1105 union {ui32_t i4
; char c
[4];} r
;
1108 r
.i4
= ++*reprocnt_or_null
;
1109 if(n_psonce
& n_PSO_BIG_ENDIAN
){ /* TODO BSWAP */
1119 switch((j
= i
& 3)){
1120 case 0: cp
[3] = r
.c
[3]; j
= 4; /* FALLTHRU */
1121 case 3: cp
[2] = r
.c
[2]; /* FALLTHRU */
1122 case 2: cp
[1] = r
.c
[1]; /* FALLTHRU */
1123 default: cp
[0] = r
.c
[0]; break;
1130 oudat
= (len
>= oulen
) ? dat
: n_lofi_alloc(oulen
+1);
1132 b64_encode_buf(&b64
, indat
, inlen
, B64_BUF
| B64_RFC4648URL
| B64_NOPAD
);
1133 assert(b64
.l
>= len
);
1134 memcpy(dat
, b64
.s
, len
);
1146 n_random_create_cp(size_t len
, ui32_t
*reprocnt_or_null
){
1150 dat
= n_autorec_alloc(len
+1);
1151 dat
= n_random_create_buf(dat
, len
, reprocnt_or_null
);
1157 boolify(char const *inbuf
, uiz_t inlen
, si8_t emptyrv
)
1162 assert(inlen
== 0 || inbuf
!= NULL
);
1164 if (inlen
== UIZ_MAX
)
1165 inlen
= strlen(inbuf
);
1168 rv
= (emptyrv
>= 0) ? (emptyrv
== 0 ? 0 : 1) : -1;
1170 if ((inlen
== 1 && (*inbuf
== '1' || *inbuf
== 'y' || *inbuf
== 'Y')) ||
1171 !ascncasecmp(inbuf
, "true", inlen
) ||
1172 !ascncasecmp(inbuf
, "yes", inlen
) ||
1173 !ascncasecmp(inbuf
, "on", inlen
))
1175 else if ((inlen
== 1 &&
1176 (*inbuf
== '0' || *inbuf
== 'n' || *inbuf
== 'N')) ||
1177 !ascncasecmp(inbuf
, "false", inlen
) ||
1178 !ascncasecmp(inbuf
, "no", inlen
) ||
1179 !ascncasecmp(inbuf
, "off", inlen
))
1184 if((n_idec_buf(&ib
, inbuf
, inlen
, 0, 0, NULL
1185 ) & (n_IDEC_STATE_EMASK
| n_IDEC_STATE_CONSUMED
)
1186 ) != n_IDEC_STATE_CONSUMED
)
1197 quadify(char const *inbuf
, uiz_t inlen
, char const *prompt
, si8_t emptyrv
)
1202 assert(inlen
== 0 || inbuf
!= NULL
);
1204 if (inlen
== UIZ_MAX
)
1205 inlen
= strlen(inbuf
);
1208 rv
= (emptyrv
>= 0) ? (emptyrv
== 0 ? 0 : 1) : -1;
1209 else if ((rv
= boolify(inbuf
, inlen
, -1)) < 0 &&
1210 !ascncasecmp(inbuf
, "ask-", 4) &&
1211 (rv
= boolify(inbuf
+ 4, inlen
- 4, -1)) >= 0 &&
1212 (n_psonce
& n_PSO_INTERACTIVE
) && !(n_pstate
& n_PS_ROBOT
))
1213 rv
= getapproval(prompt
, rv
);
1219 n_is_all_or_aster(char const *name
){
1223 rv
= ((name
[0] == '*' && name
[1] == '\0') || !asccasecmp(name
, "all"));
1228 FL
struct n_timespec
const *
1229 n_time_now(bool_t force_update
){ /* TODO event loop update IF cmd requests! */
1230 static struct n_timespec ts_now
;
1233 if(n_psonce
& n_PSO_REPRODUCIBLE
){
1234 (void)n_idec_ui64_cp(&ts_now
.ts_sec
, ok_vlook(SOURCE_DATE_EPOCH
), 0,NULL
);
1236 }else if(force_update
|| ts_now
.ts_sec
== 0){
1237 #ifdef HAVE_CLOCK_GETTIME
1240 clock_gettime(CLOCK_REALTIME
, &ts
);
1241 ts_now
.ts_sec
= (si64_t
)ts
.tv_sec
;
1242 ts_now
.ts_nsec
= (siz_t
)ts
.tv_nsec
;
1243 #elif defined HAVE_GETTIMEOFDAY
1246 gettimeofday(&tv
, NULL
);
1247 ts_now
.ts_sec
= (si64_t
)tv
.tv_sec
;
1248 ts_now
.ts_nsec
= (siz_t
)tv
.tv_usec
* 1000;
1250 ts_now
.ts_sec
= (si64_t
)time(NULL
);
1259 time_current_update(struct time_current
*tc
, bool_t full_update
)
1262 tc
->tc_time
= (time_t)n_time_now(TRU1
)->ts_sec
;
1264 memcpy(&tc
->tc_gm
, gmtime(&tc
->tc_time
), sizeof tc
->tc_gm
);
1265 memcpy(&tc
->tc_local
, localtime(&tc
->tc_time
), sizeof tc
->tc_local
);
1266 sstpcpy(tc
->tc_ctime
, ctime(&tc
->tc_time
));
1272 n_msleep(uiz_t millis
, bool_t ignint
){
1276 #ifdef HAVE_NANOSLEEP
1278 struct timespec ts
, trem
;
1281 ts
.tv_sec
= millis
/ 1000;
1282 ts
.tv_nsec
= (millis
%= 1000) * 1000 * 1000;
1284 while((i
= nanosleep(&ts
, &trem
)) != 0 && ignint
)
1286 rv
= (i
== 0) ? 0 : (trem
.tv_sec
* 1000) + (trem
.tv_nsec
/ (1000 * 1000));
1289 #elif defined HAVE_SLEEP
1290 if((millis
/= 1000) == 0)
1292 while((rv
= sleep((unsigned int)millis
)) != 0 && ignint
)
1295 # error Configuration should have detected a function for sleeping.
1303 n_err(char const *format
, ...){
1307 va_start(ap
, format
);
1309 if(n_psonce
& n_PSO_INTERACTIVE
)
1319 while(*format
== '\n'){
1321 putc('\n', n_stderr
);
1326 a_aux_err_linelen
= 0;
1328 if((len
= strlen(format
)) > 0){
1329 if(doname
|| a_aux_err_linelen
== 0){
1332 if(*(cp
= ok_vlook(log_prefix
)) != '\0')
1333 fputs(cp
, n_stderr
);
1335 vfprintf(n_stderr
, format
, ap
);
1340 if(format
[--len
] == '\n'){
1341 a_aux_err_linelen
= (i
-= ++len
);
1344 ++a_aux_err_linelen
;
1356 n_verr(char const *format
, va_list ap
){
1358 struct a_aux_err_node
*enp
;
1366 while(*format
== '\n'){
1367 putc('\n', n_stderr
);
1373 a_aux_err_linelen
= 0;
1375 if(n_psonce
& n_PSO_INTERACTIVE
){
1376 if((enp
= a_aux_err_tail
) != NULL
&&
1377 (enp
->ae_str
.s_len
> 0 &&
1378 enp
->ae_str
.s_dat
[enp
->ae_str
.s_len
- 1] != '\n'))
1379 n_string_push_c(&enp
->ae_str
, '\n');
1384 if((len
= strlen(format
)) == 0)
1387 n_pstate
|= n_PS_ERRORS_PROMPT
;
1390 if(doname
|| a_aux_err_linelen
== 0){
1393 if(*(cp
= ok_vlook(log_prefix
)) != '\0')
1394 fputs(cp
, n_stderr
);
1400 if(format
[--len
] == '\n'){
1401 a_aux_err_linelen
= (i
-= ++len
);
1404 ++a_aux_err_linelen
;
1409 if(!(n_psonce
& n_PSO_INTERACTIVE
))
1411 vfprintf(n_stderr
, format
, ap
);
1415 n_LCTAV(ERRORS_MAX
> 3);
1417 /* Link it into the `errors' message ring */
1418 if((enp
= a_aux_err_tail
) == NULL
){
1420 enp
= smalloc(sizeof *enp
);
1421 enp
->ae_next
= NULL
;
1422 n_string_creat(&enp
->ae_str
);
1423 if(a_aux_err_tail
!= NULL
)
1424 a_aux_err_tail
->ae_next
= enp
;
1426 a_aux_err_head
= enp
;
1427 a_aux_err_tail
= enp
;
1430 (enp
->ae_str
.s_len
> 0 &&
1431 enp
->ae_str
.s_dat
[enp
->ae_str
.s_len
- 1] == '\n')){
1432 if(a_aux_err_cnt
< ERRORS_MAX
)
1435 a_aux_err_head
= (enp
= a_aux_err_head
)->ae_next
;
1436 a_aux_err_tail
->ae_next
= enp
;
1437 a_aux_err_tail
= enp
;
1438 enp
->ae_next
= NULL
;
1439 n_string_trunc(&enp
->ae_str
, 0);
1442 # ifdef HAVE_N_VA_COPY
1445 imax
= n_MIN(LINESIZE
, 1024);
1447 for(i
= imax
;; imax
= ++i
/* xxx could wrap, maybe */){
1448 # ifdef HAVE_N_VA_COPY
1456 n_string_resize(&enp
->ae_str
, (len
= enp
->ae_str
.s_len
) + (size_t)i
);
1457 i
= vsnprintf(&enp
->ae_str
.s_dat
[len
], (size_t)i
, format
, vac
);
1458 # ifdef HAVE_N_VA_COPY
1465 if(UICMP(z
, i
, >=, imax
)){
1466 # ifdef HAVE_N_VA_COPY
1467 /* XXX Check overflow for upcoming LEN+++i! */
1468 n_string_trunc(&enp
->ae_str
, len
);
1471 i
= (int)strlen(&enp
->ae_str
.s_dat
[len
]);
1476 n_string_trunc(&enp
->ae_str
, len
+ (size_t)i
);
1478 fwrite(&enp
->ae_str
.s_dat
[len
], 1, (size_t)i
, n_stderr
);
1480 #endif /* HAVE_ERRORS */
1488 n_err_sighdl(char const *format
, ...){ /* TODO sigsafe; obsolete! */
1492 va_start(ap
, format
);
1493 vfprintf(n_stderr
, format
, ap
);
1499 n_perr(char const *msg
, int errval
){
1510 e
= (errval
== 0) ? n_err_no
: errval
;
1511 n_err(fmt
, msg
, n_err_to_doc(e
));
1518 n_alert(char const *format
, ...){
1522 n_err(a_aux_err_linelen
> 0 ? _("\nAlert: ") : _("Alert: "));
1524 va_start(ap
, format
);
1533 n_panic(char const *format
, ...){
1537 if(a_aux_err_linelen
> 0){
1538 putc('\n', n_stderr
);
1539 a_aux_err_linelen
= 0;
1541 fprintf(n_stderr
, "%sPanic: ", ok_vlook(log_prefix
));
1543 va_start(ap
, format
);
1544 vfprintf(n_stderr
, format
, ap
);
1547 putc('\n', n_stderr
);
1550 abort(); /* Was exit(n_EXIT_ERR); for a while, but no */
1557 struct a_aux_err_node
*enp
;
1564 if(!asccasecmp(*argv
, "show"))
1566 if(!asccasecmp(*argv
, "clear"))
1570 _("Synopsis: errors: (<show> or) <clear> the error ring\n"));
1574 return (v
== NULL
) ? !STOP
: !OKAY
; /* xxx 1:bad 0:good -- do some */
1580 if(a_aux_err_head
== NULL
){
1581 fprintf(n_stderr
, _("The error ring is empty\n"));
1585 if((fp
= Ftmp(NULL
, "errors", OF_RDWR
| OF_UNLINK
| OF_REGISTER
)) ==
1587 fprintf(n_stderr
, _("tmpfile"));
1592 for(i
= 0, enp
= a_aux_err_head
; enp
!= NULL
; enp
= enp
->ae_next
)
1593 fprintf(fp
, "%4" PRIuZ
". %s", ++i
, n_string_cp(&enp
->ae_str
));
1594 /* We don't know whether last string ended with NL; be simple XXX */
1597 page_or_print(fp
, 0);
1603 a_aux_err_tail
= NULL
;
1604 a_aux_err_cnt
= a_aux_err_cnt_noted
= 0;
1605 a_aux_err_linelen
= 0;
1606 while((enp
= a_aux_err_head
) != NULL
){
1607 a_aux_err_head
= enp
->ae_next
;
1608 n_string_gut(&enp
->ae_str
);
1613 #endif /* HAVE_ERRORS */
1616 n_err_to_doc(si32_t eno
){
1618 struct a_aux_err_map
const *aemp
;
1621 aemp
= a_aux_err_map_from_no(eno
);
1622 rv
= &a_aux_err_docs
[aemp
->aem_docoff
];
1628 n_err_to_name(si32_t eno
){
1630 struct a_aux_err_map
const *aemp
;
1633 aemp
= a_aux_err_map_from_no(eno
);
1634 rv
= &a_aux_err_names
[aemp
->aem_nameoff
];
1640 n_err_from_name(char const *name
){
1641 struct a_aux_err_map
const *aemp
;
1642 ui32_t hash
, i
, j
, x
;
1646 hash
= n_torek_hash(name
);
1648 for(i
= hash
% a_AUX_ERR_REV_PRIME
, j
= 0; j
<= a_AUX_ERR_REV_LONGEST
; ++j
){
1649 if((x
= a_aux_err_revmap
[i
]) == a_AUX_ERR_REV_ILL
)
1652 aemp
= &a_aux_err_map
[x
];
1653 if(aemp
->aem_hash
== hash
&&
1654 !strcmp(&a_aux_err_names
[aemp
->aem_nameoff
], name
)){
1655 rv
= aemp
->aem_err_no
;
1659 if(++i
== a_AUX_ERR_REV_PRIME
){
1660 #ifdef a_AUX_ERR_REV_WRAPAROUND
1668 /* Have not found it. But wait, it could be that the user did, e.g.,
1669 * eval echo \$^ERR-$: \$^ERRDOC-$!: \$^ERRNAME-$! */
1670 if((n_idec_si32_cp(&rv
, name
, 0, NULL
) &
1671 (n_IDEC_STATE_EMASK
| n_IDEC_STATE_CONSUMED
)
1672 ) == n_IDEC_STATE_CONSUMED
){
1673 aemp
= a_aux_err_map_from_no(rv
);
1674 rv
= aemp
->aem_err_no
;
1678 rv
= a_aux_err_map
[n__ERR_NUMBER_VOIDOFF
].aem_err_no
;
1686 n_regex_err_to_doc(const regex_t
*rep
, int e
){
1691 i
= regerror(e
, rep
, NULL
, 0) +1;
1693 regerror(e
, rep
, cp
, i
);