Skip to content

Commit

Permalink
feat: deduplicate absolute and relative paths
Browse files Browse the repository at this point in the history
The user may avoid path deduplication by passing absolute paths to
mmv. For example, if the user gives a path to a relative file and an
absolute path to the same file, both will appear in the editing buffer,
allowing for them to conduct dangerous naming operations.

This commit initializes deduplication for this edge case. If the user
gives the "resolve paths" option, they will receive absolute paths
back. If they do not, they will receive the paths the entered as is,
but with duplicates removed. This allows for a mix of relative and
absolute paths.
  • Loading branch information
mcauley-penney committed Dec 14, 2023
1 parent 69cc314 commit 4ae4a67
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 8 deletions.
2 changes: 1 addition & 1 deletion main.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ int main(int argc, char *argv[])
argv += optind;
argc -= optind;

struct Set *src_set = set_init(options->resolve_paths, argc, argv, false);
struct Set *src_set = init_src_set(argc, argv, options);
if (src_set == NULL)
goto free_opts_out;

Expand Down
60 changes: 57 additions & 3 deletions src/mmv.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ int write_strarr_to_tmpfile(struct Set *set, char tmpfile_template[])
FILE *tmp_fptr = fdopen(tmp_fd, "w");

for (i = set_begin(set); i < set_end_pos; i = set_next(i))
fprintf(tmp_fptr, "%s\n", *get_set_pos(set, i));
if (is_valid_key(i))
fprintf(tmp_fptr, "%s\n", *get_set_pos(set, i));

fclose(tmp_fptr);

Expand Down Expand Up @@ -49,6 +50,59 @@ int edit_tmpfile(char *path)
return 0;
}

struct Set *init_src_set(const int num_keys, char *argv[], struct Opts *options)
{
// prepare for duplicate removal by creating array of absolute paths from commandline args
char **realpath_argv = malloc(sizeof(char *) * (unsigned int)num_keys);
if (realpath_argv == NULL)
{
perror("mmv: failed to allocate memory for absolute path array");
return NULL;
}

for (int i = 0; i < num_keys; i++)
if (cpy_str_to_arr(&realpath_argv[i], realpath(argv[i], NULL)) == NULL)
{
free(realpath_argv);
return NULL;
}

// turn array of absolute paths into a set to rm duplicates
struct Set *realpath_set = set_init(options->resolve_paths, num_keys, realpath_argv, true);

if (realpath_set == NULL)
{
free(realpath_argv);
return NULL;
}

struct Set *src_set = realpath_set;

// if not using the resolve paths opt, give the original arg
// strings, those used on the commandline, back to the user.
if (!options->resolve_paths)
{
int *key, *set_end_pos = set_end(realpath_set), key_num = 0;
for (key = set_begin(realpath_set); key < set_end_pos; key = set_next(key))
if (is_valid_key(key))
{
if (cpy_str_to_arr(&realpath_argv[key_num], argv[key_num]) == NULL)
{
free(src_set);
return NULL;
}

key_num++;
}

src_set = set_init(false, key_num, realpath_argv, false);
}

free(realpath_argv);

return src_set;
}

struct Set *init_dest_set(unsigned int num_keys, char path[])
{
// size of destination array only needs to be, at
Expand Down Expand Up @@ -123,7 +177,7 @@ int rename_paths(struct Set *src_set, struct Set *dest_set, struct Opts *opts)
src_str = *get_set_pos(src_set, i);
dest_str = *get_set_pos(dest_set, j);

if (!is_invalid_key(j))
if (is_valid_key(j))
rename_path(src_str, dest_str, opts);
}

Expand Down Expand Up @@ -176,7 +230,7 @@ int rm_cycles(struct Set *src_set, struct Set *dest_set, struct Opts *opts)
for (i = set_begin(src_set), j = set_begin(dest_set); i < src_end_pos && j < dest_end_pos;
i = set_next(i), j = set_next(j))
{
if (!is_invalid_key(j))
if (is_valid_key(j))
{
dest_str = *get_set_pos(dest_set, j);
u_key = (unsigned int)*j;
Expand Down
2 changes: 2 additions & 0 deletions src/mmv.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ struct Opts
bool verbose;
};

struct Set *init_src_set(const int arg_count, char *args[], struct Opts *options);

/**
* @brief opens temp file at path, writes source strings (old names)
* to it, and closes said temp file
Expand Down
4 changes: 2 additions & 2 deletions src/set.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ char **get_set_pos(const struct Set *set, const int *iter)
return &(set->map[*iter]);
}

int is_invalid_key(const int *iter)
int is_valid_key(const int *iter)
{
return *iter == -1;
return *iter != -1;
}

int set_key(int *iter, int new_key)
Expand Down
2 changes: 1 addition & 1 deletion src/set.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ int *set_end(struct Set *set);

char **get_set_pos(const struct Set *set, const int *iter);

int is_invalid_key(const int *iter);
int is_valid_key(const int *iter);

int set_key(int *iter, int new_key);

Expand Down
2 changes: 1 addition & 1 deletion test/test_set.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ void test_set_init_onedupe_track(void)
test_set = set_init(false, argc, dupe_argv, true);
i = set_begin(test_set);
i = set_next(i);
TEST_ASSERT_TRUE(is_invalid_key(i));
TEST_ASSERT_FALSE(is_valid_key(i));
set_destroy(test_set);
}

Expand Down

0 comments on commit 4ae4a67

Please sign in to comment.