/*
* Heirloom mailx - a mail user agent derived from Berkeley Mail.
*
* Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
*/
/*
* Copyright (c) 1980, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
#ifdef DOSCCS
static char sccsid[] = "@(#)aux.c 2.83 (gritter) 3/4/06";
#endif
#endif /* not lint */
#include "rcv.h"
#include "extern.h"
#include <sys/stat.h>
#include <utime.h>
#include <time.h>
#include <termios.h>
#include <ctype.h>
#ifdef HAVE_WCTYPE_H
#include <wctype.h>
#endif /* HAVE_WCTYPE_H */
#ifdef HAVE_WCWIDTH
#include <wchar.h>
#endif /* HAVE_WCWIDTH */
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <dirent.h>
#include <fcntl.h>
#include <limits.h>
#include "md5.h"
/*
* Mail -- a mail program
*
* Auxiliary functions.
*/
/*
* Return a pointer to a dynamic copy of the argument.
*/
char *
savestr(const char *str)
{
char *new;
int size = strlen(str) + 1;
if ((new = salloc(size)) != NULL)
memcpy(new, str, size);
return new;
}
/*
* Make a copy of new argument incorporating old one.
*/
char *
save2str(const char *str, const char *old)
{
char *new;
int newsize = strlen(str) + 1;
int oldsize = old ? strlen(old) + 1 : 0;
if ((new = salloc(newsize + oldsize)) != NULL) {
if (oldsize) {
memcpy(new, old, oldsize);
new[oldsize - 1] = ' ';
}
memcpy(new + oldsize, str, newsize);
}
return new;
}
char *
savecat(const char *s1, const char *s2)
{
const char *cp;
char *ns, *np;
np = ns = salloc(strlen(s1) + strlen(s2) + 1);
for (cp = s1; *cp; cp++)
*np++ = *cp;
for (cp = s2; *cp; cp++)
*np++ = *cp;
*np = '\0';
return ns;
}
#include <stdarg.h>
#ifndef HAVE_SNPRINTF
/*
* Lazy vsprintf wrapper.
*/
int
snprintf(char *str, size_t size, const char *format, ...)
{
va_list ap;
int ret;
va_start(ap, format);
ret = vsprintf(str, format, ap);
va_end(ap);
return ret;
}
#endif /* !HAVE_SNPRINTF */
/*
* Announce a fatal error and die.
*/
void
panic(const char *format, ...)
{
va_list ap;
va_start(ap, format);
fprintf(stderr, catgets(catd, CATSET, 1, "panic: "));
vfprintf(stderr, format, ap);
va_end(ap);
fprintf(stderr, catgets(catd, CATSET, 2, "\n"));
fflush(stderr);
abort();
}
void
holdint(void)
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigprocmask(SIG_BLOCK, &set, NULL);
}
void
relseint(void)
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigprocmask(SIG_UNBLOCK, &set, NULL);
}
/*
* Touch the named message by setting its MTOUCH flag.
* Touched messages have the effect of not being sent
* back to the system mailbox on exit.
*/
void
touch(struct message *mp)
{
mp->m_flag |= MTOUCH;
if ((mp->m_flag & MREAD) == 0)
mp->m_flag |= MREAD|MSTATUS;
}
/*
* Test to see if the passed file name is a directory.
* Return true if it is.
*/
int
is_dir(char *name)
{
struct stat sbuf;
if (stat(name, &sbuf) < 0)
return(0);
return(S_ISDIR(sbuf.st_mode));
}
/*
* Count the number of arguments in the given string raw list.
*/
int
argcount(char **argv)
{
char **ap;
for (ap = argv; *ap++ != NULL;)
;
return ap - argv - 1;
}
/*
* Copy a string, lowercasing it as we go.
*/
void
i_strcpy(char *dest, const char *src, int size)
{
char *max;
max=dest+size-1;
while (dest<=max) {
*dest++ = lowerconv(*src & 0377);
if (*src++ == '\0')
break;
}
}
char *
i_strdup(const char *src)
{
int sz;
char *dest;
sz = strlen(src) + 1;
dest = salloc(sz);
i_strcpy(dest, src, sz);
return dest;
}
/*
* Convert a string to lowercase, in-place and with multibyte-aware.
*/
void
makelow(char *cp)
{
#if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
if (mb_cur_max > 1) {
char *tp = cp;
wchar_t wc;
int len;
while (*cp) {
len = mbtowc(&wc, cp, mb_cur_max);
if (len < 0)
*tp++ = *cp++;
else {
wc = towlower(wc);
if (wctomb(tp, wc) == len)
tp += len, cp += len;
else
*tp++ = *cp++;
}
}
} else
#endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
{
do
*cp = tolower(*cp & 0377);
while (*cp++);
}
}
int
substr(const char *str, const char *sub)
{
const char *cp, *backup;
cp = sub;
backup = str;
while (*str && *cp) {
#if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
if (mb_cur_max > 1) {
wchar_t c, c2;
int sz;
if ((sz = mbtowc(&c, cp, mb_cur_max)) < 0)
goto singlebyte;
cp += sz;
if ((sz = mbtowc(&c2, str, mb_cur_max)) < 0)
goto singlebyte;
str += sz;
c = towupper(c);
c2 = towupper(c2);
if (c != c2) {
if ((sz = mbtowc(&c, backup, mb_cur_max)) > 0) {
backup += sz;
str = backup;
} else
str = ++backup;
cp = sub;
}
} else
#endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
{
int c, c2;
#if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
singlebyte:
#endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
c = *cp++ & 0377;
if (islower(c))
c = toupper(c);
c2 = *str++ & 0377;
if (islower(c2))
c2 = toupper(c2);
if (c != c2) {
str = ++backup;
cp = sub;
}
}
}
return *cp == '\0';
}
char *
colalign(const char *cp, int col, int fill)
{
int n, sz;
char *nb, *np;
np = nb = salloc(mb_cur_max * strlen(cp) + col + 1);
while (*cp) {
#if defined (HAVE_MBTOWC) && defined (HAVE_WCWIDTH)
if (mb_cur_max > 1) {
wchar_t wc;
if ((sz = mbtowc(&wc, cp, mb_cur_max)) < 0) {
n = sz = 1;
} else {
if ((n = wcwidth(wc)) < 0)
n = 1;
}
} else
#endif /* HAVE_MBTOWC && HAVE_WCWIDTH */
{
n = sz = 1;
}
if (n > col)
break;
col -= n;
if (sz == 1 && spacechar(*cp&0377)) {
*np++ = ' ';
cp++;
} else
while (sz--)
*np++ = *cp++;
}
if (fill)
while (col-- > 0)
*np++ = ' ';
*np = '\0';
return nb;
}
void
try_pager(FILE *fp)
{
long lines = 0;
int c;
char *cp;
fflush(fp);
rewind(fp);
while ((c = getc(fp)) != EOF)
if (c == '\n')
lines++;
rewind(fp);
if (is_a_tty[0] && is_a_tty[1] && (cp = value("crt")) != NULL &&
lines > (*cp ? atol(cp) : scrnheight))
run_command(get_pager(), 0, fileno(fp), -1, NULL, NULL, NULL);
else
while ((c = getc(fp)) != EOF)
putchar(c);
}
/*
* The following code deals with input stacking to do source
* commands. All but the current file pointer are saved on
* the stack.
*/
static int ssp; /* Top of file stack */
struct sstack {
FILE *s_file; /* File we were in. */
enum condition s_cond; /* Saved state of conditionals */
int s_loading; /* Loading .mailrc, etc. */
#define SSTACK 20
} sstack[SSTACK];
/*
* Pushdown current input file and switch to a new one.
* Set the global flag "sourcing" so that others will realize
* that they are no longer reading from a tty (in all probability).
*/
int
source(void *v)
{
char **arglist = v;
FILE *fi;
char *cp;
if ((cp = expand(*arglist)) == NULL)
return(1);
if ((fi = Fopen(cp, "r")) == NULL) {
perror(cp);
return(1);
}
if (ssp >= SSTACK - 1) {
printf(catgets(catd, CATSET, 3,
"Too much \"sourcing\" going on.\n"));
Fclose(fi);
return(1);
}
sstack[ssp].s_file = input;
sstack[ssp].s_cond = cond;
sstack[ssp].s_loading = loading;
ssp++;
loading = 0;
cond = CANY;
input = fi;
sourcing++;
return(0);
}
/*
* Pop the current input back to the previous level.
* Update the "sourcing" flag as appropriate.
*/
int
unstack(void)
{
if (ssp <= 0) {
printf(catgets(catd, CATSET, 4,
"\"Source\" stack over-pop.\n"));
sourcing = 0;
return(1);
}
Fclose(input);
if (cond != CANY)
printf(catgets(catd, CATSET, 5, "Unmatched \"if\"\n"));
ssp--;
cond = sstack[ssp].s_cond;
loading = sstack[ssp].s_loading;
input = sstack[ssp].s_file;
if (ssp == 0)
sourcing = loading;
return(0);
}
/*
* Touch the indicated file.
* This is nifty for the shell.
*/
void
alter(char *name)
{
struct stat sb;
struct utimbuf utb;
if (stat(name, &sb))
return;
utb.actime = time((time_t *)0) + 1;
utb.modtime = sb.st_mtime;
utime(name, &utb);
}
/*
* Examine the passed line buffer and
* return true if it is all blanks and tabs.
*/
int
blankline(char *linebuf)
{
char *cp;
for (cp = linebuf; *cp; cp++)
if (!blankchar(*cp & 0377))
return(0);
return(1);
}
/*
* Are any of the characters in the two strings the same?
*/
int
anyof(char *s1, char *s2)
{
while (*s1)
if (strchr(s2, *s1++))
return 1;
return 0;
}
/*
* Determine if as1 is a valid prefix of as2.
* Return true if yep.
*/
int
is_prefix(const char *as1, const char *as2)
{
const char *s1, *s2;
s1 = as1;
s2 = as2;
while (*s1++ == *s2)
if (*s2++ == '\0')
return(1);
return(*--s1 == '\0');
}
char *
last_at_before_slash(const char *sp)
{
const char *cp;
for (cp = sp; *cp; cp++)
if (*cp == '/')
break;
while (cp > sp && *--cp != '@');
return *cp == '@' ? (char *)cp : NULL;
}
enum protocol
which_protocol(const char *name)
{
register const char *cp;
char *np;
size_t sz;
struct stat st;
enum protocol p;
if (name[0] == '%' && name[1] == ':')
name += 2;
for (cp = name; *cp && *cp != ':'; cp++)
if (!alnumchar(*cp&0377))
goto file;
if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
if (strncmp(name, "pop3://", 7) == 0)
return PROTO_POP3;
if (strncmp(name, "pop3s://", 8) == 0)
#ifdef USE_SSL
return PROTO_POP3;
#else /* !USE_SSL */
fprintf(stderr, catgets(catd, CATSET, 225,
"No SSL support compiled in.\n"));
#endif /* !USE_SSL */
if (strncmp(name, "imap://", 7) == 0)
return PROTO_IMAP;
if (strncmp(name, "imaps://", 8) == 0)
#ifdef USE_SSL
return PROTO_IMAP;
#else /* !USE_SSL */
fprintf(stderr, catgets(catd, CATSET, 225,
"No SSL support compiled in.\n"));
#endif /* !USE_SSL */
return PROTO_UNKNOWN;
} else {
file: p = PROTO_FILE;
np = ac_alloc((sz = strlen(name)) + 5);
strcpy(np, name);
if (stat(name, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
strcpy(&np[sz], "/tmp");
if (stat(np, &st) == 0 && S_ISDIR(st.st_mode)) {
strcpy(&np[sz], "/new");
if (stat(np, &st) == 0 &&
S_ISDIR(st.st_mode)) {
strcpy(&np[sz], "/cur");
if (stat(np, &st) == 0 &&
S_ISDIR(st.st_mode))
p = PROTO_MAILDIR;
}
}
}
} else {
strcpy(&np[sz], ".gz");
if (stat(np, &st) < 0) {
strcpy(&np[sz], ".bz2");
if (stat(np, &st) < 0) {
if ((cp = value("newfolders")) != 0 &&
strcmp(cp, "maildir") == 0)
p = PROTO_MAILDIR;
}
}
}
ac_free(np);
return p;
}
}
const char *
protfile(const char *xcp)
{
const char *cp = xcp;
int state = 0;
while (*cp) {
if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
cp += 3;
state = 1;
}
if (cp[0] == '/' && state == 1)
return &cp[1];
if (cp[0] == '/')
return xcp;
cp++;
}
return cp;
}
char *
protbase(const char *cp)
{
char *n = salloc(strlen(cp) + 1);
char *np = n;
while (*cp) {
if (cp[0] == ':' && cp[1] == '/' && cp[2] == '/') {
*np++ = *cp++;
*np++ = *cp++;
*np++ = *cp++;
} else if (cp[0] == '/')
break;
else
*np++ = *cp++;
}
*np = '\0';
return n;
}
int
disconnected(const char *file)
{
char *cp, *cq, *vp;
int vs, r;
if (value("disconnected"))
return 1;
cp = protbase(file);
if (strncmp(cp, "imap://", 7) == 0)
cp += 7;
else if (strncmp(cp, "imaps://", 8) == 0)
cp += 8;
else
return 0;
if ((cq = strchr(cp, ':')) != NULL)
*cq = '\0';
vp = ac_alloc(vs = strlen(cp) + 14);
snprintf(vp, vs, "disconnected-%s", cp);
r = value(vp) != NULL;
ac_free(vp);
return r;
}
unsigned
pjw(const char *cp)
{
unsigned h = 0, g;
cp--;
while (*++cp) {
h = (h << 4 & 0xffffffff) + (*cp&0377);
if ((g = h & 0xf0000000) != 0) {
h = h ^ g >> 24;
h = h ^ g;
}
}
return h;
}
long
nextprime(long n)
{
const long primes[] = {
509, 1021, 2039, 4093, 8191, 16381, 32749, 65521,
131071, 262139, 524287, 1048573, 2097143, 4194301,
8388593, 16777213, 33554393, 67108859, 134217689,
268435399, 536870909, 1073741789, 2147483647
};
long mprime = 7;
int i;
for (i = 0; i < sizeof primes / sizeof *primes; i++)
if ((mprime = primes[i]) >= (n < 65536 ? n*4 :
n < 262144 ? n*2 : n))
break;
if (i == sizeof primes / sizeof *primes)
mprime = n; /* not so prime, but better than failure */
return mprime;
}
#define Hexchar(n) ((n)>9 ? (n)-10+'A' : (n)+'0')
#define hexchar(n) ((n)>9 ? (n)-10+'a' : (n)+'0')
char *
strenc(const char *cp)
{
char *n, *np;
np = n = salloc(strlen(cp) * 3 + 1);
while (*cp) {
if (alnumchar(*cp&0377) || *cp == '_' || *cp == '@' ||
(np > n && (*cp == '.' || *cp == '-' ||
*cp == ':')))
*np++ = *cp;
else {
*np++ = '%';
*np++ = Hexchar((*cp&0xf0) >> 4);
*np++ = Hexchar(*cp&0x0f);
}
cp++;
}
*np = '\0';
return n;
}
char *
strdec(const char *cp)
{
char *n, *np;
np = n = salloc(strlen(cp) + 1);
while (*cp) {
if (cp[0] == '%' && cp[1] && cp[2]) {
*np = (int)(cp[1]>'9'?cp[1]-'A'+10:cp[1]-'0') << 4;
*np++ |= cp[2]>'9'?cp[2]-'A'+10:cp[2]-'0';
cp += 3;
} else
*np++ = *cp++;
}
*np = '\0';
return n;
}
char *
md5tohex(const void *vp)
{
char *hex;
const char *cp = vp;
int i;
hex = salloc(33);
for (i = 0; i < 16; i++) {
hex[2*i] = hexchar((cp[i]&0xf0) >> 4);
hex[2*i+1] = hexchar(cp[i]&0x0f);
}
hex[32] = '\0';
return hex;
}
char *
cram_md5_string(const char *user, const char *pass, const char *b64)
{
struct str in, out;
char digest[16], *cp, *sp, *rp, *xp;
int ss, rs;
in.s = (char *)b64;
in.l = strlen(in.s);
mime_fromb64(&in, &out, 0);
hmac_md5((unsigned char *)out.s, out.l,
(unsigned char *)pass, strlen(pass),
digest);
free(out.s);
xp = md5tohex(digest);
sp = ac_alloc(ss = strlen(user) + strlen(xp) + 2);
snprintf(sp, ss, "%s %s", user, xp);
cp = strtob64(sp);
ac_free(sp);
rp = salloc(rs = strlen(cp) + 3);
snprintf(rp, rs, "%s\r\n", cp);
free(cp);
return rp;
}
char *
getuser(void)
{
char *line = NULL, *user;
size_t linesize = 0;
if (is_a_tty[0]) {
fputs("User: ", stdout);
fflush(stdout);
}
if (readline(stdin, &line, &linesize) == 0) {
if (line)
free(line);
return NULL;
}
user = savestr(line);
free(line);
return user;
}
char *
getpassword(struct termios *otio, int *reset_tio, const char *query)
{
struct termios tio;
char *line = NULL, *pass;
size_t linesize = 0;
int i;
if (is_a_tty[0]) {
fputs(query ? query : "Password:", stdout);
fflush(stdout);
tcgetattr(0, &tio);
*otio = tio;
tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
*reset_tio = 1;
tcsetattr(0, TCSAFLUSH, &tio);
}
i = readline(stdin, &line, &linesize);
if (is_a_tty[0]) {
fputc('\n', stdout);
tcsetattr(0, TCSADRAIN, otio);
}
*reset_tio = 0;
if (i < 0) {
if (line)
free(line);
return NULL;
}
pass = savestr(line);
free(line);
return pass;
}
void
transflags(struct message *omessage, long omsgCount, int transparent)
{
struct message *omp, *nmp, *newdot, *newprevdot;
int hf;
omp = omessage;
nmp = message;
newdot = message;
newprevdot = NULL;
while (omp < &omessage[omsgCount] &&
nmp < &message[msgCount]) {
if (dot && nmp->m_uid == dot->m_uid)
newdot = nmp;
if (prevdot && nmp->m_uid == prevdot->m_uid)
newprevdot = nmp;
if (omp->m_uid == nmp->m_uid) {
hf = nmp->m_flag & MHIDDEN;
if (transparent && mb.mb_type == MB_IMAP)
omp->m_flag &= ~MHIDDEN;
*nmp++ = *omp++;
if (transparent && mb.mb_type == MB_CACHE)
nmp[-1].m_flag |= hf;
} else if (omp->m_uid < nmp->m_uid)
omp++;
else
nmp++;
}
dot = newdot;
setdot(newdot);
prevdot = newprevdot;
free(omessage);
}
char *
getrandstring(size_t length)
{
static unsigned char nodedigest[16];
static pid_t pid;
int i, fd = -1;
char *data;
char *cp, *rp;
MD5_CTX ctx;
data = salloc(length);
if ((fd = open("/dev/urandom", O_RDONLY)) < 0 ||
read(fd, data, length) != length) {
if (pid == 0) {
pid = getpid();
srand(pid);
cp = nodename(0);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *)cp, strlen(cp));
MD5Final(nodedigest, &ctx);
}
for (i = 0; i < length; i++)
data[i] = (int)(255 * (rand() / (RAND_MAX + 1.0))) ^
nodedigest[i % sizeof nodedigest];
}
if (fd > 0)
close(fd);
cp = memtob64(data, length);
rp = salloc(length+1);
strncpy(rp, cp, length)[length] = '\0';
free(cp);
return rp;
}
void
out_of_memory(void)
{
panic("no memory");
}
void *
smalloc(size_t s)
{
void *p;
if (s == 0)
s = 1;
if ((p = malloc(s)) == NULL)
out_of_memory();
return p;
}
void *
srealloc(void *v, size_t s)
{
void *r;
if (s == 0)
s = 1;
if (v == NULL)
return smalloc(s);
if ((r = realloc(v, s)) == NULL)
out_of_memory();
return r;
}
void *
scalloc(size_t nmemb, size_t size)
{
void *vp;
if (size == 0)
size = 1;
if ((vp = calloc(nmemb, size)) == NULL)
out_of_memory();
return vp;
}
char *
sstpcpy(char *dst, const char *src)
{
while ((*dst = *src++) != '\0')
dst++;
return dst;
}
char *
sstrdup(const char *cp)
{
char *dp;
if (cp) {
dp = smalloc(strlen(cp) + 1);
strcpy(dp, cp);
return dp;
} else
return NULL;
}
enum okay
makedir(const char *name)
{
int e;
struct stat st;
if (mkdir(name, 0700) < 0) {
e = errno;
if ((e == EEXIST || e == ENOSYS) &&
stat(name, &st) == 0 &&
(st.st_mode&S_IFMT) == S_IFDIR)
return OKAY;
return STOP;
}
return OKAY;
}
#ifdef HAVE_FCHDIR
enum okay
cwget(struct cw *cw)
{
if ((cw->cw_fd = open(".", O_RDONLY)) < 0)
return STOP;
if (fchdir(cw->cw_fd) < 0) {
close(cw->cw_fd);
return STOP;
}
return OKAY;
}
enum okay
cwret(struct cw *cw)
{
if (fchdir(cw->cw_fd) < 0)
return STOP;
return OKAY;
}
void
cwrelse(struct cw *cw)
{
close(cw->cw_fd);
}
#else /* !HAVE_FCHDIR */
enum okay
cwget(struct cw *cw)
{
if (getcwd(cw->cw_wd, sizeof cw->cw_wd) == NULL || chdir(cw->cw_wd) < 0)
return STOP;
return OKAY;
}
enum okay
cwret(struct cw *cw)
{
if (chdir(cw->cw_wd) < 0)
return STOP;
return OKAY;
}
/*ARGSUSED*/
void
cwrelse(struct cw *cw)
{
}
#endif /* !HAVE_FCHDIR */
void
makeprint(struct str *in, struct str *out)
{
static int print_all_chars = -1;
char *inp, *outp;
size_t msz, dist;
out->s = smalloc(msz = in->l + 1);
if (print_all_chars == -1)
print_all_chars = value("print-all-chars") != NULL;
if (print_all_chars) {
memcpy(out->s, in->s, in->l);
out->l = in->l;
out->s[out->l] = '\0';
return;
}
inp = in->s;
outp = out->s;
#if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
if (mb_cur_max > 1) {
wchar_t wc;
char mb[MB_LEN_MAX+1];
int i, n;
out->l = 0;
while (inp < &in->s[in->l]) {
if (*inp & 0200)
n = mbtowc(&wc, inp, &in->s[in->l] - inp);
else {
wc = *inp;
n = 1;
}
if (n < 0) {
mbtowc(&wc, NULL, mb_cur_max);
wc = utf8 ? 0xFFFD : '?';
n = 1;
} else if (n == 0)
n = 1;
inp += n;
if (!iswprint(wc) && wc != '\n' && wc != '\r' &&
wc != '\b' && wc != '\t') {
if ((wc & ~(wchar_t)037) == 0)
wc = utf8 ? 0x2400 | wc : '?';
else if (wc == 0177)
wc = utf8 ? 0x2421 : '?';
else
wc = utf8 ? 0x2426 : '?';
}
if ((n = wctomb(mb, wc)) <= 0)
continue;
out->l += n;
if (out->l >= msz - 1) {
dist = outp - out->s;
out->s = srealloc(out->s, msz += 32);
outp = &out->s[dist];
}
for (i = 0; i < n; i++)
*outp++ = mb[i];
}
} else
#endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
{
int c;
while (inp < &in->s[in->l]) {
c = *inp++ & 0377;
if (!isprint(c) && c != '\n' && c != '\r' &&
c != '\b' && c != '\t')
c = '?';
*outp++ = c;
}
out->l = in->l;
}
out->s[out->l] = '\0';
}
char *
prstr(const char *s)
{
struct str in, out;
char *rp;
in.s = (char *)s;
in.l = strlen(s);
makeprint(&in, &out);
rp = salloc(out.l + 1);
memcpy(rp, out.s, out.l);
rp[out.l] = '\0';
free(out.s);
return rp;
}
int
prout(const char *s, size_t sz, FILE *fp)
{
struct str in, out;
int n;
in.s = (char *)s;
in.l = sz;
makeprint(&in, &out);
n = fwrite(out.s, 1, out.l, fp);
free(out.s);
return n;
}
/*
* Print out a Unicode character or a substitute for it.
*/
int
putuc(int u, int c, FILE *fp)
{
#if defined (HAVE_MBTOWC) && defined (HAVE_WCTYPE_H)
if (utf8 && u & ~(wchar_t)0177) {
char mb[MB_LEN_MAX];
int i, n, r = 0;
if ((n = wctomb(mb, u)) > 0) {
for (i = 0; i < n; i++)
r += putc(mb[i] & 0377, fp) != EOF;
return r;
} else if (n == 0)
return putc('\0', fp) != EOF;
else
return 0;
} else
#endif /* HAVE_MBTOWC && HAVE_WCTYPE_H */
return putc(c, fp) != EOF;
}
/*
* Locale-independent character class functions.
*/
int
asccasecmp(const char *s1, const char *s2)
{
register int cmp;
do
if ((cmp = lowerconv(*s1 & 0377) - lowerconv(*s2 & 0377)) != 0)
return cmp;
while (*s1++ != '\0' && *s2++ != '\0');
return 0;
}
int
ascncasecmp(const char *s1, const char *s2, size_t sz)
{
register int cmp;
size_t i = 1;
if (sz == 0)
return 0;
do
if ((cmp = lowerconv(*s1 & 0377) - lowerconv(*s2 & 0377)) != 0)
return cmp;
while (i++ < sz && *s1++ != '\0' && *s2++ != '\0');
return 0;
}
char *
asccasestr(const char *haystack, const char *xneedle)
{
char *needle, *NEEDLE;
int i, sz;
sz = strlen(xneedle);
if (sz == 0)
return (char *)haystack;
needle = ac_alloc(sz);
NEEDLE = ac_alloc(sz);
for (i = 0; i < sz; i++) {
needle[i] = lowerconv(xneedle[i]&0377);
NEEDLE[i] = upperconv(xneedle[i]&0377);
}
while (*haystack) {
if (*haystack == *needle || *haystack == *NEEDLE) {
for (i = 1; i < sz; i++)
if (haystack[i] != needle[i] &&
haystack[i] != NEEDLE[i])
break;
if (i == sz)
return (char *)haystack;
}
haystack++;
}
return NULL;
}
const unsigned char class_char[] = {
/* 000 nul 001 soh 002 stx 003 etx 004 eot 005 enq 006 ack 007 bel */
C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
/* 010 bs 011 ht 012 nl 013 vt 014 np 015 cr 016 so 017 si */
C_CNTRL,C_BLANK,C_WHITE,C_SPACE,C_SPACE,C_SPACE,C_CNTRL,C_CNTRL,
/* 020 dle 021 dc1 022 dc2 023 dc3 024 dc4 025 nak 026 syn 027 etb */
C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
/* 030 can 031 em 032 sub 033 esc 034 fs 035 gs 036 rs 037 us */
C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
/* 040 sp 041 ! 042 " 043 # 044 $ 045 % 046 & 047 ' */
C_BLANK,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
/* 050 ( 051 ) 052 * 053 + 054 , 055 - 056 . 057 / */
C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
/* 060 0 061 1 062 2 063 3 064 4 065 5 066 6 067 7 */
C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,
/* 070 8 071 9 072 : 073 ; 074 < 075 = 076 > 077 ? */
C_DIGIT,C_DIGIT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
/* 100 @ 101 A 102 B 103 C 104 D 105 E 106 F 107 G */
C_PUNCT,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
/* 110 H 111 I 112 J 113 K 114 L 115 M 116 N 117 O */
C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
/* 120 P 121 Q 122 R 123 S 124 T 125 U 126 V 127 W */
C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
/* 130 X 131 Y 132 Z 133 [ 134 \ 135 ] 136 ^ 137 _ */
C_UPPER,C_UPPER,C_UPPER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
/* 140 ` 141 a 142 b 143 c 144 d 145 e 146 f 147 g */
C_PUNCT,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
/* 150 h 151 i 152 j 153 k 154 l 155 m 156 n 157 o */
C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
/* 160 p 161 q 162 r 163 s 164 t 165 u 166 v 167 w */
C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
/* 170 x 171 y 172 z 173 { 174 | 175 } 176 ~ 177 del */
C_LOWER,C_LOWER,C_LOWER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_CNTRL
};
syntax highlighted by Code2HTML, v. 0.9.1