]> git.ipfire.org Git - thirdparty/bash.git/blame - general.c
commit bash-20040916 snapshot
[thirdparty/bash.git] / general.c
CommitLineData
726f6388
JA
1/* general.c -- Stuff that is used by all files. */
2
4931aca6 3/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
726f6388
JA
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 it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
bb70624e 19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
726f6388 20
ccc6cda3
JA
21#include "config.h"
22
726f6388 23#include "bashtypes.h"
cce855bc
JA
24#ifndef _MINIX
25# include <sys/param.h>
26#endif
ccc6cda3
JA
27#include "posixstat.h"
28
29#if defined (HAVE_UNISTD_H)
30# include <unistd.h>
31#endif
32
726f6388
JA
33#include "filecntl.h"
34#include "bashansi.h"
ccc6cda3 35#include <stdio.h>
f73dda09 36#include "chartypes.h"
ccc6cda3
JA
37#include <errno.h>
38
5e13499c
CR
39#include "bashintl.h"
40
726f6388 41#include "shell.h"
e6e3b444
CR
42#include "test.h"
43
726f6388
JA
44#include <tilde/tilde.h>
45
726f6388
JA
46#if !defined (errno)
47extern int errno;
48#endif /* !errno */
49
f73dda09 50extern int expand_aliases;
ccc6cda3
JA
51extern int interrupt_immediately;
52extern int interactive_comments;
28ef6c31
JA
53extern int check_hashed_filenames;
54extern int source_uses_path;
55extern int source_searches_cwd;
cce855bc 56
7117c2d2
JA
57static char *bash_special_tilde_expansions __P((char *));
58static int unquoted_tilde_word __P((const char *));
59static void initialize_group_array __P((void));
60
cce855bc 61/* A standard error message to use when getcwd() returns NULL. */
5e13499c 62char *bash_getcwd_errstr = N_("getcwd: cannot access parent directories");
726f6388 63
ccc6cda3 64/* Do whatever is necessary to initialize `Posix mode'. */
726f6388 65void
ccc6cda3
JA
66posix_initialize (on)
67 int on;
726f6388 68{
28ef6c31
JA
69 /* Things that should be turned on when posix mode is enabled. */
70 if (on != 0)
71 {
72 interactive_comments = source_uses_path = expand_aliases = 1;
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 }
726f6388
JA
81}
82
ccc6cda3
JA
83/* **************************************************************** */
84/* */
85/* Functions to convert to and from and display non-standard types */
86/* */
87/* **************************************************************** */
88
726f6388
JA
89#if defined (RLIMTYPE)
90RLIMTYPE
91string_to_rlimtype (s)
92 char *s;
93{
cce855bc
JA
94 RLIMTYPE ret;
95 int neg;
726f6388 96
cce855bc
JA
97 ret = 0;
98 neg = 0;
726f6388
JA
99 while (s && *s && whitespace (*s))
100 s++;
101 if (*s == '-' || *s == '+')
102 {
103 neg = *s == '-';
104 s++;
105 }
f73dda09
JA
106 for ( ; s && *s && DIGIT (*s); s++)
107 ret = (ret * 10) + TODIGIT (*s);
726f6388
JA
108 return (neg ? -ret : ret);
109}
110
111void
112print_rlimtype (n, addnl)
113 RLIMTYPE n;
114 int addnl;
115{
f73dda09 116 char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p;
726f6388 117
f73dda09
JA
118 p = s + sizeof(s);
119 *--p = '\0';
726f6388
JA
120
121 if (n < 0)
122 {
f73dda09
JA
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);
726f6388
JA
134 }
135
f73dda09 136 printf ("%s%s", p, addnl ? "\n" : "");
726f6388
JA
137}
138#endif /* RLIMTYPE */
139
ccc6cda3
JA
140/* **************************************************************** */
141/* */
142/* Input Validation Functions */
143/* */
144/* **************************************************************** */
145
146/* Return non-zero if all of the characters in STRING are digits. */
147int
148all_digits (string)
149 char *string;
150{
28ef6c31
JA
151 register char *s;
152
153 for (s = string; *s; s++)
f73dda09 154 if (DIGIT (*s) == 0)
28ef6c31
JA
155 return (0);
156
ccc6cda3
JA
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
f73dda09 162 not null. */
ccc6cda3
JA
163int
164legal_number (string, result)
165 char *string;
7117c2d2 166 intmax_t *result;
ccc6cda3 167{
7117c2d2 168 intmax_t value;
cce855bc 169 char *ep;
ccc6cda3
JA
170
171 if (result)
172 *result = 0;
173
f73dda09 174 errno = 0;
7117c2d2 175 value = strtoimax (string, &ep, 10);
f73dda09
JA
176 if (errno)
177 return 0; /* errno is set on overflow or underflow */
ccc6cda3 178
7117c2d2 179 /* Skip any trailing whitespace, since strtoimax does not. */
28ef6c31
JA
180 while (whitespace (*ep))
181 ep++;
182
cce855bc
JA
183 /* If *string is not '\0' but *ep is '\0' on return, the entire string
184 is valid. */
185 if (string && *string && *ep == '\0')
ccc6cda3
JA
186 {
187 if (result)
cce855bc
JA
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;
ccc6cda3 193 }
cce855bc
JA
194
195 return (0);
ccc6cda3
JA
196}
197
726f6388
JA
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. */
201int
202legal_identifier (name)
203 char *name;
204{
205 register char *s;
f73dda09 206 unsigned char c;
726f6388 207
f73dda09 208 if (!name || !(c = *name) || (legal_variable_starter (c) == 0))
726f6388
JA
209 return (0);
210
f73dda09 211 for (s = name + 1; (c = *s) != 0; s++)
726f6388 212 {
f73dda09 213 if (legal_variable_char (c) == 0)
28ef6c31 214 return (0);
726f6388
JA
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. */
ccc6cda3 224int
726f6388
JA
225check_identifier (word, check_word)
226 WORD_DESC *word;
227 int check_word;
228{
ccc6cda3 229 if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word))
726f6388 230 {
5e13499c 231 internal_error (_("`%s': not a valid identifier"), word->word);
726f6388
JA
232 return (0);
233 }
234 else if (check_word && legal_identifier (word->word) == 0)
235 {
5e13499c 236 internal_error (_("`%s': not a valid identifier"), word->word);
726f6388
JA
237 return (0);
238 }
239 else
240 return (1);
241}
242
1d7ecd77
CR
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 `/'. */
246int
247legal_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
7117c2d2
JA
259/* Returns non-zero if STRING is an assignment statement. The returned value
260 is the index of the `=' sign. */
261int
5e13499c 262assignment (string, flags)
7117c2d2 263 const char *string;
5e13499c 264 int flags;
7117c2d2
JA
265{
266 register unsigned char c;
267 register int newi, indx;
268
269 c = string[indx = 0];
270
5e13499c
CR
271#if defined (ARRAY_VARS)
272 if ((legal_variable_starter (c) == 0) && (flags && c != '[')) /* ] */
273#else
7117c2d2 274 if (legal_variable_starter (c) == 0)
5e13499c 275#endif
7117c2d2
JA
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 return ((string[newi] == '=') ? newi : 0);
292 }
293#endif /* ARRAY_VARS */
294
295 /* Variable names in assignment statements may contain only letters,
296 digits, and `_'. */
297 if (legal_variable_char (c) == 0)
298 return (0);
299
300 indx++;
301 }
302 return (0);
303}
304
ccc6cda3
JA
305/* **************************************************************** */
306/* */
307/* Functions to manage files and file descriptors */
308/* */
309/* **************************************************************** */
310
726f6388
JA
311/* A function to unset no-delay mode on a file descriptor. Used in shell.c
312 to unset it on the fd passed as stdin. Should be called on stdin if
313 readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */
314
315#if !defined (O_NDELAY)
316# if defined (FNDELAY)
317# define O_NDELAY FNDELAY
318# endif
319#endif /* O_NDELAY */
320
321/* Make sure no-delay mode is not set on file descriptor FD. */
bb70624e 322int
28ef6c31 323sh_unset_nodelay_mode (fd)
726f6388
JA
324 int fd;
325{
bb70624e 326 int flags, bflags;
726f6388
JA
327
328 if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
bb70624e 329 return -1;
726f6388 330
bb70624e 331 bflags = 0;
ccc6cda3
JA
332
333 /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present
334 and O_NDELAY is defined. */
bb70624e
JA
335#ifdef O_NONBLOCK
336 bflags |= O_NONBLOCK;
337#endif
338
339#ifdef O_NDELAY
340 bflags |= O_NDELAY;
341#endif
342
343 if (flags & bflags)
726f6388 344 {
bb70624e
JA
345 flags &= ~bflags;
346 return (fcntl (fd, F_SETFL, flags));
726f6388 347 }
726f6388 348
bb70624e 349 return 0;
726f6388
JA
350}
351
7117c2d2
JA
352/* Return 1 if file descriptor FD is valid; 0 otherwise. */
353int
354sh_validfd (fd)
355 int fd;
356{
357 return (fcntl (fd, F_GETFD, 0) >= 0);
358}
359
b72432fd
JA
360/* There is a bug in the NeXT 2.1 rlogind that causes opens
361 of /dev/tty to fail. */
362
363#if defined (__BEOS__)
364/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it
365 into a no-op. This should probably go away in the future. */
366# undef O_NONBLOCK
367# define O_NONBLOCK 0
368#endif /* __BEOS__ */
369
726f6388 370void
ccc6cda3 371check_dev_tty ()
726f6388 372{
ccc6cda3
JA
373 int tty_fd;
374 char *tty;
726f6388 375
d166f048 376 tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK);
726f6388 377
ccc6cda3 378 if (tty_fd < 0)
726f6388 379 {
ccc6cda3
JA
380 tty = (char *)ttyname (fileno (stdin));
381 if (tty == 0)
382 return;
d166f048 383 tty_fd = open (tty, O_RDWR|O_NONBLOCK);
726f6388 384 }
ccc6cda3 385 close (tty_fd);
726f6388
JA
386}
387
ccc6cda3
JA
388/* Return 1 if PATH1 and PATH2 are the same file. This is kind of
389 expensive. If non-NULL STP1 and STP2 point to stat structures
390 corresponding to PATH1 and PATH2, respectively. */
726f6388 391int
ccc6cda3
JA
392same_file (path1, path2, stp1, stp2)
393 char *path1, *path2;
394 struct stat *stp1, *stp2;
726f6388 395{
ccc6cda3 396 struct stat st1, st2;
726f6388 397
ccc6cda3 398 if (stp1 == NULL)
726f6388 399 {
ccc6cda3
JA
400 if (stat (path1, &st1) != 0)
401 return (0);
402 stp1 = &st1;
726f6388 403 }
726f6388 404
ccc6cda3
JA
405 if (stp2 == NULL)
406 {
407 if (stat (path2, &st2) != 0)
408 return (0);
409 stp2 = &st2;
410 }
726f6388 411
ccc6cda3 412 return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino));
726f6388
JA
413}
414
ccc6cda3
JA
415/* Move FD to a number close to the maximum number of file descriptors
416 allowed in the shell process, to avoid the user stepping on it with
417 redirection and causing us extra work. If CHECK_NEW is non-zero,
418 we check whether or not the file descriptors are in use before
d166f048
JA
419 duplicating FD onto them. MAXFD says where to start checking the
420 file descriptors. If it's less than 20, we get the maximum value
421 available from getdtablesize(2). */
726f6388 422int
d166f048
JA
423move_to_high_fd (fd, check_new, maxfd)
424 int fd, check_new, maxfd;
726f6388 425{
ccc6cda3 426 int script_fd, nfds, ignore;
726f6388 427
d166f048
JA
428 if (maxfd < 20)
429 {
430 nfds = getdtablesize ();
431 if (nfds <= 0)
432 nfds = 20;
7117c2d2
JA
433 if (nfds > HIGH_FD_MAX)
434 nfds = HIGH_FD_MAX; /* reasonable maximum */
d166f048
JA
435 }
436 else
437 nfds = maxfd;
726f6388 438
ccc6cda3
JA
439 for (nfds--; check_new && nfds > 3; nfds--)
440 if (fcntl (nfds, F_GETFD, &ignore) == -1)
441 break;
726f6388 442
7117c2d2 443 if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
ccc6cda3
JA
444 {
445 if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */
446 close (fd);
447 return (script_fd);
448 }
726f6388 449
7117c2d2
JA
450 /* OK, we didn't find one less than our artificial maximum; return the
451 original file descriptor. */
ccc6cda3
JA
452 return (fd);
453}
454
455/* Return non-zero if the characters from SAMPLE are not all valid
456 characters to be found in the first line of a shell script. We
457 check up to the first newline, or SAMPLE_LEN, whichever comes first.
458 All of the characters must be printable or whitespace. */
726f6388 459
726f6388 460int
ccc6cda3 461check_binary_file (sample, sample_len)
f73dda09 462 char *sample;
ccc6cda3 463 int sample_len;
726f6388 464{
ccc6cda3 465 register int i;
f73dda09 466 unsigned char c;
726f6388 467
ccc6cda3
JA
468 for (i = 0; i < sample_len; i++)
469 {
f73dda09
JA
470 c = sample[i];
471 if (c == '\n')
ccc6cda3 472 return (0);
726f6388 473
f73dda09 474 if (ISSPACE (c) == 0 && ISPRINT (c) == 0)
ccc6cda3
JA
475 return (1);
476 }
726f6388 477
ccc6cda3 478 return (0);
726f6388
JA
479}
480
fb65be05
CR
481/* **************************************************************** */
482/* */
483/* Functions to inspect pathnames */
484/* */
485/* **************************************************************** */
486
487int
488file_isdir (fn)
489 char *fn;
490{
491 struct stat sb;
492
493 return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode));
494}
495
496int
497file_iswdir (fn)
498 char *fn;
499{
500 return (file_isdir (fn) && test_eaccess (fn, W_OK) == 0);
501}
502
503
ccc6cda3
JA
504/* **************************************************************** */
505/* */
506/* Functions to manipulate pathnames */
507/* */
508/* **************************************************************** */
726f6388 509
726f6388
JA
510/* Turn STRING (a pathname) into an absolute pathname, assuming that
511 DOT_PATH contains the symbolic location of `.'. This always
512 returns a new string, even if STRING was an absolute pathname to
513 begin with. */
514char *
515make_absolute (string, dot_path)
516 char *string, *dot_path;
517{
518 char *result;
ccc6cda3 519
28ef6c31 520 if (dot_path == 0 || ABSPATH(string))
d3a24ed2
CR
521#ifdef __CYGWIN__
522 {
523 char pathbuf[PATH_MAX + 1];
524
525 cygwin_conv_to_full_posix_path (string, pathbuf);
526 result = savestring (pathbuf);
527 }
528#else
726f6388 529 result = savestring (string);
d3a24ed2 530#endif
726f6388 531 else
bb70624e 532 result = sh_makepath (dot_path, string, 0);
726f6388
JA
533
534 return (result);
535}
536
28ef6c31
JA
537/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd'
538 to decide whether or not to look up a directory name in $CDPATH. */
726f6388
JA
539int
540absolute_pathname (string)
f73dda09 541 const char *string;
726f6388 542{
28ef6c31 543 if (string == 0 || *string == '\0')
726f6388
JA
544 return (0);
545
28ef6c31
JA
546 if (ABSPATH(string))
547 return (1);
548
549 if (string[0] == '.' && PATHSEP(string[1])) /* . and ./ */
550 return (1);
551
552 if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2])) /* .. and ../ */
726f6388
JA
553 return (1);
554
726f6388
JA
555 return (0);
556}
557
558/* Return 1 if STRING is an absolute program name; it is absolute if it
559 contains any slashes. This is used to decide whether or not to look
560 up through $PATH. */
561int
562absolute_program (string)
f73dda09 563 const char *string;
726f6388 564{
7117c2d2 565 return ((char *)xstrchr (string, '/') != (char *)NULL);
726f6388
JA
566}
567
568/* Return the `basename' of the pathname in STRING (the stuff after the
898cc92e 569 last '/'). If STRING is `/', just return it. */
726f6388
JA
570char *
571base_pathname (string)
572 char *string;
573{
574 char *p;
575
898cc92e 576#if 0
28ef6c31 577 if (absolute_pathname (string) == 0)
726f6388 578 return (string);
898cc92e
CR
579#endif
580
581 if (string[0] == '/' && string[1] == 0)
582 return (string);
726f6388
JA
583
584 p = (char *)strrchr (string, '/');
ccc6cda3 585 return (p ? ++p : string);
726f6388
JA
586}
587
588/* Return the full pathname of FILE. Easy. Filenames that begin
589 with a '/' are returned as themselves. Other filenames have
590 the current working directory prepended. A new string is
591 returned in either case. */
592char *
593full_pathname (file)
594 char *file;
595{
bb70624e 596 char *ret;
726f6388 597
7117c2d2 598 file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file);
726f6388 599
28ef6c31 600 if (ABSPATH(file))
726f6388
JA
601 return (file);
602
bb70624e
JA
603 ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT));
604 free (file);
726f6388 605
bb70624e 606 return (ret);
726f6388 607}
726f6388
JA
608
609/* A slightly related function. Get the prettiest name of this
610 directory possible. */
ccc6cda3 611static char tdir[PATH_MAX];
726f6388
JA
612
613/* Return a pretty pathname. If the first part of the pathname is
614 the same as $HOME, then replace that with `~'. */
615char *
616polite_directory_format (name)
617 char *name;
618{
ccc6cda3
JA
619 char *home;
620 int l;
726f6388 621
ccc6cda3
JA
622 home = get_string_value ("HOME");
623 l = home ? strlen (home) : 0;
726f6388
JA
624 if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
625 {
e8ce775d 626 strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
726f6388 627 tdir[0] = '~';
e8ce775d 628 tdir[sizeof(tdir) - 1] = '\0';
726f6388
JA
629 return (tdir);
630 }
631 else
632 return (name);
633}
634
ccc6cda3
JA
635/* Given a string containing units of information separated by colons,
636 return the next one pointed to by (P_INDEX), or NULL if there are no more.
637 Advance (P_INDEX) to the character after the colon. */
638char *
639extract_colon_unit (string, p_index)
640 char *string;
641 int *p_index;
726f6388 642{
ccc6cda3
JA
643 int i, start, len;
644 char *value;
726f6388 645
ccc6cda3
JA
646 if (string == 0)
647 return (string);
726f6388 648
ccc6cda3
JA
649 len = strlen (string);
650 if (*p_index >= len)
651 return ((char *)NULL);
726f6388 652
ccc6cda3 653 i = *p_index;
726f6388 654
ccc6cda3
JA
655 /* Each call to this routine leaves the index pointing at a colon if
656 there is more to the path. If I is > 0, then increment past the
657 `:'. If I is 0, then the path has a leading colon. Trailing colons
658 are handled OK by the `else' part of the if statement; an empty
659 string is returned in that case. */
660 if (i && string[i] == ':')
661 i++;
662
663 for (start = i; string[i] && string[i] != ':'; i++)
664 ;
665
666 *p_index = i;
667
668 if (i == start)
669 {
670 if (string[i])
671 (*p_index)++;
672 /* Return "" in the case of a trailing `:'. */
f73dda09 673 value = (char *)xmalloc (1);
ccc6cda3
JA
674 value[0] = '\0';
675 }
676 else
bb70624e 677 value = substring (string, start, i);
ccc6cda3
JA
678
679 return (value);
726f6388 680}
726f6388
JA
681
682/* **************************************************************** */
683/* */
684/* Tilde Initialization and Expansion */
685/* */
686/* **************************************************************** */
687
cce855bc
JA
688#if defined (PUSHD_AND_POPD)
689extern char *get_dirstack_from_string __P((char *));
690#endif
691
f73dda09
JA
692static char **bash_tilde_prefixes;
693static char **bash_tilde_suffixes;
694
726f6388
JA
695/* If tilde_expand hasn't been able to expand the text, perhaps it
696 is a special shell expansion. This function is installed as the
cce855bc
JA
697 tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+.
698 If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the
699 directory stack. */
726f6388 700static char *
d166f048 701bash_special_tilde_expansions (text)
726f6388
JA
702 char *text;
703{
ccc6cda3 704 char *result;
726f6388 705
ccc6cda3 706 result = (char *)NULL;
cce855bc
JA
707
708 if (text[0] == '+' && text[1] == '\0')
709 result = get_string_value ("PWD");
710 else if (text[0] == '-' && text[1] == '\0')
711 result = get_string_value ("OLDPWD");
712#if defined (PUSHD_AND_POPD)
f73dda09 713 else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1])))
cce855bc
JA
714 result = get_dirstack_from_string (text);
715#endif
726f6388 716
ccc6cda3 717 return (result ? savestring (result) : (char *)NULL);
726f6388
JA
718}
719
720/* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as
721 well as handling special tilde prefixes; `:~" and `=~' are indications
722 that we should do tilde expansion. */
723void
724tilde_initialize ()
725{
726 static int times_called = 0;
727
d166f048 728 /* Tell the tilde expander that we want a crack first. */
f73dda09 729 tilde_expansion_preexpansion_hook = bash_special_tilde_expansions;
726f6388
JA
730
731 /* Tell the tilde expander about special strings which start a tilde
732 expansion, and the special strings that end one. Only do this once.
733 tilde_initialize () is called from within bashline_reinitialize (). */
cce855bc 734 if (times_called++ == 0)
726f6388 735 {
7117c2d2 736 bash_tilde_prefixes = strvec_create (3);
f73dda09
JA
737 bash_tilde_prefixes[0] = "=~";
738 bash_tilde_prefixes[1] = ":~";
739 bash_tilde_prefixes[2] = (char *)NULL;
740
741 tilde_additional_prefixes = bash_tilde_prefixes;
742
7117c2d2 743 bash_tilde_suffixes = strvec_create (3);
f73dda09
JA
744 bash_tilde_suffixes[0] = ":";
745 bash_tilde_suffixes[1] = "=~"; /* XXX - ?? */
746 bash_tilde_suffixes[2] = (char *)NULL;
747
748 tilde_additional_suffixes = bash_tilde_suffixes;
726f6388 749 }
726f6388
JA
750}
751
f73dda09
JA
752/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character
753 at the beginning of the word, followed by all of the characters preceding
754 the first unquoted slash in the word, or all the characters in the word
755 if there is no slash...If none of the characters in the tilde-prefix are
756 quoted, the characters in the tilde-prefix following the tilde shell be
757 treated as a possible login name. */
758
759#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':')
760
761static int
762unquoted_tilde_word (s)
763 const char *s;
764{
765 const char *r;
766
767 for (r = s; TILDE_END(*r) == 0; r++)
768 {
769 switch (*r)
770 {
771 case '\\':
772 case '\'':
773 case '"':
774 return 0;
775 }
776 }
777 return 1;
778}
779
7117c2d2
JA
780/* Tilde-expand S by running it through the tilde expansion library.
781 ASSIGN_P is 1 if this is a variable assignment, so the alternate
782 tilde prefixes should be enabled (`=~' and `:~', see above). */
ccc6cda3 783char *
7117c2d2 784bash_tilde_expand (s, assign_p)
f73dda09 785 const char *s;
7117c2d2 786 int assign_p;
726f6388 787{
f73dda09 788 int old_immed, r;
ccc6cda3 789 char *ret;
726f6388 790
ccc6cda3
JA
791 old_immed = interrupt_immediately;
792 interrupt_immediately = 1;
7117c2d2 793 tilde_additional_prefixes = assign_p ? bash_tilde_prefixes : (char **)0;
f73dda09
JA
794 r = (*s == '~') ? unquoted_tilde_word (s) : 1;
795 ret = r ? tilde_expand (s) : savestring (s);
ccc6cda3
JA
796 interrupt_immediately = old_immed;
797 return (ret);
726f6388 798}
d166f048
JA
799
800/* **************************************************************** */
801/* */
802/* Functions to manipulate and search the group list */
803/* */
804/* **************************************************************** */
805
806static int ngroups, maxgroups;
807
808/* The set of groups that this user is a member of. */
809static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
810
811#if !defined (NOGROUP)
812# define NOGROUP (gid_t) -1
813#endif
814
d166f048
JA
815static void
816initialize_group_array ()
817{
818 register int i;
819
820 if (maxgroups == 0)
821 maxgroups = getmaxgroups ();
822
823 ngroups = 0;
824 group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
825
826#if defined (HAVE_GETGROUPS)
827 ngroups = getgroups (maxgroups, group_array);
828#endif
829
830 /* If getgroups returns nothing, or the OS does not support getgroups(),
831 make sure the groups array includes at least the current gid. */
832 if (ngroups == 0)
833 {
834 group_array[0] = current_user.gid;
835 ngroups = 1;
836 }
837
838 /* If the primary group is not in the groups array, add it as group_array[0]
839 and shuffle everything else up 1, if there's room. */
840 for (i = 0; i < ngroups; i++)
841 if (current_user.gid == (gid_t)group_array[i])
842 break;
843 if (i == ngroups && ngroups < maxgroups)
844 {
845 for (i = ngroups; i > 0; i--)
28ef6c31 846 group_array[i] = group_array[i - 1];
d166f048
JA
847 group_array[0] = current_user.gid;
848 ngroups++;
849 }
cce855bc
JA
850
851 /* If the primary group is not group_array[0], swap group_array[0] and
852 whatever the current group is. The vast majority of systems should
853 not need this; a notable exception is Linux. */
854 if (group_array[0] != current_user.gid)
855 {
856 for (i = 0; i < ngroups; i++)
28ef6c31
JA
857 if (group_array[i] == current_user.gid)
858 break;
cce855bc
JA
859 if (i < ngroups)
860 {
861 group_array[i] = group_array[0];
862 group_array[0] = current_user.gid;
863 }
864 }
d166f048
JA
865}
866
867/* Return non-zero if GID is one that we have in our groups list. */
868int
cce855bc
JA
869#if defined (__STDC__) || defined ( _MINIX)
870group_member (gid_t gid)
871#else
d166f048
JA
872group_member (gid)
873 gid_t gid;
cce855bc 874#endif /* !__STDC__ && !_MINIX */
d166f048
JA
875{
876#if defined (HAVE_GETGROUPS)
877 register int i;
878#endif
879
880 /* Short-circuit if possible, maybe saving a call to getgroups(). */
881 if (gid == current_user.gid || gid == current_user.egid)
882 return (1);
883
884#if defined (HAVE_GETGROUPS)
885 if (ngroups == 0)
886 initialize_group_array ();
887
888 /* In case of error, the user loses. */
889 if (ngroups <= 0)
890 return (0);
891
892 /* Search through the list looking for GID. */
893 for (i = 0; i < ngroups; i++)
894 if (gid == (gid_t)group_array[i])
895 return (1);
896#endif
897
898 return (0);
899}
900
901char **
902get_group_list (ngp)
903 int *ngp;
904{
905 static char **group_vector = (char **)NULL;
906 register int i;
d166f048
JA
907
908 if (group_vector)
909 {
910 if (ngp)
911 *ngp = ngroups;
912 return group_vector;
913 }
914
915 if (ngroups == 0)
916 initialize_group_array ();
917
918 if (ngroups <= 0)
919 {
920 if (ngp)
921 *ngp = 0;
922 return (char **)NULL;
923 }
924
7117c2d2 925 group_vector = strvec_create (ngroups);
d166f048 926 for (i = 0; i < ngroups; i++)
7117c2d2 927 group_vector[i] = itos (group_array[i]);
b72432fd 928
d166f048
JA
929 if (ngp)
930 *ngp = ngroups;
931 return group_vector;
932}
b72432fd
JA
933
934int *
935get_group_array (ngp)
936 int *ngp;
937{
938 int i;
939 static int *group_iarray = (int *)NULL;
940
941 if (group_iarray)
942 {
943 if (ngp)
944 *ngp = ngroups;
945 return (group_iarray);
946 }
947
948 if (ngroups == 0)
949 initialize_group_array ();
950
951 if (ngroups <= 0)
952 {
953 if (ngp)
954 *ngp = 0;
955 return (int *)NULL;
956 }
957
958 group_iarray = (int *)xmalloc (ngroups * sizeof (int));
959 for (i = 0; i < ngroups; i++)
960 group_iarray[i] = (int)group_array[i];
961
962 if (ngp)
963 *ngp = ngroups;
964 return group_iarray;
965}