Skip to content

Commit

Permalink
lib/cmdline.c: Refactor `rm_cmd_set_paths*()'
Browse files Browse the repository at this point in the history
The code has been organized into finer-grained functions/macros,
and has thereby been easily optimized for certain cases.
  • Loading branch information
mfwitten committed Oct 16, 2018
2 parents f53b7d8 + c5b7b3e commit 4627418
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 80 deletions.
25 changes: 18 additions & 7 deletions lib/cfg-funcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,25 +125,36 @@ bool rm_cfg_prepend_json(
} return false;
}

#define PREPEND_TO(list) \
rm_path_prepend( \
&(list), \
real_path, \
index, \
preferred \
)

static INLINE
bool rm_cfg_prepend_path(
RmCfg *const cfg,
const char *const path,
const unsigned int index,
const bool replay,
const bool preferred
) {
g_assert(cfg);
char *real_path;
if(rm_path_is_valid(path, &real_path)) {
rm_path_prepend(
(cfg->replay && rm_path_is_json(path)) ?
&cfg->json_paths : &cfg->paths,
real_path,
cfg->path_count++,
preferred
); return true;
if(replay && rm_path_is_json(path)) {
PREPEND_TO(cfg->json_paths);
} else {
PREPEND_TO(cfg->paths);
++(cfg->path_count);
} return true;
} return false;
}

#undef PREPEND_TO

static INLINE
void rm_cfg_free_paths(RmCfg *const cfg) {
g_assert(cfg);
Expand Down
16 changes: 6 additions & 10 deletions lib/cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ typedef struct RmCfg {
gboolean progress_enabled;
gboolean list_mounts;
gboolean replay;
gboolean read_stdin;
gboolean read_stdin0;
gboolean no_backup;

Expand Down Expand Up @@ -101,16 +100,13 @@ typedef struct RmCfg {
*
* + To record a unique index for each path supplied by the
* user; a path's index represents the number of paths that
* were already processed. This is always the case.
* were already processed. This is the case DURING the
* processing of user-input options (such as '--replay').
*
* + To provide quick access to the length of its associated
* RmCfg::paths list. This is only the case when NOT running
* in "--replay" mode; when running in "--replay" mode, it
* just represents the total number of paths that have been
* supplied by the user, i.e., the sums of the lengths of
* the associated lists RmCfg::{paths,json_paths}, which is
* not meant to be a useful number to know, and is simply a
* byproduct of calculating path indicies.
* + To provide quick access to the length of its associated
* RmCfg::paths list. This is the case AFTER the processing
* of user-input options (including during the processing of
* non-option paths from the command line or stdin).
*/
guint path_count;

Expand Down
161 changes: 112 additions & 49 deletions lib/cmdline.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,31 +360,6 @@ static GLogLevelFlags VERBOSITY_TO_LOG_LEVEL[] = {[0] = G_LOG_LEVEL_CRITICAL,
[3] = G_LOG_LEVEL_MESSAGE |
G_LOG_LEVEL_INFO,
[4] = G_LOG_LEVEL_DEBUG};
static bool rm_cmd_read_paths_from_stdin(RmSession *session, bool is_prefd,
bool null_separated) {
char delim = null_separated ? 0 : '\n';

size_t buf_len = PATH_MAX;
char *path_buf = malloc(buf_len * sizeof(char));

bool all_paths_read = true;

int path_len;

/* Still read all paths on errors, so the user knows all paths that failed */
while((path_len = getdelim(&path_buf, &buf_len, delim, stdin)) >= 0) {
if(path_len > 0) {
/* replace returned delimiter with null */
if (path_buf[path_len - 1] == delim) {
path_buf[path_len - 1] = 0;
}
all_paths_read &= rm_cfg_prepend_path(session->cfg, path_buf, is_prefd);
}
}

free(path_buf);
return all_paths_read;
}

static bool rm_cmd_parse_output_pair(RmSession *session, const char *pair,
GError **error) {
Expand Down Expand Up @@ -1170,42 +1145,130 @@ static bool rm_cmd_set_cmdline(RmCfg *cfg, int argc, char **argv) {
return true;
}

static bool rm_cmd_set_paths(RmSession *session, char **paths) {
bool is_prefd = false;
bool all_paths_valid = true;
bool stdin_paths_preferred = false;

RmCfg *cfg = session->cfg;

/* Check the directory to be valid */
for(int i = 0; paths && paths[i]; ++i) {
if(strcmp(paths[i], "-") == 0) {
cfg->read_stdin = true;
typedef struct rm_cmd_set_paths_vars {
RmCfg *const cfg;
char **const paths;
unsigned int index;
bool is_prefd;
bool read_stdin;
bool stdin_paths_preferred;
const bool null_separated;
bool all_paths_valid;
} rm_cmd_set_paths_vars;

static INLINE
void rm_cmd_set_paths_from_cmdline(
rm_cmd_set_paths_vars *const v,
const bool replay
) {
g_assert(v);
g_assert(v->paths);

for(char *path, **list = v->paths; (path = *list); ++list) {
if(path[0] == '-' && path[1] == 0) {
v->read_stdin = true;
/* remember whether to treat stdin paths as preferred paths */
stdin_paths_preferred = is_prefd;
} else if(strcmp(paths[i], "//") == 0) {
v->stdin_paths_preferred = v->is_prefd;
} else if(path[0] == '/' && path[1] == '/' && path[2] == 0) {
/* the '//' separator separates non-preferred paths from preferred */
is_prefd = !is_prefd;
v->is_prefd = !v->is_prefd;
} else {
all_paths_valid &= rm_cfg_prepend_path(cfg, paths[i], is_prefd);
v->all_paths_valid &= rm_cfg_prepend_path(
v->cfg, path, v->index++, replay, v->is_prefd
);
}
g_free(path);
}
g_free(v->paths);
}

static INLINE
bool rm_cmd_set_paths_from_stdin(
rm_cmd_set_paths_vars *const v,
const bool replay
) {
g_assert(v);
g_assert(v->cfg);

RmCfg *const cfg = v->cfg;
const bool is_prefd = v->stdin_paths_preferred;

char delim = v->null_separated ? 0 : '\n';

size_t buf_len;
char *path_buf = malloc(buf_len = PATH_MAX);
if(!path_buf) {
rm_log_perror(_("Failed to allocate memory"));
return false;
}

int path_len;

/* Still read all paths on errors, so the user knows all paths that failed */
while((path_len = getdelim(&path_buf, &buf_len, delim, stdin)) >= 0) {
if(path_len > 0) {
/* replace returned delimiter with null */
if(path_buf[path_len - 1] == delim) {
path_buf[path_len - 1] = 0;
}
v->all_paths_valid &= rm_cfg_prepend_path(
cfg, path_buf, v->index++, replay, is_prefd
);
}
}

g_strfreev(paths);
if(ferror(stdin)) {
rm_log_perror(_("Failed to read stdin"))
return false;
}

free(path_buf);
return true;
}

#define PROCESS_PATHS(replay) \
if(paths) { \
rm_cmd_set_paths_from_cmdline(&v, (replay)); \
} \
if(v.read_stdin) { \
if(!rm_cmd_set_paths_from_stdin(&v, (replay))) { \
rm_log_error_line(_("Could not process path arguments")); \
return false; \
} \
}

static INLINE
bool rm_cmd_set_paths(RmCfg *const cfg, char **const paths) {
g_assert(cfg);

const bool replay = cfg->replay;
const bool read_stdin0 = cfg->read_stdin0;
rm_cmd_set_paths_vars v = {
.cfg = cfg,
.paths = paths,
.index = cfg->path_count,
.read_stdin = read_stdin0,
.null_separated = read_stdin0,
.all_paths_valid = true
};

cfg->path_count = 0;

if(cfg->read_stdin || cfg->read_stdin0) {
/* option '-' means read paths from stdin */
all_paths_valid &=
rm_cmd_read_paths_from_stdin(session, stdin_paths_preferred, cfg->read_stdin0);
if(replay) {
PROCESS_PATHS(true);
} else {
PROCESS_PATHS(false);
}

if(g_slist_length(cfg->paths) == 0 && all_paths_valid) {
if(cfg->path_count == 0 && v.all_paths_valid) {
/* Still no path set? - use `pwd` */
rm_cfg_prepend_path(session->cfg, cfg->iwd, is_prefd);
rm_cfg_prepend_path(
cfg, cfg->iwd, v.index, /* replay */ false, v.is_prefd
);
}

/* Only return success if everything is fine. */
return all_paths_valid;
return v.all_paths_valid;
}

static bool rm_cmd_set_outputs(RmSession *session, GError **error) {
Expand Down Expand Up @@ -1466,7 +1529,7 @@ bool rm_cmd_parse_args(int argc, char **argv, RmSession *session) {
goto cleanup;
}

if(!rm_cmd_set_paths(session, paths)) {
if(!rm_cmd_set_paths(cfg, paths)) {
error = g_error_new(RM_ERROR_QUARK, 0, _("Not all given paths are valid. Aborting"));
goto cleanup;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/treemerge.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ static bool rm_tm_count_files(RmTrie *count_tree, const RmCfg *const cfg) {

const char **const path_vec = malloc(sizeof(*path_vec) * (path_count + 1));
if(!path_vec) {
rm_log_error(_("Failed to allocate memory. Out of memory?"));
rm_log_perror(_("Failed to allocate memory"));
return false;
}

Expand Down
14 changes: 11 additions & 3 deletions po/de.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: rmlint 2.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-06 00:43+0000\n"
"POT-Creation-Date: 2018-10-15 04:46+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand Down Expand Up @@ -1015,8 +1015,8 @@ msgstr ""
msgid "Failed to complete setup for merging directories"
msgstr ""

#: lib/treemerge.c
msgid "Failed to allocate memory. Out of memory?"
#: lib/treemerge.c lib/cmdline.c
msgid "Failed to allocate memory"
msgstr ""

#: lib/cmdline.c
Expand All @@ -1038,6 +1038,14 @@ msgstr ""
msgid "Could not get metadata for path \"%s\": %s"
msgstr ""

#: lib/cmdline.c
msgid "Failed to read stdin"
msgstr ""

#: lib/cmdline.c
msgid "Could not process path arguments"
msgstr ""

#~ msgid "%s%15"
#~ msgstr "%s%15"

Expand Down
14 changes: 11 additions & 3 deletions po/es.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: rmlint 2.4.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-06 00:43+0000\n"
"POT-Creation-Date: 2018-10-15 04:46+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand Down Expand Up @@ -992,8 +992,8 @@ msgstr ""
msgid "Failed to complete setup for merging directories"
msgstr ""

#: lib/treemerge.c
msgid "Failed to allocate memory. Out of memory?"
#: lib/treemerge.c lib/cmdline.c
msgid "Failed to allocate memory"
msgstr ""

#: lib/cmdline.c
Expand All @@ -1015,6 +1015,14 @@ msgstr ""
msgid "Could not get metadata for path \"%s\": %s"
msgstr ""

#: lib/cmdline.c
msgid "Failed to read stdin"
msgstr ""

#: lib/cmdline.c
msgid "Could not process path arguments"
msgstr ""

#~ msgid "caching is not supported due to missing json-glib library."
#~ msgstr ""
#~ "el cacheo no es soportado debido a la librería inexistente json-glib"
Expand Down
14 changes: 11 additions & 3 deletions po/fr.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: rmlint 2.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-06 00:43+0000\n"
"POT-Creation-Date: 2018-10-15 04:46+0000\n"
"PO-Revision-Date: 2014-12-02 13:37+0100\n"
"Last-Translator: F. <[email protected]>\n"
"Language-Team: none\n"
Expand Down Expand Up @@ -988,8 +988,8 @@ msgstr ""
msgid "Failed to complete setup for merging directories"
msgstr ""

#: lib/treemerge.c
msgid "Failed to allocate memory. Out of memory?"
#: lib/treemerge.c lib/cmdline.c
msgid "Failed to allocate memory"
msgstr ""

#: lib/cmdline.c
Expand All @@ -1011,6 +1011,14 @@ msgstr ""
msgid "Could not get metadata for path \"%s\": %s"
msgstr ""

#: lib/cmdline.c
msgid "Failed to read stdin"
msgstr ""

#: lib/cmdline.c
msgid "Could not process path arguments"
msgstr ""

#~ msgid "caching is not supported due to missing json-glib library."
#~ msgstr "Cache non supporté, librairie json-glib manquante."

Expand Down
Loading

0 comments on commit 4627418

Please sign in to comment.