9623df0314859d6144c86d967e003216d96bac12
[platform/upstream/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 }