Skip to content

Commit

Permalink
refactor: explicitly handle unedited args
Browse files Browse the repository at this point in the history
It is possible to pass args to mmv and subsequently not edit
them in the editing buffer. Until now, avoiding working with
these args was handled in various places, such as via checks
in our rename function and in our cycle removal function.

This commit adds a function which checks for such args and
replaces their key in the set data structure with an invalid
key so that they will not be looked at for cycle removal or
renaming. For example, if the user does

```
mmv -v test1.txt test2.txt
```

but then does not edit `test2.txt` in the editing buffer,
`test2.txt` will appear as the destination name for the
`test2.txt` source arg, given that it was not edited. When
the sets are subjected to this function, `test2.txt` will be
found as a duplicate of its source argument and will be avoided
in later operations.
  • Loading branch information
mcauley-penney committed Dec 7, 2023
1 parent e8ee625 commit 69cc314
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 22 deletions.
3 changes: 3 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ int main(int argc, char *argv[])
if (dest_set == NULL)
goto rm_path_out;

if (rm_unedited_pairs(src_set, dest_set, options) != 0)
goto free_dest_out;

if (argc > 1 && rm_cycles(src_set, dest_set, options) != 0)
goto free_dest_out;

Expand Down
47 changes: 31 additions & 16 deletions src/mmv.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,19 +125,13 @@ int rename_paths(struct Set *src_set, struct Set *dest_set, struct Opts *opts)

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

else
fprintf(stderr, "mmv: duplicate dest found for src '%s'. No mv conducted.\n", src_str);
}

return 0;
}

void rename_path(const char *src, const char *dest, struct Opts *opts)
{
if (strcmp(src, dest) == 0)
return;

if (rename(src, dest) == -1)
{
fprintf(stderr, "mmv: \'%s\' to \'%s\': %s\n", src, dest, strerror(errno));
Expand All @@ -150,30 +144,51 @@ void rename_path(const char *src, const char *dest, struct Opts *opts)
printf(" '%s' to '%s'\n", src, dest);
}

// TODO: modularize
int rm_cycles(struct Set *src_set, struct Set *dest_set, struct Opts *opts)
int rm_unedited_pairs(struct Set *src_set, struct Set *dest_set, struct Opts *opts)
{
int is_dupe, *i, *j, *src_end_pos = set_end(src_set), *dest_end_pos = set_end(dest_set);
unsigned long int u_key;
char *src_str, *dest_str, **cur_src_pos;
char *src_str, *dest_str;
int *i, *j, *src_end_pos = set_end(src_set), *dest_end_pos = set_end(dest_set);

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))
{
src_str = *get_set_pos(src_set, i);
dest_str = *get_set_pos(dest_set, j);

if (!is_invalid_key(j) && strcmp(src_str, dest_str) != 0)
if (strcmp(src_str, dest_str) == 0)
{
set_key(j, -1);

if (opts->verbose)
printf(" '%s' was not edited. No mv will be conducted.\n", src_str);
}
}

return 0;
}

int rm_cycles(struct Set *src_set, struct Set *dest_set, struct Opts *opts)
{
int is_dupe, *i, *j, *src_end_pos = set_end(src_set), *dest_end_pos = set_end(dest_set);
unsigned long int u_key;
char *dest_str, *tmp_path, **cur_src_pos;

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))
{
u_key = (unsigned int)*j;
is_dupe = is_duplicate_element(dest_str, src_set, &u_key);
char template[] = "_mmv_XXXXXX";
dest_str = *get_set_pos(dest_set, j);
u_key = (unsigned int)*j;
is_dupe = is_duplicate_element(dest_str, src_set, &u_key);

if (is_dupe == 0)
{
cur_src_pos = get_set_pos(src_set, j);
char template[] = "_mmv_XXXXXX";
char *tmp_path_parts[2] = {*cur_src_pos, template};
char *tmp_path = strccat(tmp_path_parts, 2);

tmp_path = strccat(tmp_path_parts, 2);
if (tmp_path == NULL)
{
perror("mmv: failed to allocate memory for cycle-removal temporary path");
Expand Down
2 changes: 2 additions & 0 deletions src/mmv.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,6 @@ int rename_paths(struct Set *src_set, struct Set *dest_set, struct Opts *options
*/
void rename_path(const char *src, const char *dest, struct Opts *options);

int rm_unedited_pairs(struct Set *src_set, struct Set *dest_set, struct Opts *opts);

int rm_cycles(struct Set *src_set, struct Set *dest_set, struct Opts *options);
5 changes: 5 additions & 0 deletions src/set.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,8 @@ int is_invalid_key(const int *iter)
{
return *iter == -1;
}

int set_key(int *iter, int new_key)
{
return *iter = new_key;
}
1 change: 1 addition & 0 deletions src/set.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@ char **get_set_pos(const struct Set *set, const int *iter);

int is_invalid_key(const int *iter);

int set_key(int *iter, int new_key);

#endif // SET_H
60 changes: 54 additions & 6 deletions test/test_mmv.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,53 @@ void test_read_tmpfile_strs(void)
set_destroy(test_set);
}

void test_rm_cycles()
void test_rm_unedited_pairs_no_matches(void)
{
int *i;

struct Opts *options = make_opts();

// 1. create two sets
int src_argc = 2;
char *src_argv[] = {"TEST_STRING1", "TEST_STRING2"};
struct Set *src_set = set_init(false, src_argc, src_argv, false);

int dest_argc = 2;
char *dest_argv[] = {"TEST_STRING2", "TEST_STRING3"};
struct Set *dest_set = set_init(false, dest_argc, dest_argv, false);

// 2. subject them to rm_unedited_pairs()
rm_unedited_pairs(src_set, dest_set, options);

// 3. check their keys
for (i = set_begin(dest_set); i < set_end(dest_set) - 1; i = set_next(i))
TEST_ASSERT(*i != -1);
}

void test_rm_unedited_pairs_matches(void)
{
int *i;

struct Opts *options = make_opts();

// 1. create two sets
int src_argc = 2;
char *src_argv[] = {"TEST_STRING1", "TEST_STRING2"};
struct Set *src_set = set_init(false, src_argc, src_argv, false);

int dest_argc = 2;
char *dest_argv[] = {"TEST_STRING1", "TEST_STRING3"};
struct Set *dest_set = set_init(false, dest_argc, dest_argv, false);

// 2. subject them to rm_unedited_pairs()
rm_unedited_pairs(src_set, dest_set, options);

// 3. check their keys
i = set_begin(dest_set);
TEST_ASSERT_EQUAL_INT(-1, *i);
}

void test_rm_cycles(void)
{
struct Opts *options = make_opts();

Expand Down Expand Up @@ -139,11 +185,13 @@ int main(void)
{
UNITY_BEGIN();

RUN_TEST(test_rename_path); // rename_path
RUN_TEST(test_write_strarr_to_tmpfile); // write_strarr_to_tmpfile
RUN_TEST(test_edit_tmpfile); // edit_tmpfile
RUN_TEST(test_read_tmpfile_strs); // read_tmpfile_strs
RUN_TEST(test_rm_cycles); // rm_cycles
RUN_TEST(test_rename_path); // rename_path
RUN_TEST(test_write_strarr_to_tmpfile); // write_strarr_to_tmpfile
RUN_TEST(test_edit_tmpfile); // edit_tmpfile
RUN_TEST(test_read_tmpfile_strs); // read_tmpfile_strs
RUN_TEST(test_rm_unedited_pairs_no_matches); // rm_unedited_pairs
RUN_TEST(test_rm_unedited_pairs_matches); // rm_unedited_pairs
RUN_TEST(test_rm_cycles); // rm_cycles

return UNITY_END();
}

0 comments on commit 69cc314

Please sign in to comment.