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