Go back to simpler chdir_arg API

* src/misc.c (add_wd, ensure_wd): New functions, replacing ...
(grow_wd): .. this function, for clarity.  All uses changed.
(chdir_arg): Omit 2nd arg, to keep callers simpler.
All uses changed.  Instead of being recursive, be iterative;
this is part of the simplification.
This commit is contained in:
Paul Eggert
2026-07-29 23:12:46 -07:00
parent e335e2c8b1
commit 0ec9f0ebf6
3 changed files with 50 additions and 48 deletions
+1 -1
View File
@@ -782,7 +782,7 @@ idx_t blocking_write (int fd, void const *buf, idx_t count);
enum { BADFD = AT_FDCWD == -1 ? -2 : -1 };
extern idx_t chdir_current;
idx_t chdir_arg (char const *dir, bool one_top_level);
idx_t chdir_arg (char const *dir);
void chdir_do (idx_t dir, bool create);
struct chdir_id { int err; dev_t st_dev; ino_t st_ino; } chdir_id (void);
struct fdbase fdbase (char const *);
+45 -42
View File
@@ -1015,65 +1015,69 @@ chdir_count (void)
return count;
}
/* Grow the WD table by at least one entry. */
/* Add DIR to the WD table. If one_top_level_dir, add that too.
There must already be room.
DFD is either AT_FDWD for the initial "." entry,
or 0 meaning the file descriptor is not open yet. */
static void
grow_wd (void)
add_wd (char const *dir, int dfd)
{
wd = xpalloc (wd, &wd_alloc, wd_alloc ? 1 : 2, -1, sizeof *wd);
wd[wd_count].name = dir;
wd[wd_count].abspath = NULL;
wd[wd_count].fd = dfd;
wd[wd_count].id.err = -1;
wd[wd_count].one_top_level = false;
wd_count++;
if (! wd_count)
if (one_top_level_dir)
{
wd[wd_count].name = ".";
wd[wd_count].name = one_top_level_dir;
wd[wd_count].abspath = NULL;
wd[wd_count].fd = AT_FDCWD;
wd[wd_count].fd = 0;
wd[wd_count].id.err = -1;
wd[wd_count].one_top_level = false;
wd[wd_count].one_top_level = true;
wd_count++;
if (one_top_level_dir)
{
wd[wd_count].name = one_top_level_dir;
wd[wd_count].abspath = NULL;
wd[wd_count].fd = 0;
wd[wd_count].id.err = -1;
wd[wd_count].one_top_level = true;
wd_count++;
}
}
}
/* Ensure that WD exists, with an initial "." entry. */
static void
ensure_wd (void)
{
if (!wd)
{
/* This must be at least 1 + !!top_level_dir. Make it 4, to lessen
reallocation effort when -C and --one-top-level are both used. */
int n_incr_min = 4;
wd = xpalloc (NULL, &wd_alloc, n_incr_min, -1, sizeof *wd);
add_wd (".", AT_FDCWD);
}
}
/* DIR is the operand of a -C option; add it to vector of chdir targets,
and return the index of its location. */
and return the index of its location. If --one-top-level-dir, add
two targets to the vector. However, if DIR is "." or an equivalent,
just reuse the last item in the vector. */
idx_t
chdir_arg (char const *dir, bool one_top_level)
chdir_arg (char const *dir)
{
if (one_top_level)
chdir_arg (dir, false);
if (wd_count == wd_alloc)
grow_wd ();
ensure_wd ();
/* Optimize the common special case of the working directory,
or the working directory as a prefix. */
if (dir[0])
{
dir += dotslashlen (dir);
if (! dir[dir[0] == '.'])
{
if (wd[wd_count - 1].one_top_level == one_top_level)
return wd_count - 1;
else
return wd_count - 2;
}
if (!dir[dir[0] == '.'])
return wd_count - 1;
}
if (one_top_level)
dir = one_top_level_dir;
wd[wd_count].name = dir;
wd[wd_count].abspath = NULL;
wd[wd_count].fd = 0;
wd[wd_count].id.err = -1;
wd[wd_count].one_top_level = one_top_level;
return wd_count++;
ptrdiff_t shortage = 1 + !!one_top_level_dir - (wd_alloc - wd_count);
if (0 < shortage)
wd = xpalloc (wd, &wd_alloc, shortage, -1, sizeof *wd);
add_wd (dir, 0);
return wd_count - 1;
}
/* Index of current directory. */
@@ -1202,8 +1206,7 @@ chdir_do (idx_t i, bool create)
struct chdir_id
chdir_id (void)
{
if (!wd)
grow_wd ();
ensure_wd ();
struct wd *curr = &wd[chdir_current];
if (curr->id.err < 0)
@@ -1418,8 +1421,8 @@ transform_top_level (const char *name)
/* Return the absolute path that represents the working
directory referenced by IDX.
If wd is empty, then there were no -C options given, and
chdir_args() has never been called, so we simply return the
If wd is empty, then no -C options were given, and
chdir_arg has never been called, so simply return the
process's actual cwd. (Note that in this case IDX is ignored,
since it should always be 0.) */
static const char *
+4 -5
View File
@@ -875,7 +875,7 @@ static idx_t name_buffer_length; /* allocated length of name_buffer */
void
name_init (void)
{
chdir_do (chdir_arg (".", !!one_top_level_dir), false);
chdir_do (chdir_arg ("."), false);
name_list_adjust ();
}
@@ -1119,8 +1119,7 @@ name_next_elt (bool change_dirs)
case NELT_CHDIR:
if (change_dirs)
{
chdir_do (chdir_arg (xstrdup (ep->v.name), !!one_top_level_dir),
false);
chdir_do (chdir_arg (xstrdup (ep->v.name)), false);
name_list_advance ();
break;
}
@@ -1183,7 +1182,7 @@ name_gather (void)
static idx_t change_dir;
while ((ep = name_next_elt (false)) && ep->type == NELT_CHDIR)
change_dir = chdir_arg (xstrdup (ep->v.name), !!one_top_level_dir);
change_dir = chdir_arg (xstrdup (ep->v.name));
if (ep)
{
@@ -1212,7 +1211,7 @@ name_gather (void)
{
idx_t change_dir0 = change_dir;
while ((ep = name_next_elt (false)) && ep->type == NELT_CHDIR)
change_dir = chdir_arg (xstrdup (ep->v.name), !!one_top_level_dir);
change_dir = chdir_arg (xstrdup (ep->v.name));
if (ep)
addname (ep->v.name, change_dir, true, NULL);