]> git.ipfire.org Git - thirdparty/bash.git/blob - general.c
Imported from ../bash-2.0.tar.gz.
[thirdparty/bash.git] / general.c
1 /* general.c -- Stuff that is used by all files. */
2
3 /* Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992
4 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22 #include "config.h"
23
24 #include "bashtypes.h"
25 #include <sys/param.h>
26 #include "posixstat.h"
27
28 #if defined (HAVE_UNISTD_H)
29 # include <unistd.h>
30 #endif
31
32 #include "filecntl.h"
33 #include "bashansi.h"
34 #include <stdio.h>
35 #include <ctype.h>
36 #include <errno.h>
37
38 #include "shell.h"
39 #include <tilde/tilde.h>
40
41 #if defined (TIME_WITH_SYS_TIME)
42 # include <sys/time.h>
43 # include <time.h>
44 #else
45 # if defined (HAVE_SYS_TIME_H)
46 # include <sys/time.h>
47 # else
48 # include <time.h>
49 # endif
50 #endif
51
52 #include <sys/times.h>
53 #include "maxpath.h"
54
55 #if !defined (errno)
56 extern int errno;
57 #endif /* !errno */
58
59 #ifndef to_upper
60 # define to_upper(c) (islower(c) ? toupper(c) : (c))
61 # define to_lower(c) (isupper(c) ? tolower(c) : (c))
62 #endif
63
64 extern int interrupt_immediately;
65 extern int interactive_comments;
66 extern char *bash_getcwd_errstr;
67
68 /* Do whatever is necessary to initialize `Posix mode'. */
69 void
70 posix_initialize (on)
71 int on;
72 {
73 interactive_comments = on != 0;
74 }
75
76 /* **************************************************************** */
77 /* */
78 /* Integer to String Conversion */
79 /* */
80 /* **************************************************************** */
81
82 /* Number of characters that can appear in a string representation
83 of an integer. 32 is larger than the string rep of 2^^31 - 1. */
84 #define MAX_INT_LEN 32
85
86 /* Integer to string conversion. This conses the string; the
87 caller should free it. */
88 char *
89 itos (i)
90 int i;
91 {
92 char *buf, *p, *ret;
93 int negative = 0;
94 unsigned int ui;
95
96 buf = xmalloc (MAX_INT_LEN);
97
98 if (i < 0)
99 {
100 negative++;
101 i = -i;
102 }
103
104 ui = (unsigned int) i;
105
106 p = buf + MAX_INT_LEN - 2;
107 p[1] = '\0';
108
109 do
110 *p-- = (ui % 10) + '0';
111 while (ui /= 10);
112
113 if (negative)
114 *p-- = '-';
115
116 ret = savestring (p + 1);
117 free (buf);
118 return (ret);
119 }
120
121 /* atol(3) is not universal */
122 long
123 string_to_long (s)
124 char *s;
125 {
126 long ret = 0L;
127 int neg = 0;
128
129 while (s && *s && whitespace (*s))
130 s++;
131 if (*s == '-' || *s == '+')
132 {
133 neg = *s == '-';
134 s++;
135 }
136 for ( ; s && *s && digit (*s); s++)
137 ret = (ret * 10) + digit_value (*s);
138 return (neg ? -ret : ret);
139 }
140
141 /* **************************************************************** */
142 /* */
143 /* Functions to convert to and from and display non-standard types */
144 /* */
145 /* **************************************************************** */
146
147 #if defined (RLIMTYPE)
148 RLIMTYPE
149 string_to_rlimtype (s)
150 char *s;
151 {
152 RLIMTYPE ret = 0;
153 int neg = 0;
154
155 while (s && *s && whitespace (*s))
156 s++;
157 if (*s == '-' || *s == '+')
158 {
159 neg = *s == '-';
160 s++;
161 }
162 for ( ; s && *s && digit (*s); s++)
163 ret = (ret * 10) + digit_value (*s);
164 return (neg ? -ret : ret);
165 }
166
167 void
168 print_rlimtype (n, addnl)
169 RLIMTYPE n;
170 int addnl;
171 {
172 char s[sizeof (RLIMTYPE) * 3 + 1];
173 int len = sizeof (RLIMTYPE) * 3 + 1;
174
175 if (n == 0)
176 {
177 printf ("0%s", addnl ? "\n" : "");
178 return;
179 }
180
181 if (n < 0)
182 {
183 putchar ('-');
184 n = -n;
185 }
186
187 s[--len] = '\0';
188 for ( ; n != 0; n /= 10)
189 s[--len] = n % 10 + '0';
190 printf ("%s%s", s + len, addnl ? "\n" : "");
191 }
192 #endif /* RLIMTYPE */
193
194 #if defined (HAVE_TIMEVAL)
195 /* Convert a pointer to a struct timeval to seconds and thousandths of a
196 second, returning the values in *SP and *SFP, respectively. This does
197 rounding on the fractional part, not just truncation to three places. */
198 void
199 timeval_to_secs (tvp, sp, sfp)
200 struct timeval *tvp;
201 long *sp;
202 int *sfp;
203 {
204 int rest;
205
206 *sp = tvp->tv_sec;
207
208 *sfp = tvp->tv_usec % 1000000; /* pretty much a no-op */
209 rest = *sfp % 1000;
210 *sfp = (*sfp * 1000) / 1000000;
211 if (rest >= 500)
212 *sfp += 1;
213 }
214
215 /* Print the contents of a struct timeval * in a standard way to stdio
216 stream FP. */
217 void
218 print_timeval (fp, tvp)
219 FILE *fp;
220 struct timeval *tvp;
221 {
222 int minutes, seconds_fraction;
223 long seconds;
224
225 timeval_to_secs (tvp, &seconds, &seconds_fraction);
226
227 minutes = seconds / 60;
228 seconds %= 60;
229
230 fprintf (fp, "%0dm%0ld.%03ds", minutes, seconds, seconds_fraction);
231 }
232 #endif /* HAVE_TIMEVAL */
233
234 #if defined (HAVE_TIMES)
235 void
236 clock_t_to_secs (t, sp, sfp)
237 clock_t t;
238 long *sp;
239 int *sfp;
240 {
241 static long clk_tck = 0;
242
243 if (clk_tck == 0)
244 clk_tck = get_clk_tck ();
245
246 *sfp = t % clk_tck;
247 *sfp = (*sfp * 1000) / clk_tck;
248
249 *sp = t / clk_tck;
250 }
251
252 /* Print the time defined by a time_t (returned by the `times' and `time'
253 system calls) in a standard way to stdion stream FP. This is scaled in
254 terms of HZ, which is what is returned by the `times' call. */
255 void
256 print_time_in_hz (fp, t)
257 FILE *fp;
258 clock_t t;
259 {
260 int minutes, seconds_fraction;
261 long seconds;
262
263 clock_t_to_secs (t, &seconds, &seconds_fraction);
264
265 minutes = seconds / 60;
266 seconds %= 60;
267
268 fprintf (fp, "%0dm%0ld.%03ds", minutes, seconds, seconds_fraction);
269 }
270 #endif /* HAVE_TIMES */
271
272 /* **************************************************************** */
273 /* */
274 /* Input Validation Functions */
275 /* */
276 /* **************************************************************** */
277
278 /* Return non-zero if all of the characters in STRING are digits. */
279 int
280 all_digits (string)
281 char *string;
282 {
283 while (*string)
284 {
285 if (!digit (*string))
286 return (0);
287 else
288 string++;
289 }
290 return (1);
291 }
292
293 /* Return non-zero if the characters pointed to by STRING constitute a
294 valid number. Stuff the converted number into RESULT if RESULT is
295 a non-null pointer to a long. */
296 int
297 legal_number (string, result)
298 char *string;
299 long *result;
300 {
301 int sign;
302 long value;
303
304 sign = 1;
305 value = 0;
306
307 if (result)
308 *result = 0;
309
310 /* Skip leading whitespace characters. */
311 while (whitespace (*string))
312 string++;
313
314 if (!*string)
315 return (0);
316
317 /* We allow leading `-' or `+'. */
318 if (*string == '-' || *string == '+')
319 {
320 if (!digit (string[1]))
321 return (0);
322
323 if (*string == '-')
324 sign = -1;
325
326 string++;
327 }
328
329 while (digit (*string))
330 {
331 if (result)
332 value = (value * 10) + digit_value (*string);
333 string++;
334 }
335
336 /* Skip trailing whitespace, if any. */
337 while (whitespace (*string))
338 string++;
339
340 /* Error if not at end of string. */
341 if (*string)
342 return (0);
343
344 if (result)
345 *result = value * sign;
346
347 return (1);
348 }
349
350 /* Return 1 if this token is a legal shell `identifier'; that is, it consists
351 solely of letters, digits, and underscores, and does not begin with a
352 digit. */
353 int
354 legal_identifier (name)
355 char *name;
356 {
357 register char *s;
358
359 if (!name || !*name || (legal_variable_starter (*name) == 0))
360 return (0);
361
362 for (s = name + 1; *s; s++)
363 {
364 if (legal_variable_char (*s) == 0)
365 return (0);
366 }
367 return (1);
368 }
369
370 /* Make sure that WORD is a valid shell identifier, i.e.
371 does not contain a dollar sign, nor is quoted in any way. Nor
372 does it consist of all digits. If CHECK_WORD is non-zero,
373 the word is checked to ensure that it consists of only letters,
374 digits, and underscores. */
375 int
376 check_identifier (word, check_word)
377 WORD_DESC *word;
378 int check_word;
379 {
380 if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word))
381 {
382 internal_error ("`%s': not a valid identifier", word->word);
383 return (0);
384 }
385 else if (check_word && legal_identifier (word->word) == 0)
386 {
387 internal_error ("`%s': not a valid identifier", word->word);
388 return (0);
389 }
390 else
391 return (1);
392 }
393
394 /* **************************************************************** */
395 /* */
396 /* Functions to manage files and file descriptors */
397 /* */
398 /* **************************************************************** */
399
400 /* A function to unset no-delay mode on a file descriptor. Used in shell.c
401 to unset it on the fd passed as stdin. Should be called on stdin if
402 readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */
403
404 #if !defined (O_NDELAY)
405 # if defined (FNDELAY)
406 # define O_NDELAY FNDELAY
407 # endif
408 #endif /* O_NDELAY */
409
410 /* Make sure no-delay mode is not set on file descriptor FD. */
411 void
412 unset_nodelay_mode (fd)
413 int fd;
414 {
415 int flags, set;
416
417 if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
418 return;
419
420 set = 0;
421
422 /* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present
423 and O_NDELAY is defined. */
424 if (flags & O_NONBLOCK)
425 {
426 flags &= ~O_NONBLOCK;
427 set++;
428 }
429
430 if (set)
431 fcntl (fd, F_SETFL, flags);
432 }
433
434 /* There is a bug in the NeXT 2.1 rlogind that causes opens
435 of /dev/tty to fail. */
436 void
437 check_dev_tty ()
438 {
439 int tty_fd;
440 char *tty;
441
442 tty_fd = open ("/dev/tty", O_RDWR);
443
444 if (tty_fd < 0)
445 {
446 tty = (char *)ttyname (fileno (stdin));
447 if (tty == 0)
448 return;
449 tty_fd = open (tty, O_RDWR);
450 }
451 close (tty_fd);
452 }
453
454 /* Return 1 if PATH1 and PATH2 are the same file. This is kind of
455 expensive. If non-NULL STP1 and STP2 point to stat structures
456 corresponding to PATH1 and PATH2, respectively. */
457 int
458 same_file (path1, path2, stp1, stp2)
459 char *path1, *path2;
460 struct stat *stp1, *stp2;
461 {
462 struct stat st1, st2;
463
464 if (stp1 == NULL)
465 {
466 if (stat (path1, &st1) != 0)
467 return (0);
468 stp1 = &st1;
469 }
470
471 if (stp2 == NULL)
472 {
473 if (stat (path2, &st2) != 0)
474 return (0);
475 stp2 = &st2;
476 }
477
478 return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino));
479 }
480
481 /* Move FD to a number close to the maximum number of file descriptors
482 allowed in the shell process, to avoid the user stepping on it with
483 redirection and causing us extra work. If CHECK_NEW is non-zero,
484 we check whether or not the file descriptors are in use before
485 duplicating FD onto them. */
486 int
487 move_to_high_fd (fd, check_new)
488 int fd, check_new;
489 {
490 int script_fd, nfds, ignore;
491
492 nfds = getdtablesize ();
493 if (nfds <= 0)
494 nfds = 20;
495 if (nfds > 256)
496 nfds = 256;
497
498 for (nfds--; check_new && nfds > 3; nfds--)
499 if (fcntl (nfds, F_GETFD, &ignore) == -1)
500 break;
501
502 if (nfds && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
503 {
504 if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */
505 close (fd);
506 return (script_fd);
507 }
508
509 return (fd);
510 }
511
512 /* Return non-zero if the characters from SAMPLE are not all valid
513 characters to be found in the first line of a shell script. We
514 check up to the first newline, or SAMPLE_LEN, whichever comes first.
515 All of the characters must be printable or whitespace. */
516
517 #if !defined (isspace)
518 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f')
519 #endif
520
521 #if !defined (isprint)
522 #define isprint(c) (isletter(c) || digit(c) || ispunct(c))
523 #endif
524
525 int
526 check_binary_file (sample, sample_len)
527 unsigned char *sample;
528 int sample_len;
529 {
530 register int i;
531
532 for (i = 0; i < sample_len; i++)
533 {
534 if (sample[i] == '\n')
535 return (0);
536
537 if (isspace (sample[i]) == 0 && isprint (sample[i]) == 0)
538 return (1);
539 }
540
541 return (0);
542 }
543
544 /* **************************************************************** */
545 /* */
546 /* Functions to manipulate pathnames */
547 /* */
548 /* **************************************************************** */
549
550 /* Return 1 if PATH corresponds to a directory. */
551 static int
552 canon_stat (path)
553 char *path;
554 {
555 int l;
556 char *s;
557 struct stat sb;
558
559 l = strlen (path);
560 s = xmalloc (l + 3);
561 strcpy (s, path);
562 s[l] = '/';
563 s[l+1] = '.';
564 s[l+2] = '\0';
565 l = stat (s, &sb) == 0 && S_ISDIR (sb.st_mode);
566 free (s);
567 return l;
568 }
569
570 /* Canonicalize PATH, and return a new path. The new path differs from PATH
571 in that:
572 Multple `/'s are collapsed to a single `/'.
573 Leading `./'s and trailing `/.'s are removed.
574 Trailing `/'s are removed.
575 Non-leading `../'s and trailing `..'s are handled by removing
576 portions of the path. */
577 char *
578 canonicalize_pathname (path)
579 char *path;
580 {
581 register int i, start;
582 char stub_char;
583 char *result;
584
585 /* The result cannot be larger than the input PATH. */
586 result = savestring (path);
587
588 stub_char = (*path == '/') ? '/' : '.';
589
590 /* Walk along RESULT looking for things to compact. */
591 i = 0;
592 while (1)
593 {
594 if (!result[i])
595 break;
596
597 while (result[i] && result[i] != '/')
598 i++;
599
600 start = i++;
601
602 /* If we didn't find any slashes, then there is nothing left to do. */
603 if (!result[start])
604 break;
605
606 /* Handle multiple `/'s in a row. */
607 while (result[i] == '/')
608 i++;
609
610 #if !defined (apollo)
611 if ((start + 1) != i)
612 #else
613 if ((start + 1) != i && (start != 0 || i != 2))
614 #endif /* apollo */
615 {
616 strcpy (result + start + 1, result + i);
617 i = start + 1;
618 /* Make sure that what we have so far corresponds to a directory.
619 If it does not, just punt. */
620 if (*result)
621 {
622 char c;
623 c = result[start];
624 result[start] = '\0';
625 if (canon_stat (result) == 0)
626 {
627 free (result);
628 return ((char *)NULL);
629 }
630 result[start] = c;
631 }
632 }
633 #if 0
634 /* Handle backslash-quoted `/'. */
635 if (start > 0 && result[start - 1] == '\\')
636 continue;
637 #endif
638
639 /* Check for trailing `/'. */
640 if (start && !result[i])
641 {
642 zero_last:
643 result[--i] = '\0';
644 break;
645 }
646
647 /* Check for `../', `./' or trailing `.' by itself. */
648 if (result[i] == '.')
649 {
650 /* Handle trailing `.' by itself. */
651 if (!result[i + 1])
652 goto zero_last;
653
654 /* Handle `./'. */
655 if (result[i + 1] == '/')
656 {
657 strcpy (result + i, result + i + 1);
658 i = (start < 0) ? 0 : start;
659 continue;
660 }
661
662 /* Handle `../' or trailing `..' by itself. */
663 if (result[i + 1] == '.' &&
664 (result[i + 2] == '/' || !result[i + 2]))
665 {
666 /* Make sure that the last component corresponds to a directory
667 before blindly chopping it off. */
668 if (i)
669 {
670 result[i] = '\0';
671 if (canon_stat (result) == 0)
672 {
673 free (result);
674 return ((char *)NULL);
675 }
676 result[i] = '.';
677 }
678 while (--start > -1 && result[start] != '/');
679 strcpy (result + start + 1, result + i + 2);
680 #if 0 /* Unnecessary */
681 if (*result && canon_stat (result) == 0)
682 {
683 free (result);
684 return ((char *)NULL);
685 }
686 #endif
687 i = (start < 0) ? 0 : start;
688 continue;
689 }
690 }
691 }
692
693 if (!*result)
694 {
695 *result = stub_char;
696 result[1] = '\0';
697 }
698 return (result);
699 }
700
701 /* Turn STRING (a pathname) into an absolute pathname, assuming that
702 DOT_PATH contains the symbolic location of `.'. This always
703 returns a new string, even if STRING was an absolute pathname to
704 begin with. */
705 char *
706 make_absolute (string, dot_path)
707 char *string, *dot_path;
708 {
709 char *result;
710 int result_len;
711
712 if (!dot_path || *string == '/')
713 result = savestring (string);
714 else
715 {
716 if (dot_path && dot_path[0])
717 {
718 result_len = strlen (dot_path);
719 result = xmalloc (2 + result_len + strlen (string));
720 strcpy (result, dot_path);
721 if (result[result_len - 1] != '/')
722 {
723 result[result_len++] = '/';
724 result[result_len] = '\0';
725 }
726 }
727 else
728 {
729 result = xmalloc (3 + strlen (string));
730 result[0] = '.'; result[1] = '/'; result[2] = '\0';
731 result_len = 2;
732 }
733
734 strcpy (result + result_len, string);
735 }
736
737 return (result);
738 }
739
740 /* Return 1 if STRING contains an absolute pathname, else 0. */
741 int
742 absolute_pathname (string)
743 char *string;
744 {
745 if (!string || !*string)
746 return (0);
747
748 if (*string == '/')
749 return (1);
750
751 if (*string++ == '.')
752 {
753 if (!*string || *string == '/' ||
754 (*string == '.' && (string[1] == '\0' || string[1] == '/')))
755 return (1);
756 }
757 return (0);
758 }
759
760 /* Return 1 if STRING is an absolute program name; it is absolute if it
761 contains any slashes. This is used to decide whether or not to look
762 up through $PATH. */
763 int
764 absolute_program (string)
765 char *string;
766 {
767 return ((char *)strchr (string, '/') != (char *)NULL);
768 }
769
770 /* Return the `basename' of the pathname in STRING (the stuff after the
771 last '/'). If STRING is not a full pathname, simply return it. */
772 char *
773 base_pathname (string)
774 char *string;
775 {
776 char *p;
777
778 if (!absolute_pathname (string))
779 return (string);
780
781 p = (char *)strrchr (string, '/');
782 return (p ? ++p : string);
783 }
784
785 /* Return the full pathname of FILE. Easy. Filenames that begin
786 with a '/' are returned as themselves. Other filenames have
787 the current working directory prepended. A new string is
788 returned in either case. */
789 char *
790 full_pathname (file)
791 char *file;
792 {
793 char *disposer;
794 char *current_dir;
795 int dlen;
796
797 file = (*file == '~') ? bash_tilde_expand (file) : savestring (file);
798
799 if ((*file == '/') && absolute_pathname (file))
800 return (file);
801
802 disposer = file;
803
804 current_dir = xmalloc (2 + PATH_MAX + strlen (file));
805 if (getcwd (current_dir, PATH_MAX) == 0)
806 {
807 sys_error (bash_getcwd_errstr);
808 free (disposer);
809 free (current_dir);
810 return ((char *)NULL);
811 }
812 dlen = strlen (current_dir);
813 current_dir[dlen++] = '/';
814
815 /* Turn /foo/./bar into /foo/bar. */
816 if (file[0] == '.' && file[1] == '/')
817 file += 2;
818
819 strcpy (current_dir + dlen, file);
820 free (disposer);
821 return (current_dir);
822 }
823
824 /* A slightly related function. Get the prettiest name of this
825 directory possible. */
826 static char tdir[PATH_MAX];
827
828 /* Return a pretty pathname. If the first part of the pathname is
829 the same as $HOME, then replace that with `~'. */
830 char *
831 polite_directory_format (name)
832 char *name;
833 {
834 char *home;
835 int l;
836
837 home = get_string_value ("HOME");
838 l = home ? strlen (home) : 0;
839 if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
840 {
841 strcpy (tdir + 1, name + l);
842 tdir[0] = '~';
843 return (tdir);
844 }
845 else
846 return (name);
847 }
848
849 /* Given a string containing units of information separated by colons,
850 return the next one pointed to by (P_INDEX), or NULL if there are no more.
851 Advance (P_INDEX) to the character after the colon. */
852 char *
853 extract_colon_unit (string, p_index)
854 char *string;
855 int *p_index;
856 {
857 int i, start, len;
858 char *value;
859
860 if (string == 0)
861 return (string);
862
863 len = strlen (string);
864 if (*p_index >= len)
865 return ((char *)NULL);
866
867 i = *p_index;
868
869 /* Each call to this routine leaves the index pointing at a colon if
870 there is more to the path. If I is > 0, then increment past the
871 `:'. If I is 0, then the path has a leading colon. Trailing colons
872 are handled OK by the `else' part of the if statement; an empty
873 string is returned in that case. */
874 if (i && string[i] == ':')
875 i++;
876
877 for (start = i; string[i] && string[i] != ':'; i++)
878 ;
879
880 *p_index = i;
881
882 if (i == start)
883 {
884 if (string[i])
885 (*p_index)++;
886 /* Return "" in the case of a trailing `:'. */
887 value = xmalloc (1);
888 value[0] = '\0';
889 }
890 else
891 {
892 len = i - start;
893 value = xmalloc (1 + len);
894 strncpy (value, string + start, len);
895 value [len] = '\0';
896 }
897
898 return (value);
899 }
900
901 /* **************************************************************** */
902 /* */
903 /* Tilde Initialization and Expansion */
904 /* */
905 /* **************************************************************** */
906
907 /* If tilde_expand hasn't been able to expand the text, perhaps it
908 is a special shell expansion. This function is installed as the
909 tilde_expansion_failure_hook. It knows how to expand ~- and ~+. */
910 static char *
911 bash_tilde_expansion_failure_hook (text)
912 char *text;
913 {
914 char *result;
915
916 result = (char *)NULL;
917 if (text[1] == '\0')
918 {
919 if (*text == '+')
920 result = get_string_value ("PWD");
921 else if (*text == '-')
922 result = get_string_value ("OLDPWD");
923 }
924
925 return (result ? savestring (result) : (char *)NULL);
926 }
927
928 /* Initialize the tilde expander. In Bash, we handle `~-' and `~+', as
929 well as handling special tilde prefixes; `:~" and `=~' are indications
930 that we should do tilde expansion. */
931 void
932 tilde_initialize ()
933 {
934 static int times_called = 0;
935
936 /* Tell the tilde expander that we want a crack if it fails. */
937 tilde_expansion_failure_hook = (CPFunction *)bash_tilde_expansion_failure_hook;
938
939 /* Tell the tilde expander about special strings which start a tilde
940 expansion, and the special strings that end one. Only do this once.
941 tilde_initialize () is called from within bashline_reinitialize (). */
942 if (times_called == 0)
943 {
944 tilde_additional_prefixes = (char **)xmalloc (3 * sizeof (char *));
945 tilde_additional_prefixes[0] = "=~";
946 tilde_additional_prefixes[1] = ":~";
947 tilde_additional_prefixes[2] = (char *)NULL;
948
949 tilde_additional_suffixes = (char **)xmalloc (3 * sizeof (char *));
950 tilde_additional_suffixes[0] = ":";
951 tilde_additional_suffixes[1] = "=~";
952 tilde_additional_suffixes[2] = (char *)NULL;
953 }
954 times_called++;
955 }
956
957 char *
958 bash_tilde_expand (s)
959 char *s;
960 {
961 int old_immed;
962 char *ret;
963
964 old_immed = interrupt_immediately;
965 interrupt_immediately = 1;
966 ret = tilde_expand (s);
967 interrupt_immediately = old_immed;
968 return (ret);
969 }