diff options
Diffstat (limited to 'sh.misc.c')
-rw-r--r-- | sh.misc.c | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/sh.misc.c b/sh.misc.c new file mode 100644 index 0000000..7c4094f --- /dev/null +++ b/sh.misc.c @@ -0,0 +1,666 @@ +/* $Header: /p/tcsh/cvsroot/tcsh/sh.misc.c,v 3.45 2006/10/14 17:57:21 christos Exp $ */ +/* + * sh.misc.c: Miscelaneous functions + */ +/*- + * Copyright (c) 1980, 1991 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. 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. + */ +#include "sh.h" + +RCSID("$tcsh: sh.misc.c,v 3.45 2006/10/14 17:57:21 christos Exp $") + +static int renum (int, int); +static Char **blkend (Char **); +static Char **blkcat (Char **, Char **); +static int xdup2 (int, int); + +/* + * C Shell + */ + +int +any(const char *s, Char c) +{ + if (!s) + return (0); /* Check for nil pointer */ + while (*s) + if ((Char)*s++ == c) + return (1); + return (0); +} + +void +setzero(void *p, size_t size) +{ + memset(p, 0, size); +} + +char * +strnsave(const char *s, size_t len) +{ + char *r; + + r = xmalloc(len + 1); + memcpy(r, s, len); + r[len] = '\0'; + return r; +} + +char * +strsave(const char *s) +{ + char *r; + size_t size; + + if (s == NULL) + s = ""; + size = strlen(s) + 1; + r = xmalloc(size); + memcpy(r, s, size); + return (r); +} + +static Char ** +blkend(Char **up) +{ + + while (*up) + up++; + return (up); +} + + +void +blkpr(Char *const *av) +{ + + for (; *av; av++) { + xprintf("%S", *av); + if (av[1]) + xprintf(" "); + } +} + +Char * +blkexpand(Char *const *av) +{ + struct Strbuf buf = Strbuf_INIT; + + for (; *av; av++) { + Strbuf_append(&buf, *av); + if (av[1]) + Strbuf_append1(&buf, ' '); + } + return Strbuf_finish(&buf); +} + +int +blklen(Char **av) +{ + int i = 0; + + while (*av++) + i++; + return (i); +} + +Char ** +blkcpy(Char **oav, Char **bv) +{ + Char **av = oav; + + while ((*av++ = *bv++) != NULL) + continue; + return (oav); +} + +static Char ** +blkcat(Char **up, Char **vp) +{ + + (void) blkcpy(blkend(up), vp); + return (up); +} + +void +blkfree(Char **av0) +{ + Char **av = av0; + + if (!av0) + return; + for (; *av; av++) + xfree(*av); + xfree(av0); +} + +void +blk_cleanup(void *ptr) +{ + blkfree(ptr); +} + +void +blk_indirect_cleanup(void *xptr) +{ + Char ***ptr; + + ptr = xptr; + blkfree(*ptr); + xfree(ptr); +} + +Char ** +saveblk(Char **v) +{ + Char **newv, **onewv; + + if (v == NULL) + return NULL; + + onewv = newv = xcalloc(blklen(v) + 1, sizeof(Char **)); + + while (*v) + *newv++ = Strsave(*v++); + return (onewv); +} + +#ifndef HAVE_STRSTR +char * +strstr(const char *s, const char *t) +{ + do { + const char *ss = s; + const char *tt = t; + + do + if (*tt == '\0') + return (s); + while (*ss++ == *tt++); + } while (*s++ != '\0'); + return (NULL); +} +#endif /* !HAVE_STRSTR */ + +char * +strspl(const char *cp, const char *dp) +{ + char *ep; + size_t cl, dl; + + if (!cp) + cp = ""; + if (!dp) + dp = ""; + cl = strlen(cp); + dl = strlen(dp); + ep = xmalloc((cl + dl + 1) * sizeof(char)); + memcpy(ep, cp, cl); + memcpy(ep + cl, dp, dl + 1); + return (ep); +} + +Char ** +blkspl(Char **up, Char **vp) +{ + Char **wp = xcalloc(blklen(up) + blklen(vp) + 1, sizeof(Char **)); + + (void) blkcpy(wp, up); + return (blkcat(wp, vp)); +} + +Char +lastchr(Char *cp) +{ + + if (!cp) + return (0); + if (!*cp) + return (0); + while (cp[1]) + cp++; + return (*cp); +} + +/* + * This routine is called after an error to close up + * any units which may have been left open accidentally. + */ +void +closem(void) +{ + int f, num_files; + +#ifdef NLS_BUGS +#ifdef NLS_CATALOGS + nlsclose(); +#endif /* NLS_CATALOGS */ +#endif /* NLS_BUGS */ +#ifdef YPBUGS + /* suggested by Justin Bur; thanks to Karl Kleinpaste */ + fix_yp_bugs(); +#endif /* YPBUGS */ + num_files = NOFILE; + for (f = 0; f < num_files; f++) + if (f != SHIN && f != SHOUT && f != SHDIAG && f != OLDSTD && + f != FSHTTY +#ifdef MALLOC_TRACE + && f != 25 +#endif /* MALLOC_TRACE */ + ) + { + xclose(f); +#ifdef NISPLUS + if(f < 3) + (void) xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE); +#endif /* NISPLUS */ + } +#ifdef NLS_BUGS +#ifdef NLS_CATALOGS + nlsinit(); +#endif /* NLS_CATALOGS */ +#endif /* NLS_BUGS */ +} + +#ifndef CLOSE_ON_EXEC +/* + * Close files before executing a file. + * We could be MUCH more intelligent, since (on a version 7 system) + * we need only close files here during a source, the other + * shell fd's being in units 16-19 which are closed automatically! + */ +void +closech(void) +{ + int f, num_files; + + if (didcch) + return; + didcch = 1; + SHIN = 0; + SHOUT = 1; + SHDIAG = 2; + OLDSTD = 0; + isoutatty = isatty(SHOUT); + isdiagatty = isatty(SHDIAG); + num_files = NOFILE; + for (f = 3; f < num_files; f++) + xclose(f); +} + +#endif /* CLOSE_ON_EXEC */ + +void +donefds(void) +{ + + xclose(0); + xclose(1); + xclose(2); + didfds = 0; +#ifdef NISPLUS + { + int fd = xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE); + (void)dcopy(fd, 1); + (void)dcopy(fd, 2); + (void)dmove(fd, 0); + } +#endif /*NISPLUS*/ +} + +/* + * Move descriptor i to j. + * If j is -1 then we just want to get i to a safe place, + * i.e. to a unit > FSAFE. This also happens in dcopy. + */ +int +dmove(int i, int j) +{ + + if (i == j || i < 0) + return (i); +#ifdef HAVE_DUP2 + if (j >= 0) { + (void) xdup2(i, j); + if (j != i) + xclose(i); + return (j); + } +#endif + j = dcopy(i, j); + if (j != i) + xclose(i); + return (j); +} + +int +dcopy(int i, int j) +{ + + if (i == j || i < 0 || (j < 0 && i > FSAFE)) + return (i); + if (j >= 0) { +#ifdef HAVE_DUP2 + (void) xdup2(i, j); + return (j); +#else + xclose(j); +#endif + } + return (renum(i, j)); +} + +static int +renum(int i, int j) +{ + int k = dup(i); + + if (k < 0) + return (-1); + if (j == -1 && k > FSAFE) + return (k); + if (k != j) { + j = renum(k, j); + xclose(k); + return (j); + } + return (k); +} + +/* + * Left shift a command argument list, discarding + * the first c arguments. Used in "shift" commands + * as well as by commands like "repeat". + */ +void +lshift(Char **v, int c) +{ + Char **u; + + for (u = v; *u && --c >= 0; u++) + xfree(*u); + (void) blkcpy(v, u); +} + +int +number(Char *cp) +{ + if (!cp) + return (0); + if (*cp == '-') { + cp++; + if (!Isdigit(*cp)) + return (0); + cp++; + } + while (*cp && Isdigit(*cp)) + cp++; + return (*cp == 0); +} + +Char ** +copyblk(Char **v) +{ + Char **nv = xcalloc(blklen(v) + 1, sizeof(Char **)); + + return (blkcpy(nv, v)); +} + +char * +strend(const char *cp) +{ + if (!cp) + return ((char *)(intptr_t)cp); + while (*cp) + cp++; + return ((char *)(intptr_t)cp); +} + +Char * +strip(Char *cp) +{ + Char *dp = cp; + + if (!cp) + return (cp); + while ((*dp++ &= TRIM) != '\0') + continue; + return (cp); +} + +Char * +quote(Char *cp) +{ + Char *dp = cp; + + if (!cp) + return (cp); + while (*dp != '\0') + *dp++ |= QUOTE; + return (cp); +} + +const Char * +quote_meta(struct Strbuf *buf, const Char *s) +{ + buf->len = 0; + while (*s != '\0') { + if (cmap(*s, _META | _DOL | _QF | _QB | _ESC | _GLOB)) + Strbuf_append1(buf, '\\'); + Strbuf_append1(buf, *s++); + } + Strbuf_terminate(buf); + return buf->s; +} + +void +udvar(Char *name) +{ + setname(short2str(name)); + stderror(ERR_NAME | ERR_UNDVAR); +} + +int +prefix(const Char *sub, const Char *str) +{ + + for (;;) { + if (*sub == 0) + return (1); + if (*str == 0) + return (0); + if ((*sub++ & TRIM) != (*str++ & TRIM)) + return (0); + } +} +#ifndef WINNT_NATIVE +char * +areadlink(const char *path) +{ + char *buf; + size_t size; + ssize_t res; + + size = MAXPATHLEN + 1; + buf = xmalloc(size); + while ((size_t)(res = readlink(path, buf, size)) == size) { + size *= 2; + buf = xrealloc(buf, size); + } + if (res == -1) { + int err; + + err = errno; + xfree(buf); + errno = err; + return NULL; + } + buf[res] = '\0'; + return xrealloc(buf, res + 1); +} +#endif /*!WINNT_NATIVE*/ + +void +xclose(int fildes) +{ + if (fildes < 0) + return; + while (close(fildes) == -1 && errno == EINTR) + handle_pending_signals(); +} + +void +xclosedir(DIR *dirp) +{ + while (closedir(dirp) == -1 && errno == EINTR) + handle_pending_signals(); +} + +int +xcreat(const char *path, mode_t mode) +{ + int res; + + while ((res = creat(path, mode)) == -1 && errno == EINTR) + handle_pending_signals(); + return res; +} + +#ifdef HAVE_DUP2 +static int +xdup2(int fildes, int fildes2) +{ + int res; + + while ((res = dup2(fildes, fildes2)) == -1 && errno == EINTR) + handle_pending_signals(); + return res; +} +#endif + +struct group * +xgetgrgid(gid_t xgid) +{ + struct group *res; + + errno = 0; + while ((res = getgrgid(xgid)) == NULL && errno == EINTR) { + handle_pending_signals(); + errno = 0; + } + return res; +} + +struct passwd * +xgetpwnam(const char *name) +{ + struct passwd *res; + + errno = 0; + while ((res = getpwnam(name)) == NULL && errno == EINTR) { + handle_pending_signals(); + errno = 0; + } + return res; +} + +struct passwd * +xgetpwuid(uid_t xuid) +{ + struct passwd *res; + + errno = 0; + while ((res = getpwuid(xuid)) == NULL && errno == EINTR) { + handle_pending_signals(); + errno = 0; + } + return res; +} + +int +xopen(const char *path, int oflag, ...) +{ + int res; + + if ((oflag & O_CREAT) == 0) { + while ((res = open(path, oflag)) == -1 && errno == EINTR) + handle_pending_signals(); + } else { + va_list ap; + mode_t mode; + + va_start(ap, oflag); + /* "int" should actually be "mode_t after default argument + promotions". "int" is the best guess we have, "mode_t" used to be + "unsigned short", which we obviously can't use. */ + mode = va_arg(ap, int); + va_end(ap); + while ((res = open(path, oflag, mode)) == -1 && errno == EINTR) + handle_pending_signals(); + } + return res; +} + +ssize_t +xread(int fildes, void *buf, size_t nbyte) +{ + ssize_t res; + + /* This is where we will be blocked most of the time, so handle signals + that didn't interrupt any system call. */ + do + handle_pending_signals(); + while ((res = read(fildes, buf, nbyte)) == -1 && errno == EINTR); + return res; +} + +#ifdef POSIX +int +xtcsetattr(int fildes, int optional_actions, const struct termios *termios_p) +{ + int res; + + while ((res = tcsetattr(fildes, optional_actions, termios_p)) == -1 && + errno == EINTR) + handle_pending_signals(); + return res; +} +#endif + +ssize_t +xwrite(int fildes, const void *buf, size_t nbyte) +{ + ssize_t res; + + /* This is where we will be blocked most of the time, so handle signals + that didn't interrupt any system call. */ + do + handle_pending_signals(); + while ((res = write(fildes, buf, nbyte)) == -1 && errno == EINTR); + return res; +} |