Imported from ../bash-1.14.7.tar.gz.
This commit is contained in:
commit
726f63884d
402 changed files with 150297 additions and 0 deletions
689
builtins/cd.def
Normal file
689
builtins/cd.def
Normal file
|
|
@ -0,0 +1,689 @@
|
|||
This file is cd.def, from which is created cd.c. It implements the
|
||||
builtins "cd", "pwd", "pushd", "popd", and "dirs" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES cd.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include <errno.h>
|
||||
#include <tilde/tilde.h>
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../flags.h"
|
||||
#include "../maxpath.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
static int change_to_directory (), cd_to_string ();
|
||||
|
||||
$BUILTIN cd
|
||||
$FUNCTION cd_builtin
|
||||
$SHORT_DOC cd [dir]
|
||||
Change the current directory to DIR. The variable $HOME is the
|
||||
default DIR. The variable $CDPATH defines the search path for
|
||||
the directory containing DIR. Alternative directory names are
|
||||
separated by a colon (:). A null directory name is the same as
|
||||
the current directory, i.e. `.'. If DIR begins with a slash (/),
|
||||
then $CDPATH is not used. If the directory is not found, and the
|
||||
shell variable `cdable_vars' exists, then try the word as a variable
|
||||
name. If that variable has a value, then cd to the value of that
|
||||
variable.
|
||||
$END
|
||||
|
||||
/* This builtin is ultimately the way that all user-visible commands should
|
||||
change the current working directory. It is called by cd_to_string (),
|
||||
so the programming interface is simple, and it handles errors and
|
||||
restrictions properly. */
|
||||
int
|
||||
cd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *dirname;
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted)
|
||||
{
|
||||
builtin_error ("restricted");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif /* RESTRICTED_SHELL */
|
||||
|
||||
if (list)
|
||||
{
|
||||
char *extract_colon_unit ();
|
||||
char *path_string = get_string_value ("CDPATH");
|
||||
char *path;
|
||||
int path_index = 0, dirlen, pathlen;
|
||||
|
||||
dirname = list->word->word;
|
||||
|
||||
if (path_string && !absolute_pathname (dirname))
|
||||
{
|
||||
while ((path = extract_colon_unit (path_string, &path_index)))
|
||||
{
|
||||
char *dir;
|
||||
|
||||
if (*path == '~')
|
||||
{
|
||||
char *te_string = tilde_expand (path);
|
||||
|
||||
free (path);
|
||||
path = te_string;
|
||||
}
|
||||
|
||||
if (!*path)
|
||||
{
|
||||
free (path);
|
||||
path = xmalloc (2);
|
||||
path[0] = '.'; /* by definition. */
|
||||
path[1] = '\0';
|
||||
}
|
||||
|
||||
dirlen = strlen (dirname);
|
||||
pathlen = strlen (path);
|
||||
dir = xmalloc (2 + dirlen + pathlen);
|
||||
strcpy (dir, path);
|
||||
if (path[pathlen - 1] != '/')
|
||||
{
|
||||
dir[pathlen++] = '/';
|
||||
dir[pathlen] = '\0';
|
||||
}
|
||||
strcpy (dir + pathlen, dirname);
|
||||
free (path);
|
||||
|
||||
if (change_to_directory (dir))
|
||||
{
|
||||
/* replaces (strncmp (dir, "./", 2) != 0) */
|
||||
if (dir[0] != '.' || dir[1] != '/')
|
||||
printf ("%s\n", dir);
|
||||
|
||||
free (dir);
|
||||
goto bind_and_exit;
|
||||
}
|
||||
else
|
||||
free (dir);
|
||||
}
|
||||
}
|
||||
|
||||
if (!change_to_directory (dirname))
|
||||
{
|
||||
/* Maybe this is `cd -', equivalent to `cd $OLDPWD' */
|
||||
if (dirname[0] == '-' && dirname[1] == '\0')
|
||||
{
|
||||
char *t = get_string_value ("OLDPWD");
|
||||
|
||||
if (t && change_to_directory (t))
|
||||
goto bind_and_exit;
|
||||
}
|
||||
|
||||
/* If the user requests it, then perhaps this is the name of
|
||||
a shell variable, whose value contains the directory to
|
||||
change to. If that is the case, then change to that
|
||||
directory. */
|
||||
if (find_variable ("cdable_vars"))
|
||||
{
|
||||
char *t = get_string_value (dirname);
|
||||
|
||||
if (t && change_to_directory (t))
|
||||
{
|
||||
printf ("%s\n", t);
|
||||
goto bind_and_exit;
|
||||
}
|
||||
}
|
||||
|
||||
file_error (dirname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
goto bind_and_exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
dirname = get_string_value ("HOME");
|
||||
|
||||
if (!dirname)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (!change_to_directory (dirname))
|
||||
{
|
||||
file_error (dirname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
bind_and_exit:
|
||||
{
|
||||
char *directory;
|
||||
|
||||
directory = get_working_directory ("cd");
|
||||
|
||||
bind_variable ("OLDPWD", get_string_value ("PWD"));
|
||||
bind_variable ("PWD", directory);
|
||||
|
||||
FREE (directory);
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
$BUILTIN pwd
|
||||
$FUNCTION pwd_builtin
|
||||
$SHORT_DOC pwd
|
||||
Print the current working directory.
|
||||
$END
|
||||
|
||||
/* Non-zero means that pwd always give verbatim directory, regardless of
|
||||
symbolic link following. */
|
||||
static int verbatim_pwd;
|
||||
|
||||
/* Print the name of the current working directory. */
|
||||
pwd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *directory, *s;
|
||||
|
||||
#if 0
|
||||
no_args (list);
|
||||
#else
|
||||
verbatim_pwd = no_symbolic_links;
|
||||
if (list && (s = list->word->word) && s[0] == '-' && s[1] == 'P' && !s[2])
|
||||
verbatim_pwd = 1;
|
||||
#endif
|
||||
|
||||
if (verbatim_pwd)
|
||||
{
|
||||
char *buffer = xmalloc (MAXPATHLEN);
|
||||
directory = getwd (buffer);
|
||||
|
||||
if (!directory)
|
||||
{
|
||||
builtin_error ("%s", buffer);
|
||||
free (buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
directory = get_working_directory ("pwd");
|
||||
|
||||
if (directory)
|
||||
{
|
||||
printf ("%s\n", directory);
|
||||
fflush (stdout);
|
||||
free (directory);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
$BUILTIN pushd
|
||||
$FUNCTION pushd_builtin
|
||||
$DEPENDS_ON PUSHD_AND_POPD
|
||||
$SHORT_DOC pushd [dir | +n | -n]
|
||||
Adds a directory to the top of the directory stack, or rotates
|
||||
the stack, making the new top of the stack the current working
|
||||
directory. With no arguments, exchanges the top two directories.
|
||||
|
||||
+n Rotates the stack so that the Nth directory (counting
|
||||
from the left of the list shown by `dirs') is at the top.
|
||||
|
||||
-n Rotates the stack so that the Nth directory (counting
|
||||
from the right) is at the top.
|
||||
|
||||
dir adds DIR to the directory stack at the top, making it the
|
||||
new current working directory.
|
||||
|
||||
You can see the directory stack with the `dirs' command.
|
||||
$END
|
||||
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
/* Some useful commands whose behaviour has been observed in Csh. */
|
||||
|
||||
/* The list of remembered directories. */
|
||||
static char **pushd_directory_list = (char **)NULL;
|
||||
|
||||
/* Number of existing slots in this list. */
|
||||
static int directory_list_size = 0;
|
||||
|
||||
/* Offset to the end of the list. */
|
||||
static int directory_list_offset = 0;
|
||||
|
||||
pushd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *temp, *current_directory;
|
||||
int j = directory_list_offset - 1;
|
||||
char direction = '+';
|
||||
|
||||
/* If there is no argument list then switch current and
|
||||
top of list. */
|
||||
if (!list)
|
||||
{
|
||||
if (!directory_list_offset)
|
||||
{
|
||||
builtin_error ("No other directory");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
current_directory = get_working_directory ("pushd");
|
||||
if (!current_directory)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
temp = pushd_directory_list[j];
|
||||
pushd_directory_list[j] = current_directory;
|
||||
goto change_to_temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
direction = *(list->word->word);
|
||||
if (direction == '+' || direction == '-')
|
||||
{
|
||||
int num;
|
||||
if (1 == sscanf (&(list->word->word)[1], "%d", &num))
|
||||
{
|
||||
if (direction == '-')
|
||||
num = directory_list_offset - num;
|
||||
|
||||
if (num > directory_list_offset || num < 0)
|
||||
{
|
||||
if (!directory_list_offset)
|
||||
builtin_error ("Directory stack empty");
|
||||
else
|
||||
builtin_error ("Stack contains only %d directories",
|
||||
directory_list_offset + 1);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Rotate the stack num times. Remember, the
|
||||
current directory acts like it is part of the
|
||||
stack. */
|
||||
temp = get_working_directory ("pushd");
|
||||
|
||||
if (!num)
|
||||
goto change_to_temp;
|
||||
|
||||
do
|
||||
{
|
||||
char *top =
|
||||
pushd_directory_list[directory_list_offset - 1];
|
||||
|
||||
for (j = directory_list_offset - 2; j > -1; j--)
|
||||
pushd_directory_list[j + 1] = pushd_directory_list[j];
|
||||
|
||||
pushd_directory_list[j + 1] = temp;
|
||||
|
||||
temp = top;
|
||||
num--;
|
||||
}
|
||||
while (num);
|
||||
|
||||
temp = savestring (temp);
|
||||
change_to_temp:
|
||||
{
|
||||
int tt = EXECUTION_FAILURE;
|
||||
|
||||
if (temp)
|
||||
{
|
||||
tt = cd_to_string (temp);
|
||||
free (temp);
|
||||
}
|
||||
|
||||
if ((tt == EXECUTION_SUCCESS))
|
||||
dirs_builtin ((WORD_LIST *)NULL);
|
||||
|
||||
return (tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Change to the directory in list->word->word. Save the current
|
||||
directory on the top of the stack. */
|
||||
current_directory = get_working_directory ("pushd");
|
||||
if (!current_directory)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (cd_builtin (list) == EXECUTION_SUCCESS)
|
||||
{
|
||||
if (directory_list_offset == directory_list_size)
|
||||
{
|
||||
pushd_directory_list = (char **)
|
||||
xrealloc (pushd_directory_list,
|
||||
(directory_list_size += 10) * sizeof (char *));
|
||||
}
|
||||
pushd_directory_list[directory_list_offset++] = current_directory;
|
||||
|
||||
dirs_builtin ((WORD_LIST *)NULL);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
free (current_directory);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* PUSHD_AND_POPD */
|
||||
|
||||
$BUILTIN dirs
|
||||
$FUNCTION dirs_builtin
|
||||
$DEPENDS_ON PUSHD_AND_POPD
|
||||
$SHORT_DOC dirs [-l]
|
||||
Display the list of currently remembered directories. Directories
|
||||
find their way onto the list with the `pushd' command; you can get
|
||||
back up through the list with the `popd' command.
|
||||
|
||||
The -l flag specifies that `dirs' should not print shorthand versions
|
||||
of directories which are relative to your home directory. This means
|
||||
that `~/bin' might be displayed as `/homes/bfox/bin'.
|
||||
$END
|
||||
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
/* Print the current list of directories on the directory stack. */
|
||||
dirs_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int i, format, desired_index, index_flag;
|
||||
char *temp, *w;
|
||||
|
||||
format = index_flag = 0;
|
||||
desired_index = -1;
|
||||
/* Maybe do long form or print specific dir stack entry? */
|
||||
while (list)
|
||||
{
|
||||
if (strcmp (list->word->word, "-l") == 0)
|
||||
{
|
||||
format++;
|
||||
list = list->next;
|
||||
}
|
||||
else if (*list->word->word == '+' && all_digits (list->word->word + 1))
|
||||
{
|
||||
w = list->word->word + 1;
|
||||
index_flag = 1;
|
||||
i = atoi (w);
|
||||
/* dirs +0 prints the current working directory. */
|
||||
if (i == 0)
|
||||
desired_index = i;
|
||||
else if (i == directory_list_offset)
|
||||
{
|
||||
desired_index = 0;
|
||||
index_flag = 2;
|
||||
}
|
||||
else
|
||||
desired_index = directory_list_offset - i;
|
||||
list = list->next;
|
||||
}
|
||||
else if (*list->word->word == '-' && all_digits (list->word->word + 1))
|
||||
{
|
||||
w = list->word->word + 1;
|
||||
i = atoi (w);
|
||||
index_flag = 2;
|
||||
/* dirs -X where X is directory_list_offset prints the current
|
||||
working directory. */
|
||||
if (i == directory_list_offset)
|
||||
{
|
||||
index_flag = 1;
|
||||
desired_index = 0;
|
||||
}
|
||||
else
|
||||
desired_index = i;
|
||||
list = list->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
bad_option (list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
|
||||
{
|
||||
if (directory_list_offset == 0)
|
||||
builtin_error ("directory stack empty");
|
||||
else
|
||||
builtin_error ("%s: bad directory stack index", w);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* The first directory printed is always the current working directory. */
|
||||
if (!index_flag || (index_flag == 1 && desired_index == 0))
|
||||
{
|
||||
temp = get_working_directory ("dirs");
|
||||
if (!temp)
|
||||
temp = savestring ("<no directory>");
|
||||
printf ("%s", format ? temp : polite_directory_format (temp));
|
||||
free (temp);
|
||||
if (index_flag)
|
||||
{
|
||||
putchar ('\n');
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
#define DIRSTACK_ENTRY(i) \
|
||||
format ? pushd_directory_list[i] \
|
||||
: polite_directory_format (pushd_directory_list[i])
|
||||
|
||||
/* Now print the requested directory stack entries. */
|
||||
if (index_flag)
|
||||
printf ("%s", DIRSTACK_ENTRY (desired_index));
|
||||
else
|
||||
for (i = (directory_list_offset - 1); i > -1; i--)
|
||||
printf (" %s", DIRSTACK_ENTRY (i));
|
||||
|
||||
putchar ('\n');
|
||||
fflush (stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif /* PUSHD_AND_POPD */
|
||||
|
||||
$BUILTIN popd
|
||||
$FUNCTION popd_builtin
|
||||
$DEPENDS_ON PUSHD_AND_POPD
|
||||
$SHORT_DOC popd [+n | -n]
|
||||
Removes entries from the directory stack. With no arguments,
|
||||
removes the top directory from the stack, and cd's to the new
|
||||
top directory.
|
||||
|
||||
+n removes the Nth entry counting from the left of the list
|
||||
shown by `dirs', starting with zero. For example: `popd +0'
|
||||
removes the first directory, `popd +1' the second.
|
||||
|
||||
-n removes the Nth entry counting from the right of the list
|
||||
shown by `dirs', starting with zero. For example: `popd -0'
|
||||
removes the last directory, `popd -1' the next to last.
|
||||
|
||||
You can see the directory stack with the `dirs' command.
|
||||
$END
|
||||
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
/* Pop the directory stack, and then change to the new top of the stack.
|
||||
If LIST is non-null it should consist of a word +N or -N, which says
|
||||
what element to delete from the stack. The default is the top one. */
|
||||
popd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
int which = 0;
|
||||
char direction = '+';
|
||||
|
||||
if (list)
|
||||
{
|
||||
direction = *(list->word->word);
|
||||
|
||||
if ((direction != '+' && direction != '-') ||
|
||||
(1 != sscanf (&((list->word->word)[1]), "%d", &which)))
|
||||
{
|
||||
builtin_error ("bad arg `%s'", list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (which > directory_list_offset || (!directory_list_offset && !which))
|
||||
{
|
||||
if (!directory_list_offset)
|
||||
builtin_error ("Directory stack empty");
|
||||
else
|
||||
builtin_error ("Stack contains only %d directories",
|
||||
directory_list_offset + 1);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Handle case of no specification, or top of stack specification. */
|
||||
if ((direction == '+' && which == 0) ||
|
||||
(direction == '-' && which == directory_list_offset))
|
||||
{
|
||||
i = cd_to_string (pushd_directory_list[directory_list_offset - 1]);
|
||||
if (i != EXECUTION_SUCCESS)
|
||||
return (i);
|
||||
free (pushd_directory_list[--directory_list_offset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Since an offset other than the top directory was specified,
|
||||
remove that directory from the list and shift the remainder
|
||||
of the list into place. */
|
||||
|
||||
if (direction == '+')
|
||||
i = directory_list_offset - which;
|
||||
else
|
||||
i = which;
|
||||
|
||||
free (pushd_directory_list[i]);
|
||||
directory_list_offset--;
|
||||
|
||||
/* Shift the remainder of the list into place. */
|
||||
for (; i < directory_list_offset; i++)
|
||||
pushd_directory_list[i] = pushd_directory_list[i + 1];
|
||||
}
|
||||
|
||||
dirs_builtin ((WORD_LIST *)NULL);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif /* PUSHD_AND_POPD */
|
||||
|
||||
/* Do the work of changing to the directory NEWDIR. Handle symbolic
|
||||
link following, etc. */
|
||||
|
||||
static int
|
||||
change_to_directory (newdir)
|
||||
char *newdir;
|
||||
{
|
||||
char *t;
|
||||
|
||||
if (!no_symbolic_links)
|
||||
{
|
||||
int chdir_return = 0;
|
||||
char *tdir = (char *)NULL;
|
||||
|
||||
if (!the_current_working_directory)
|
||||
{
|
||||
t = get_working_directory ("cd_links");
|
||||
FREE (t);
|
||||
}
|
||||
|
||||
if (the_current_working_directory)
|
||||
t = make_absolute (newdir, the_current_working_directory);
|
||||
else
|
||||
t = savestring (newdir);
|
||||
|
||||
/* TDIR is the canonicalized absolute pathname of the NEWDIR. */
|
||||
tdir = canonicalize_pathname (t);
|
||||
|
||||
/* Use the canonicalized version of NEWDIR, or, if canonicalization
|
||||
failed, use the non-canonical form. */
|
||||
if (tdir && *tdir)
|
||||
free (t);
|
||||
else
|
||||
{
|
||||
FREE (tdir);
|
||||
|
||||
tdir = t;
|
||||
}
|
||||
|
||||
if (chdir (tdir) < 0)
|
||||
{
|
||||
int err;
|
||||
|
||||
chdir_return = 0;
|
||||
free (tdir);
|
||||
|
||||
err = errno;
|
||||
|
||||
/* We failed changing to the canonicalized directory name. Try
|
||||
what the user passed verbatim. If we succeed, reinitialize
|
||||
the_current_working_directory. */
|
||||
if (chdir (newdir) == 0)
|
||||
{
|
||||
chdir_return = 1;
|
||||
if (the_current_working_directory)
|
||||
{
|
||||
free (the_current_working_directory);
|
||||
the_current_working_directory = (char *)NULL;
|
||||
}
|
||||
|
||||
tdir = get_working_directory ("cd");
|
||||
FREE (tdir);
|
||||
}
|
||||
else
|
||||
errno = err;
|
||||
}
|
||||
else
|
||||
{
|
||||
chdir_return = 1;
|
||||
|
||||
FREE (the_current_working_directory);
|
||||
the_current_working_directory = tdir;
|
||||
}
|
||||
|
||||
return (chdir_return);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chdir (newdir) < 0)
|
||||
return (0);
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Switch to the directory in NAME. This uses the cd_builtin to do the work,
|
||||
so if the result is EXECUTION_FAILURE then an error message has already
|
||||
been printed. */
|
||||
static int
|
||||
cd_to_string (name)
|
||||
char *name;
|
||||
{
|
||||
WORD_LIST *tlist = make_word_list (make_word (name), NULL);
|
||||
int result = (cd_builtin (tlist));
|
||||
dispose_words (tlist);
|
||||
return (result);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue