~ubuntu-branches/ubuntu/trusty/bash/trusty-security

« back to all changes in this revision

Viewing changes to builtins/pushd.def

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2014-03-03 22:52:05 UTC
  • mfrom: (1.3.5) (2.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20140303225205-87ltrt5kspeq0g1b
Tags: 4.3-1ubuntu1
* Merge with Debian; remaining changes:
  - skel.bashrc:
    - Run lesspipe.
    - Enable ls aliases.
    - Set options in ll alias to -alF.
    - Define an alert alias.
    - Enabled colored grep aliases.
  - etc.bash.bashrc:
    - Add sudo hint.

Show diffs side-by-side

added added

removed removed

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