usb4bsd/ukbd: Adjust comment style a bit.
[dragonfly.git] / contrib / tcsh-6 / sh.misc.c
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
35 RCSID("$tcsh: sh.misc.c,v 3.45 2006/10/14 17:57:21 christos Exp $")
36
37 static  int     renum   (int, int);
38 static  Char  **blkend  (Char **);
39 static  Char  **blkcat  (Char **, Char **);
40 static  int     xdup2   (int, int);
41
42 /*
43  * C Shell
44  */
45
46 int
47 any(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
57 void
58 setzero(void *p, size_t size)
59 {
60     memset(p, 0, size);
61 }
62
63 char *
64 strnsave(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
74 char   *
75 strsave(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
88 static Char  **
89 blkend(Char **up)
90 {
91
92     while (*up)
93         up++;
94     return (up);
95 }
96
97
98 void
99 blkpr(Char *const *av)
100 {
101
102     for (; *av; av++) {
103         xprintf("%S", *av);
104         if (av[1])
105             xprintf(" ");
106     }
107 }
108
109 Char *
110 blkexpand(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
122 int
123 blklen(Char **av)
124 {
125     int i = 0;
126
127     while (*av++)
128         i++;
129     return (i);
130 }
131
132 Char  **
133 blkcpy(Char **oav, Char **bv)
134 {
135     Char **av = oav;
136
137     while ((*av++ = *bv++) != NULL)
138         continue;
139     return (oav);
140 }
141
142 static Char  **
143 blkcat(Char **up, Char **vp)
144 {
145
146     (void) blkcpy(blkend(up), vp);
147     return (up);
148 }
149
150 void
151 blkfree(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
162 void
163 blk_cleanup(void *ptr)
164 {
165     blkfree(ptr);
166 }
167
168 void
169 blk_indirect_cleanup(void *xptr)
170 {
171     Char ***ptr;
172
173     ptr = xptr;
174     blkfree(*ptr);
175     xfree(ptr);
176 }
177
178 Char  **
179 saveblk(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
194 char   *
195 strstr(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
210 char   *
211 strspl(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
228 Char  **
229 blkspl(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
237 Char
238 lastchr(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  */
254 void
255 closem(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  */
297 void
298 closech(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
318 void
319 donefds(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  */
341 int
342 dmove(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
361 int
362 dcopy(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
378 static int
379 renum(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  */
400 void
401 lshift(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
410 int
411 number(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
426 Char  **
427 copyblk(Char **v)
428 {
429     Char **nv = xcalloc(blklen(v) + 1, sizeof(Char **));
430
431     return (blkcpy(nv, v));
432 }
433
434 char   *
435 strend(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
444 Char   *
445 strip(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
456 Char   *
457 quote(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
468 const Char *
469 quote_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
481 void
482 udvar(Char *name)
483 {
484     setname(short2str(name));
485     stderror(ERR_NAME | ERR_UNDVAR);
486 }
487
488 int
489 prefix(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
502 char *
503 areadlink(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
528 void
529 xclose(int fildes)
530 {
531     if (fildes < 0)
532         return;
533     while (close(fildes) == -1 && errno == EINTR)
534         handle_pending_signals();
535 }
536
537 void
538 xclosedir(DIR *dirp)
539 {
540     while (closedir(dirp) == -1 && errno == EINTR)
541         handle_pending_signals();
542 }
543
544 int
545 xcreat(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
555 static int
556 xdup2(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
566 struct group *
567 xgetgrgid(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
579 struct passwd *
580 xgetpwnam(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
592 struct passwd *
593 xgetpwuid(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
605 int
606 xopen(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
629 ssize_t
630 xread(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
643 int
644 xtcsetattr(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
655 ssize_t
656 xwrite(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 }