sh.misc.c revision 316957
1/* $Header: /p/tcsh/cvsroot/tcsh/sh.misc.c,v 3.50 2015/06/06 21:19:08 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.50 2015/06/06 21:19:08 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 != '\0') {
454#if INVALID_BYTE != 0
455	if ((*dp & INVALID_BYTE) != INVALID_BYTE)    /* *dp < INVALID_BYTE */
456#endif
457		*dp &= TRIM;
458	dp++;
459    }
460    return (cp);
461}
462
463Char   *
464quote(Char *cp)
465{
466    Char *dp = cp;
467
468    if (!cp)
469	return (cp);
470    while (*dp != '\0') {
471#ifdef WIDE_STRINGS
472	if ((*dp & 0xffffff80) == 0)	/* *dp < 0x80 */
473#elif defined SHORT_STRINGS
474	if ((*dp & 0xff80) == 0)	/* *dp < 0x80 */
475#else
476	if ((*dp & 0x80) == 0)		/* *dp < 0x80 */
477#endif
478	    *dp |= QUOTE;
479	dp++;
480    }
481    return (cp);
482}
483
484const Char *
485quote_meta(struct Strbuf *buf, const Char *s)
486{
487    buf->len = 0;
488    while (*s != '\0') {
489	if (cmap(*s, _META | _DOL | _QF | _QB | _ESC | _GLOB))
490	    Strbuf_append1(buf, '\\');
491	Strbuf_append1(buf, *s++);
492    }
493    Strbuf_terminate(buf);
494    return buf->s;
495}
496
497void
498udvar(Char *name)
499{
500    setname(short2str(name));
501    stderror(ERR_NAME | ERR_UNDVAR);
502}
503
504int
505prefix(const Char *sub, const Char *str)
506{
507
508    for (;;) {
509	if (*sub == 0)
510	    return (1);
511	if (*str == 0)
512	    return (0);
513	if ((*sub++ & TRIM) != (*str++ & TRIM))
514	    return (0);
515    }
516}
517#ifndef WINNT_NATIVE
518char *
519areadlink(const char *path)
520{
521    char *buf;
522    size_t size;
523    ssize_t res;
524
525    size = MAXPATHLEN + 1;
526    buf = xmalloc(size);
527    while ((size_t)(res = readlink(path, buf, size)) == size) {
528	size *= 2;
529	buf = xrealloc(buf, size);
530    }
531    if (res == -1) {
532	int err;
533
534	err = errno;
535	xfree(buf);
536	errno = err;
537	return NULL;
538    }
539    buf[res] = '\0';
540    return xrealloc(buf, res + 1);
541}
542#endif /*!WINNT_NATIVE*/
543
544void
545xclose(int fildes)
546{
547    if (fildes < 0)
548	return;
549    while (close(fildes) == -1 && errno == EINTR)
550	if (handle_pending_signals())
551	    break;
552}
553
554void
555xclosedir(DIR *dirp)
556{
557    while (closedir(dirp) == -1 && errno == EINTR)
558	if (handle_pending_signals())
559	    break;
560}
561
562int
563xcreat(const char *path, mode_t mode)
564{
565    int res;
566
567    while ((res = creat(path, mode)) == -1 && errno == EINTR)
568	if (handle_pending_signals())
569	    break;
570    return res;
571}
572
573#ifdef HAVE_DUP2
574static int
575xdup2(int fildes, int fildes2)
576{
577    int res;
578
579    while ((res = dup2(fildes, fildes2)) == -1 && errno == EINTR)
580	if (handle_pending_signals())
581	    break;
582    return res;
583}
584#endif
585
586struct group *
587xgetgrgid(gid_t xgid)
588{
589    struct group *res;
590
591    errno = 0;
592    while ((res = getgrgid(xgid)) == NULL && errno == EINTR) {
593	if (handle_pending_signals())
594	    break;
595	errno = 0;
596    }
597    return res;
598}
599
600struct passwd *
601xgetpwnam(const char *name)
602{
603    struct passwd *res;
604
605    errno = 0;
606    while ((res = getpwnam(name)) == NULL && errno == EINTR) {
607	if (handle_pending_signals())
608	    break;
609	errno = 0;
610    }
611    return res;
612}
613
614struct passwd *
615xgetpwuid(uid_t xuid)
616{
617    struct passwd *res;
618
619    errno = 0;
620    while ((res = getpwuid(xuid)) == NULL && errno == EINTR) {
621	if (handle_pending_signals())
622	    break;
623	errno = 0;
624    }
625    return res;
626}
627
628int
629xopen(const char *path, int oflag, ...)
630{
631    int res;
632
633    if ((oflag & O_CREAT) == 0) {
634	while ((res = open(path, oflag)) == -1 && errno == EINTR)
635	    if (handle_pending_signals())
636		break;
637    } else {
638	va_list ap;
639	mode_t mode;
640
641	va_start(ap, oflag);
642	/* "int" should actually be "mode_t after default argument
643	   promotions". "int" is the best guess we have, "mode_t" used to be
644	   "unsigned short", which we obviously can't use. */
645	mode = va_arg(ap, int);
646	va_end(ap);
647	while ((res = open(path, oflag, mode)) == -1 && errno == EINTR)
648	    if (handle_pending_signals())
649		break;
650    }
651    return res;
652}
653
654ssize_t
655xread(int fildes, void *buf, size_t nbyte)
656{
657    ssize_t res;
658
659    /* This is where we will be blocked most of the time, so handle signals
660       that didn't interrupt any system call. */
661    do
662      if (handle_pending_signals())
663	  break;
664    while ((res = read(fildes, buf, nbyte)) == -1 && errno == EINTR);
665    return res;
666}
667
668#ifdef POSIX
669int
670xtcsetattr(int fildes, int optional_actions, const struct termios *termios_p)
671{
672    int res;
673
674    while ((res = tcsetattr(fildes, optional_actions, termios_p)) == -1 &&
675	   errno == EINTR)
676	if (handle_pending_signals())
677	    break;
678    return res;
679}
680#endif
681
682ssize_t
683xwrite(int fildes, const void *buf, size_t nbyte)
684{
685    ssize_t res;
686
687    /* This is where we will be blocked most of the time, so handle signals
688       that didn't interrupt any system call. */
689    do
690      if (handle_pending_signals())
691	  break;
692    while ((res = write(fildes, buf, nbyte)) == -1 && errno == EINTR);
693    return res;
694}
695