]> git.ipfire.org Git - thirdparty/bash.git/blame - general.c
commit bash-20041101 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 271#if defined (ARRAY_VARS)
c3271763 272 if ((legal_variable_starter (c) == 0) && (flags == 0 || c != '[')) /* ] */
5e13499c 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 692static char **bash_tilde_prefixes;
22e63b05 693static char **bash_tilde_prefixes2;
f73dda09 694static char **bash_tilde_suffixes;
22e63b05 695static char **bash_tilde_suffixes2;
f73dda09 696
726f6388
JA
697/* If tilde_expand hasn't been able to expand the text, perhaps it
698 is a special shell expansion. This function is installed as the
cce855bc
JA
699 tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+.
700 If PUSHD_AND_POPD is defined, ~[+-]N expands to directories from the
701 directory stack. */
726f6388 702static char *
d166f048 703bash_special_tilde_expansions (text)
726f6388
JA
704 char *text;
705{
ccc6cda3 706 char *result;
726f6388 707
ccc6cda3 708 result = (char *)NULL;
cce855bc
JA
709
710 if (text[0] == '+' && text[1] == '\0')
711 result = get_string_value ("PWD");
712 else if (text[0] == '-' && text[1] == '\0')
713 result = get_string_value ("OLDPWD");
714#if defined (PUSHD_AND_POPD)
f73dda09 715 else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1])))
cce855bc
JA
716 result = get_dirstack_from_string (text);
717#endif
726f6388 718
ccc6cda3 719 return (result ? savestring (result) : (char *)NULL);
726f6388
JA
720}
721
722/* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as
723 well as handling special tilde prefixes; `:~" and `=~' are indications
724 that we should do tilde expansion. */
725void
726tilde_initialize ()
727{
728 static int times_called = 0;
729
d166f048 730 /* Tell the tilde expander that we want a crack first. */
f73dda09 731 tilde_expansion_preexpansion_hook = bash_special_tilde_expansions;
726f6388
JA
732
733 /* Tell the tilde expander about special strings which start a tilde
734 expansion, and the special strings that end one. Only do this once.
735 tilde_initialize () is called from within bashline_reinitialize (). */
cce855bc 736 if (times_called++ == 0)
726f6388 737 {
7117c2d2 738 bash_tilde_prefixes = strvec_create (3);
f73dda09
JA
739 bash_tilde_prefixes[0] = "=~";
740 bash_tilde_prefixes[1] = ":~";
741 bash_tilde_prefixes[2] = (char *)NULL;
742
22e63b05
CR
743 bash_tilde_prefixes2 = strvec_create (2);
744 bash_tilde_prefixes2[0] = ":~";
745 bash_tilde_prefixes2[1] = (char *)NULL;
746
f73dda09
JA
747 tilde_additional_prefixes = bash_tilde_prefixes;
748
7117c2d2 749 bash_tilde_suffixes = strvec_create (3);
f73dda09
JA
750 bash_tilde_suffixes[0] = ":";
751 bash_tilde_suffixes[1] = "=~"; /* XXX - ?? */
752 bash_tilde_suffixes[2] = (char *)NULL;
753
754 tilde_additional_suffixes = bash_tilde_suffixes;
22e63b05
CR
755
756 bash_tilde_suffixes2 = strvec_create (2);
757 bash_tilde_suffixes2[0] = ":";
758 bash_tilde_suffixes2[1] = (char *)NULL;
726f6388 759 }
726f6388
JA
760}
761
f73dda09
JA
762/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character
763 at the beginning of the word, followed by all of the characters preceding
764 the first unquoted slash in the word, or all the characters in the word
765 if there is no slash...If none of the characters in the tilde-prefix are
766 quoted, the characters in the tilde-prefix following the tilde shell be
767 treated as a possible login name. */
768
769#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':')
770
771static int
772unquoted_tilde_word (s)
773 const char *s;
774{
775 const char *r;
776
777 for (r = s; TILDE_END(*r) == 0; r++)
778 {
779 switch (*r)
780 {
781 case '\\':
782 case '\'':
783 case '"':
784 return 0;
785 }
786 }
787 return 1;
788}
789
22e63b05
CR
790/* Find the end of the tilde-prefix starting at S, and return the tilde
791 prefix in newly-allocated memory. Return the length of the string in
792 *LENP. FLAGS tells whether or not we're in an assignment context --
793 if so, `:' delimits the end of the tilde prefix as well. */
794char *
795bash_tilde_find_word (s, flags, lenp)
796 const char *s;
797 int flags, *lenp;
798{
799 const char *r;
800 char *ret;
801 int l;
802
803 for (r = s; *r && *r != '/'; r++)
804 {
805 /* Short-circuit immediately if we see a quote character. Even though
806 POSIX says that `the first unquoted slash' (or `:') terminates the
807 tilde-prefix, in practice, any quoted portion of the tilde prefix
808 will cause it to not be expanded. */
809 if (*r == '\\' || *r == '\'' || *r == '"')
810 {
811 ret = savestring (s);
812 if (lenp)
813 *lenp = 0;
814 return ret;
815 }
816 else if (flags && *r == ':')
817 break;
818 }
819 l = r - s;
820 ret = xmalloc (l + 1);
821 strncpy (ret, s, l);
822 ret[l] = '\0';
823 if (lenp)
824 *lenp = l;
825 return ret;
826}
827
7117c2d2
JA
828/* Tilde-expand S by running it through the tilde expansion library.
829 ASSIGN_P is 1 if this is a variable assignment, so the alternate
22e63b05
CR
830 tilde prefixes should be enabled (`=~' and `:~', see above). If
831 ASSIGN_P is 2, we are expanding the rhs of an assignment statement,
832 so `=~' is not valid. */
ccc6cda3 833char *
7117c2d2 834bash_tilde_expand (s, assign_p)
f73dda09 835 const char *s;
7117c2d2 836 int assign_p;
726f6388 837{
f73dda09 838 int old_immed, r;
ccc6cda3 839 char *ret;
726f6388 840
ccc6cda3
JA
841 old_immed = interrupt_immediately;
842 interrupt_immediately = 1;
22e63b05
CR
843
844 tilde_additional_prefixes = assign_p == 0 ? (char **)0
845 : (assign_p == 2 ? bash_tilde_prefixes2 : bash_tilde_prefixes);
846 if (assign_p == 2)
847 tilde_additional_suffixes = bash_tilde_suffixes2;
848
f73dda09
JA
849 r = (*s == '~') ? unquoted_tilde_word (s) : 1;
850 ret = r ? tilde_expand (s) : savestring (s);
ccc6cda3
JA
851 interrupt_immediately = old_immed;
852 return (ret);
726f6388 853}
d166f048
JA
854
855/* **************************************************************** */
856/* */
857/* Functions to manipulate and search the group list */
858/* */
859/* **************************************************************** */
860
861static int ngroups, maxgroups;
862
863/* The set of groups that this user is a member of. */
864static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
865
866#if !defined (NOGROUP)
867# define NOGROUP (gid_t) -1
868#endif
869
d166f048
JA
870static void
871initialize_group_array ()
872{
873 register int i;
874
875 if (maxgroups == 0)
876 maxgroups = getmaxgroups ();
877
878 ngroups = 0;
879 group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
880
881#if defined (HAVE_GETGROUPS)
882 ngroups = getgroups (maxgroups, group_array);
883#endif
884
885 /* If getgroups returns nothing, or the OS does not support getgroups(),
886 make sure the groups array includes at least the current gid. */
887 if (ngroups == 0)
888 {
889 group_array[0] = current_user.gid;
890 ngroups = 1;
891 }
892
893 /* If the primary group is not in the groups array, add it as group_array[0]
894 and shuffle everything else up 1, if there's room. */
895 for (i = 0; i < ngroups; i++)
896 if (current_user.gid == (gid_t)group_array[i])
897 break;
898 if (i == ngroups && ngroups < maxgroups)
899 {
900 for (i = ngroups; i > 0; i--)
28ef6c31 901 group_array[i] = group_array[i - 1];
d166f048
JA
902 group_array[0] = current_user.gid;
903 ngroups++;
904 }
cce855bc
JA
905
906 /* If the primary group is not group_array[0], swap group_array[0] and
907 whatever the current group is. The vast majority of systems should
908 not need this; a notable exception is Linux. */
909 if (group_array[0] != current_user.gid)
910 {
911 for (i = 0; i < ngroups; i++)
28ef6c31
JA
912 if (group_array[i] == current_user.gid)
913 break;
cce855bc
JA
914 if (i < ngroups)
915 {
916 group_array[i] = group_array[0];
917 group_array[0] = current_user.gid;
918 }
919 }
d166f048
JA
920}
921
922/* Return non-zero if GID is one that we have in our groups list. */
923int
cce855bc
JA
924#if defined (__STDC__) || defined ( _MINIX)
925group_member (gid_t gid)
926#else
d166f048
JA
927group_member (gid)
928 gid_t gid;
cce855bc 929#endif /* !__STDC__ && !_MINIX */
d166f048
JA
930{
931#if defined (HAVE_GETGROUPS)
932 register int i;
933#endif
934
935 /* Short-circuit if possible, maybe saving a call to getgroups(). */
936 if (gid == current_user.gid || gid == current_user.egid)
937 return (1);
938
939#if defined (HAVE_GETGROUPS)
940 if (ngroups == 0)
941 initialize_group_array ();
942
943 /* In case of error, the user loses. */
944 if (ngroups <= 0)
945 return (0);
946
947 /* Search through the list looking for GID. */
948 for (i = 0; i < ngroups; i++)
949 if (gid == (gid_t)group_array[i])
950 return (1);
951#endif
952
953 return (0);
954}
955
956char **
957get_group_list (ngp)
958 int *ngp;
959{
960 static char **group_vector = (char **)NULL;
961 register int i;
d166f048
JA
962
963 if (group_vector)
964 {
965 if (ngp)
966 *ngp = ngroups;
967 return group_vector;
968 }
969
970 if (ngroups == 0)
971 initialize_group_array ();
972
973 if (ngroups <= 0)
974 {
975 if (ngp)
976 *ngp = 0;
977 return (char **)NULL;
978 }
979
7117c2d2 980 group_vector = strvec_create (ngroups);
d166f048 981 for (i = 0; i < ngroups; i++)
7117c2d2 982 group_vector[i] = itos (group_array[i]);
b72432fd 983
d166f048
JA
984 if (ngp)
985 *ngp = ngroups;
986 return group_vector;
987}
b72432fd
JA
988
989int *
990get_group_array (ngp)
991 int *ngp;
992{
993 int i;
994 static int *group_iarray = (int *)NULL;
995
996 if (group_iarray)
997 {
998 if (ngp)
999 *ngp = ngroups;
1000 return (group_iarray);
1001 }
1002
1003 if (ngroups == 0)
1004 initialize_group_array ();
1005
1006 if (ngroups <= 0)
1007 {
1008 if (ngp)
1009 *ngp = 0;
1010 return (int *)NULL;
1011 }
1012
1013 group_iarray = (int *)xmalloc (ngroups * sizeof (int));
1014 for (i = 0; i < ngroups; i++)
1015 group_iarray[i] = (int)group_array[i];
1016
1017 if (ngp)
1018 *ngp = ngroups;
1019 return group_iarray;
1020}