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