]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/pushd.def
bash-5.1 distribution sources and documentation
[thirdparty/bash.git] / builtins / pushd.def
CommitLineData
ccc6cda3
JA
1This file is pushd.def, from which is created pushd.c. It implements the
2builtins "pushd", "popd", and "dirs" in Bash.
3
8868edaf 4Copyright (C) 1987-2020 Free Software Foundation, Inc.
ccc6cda3
JA
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
3185942a
JA
8Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
ccc6cda3 12
3185942a
JA
13Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
ccc6cda3 17
3185942a
JA
18You should have received a copy of the GNU General Public License
19along with Bash. If not, see <http://www.gnu.org/licenses/>.
ccc6cda3
JA
20
21$PRODUCES pushd.c
22
23$BUILTIN pushd
24$FUNCTION pushd_builtin
25$DEPENDS_ON PUSHD_AND_POPD
3185942a
JA
26$SHORT_DOC pushd [-n] [+N | -N | dir]
27Add directories to stack.
28
ccc6cda3
JA
29Adds a directory to the top of the directory stack, or rotates
30the stack, making the new top of the stack the current working
31directory. With no arguments, exchanges the top two directories.
32
3185942a
JA
33Options:
34 -n Suppresses the normal change of directory when adding
a0c0a00f 35 directories to the stack, so only the stack is manipulated.
3185942a
JA
36
37Arguments:
38 +N Rotates the stack so that the Nth directory (counting
a0c0a00f
CR
39 from the left of the list shown by `dirs', starting with
40 zero) is at the top.
ccc6cda3 41
3185942a 42 -N Rotates the stack so that the Nth directory (counting
a0c0a00f
CR
43 from the right of the list shown by `dirs', starting with
44 zero) is at the top.
ccc6cda3 45
3185942a 46 dir Adds DIR to the directory stack at the top, making it the
a0c0a00f 47 new current working directory.
ccc6cda3 48
3185942a
JA
49The `dirs' builtin displays the directory stack.
50
51Exit Status:
52Returns success unless an invalid argument is supplied or the directory
53change fails.
ccc6cda3
JA
54$END
55
56$BUILTIN popd
57$FUNCTION popd_builtin
58$DEPENDS_ON PUSHD_AND_POPD
3185942a
JA
59$SHORT_DOC popd [-n] [+N | -N]
60Remove directories from stack.
61
62Removes entries from the directory stack. With no arguments, removes
63the top directory from the stack, and changes to the new top directory.
ccc6cda3 64
3185942a
JA
65Options:
66 -n Suppresses the normal change of directory when removing
a0c0a00f 67 directories from the stack, so only the stack is manipulated.
3185942a
JA
68
69Arguments:
70 +N Removes the Nth entry counting from the left of the list
a0c0a00f
CR
71 shown by `dirs', starting with zero. For example: `popd +0'
72 removes the first directory, `popd +1' the second.
ccc6cda3 73
3185942a 74 -N Removes the Nth entry counting from the right of the list
a0c0a00f
CR
75 shown by `dirs', starting with zero. For example: `popd -0'
76 removes the last directory, `popd -1' the next to last.
ccc6cda3 77
3185942a 78The `dirs' builtin displays the directory stack.
ccc6cda3 79
3185942a
JA
80Exit Status:
81Returns success unless an invalid argument is supplied or the directory
82change fails.
ccc6cda3
JA
83$END
84
85$BUILTIN dirs
86$FUNCTION dirs_builtin
87$DEPENDS_ON PUSHD_AND_POPD
88$SHORT_DOC dirs [-clpv] [+N] [-N]
3185942a
JA
89Display directory stack.
90
ccc6cda3
JA
91Display the list of currently remembered directories. Directories
92find their way onto the list with the `pushd' command; you can get
93back up through the list with the `popd' command.
94
3185942a
JA
95Options:
96 -c clear the directory stack by deleting all of the elements
97 -l do not print tilde-prefixed versions of directories relative
a0c0a00f 98 to your home directory
3185942a
JA
99 -p print the directory stack with one entry per line
100 -v print the directory stack with one entry per line prefixed
a0c0a00f 101 with its position in the stack
ccc6cda3 102
3185942a 103Arguments:
a0c0a00f
CR
104 +N Displays the Nth entry counting from the left of the list
105 shown by dirs when invoked without options, starting with
106 zero.
ccc6cda3 107
a0c0a00f
CR
108 -N Displays the Nth entry counting from the right of the list
109 shown by dirs when invoked without options, starting with
110 zero.
3185942a
JA
111
112Exit Status:
113Returns success unless an invalid option is supplied or an error occurs.
ccc6cda3
JA
114$END
115
116#include <config.h>
117
118#if defined (PUSHD_AND_POPD)
119#include <stdio.h>
ac50fbac 120#if defined (HAVE_SYS_PARAM_H)
cce855bc
JA
121# include <sys/param.h>
122#endif
ccc6cda3
JA
123
124#if defined (HAVE_UNISTD_H)
cce855bc
JA
125# ifdef _MINIX
126# include <sys/types.h>
127# endif
ccc6cda3
JA
128# include <unistd.h>
129#endif
130
131#include "../bashansi.h"
b80f6443 132#include "../bashintl.h"
ccc6cda3
JA
133
134#include <errno.h>
135
136#include <tilde/tilde.h>
137
138#include "../shell.h"
bb70624e 139#include "maxpath.h"
ccc6cda3
JA
140#include "common.h"
141#include "builtext.h"
142
b72432fd
JA
143#ifdef LOADABLE_BUILTIN
144# include "builtins.h"
145#endif
146
ccc6cda3
JA
147#if !defined (errno)
148extern int errno;
149#endif /* !errno */
150
ccc6cda3
JA
151/* The list of remembered directories. */
152static char **pushd_directory_list = (char **)NULL;
153
154/* Number of existing slots in this list. */
155static int directory_list_size;
156
157/* Offset to the end of the list. */
158static int directory_list_offset;
159
8868edaf
CR
160static void pushd_error PARAMS((int, char *));
161static void clear_directory_stack PARAMS((void));
162static int cd_to_string PARAMS((char *));
163static int change_to_temp PARAMS((char *));
164static void add_dirstack_element PARAMS((char *));
165static int get_dirstack_index PARAMS((intmax_t, int, int *));
ccc6cda3
JA
166
167#define NOCD 0x01
168#define ROTATE 0x02
169#define LONGFORM 0x04
170#define CLEARSTAK 0x08
171
172int
173pushd_builtin (list)
174 WORD_LIST *list;
175{
95732b49 176 WORD_LIST *orig_list;
ccc6cda3 177 char *temp, *current_directory, *top;
95732b49 178 int j, flags, skipopt;
7117c2d2 179 intmax_t num;
ccc6cda3
JA
180 char direction;
181
95732b49 182 orig_list = list;
a0c0a00f
CR
183
184 CHECK_HELPOPT (list);
7117c2d2 185 if (list && list->word && ISOPTION (list->word->word, '-'))
95732b49
JA
186 {
187 list = list->next;
188 skipopt = 1;
189 }
190 else
191 skipopt = 0;
7117c2d2 192
ccc6cda3
JA
193 /* If there is no argument list then switch current and
194 top of list. */
195 if (list == 0)
196 {
197 if (directory_list_offset == 0)
198 {
b80f6443 199 builtin_error (_("no other directory"));
ccc6cda3
JA
200 return (EXECUTION_FAILURE);
201 }
202
203 current_directory = get_working_directory ("pushd");
204 if (current_directory == 0)
205 return (EXECUTION_FAILURE);
206
207 j = directory_list_offset - 1;
208 temp = pushd_directory_list[j];
209 pushd_directory_list[j] = current_directory;
210 j = change_to_temp (temp);
211 free (temp);
212 return j;
213 }
214
95732b49 215 for (flags = 0; skipopt == 0 && list; list = list->next)
ccc6cda3
JA
216 {
217 if (ISOPTION (list->word->word, 'n'))
218 {
219 flags |= NOCD;
220 }
221 else if (ISOPTION (list->word->word, '-'))
28ef6c31
JA
222 {
223 list = list->next;
224 break;
225 }
ccc6cda3
JA
226 else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
227 /* Let `pushd -' work like it used to. */
228 break;
229 else if (((direction = list->word->word[0]) == '+') || direction == '-')
230 {
231 if (legal_number (list->word->word + 1, &num) == 0)
232 {
7117c2d2 233 sh_invalidnum (list->word->word);
ccc6cda3 234 builtin_usage ();
ac50fbac 235 return (EX_USAGE);
ccc6cda3
JA
236 }
237
238 if (direction == '-')
239 num = directory_list_offset - num;
240
241 if (num > directory_list_offset || num < 0)
242 {
243 pushd_error (directory_list_offset, list->word->word);
244 return (EXECUTION_FAILURE);
245 }
246 flags |= ROTATE;
247 }
248 else if (*list->word->word == '-')
249 {
7117c2d2 250 sh_invalidopt (list->word->word);
ccc6cda3 251 builtin_usage ();
ac50fbac 252 return (EX_USAGE);
ccc6cda3
JA
253 }
254 else
255 break;
256 }
257
258 if (flags & ROTATE)
259 {
260 /* Rotate the stack num times. Remember, the current
261 directory acts like it is part of the stack. */
262 temp = get_working_directory ("pushd");
263
264 if (num == 0)
265 {
266 j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
267 free (temp);
268 return j;
269 }
270
271 do
272 {
273 top = pushd_directory_list[directory_list_offset - 1];
274
275 for (j = directory_list_offset - 2; j > -1; j--)
276 pushd_directory_list[j + 1] = pushd_directory_list[j];
277
278 pushd_directory_list[j + 1] = temp;
279
280 temp = top;
281 num--;
282 }
283 while (num);
284
285 j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
286 free (temp);
287 return j;
288 }
289
290 if (list == 0)
291 return (EXECUTION_SUCCESS);
292
293 /* Change to the directory in list->word->word. Save the current
294 directory on the top of the stack. */
295 current_directory = get_working_directory ("pushd");
296 if (current_directory == 0)
297 return (EXECUTION_FAILURE);
298
95732b49 299 j = ((flags & NOCD) == 0) ? cd_builtin (skipopt ? orig_list : list) : EXECUTION_SUCCESS;
ccc6cda3
JA
300 if (j == EXECUTION_SUCCESS)
301 {
302 add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory);
303 dirs_builtin ((WORD_LIST *)NULL);
d166f048
JA
304 if (flags & NOCD)
305 free (current_directory);
ccc6cda3
JA
306 return (EXECUTION_SUCCESS);
307 }
308 else
309 {
310 free (current_directory);
311 return (EXECUTION_FAILURE);
312 }
313}
314
315/* Pop the directory stack, and then change to the new top of the stack.
316 If LIST is non-null it should consist of a word +N or -N, which says
317 what element to delete from the stack. The default is the top one. */
318int
319popd_builtin (list)
320 WORD_LIST *list;
321{
322 register int i;
7117c2d2 323 intmax_t which;
ccc6cda3
JA
324 int flags;
325 char direction;
d166f048 326 char *which_word;
ccc6cda3 327
a0c0a00f
CR
328 CHECK_HELPOPT (list);
329
d166f048 330 which_word = (char *)NULL;
f73dda09 331 for (flags = 0, which = 0, direction = '+'; list; list = list->next)
ccc6cda3
JA
332 {
333 if (ISOPTION (list->word->word, 'n'))
28ef6c31
JA
334 {
335 flags |= NOCD;
336 }
ccc6cda3 337 else if (ISOPTION (list->word->word, '-'))
28ef6c31
JA
338 {
339 list = list->next;
340 break;
341 }
ccc6cda3
JA
342 else if (((direction = list->word->word[0]) == '+') || direction == '-')
343 {
344 if (legal_number (list->word->word + 1, &which) == 0)
345 {
7117c2d2 346 sh_invalidnum (list->word->word);
ccc6cda3 347 builtin_usage ();
ac50fbac 348 return (EX_USAGE);
ccc6cda3 349 }
d166f048 350 which_word = list->word->word;
ccc6cda3
JA
351 }
352 else if (*list->word->word == '-')
353 {
7117c2d2 354 sh_invalidopt (list->word->word);
ccc6cda3 355 builtin_usage ();
ac50fbac
CR
356 return (EX_USAGE);
357 }
358 else if (*list->word->word)
359 {
360 builtin_error (_("%s: invalid argument"), list->word->word);
361 builtin_usage ();
362 return (EX_USAGE);
ccc6cda3
JA
363 }
364 else
365 break;
366 }
367
44bfefc5 368 if (which > directory_list_offset || (which < -directory_list_offset) || (directory_list_offset == 0 && which == 0))
ccc6cda3 369 {
d166f048 370 pushd_error (directory_list_offset, which_word ? which_word : "");
ccc6cda3
JA
371 return (EXECUTION_FAILURE);
372 }
373
374 /* Handle case of no specification, or top of stack specification. */
375 if ((direction == '+' && which == 0) ||
376 (direction == '-' && which == directory_list_offset))
377 {
378 i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1])
28ef6c31 379 : EXECUTION_SUCCESS;
ccc6cda3
JA
380 if (i != EXECUTION_SUCCESS)
381 return (i);
382 free (pushd_directory_list[--directory_list_offset]);
383 }
384 else
385 {
386 /* Since an offset other than the top directory was specified,
387 remove that directory from the list and shift the remainder
388 of the list into place. */
389 i = (direction == '+') ? directory_list_offset - which : which;
44bfefc5
CR
390 if (i < 0 || i > directory_list_offset)
391 {
392 pushd_error (directory_list_offset, which_word ? which_word : "");
393 return (EXECUTION_FAILURE);
394 }
ccc6cda3
JA
395 free (pushd_directory_list[i]);
396 directory_list_offset--;
397
398 /* Shift the remainder of the list into place. */
399 for (; i < directory_list_offset; i++)
400 pushd_directory_list[i] = pushd_directory_list[i + 1];
401 }
402
403 dirs_builtin ((WORD_LIST *)NULL);
404 return (EXECUTION_SUCCESS);
405}
406
407/* Print the current list of directories on the directory stack. */
408int
409dirs_builtin (list)
410 WORD_LIST *list;
411{
412 int flags, desired_index, index_flag, vflag;
7117c2d2 413 intmax_t i;
ccc6cda3
JA
414 char *temp, *w;
415
a0c0a00f 416 CHECK_HELPOPT (list);
ccc6cda3
JA
417 for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next)
418 {
419 if (ISOPTION (list->word->word, 'l'))
420 {
421 flags |= LONGFORM;
422 }
423 else if (ISOPTION (list->word->word, 'c'))
424 {
425 flags |= CLEARSTAK;
426 }
427 else if (ISOPTION (list->word->word, 'v'))
428 {
429 vflag |= 2;
430 }
431 else if (ISOPTION (list->word->word, 'p'))
432 {
433 vflag |= 1;
434 }
435 else if (ISOPTION (list->word->word, '-'))
28ef6c31
JA
436 {
437 list = list->next;
438 break;
439 }
ccc6cda3 440 else if (*list->word->word == '+' || *list->word->word == '-')
28ef6c31
JA
441 {
442 int sign;
443 if (legal_number (w = list->word->word + 1, &i) == 0)
ccc6cda3 444 {
7117c2d2 445 sh_invalidnum (list->word->word);
ccc6cda3 446 builtin_usage ();
ac50fbac 447 return (EX_USAGE);
ccc6cda3
JA
448 }
449 sign = (*list->word->word == '+') ? 1 : -1;
450 desired_index = get_dirstack_index (i, sign, &index_flag);
451 }
452 else
453 {
7117c2d2 454 sh_invalidopt (list->word->word);
ccc6cda3 455 builtin_usage ();
ac50fbac 456 return (EX_USAGE);
ccc6cda3
JA
457 }
458 }
459
460 if (flags & CLEARSTAK)
461 {
462 clear_directory_stack ();
463 return (EXECUTION_SUCCESS);
464 }
465
466 if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
467 {
468 pushd_error (directory_list_offset, w);
469 return (EXECUTION_FAILURE);
470 }
471
472#define DIRSTACK_FORMAT(temp) \
473 (flags & LONGFORM) ? temp : polite_directory_format (temp)
474
475 /* The first directory printed is always the current working directory. */
476 if (index_flag == 0 || (index_flag == 1 && desired_index == 0))
477 {
478 temp = get_working_directory ("dirs");
479 if (temp == 0)
b80f6443 480 temp = savestring (_("<no current directory>"));
ccc6cda3
JA
481 if (vflag & 2)
482 printf ("%2d %s", 0, DIRSTACK_FORMAT (temp));
483 else
484 printf ("%s", DIRSTACK_FORMAT (temp));
485 free (temp);
486 if (index_flag)
487 {
488 putchar ('\n');
3185942a 489 return (sh_chkwrite (EXECUTION_SUCCESS));
ccc6cda3
JA
490 }
491 }
492
493#define DIRSTACK_ENTRY(i) \
494 (flags & LONGFORM) ? pushd_directory_list[i] \
495 : polite_directory_format (pushd_directory_list[i])
496
497 /* Now print the requested directory stack entries. */
498 if (index_flag)
499 {
500 if (vflag & 2)
501 printf ("%2d %s", directory_list_offset - desired_index,
502 DIRSTACK_ENTRY (desired_index));
503 else
504 printf ("%s", DIRSTACK_ENTRY (desired_index));
505 }
506 else
507 for (i = directory_list_offset - 1; i >= 0; i--)
508 if (vflag >= 2)
509 printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i));
510 else
511 printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i));
512
513 putchar ('\n');
3185942a
JA
514
515 return (sh_chkwrite (EXECUTION_SUCCESS));
ccc6cda3
JA
516}
517
518static void
519pushd_error (offset, arg)
520 int offset;
521 char *arg;
522{
523 if (offset == 0)
3185942a 524 builtin_error (_("directory stack empty"));
ccc6cda3 525 else
3185942a 526 sh_erange (arg, _("directory stack index"));
ccc6cda3
JA
527}
528
529static void
530clear_directory_stack ()
531{
532 register int i;
533
534 for (i = 0; i < directory_list_offset; i++)
535 free (pushd_directory_list[i]);
536 directory_list_offset = 0;
537}
538
539/* Switch to the directory in NAME. This uses the cd_builtin to do the work,
540 so if the result is EXECUTION_FAILURE then an error message has already
541 been printed. */
542static int
543cd_to_string (name)
544 char *name;
545{
546 WORD_LIST *tlist;
95732b49 547 WORD_LIST *dir;
ccc6cda3
JA
548 int result;
549
95732b49
JA
550 dir = make_word_list (make_word (name), NULL);
551 tlist = make_word_list (make_word ("--"), dir);
ccc6cda3
JA
552 result = cd_builtin (tlist);
553 dispose_words (tlist);
554 return (result);
555}
556
557static int
558change_to_temp (temp)
559 char *temp;
560{
561 int tt;
562
563 tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE;
564
565 if (tt == EXECUTION_SUCCESS)
566 dirs_builtin ((WORD_LIST *)NULL);
567
568 return (tt);
569}
570
571static void
572add_dirstack_element (dir)
573 char *dir;
574{
ccc6cda3 575 if (directory_list_offset == directory_list_size)
7117c2d2 576 pushd_directory_list = strvec_resize (pushd_directory_list, directory_list_size += 10);
ccc6cda3
JA
577 pushd_directory_list[directory_list_offset++] = dir;
578}
579
580static int
581get_dirstack_index (ind, sign, indexp)
7117c2d2 582 intmax_t ind;
f73dda09 583 int sign, *indexp;
ccc6cda3
JA
584{
585 if (indexp)
586 *indexp = sign > 0 ? 1 : 2;
587
588 /* dirs +0 prints the current working directory. */
589 /* dirs -0 prints last element in directory stack */
590 if (ind == 0 && sign > 0)
591 return 0;
592 else if (ind == directory_list_offset)
593 {
594 if (indexp)
595 *indexp = sign > 0 ? 2 : 1;
596 return 0;
597 }
f73dda09 598 else if (ind >= 0 && ind <= directory_list_offset)
ccc6cda3 599 return (sign > 0 ? directory_list_offset - ind : ind);
f73dda09
JA
600 else
601 return -1;
ccc6cda3
JA
602}
603
cce855bc
JA
604/* Used by the tilde expansion code. */
605char *
606get_dirstack_from_string (string)
607 char *string;
608{
609 int ind, sign, index_flag;
7117c2d2 610 intmax_t i;
cce855bc
JA
611
612 sign = 1;
613 if (*string == '-' || *string == '+')
614 {
615 sign = (*string == '-') ? -1 : 1;
616 string++;
617 }
618 if (legal_number (string, &i) == 0)
619 return ((char *)NULL);
620
621 index_flag = 0;
622 ind = get_dirstack_index (i, sign, &index_flag);
623 if (index_flag && (ind < 0 || ind > directory_list_offset))
624 return ((char *)NULL);
625 if (index_flag == 0 || (index_flag == 1 && ind == 0))
626 return (get_string_value ("PWD"));
627 else
628 return (pushd_directory_list[ind]);
629}
630
631#ifdef INCLUDE_UNUSED
ccc6cda3
JA
632char *
633get_dirstack_element (ind, sign)
7117c2d2 634 intmax_t ind;
f73dda09 635 int sign;
ccc6cda3
JA
636{
637 int i;
638
639 i = get_dirstack_index (ind, sign, (int *)NULL);
640 return (i < 0 || i > directory_list_offset) ? (char *)NULL
641 : pushd_directory_list[i];
642}
cce855bc 643#endif
ccc6cda3
JA
644
645void
646set_dirstack_element (ind, sign, value)
7117c2d2 647 intmax_t ind;
f73dda09 648 int sign;
ccc6cda3
JA
649 char *value;
650{
651 int i;
652
653 i = get_dirstack_index (ind, sign, (int *)NULL);
654 if (ind == 0 || i < 0 || i > directory_list_offset)
655 return;
656 free (pushd_directory_list[i]);
657 pushd_directory_list[i] = savestring (value);
658}
659
660WORD_LIST *
0628567a
JA
661get_directory_stack (flags)
662 int flags;
ccc6cda3
JA
663{
664 register int i;
665 WORD_LIST *ret;
666 char *d, *t;
667
668 for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++)
669 {
0628567a
JA
670 d = (flags&1) ? polite_directory_format (pushd_directory_list[i])
671 : pushd_directory_list[i];
ccc6cda3
JA
672 ret = make_word_list (make_word (d), ret);
673 }
674 /* Now the current directory. */
675 d = get_working_directory ("dirstack");
676 i = 0; /* sentinel to decide whether or not to free d */
677 if (d == 0)
678 d = ".";
679 else
680 {
d233b485 681 t = (flags&1) ? polite_directory_format (d) : d;
ccc6cda3
JA
682 /* polite_directory_format sometimes returns its argument unchanged.
683 If it does not, we can free d right away. If it does, we need to
684 mark d to be deleted later. */
685 if (t != d)
686 {
687 free (d);
688 d = t;
689 }
690 else /* t == d, so d is what we want */
691 i = 1;
692 }
693 ret = make_word_list (make_word (d), ret);
694 if (i)
695 free (d);
696 return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */
697}
b72432fd
JA
698
699#ifdef LOADABLE_BUILTIN
0628567a 700char * const dirs_doc[] = {
3185942a
JA
701N_("Display the list of currently remembered directories. Directories\n\
702 find their way onto the list with the `pushd' command; you can get\n\
703 back up through the list with the `popd' command.\n\
704 \n\
705 Options:\n\
706 -c clear the directory stack by deleting all of the elements\n\
707 -l do not print tilde-prefixed versions of directories relative\n\
708 to your home directory\n\
709 -p print the directory stack with one entry per line\n\
710 -v print the directory stack with one entry per line prefixed\n\
711 with its position in the stack\n\
712 \n\
713 Arguments:\n\
714 +N Displays the Nth entry counting from the left of the list shown by\n\
715 dirs when invoked without options, starting with zero.\n\
716 \n\
717 -N Displays the Nth entry counting from the right of the list shown by\n\
718 dirs when invoked without options, starting with zero."),
b72432fd
JA
719 (char *)NULL
720};
721
0628567a 722char * const pushd_doc[] = {
3185942a
JA
723N_("Adds a directory to the top of the directory stack, or rotates\n\
724 the stack, making the new top of the stack the current working\n\
725 directory. With no arguments, exchanges the top two directories.\n\
726 \n\
727 Options:\n\
728 -n Suppresses the normal change of directory when adding\n\
729 directories to the stack, so only the stack is manipulated.\n\
730 \n\
731 Arguments:\n\
732 +N Rotates the stack so that the Nth directory (counting\n\
733 from the left of the list shown by `dirs', starting with\n\
734 zero) is at the top.\n\
735 \n\
736 -N Rotates the stack so that the Nth directory (counting\n\
737 from the right of the list shown by `dirs', starting with\n\
738 zero) is at the top.\n\
739 \n\
740 dir Adds DIR to the directory stack at the top, making it the\n\
741 new current working directory.\n\
742 \n\
743 The `dirs' builtin displays the directory stack."),
b72432fd
JA
744 (char *)NULL
745};
746
0628567a 747char * const popd_doc[] = {
3185942a
JA
748N_("Removes entries from the directory stack. With no arguments, removes\n\
749 the top directory from the stack, and changes to the new top directory.\n\
750 \n\
751 Options:\n\
752 -n Suppresses the normal change of directory when removing\n\
753 directories from the stack, so only the stack is manipulated.\n\
754 \n\
755 Arguments:\n\
756 +N Removes the Nth entry counting from the left of the list\n\
757 shown by `dirs', starting with zero. For example: `popd +0'\n\
758 removes the first directory, `popd +1' the second.\n\
759 \n\
760 -N Removes the Nth entry counting from the right of the list\n\
761 shown by `dirs', starting with zero. For example: `popd -0'\n\
762 removes the last directory, `popd -1' the next to last.\n\
763 \n\
764 The `dirs' builtin displays the directory stack."),
b72432fd
JA
765 (char *)NULL
766};
767
768struct builtin pushd_struct = {
769 "pushd",
770 pushd_builtin,
771 BUILTIN_ENABLED,
772 pushd_doc,
773 "pushd [+N | -N] [-n] [dir]",
774 0
775};
776
777struct builtin popd_struct = {
778 "popd",
779 popd_builtin,
780 BUILTIN_ENABLED,
781 popd_doc,
782 "popd [+N | -N] [-n]",
783 0
784};
785
786struct builtin dirs_struct = {
787 "dirs",
788 dirs_builtin,
789 BUILTIN_ENABLED,
790 dirs_doc,
791 "dirs [-clpv] [+N] [-N]",
792 0
793};
794#endif /* LOADABLE_BUILTIN */
795
ccc6cda3 796#endif /* PUSHD_AND_POPD */