Imported from ../bash-2.01.1.tar.gz.
[platform/upstream/bash.git] / general.c
1 /* general.c -- Stuff that is used by all files. */
2
3 /* Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992
4    Free Software Foundation, Inc.
5
6    This file is part of GNU Bash, the Bourne Again SHell.
7
8    Bash is free software; you can redistribute it and/or modify it under
9    the terms of the GNU General Public License as published by the Free
10    Software Foundation; either version 2, or (at your option) any later
11    version.
12
13    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14    WARRANTY; without even the implied warranty of MERCHANTABILITY or
15    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16    for more details.
17
18    You should have received a copy of the GNU General Public License along
19    with Bash; see the file COPYING.  If not, write to the Free Software
20    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22 #include "config.h"
23
24 #include "bashtypes.h"
25 #include <sys/param.h>
26 #include "posixstat.h"
27
28 #if defined (HAVE_UNISTD_H)
29 #  include <unistd.h>
30 #endif
31
32 #include "filecntl.h"
33 #include "bashansi.h"
34 #include <stdio.h>
35 #include <ctype.h>
36 #include <errno.h>
37
38 #include "shell.h"
39 #include <tilde/tilde.h>
40
41 #if defined (TIME_WITH_SYS_TIME)
42 #  include <sys/time.h>
43 #  include <time.h>
44 #else
45 #  if defined (HAVE_SYS_TIME_H)
46 #    include <sys/time.h>
47 #  else
48 #    include <time.h>
49 #  endif
50 #endif
51
52 #include <sys/times.h>
53 #include "maxpath.h"
54
55 #if !defined (errno)
56 extern int errno;
57 #endif /* !errno */
58
59 #ifndef to_upper
60 #  define to_upper(c) (islower(c) ? toupper(c) : (c))
61 #  define to_lower(c) (isupper(c) ? tolower(c) : (c))
62 #endif
63
64 extern int interrupt_immediately;
65 extern int interactive_comments;
66 extern char *bash_getcwd_errstr;
67
68 /* Do whatever is necessary to initialize `Posix mode'. */
69 void
70 posix_initialize (on)
71      int on;
72 {
73   interactive_comments = on != 0;
74 }
75
76 /* **************************************************************** */
77 /*                                                                  */
78 /*                   Integer to String Conversion                   */
79 /*                                                                  */
80 /* **************************************************************** */
81
82 /* Number of characters that can appear in a string representation
83    of an integer.  32 is larger than the string rep of 2^^31 - 1. */
84 #define MAX_INT_LEN 32
85
86 /* Integer to string conversion.  This conses the string; the
87    caller should free it. */
88 char *
89 itos (i)
90      int i;
91 {
92   char buf[MAX_INT_LEN], *p, *ret;
93   int negative = 0;
94   unsigned int ui;
95
96   if (i < 0)
97     {
98       negative++;
99       i = -i;
100     }
101
102   ui = (unsigned int) i;
103
104   p = buf + MAX_INT_LEN - 2;
105   p[1] = '\0';
106
107   do
108     *p-- = (ui % 10) + '0';
109   while (ui /= 10);
110
111   if (negative)
112     *p-- = '-';
113
114   ret = savestring (p + 1);
115   return (ret);
116 }
117
118 /* atol(3) is not universal */
119 long
120 string_to_long (s)
121      char *s;
122 {
123   long ret = 0L;
124   int neg = 0;
125
126   while (s && *s && whitespace (*s))
127     s++;
128   if (*s == '-' || *s == '+')
129     {
130       neg = *s == '-';
131       s++;
132     }
133   for ( ; s && *s && digit (*s); s++)
134     ret = (ret * 10) + digit_value (*s);
135   return (neg ? -ret : ret);
136 }
137
138 /* **************************************************************** */
139 /*                                                                  */
140 /*  Functions to convert to and from and display non-standard types */
141 /*                                                                  */
142 /* **************************************************************** */
143
144 #if defined (RLIMTYPE)
145 RLIMTYPE
146 string_to_rlimtype (s)
147      char *s;
148 {
149   RLIMTYPE ret = 0;
150   int neg = 0;
151
152   while (s && *s && whitespace (*s))
153     s++;
154   if (*s == '-' || *s == '+')
155     {
156       neg = *s == '-';
157       s++;
158     }
159   for ( ; s && *s && digit (*s); s++)
160     ret = (ret * 10) + digit_value (*s);
161   return (neg ? -ret : ret);
162 }
163
164 void
165 print_rlimtype (n, addnl)
166      RLIMTYPE n;
167      int addnl;
168 {
169   char s[sizeof (RLIMTYPE) * 3 + 1];
170   int len = sizeof (RLIMTYPE) * 3 + 1;
171
172   if (n == 0)
173     {
174       printf ("0%s", addnl ? "\n" : "");
175       return;
176     }
177
178   if (n < 0)
179     {
180       putchar ('-');
181       n = -n;
182     }
183
184   s[--len] = '\0';
185   for ( ; n != 0; n /= 10)
186     s[--len] = n % 10 + '0';
187   printf ("%s%s", s + len, addnl ? "\n" : "");
188 }
189 #endif /* RLIMTYPE */
190
191 #if defined (HAVE_TIMEVAL)
192 /* Convert a pointer to a struct timeval to seconds and thousandths of a
193    second, returning the values in *SP and *SFP, respectively.  This does
194    rounding on the fractional part, not just truncation to three places. */
195 void
196 timeval_to_secs (tvp, sp, sfp)
197      struct timeval *tvp;
198      long *sp;
199      int *sfp;
200 {
201   int rest;
202
203   *sp = tvp->tv_sec;
204
205   *sfp = tvp->tv_usec % 1000000;        /* pretty much a no-op */
206   rest = *sfp % 1000;
207   *sfp = (*sfp * 1000) / 1000000;
208   if (rest >= 500)
209     *sfp += 1;
210 }
211   
212 /* Print the contents of a struct timeval * in a standard way to stdio
213    stream FP.  */
214 void
215 print_timeval (fp, tvp)
216      FILE *fp;
217      struct timeval *tvp;
218 {
219   int minutes, seconds_fraction;
220   long seconds;
221
222   timeval_to_secs (tvp, &seconds, &seconds_fraction);
223
224   minutes = seconds / 60;
225   seconds %= 60;
226
227   fprintf (fp, "%0dm%0ld.%03ds",  minutes, seconds, seconds_fraction);
228 }
229 #endif /* HAVE_TIMEVAL */
230
231 #if defined (HAVE_TIMES)
232 void
233 clock_t_to_secs (t, sp, sfp)
234      clock_t t;
235      long *sp;
236      int *sfp;
237 {
238   static long clk_tck = 0;
239
240   if (clk_tck == 0)
241     clk_tck = get_clk_tck ();
242
243   *sfp = t % clk_tck;
244   *sfp = (*sfp * 1000) / clk_tck;
245
246   *sp = t / clk_tck;
247 }
248
249 /* Print the time defined by a time_t (returned by the `times' and `time'
250    system calls) in a standard way to stdion stream FP.  This is scaled in
251    terms of HZ, which is what is returned by the `times' call. */
252 void
253 print_time_in_hz (fp, t)
254      FILE *fp;
255      clock_t t;
256 {
257   int minutes, seconds_fraction;
258   long seconds;
259
260   clock_t_to_secs (t, &seconds, &seconds_fraction);
261
262   minutes = seconds / 60;
263   seconds %= 60;
264
265   fprintf (fp, "%0dm%0ld.%03ds",  minutes, seconds, seconds_fraction);
266 }
267 #endif /* HAVE_TIMES */
268
269 /* **************************************************************** */
270 /*                                                                  */
271 /*                     Input Validation Functions                   */
272 /*                                                                  */
273 /* **************************************************************** */
274
275 /* Return non-zero if all of the characters in STRING are digits. */
276 int
277 all_digits (string)
278      char *string;
279 {
280   while (*string)
281     {
282       if (!digit (*string))
283         return (0);
284       else
285         string++;
286     }
287   return (1);
288 }
289
290 /* Return non-zero if the characters pointed to by STRING constitute a
291    valid number.  Stuff the converted number into RESULT if RESULT is
292    a non-null pointer to a long. */
293 int
294 legal_number (string, result)
295      char *string;
296      long *result;
297 {
298   int sign;
299   long value;
300
301   sign = 1;
302   value = 0;
303
304   if (result)
305     *result = 0;
306
307   /* Skip leading whitespace characters. */
308   while (whitespace (*string))
309     string++;
310
311   if (!*string)
312     return (0);
313
314   /* We allow leading `-' or `+'. */
315   if (*string == '-' || *string == '+')
316     {
317       if (!digit (string[1]))
318         return (0);
319
320       if (*string == '-')
321         sign = -1;
322
323       string++;
324     }
325
326   while (digit (*string))
327     {
328       if (result)
329         value = (value * 10) + digit_value (*string);
330       string++;
331     }
332
333   /* Skip trailing whitespace, if any. */
334   while (whitespace (*string))
335     string++;
336
337   /* Error if not at end of string. */
338   if (*string)
339     return (0);
340
341   if (result)
342     *result = value * sign;
343
344   return (1);
345 }
346
347 /* Return 1 if this token is a legal shell `identifier'; that is, it consists
348    solely of letters, digits, and underscores, and does not begin with a
349    digit. */
350 int
351 legal_identifier (name)
352      char *name;
353 {
354   register char *s;
355
356   if (!name || !*name || (legal_variable_starter (*name) == 0))
357     return (0);
358
359   for (s = name + 1; *s; s++)
360     {
361       if (legal_variable_char (*s) == 0)
362         return (0);
363     }
364   return (1);
365 }
366
367 /* Make sure that WORD is a valid shell identifier, i.e.
368    does not contain a dollar sign, nor is quoted in any way.  Nor
369    does it consist of all digits.  If CHECK_WORD is non-zero,
370    the word is checked to ensure that it consists of only letters,
371    digits, and underscores. */
372 int
373 check_identifier (word, check_word)
374      WORD_DESC *word;
375      int check_word;
376 {
377   if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word))
378     {
379       internal_error ("`%s': not a valid identifier", word->word);
380       return (0);
381     }
382   else if (check_word && legal_identifier (word->word) == 0)
383     {
384       internal_error ("`%s': not a valid identifier", word->word);
385       return (0);
386     }
387   else
388     return (1);
389 }
390
391 /* **************************************************************** */
392 /*                                                                  */
393 /*           Functions to manage files and file descriptors         */
394 /*                                                                  */
395 /* **************************************************************** */
396
397 /* A function to unset no-delay mode on a file descriptor.  Used in shell.c
398    to unset it on the fd passed as stdin.  Should be called on stdin if
399    readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */
400
401 #if !defined (O_NDELAY)
402 #  if defined (FNDELAY)
403 #    define O_NDELAY FNDELAY
404 #  endif
405 #endif /* O_NDELAY */
406
407 /* Make sure no-delay mode is not set on file descriptor FD. */
408 void
409 unset_nodelay_mode (fd)
410      int fd;
411 {
412   int flags, set;
413
414   if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
415     return;
416
417   set = 0;
418
419   /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present
420      and O_NDELAY is defined. */
421   if (flags & O_NONBLOCK)
422     {
423       flags &= ~O_NONBLOCK;
424       set++;
425     }
426
427   if (set)
428     fcntl (fd, F_SETFL, flags);
429 }
430
431   /* There is a bug in the NeXT 2.1 rlogind that causes opens
432      of /dev/tty to fail. */
433 void
434 check_dev_tty ()
435 {
436   int tty_fd;
437   char *tty;
438
439   tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK);
440
441   if (tty_fd < 0)
442     {
443       tty = (char *)ttyname (fileno (stdin));
444       if (tty == 0)
445         return;
446       tty_fd = open (tty, O_RDWR|O_NONBLOCK);
447     }
448   close (tty_fd);
449 }
450
451 /* Return 1 if PATH1 and PATH2 are the same file.  This is kind of
452    expensive.  If non-NULL STP1 and STP2 point to stat structures
453    corresponding to PATH1 and PATH2, respectively. */
454 int
455 same_file (path1, path2, stp1, stp2)
456      char *path1, *path2;
457      struct stat *stp1, *stp2;
458 {
459   struct stat st1, st2;
460
461   if (stp1 == NULL)
462     {
463       if (stat (path1, &st1) != 0)
464         return (0);
465       stp1 = &st1;
466     }
467
468   if (stp2 == NULL)
469     {
470       if (stat (path2, &st2) != 0)
471         return (0);
472       stp2 = &st2;
473     }
474
475   return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino));
476 }
477
478 /* Move FD to a number close to the maximum number of file descriptors
479    allowed in the shell process, to avoid the user stepping on it with
480    redirection and causing us extra work.  If CHECK_NEW is non-zero,
481    we check whether or not the file descriptors are in use before
482    duplicating FD onto them.  MAXFD says where to start checking the
483    file descriptors.  If it's less than 20, we get the maximum value
484    available from getdtablesize(2). */
485 int
486 move_to_high_fd (fd, check_new, maxfd)
487      int fd, check_new, maxfd;
488 {
489   int script_fd, nfds, ignore;
490
491   if (maxfd < 20)
492     {
493       nfds = getdtablesize ();
494       if (nfds <= 0)
495         nfds = 20;
496       if (nfds > 256)
497         nfds = 256;
498     }
499   else
500     nfds = maxfd;
501
502   for (nfds--; check_new && nfds > 3; nfds--)
503     if (fcntl (nfds, F_GETFD, &ignore) == -1)
504       break;
505
506   if (nfds && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
507     {
508       if (check_new == 0 || fd != fileno (stderr))      /* don't close stderr */
509         close (fd);
510       return (script_fd);
511     }
512
513   return (fd);
514 }
515  
516 /* Return non-zero if the characters from SAMPLE are not all valid
517    characters to be found in the first line of a shell script.  We
518    check up to the first newline, or SAMPLE_LEN, whichever comes first.
519    All of the characters must be printable or whitespace. */
520
521 #if !defined (isspace)
522 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f')
523 #endif
524
525 #if !defined (isprint)
526 #define isprint(c) (isletter(c) || digit(c) || ispunct(c))
527 #endif
528
529 int
530 check_binary_file (sample, sample_len)
531      unsigned char *sample;
532      int sample_len;
533 {
534   register int i;
535
536   for (i = 0; i < sample_len; i++)
537     {
538       if (sample[i] == '\n')
539         return (0);
540
541       if (isspace (sample[i]) == 0 && isprint (sample[i]) == 0)
542         return (1);
543     }
544
545   return (0);
546 }
547
548 /* **************************************************************** */
549 /*                                                                  */
550 /*                  Functions to manipulate pathnames               */
551 /*                                                                  */
552 /* **************************************************************** */
553
554 /* Return 1 if PATH corresponds to a directory. */
555 static int
556 canon_stat (path)
557      char *path;
558 {
559   int l;
560   char *s;
561   struct stat sb;
562
563   l = strlen (path);
564   s = xmalloc (l + 3);
565   strcpy (s, path);
566   s[l] = '/';
567   s[l+1] = '.';
568   s[l+2] = '\0';
569   l = stat (s, &sb) == 0 && S_ISDIR (sb.st_mode);
570   free (s);
571   return l;
572 }
573
574 /* Canonicalize PATH, and return a new path.  The new path differs from PATH
575    in that:
576         Multple `/'s are collapsed to a single `/'.
577         Leading `./'s and trailing `/.'s are removed.
578         Trailing `/'s are removed.
579         Non-leading `../'s and trailing `..'s are handled by removing
580         portions of the path. */
581 char *
582 canonicalize_pathname (path)
583      char *path;
584 {
585   register int i, start;
586   char stub_char;
587   char *result;
588
589   /* The result cannot be larger than the input PATH. */
590   result = savestring (path);
591
592   stub_char = (*path == '/') ? '/' : '.';
593
594   /* Walk along RESULT looking for things to compact. */
595   i = 0;
596   while (1)
597     {
598       if (!result[i])
599         break;
600
601       while (result[i] && result[i] != '/')
602         i++;
603
604       start = i++;
605
606       /* If we didn't find any slashes, then there is nothing left to do. */
607       if (!result[start])
608         break;
609
610       /* Handle multiple `/'s in a row. */
611       while (result[i] == '/')
612         i++;
613
614 #if 0
615       if ((start + 1) != i)
616 #else
617       /* Leave a leading `//' alone, as POSIX requires. */
618       if ((start + 1) != i && (start != 0 || i != 2))
619 #endif
620         {
621           strcpy (result + start + 1, result + i);
622           i = start + 1;
623           /* Make sure that what we have so far corresponds to a directory.
624              If it does not, just punt. */
625           if (*result)
626             {
627               char c;
628               c = result[start];
629               result[start] = '\0';
630               if (canon_stat (result) == 0)
631                 {
632                   free (result);
633                   return ((char *)NULL);
634                 }
635               result[start] = c;
636             }
637         }
638 #if 0
639       /* Handle backslash-quoted `/'. */
640       if (start > 0 && result[start - 1] == '\\')
641         continue;
642 #endif
643
644       /* Check for trailing `/'. */
645       if (start && !result[i])
646         {
647         zero_last:
648           result[--i] = '\0';
649           break;
650         }
651
652       /* Check for `../', `./' or trailing `.' by itself. */
653       if (result[i] == '.')
654         {
655           /* Handle trailing `.' by itself. */
656           if (!result[i + 1])
657             goto zero_last;
658
659           /* Handle `./'. */
660           if (result[i + 1] == '/')
661             {
662               strcpy (result + i, result + i + 1);
663               i = (start < 0) ? 0 : start;
664               continue;
665             }
666
667           /* Handle `../' or trailing `..' by itself. */
668           if (result[i + 1] == '.' &&
669               (result[i + 2] == '/' || !result[i + 2]))
670             {
671               /* Make sure that the last component corresponds to a directory
672                  before blindly chopping it off. */
673               if (i)
674                 {
675                   result[i] = '\0';
676                   if (canon_stat (result) == 0)
677                     {
678                       free (result);
679                       return ((char *)NULL);
680                     }
681                   result[i] = '.';
682                 }
683               while (--start > -1 && result[start] != '/');
684               strcpy (result + start + 1, result + i + 2);
685 #if 0   /* Unnecessary */
686               if (*result && canon_stat (result) == 0)
687                 {
688                   free (result);
689                   return ((char *)NULL);
690                 }
691 #endif
692               i = (start < 0) ? 0 : start;
693               continue;
694             }
695         }
696     }
697
698   if (!*result)
699     {
700       *result = stub_char;
701       result[1] = '\0';
702     }
703   return (result);
704 }
705
706 /* Turn STRING (a pathname) into an absolute pathname, assuming that
707    DOT_PATH contains the symbolic location of `.'.  This always
708    returns a new string, even if STRING was an absolute pathname to
709    begin with. */
710 char *
711 make_absolute (string, dot_path)
712      char *string, *dot_path;
713 {
714   char *result;
715   int result_len;
716
717   if (dot_path == 0 || *string == '/')
718     result = savestring (string);
719   else
720     {
721       if (dot_path[0])
722         {
723           result_len = strlen (dot_path);
724           result = xmalloc (2 + result_len + strlen (string));
725           strcpy (result, dot_path);
726           if (result[result_len - 1] != '/')
727             {
728               result[result_len++] = '/';
729               result[result_len] = '\0';
730             }
731         }
732       else
733         {
734           result = xmalloc (3 + strlen (string));
735           result[0] = '.'; result[1] = '/'; result[2] = '\0';
736           result_len = 2;
737         }
738
739       strcpy (result + result_len, string);
740     }
741
742   return (result);
743 }
744
745 /* Return 1 if STRING contains an absolute pathname, else 0. */
746 int
747 absolute_pathname (string)
748      char *string;
749 {
750   if (!string || !*string)
751     return (0);
752
753   if (*string == '/')
754     return (1);
755
756   if (*string++ == '.')
757     {
758       if (!*string || *string == '/' ||
759            (*string == '.' && (string[1] == '\0' || string[1] == '/')))
760         return (1);
761     }
762   return (0);
763 }
764
765 /* Return 1 if STRING is an absolute program name; it is absolute if it
766    contains any slashes.  This is used to decide whether or not to look
767    up through $PATH. */
768 int
769 absolute_program (string)
770      char *string;
771 {
772   return ((char *)strchr (string, '/') != (char *)NULL);
773 }
774
775 /* Return the `basename' of the pathname in STRING (the stuff after the
776    last '/').  If STRING is not a full pathname, simply return it. */
777 char *
778 base_pathname (string)
779      char *string;
780 {
781   char *p;
782
783   if (!absolute_pathname (string))
784     return (string);
785
786   p = (char *)strrchr (string, '/');
787   return (p ? ++p : string);
788 }
789
790 /* Return the full pathname of FILE.  Easy.  Filenames that begin
791    with a '/' are returned as themselves.  Other filenames have
792    the current working directory prepended.  A new string is
793    returned in either case. */
794 char *
795 full_pathname (file)
796      char *file;
797 {
798   char *disposer;
799   char *current_dir;
800   int dlen;
801
802   file = (*file == '~') ? bash_tilde_expand (file) : savestring (file);
803
804   if ((*file == '/') && absolute_pathname (file))
805     return (file);
806
807   disposer = file;
808
809   /* XXX - this should probably be just PATH_MAX or PATH_MAX + 1 */
810   current_dir = xmalloc (2 + PATH_MAX + strlen (file));
811   if (getcwd (current_dir, PATH_MAX) == 0)
812     {
813       sys_error (bash_getcwd_errstr);
814       free (disposer);
815       free (current_dir);
816       return ((char *)NULL);
817     }
818   dlen = strlen (current_dir);
819   current_dir[dlen++] = '/';
820
821   /* Turn /foo/./bar into /foo/bar. */
822   if (file[0] == '.' && file[1] == '/')
823     file += 2;
824
825   strcpy (current_dir + dlen, file);
826   free (disposer);
827   return (current_dir);
828 }
829
830 /* A slightly related function.  Get the prettiest name of this
831    directory possible. */
832 static char tdir[PATH_MAX];
833
834 /* Return a pretty pathname.  If the first part of the pathname is
835    the same as $HOME, then replace that with `~'.  */
836 char *
837 polite_directory_format (name)
838      char *name;
839 {
840   char *home;
841   int l;
842
843   home = get_string_value ("HOME");
844   l = home ? strlen (home) : 0;
845   if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
846     {
847       strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
848       tdir[0] = '~';
849       tdir[sizeof(tdir) - 1] = '\0';
850       return (tdir);
851     }
852   else
853     return (name);
854 }
855
856 /* Given a string containing units of information separated by colons,
857    return the next one pointed to by (P_INDEX), or NULL if there are no more.
858    Advance (P_INDEX) to the character after the colon. */
859 char *
860 extract_colon_unit (string, p_index)
861      char *string;
862      int *p_index;
863 {
864   int i, start, len;
865   char *value;
866
867   if (string == 0)
868     return (string);
869
870   len = strlen (string);
871   if (*p_index >= len)
872     return ((char *)NULL);
873
874   i = *p_index;
875
876   /* Each call to this routine leaves the index pointing at a colon if
877      there is more to the path.  If I is > 0, then increment past the
878      `:'.  If I is 0, then the path has a leading colon.  Trailing colons
879      are handled OK by the `else' part of the if statement; an empty
880      string is returned in that case. */
881   if (i && string[i] == ':')
882     i++;
883
884   for (start = i; string[i] && string[i] != ':'; i++)
885     ;
886
887   *p_index = i;
888
889   if (i == start)
890     {
891       if (string[i])
892         (*p_index)++;
893       /* Return "" in the case of a trailing `:'. */
894       value = xmalloc (1);
895       value[0] = '\0';
896     }
897   else
898     {
899       len = i - start;
900       value = xmalloc (1 + len);
901       strncpy (value, string + start, len);
902       value [len] = '\0';
903     }
904
905   return (value);
906 }
907
908 /* **************************************************************** */
909 /*                                                                  */
910 /*                  Tilde Initialization and Expansion              */
911 /*                                                                  */
912 /* **************************************************************** */
913
914 /* If tilde_expand hasn't been able to expand the text, perhaps it
915    is a special shell expansion.  This function is installed as the
916    tilde_expansion_preexpansion_hook.  It knows how to expand ~- and ~+. */
917 static char *
918 bash_special_tilde_expansions (text)
919      char *text;
920 {
921   char *result;
922
923   result = (char *)NULL;
924   if (text[1] == '\0')
925     {
926       if (*text == '+')
927         result = get_string_value ("PWD");
928       else if (*text == '-')
929         result = get_string_value ("OLDPWD");
930     }
931
932   return (result ? savestring (result) : (char *)NULL);
933 }
934
935 /* Initialize the tilde expander.  In Bash, we handle `~-' and `~+', as
936    well as handling special tilde prefixes; `:~" and `=~' are indications
937    that we should do tilde expansion. */
938 void
939 tilde_initialize ()
940 {
941   static int times_called = 0;
942
943   /* Tell the tilde expander that we want a crack first. */
944   tilde_expansion_preexpansion_hook = (CPFunction *)bash_special_tilde_expansions;
945
946   /* Tell the tilde expander about special strings which start a tilde
947      expansion, and the special strings that end one.  Only do this once.
948      tilde_initialize () is called from within bashline_reinitialize (). */
949   if (times_called == 0)
950     {
951       tilde_additional_prefixes = (char **)xmalloc (3 * sizeof (char *));
952       tilde_additional_prefixes[0] = "=~";
953       tilde_additional_prefixes[1] = ":~";
954       tilde_additional_prefixes[2] = (char *)NULL;
955
956       tilde_additional_suffixes = (char **)xmalloc (3 * sizeof (char *));
957       tilde_additional_suffixes[0] = ":";
958       tilde_additional_suffixes[1] = "=~";
959       tilde_additional_suffixes[2] = (char *)NULL;
960     }
961   times_called++;
962 }
963
964 char *
965 bash_tilde_expand (s)
966      char *s;
967 {
968   int old_immed;
969   char *ret;
970
971   old_immed = interrupt_immediately;
972   interrupt_immediately = 1;
973   ret = tilde_expand (s);
974   interrupt_immediately = old_immed;
975   return (ret);
976 }
977
978 /* **************************************************************** */
979 /*                                                                  */
980 /*        Functions to manipulate and search the group list         */
981 /*                                                                  */
982 /* **************************************************************** */
983
984 static int ngroups, maxgroups;
985
986 /* The set of groups that this user is a member of. */
987 static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
988
989 #if !defined (NOGROUP)
990 #  define NOGROUP (gid_t) -1
991 #endif
992
993 #if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
994 #  define getmaxgroups() sysconf(_SC_NGROUPS_MAX)
995 #else
996 #  if defined (NGROUPS_MAX)
997 #    define getmaxgroups() NGROUPS_MAX
998 #  else /* !NGROUPS_MAX */
999 #    if defined (NGROUPS)
1000 #      define getmaxgroups() NGROUPS
1001 #    else /* !NGROUPS */
1002 #      define getmaxgroups() 64
1003 #    endif /* !NGROUPS */
1004 #  endif /* !NGROUPS_MAX */
1005 #endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */
1006
1007 static void
1008 initialize_group_array ()
1009 {
1010   register int i;
1011
1012   if (maxgroups == 0)
1013     maxgroups = getmaxgroups ();
1014
1015   ngroups = 0;
1016   group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
1017
1018 #if defined (HAVE_GETGROUPS)
1019   ngroups = getgroups (maxgroups, group_array);
1020 #endif
1021
1022   /* If getgroups returns nothing, or the OS does not support getgroups(),
1023      make sure the groups array includes at least the current gid. */
1024   if (ngroups == 0)
1025     {
1026       group_array[0] = current_user.gid;
1027       ngroups = 1;
1028     }
1029
1030   /* If the primary group is not in the groups array, add it as group_array[0]
1031      and shuffle everything else up 1, if there's room. */
1032   for (i = 0; i < ngroups; i++)
1033     if (current_user.gid == (gid_t)group_array[i])
1034       break;
1035   if (i == ngroups && ngroups < maxgroups)
1036     {
1037       for (i = ngroups; i > 0; i--)
1038         group_array[i] = group_array[i - 1];
1039       group_array[0] = current_user.gid;
1040       ngroups++;
1041     }
1042 }
1043
1044 /* Return non-zero if GID is one that we have in our groups list. */
1045 int
1046 group_member (gid)
1047      gid_t gid;
1048 {
1049 #if defined (HAVE_GETGROUPS)
1050   register int i;
1051 #endif
1052
1053   /* Short-circuit if possible, maybe saving a call to getgroups(). */
1054   if (gid == current_user.gid || gid == current_user.egid)
1055     return (1);
1056
1057 #if defined (HAVE_GETGROUPS)
1058   if (ngroups == 0)
1059     initialize_group_array ();
1060
1061   /* In case of error, the user loses. */
1062   if (ngroups <= 0)
1063     return (0);
1064
1065   /* Search through the list looking for GID. */
1066   for (i = 0; i < ngroups; i++)
1067     if (gid == (gid_t)group_array[i])
1068       return (1);
1069 #endif
1070
1071   return (0);
1072 }
1073
1074 char **
1075 get_group_list (ngp)
1076      int *ngp;
1077 {
1078   static char **group_vector = (char **)NULL;
1079   register int i;
1080   char *nbuf;
1081
1082   if (group_vector)
1083     {
1084       if (ngp)
1085         *ngp = ngroups;
1086       return group_vector;
1087     }
1088
1089   if (ngroups == 0)
1090     initialize_group_array ();
1091
1092   if (ngroups <= 0)
1093     {
1094       if (ngp)
1095         *ngp = 0;
1096       return (char **)NULL;
1097     }
1098
1099   group_vector = (char **)xmalloc (ngroups * sizeof (char *));
1100   for (i = 0; i < ngroups; i++)
1101     {
1102       nbuf = itos ((int)group_array[i]);
1103       group_vector[i] = nbuf;
1104     }
1105   if (ngp)
1106     *ngp = ngroups;
1107   return group_vector;
1108 }