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