Isolate iconv(3) usage in a single place..
[s-mailx.git] / aux.c
blob3186898e658d1d03ab9bc82c2a2ae44f69c7af53
1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
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.
40 #ifndef lint
41 #ifdef DOSCCS
42 static char sccsid[] = "@(#)aux.c 2.83 (gritter) 3/4/06";
43 #endif
44 #endif /* not lint */
46 #include "rcv.h"
47 #include "extern.h"
48 #include <sys/stat.h>
49 #include <utime.h>
50 #include <time.h>
51 #include <termios.h>
52 #include <ctype.h>
53 #ifdef HAVE_WCTYPE_H
54 #include <wctype.h>
55 #endif /* HAVE_WCTYPE_H */
56 #ifdef HAVE_WCWIDTH
57 #include <wchar.h>
58 #endif /* HAVE_WCWIDTH */
59 #include <errno.h>
60 #include <sys/stat.h>
61 #include <unistd.h>
62 #include <time.h>
63 #include <dirent.h>
64 #include <fcntl.h>
65 #include <limits.h>
67 #include "md5.h"
70 * Mail -- a mail program
72 * Auxiliary functions.
76 * Return a pointer to a dynamic copy of the argument.
78 char *
79 savestr(const char *str)
81 char *new;
82 int size = strlen(str) + 1;
84 if ((new = salloc(size)) != NULL)
85 memcpy(new, str, size);
86 return new;
90 * Make a copy of new argument incorporating old one.
92 char *
93 save2str(const char *str, const char *old)
95 char *new;
96 int newsize = strlen(str) + 1;
97 int oldsize = old ? strlen(old) + 1 : 0;
99 if ((new = salloc(newsize + oldsize)) != NULL) {
100 if (oldsize) {
101 memcpy(new, old, oldsize);
102 new[oldsize - 1] = ' ';
104 memcpy(new + oldsize, str, newsize);
106 return new;
109 char *
110 savecat(const char *s1, const char *s2)
112 const char *cp;
113 char *ns, *np;
115 np = ns = salloc(strlen(s1) + strlen(s2) + 1);
116 for (cp = s1; *cp; cp++)
117 *np++ = *cp;
118 for (cp = s2; *cp; cp++)
119 *np++ = *cp;
120 *np = '\0';
121 return ns;
124 #include <stdarg.h>
126 #ifndef HAVE_SNPRINTF
128 * Lazy vsprintf wrapper.
131 snprintf(char *str, size_t size, const char *format, ...)
133 va_list ap;
134 int ret;
136 va_start(ap, format);
137 ret = vsprintf(str, format, ap);
138 va_end(ap);
139 return ret;
141 #endif /* !HAVE_SNPRINTF */
144 * Announce a fatal error and die.
146 void
147 panic(const char *format, ...)
149 va_list ap;
151 va_start(ap, format);
152 fprintf(stderr, catgets(catd, CATSET, 1, "panic: "));
153 vfprintf(stderr, format, ap);
154 va_end(ap);
155 fprintf(stderr, catgets(catd, CATSET, 2, "\n"));
156 fflush(stderr);
157 abort();
160 void
161 holdint(void)
163 sigset_t set;
165 sigemptyset(&set);
166 sigaddset(&set, SIGINT);
167 sigprocmask(SIG_BLOCK, &set, NULL);
170 void
171 relseint(void)
173 sigset_t set;
175 sigemptyset(&set);
176 sigaddset(&set, SIGINT);
177 sigprocmask(SIG_UNBLOCK, &set, NULL);
181 * Touch the named message by setting its MTOUCH flag.
182 * Touched messages have the effect of not being sent
183 * back to the system mailbox on exit.
185 void
186 touch(struct message *mp)
189 mp->m_flag |= MTOUCH;
190 if ((mp->m_flag & MREAD) == 0)
191 mp->m_flag |= MREAD|MSTATUS;
195 * Test to see if the passed file name is a directory.
196 * Return true if it is.
198 int
199 is_dir(char *name)
201 struct stat sbuf;
203 if (stat(name, &sbuf) < 0)
204 return(0);
205 return(S_ISDIR(sbuf.st_mode));
209 * Count the number of arguments in the given string raw list.
211 int
212 argcount(char **argv)
214 char **ap;
216 for (ap = argv; *ap++ != NULL;)
218 return ap - argv - 1;
222 * Copy a string, lowercasing it as we go.
224 void
225 i_strcpy(char *dest, const char *src, int size)
227 char *max;
229 max=dest+size-1;
230 while (dest<=max) {
231 *dest++ = lowerconv(*src & 0377);
232 if (*src++ == '\0')
233 break;
237 char *
238 i_strdup(const char *src)
240 int sz;
241 char *dest;
243 sz = strlen(src) + 1;
244 dest = salloc(sz);
245 i_strcpy(dest, src, sz);
246 return dest;
250 * Convert a string to lowercase, in-place and with multibyte-aware.
252 void
253 makelow(char *cp)
255 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
256 if (mb_cur_max > 1) {
257 char *tp = cp;
258 wchar_t wc;
259 int len;
261 while (*cp) {
262 len = mbtowc(&wc, cp, mb_cur_max);
263 if (len < 0)
264 *tp++ = *cp++;
265 else {
266 wc = towlower(wc);
267 if (wctomb(tp, wc) == len)
268 tp += len, cp += len;
269 else
270 *tp++ = *cp++;
273 } else
274 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
277 *cp = tolower(*cp & 0377);
278 while (*cp++);
282 int
283 substr(const char *str, const char *sub)
285 const char *cp, *backup;
287 cp = sub;
288 backup = str;
289 while (*str && *cp) {
290 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
291 if (mb_cur_max > 1) {
292 wchar_t c, c2;
293 int sz;
295 if ((sz = mbtowc(&c, cp, mb_cur_max)) < 0)
296 goto singlebyte;
297 cp += sz;
298 if ((sz = mbtowc(&c2, str, mb_cur_max)) < 0)
299 goto singlebyte;
300 str += sz;
301 c = towupper(c);
302 c2 = towupper(c2);
303 if (c != c2) {
304 if ((sz = mbtowc(&c, backup, mb_cur_max)) > 0) {
305 backup += sz;
306 str = backup;
307 } else
308 str = ++backup;
309 cp = sub;
311 } else
312 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
314 int c, c2;
316 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
317 singlebyte:
318 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
319 c = *cp++ & 0377;
320 if (islower(c))
321 c = toupper(c);
322 c2 = *str++ & 0377;
323 if (islower(c2))
324 c2 = toupper(c2);
325 if (c != c2) {
326 str = ++backup;
327 cp = sub;
331 return *cp == '\0';
334 char *
335 colalign(const char *cp, int col, int fill)
337 int n, sz;
338 char *nb, *np;
340 np = nb = salloc(mb_cur_max * strlen(cp) + col + 1);
341 while (*cp) {
342 #if defined (HAVE_MBTOWC) && defined (HAVE_WCWIDTH)
343 if (mb_cur_max > 1) {
344 wchar_t wc;
346 if ((sz = mbtowc(&wc, cp, mb_cur_max)) < 0) {
347 n = sz = 1;
348 } else {
349 if ((n = wcwidth(wc)) < 0)
350 n = 1;
352 } else
353 #endif /* HAVE_MBTOWC && HAVE_WCWIDTH */
355 n = sz = 1;
357 if (n > col)
358 break;
359 col -= n;
360 if (sz == 1 && spacechar(*cp&0377)) {
361 *np++ = ' ';
362 cp++;
363 } else
364 while (sz--)
365 *np++ = *cp++;
367 if (fill)
368 while (col-- > 0)
369 *np++ = ' ';
370 *np = '\0';
371 return nb;
374 void
375 try_pager(FILE *fp)
377 long lines = 0;
378 int c;
379 char *cp;
381 fflush(fp);
382 rewind(fp);
383 while ((c = getc(fp)) != EOF)
384 if (c == '\n')
385 lines++;
386 rewind(fp);
387 if (is_a_tty[0] && is_a_tty[1] && (cp = value("crt")) != NULL &&
388 lines > (*cp ? atol(cp) : scrnheight))
389 run_command(get_pager(), 0, fileno(fp), -1, NULL, NULL, NULL);
390 else
391 while ((c = getc(fp)) != EOF)
392 putchar(c);
396 * The following code deals with input stacking to do source
397 * commands. All but the current file pointer are saved on
398 * the stack.
401 static int ssp; /* Top of file stack */
402 struct sstack {
403 FILE *s_file; /* File we were in. */
404 enum condition s_cond; /* Saved state of conditionals */
405 int s_loading; /* Loading .mailrc, etc. */
406 #define SSTACK 20
407 } sstack[SSTACK];
410 * Pushdown current input file and switch to a new one.
411 * Set the global flag "sourcing" so that others will realize
412 * that they are no longer reading from a tty (in all probability).
414 int
415 source(void *v)
417 char **arglist = v;
418 FILE *fi;
419 char *cp;
421 if ((cp = expand(*arglist)) == NULL)
422 return(1);
423 if ((fi = Fopen(cp, "r")) == NULL) {
424 perror(cp);
425 return(1);
427 if (ssp >= SSTACK - 1) {
428 printf(catgets(catd, CATSET, 3,
429 "Too much \"sourcing\" going on.\n"));
430 Fclose(fi);
431 return(1);
433 sstack[ssp].s_file = input;
434 sstack[ssp].s_cond = cond;
435 sstack[ssp].s_loading = loading;
436 ssp++;
437 loading = 0;
438 cond = CANY;
439 input = fi;
440 sourcing++;
441 return(0);
445 * Pop the current input back to the previous level.
446 * Update the "sourcing" flag as appropriate.
448 int
449 unstack(void)
451 if (ssp <= 0) {
452 printf(catgets(catd, CATSET, 4,
453 "\"Source\" stack over-pop.\n"));
454 sourcing = 0;
455 return(1);
457 Fclose(input);
458 if (cond != CANY)
459 printf(catgets(catd, CATSET, 5, "Unmatched \"if\"\n"));
460 ssp--;
461 cond = sstack[ssp].s_cond;
462 loading = sstack[ssp].s_loading;
463 input = sstack[ssp].s_file;
464 if (ssp == 0)
465 sourcing = loading;
466 return(0);
470 * Touch the indicated file.
471 * This is nifty for the shell.
473 void
474 alter(char *name)
476 struct stat sb;
477 struct utimbuf utb;
479 if (stat(name, &sb))
480 return;
481 utb.actime = time((time_t *)0) + 1;
482 utb.modtime = sb.st_mtime;
483 utime(name, &utb);
487 * Examine the passed line buffer and
488 * return true if it is all blanks and tabs.
490 int
491 blankline(char *linebuf)
493 char *cp;
495 for (cp = linebuf; *cp; cp++)
496 if (!blankchar(*cp & 0377))
497 return(0);
498 return(1);
502 * Are any of the characters in the two strings the same?
504 int
505 anyof(char *s1, char *s2)
508 while (*s1)
509 if (strchr(s2, *s1++))
510 return 1;
511 return 0;
515 * Determine if as1 is a valid prefix of as2.
516 * Return true if yep.
518 int
519 is_prefix(const char *as1, const char *as2)
521 const char *s1, *s2;
523 s1 = as1;
524 s2 = as2;
525 while (*s1++ == *s2)
526 if (*s2++ == '\0')
527 return(1);
528 return(*--s1 == '\0');
531 char *
532 last_at_before_slash(const char *sp)
534 const char *cp;
536 for (cp = sp; *cp; cp++)
537 if (*cp == '/')
538 break;
539 while (cp > sp && *--cp != '@');
540 return *cp == '@' ? (char *)cp : NULL;
543 enum protocol
544 which_protocol(const char *name)
546 register const char *cp;
547 char *np;
548 size_t sz;
549 struct stat st;
550 enum protocol p;
552 if (name[0] == '%' && name[1] == ':')
553 name += 2;
554 for (cp = name; *cp && *cp != ':'; cp++)
555 if (!alnumchar(*cp&0377))
556 goto file;
557 if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
558 if (strncmp(name, "pop3://", 7) == 0)
559 #ifdef USE_POP3
560 return PROTO_POP3;
561 #else
562 fprintf(stderr, catgets(catd, CATSET, 216,
563 "No POP3 support compiled in.\n"));
564 #endif
565 if (strncmp(name, "pop3s://", 8) == 0)
566 #ifdef USE_SSL
567 return PROTO_POP3;
568 #else /* !USE_SSL */
569 fprintf(stderr, catgets(catd, CATSET, 225,
570 "No SSL support compiled in.\n"));
571 #endif /* !USE_SSL */
572 if (strncmp(name, "imap://", 7) == 0)
573 #ifdef USE_IMAP
574 return PROTO_IMAP;
575 #else
576 fprintf(stderr, catgets(catd, CATSET, 269,
577 "No IMAP support compiled in.\n"));
578 #endif
579 if (strncmp(name, "imaps://", 8) == 0)
580 #ifdef USE_SSL
581 return PROTO_IMAP;
582 #else /* !USE_SSL */
583 fprintf(stderr, catgets(catd, CATSET, 225,
584 "No SSL support compiled in.\n"));
585 #endif /* !USE_SSL */
586 return PROTO_UNKNOWN;
587 } else {
588 file: p = PROTO_FILE;
589 np = ac_alloc((sz = strlen(name)) + 5);
590 strcpy(np, name);
591 if (stat(name, &st) == 0) {
592 if (S_ISDIR(st.st_mode)) {
593 strcpy(&np[sz], "/tmp");
594 if (stat(np, &st) == 0 && S_ISDIR(st.st_mode)) {
595 strcpy(&np[sz], "/new");
596 if (stat(np, &st) == 0 &&
597 S_ISDIR(st.st_mode)) {
598 strcpy(&np[sz], "/cur");
599 if (stat(np, &st) == 0 &&
600 S_ISDIR(st.st_mode))
601 p = PROTO_MAILDIR;
605 } else {
606 strcpy(&np[sz], ".gz");
607 if (stat(np, &st) < 0) {
608 strcpy(&np[sz], ".bz2");
609 if (stat(np, &st) < 0) {
610 if ((cp = value("newfolders")) != 0 &&
611 strcmp(cp, "maildir") == 0)
612 p = PROTO_MAILDIR;
616 ac_free(np);
617 return p;
621 const char *
622 protfile(const char *xcp)
624 const char *cp = xcp;
625 int state = 0;
627 while (*cp) {
628 if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
629 cp += 3;
630 state = 1;
632 if (cp[0] == '/' && state == 1)
633 return &cp[1];
634 if (cp[0] == '/')
635 return xcp;
636 cp++;
638 return cp;
641 char *
642 protbase(const char *cp)
644 char *n = salloc(strlen(cp) + 1);
645 char *np = n;
647 while (*cp) {
648 if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
649 *np++ = *cp++;
650 *np++ = *cp++;
651 *np++ = *cp++;
652 } else if (cp[0] == '/')
653 break;
654 else
655 *np++ = *cp++;
657 *np = '\0';
658 return n;
661 int
662 disconnected(const char *file)
664 char *cp, *cq, *vp;
665 int vs, r;
667 if (value("disconnected"))
668 return 1;
669 cp = protbase(file);
670 if (strncmp(cp, "imap://", 7) == 0)
671 cp += 7;
672 else if (strncmp(cp, "imaps://", 8) == 0)
673 cp += 8;
674 else
675 return 0;
676 if ((cq = strchr(cp, ':')) != NULL)
677 *cq = '\0';
678 vp = ac_alloc(vs = strlen(cp) + 14);
679 snprintf(vp, vs, "disconnected-%s", cp);
680 r = value(vp) != NULL;
681 ac_free(vp);
682 return r;
685 unsigned
686 pjw(const char *cp)
688 unsigned h = 0, g;
690 cp--;
691 while (*++cp) {
692 h = (h << 4 & 0xffffffff) + (*cp&0377);
693 if ((g = h & 0xf0000000) != 0) {
694 h = h ^ g >> 24;
695 h = h ^ g;
698 return h;
701 long
702 nextprime(long n)
704 const long primes[] = {
705 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521,
706 131071, 262139, 524287, 1048573, 2097143, 4194301,
707 8388593, 16777213, 33554393, 67108859, 134217689,
708 268435399, 536870909, 1073741789, 2147483647
710 long mprime = 7;
711 size_t i;
713 for (i = 0; i < sizeof primes / sizeof *primes; i++)
714 if ((mprime = primes[i]) >= (n < 65536 ? n*4 :
715 n < 262144 ? n*2 : n))
716 break;
717 if (i == sizeof primes / sizeof *primes)
718 mprime = n; /* not so prime, but better than failure */
719 return mprime;
722 #define Hexchar(n) ((n)>9 ? (n)-10+'A' : (n)+'0')
723 #define hexchar(n) ((n)>9 ? (n)-10+'a' : (n)+'0')
725 char *
726 strenc(const char *cp)
728 char *n, *np;
730 np = n = salloc(strlen(cp) * 3 + 1);
731 while (*cp) {
732 if (alnumchar(*cp&0377) || *cp == '_' || *cp == '@' ||
733 (np > n && (*cp == '.' || *cp == '-' ||
734 *cp == ':')))
735 *np++ = *cp;
736 else {
737 *np++ = '%';
738 *np++ = Hexchar((*cp&0xf0) >> 4);
739 *np++ = Hexchar(*cp&0x0f);
741 cp++;
743 *np = '\0';
744 return n;
747 char *
748 strdec(const char *cp)
750 char *n, *np;
752 np = n = salloc(strlen(cp) + 1);
753 while (*cp) {
754 if (cp[0] == '%' && cp[1] && cp[2]) {
755 *np = (int)(cp[1]>'9'?cp[1]-'A'+10:cp[1]-'0') << 4;
756 *np++ |= cp[2]>'9'?cp[2]-'A'+10:cp[2]-'0';
757 cp += 3;
758 } else
759 *np++ = *cp++;
761 *np = '\0';
762 return n;
765 char *
766 md5tohex(const void *vp)
768 char *hex;
769 const char *cp = vp;
770 int i;
772 hex = salloc(33);
773 for (i = 0; i < 16; i++) {
774 hex[2*i] = hexchar((cp[i]&0xf0) >> 4);
775 hex[2*i+1] = hexchar(cp[i]&0x0f);
777 hex[32] = '\0';
778 return hex;
781 char *
782 cram_md5_string(const char *user, const char *pass, const char *b64)
784 struct str in, out;
785 char digest[16], *cp, *sp, *rp, *xp;
786 int ss, rs;
788 in.s = (char *)b64;
789 in.l = strlen(in.s);
790 mime_fromb64(&in, &out, 0);
791 hmac_md5((unsigned char *)out.s, out.l,
792 (unsigned char *)pass, strlen(pass),
793 digest);
794 free(out.s);
795 xp = md5tohex(digest);
796 sp = ac_alloc(ss = strlen(user) + strlen(xp) + 2);
797 snprintf(sp, ss, "%s %s", user, xp);
798 cp = strtob64(sp);
799 ac_free(sp);
800 rp = salloc(rs = strlen(cp) + 3);
801 snprintf(rp, rs, "%s\r\n", cp);
802 free(cp);
803 return rp;
806 char *
807 getuser(void)
809 char *line = NULL, *user;
810 size_t linesize = 0;
812 if (is_a_tty[0]) {
813 fputs("User: ", stdout);
814 fflush(stdout);
816 if (readline(stdin, &line, &linesize) == 0) {
817 if (line)
818 free(line);
819 return NULL;
821 user = savestr(line);
822 free(line);
823 return user;
826 char *
827 getpassword(struct termios *otio, int *reset_tio, const char *query)
829 struct termios tio;
830 char *line = NULL, *pass;
831 size_t linesize = 0;
832 int i;
834 if (is_a_tty[0]) {
835 fputs(query ? query : "Password:", stdout);
836 fflush(stdout);
837 tcgetattr(0, &tio);
838 *otio = tio;
839 tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
840 *reset_tio = 1;
841 tcsetattr(0, TCSAFLUSH, &tio);
843 i = readline(stdin, &line, &linesize);
844 if (is_a_tty[0]) {
845 fputc('\n', stdout);
846 tcsetattr(0, TCSADRAIN, otio);
848 *reset_tio = 0;
849 if (i < 0) {
850 if (line)
851 free(line);
852 return NULL;
854 pass = savestr(line);
855 free(line);
856 return pass;
859 void
860 transflags(struct message *omessage, long omsgCount, int transparent)
862 struct message *omp, *nmp, *newdot, *newprevdot;
863 int hf;
865 omp = omessage;
866 nmp = message;
867 newdot = message;
868 newprevdot = NULL;
869 while (omp < &omessage[omsgCount] &&
870 nmp < &message[msgCount]) {
871 if (dot && nmp->m_uid == dot->m_uid)
872 newdot = nmp;
873 if (prevdot && nmp->m_uid == prevdot->m_uid)
874 newprevdot = nmp;
875 if (omp->m_uid == nmp->m_uid) {
876 hf = nmp->m_flag & MHIDDEN;
877 if (transparent && mb.mb_type == MB_IMAP)
878 omp->m_flag &= ~MHIDDEN;
879 *nmp++ = *omp++;
880 if (transparent && mb.mb_type == MB_CACHE)
881 nmp[-1].m_flag |= hf;
882 } else if (omp->m_uid < nmp->m_uid)
883 omp++;
884 else
885 nmp++;
887 dot = newdot;
888 setdot(newdot);
889 prevdot = newprevdot;
890 free(omessage);
893 char *
894 getrandstring(size_t length)
896 static unsigned char nodedigest[16];
897 static pid_t pid;
898 int fd = -1;
899 char *data;
900 char *cp, *rp;
901 size_t i;
902 MD5_CTX ctx;
904 data = salloc(length);
905 if ((fd = open("/dev/urandom", O_RDONLY)) < 0 ||
906 length != (size_t)read(fd, data, length)) {
907 if (pid == 0) {
908 pid = getpid();
909 srand(pid);
910 cp = nodename(0);
911 MD5Init(&ctx);
912 MD5Update(&ctx, (unsigned char *)cp, strlen(cp));
913 MD5Final(nodedigest, &ctx);
915 for (i = 0; i < length; i++)
916 data[i] = (char)
917 ((int)(255 * (rand() / (RAND_MAX + 1.0))) ^
918 nodedigest[i % sizeof nodedigest]);
920 if (fd > 0)
921 close(fd);
922 cp = memtob64(data, length);
923 rp = salloc(length+1);
924 strncpy(rp, cp, length)[length] = '\0';
925 free(cp);
926 return rp;
929 void
930 out_of_memory(void)
932 panic("no memory");
935 void *
936 smalloc(size_t s)
938 void *p;
940 if (s == 0)
941 s = 1;
942 if ((p = malloc(s)) == NULL)
943 out_of_memory();
944 return p;
947 void *
948 srealloc(void *v, size_t s)
950 void *r;
952 if (s == 0)
953 s = 1;
954 if (v == NULL)
955 return smalloc(s);
956 if ((r = realloc(v, s)) == NULL)
957 out_of_memory();
958 return r;
961 void *
962 scalloc(size_t nmemb, size_t size)
964 void *vp;
966 if (size == 0)
967 size = 1;
968 if ((vp = calloc(nmemb, size)) == NULL)
969 out_of_memory();
970 return vp;
973 char *
974 sstpcpy(char *dst, const char *src)
976 while ((*dst = *src++) != '\0')
977 dst++;
978 return dst;
981 char *
982 sstrdup(const char *cp)
984 char *dp;
986 if (cp) {
987 dp = smalloc(strlen(cp) + 1);
988 strcpy(dp, cp);
989 return dp;
990 } else
991 return NULL;
994 enum okay
995 makedir(const char *name)
997 int e;
998 struct stat st;
1000 if (mkdir(name, 0700) < 0) {
1001 e = errno;
1002 if ((e == EEXIST || e == ENOSYS) &&
1003 stat(name, &st) == 0 &&
1004 (st.st_mode&S_IFMT) == S_IFDIR)
1005 return OKAY;
1006 return STOP;
1008 return OKAY;
1011 #ifdef HAVE_FCHDIR
1012 enum okay
1013 cwget(struct cw *cw)
1015 if ((cw->cw_fd = open(".", O_RDONLY)) < 0)
1016 return STOP;
1017 if (fchdir(cw->cw_fd) < 0) {
1018 close(cw->cw_fd);
1019 return STOP;
1021 return OKAY;
1024 enum okay
1025 cwret(struct cw *cw)
1027 if (fchdir(cw->cw_fd) < 0)
1028 return STOP;
1029 return OKAY;
1032 void
1033 cwrelse(struct cw *cw)
1035 close(cw->cw_fd);
1037 #else /* !HAVE_FCHDIR */
1038 enum okay
1039 cwget(struct cw *cw)
1041 if (getcwd(cw->cw_wd, sizeof cw->cw_wd) == NULL || chdir(cw->cw_wd) < 0)
1042 return STOP;
1043 return OKAY;
1046 enum okay
1047 cwret(struct cw *cw)
1049 if (chdir(cw->cw_wd) < 0)
1050 return STOP;
1051 return OKAY;
1054 /*ARGSUSED*/
1055 void
1056 cwrelse(struct cw *cw)
1059 #endif /* !HAVE_FCHDIR */
1061 void
1062 makeprint(struct str *in, struct str *out)
1064 static int print_all_chars = -1;
1065 char *inp, *outp;
1066 size_t msz, dist;
1068 out->s = smalloc(msz = in->l + 1);
1069 if (print_all_chars == -1)
1070 print_all_chars = value("print-all-chars") != NULL;
1071 if (print_all_chars) {
1072 memcpy(out->s, in->s, in->l);
1073 out->l = in->l;
1074 out->s[out->l] = '\0';
1075 return;
1077 inp = in->s;
1078 outp = out->s;
1079 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
1080 if (mb_cur_max > 1) {
1081 wchar_t wc;
1082 char mb[MB_LEN_MAX+1];
1083 int i, n;
1084 out->l = 0;
1085 while (inp < &in->s[in->l]) {
1086 if (*inp & 0200)
1087 n = mbtowc(&wc, inp, &in->s[in->l] - inp);
1088 else {
1089 wc = *inp;
1090 n = 1;
1092 if (n < 0) {
1093 mbtowc(&wc, NULL, mb_cur_max);
1094 wc = utf8 ? 0xFFFD : '?';
1095 n = 1;
1096 } else if (n == 0)
1097 n = 1;
1098 inp += n;
1099 if (!iswprint(wc) && wc != '\n' && wc != '\r' &&
1100 wc != '\b' && wc != '\t') {
1101 if ((wc & ~(wchar_t)037) == 0)
1102 wc = utf8 ? 0x2400 | wc : '?';
1103 else if (wc == 0177)
1104 wc = utf8 ? 0x2421 : '?';
1105 else
1106 wc = utf8 ? 0x2426 : '?';
1108 if ((n = wctomb(mb, wc)) <= 0)
1109 continue;
1110 out->l += n;
1111 if (out->l >= msz - 1) {
1112 dist = outp - out->s;
1113 out->s = srealloc(out->s, msz += 32);
1114 outp = &out->s[dist];
1116 for (i = 0; i < n; i++)
1117 *outp++ = mb[i];
1119 } else
1120 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
1122 int c;
1123 while (inp < &in->s[in->l]) {
1124 c = *inp++ & 0377;
1125 if (!isprint(c) && c != '\n' && c != '\r' &&
1126 c != '\b' && c != '\t')
1127 c = '?';
1128 *outp++ = c;
1130 out->l = in->l;
1132 out->s[out->l] = '\0';
1135 char *
1136 prstr(const char *s)
1138 struct str in, out;
1139 char *rp;
1141 in.s = (char *)s;
1142 in.l = strlen(s);
1143 makeprint(&in, &out);
1144 rp = salloc(out.l + 1);
1145 memcpy(rp, out.s, out.l);
1146 rp[out.l] = '\0';
1147 free(out.s);
1148 return rp;
1152 prout(const char *s, size_t sz, FILE *fp)
1154 struct str in, out;
1155 int n;
1157 in.s = (char *)s;
1158 in.l = sz;
1159 makeprint(&in, &out);
1160 n = fwrite(out.s, 1, out.l, fp);
1161 free(out.s);
1162 return n;
1166 * Print out a Unicode character or a substitute for it.
1169 putuc(int u, int c, FILE *fp)
1171 #if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
1172 if (utf8 && u & ~(wchar_t)0177) {
1173 char mb[MB_LEN_MAX];
1174 int i, n, r = 0;
1175 if ((n = wctomb(mb, u)) > 0) {
1176 for (i = 0; i < n; i++)
1177 r += putc(mb[i] & 0377, fp) != EOF;
1178 return r;
1179 } else if (n == 0)
1180 return putc('\0', fp) != EOF;
1181 else
1182 return 0;
1183 } else
1184 #endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
1185 return putc(c, fp) != EOF;
1189 * Locale-independent character class functions.
1191 int
1192 asccasecmp(const char *s1, const char *s2)
1194 register int cmp;
1197 if ((cmp = lowerconv(*s1 & 0377) - lowerconv(*s2 & 0377)) != 0)
1198 return cmp;
1199 while (*s1++ != '\0' && *s2++ != '\0');
1200 return 0;
1204 ascncasecmp(const char *s1, const char *s2, size_t sz)
1206 register int cmp;
1207 size_t i = 1;
1209 if (sz == 0)
1210 return 0;
1212 if ((cmp = lowerconv(*s1 & 0377) - lowerconv(*s2 & 0377)) != 0)
1213 return cmp;
1214 while (i++ < sz && *s1++ != '\0' && *s2++ != '\0');
1215 return 0;
1218 char *
1219 asccasestr(const char *haystack, const char *xneedle)
1221 char *needle, *NEEDLE;
1222 int i, sz;
1224 sz = strlen(xneedle);
1225 if (sz == 0)
1226 return (char *)haystack;
1227 needle = ac_alloc(sz);
1228 NEEDLE = ac_alloc(sz);
1229 for (i = 0; i < sz; i++) {
1230 needle[i] = lowerconv(xneedle[i]&0377);
1231 NEEDLE[i] = upperconv(xneedle[i]&0377);
1233 while (*haystack) {
1234 if (*haystack == *needle || *haystack == *NEEDLE) {
1235 for (i = 1; i < sz; i++)
1236 if (haystack[i] != needle[i] &&
1237 haystack[i] != NEEDLE[i])
1238 break;
1239 if (i == sz)
1240 return (char *)haystack;
1242 haystack++;
1244 return NULL;
1247 const unsigned char class_char[] = {
1248 /* 000 nul 001 soh 002 stx 003 etx 004 eot 005 enq 006 ack 007 bel */
1249 C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
1250 /* 010 bs 011 ht 012 nl 013 vt 014 np 015 cr 016 so 017 si */
1251 C_CNTRL,C_BLANK,C_WHITE,C_SPACE,C_SPACE,C_SPACE,C_CNTRL,C_CNTRL,
1252 /* 020 dle 021 dc1 022 dc2 023 dc3 024 dc4 025 nak 026 syn 027 etb */
1253 C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
1254 /* 030 can 031 em 032 sub 033 esc 034 fs 035 gs 036 rs 037 us */
1255 C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
1256 /* 040 sp 041 ! 042 " 043 # 044 $ 045 % 046 & 047 ' */
1257 C_BLANK,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
1258 /* 050 ( 051 ) 052 * 053 + 054 , 055 - 056 . 057 / */
1259 C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
1260 /* 060 0 061 1 062 2 063 3 064 4 065 5 066 6 067 7 */
1261 C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,
1262 /* 070 8 071 9 072 : 073 ; 074 < 075 = 076 > 077 ? */
1263 C_DIGIT,C_DIGIT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
1264 /* 100 @ 101 A 102 B 103 C 104 D 105 E 106 F 107 G */
1265 C_PUNCT,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
1266 /* 110 H 111 I 112 J 113 K 114 L 115 M 116 N 117 O */
1267 C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
1268 /* 120 P 121 Q 122 R 123 S 124 T 125 U 126 V 127 W */
1269 C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
1270 /* 130 X 131 Y 132 Z 133 [ 134 \ 135 ] 136 ^ 137 _ */
1271 C_UPPER,C_UPPER,C_UPPER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
1272 /* 140 ` 141 a 142 b 143 c 144 d 145 e 146 f 147 g */
1273 C_PUNCT,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
1274 /* 150 h 151 i 152 j 153 k 154 l 155 m 156 n 157 o */
1275 C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
1276 /* 160 p 161 q 162 r 163 s 164 t 165 u 166 v 167 w */
1277 C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
1278 /* 170 x 171 y 172 z 173 { 174 | 175 } 176 ~ 177 del */
1279 C_LOWER,C_LOWER,C_LOWER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_CNTRL