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