sh.misc.c revision 231990
1/* $Header: /p/tcsh/cvsroot/tcsh/sh.misc.c,v 3.46 2010/05/08 00:41:58 christos Exp $ */
2/*
3 * sh.misc.c: Miscelaneous functions
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33#include "sh.h"
34
35RCSID("$tcsh: sh.misc.c,v 3.46 2010/05/08 00:41:58 christos Exp $")
36
37static	int	renum	(int, int);
38static  Char  **blkend	(Char **);
39static  Char  **blkcat	(Char **, Char **);
40static	int	xdup2	(int, int);
41
42/*
43 * C Shell
44 */
45
46int
47any(const char *s, Char c)
48{
49    if (!s)
50	return (0);		/* Check for nil pointer */
51    while (*s)
52	if ((Char)*s++ == c)
53	    return (1);
54    return (0);
55}
56
57void
58setzero(void *p, size_t size)
59{
60    memset(p, 0, size);
61}
62
63#ifndef SHORT_STRINGS
64char *
65strnsave(const char *s, size_t len)
66{
67    char *r;
68
69    r = xmalloc(len + 1);
70    memcpy(r, s, len);
71    r[len] = '\0';
72    return r;
73}
74#endif
75
76char   *
77strsave(const char *s)
78{
79    char   *r;
80    size_t size;
81
82    if (s == NULL)
83	s = "";
84    size = strlen(s) + 1;
85    r = xmalloc(size);
86    memcpy(r, s, size);
87    return (r);
88}
89
90static Char  **
91blkend(Char **up)
92{
93
94    while (*up)
95	up++;
96    return (up);
97}
98
99
100void
101blkpr(Char *const *av)
102{
103
104    for (; *av; av++) {
105	xprintf("%S", *av);
106	if (av[1])
107	    xprintf(" ");
108    }
109}
110
111Char *
112blkexpand(Char *const *av)
113{
114    struct Strbuf buf = Strbuf_INIT;
115
116    for (; *av; av++) {
117	Strbuf_append(&buf, *av);
118	if (av[1])
119	    Strbuf_append1(&buf, ' ');
120    }
121    return Strbuf_finish(&buf);
122}
123
124int
125blklen(Char **av)
126{
127    int i = 0;
128
129    while (*av++)
130	i++;
131    return (i);
132}
133
134Char  **
135blkcpy(Char **oav, Char **bv)
136{
137    Char **av = oav;
138
139    while ((*av++ = *bv++) != NULL)
140	continue;
141    return (oav);
142}
143
144static Char  **
145blkcat(Char **up, Char **vp)
146{
147
148    (void) blkcpy(blkend(up), vp);
149    return (up);
150}
151
152void
153blkfree(Char **av0)
154{
155    Char **av = av0;
156
157    if (!av0)
158	return;
159    for (; *av; av++)
160	xfree(*av);
161    xfree(av0);
162}
163
164void
165blk_cleanup(void *ptr)
166{
167    blkfree(ptr);
168}
169
170void
171blk_indirect_cleanup(void *xptr)
172{
173    Char ***ptr;
174
175    ptr = xptr;
176    blkfree(*ptr);
177    xfree(ptr);
178}
179
180Char  **
181saveblk(Char **v)
182{
183    Char **newv, **onewv;
184
185    if (v == NULL)
186	return NULL;
187
188    onewv = newv = xcalloc(blklen(v) + 1, sizeof(Char **));
189
190    while (*v)
191	*newv++ = Strsave(*v++);
192    return (onewv);
193}
194
195#ifndef HAVE_STRSTR
196char   *
197strstr(const char *s, const char *t)
198{
199    do {
200	const char *ss = s;
201	const char *tt = t;
202
203	do
204	    if (*tt == '\0')
205		return (s);
206	while (*ss++ == *tt++);
207    } while (*s++ != '\0');
208    return (NULL);
209}
210#endif /* !HAVE_STRSTR */
211
212char   *
213strspl(const char *cp, const char *dp)
214{
215    char   *ep;
216    size_t cl, dl;
217
218    if (!cp)
219	cp = "";
220    if (!dp)
221	dp = "";
222    cl = strlen(cp);
223    dl = strlen(dp);
224    ep = xmalloc((cl + dl + 1) * sizeof(char));
225    memcpy(ep, cp, cl);
226    memcpy(ep + cl, dp, dl + 1);
227    return (ep);
228}
229
230Char  **
231blkspl(Char **up, Char **vp)
232{
233    Char **wp = xcalloc(blklen(up) + blklen(vp) + 1, sizeof(Char **));
234
235    (void) blkcpy(wp, up);
236    return (blkcat(wp, vp));
237}
238
239Char
240lastchr(Char *cp)
241{
242
243    if (!cp)
244	return (0);
245    if (!*cp)
246	return (0);
247    while (cp[1])
248	cp++;
249    return (*cp);
250}
251
252/*
253 * This routine is called after an error to close up
254 * any units which may have been left open accidentally.
255 */
256void
257closem(void)
258{
259    int f, num_files;
260
261#ifdef NLS_BUGS
262#ifdef NLS_CATALOGS
263    nlsclose();
264#endif /* NLS_CATALOGS */
265#endif /* NLS_BUGS */
266#ifdef YPBUGS
267    /* suggested by Justin Bur; thanks to Karl Kleinpaste */
268    fix_yp_bugs();
269#endif /* YPBUGS */
270    num_files = NOFILE;
271    for (f = 0; f < num_files; f++)
272	if (f != SHIN && f != SHOUT && f != SHDIAG && f != OLDSTD &&
273	    f != FSHTTY
274#ifdef MALLOC_TRACE
275	    && f != 25
276#endif /* MALLOC_TRACE */
277	    )
278	  {
279	    xclose(f);
280#ifdef NISPLUS
281	    if(f < 3)
282		(void) xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE);
283#endif /* NISPLUS */
284	  }
285#ifdef NLS_BUGS
286#ifdef NLS_CATALOGS
287    nlsinit();
288#endif /* NLS_CATALOGS */
289#endif /* NLS_BUGS */
290}
291
292#ifndef CLOSE_ON_EXEC
293/*
294 * Close files before executing a file.
295 * We could be MUCH more intelligent, since (on a version 7 system)
296 * we need only close files here during a source, the other
297 * shell fd's being in units 16-19 which are closed automatically!
298 */
299void
300closech(void)
301{
302    int f, num_files;
303
304    if (didcch)
305	return;
306    didcch = 1;
307    SHIN = 0;
308    SHOUT = 1;
309    SHDIAG = 2;
310    OLDSTD = 0;
311    isoutatty = isatty(SHOUT);
312    isdiagatty = isatty(SHDIAG);
313    num_files = NOFILE;
314    for (f = 3; f < num_files; f++)
315	xclose(f);
316}
317
318#endif /* CLOSE_ON_EXEC */
319
320void
321donefds(void)
322{
323
324    xclose(0);
325    xclose(1);
326    xclose(2);
327    didfds = 0;
328#ifdef NISPLUS
329    {
330	int fd = xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE);
331	(void)dcopy(fd, 1);
332	(void)dcopy(fd, 2);
333	(void)dmove(fd, 0);
334    }
335#endif /*NISPLUS*/
336}
337
338/*
339 * Move descriptor i to j.
340 * If j is -1 then we just want to get i to a safe place,
341 * i.e. to a unit > FSAFE.  This also happens in dcopy.
342 */
343int
344dmove(int i, int j)
345{
346
347    if (i == j || i < 0)
348	return (i);
349#ifdef HAVE_DUP2
350    if (j >= 0) {
351	(void) xdup2(i, j);
352	if (j != i)
353	    xclose(i);
354	return (j);
355    }
356#endif
357    j = dcopy(i, j);
358    if (j != i)
359	xclose(i);
360    return (j);
361}
362
363int
364dcopy(int i, int j)
365{
366
367    if (i == j || i < 0 || (j < 0 && i > FSAFE))
368	return (i);
369    if (j >= 0) {
370#ifdef HAVE_DUP2
371	(void) xdup2(i, j);
372	return (j);
373#else
374	xclose(j);
375#endif
376    }
377    return (renum(i, j));
378}
379
380static int
381renum(int i, int j)
382{
383    int k = dup(i);
384
385    if (k < 0)
386	return (-1);
387    if (j == -1 && k > FSAFE)
388	return (k);
389    if (k != j) {
390	j = renum(k, j);
391	xclose(k);
392	return (j);
393    }
394    return (k);
395}
396
397/*
398 * Left shift a command argument list, discarding
399 * the first c arguments.  Used in "shift" commands
400 * as well as by commands like "repeat".
401 */
402void
403lshift(Char **v, int c)
404{
405    Char **u;
406
407    for (u = v; *u && --c >= 0; u++)
408	xfree(*u);
409    (void) blkcpy(v, u);
410}
411
412int
413number(Char *cp)
414{
415    if (!cp)
416	return (0);
417    if (*cp == '-') {
418	cp++;
419	if (!Isdigit(*cp))
420	    return (0);
421	cp++;
422    }
423    while (*cp && Isdigit(*cp))
424	cp++;
425    return (*cp == 0);
426}
427
428Char  **
429copyblk(Char **v)
430{
431    Char **nv = xcalloc(blklen(v) + 1, sizeof(Char **));
432
433    return (blkcpy(nv, v));
434}
435
436char   *
437strend(const char *cp)
438{
439    if (!cp)
440	return ((char *)(intptr_t)cp);
441    while (*cp)
442	cp++;
443    return ((char *)(intptr_t)cp);
444}
445
446Char   *
447strip(Char *cp)
448{
449    Char *dp = cp;
450
451    if (!cp)
452	return (cp);
453    while ((*dp++ &= TRIM) != '\0')
454	continue;
455    return (cp);
456}
457
458Char   *
459quote(Char *cp)
460{
461    Char *dp = cp;
462
463    if (!cp)
464	return (cp);
465    while (*dp != '\0')
466	*dp++ |= QUOTE;
467    return (cp);
468}
469
470const Char *
471quote_meta(struct Strbuf *buf, const Char *s)
472{
473    buf->len = 0;
474    while (*s != '\0') {
475	if (cmap(*s, _META | _DOL | _QF | _QB | _ESC | _GLOB))
476	    Strbuf_append1(buf, '\\');
477	Strbuf_append1(buf, *s++);
478    }
479    Strbuf_terminate(buf);
480    return buf->s;
481}
482
483void
484udvar(Char *name)
485{
486    setname(short2str(name));
487    stderror(ERR_NAME | ERR_UNDVAR);
488}
489
490int
491prefix(const Char *sub, const Char *str)
492{
493
494    for (;;) {
495	if (*sub == 0)
496	    return (1);
497	if (*str == 0)
498	    return (0);
499	if ((*sub++ & TRIM) != (*str++ & TRIM))
500	    return (0);
501    }
502}
503#ifndef WINNT_NATIVE
504char *
505areadlink(const char *path)
506{
507    char *buf;
508    size_t size;
509    ssize_t res;
510
511    size = MAXPATHLEN + 1;
512    buf = xmalloc(size);
513    while ((size_t)(res = readlink(path, buf, size)) == size) {
514	size *= 2;
515	buf = xrealloc(buf, size);
516    }
517    if (res == -1) {
518	int err;
519
520	err = errno;
521	xfree(buf);
522	errno = err;
523	return NULL;
524    }
525    buf[res] = '\0';
526    return xrealloc(buf, res + 1);
527}
528#endif /*!WINNT_NATIVE*/
529
530void
531xclose(int fildes)
532{
533    if (fildes < 0)
534	return;
535    while (close(fildes) == -1 && errno == EINTR)
536	handle_pending_signals();
537}
538
539void
540xclosedir(DIR *dirp)
541{
542    while (closedir(dirp) == -1 && errno == EINTR)
543	handle_pending_signals();
544}
545
546int
547xcreat(const char *path, mode_t mode)
548{
549    int res;
550
551    while ((res = creat(path, mode)) == -1 && errno == EINTR)
552	handle_pending_signals();
553    return res;
554}
555
556#ifdef HAVE_DUP2
557static int
558xdup2(int fildes, int fildes2)
559{
560    int res;
561
562    while ((res = dup2(fildes, fildes2)) == -1 && errno == EINTR)
563	handle_pending_signals();
564    return res;
565}
566#endif
567
568struct group *
569xgetgrgid(gid_t xgid)
570{
571    struct group *res;
572
573    errno = 0;
574    while ((res = getgrgid(xgid)) == NULL && errno == EINTR) {
575	handle_pending_signals();
576	errno = 0;
577    }
578    return res;
579}
580
581struct passwd *
582xgetpwnam(const char *name)
583{
584    struct passwd *res;
585
586    errno = 0;
587    while ((res = getpwnam(name)) == NULL && errno == EINTR) {
588	handle_pending_signals();
589	errno = 0;
590    }
591    return res;
592}
593
594struct passwd *
595xgetpwuid(uid_t xuid)
596{
597    struct passwd *res;
598
599    errno = 0;
600    while ((res = getpwuid(xuid)) == NULL && errno == EINTR) {
601	handle_pending_signals();
602	errno = 0;
603    }
604    return res;
605}
606
607int
608xopen(const char *path, int oflag, ...)
609{
610    int res;
611
612    if ((oflag & O_CREAT) == 0) {
613	while ((res = open(path, oflag)) == -1 && errno == EINTR)
614	    handle_pending_signals();
615    } else {
616	va_list ap;
617	mode_t mode;
618
619	va_start(ap, oflag);
620	/* "int" should actually be "mode_t after default argument
621	   promotions". "int" is the best guess we have, "mode_t" used to be
622	   "unsigned short", which we obviously can't use. */
623	mode = va_arg(ap, int);
624	va_end(ap);
625	while ((res = open(path, oflag, mode)) == -1 && errno == EINTR)
626	    handle_pending_signals();
627    }
628    return res;
629}
630
631ssize_t
632xread(int fildes, void *buf, size_t nbyte)
633{
634    ssize_t res;
635
636    /* This is where we will be blocked most of the time, so handle signals
637       that didn't interrupt any system call. */
638    do
639      handle_pending_signals();
640    while ((res = read(fildes, buf, nbyte)) == -1 && errno == EINTR);
641    return res;
642}
643
644#ifdef POSIX
645int
646xtcsetattr(int fildes, int optional_actions, const struct termios *termios_p)
647{
648    int res;
649
650    while ((res = tcsetattr(fildes, optional_actions, termios_p)) == -1 &&
651	   errno == EINTR)
652	handle_pending_signals();
653    return res;
654}
655#endif
656
657ssize_t
658xwrite(int fildes, const void *buf, size_t nbyte)
659{
660    ssize_t res;
661
662    /* This is where we will be blocked most of the time, so handle signals
663       that didn't interrupt any system call. */
664    do
665      handle_pending_signals();
666    while ((res = write(fildes, buf, nbyte)) == -1 && errno == EINTR);
667    return res;
668}
669