sh.misc.c revision 100616
1/* $Header: /src/pub/tcsh/sh.misc.c,v 3.24 2002/03/08 17:36:46 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("$Id: sh.misc.c,v 3.24 2002/03/08 17:36:46 christos Exp $")
36
37static	int	renum	__P((int, int));
38static  Char  **blkend	__P((Char **));
39static  Char  **blkcat	__P((Char **, Char **));
40
41/*
42 * C Shell
43 */
44
45int
46any(s, c)
47    register char *s;
48    register int c;
49{
50    if (!s)
51	return (0);		/* Check for nil pointer */
52    while (*s)
53	if (*s++ == c)
54	    return (1);
55    return (0);
56}
57
58void
59setzero(cp, i)
60    char   *cp;
61    int     i;
62{
63    if (i != 0)
64	do
65	    *cp++ = 0;
66	while (--i);
67}
68
69char   *
70strsave(s)
71    register const char *s;
72{
73    char   *n;
74    register char *p;
75
76    if (s == NULL)
77	s = (const char *) "";
78    for (p = (char *) s; *p++ != '\0';)
79	continue;
80    n = p = (char *) xmalloc((size_t)
81			     ((((const char *) p) - s) * sizeof(char)));
82    while ((*p++ = *s++) != '\0')
83	continue;
84    return (n);
85}
86
87static Char  **
88blkend(up)
89    register Char **up;
90{
91
92    while (*up)
93	up++;
94    return (up);
95}
96
97
98void
99blkpr(av)
100    register Char **av;
101{
102
103    for (; *av; av++) {
104	xprintf("%S", *av);
105	if (av[1])
106	    xprintf(" ");
107    }
108}
109
110void
111blkexpand(av, str)
112    register Char **av;
113    Char *str;
114{
115    *str = '\0';
116    for (; *av; av++) {
117	(void) Strcat(str, *av);
118	if (av[1])
119	    (void) Strcat(str, STRspace);
120    }
121}
122
123int
124blklen(av)
125    register Char **av;
126{
127    register int i = 0;
128
129    while (*av++)
130	i++;
131    return (i);
132}
133
134Char  **
135blkcpy(oav, bv)
136    Char  **oav;
137    register Char **bv;
138{
139    register Char **av = oav;
140
141    while ((*av++ = *bv++) != NULL)
142	continue;
143    return (oav);
144}
145
146static Char  **
147blkcat(up, vp)
148    Char  **up, **vp;
149{
150
151    (void) blkcpy(blkend(up), vp);
152    return (up);
153}
154
155void
156blkfree(av0)
157    Char  **av0;
158{
159    register Char **av = av0;
160
161    if (!av0)
162	return;
163    for (; *av; av++)
164	xfree((ptr_t) * av);
165    xfree((ptr_t) av0);
166}
167
168Char  **
169saveblk(v)
170    register Char **v;
171{
172    register Char **newv =
173    (Char **) xcalloc((size_t) (blklen(v) + 1), sizeof(Char **));
174    Char  **onewv = newv;
175
176    while (*v)
177	*newv++ = Strsave(*v++);
178    return (onewv);
179}
180
181#if !defined(SHORT_STRINGS) && !defined(POSIX)
182char   *
183strstr(s, t)
184    register const char *s, *t;
185{
186    do {
187	register const char *ss = s;
188	register const char *tt = t;
189
190	do
191	    if (*tt == '\0')
192		return ((char *) s);
193	while (*ss++ == *tt++);
194    } while (*s++ != '\0');
195    return (NULL);
196}
197
198#endif /* !SHORT_STRINGS && !POSIX */
199
200#ifndef SHORT_STRINGS
201char   *
202strspl(cp, dp)
203    char   *cp, *dp;
204{
205    char   *ep;
206    register char *p, *q;
207
208    if (!cp)
209	cp = "";
210    if (!dp)
211	dp = "";
212    for (p = cp; *p++ != '\0';)
213	continue;
214    for (q = dp; *q++ != '\0';)
215	continue;
216    ep = (char *) xmalloc((size_t) (((p - cp) + (q - dp) - 1) * sizeof(char)));
217    for (p = ep, q = cp; (*p++ = *q++) != '\0';)
218	continue;
219    for (p--, q = dp; (*p++ = *q++) != '\0';)
220	continue;
221    return (ep);
222}
223
224#endif /* !SHORT_STRINGS */
225
226Char  **
227blkspl(up, vp)
228    register Char **up, **vp;
229{
230    register Char **wp =
231    (Char **) xcalloc((size_t) (blklen(up) + blklen(vp) + 1),
232		      sizeof(Char **));
233
234    (void) blkcpy(wp, up);
235    return (blkcat(wp, vp));
236}
237
238Char
239lastchr(cp)
240    register 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()
258{
259    register int f;
260
261#ifdef YPBUGS
262    /* suggested by Justin Bur; thanks to Karl Kleinpaste */
263    fix_yp_bugs();
264#endif /* YPBUGS */
265    for (f = 0; f < NOFILE; f++)
266	if (f != SHIN && f != SHOUT && f != SHDIAG && f != OLDSTD &&
267	    f != FSHTTY
268#ifdef MALLOC_TRACE
269	    && f != 25
270#endif /* MALLOC_TRACE */
271	    )
272	  {
273	    (void) close(f);
274#ifdef NISPLUS
275	    if(f < 3)
276		(void) open(_PATH_DEVNULL, O_RDONLY);
277#endif /* NISPLUS */
278	  }
279}
280
281#ifndef CLOSE_ON_EXEC
282/*
283 * Close files before executing a file.
284 * We could be MUCH more intelligent, since (on a version 7 system)
285 * we need only close files here during a source, the other
286 * shell fd's being in units 16-19 which are closed automatically!
287 */
288void
289closech()
290{
291    register int f;
292
293    if (didcch)
294	return;
295    didcch = 1;
296    SHIN = 0;
297    SHOUT = 1;
298    SHDIAG = 2;
299    OLDSTD = 0;
300    isoutatty = isatty(SHOUT);
301    isdiagatty = isatty(SHDIAG);
302    for (f = 3; f < NOFILE; f++)
303	(void) close(f);
304}
305
306#endif /* CLOSE_ON_EXEC */
307
308void
309donefds()
310{
311
312    (void) close(0);
313    (void) close(1);
314    (void) close(2);
315    didfds = 0;
316#ifdef NISPLUS
317    {
318	int fd = open(_PATH_DEVNULL, O_RDONLY);
319	(void) dup2(fd, 1);
320	(void) dup2(fd, 2);
321	if (fd != 0) {
322	    (void) dup2(fd, 0);
323	    (void) close(fd);
324	}
325    }
326#endif /*NISPLUS*/
327}
328
329/*
330 * Move descriptor i to j.
331 * If j is -1 then we just want to get i to a safe place,
332 * i.e. to a unit > 2.  This also happens in dcopy.
333 */
334int
335dmove(i, j)
336    register int i, j;
337{
338
339    if (i == j || i < 0)
340	return (i);
341#ifdef HAVEDUP2
342    if (j >= 0) {
343	(void) dup2(i, j);
344	if (j != i)
345	    (void) close(i);
346	return (j);
347    }
348#endif
349    j = dcopy(i, j);
350    if (j != i)
351	(void) close(i);
352    return (j);
353}
354
355int
356dcopy(i, j)
357    register int i, j;
358{
359
360    if (i == j || i < 0 || (j < 0 && i > 2))
361	return (i);
362    if (j >= 0) {
363#ifdef HAVEDUP2
364	(void) dup2(i, j);
365	return (j);
366#else
367	(void) close(j);
368#endif
369    }
370    return (renum(i, j));
371}
372
373static int
374renum(i, j)
375    register int i, j;
376{
377    register int k = dup(i);
378
379    if (k < 0)
380	return (-1);
381    if (j == -1 && k > 2)
382	return (k);
383    if (k != j) {
384	j = renum(k, j);
385	(void) close(k);
386	return (j);
387    }
388    return (k);
389}
390
391/*
392 * Left shift a command argument list, discarding
393 * the first c arguments.  Used in "shift" commands
394 * as well as by commands like "repeat".
395 */
396void
397lshift(v, c)
398    register Char **v;
399    register int c;
400{
401    register Char **u;
402
403    for (u = v; *u && --c >= 0; u++)
404	xfree((ptr_t) *u);
405    (void) blkcpy(v, u);
406}
407
408int
409number(cp)
410    Char   *cp;
411{
412    if (!cp)
413	return (0);
414    if (*cp == '-') {
415	cp++;
416	if (!Isdigit(*cp))
417	    return (0);
418	cp++;
419    }
420    while (*cp && Isdigit(*cp))
421	cp++;
422    return (*cp == 0);
423}
424
425Char  **
426copyblk(v)
427    register Char **v;
428{
429    register Char **nv =
430    (Char **) xcalloc((size_t) (blklen(v) + 1), sizeof(Char **));
431
432    return (blkcpy(nv, v));
433}
434
435#ifndef SHORT_STRINGS
436char   *
437strend(cp)
438    register char *cp;
439{
440    if (!cp)
441	return (cp);
442    while (*cp)
443	cp++;
444    return (cp);
445}
446
447#endif /* SHORT_STRINGS */
448
449Char   *
450strip(cp)
451    Char   *cp;
452{
453    register Char *dp = cp;
454
455    if (!cp)
456	return (cp);
457    while ((*dp++ &= TRIM) != '\0')
458	continue;
459    return (cp);
460}
461
462Char   *
463quote(cp)
464    Char   *cp;
465{
466    register Char *dp = cp;
467
468    if (!cp)
469	return (cp);
470    while (*dp != '\0')
471	*dp++ |= QUOTE;
472    return (cp);
473}
474
475Char   *
476quote_meta(d, s)
477    Char   *d;
478    const Char   *s;
479{
480    Char *r = d;
481    while (*s != '\0') {
482	if (cmap(*s, _META | _DOL | _QF | _QB | _ESC | _GLOB))
483		*d++ = '\\';
484	*d++ = *s++;
485    }
486    *d = '\0';
487    return r;
488}
489
490void
491udvar(name)
492    Char   *name;
493{
494
495    setname(short2str(name));
496    stderror(ERR_NAME | ERR_UNDVAR);
497}
498
499int
500prefix(sub, str)
501    register Char *sub, *str;
502{
503
504    for (;;) {
505	if (*sub == 0)
506	    return (1);
507	if (*str == 0)
508	    return (0);
509	if ((*sub++ & TRIM) != (*str++ & TRIM))
510	    return (0);
511    }
512}
513