1 This file is cd.def, from which is created cd.c. It implements the
2 builtins "cd", "pwd", "pushd", "popd", and "dirs" in Bash.
4 Copyright (C) 1987, 1989, 1991 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 1, 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.
25 #include <sys/param.h>
27 #if defined (HAVE_STRING_H)
29 #else /* !HAVE_STRING_H */
31 #endif /* !HAVE_STRING_H */
34 #include <tilde/tilde.h>
38 #include "../maxpath.h"
45 static int change_to_directory (), cd_to_string ();
50 Change the current directory to DIR. The variable $HOME is the
51 default DIR. The variable $CDPATH defines the search path for
52 the directory containing DIR. Alternative directory names are
53 separated by a colon (:). A null directory name is the same as
54 the current directory, i.e. `.'. If DIR begins with a slash (/),
55 then $CDPATH is not used. If the directory is not found, and the
56 shell variable `cdable_vars' exists, then try the word as a variable
57 name. If that variable has a value, then cd to the value of that
61 /* This builtin is ultimately the way that all user-visible commands should
62 change the current working directory. It is called by cd_to_string (),
63 so the programming interface is simple, and it handles errors and
64 restrictions properly. */
71 #if defined (RESTRICTED_SHELL)
74 builtin_error ("restricted");
75 return (EXECUTION_FAILURE);
77 #endif /* RESTRICTED_SHELL */
81 char *extract_colon_unit ();
82 char *path_string = get_string_value ("CDPATH");
84 int path_index = 0, dirlen, pathlen;
86 dirname = list->word->word;
88 if (path_string && !absolute_pathname (dirname))
90 while ((path = extract_colon_unit (path_string, &path_index)))
96 char *te_string = tilde_expand (path);
106 path[0] = '.'; /* by definition. */
110 dirlen = strlen (dirname);
111 pathlen = strlen (path);
112 dir = xmalloc (2 + dirlen + pathlen);
114 if (path[pathlen - 1] != '/')
116 dir[pathlen++] = '/';
119 strcpy (dir + pathlen, dirname);
122 if (change_to_directory (dir))
124 /* replaces (strncmp (dir, "./", 2) != 0) */
125 if (dir[0] != '.' || dir[1] != '/')
126 printf ("%s\n", dir);
136 if (!change_to_directory (dirname))
138 /* Maybe this is `cd -', equivalent to `cd $OLDPWD' */
139 if (dirname[0] == '-' && dirname[1] == '\0')
141 char *t = get_string_value ("OLDPWD");
143 if (t && change_to_directory (t))
147 /* If the user requests it, then perhaps this is the name of
148 a shell variable, whose value contains the directory to
149 change to. If that is the case, then change to that
151 if (find_variable ("cdable_vars"))
153 char *t = get_string_value (dirname);
155 if (t && change_to_directory (t))
162 file_error (dirname);
163 return (EXECUTION_FAILURE);
169 dirname = get_string_value ("HOME");
172 return (EXECUTION_FAILURE);
174 if (!change_to_directory (dirname))
176 file_error (dirname);
177 return (EXECUTION_FAILURE);
184 directory = get_working_directory ("cd");
186 bind_variable ("OLDPWD", get_string_value ("PWD"));
187 bind_variable ("PWD", directory);
191 return (EXECUTION_SUCCESS);
196 $FUNCTION pwd_builtin
198 Print the current working directory.
201 /* Non-zero means that pwd always give verbatim directory, regardless of
202 symbolic link following. */
203 static int verbatim_pwd;
205 /* Print the name of the current working directory. */
214 verbatim_pwd = no_symbolic_links;
215 if (list && (s = list->word->word) && s[0] == '-' && s[1] == 'P' && !s[2])
221 char *buffer = xmalloc (MAXPATHLEN);
222 directory = getwd (buffer);
226 builtin_error ("%s", buffer);
231 directory = get_working_directory ("pwd");
235 printf ("%s\n", directory);
238 return (EXECUTION_SUCCESS);
241 return (EXECUTION_FAILURE);
245 $FUNCTION pushd_builtin
246 $DEPENDS_ON PUSHD_AND_POPD
247 $SHORT_DOC pushd [dir | +n | -n]
248 Adds a directory to the top of the directory stack, or rotates
249 the stack, making the new top of the stack the current working
250 directory. With no arguments, exchanges the top two directories.
252 +n Rotates the stack so that the Nth directory (counting
253 from the left of the list shown by `dirs') is at the top.
255 -n Rotates the stack so that the Nth directory (counting
256 from the right) is at the top.
258 dir adds DIR to the directory stack at the top, making it the
259 new current working directory.
261 You can see the directory stack with the `dirs' command.
264 #if defined (PUSHD_AND_POPD)
265 /* Some useful commands whose behaviour has been observed in Csh. */
267 /* The list of remembered directories. */
268 static char **pushd_directory_list = (char **)NULL;
270 /* Number of existing slots in this list. */
271 static int directory_list_size = 0;
273 /* Offset to the end of the list. */
274 static int directory_list_offset = 0;
279 char *temp, *current_directory;
280 int j = directory_list_offset - 1;
281 char direction = '+';
283 /* If there is no argument list then switch current and
287 if (!directory_list_offset)
289 builtin_error ("No other directory");
290 return (EXECUTION_FAILURE);
293 current_directory = get_working_directory ("pushd");
294 if (!current_directory)
295 return (EXECUTION_FAILURE);
297 temp = pushd_directory_list[j];
298 pushd_directory_list[j] = current_directory;
303 direction = *(list->word->word);
304 if (direction == '+' || direction == '-')
307 if (1 == sscanf (&(list->word->word)[1], "%d", &num))
309 if (direction == '-')
310 num = directory_list_offset - num;
312 if (num > directory_list_offset || num < 0)
314 if (!directory_list_offset)
315 builtin_error ("Directory stack empty");
317 builtin_error ("Stack contains only %d directories",
318 directory_list_offset + 1);
319 return (EXECUTION_FAILURE);
323 /* Rotate the stack num times. Remember, the
324 current directory acts like it is part of the
326 temp = get_working_directory ("pushd");
334 pushd_directory_list[directory_list_offset - 1];
336 for (j = directory_list_offset - 2; j > -1; j--)
337 pushd_directory_list[j + 1] = pushd_directory_list[j];
339 pushd_directory_list[j + 1] = temp;
346 temp = savestring (temp);
349 int tt = EXECUTION_FAILURE;
353 tt = cd_to_string (temp);
357 if ((tt == EXECUTION_SUCCESS))
358 dirs_builtin ((WORD_LIST *)NULL);
366 /* Change to the directory in list->word->word. Save the current
367 directory on the top of the stack. */
368 current_directory = get_working_directory ("pushd");
369 if (!current_directory)
370 return (EXECUTION_FAILURE);
372 if (cd_builtin (list) == EXECUTION_SUCCESS)
374 if (directory_list_offset == directory_list_size)
376 pushd_directory_list = (char **)
377 xrealloc (pushd_directory_list,
378 (directory_list_size += 10) * sizeof (char *));
380 pushd_directory_list[directory_list_offset++] = current_directory;
382 dirs_builtin ((WORD_LIST *)NULL);
384 return (EXECUTION_SUCCESS);
388 free (current_directory);
389 return (EXECUTION_FAILURE);
393 #endif /* PUSHD_AND_POPD */
396 $FUNCTION dirs_builtin
397 $DEPENDS_ON PUSHD_AND_POPD
399 Display the list of currently remembered directories. Directories
400 find their way onto the list with the `pushd' command; you can get
401 back up through the list with the `popd' command.
403 The -l flag specifies that `dirs' should not print shorthand versions
404 of directories which are relative to your home directory. This means
405 that `~/bin' might be displayed as `/homes/bfox/bin'.
408 #if defined (PUSHD_AND_POPD)
409 /* Print the current list of directories on the directory stack. */
413 int i, format, desired_index, index_flag;
416 format = index_flag = 0;
418 /* Maybe do long form or print specific dir stack entry? */
421 if (strcmp (list->word->word, "-l") == 0)
426 else if (*list->word->word == '+' && all_digits (list->word->word + 1))
428 w = list->word->word + 1;
431 /* dirs +0 prints the current working directory. */
434 else if (i == directory_list_offset)
440 desired_index = directory_list_offset - i;
443 else if (*list->word->word == '-' && all_digits (list->word->word + 1))
445 w = list->word->word + 1;
448 /* dirs -X where X is directory_list_offset prints the current
449 working directory. */
450 if (i == directory_list_offset)
461 bad_option (list->word->word);
462 return (EXECUTION_FAILURE);
466 if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
468 if (directory_list_offset == 0)
469 builtin_error ("directory stack empty");
471 builtin_error ("%s: bad directory stack index", w);
472 return (EXECUTION_FAILURE);
475 /* The first directory printed is always the current working directory. */
476 if (!index_flag || (index_flag == 1 && desired_index == 0))
478 temp = get_working_directory ("dirs");
480 temp = savestring ("<no directory>");
481 printf ("%s", format ? temp : polite_directory_format (temp));
486 return EXECUTION_SUCCESS;
490 #define DIRSTACK_ENTRY(i) \
491 format ? pushd_directory_list[i] \
492 : polite_directory_format (pushd_directory_list[i])
494 /* Now print the requested directory stack entries. */
496 printf ("%s", DIRSTACK_ENTRY (desired_index));
498 for (i = (directory_list_offset - 1); i > -1; i--)
499 printf (" %s", DIRSTACK_ENTRY (i));
503 return (EXECUTION_SUCCESS);
505 #endif /* PUSHD_AND_POPD */
508 $FUNCTION popd_builtin
509 $DEPENDS_ON PUSHD_AND_POPD
510 $SHORT_DOC popd [+n | -n]
511 Removes entries from the directory stack. With no arguments,
512 removes the top directory from the stack, and cd's to the new
515 +n removes the Nth entry counting from the left of the list
516 shown by `dirs', starting with zero. For example: `popd +0'
517 removes the first directory, `popd +1' the second.
519 -n removes the Nth entry counting from the right of the list
520 shown by `dirs', starting with zero. For example: `popd -0'
521 removes the last directory, `popd -1' the next to last.
523 You can see the directory stack with the `dirs' command.
526 #if defined (PUSHD_AND_POPD)
527 /* Pop the directory stack, and then change to the new top of the stack.
528 If LIST is non-null it should consist of a word +N or -N, which says
529 what element to delete from the stack. The default is the top one. */
535 char direction = '+';
539 direction = *(list->word->word);
541 if ((direction != '+' && direction != '-') ||
542 (1 != sscanf (&((list->word->word)[1]), "%d", &which)))
544 builtin_error ("bad arg `%s'", list->word->word);
545 return (EXECUTION_FAILURE);
549 if (which > directory_list_offset || (!directory_list_offset && !which))
551 if (!directory_list_offset)
552 builtin_error ("Directory stack empty");
554 builtin_error ("Stack contains only %d directories",
555 directory_list_offset + 1);
556 return (EXECUTION_FAILURE);
559 /* Handle case of no specification, or top of stack specification. */
560 if ((direction == '+' && which == 0) ||
561 (direction == '-' && which == directory_list_offset))
563 i = cd_to_string (pushd_directory_list[directory_list_offset - 1]);
564 if (i != EXECUTION_SUCCESS)
566 free (pushd_directory_list[--directory_list_offset]);
570 /* Since an offset other than the top directory was specified,
571 remove that directory from the list and shift the remainder
572 of the list into place. */
574 if (direction == '+')
575 i = directory_list_offset - which;
579 free (pushd_directory_list[i]);
580 directory_list_offset--;
582 /* Shift the remainder of the list into place. */
583 for (; i < directory_list_offset; i++)
584 pushd_directory_list[i] = pushd_directory_list[i + 1];
587 dirs_builtin ((WORD_LIST *)NULL);
589 return (EXECUTION_SUCCESS);
591 #endif /* PUSHD_AND_POPD */
593 /* Do the work of changing to the directory NEWDIR. Handle symbolic
594 link following, etc. */
597 change_to_directory (newdir)
602 if (!no_symbolic_links)
604 int chdir_return = 0;
605 char *tdir = (char *)NULL;
607 if (!the_current_working_directory)
609 t = get_working_directory ("cd_links");
613 if (the_current_working_directory)
614 t = make_absolute (newdir, the_current_working_directory);
616 t = savestring (newdir);
618 /* TDIR is the canonicalized absolute pathname of the NEWDIR. */
619 tdir = canonicalize_pathname (t);
621 /* Use the canonicalized version of NEWDIR, or, if canonicalization
622 failed, use the non-canonical form. */
632 if (chdir (tdir) < 0)
641 /* We failed changing to the canonicalized directory name. Try
642 what the user passed verbatim. If we succeed, reinitialize
643 the_current_working_directory. */
644 if (chdir (newdir) == 0)
647 if (the_current_working_directory)
649 free (the_current_working_directory);
650 the_current_working_directory = (char *)NULL;
653 tdir = get_working_directory ("cd");
663 FREE (the_current_working_directory);
664 the_current_working_directory = tdir;
667 return (chdir_return);
671 if (chdir (newdir) < 0)
678 /* Switch to the directory in NAME. This uses the cd_builtin to do the work,
679 so if the result is EXECUTION_FAILURE then an error message has already
685 WORD_LIST *tlist = make_word_list (make_word (name), NULL);
686 int result = (cd_builtin (tlist));
687 dispose_words (tlist);