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 - 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. 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 #ifndef HAVE_POSIX_RANDOM
60 ui8_t b8
[sizeof(struct rand_arc4
)];
61 ui32_t b32
[sizeof(struct rand_arc4
) / sizeof(ui32_t
)];
66 struct a_aux_err_node
{
67 struct a_aux_err_node
*ae_next
;
68 struct n_string ae_str
;
72 #ifndef HAVE_POSIX_RANDOM
73 static union rand_state
*_rand
;
76 /* Error ring, for `errors' */
78 static struct a_aux_err_node
*a_aux_err_head
, *a_aux_err_tail
;
79 static size_t a_aux_err_cnt
, a_aux_err_cnt_noted
;
81 static size_t a_aux_err_linelen
;
83 /* Our ARC4 random generator with its completely unacademical pseudo
84 * initialization (shall /dev/urandom fail) */
85 #ifndef HAVE_POSIX_RANDOM
86 static void _rand_init(void);
87 static ui32_t
_rand_weak(ui32_t seed
);
88 SINLINE ui8_t
_rand_get8(void);
91 #ifndef HAVE_POSIX_RANDOM
95 # ifdef HAVE_CLOCK_GETTIME
100 union {int fd
; size_t i
;} u
;
104 _rand
= smalloc(sizeof *_rand
);
106 if ((u
.fd
= open("/dev/urandom", O_RDONLY
)) != -1) {
107 bool_t ok
= (sizeof *_rand
== (size_t)read(u
.fd
, _rand
, sizeof *_rand
));
114 for (seed
= (uintptr_t)_rand
& UI32_MAX
, rnd
= 21; rnd
!= 0; --rnd
) {
115 for (u
.i
= NELEM(_rand
->b32
); u
.i
-- != 0;) {
118 # ifdef HAVE_CLOCK_GETTIME
119 clock_gettime(CLOCK_REALTIME
, &ts
);
120 t
= (ui32_t
)ts
.tv_nsec
;
122 gettimeofday(&ts
, NULL
);
123 t
= (ui32_t
)ts
.tv_usec
;
126 t
= (t
>> 16) | (t
<< 16);
127 _rand
->b32
[u
.i
] ^= _rand_weak(seed
^ t
);
128 _rand
->b32
[t
% NELEM(_rand
->b32
)] ^= seed
;
129 if (rnd
== 7 || rnd
== 17)
130 _rand
->b32
[u
.i
] ^= _rand_weak(seed
^ (ui32_t
)ts
.tv_sec
);
131 k
= _rand
->b32
[u
.i
] % NELEM(_rand
->b32
);
132 _rand
->b32
[k
] ^= _rand
->b32
[u
.i
];
133 seed
^= _rand_weak(_rand
->b32
[k
]);
135 seed
^= nextprime(seed
);
139 for (u
.i
= 5 * sizeof(_rand
->b8
); u
.i
!= 0; --u
.i
)
146 _rand_weak(ui32_t seed
)
148 /* From "Random number generators: good ones are hard to find",
149 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
150 * October 1988, p. 1195.
151 * (In fact: FreeBSD 4.7, /usr/src/lib/libc/stdlib/random.c.) */
158 seed
= (seed
* 16807) - (hi
* 2836);
159 if ((si32_t
)seed
< 0)
169 si
= _rand
->a
._dat
[++_rand
->a
._i
];
170 sj
= _rand
->a
._dat
[_rand
->a
._j
+= si
];
171 _rand
->a
._dat
[_rand
->a
._i
] = sj
;
172 _rand
->a
._dat
[_rand
->a
._j
] = si
;
173 return _rand
->a
._dat
[(ui8_t
)(si
+ sj
)];
175 #endif /* HAVE_POSIX_RANDOM */
183 if((cp
= ok_vlook(screen
)) == NULL
|| (s
= strtoul(cp
, NULL
, 0)) == 0)
185 s
-= 2; /* XXX no magics */
186 if(s
> INT_MAX
) /* TODO function should return unsigned */
193 n_pager_get(char const **env_addon
){
197 rv
= ok_vlook(PAGER
);
199 if(env_addon
!= NULL
){
201 /* Update the manual upon any changes:
202 * *colour-pager*, $PAGER */
203 if(strstr(rv
, "less") != NULL
){
204 if(getenv("LESS") == NULL
)
207 (pstate
& PS_TERMCAP_CA_MODE
) ? "LESS=Ri"
208 : !(pstate
& PS_TERMCAP_DISABLE
) ? "LESS=FRi" :
211 }else if(strstr(rv
, "lv") != NULL
){
212 if(getenv("LV") == NULL
)
213 *env_addon
= "LV=-c";
221 page_or_print(FILE *fp
, size_t lines
)
229 if (n_source_may_yield_control() && (cp
= ok_vlook(crt
)) != NULL
) {
232 rows
= (*cp
== '\0') ? (size_t)scrnheight
: strtoul(cp
, NULL
, 0);
234 if (rows
> 0 && lines
== 0) {
235 while ((c
= getc(fp
)) != EOF
)
236 if (c
== '\n' && ++lines
>= rows
)
242 run_command(n_pager_get(NULL
), 0, fileno(fp
), COMMAND_FD_PASS
,
243 NULL
, NULL
, NULL
, NULL
);
248 while ((c
= getc(fp
)) != EOF
)
255 which_protocol(char const *name
) /* XXX (->URL (yet auxlily.c)) */
261 enum protocol rv
= PROTO_UNKNOWN
;
264 temporary_protocol_ext
= NULL
;
266 if (name
[0] == '%' && name
[1] == ':')
268 for (cp
= name
; *cp
&& *cp
!= ':'; cp
++)
272 if (cp
[0] == ':' && cp
[1] == '/' && cp
[2] == '/') {
273 if (!strncmp(name
, "pop3://", 7)) {
277 n_err(_("No POP3 support compiled in\n"));
279 } else if (!strncmp(name
, "pop3s://", 8)) {
280 #if defined HAVE_POP3 && defined HAVE_SSL
284 n_err(_("No POP3 support compiled in\n"));
287 n_err(_("No SSL support compiled in\n"));
294 /* TODO This is the de facto maildir code and thus belongs into there!
295 * TODO and: we should have maildir:// and mbox:// pseudo-protos, instead of
296 * TODO or (more likely) in addition to *newfolders*) */
299 np
= ac_alloc((sz
= strlen(name
)) + 4 +1);
300 memcpy(np
, name
, sz
+ 1);
301 if (!stat(name
, &st
)) {
302 if (S_ISDIR(st
.st_mode
) &&
303 (memcpy(np
+sz
, "/tmp", 5), !stat(np
, &st
) && S_ISDIR(st
.st_mode
)) &&
304 (memcpy(np
+sz
, "/new", 5), !stat(np
, &st
) && S_ISDIR(st
.st_mode
)) &&
305 (memcpy(np
+sz
, "/cur", 5), !stat(np
, &st
) && S_ISDIR(st
.st_mode
)))
308 if ((memcpy(np
+sz
, cp
=".gz", 4), !stat(np
, &st
) && S_ISREG(st
.st_mode
)) ||
309 (memcpy(np
+sz
, cp
=".xz",4), !stat(np
,&st
) && S_ISREG(st
.st_mode
)) ||
310 (memcpy(np
+sz
, cp
=".bz2",5), !stat(np
, &st
) && S_ISREG(st
.st_mode
)))
311 temporary_protocol_ext
= cp
;
312 else if ((cp
= ok_vlook(newfolders
)) != NULL
&&
313 !asccasecmp(cp
, "maildir"))
323 n_c_to_hex_base16(char store
[3], char c
){
324 static char const itoa16
[] = "0123456789ABCDEF";
328 store
[1] = itoa16
[(ui8_t
)c
& 0x0F];
329 c
= ((ui8_t
)c
>> 4) & 0x0F;
330 store
[0] = itoa16
[(ui8_t
)c
];
336 n_c_from_hex_base16(char const hex
[2]){
337 static ui8_t
const atoi16
[] = {
338 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x30-0x37 */
339 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x38-0x3F */
340 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, /* 0x40-0x47 */
341 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x48-0x4f */
342 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x50-0x57 */
343 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x58-0x5f */
344 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF /* 0x60-0x67 */
350 if ((i1
= (ui8_t
)hex
[0] - '0') >= NELEM(atoi16
) ||
351 (i2
= (ui8_t
)hex
[1] - '0') >= NELEM(atoi16
))
355 if ((i1
| i2
) & 0xF0u
)
369 torek_hash(char const *name
)
371 /* Chris Torek's hash.
372 * NOTE: need to change *at least* mk-okey-map.pl when changing the
377 while (*name
!= '\0') {
386 torek_ihashn(char const *dat
, size_t len
){
387 /* See torek_hash() */
392 for(h
= 0; len
> 0 && (c
= *dat
++) != '\0'; --len
)
393 h
= (h
* 33) + lowerconv(c
);
399 pjw(char const *cp
) /* TODO obsolete that -> torek_hash */
406 h
= (h
<< 4 & 0xffffffff) + (*cp
&0377);
407 if ((g
= h
& 0xf0000000) != 0) {
419 static ui32_t
const primes
[] = {
420 5, 11, 23, 47, 97, 157, 283,
421 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521,
422 131071, 262139, 524287, 1048573, 2097143, 4194301,
423 8388593, 16777213, 33554393, 67108859, 134217689,
424 268435399, 536870909, 1073741789, 2147483647
430 i
= (n
< primes
[NELEM(primes
) / 4] ? 0
431 : (n
< primes
[NELEM(primes
) / 2] ? NELEM(primes
) / 4
432 : NELEM(primes
) / 2));
434 if ((mprime
= primes
[i
]) > n
)
436 while (++i
< NELEM(primes
));
437 if (i
== NELEM(primes
) && mprime
< n
)
444 getprompt(void) /* TODO evaluate only as necessary (needs a bit) PART OF UI! */
445 { /* FIXME getprompt must mb->wc->mb+reset seq! */
446 static char buf
[PROMPT_BUFFER_SIZE
];
449 char const *ccp_base
, *ccp
;
450 size_t NATCH_CHAR( cclen_base COMMA cclen COMMA
) maxlen
, dfmaxlen
;
451 bool_t trigger
; /* 1.: `errors' ring note? 2.: first loop tick done */
454 /* No other place to place this */
456 if (options
& OPT_INTERACTIVE
) {
457 if (!(pstate
& PS_ERRORS_NOTED
) && a_aux_err_head
!= NULL
) {
458 pstate
|= PS_ERRORS_NOTED
;
459 fprintf(stderr
, _("There are new messages in the error message ring "
460 "(denoted by \"#ERR#\")\n"
461 " The `errors' command manages this message ring\n"));
464 if ((trigger
= (a_aux_err_cnt_noted
!= a_aux_err_cnt
)))
465 a_aux_err_cnt_noted
= a_aux_err_cnt
;
471 if ((ccp_base
= ok_vlook(prompt
)) == NULL
|| *ccp_base
== '\0') {
481 ccp_base
= savecatsep(_("#ERR#"), '\0', ccp_base
);
483 NATCH_CHAR( cclen_base
= strlen(ccp_base
); )
485 dfmaxlen
= 0; /* keep CC happy */
489 NATCH_CHAR( cclen
= cclen_base
; )
490 maxlen
= sizeof(buf
) -1;
498 #ifdef HAVE_NATCH_CHAR
499 c
= mblen(ccp
, cclen
); /* TODO use mbrtowc() */
508 } else if ((l
= c
) > 1) {
518 if ((c
= n_shell_expand_escape(&ccp
, TRU1
)) > 0) {
524 if (c
== 0 || c
== PROMPT_STOP
)
528 char const *a
= (c
== PROMPT_DOLLAR
) ? account_name
: displayname
;
531 if ((l
= field_put_bidi_clip(cp
, dfmaxlen
, a
, strlen(a
))) > 0) {
551 nodename(int mayoverride
)
553 static char *sys_hostname
, *hostname
; /* XXX free-at-exit */
558 # ifdef HAVE_GETADDRINFO
559 struct addrinfo hints
, *res
;
561 struct hostent
*hent
;
566 if (mayoverride
&& (hn
= ok_vlook(hostname
)) != NULL
&& *hn
!= '\0') {
568 } else if ((hn
= sys_hostname
) == NULL
) {
572 # ifdef HAVE_GETADDRINFO
573 memset(&hints
, 0, sizeof hints
);
574 hints
.ai_family
= AF_UNSPEC
;
575 hints
.ai_flags
= AI_CANONNAME
;
576 if (getaddrinfo(hn
, NULL
, &hints
, &res
) == 0) {
577 if (res
->ai_canonname
!= NULL
) {
578 size_t l
= strlen(res
->ai_canonname
) +1;
581 memcpy(hn
, res
->ai_canonname
, l
);
586 hent
= gethostbyname(hn
);
591 sys_hostname
= sstrdup(hn
);
592 #if defined HAVE_SOCKETS && defined HAVE_GETADDRINFO
593 if (hn
!= ut
.nodename
)
599 if (hostname
!= NULL
&& hostname
!= sys_hostname
)
601 hostname
= sstrdup(hn
);
607 getrandstring(size_t length
)
614 #ifndef HAVE_POSIX_RANDOM
619 /* We use our base64 encoder with _NOPAD set, so ensure the encoded result
620 * with PAD stripped is still longer than what the user requests, easy way */
621 data
= ac_alloc(i
= length
+ 3);
623 #ifndef HAVE_POSIX_RANDOM
625 data
[i
] = (char)_rand_get8();
630 union {ui32_t i4
; char c
[4];} r
;
633 r
.i4
= (ui32_t
)arc4random();
634 switch ((j
= i
& 3)) {
635 case 0: cp
[3] = r
.c
[3]; j
= 4;
636 case 3: cp
[2] = r
.c
[2];
637 case 2: cp
[1] = r
.c
[1];
638 default: cp
[0] = r
.c
[0]; break;
646 b64_encode_buf(&b64
, data
, length
+ 3,
647 B64_SALLOC
| B64_RFC4648URL
| B64_NOPAD
);
650 assert(b64
.l
>= length
);
651 b64
.s
[length
] = '\0';
657 boolify(char const *inbuf
, uiz_t inlen
, si8_t emptyrv
)
664 assert(inlen
== 0 || inbuf
!= NULL
);
666 if (inlen
== UIZ_MAX
)
667 inlen
= strlen(inbuf
);
670 rv
= (emptyrv
>= 0) ? (emptyrv
== 0 ? 0 : 1) : -1;
672 if ((inlen
== 1 && *inbuf
== '1') ||
673 !ascncasecmp(inbuf
, "true", inlen
) ||
674 !ascncasecmp(inbuf
, "yes", inlen
) ||
675 !ascncasecmp(inbuf
, "on", inlen
))
677 else if ((inlen
== 1 && *inbuf
== '0') ||
678 !ascncasecmp(inbuf
, "false", inlen
) ||
679 !ascncasecmp(inbuf
, "no", inlen
) ||
680 !ascncasecmp(inbuf
, "off", inlen
))
683 dat
= ac_alloc(inlen
+1);
684 memcpy(dat
, inbuf
, inlen
);
687 sli
= strtol(dat
, &eptr
, 0);
688 if (*dat
!= '\0' && *eptr
== '\0')
701 quadify(char const *inbuf
, uiz_t inlen
, char const *prompt
, si8_t emptyrv
)
706 assert(inlen
== 0 || inbuf
!= NULL
);
708 if (inlen
== UIZ_MAX
)
709 inlen
= strlen(inbuf
);
712 rv
= (emptyrv
>= 0) ? (emptyrv
== 0 ? 0 : 1) : -1;
713 else if ((rv
= boolify(inbuf
, inlen
, -1)) < 0 &&
714 !ascncasecmp(inbuf
, "ask-", 4) &&
715 (rv
= boolify(inbuf
+ 4, inlen
- 4, -1)) >= 0 &&
716 (options
& OPT_INTERACTIVE
))
717 rv
= getapproval(prompt
, rv
);
723 n_is_all_or_aster(char const *name
){
727 rv
= ((name
[0] == '*' && name
[1] == '\0') || !asccasecmp(name
, "all"));
735 #ifdef HAVE_CLOCK_GETTIME
737 #elif defined HAVE_GETTIMEOFDAY
743 #ifdef HAVE_CLOCK_GETTIME
744 clock_gettime(CLOCK_REALTIME
, &ts
);
745 rv
= (time_t)ts
.tv_sec
;
746 #elif defined HAVE_GETTIMEOFDAY
747 gettimeofday(&ts
, NULL
);
748 rv
= (time_t)ts
.tv_sec
;
757 time_current_update(struct time_current
*tc
, bool_t full_update
)
760 tc
->tc_time
= n_time_epoch();
762 memcpy(&tc
->tc_gm
, gmtime(&tc
->tc_time
), sizeof tc
->tc_gm
);
763 memcpy(&tc
->tc_local
, localtime(&tc
->tc_time
), sizeof tc
->tc_local
);
764 sstpcpy(tc
->tc_ctime
, ctime(&tc
->tc_time
));
770 n_msleep(uiz_t millis
, bool_t ignint
){
774 #ifdef HAVE_NANOSLEEP
776 struct timespec ts
, trem
;
779 ts
.tv_sec
= millis
/ 1000;
780 ts
.tv_nsec
= (millis
%= 1000) * 1000 * 1000;
782 while((i
= nanosleep(&ts
, &trem
)) != 0 && ignint
)
784 rv
= (i
== 0) ? 0 : (trem
.tv_sec
* 1000) + (trem
.tv_nsec
/ (1000 * 1000));
787 #elif defined HAVE_SLEEP
788 if((millis
/= 1000) == 0)
790 while((rv
= sleep((unsigned int)millis
)) != 0 && ignint
)
793 # error Configuration should have detected a function for sleeping.
801 n_err(char const *format
, ...){
805 va_start(ap
, format
);
807 if(options
& OPT_INTERACTIVE
)
813 bool_t doname
, doflush
;
816 while(*format
== '\n'){
822 if((doname
= doflush
))
823 a_aux_err_linelen
= 0;
825 if((len
= strlen(format
)) > 0){
826 if(doname
|| a_aux_err_linelen
== 0)
827 fputs(UAGENT
": ", stderr
);
828 vfprintf(stderr
, format
, ap
);
833 if(format
[--len
] == '\n'){
834 a_aux_err_linelen
= (i
-= ++len
);
850 n_verr(char const *format
, va_list ap
){
851 /* Check use cases of PS_ERRORS_NOTED, too! */
853 struct a_aux_err_node
*enp
;
855 bool_t doname
, doflush
;
860 while(*format
== '\n'){
866 if((doname
= doflush
)){
867 a_aux_err_linelen
= 0;
869 if(options
& OPT_INTERACTIVE
){
870 if((enp
= a_aux_err_tail
) != NULL
&&
871 (enp
->ae_str
.s_len
> 0 &&
872 enp
->ae_str
.s_dat
[enp
->ae_str
.s_len
- 1] != '\n'))
873 n_string_push_c(&enp
->ae_str
, '\n');
878 if((len
= strlen(format
)) == 0)
881 if(doname
|| a_aux_err_linelen
== 0)
882 fputs(UAGENT
": ", stderr
);
887 if(format
[--len
] == '\n'){
888 a_aux_err_linelen
= (i
-= ++len
);
896 if(!(options
& OPT_INTERACTIVE
))
898 vfprintf(stderr
, format
, ap
);
902 LCTA(ERRORS_MAX
> 3);
904 /* Link it into the `errors' message ring */
905 if((enp
= a_aux_err_tail
) == NULL
){
907 enp
= smalloc(sizeof *enp
);
909 n_string_creat(&enp
->ae_str
);
910 if(a_aux_err_tail
!= NULL
)
911 a_aux_err_tail
->ae_next
= enp
;
913 a_aux_err_head
= enp
;
914 a_aux_err_tail
= enp
;
917 (enp
->ae_str
.s_len
> 0 &&
918 enp
->ae_str
.s_dat
[enp
->ae_str
.s_len
- 1] == '\n')){
919 if(a_aux_err_cnt
< ERRORS_MAX
)
922 a_aux_err_head
= (enp
= a_aux_err_head
)->ae_next
;
923 a_aux_err_tail
->ae_next
= enp
;
924 a_aux_err_tail
= enp
;
926 n_string_trunc(&enp
->ae_str
, 0);
934 for(i
= imax
;; imax
= ++i
/* xxx could wrap, maybe */){
942 n_string_resize(&enp
->ae_str
, (len
= enp
->ae_str
.s_len
) + (size_t)i
);
943 i
= vsnprintf(&enp
->ae_str
.s_dat
[len
], (size_t)i
, format
, vac
);
951 if(UICMP(z
, i
, >=, imax
)){
953 /* XXX Check overflow for upcoming LEN+++i! */
954 n_string_trunc(&enp
->ae_str
, len
);
957 i
= (int)strlen(&enp
->ae_str
.s_dat
[len
]);
962 n_string_trunc(&enp
->ae_str
, len
+ (size_t)i
);
964 fwrite(&enp
->ae_str
.s_dat
[len
], 1, (size_t)i
, stderr
);
966 #endif /* HAVE_ERRORS */
975 n_err_sighdl(char const *format
, ...){ /* TODO sigsafe; obsolete! */
979 va_start(ap
, format
);
980 vfprintf(stderr
, format
, ap
);
986 n_perr(char const *msg
, int errval
){
999 n_err(fmt
, msg
, strerror(errval
));
1004 n_alert(char const *format
, ...){
1008 n_err(a_aux_err_linelen
> 0 ? _("\nAlert: ") : _("Alert: "));
1010 va_start(ap
, format
);
1019 n_panic(char const *format
, ...){
1023 if(a_aux_err_linelen
> 0){
1025 a_aux_err_linelen
= 0;
1027 fprintf(stderr
, UAGENT
": Panic: ");
1029 va_start(ap
, format
);
1030 vfprintf(stderr
, format
, ap
);
1036 abort(); /* Was exit(EXIT_ERR); for a while, but no */
1043 struct a_aux_err_node
*enp
;
1050 if(!asccasecmp(*argv
, "show"))
1052 if(!asccasecmp(*argv
, "clear"))
1055 fprintf(stderr
, _("Synopsis: errors: (<show> or) <clear> the error ring\n"));
1059 return (v
== NULL
) ? !STOP
: !OKAY
; /* xxx 1:bad 0:good -- do some */
1065 if(a_aux_err_head
== NULL
){
1066 fprintf(stderr
, _("The error ring is empty\n"));
1070 if((fp
= Ftmp(NULL
, "errors", OF_RDWR
| OF_UNLINK
| OF_REGISTER
)) ==
1072 fprintf(stderr
, _("tmpfile"));
1077 for(i
= 0, enp
= a_aux_err_head
; enp
!= NULL
; enp
= enp
->ae_next
)
1078 fprintf(fp
, "%4" PRIuZ
". %u B: %s",
1079 ++i
, enp
->ae_str
.s_len
, n_string_cp(&enp
->ae_str
));
1080 /* We don't know wether last string ended with NL; be simple */
1083 page_or_print(fp
, 0);
1089 a_aux_err_tail
= NULL
;
1090 a_aux_err_cnt
= a_aux_err_cnt_noted
= 0;
1091 a_aux_err_linelen
= 0;
1092 while((enp
= a_aux_err_head
) != NULL
){
1093 a_aux_err_head
= enp
->ae_next
;
1094 n_string_gut(&enp
->ae_str
);
1099 #endif /* HAVE_ERRORS */