diff --git a/lib/mu-script.c b/lib/mu-script.c index 4bc0df30..04c2a99d 100644 --- a/lib/mu-script.c +++ b/lib/mu-script.c @@ -34,6 +34,7 @@ #include #include +#include "mu-str.h" #include "mu-script.h" #include "mu-util.h" @@ -42,9 +43,10 @@ * the values will be *freed* when MuScriptInfo is freed */ struct _MuScriptInfo { - char *_name; /* filename-sans-extension */ - char *_path; /* full path to script */ - char *_descr; /* one-line description */ + char *_name; /* filename-sans-extension */ + char *_path; /* full path to script */ + char *_oneline; /* one-line description */ + char *_descr; /* longer description */ }; @@ -64,6 +66,7 @@ script_info_destroy (MuScriptInfo *msi) g_free (msi->_name); g_free (msi->_path); + g_free (msi->_oneline); g_free (msi->_descr); g_slice_free (MuScriptInfo, msi); @@ -91,6 +94,13 @@ mu_script_info_path (MuScriptInfo *msi) return msi->_path; } +const char* +mu_script_info_one_line (MuScriptInfo *msi) +{ + g_return_val_if_fail (msi, NULL); + return msi->_oneline; +} + const char* mu_script_info_description (MuScriptInfo *msi) { @@ -98,6 +108,30 @@ mu_script_info_description (MuScriptInfo *msi) return msi->_descr; } + +gboolean +mu_script_info_matches_regex (MuScriptInfo *msi, const char *rxstr, + GError **err) +{ + GRegex *rx; + gboolean match; + + g_return_val_if_fail (msi, FALSE); + g_return_val_if_fail (rxstr, FALSE); + + rx = g_regex_new (rxstr, G_REGEX_CASELESS|G_REGEX_OPTIMIZE, 0, err); + if (!rx) + return FALSE; + + match = FALSE; + if (msi->_name) + match = g_regex_match (rx, msi->_name, 0, NULL); + if (!match && msi->_oneline) + match = g_regex_match (rx, msi->_oneline, 0, NULL); + + return match; +} + void mu_script_info_list_destroy (GSList *lst) { @@ -105,38 +139,53 @@ mu_script_info_list_destroy (GSList *lst) g_slist_free (lst); } -static gchar* -get_description (const char *path, const char *prefix) +static gboolean +get_descriptions (MuScriptInfo *msi, const char *prefix) { FILE *script; - char *line, *descr; + char *line, *descr, *oneline; size_t n; if (!prefix) - return NULL; /* not an error */ + return TRUE; /* not an error */ - script = fopen (path, "r"); + script = fopen (msi->_path, "r"); if (!script) { g_warning ("failed to open %s: %s", - path, strerror(errno)); - return NULL; + msi->_path, strerror(errno)); + return FALSE; } - descr = NULL; + descr = oneline = NULL; line = NULL; - while (!descr && getline (&line, &n, script) != -1) { - if (g_str_has_prefix(line, prefix)) { - descr = g_strdup (line + strlen(prefix)); - /* remove trailing '\n' */ - descr[strlen(descr) - 1] = '\0'; + while (getline (&line, &n, script) != -1) { + + if (!g_str_has_prefix(line, prefix)) { + free (line); + line = NULL; + continue; } + + if (!oneline) + oneline = g_strdup (line + strlen (prefix)); + else { + char *tmp; + tmp = descr; + descr = g_strdup_printf ( + "%s%s", descr ? descr : "", + line + strlen(prefix)); + g_free (tmp); + } + free (line); line = NULL; } - fclose (script); - return descr; + msi->_oneline = oneline; + msi->_descr = descr; + + return TRUE; } @@ -163,7 +212,6 @@ mu_script_get_script_info_list (const char *path, const char *ext, lst = NULL; while ((dentry = readdir (dir))) { MuScriptInfo *msi; - /* only consider files with certain extensions, * if ext != NULL */ if (ext && !g_str_has_suffix (dentry->d_name, ext)) @@ -174,7 +222,8 @@ mu_script_get_script_info_list (const char *path, const char *ext, msi->_name[strlen(msi->_name) - strlen(ext)] = '\0'; msi->_path = g_strdup_printf ("%s%c%s", path, G_DIR_SEPARATOR, dentry->d_name); - msi->_descr = get_description (msi->_path, descprefix); + /* set the one-line and long description */ + get_descriptions (msi, descprefix); lst = g_slist_prepend (lst, msi); } @@ -214,32 +263,35 @@ guile_shell (void *closure, int argc, char **argv) gboolean mu_script_guile_run (MuScriptInfo *msi, const char *muhome, - const char *query, gboolean textonly, GError **err) -{ - char *expr; - char *argv[] = { - "guile", "-l", NULL, "-c", NULL, NULL - }; + const char **args, GError **err) + { + char *mainargs, *expr; + char *argv[] = { + "guile", "-l", NULL, "-c", NULL, NULL + }; - g_return_val_if_fail (msi, FALSE); - g_return_val_if_fail (muhome, FALSE); + g_return_val_if_fail (msi, FALSE); + g_return_val_if_fail (muhome, FALSE); - if (access (mu_script_info_path (msi), R_OK) != 0) { - mu_util_g_set_error (err, MU_ERROR_FILE_CANNOT_READ, - strerror(errno)); - return FALSE; - } - argv[2] = (char*)mu_script_info_path (msi); + if (access (mu_script_info_path (msi), R_OK) != 0) { + mu_util_g_set_error (err, MU_ERROR_FILE_CANNOT_READ, + strerror(errno)); + return FALSE; + } + argv[2] = (char*)mu_script_info_path (msi); - expr = g_strdup_printf ( - "(main '(\"%s\" \"--muhome=%s\" %s %s))", - mu_script_info_name (msi), - muhome, - textonly ? "\"--textonly\"" : "", - query ? query : ""); - argv[4] = expr; + mainargs = mu_str_quoted_from_strv (args); + expr = g_strdup_printf ( + "(main '(\"%s\" \"--muhome=%s\" %s))", + mu_script_info_name (msi), + muhome, + mainargs ? mainargs : ""); + g_print ("[%s]\n", mainargs); - scm_boot_guile (5, argv, guile_shell, NULL); + g_free (mainargs); + argv[4] = expr; + + scm_boot_guile (5, argv, guile_shell, NULL); /* never reached but let's be correct(TM)*/ g_free (expr); diff --git a/lib/mu-script.h b/lib/mu-script.h index a8e877fc..3732641f 100644 --- a/lib/mu-script.h +++ b/lib/mu-script.h @@ -55,8 +55,29 @@ const char* mu_script_info_path (MuScriptInfo *msi); * * @return the description, or NULL if there was none */ +const char* mu_script_info_one_line (MuScriptInfo *msi); + +/** + * get a full description for the script + * + * @param msi a MuScriptInfo structure + * + * @return the description, or NULL if there was none + */ const char* mu_script_info_description (MuScriptInfo *msi); +/** + * check whether either the name or one-line description of a + * MuScriptInfo matches regular expression rxstr + * + * @param msi a MuScriptInfo + * @param rxstr a regular expression string + * @param err receives error information + * + * @return TRUE if it matches, FALSE if not or in case of error + */ +gboolean mu_script_info_matches_regex (MuScriptInfo *msi, const char *rxstr, + GError **err); /** * Get the list of all scripts in path with extension ext @@ -96,17 +117,15 @@ MuScriptInfo* mu_script_find_script_with_name (GSList *lst, const char *name); * run the guile script at path * * @param msi MuScriptInfo object for the script - * @param muhome mu home directory - * @param query query for this script (or NULL) - * @param textonly whether to not use a graphical display + * @param muhome path to the mu home dir + * @param args NULL-terminated array of strings (argv for the script) * @param err receives error information * * @return FALSE in case of error -- otherwise, this function will * _not return_ */ gboolean mu_script_guile_run (MuScriptInfo *msi, const char *muhome, - const char* query, gboolean textonly, - GError **err); + const char **args, GError **err); G_END_DECLS diff --git a/mu/Makefile.am b/mu/Makefile.am index 75e191b9..37e7f23a 100644 --- a/mu/Makefile.am +++ b/mu/Makefile.am @@ -27,7 +27,7 @@ INCLUDES=-I${top_srcdir}/lib $(GLIB_CFLAGS) # really need all the params they get AM_CFLAGS=-Wall -Wextra -Wno-unused-parameter -Wdeclaration-after-statement \ -pedantic -Wno-variadic-macros \ - -DMU_STATSDIR="\"$(pkgdatadir)/scripts/stats\"" + -DMU_SCRIPTS_DIR="\"$(pkgdatadir)/scripts/\"" AM_CXXFLAGS=-Wall -Wextra -Wno-unused-parameter bin_PROGRAMS= \ diff --git a/mu/mu-cmd-script.c b/mu/mu-cmd-script.c index bd82199b..c825e0e7 100644 --- a/mu/mu-cmd-script.c +++ b/mu/mu-cmd-script.c @@ -35,33 +35,56 @@ #include "mu-script.h" #define MU_GUILE_EXT ".scm" -#define MU_GUILE_DESCR_PREFIX ";; DESCRIPTION: " +#define MU_GUILE_DESCR_PREFIX ";; INFO: " -static void -print_stats (GSList *scripts) +static gboolean +print_scripts (GSList *scripts, gboolean verbose, const char *rxstr, + GError **err) { GSList *cur; + gboolean first; if (!scripts) { - g_print ("No statistics available\n"); - return; + g_print ("No scripts available\n"); + return TRUE; /* not an error */ } - g_print ("Available statistics " - "(use with --stat=):\n"); - for (cur = scripts; cur; cur = g_slist_next (cur)) { + if (rxstr) + g_print ("Available scripts matching '%s':\n", rxstr); + else + g_print ("Available scripts:\n"); + + for (cur = scripts, first = TRUE; cur; cur = g_slist_next (cur)) { MuScriptInfo *msi; - const char* descr; + const char* descr, *oneline, *name; - msi = (MuScriptInfo*)cur->data; - descr = mu_script_info_description (msi); + msi = (MuScriptInfo*)cur->data; + name = mu_script_info_name (msi); + oneline = mu_script_info_one_line (msi); + descr = mu_script_info_description (msi); - g_print ("\t%s%s%s\n", - mu_script_info_name (msi), - descr ? ": " : "", - descr ? descr : ""); + /* if rxstr is provide, only consider matching scriptinfos */ + if (rxstr && !mu_script_info_matches_regex (msi, rxstr, err)) { + if (err && *err) + return FALSE; + continue; + } + + /* whitespace between */ + if (verbose && !first) + g_print ("\n"); + first = FALSE; + + g_print ("%s%s%s", name, + oneline ? ": " : "", + oneline ? oneline :""); + + if (verbose && descr) + g_print ("%s", descr); } + + return TRUE; } @@ -71,9 +94,11 @@ get_script_info_list (const char *muhome, GError **err) GSList *scripts, *userscripts, *last; char *userpath; - scripts = mu_script_get_script_info_list (MU_STATSDIR, MU_GUILE_EXT, - MU_GUILE_DESCR_PREFIX, - err); + scripts = mu_script_get_script_info_list + (MU_SCRIPTS_DIR, MU_GUILE_EXT, + MU_GUILE_DESCR_PREFIX, + err); + if (err && *err) return NULL; @@ -111,7 +136,7 @@ check_params (MuConfig *opts, GError **err) { if (!mu_util_supports (MU_FEATURE_GUILE | MU_FEATURE_GNUPLOT)) { mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, - "the 'stats' command is not supported"); + "the 'script' command is not supported"); return FALSE; } @@ -120,18 +145,15 @@ check_params (MuConfig *opts, GError **err) MuError -mu_cmd_stats (MuConfig *opts, GError **err) +mu_cmd_script (MuConfig *opts, GError **err) { MuScriptInfo *msi; GSList *scripts; - gchar *query; g_return_val_if_fail (opts, MU_ERROR_INTERNAL); - g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_STATS, + g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_SCRIPT, MU_ERROR_INTERNAL); - query = NULL; - if (!check_params (opts, err)) return MU_ERROR; @@ -139,29 +161,24 @@ mu_cmd_stats (MuConfig *opts, GError **err) if (err && *err) goto leave; - if (!opts->stat) { - print_stats (scripts); + if (!opts->script) { + print_scripts (scripts, opts->verbose, + opts->params[1], err); goto leave; } - msi = mu_script_find_script_with_name (scripts, opts->stat); + msi = mu_script_find_script_with_name (scripts, opts->script); if (!msi) { mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, "script not found"); goto leave; } - query = (opts->params[1]) ? - mu_str_quoted_from_strv ((const gchar**)&opts->params[1]) : - NULL; - /* do it! */ - mu_script_guile_run (msi, opts->muhome, query ? query : "", - opts->textonly, err); + mu_script_guile_run (msi, opts->muhome, + (const gchar**)&opts->params[1], err); leave: /* this won't be reached, unless there is some error */ mu_script_info_list_destroy (scripts); - g_free (query); - return (err && *err) ? MU_ERROR : MU_OK; } diff --git a/mu/mu-cmd.c b/mu/mu-cmd.c index 8df1dacc..1b8c6bc4 100644 --- a/mu/mu-cmd.c +++ b/mu/mu-cmd.c @@ -609,11 +609,11 @@ mu_cmd_execute (MuConfig *opts, GError **err) /* already handled in mu-config.c */ case MU_CONFIG_CMD_HELP: return MU_OK; - case MU_CONFIG_CMD_CFIND: merr = mu_cmd_cfind (opts, err); break; - case MU_CONFIG_CMD_MKDIR: merr = mu_cmd_mkdir (opts, err); break; - case MU_CONFIG_CMD_STATS: merr = mu_cmd_stats (opts, err); break; - case MU_CONFIG_CMD_VIEW: merr = mu_cmd_view (opts, err); break; - case MU_CONFIG_CMD_VERIFY: merr = mu_cmd_verify (opts, err); break; + case MU_CONFIG_CMD_CFIND: merr = mu_cmd_cfind (opts, err); break; + case MU_CONFIG_CMD_MKDIR: merr = mu_cmd_mkdir (opts, err); break; + case MU_CONFIG_CMD_SCRIPT: merr = mu_cmd_script (opts, err); break; + case MU_CONFIG_CMD_VIEW: merr = mu_cmd_view (opts, err); break; + case MU_CONFIG_CMD_VERIFY: merr = mu_cmd_verify (opts, err); break; case MU_CONFIG_CMD_EXTRACT: merr = mu_cmd_extract (opts, err); break; case MU_CONFIG_CMD_FIND: diff --git a/mu/mu-cmd.h b/mu/mu-cmd.h index f58ce647..ca6dd8a5 100644 --- a/mu/mu-cmd.h +++ b/mu/mu-cmd.h @@ -105,7 +105,7 @@ MuError mu_cmd_mv (MuConfig *opts, GError **err); /** - * execute the 'stats' command + * execute the 'script' command * * @param opts configuration options * @param err receives error information, or NULL @@ -113,7 +113,7 @@ MuError mu_cmd_mv (MuConfig *opts, GError **err); * @return MU_OK (0) if the command succeeds, * some error code otherwise */ -MuError mu_cmd_stats (MuConfig *opts, GError **err); +MuError mu_cmd_script (MuConfig *opts, GError **err); /** * execute the cfind command diff --git a/mu/mu-config.c b/mu/mu-config.c index a3aa687b..751aa775 100644 --- a/mu/mu-config.c +++ b/mu/mu-config.c @@ -95,7 +95,7 @@ config_options_group_mu (void) "print debug output to standard error (false)", NULL}, {"quiet", 'q', 0, G_OPTION_ARG_NONE, &MU_CONFIG.quiet, "don't give any progress information (false)", NULL}, - {"version", 'v', 0, G_OPTION_ARG_NONE, &MU_CONFIG.version, + {"version", 0, 0, G_OPTION_ARG_NONE, &MU_CONFIG.version, "display version and copyright information (false)", NULL}, {"muhome", 0, 0, G_OPTION_ARG_FILENAME, &MU_CONFIG.muhome, "specify an alternative mu directory", ""}, @@ -292,18 +292,16 @@ config_options_group_cfind (void) static GOptionGroup * -config_options_group_stats (void) +config_options_group_script (void) { GOptionGroup *og; GOptionEntry entries[] = { - {"stat", 0, 0, G_OPTION_ARG_STRING, &MU_CONFIG.stat, - "statistic to show (see `mu help stats')", ""}, - {"textonly", 0, 0, G_OPTION_ARG_NONE, &MU_CONFIG.textonly, - "use text-only output", NULL}, + {"script", 0, 0, G_OPTION_ARG_STRING, &MU_CONFIG.script, + "script to run (see `mu help script')", "