1 /* general.c -- Stuff that is used by all files. */
3 /* Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992
4 Free Software Foundation, Inc.
6 This file is part of GNU Bash, the Bourne Again SHell.
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
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
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. */
24 #include "bashtypes.h"
25 #include <sys/param.h>
26 #include "posixstat.h"
28 #if defined (HAVE_UNISTD_H)
39 #include <tilde/tilde.h>
41 #if defined (TIME_WITH_SYS_TIME)
42 # include <sys/time.h>
45 # if defined (HAVE_SYS_TIME_H)
46 # include <sys/time.h>
52 #include <sys/times.h>
60 # define to_upper(c) (islower(c) ? toupper(c) : (c))
61 # define to_lower(c) (isupper(c) ? tolower(c) : (c))
64 extern int interrupt_immediately
;
65 extern int interactive_comments
;
66 extern char *bash_getcwd_errstr
;
68 /* Do whatever is necessary to initialize `Posix mode'. */
73 interactive_comments
= on
!= 0;
76 /* **************************************************************** */
78 /* Integer to String Conversion */
80 /* **************************************************************** */
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
86 /* Integer to string conversion. This conses the string; the
87 caller should free it. */
96 buf
= xmalloc (MAX_INT_LEN
);
104 ui
= (unsigned int) i
;
106 p
= buf
+ MAX_INT_LEN
- 2;
110 *p
-- = (ui
% 10) + '0';
116 ret
= savestring (p
+ 1);
121 /* atol(3) is not universal */
129 while (s
&& *s
&& whitespace (*s
))
131 if (*s
== '-' || *s
== '+')
136 for ( ; s
&& *s
&& digit (*s
); s
++)
137 ret
= (ret
* 10) + digit_value (*s
);
138 return (neg
? -ret
: ret
);
141 /* **************************************************************** */
143 /* Functions to convert to and from and display non-standard types */
145 /* **************************************************************** */
147 #if defined (RLIMTYPE)
149 string_to_rlimtype (s
)
155 while (s
&& *s
&& whitespace (*s
))
157 if (*s
== '-' || *s
== '+')
162 for ( ; s
&& *s
&& digit (*s
); s
++)
163 ret
= (ret
* 10) + digit_value (*s
);
164 return (neg
? -ret
: ret
);
168 print_rlimtype (n
, addnl
)
172 char s
[sizeof (RLIMTYPE
) * 3 + 1];
173 int len
= sizeof (RLIMTYPE
) * 3 + 1;
177 printf ("0%s", addnl
? "\n" : "");
188 for ( ; n
!= 0; n
/= 10)
189 s
[--len
] = n
% 10 + '0';
190 printf ("%s%s", s
+ len
, addnl
? "\n" : "");
192 #endif /* RLIMTYPE */
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. */
199 timeval_to_secs (tvp
, sp
, sfp
)
208 *sfp
= tvp
->tv_usec
% 1000000; /* pretty much a no-op */
210 *sfp
= (*sfp
* 1000) / 1000000;
215 /* Print the contents of a struct timeval * in a standard way to stdio
218 print_timeval (fp
, tvp
)
222 int minutes
, seconds_fraction
;
225 timeval_to_secs (tvp
, &seconds
, &seconds_fraction
);
227 minutes
= seconds
/ 60;
230 fprintf (fp
, "%0dm%0ld.%03ds", minutes
, seconds
, seconds_fraction
);
232 #endif /* HAVE_TIMEVAL */
234 #if defined (HAVE_TIMES)
236 clock_t_to_secs (t
, sp
, sfp
)
241 static long clk_tck
= 0;
244 clk_tck
= get_clk_tck ();
247 *sfp
= (*sfp
* 1000) / clk_tck
;
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. */
256 print_time_in_hz (fp
, t
)
260 int minutes
, seconds_fraction
;
263 clock_t_to_secs (t
, &seconds
, &seconds_fraction
);
265 minutes
= seconds
/ 60;
268 fprintf (fp
, "%0dm%0ld.%03ds", minutes
, seconds
, seconds_fraction
);
270 #endif /* HAVE_TIMES */
272 /* **************************************************************** */
274 /* Input Validation Functions */
276 /* **************************************************************** */
278 /* Return non-zero if all of the characters in STRING are digits. */
285 if (!digit (*string
))
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. */
297 legal_number (string
, result
)
310 /* Skip leading whitespace characters. */
311 while (whitespace (*string
))
317 /* We allow leading `-' or `+'. */
318 if (*string
== '-' || *string
== '+')
320 if (!digit (string
[1]))
329 while (digit (*string
))
332 value
= (value
* 10) + digit_value (*string
);
336 /* Skip trailing whitespace, if any. */
337 while (whitespace (*string
))
340 /* Error if not at end of string. */
345 *result
= value
* sign
;
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
354 legal_identifier (name
)
359 if (!name
|| !*name
|| (legal_variable_starter (*name
) == 0))
362 for (s
= name
+ 1; *s
; s
++)
364 if (legal_variable_char (*s
) == 0)
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. */
376 check_identifier (word
, check_word
)
380 if ((word
->flags
& (W_HASDOLLAR
|W_QUOTED
)) || all_digits (word
->word
))
382 internal_error ("`%s': not a valid identifier", word
->word
);
385 else if (check_word
&& legal_identifier (word
->word
) == 0)
387 internal_error ("`%s': not a valid identifier", word
->word
);
394 /* **************************************************************** */
396 /* Functions to manage files and file descriptors */
398 /* **************************************************************** */
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. */
404 #if !defined (O_NDELAY)
405 # if defined (FNDELAY)
406 # define O_NDELAY FNDELAY
408 #endif /* O_NDELAY */
410 /* Make sure no-delay mode is not set on file descriptor FD. */
412 unset_nodelay_mode (fd
)
417 if ((flags
= fcntl (fd
, F_GETFL
, 0)) < 0)
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
)
426 flags
&= ~O_NONBLOCK
;
431 fcntl (fd
, F_SETFL
, flags
);
434 /* There is a bug in the NeXT 2.1 rlogind that causes opens
435 of /dev/tty to fail. */
442 tty_fd
= open ("/dev/tty", O_RDWR
);
446 tty
= (char *)ttyname (fileno (stdin
));
449 tty_fd
= open (tty
, O_RDWR
);
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. */
458 same_file (path1
, path2
, stp1
, stp2
)
460 struct stat
*stp1
, *stp2
;
462 struct stat st1
, st2
;
466 if (stat (path1
, &st1
) != 0)
473 if (stat (path2
, &st2
) != 0)
478 return ((stp1
->st_dev
== stp2
->st_dev
) && (stp1
->st_ino
== stp2
->st_ino
));
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. */
487 move_to_high_fd (fd
, check_new
)
490 int script_fd
, nfds
, ignore
;
492 nfds
= getdtablesize ();
498 for (nfds
--; check_new
&& nfds
> 3; nfds
--)
499 if (fcntl (nfds
, F_GETFD
, &ignore
) == -1)
502 if (nfds
&& fd
!= nfds
&& (script_fd
= dup2 (fd
, nfds
)) != -1)
504 if (check_new
== 0 || fd
!= fileno (stderr
)) /* don't close stderr */
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. */
517 #if !defined (isspace)
518 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f')
521 #if !defined (isprint)
522 #define isprint(c) (isletter(c) || digit(c) || ispunct(c))
526 check_binary_file (sample
, sample_len
)
527 unsigned char *sample
;
532 for (i
= 0; i
< sample_len
; i
++)
534 if (sample
[i
] == '\n')
537 if (isspace (sample
[i
]) == 0 && isprint (sample
[i
]) == 0)
544 /* **************************************************************** */
546 /* Functions to manipulate pathnames */
548 /* **************************************************************** */
550 /* Return 1 if PATH corresponds to a directory. */
565 l
= stat (s
, &sb
) == 0 && S_ISDIR (sb
.st_mode
);
570 /* Canonicalize PATH, and return a new path. The new path differs from PATH
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. */
578 canonicalize_pathname (path
)
581 register int i
, start
;
585 /* The result cannot be larger than the input PATH. */
586 result
= savestring (path
);
588 stub_char
= (*path
== '/') ? '/' : '.';
590 /* Walk along RESULT looking for things to compact. */
597 while (result
[i
] && result
[i
] != '/')
602 /* If we didn't find any slashes, then there is nothing left to do. */
606 /* Handle multiple `/'s in a row. */
607 while (result
[i
] == '/')
610 #if !defined (apollo)
611 if ((start
+ 1) != i
)
613 if ((start
+ 1) != i
&& (start
!= 0 || i
!= 2))
616 strcpy (result
+ start
+ 1, result
+ i
);
618 /* Make sure that what we have so far corresponds to a directory.
619 If it does not, just punt. */
624 result
[start
] = '\0';
625 if (canon_stat (result
) == 0)
628 return ((char *)NULL
);
634 /* Handle backslash-quoted `/'. */
635 if (start
> 0 && result
[start
- 1] == '\\')
639 /* Check for trailing `/'. */
640 if (start
&& !result
[i
])
647 /* Check for `../', `./' or trailing `.' by itself. */
648 if (result
[i
] == '.')
650 /* Handle trailing `.' by itself. */
655 if (result
[i
+ 1] == '/')
657 strcpy (result
+ i
, result
+ i
+ 1);
658 i
= (start
< 0) ? 0 : start
;
662 /* Handle `../' or trailing `..' by itself. */
663 if (result
[i
+ 1] == '.' &&
664 (result
[i
+ 2] == '/' || !result
[i
+ 2]))
666 /* Make sure that the last component corresponds to a directory
667 before blindly chopping it off. */
671 if (canon_stat (result
) == 0)
674 return ((char *)NULL
);
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)
684 return ((char *)NULL
);
687 i
= (start
< 0) ? 0 : start
;
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
706 make_absolute (string
, dot_path
)
707 char *string
, *dot_path
;
712 if (!dot_path
|| *string
== '/')
713 result
= savestring (string
);
716 if (dot_path
&& dot_path
[0])
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] != '/')
723 result
[result_len
++] = '/';
724 result
[result_len
] = '\0';
729 result
= xmalloc (3 + strlen (string
));
730 result
[0] = '.'; result
[1] = '/'; result
[2] = '\0';
734 strcpy (result
+ result_len
, string
);
740 /* Return 1 if STRING contains an absolute pathname, else 0. */
742 absolute_pathname (string
)
745 if (!string
|| !*string
)
751 if (*string
++ == '.')
753 if (!*string
|| *string
== '/' ||
754 (*string
== '.' && (string
[1] == '\0' || string
[1] == '/')))
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
764 absolute_program (string
)
767 return ((char *)strchr (string
, '/') != (char *)NULL
);
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. */
773 base_pathname (string
)
778 if (!absolute_pathname (string
))
781 p
= (char *)strrchr (string
, '/');
782 return (p
? ++p
: string
);
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. */
797 file
= (*file
== '~') ? bash_tilde_expand (file
) : savestring (file
);
799 if ((*file
== '/') && absolute_pathname (file
))
804 current_dir
= xmalloc (2 + PATH_MAX
+ strlen (file
));
805 if (getcwd (current_dir
, PATH_MAX
) == 0)
807 sys_error (bash_getcwd_errstr
);
810 return ((char *)NULL
);
812 dlen
= strlen (current_dir
);
813 current_dir
[dlen
++] = '/';
815 /* Turn /foo/./bar into /foo/bar. */
816 if (file
[0] == '.' && file
[1] == '/')
819 strcpy (current_dir
+ dlen
, file
);
821 return (current_dir
);
824 /* A slightly related function. Get the prettiest name of this
825 directory possible. */
826 static char tdir
[PATH_MAX
];
828 /* Return a pretty pathname. If the first part of the pathname is
829 the same as $HOME, then replace that with `~'. */
831 polite_directory_format (name
)
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
] == '/'))
841 strcpy (tdir
+ 1, name
+ l
);
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. */
853 extract_colon_unit (string
, p_index
)
863 len
= strlen (string
);
865 return ((char *)NULL
);
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
] == ':')
877 for (start
= i
; string
[i
] && string
[i
] != ':'; i
++)
886 /* Return "" in the case of a trailing `:'. */
893 value
= xmalloc (1 + len
);
894 strncpy (value
, string
+ start
, len
);
901 /* **************************************************************** */
903 /* Tilde Initialization and Expansion */
905 /* **************************************************************** */
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 ~+. */
911 bash_tilde_expansion_failure_hook (text
)
916 result
= (char *)NULL
;
920 result
= get_string_value ("PWD");
921 else if (*text
== '-')
922 result
= get_string_value ("OLDPWD");
925 return (result
? savestring (result
) : (char *)NULL
);
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. */
934 static int times_called
= 0;
936 /* Tell the tilde expander that we want a crack if it fails. */
937 tilde_expansion_failure_hook
= (CPFunction
*)bash_tilde_expansion_failure_hook
;
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)
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
;
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
;
958 bash_tilde_expand (s
)
964 old_immed
= interrupt_immediately
;
965 interrupt_immediately
= 1;
966 ret
= tilde_expand (s
);
967 interrupt_immediately
= old_immed
;