Imported from ../bash-2.01.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       strcpy (tdir + 1, name + l);
848       tdir[0] = '~';
849       return (tdir);
850     }
851   else
852     return (name);
853 }
854
855 /* Given a string containing units of information separated by colons,
856    return the next one pointed to by (P_INDEX), or NULL if there are no more.
857    Advance (P_INDEX) to the character after the colon. */
858 char *
859 extract_colon_unit (string, p_index)
860      char *string;
861      int *p_index;
862 {
863   int i, start, len;
864   char *value;
865
866   if (string == 0)
867     return (string);
868
869   len = strlen (string);
870   if (*p_index >= len)
871     return ((char *)NULL);
872
873   i = *p_index;
874
875   /* Each call to this routine leaves the index pointing at a colon if
876      there is more to the path.  If I is > 0, then increment past the
877      `:'.  If I is 0, then the path has a leading colon.  Trailing colons
878      are handled OK by the `else' part of the if statement; an empty
879      string is returned in that case. */
880   if (i && string[i] == ':')
881     i++;
882
883   for (start = i; string[i] && string[i] != ':'; i++)
884     ;
885
886   *p_index = i;
887
888   if (i == start)
889     {
890       if (string[i])
891         (*p_index)++;
892       /* Return "" in the case of a trailing `:'. */
893       value = xmalloc (1);
894       value[0] = '\0';
895     }
896   else
897     {
898       len = i - start;
899       value = xmalloc (1 + len);
900       strncpy (value, string + start, len);
901       value [len] = '\0';
902     }
903
904   return (value);
905 }
906
907 /* **************************************************************** */
908 /*                                                                  */
909 /*                  Tilde Initialization and Expansion              */
910 /*                                                                  */
911 /* **************************************************************** */
912
913 /* If tilde_expand hasn't been able to expand the text, perhaps it
914    is a special shell expansion.  This function is installed as the
915    tilde_expansion_preexpansion_hook.  It knows how to expand ~- and ~+. */
916 static char *
917 bash_special_tilde_expansions (text)
918      char *text;
919 {
920   char *result;
921
922   result = (char *)NULL;
923   if (text[1] == '\0')
924     {
925       if (*text == '+')
926         result = get_string_value ("PWD");
927       else if (*text == '-')
928         result = get_string_value ("OLDPWD");
929     }
930
931   return (result ? savestring (result) : (char *)NULL);
932 }
933
934 /* Initialize the tilde expander.  In Bash, we handle `~-' and `~+', as
935    well as handling special tilde prefixes; `:~" and `=~' are indications
936    that we should do tilde expansion. */
937 void
938 tilde_initialize ()
939 {
940   static int times_called = 0;
941
942   /* Tell the tilde expander that we want a crack first. */
943   tilde_expansion_preexpansion_hook = (CPFunction *)bash_special_tilde_expansions;
944
945   /* Tell the tilde expander about special strings which start a tilde
946      expansion, and the special strings that end one.  Only do this once.
947      tilde_initialize () is called from within bashline_reinitialize (). */
948   if (times_called == 0)
949     {
950       tilde_additional_prefixes = (char **)xmalloc (3 * sizeof (char *));
951       tilde_additional_prefixes[0] = "=~";
952       tilde_additional_prefixes[1] = ":~";
953       tilde_additional_prefixes[2] = (char *)NULL;
954
955       tilde_additional_suffixes = (char **)xmalloc (3 * sizeof (char *));
956       tilde_additional_suffixes[0] = ":";
957       tilde_additional_suffixes[1] = "=~";
958       tilde_additional_suffixes[2] = (char *)NULL;
959     }
960   times_called++;
961 }
962
963 char *
964 bash_tilde_expand (s)
965      char *s;
966 {
967   int old_immed;
968   char *ret;
969
970   old_immed = interrupt_immediately;
971   interrupt_immediately = 1;
972   ret = tilde_expand (s);
973   interrupt_immediately = old_immed;
974   return (ret);
975 }
976
977 /* **************************************************************** */
978 /*                                                                  */
979 /*        Functions to manipulate and search the group list         */
980 /*                                                                  */
981 /* **************************************************************** */
982
983 static int ngroups, maxgroups;
984
985 /* The set of groups that this user is a member of. */
986 static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
987
988 #if !defined (NOGROUP)
989 #  define NOGROUP (gid_t) -1
990 #endif
991
992 #if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
993 #  define getmaxgroups() sysconf(_SC_NGROUPS_MAX)
994 #else
995 #  if defined (NGROUPS_MAX)
996 #    define getmaxgroups() NGROUPS_MAX
997 #  else /* !NGROUPS_MAX */
998 #    if defined (NGROUPS)
999 #      define getmaxgroups() NGROUPS
1000 #    else /* !NGROUPS */
1001 #      define getmaxgroups() 64
1002 #    endif /* !NGROUPS */
1003 #  endif /* !NGROUPS_MAX */
1004 #endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */
1005
1006 static void
1007 initialize_group_array ()
1008 {
1009   register int i;
1010
1011   if (maxgroups == 0)
1012     maxgroups = getmaxgroups ();
1013
1014   ngroups = 0;
1015   group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
1016
1017 #if defined (HAVE_GETGROUPS)
1018   ngroups = getgroups (maxgroups, group_array);
1019 #endif
1020
1021   /* If getgroups returns nothing, or the OS does not support getgroups(),
1022      make sure the groups array includes at least the current gid. */
1023   if (ngroups == 0)
1024     {
1025       group_array[0] = current_user.gid;
1026       ngroups = 1;
1027     }
1028
1029   /* If the primary group is not in the groups array, add it as group_array[0]
1030      and shuffle everything else up 1, if there's room. */
1031   for (i = 0; i < ngroups; i++)
1032     if (current_user.gid == (gid_t)group_array[i])
1033       break;
1034   if (i == ngroups && ngroups < maxgroups)
1035     {
1036       for (i = ngroups; i > 0; i--)
1037         group_array[i] = group_array[i - 1];
1038       group_array[0] = current_user.gid;
1039       ngroups++;
1040     }
1041 }
1042
1043 /* Return non-zero if GID is one that we have in our groups list. */
1044 int
1045 group_member (gid)
1046      gid_t gid;
1047 {
1048 #if defined (HAVE_GETGROUPS)
1049   register int i;
1050 #endif
1051
1052   /* Short-circuit if possible, maybe saving a call to getgroups(). */
1053   if (gid == current_user.gid || gid == current_user.egid)
1054     return (1);
1055
1056 #if defined (HAVE_GETGROUPS)
1057   if (ngroups == 0)
1058     initialize_group_array ();
1059
1060   /* In case of error, the user loses. */
1061   if (ngroups <= 0)
1062     return (0);
1063
1064   /* Search through the list looking for GID. */
1065   for (i = 0; i < ngroups; i++)
1066     if (gid == (gid_t)group_array[i])
1067       return (1);
1068 #endif
1069
1070   return (0);
1071 }
1072
1073 char **
1074 get_group_list (ngp)
1075      int *ngp;
1076 {
1077   static char **group_vector = (char **)NULL;
1078   register int i;
1079   char *nbuf;
1080
1081   if (group_vector)
1082     {
1083       if (ngp)
1084         *ngp = ngroups;
1085       return group_vector;
1086     }
1087
1088   if (ngroups == 0)
1089     initialize_group_array ();
1090
1091   if (ngroups <= 0)
1092     {
1093       if (ngp)
1094         *ngp = 0;
1095       return (char **)NULL;
1096     }
1097
1098   group_vector = (char **)xmalloc (ngroups * sizeof (char *));
1099   for (i = 0; i < ngroups; i++)
1100     {
1101       nbuf = itos ((int)group_array[i]);
1102       group_vector[i] = nbuf;
1103     }
1104   if (ngp)
1105     *ngp = ngroups;
1106   return group_vector;
1107 }