dovecot-2.0: doveadm: Group subcommands into a single line in us...

dovecot at dovecot.org dovecot at dovecot.org
Fri May 28 18:26:40 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/cfa4a9dcb832
changeset: 11421:cfa4a9dcb832
user:      Timo Sirainen <tss at iki.fi>
date:      Fri May 28 16:26:30 2010 +0100
description:
doveadm: Group subcommands into a single line in usage output.

diffstat:

 src/doveadm/doveadm-mail.c |   21 +++++-
 src/doveadm/doveadm-mail.h |    3 +-
 src/doveadm/doveadm.c      |  106 +++++++++++++++++++++++++++++++----
 3 files changed, 113 insertions(+), 17 deletions(-)

diffs (222 lines):

diff -r 425823ba9fcb -r cfa4a9dcb832 src/doveadm/doveadm-mail.c
--- a/src/doveadm/doveadm-mail.c	Fri May 28 15:26:39 2010 +0100
+++ b/src/doveadm/doveadm-mail.c	Fri May 28 16:26:30 2010 +0100
@@ -446,15 +446,15 @@
 	array_append(&doveadm_mail_cmds, cmd, 1);
 }
 
-void doveadm_mail_usage(FILE *out)
+void doveadm_mail_usage(string_t *out)
 {
 	const struct doveadm_mail_cmd *cmd;
 
 	array_foreach(&doveadm_mail_cmds, cmd) {
-		fprintf(out, USAGE_CMDNAME_FMT" [-u <user>|-A]", cmd->name);
+		str_printfa(out, "%s\t[-u <user>|-A]", cmd->name);
 		if (cmd->usage_args != NULL)
-			fprintf(out, " %s", cmd->usage_args);
-		fputc('\n', out);
+			str_printfa(out, " %s", cmd->usage_args);
+		str_append_c(out, '\n');
 	}
 }
 
@@ -475,6 +475,19 @@
 	}
 }
 
+bool doveadm_mail_has_subcommands(const char *cmd_name)
+{
+	const struct doveadm_mail_cmd *cmd;
+	unsigned int len = strlen(cmd_name);
+
+	array_foreach(&doveadm_mail_cmds, cmd) {
+		if (strncmp(cmd->name, cmd_name, len) == 0 &&
+		    cmd->name[len] == ' ')
+			return TRUE;
+	}
+	return FALSE;
+}
+
 void doveadm_mail_help_name(const char *cmd_name)
 {
 	doveadm_mail_try_help_name(cmd_name);
diff -r 425823ba9fcb -r cfa4a9dcb832 src/doveadm/doveadm-mail.h
--- a/src/doveadm/doveadm-mail.h	Fri May 28 15:26:39 2010 +0100
+++ b/src/doveadm/doveadm-mail.h	Fri May 28 16:26:30 2010 +0100
@@ -57,10 +57,11 @@
 bool doveadm_mail_try_run(const char *cmd_name, int argc, char *argv[]);
 void doveadm_mail_register_cmd(const struct doveadm_mail_cmd *cmd);
 
-void doveadm_mail_usage(FILE *out);
+void doveadm_mail_usage(string_t *out);
 void doveadm_mail_help(const struct doveadm_mail_cmd *cmd) ATTR_NORETURN;
 void doveadm_mail_help_name(const char *cmd_name) ATTR_NORETURN;
 void doveadm_mail_try_help_name(const char *cmd_name);
+bool doveadm_mail_has_subcommands(const char *cmd_name);
 
 void doveadm_mail_init(void);
 void doveadm_mail_deinit(void);
diff -r 425823ba9fcb -r cfa4a9dcb832 src/doveadm/doveadm.c
--- a/src/doveadm/doveadm.c	Fri May 28 15:26:39 2010 +0100
+++ b/src/doveadm/doveadm.c	Fri May 28 16:26:30 2010 +0100
@@ -25,24 +25,84 @@
 	array_append(&doveadm_cmds, cmd, 1);
 }
 
+static void
+doveadm_usage_compress_lines(FILE *out, const char *str, const char *prefix)
+{
+	const char *cmd, *args, *p, *short_name, *prev_name = "";
+	char **lines;
+	unsigned int i, count, prefix_len = strlen(prefix);
+
+	/* split lines */
+	lines = p_strsplit(pool_datastack_create(), str, "\n");
+	for (count = 0; lines[count] != NULL; count++) ;
+
+	/* sort lines */
+	qsort(lines, count, sizeof(*lines), i_strcmp_p);
+
+	/* print lines, compress subcommands into a single line */
+	for (i = 0; i < count; i++) {
+		args = strchr(lines[i], '\t');
+		if (args == NULL) {
+			cmd = lines[i];
+			args = "";
+		} else {
+			cmd = t_strdup_until(lines[i], args);
+			args++;
+		}
+		if (*prefix != '\0') {
+			if (strncmp(cmd, prefix, prefix_len) != 0 ||
+			    cmd[prefix_len] != ' ')
+				continue;
+			cmd += prefix_len + 1;
+		}
+
+		p = strchr(cmd, ' ');
+		if (p == NULL) {
+			if (*prev_name != '\0') {
+				fprintf(out, "\n");
+				prev_name = "";
+			}
+			fprintf(out, USAGE_CMDNAME_FMT" %s\n", cmd, args);
+		} else {
+			short_name = t_strdup_until(cmd, p);
+			if (strcmp(prev_name, short_name) != 0) {
+				if (*prev_name != '\0')
+					fprintf(out, "\n");
+				fprintf(out, USAGE_CMDNAME_FMT" %s",
+					short_name, t_strcut(p + 1, ' '));
+				prev_name = short_name;
+			} else {
+				fprintf(out, "|%s", t_strcut(p + 1, ' '));
+			}
+		}
+	}
+	if (*prev_name != '\0')
+		fprintf(out, "\n");
+}
+
 static void ATTR_NORETURN
-usage_to(FILE *out)
+usage_to(FILE *out, const char *prefix)
 {
 	const struct doveadm_cmd *cmd;
+	string_t *str = t_str_new(1024);
 
-	fprintf(out, "usage: doveadm [-Dv] <command> [<args>]\n");
+	fprintf(out, "usage: doveadm [-Dv] ");
+	if (*prefix != '\0')
+		fprintf(out, "%s ", prefix);
+	fprintf(out, "<command> [<args>]\n");
 
-	array_foreach(&doveadm_cmds, cmd) {
-		fprintf(out, USAGE_CMDNAME_FMT" %s\n",
-			cmd->name, cmd->short_usage);
-	}
-	doveadm_mail_usage(out);
+	array_foreach(&doveadm_cmds, cmd)
+		str_printfa(str, "%s\t%s\n", cmd->name, cmd->short_usage);
+
+	doveadm_mail_usage(str);
+	doveadm_usage_compress_lines(out, str_c(str), prefix);
+
 	exit(1);
 }
 
 void usage(void)
 {
-	usage_to(stderr);
+	usage_to(stderr, "");
 }
 
 static void help_to(const struct doveadm_cmd *cmd, FILE *out)
@@ -84,6 +144,19 @@
 	return NULL;
 }
 
+static bool doveadm_has_subcommands(const char *cmd_name)
+{
+	const struct doveadm_cmd *cmd;
+	unsigned int len = strlen(cmd_name);
+
+	array_foreach(&doveadm_cmds, cmd) {
+		if (strncmp(cmd->name, cmd_name, len) == 0 &&
+		    cmd->name[len] == ' ')
+			return TRUE;
+	}
+	return doveadm_mail_has_subcommands(cmd_name);
+}
+
 static void cmd_help(int argc, char *argv[])
 {
 	const struct doveadm_cmd *cmd;
@@ -91,8 +164,9 @@
 	int i;
 
 	if (argv[1] == NULL)
-		usage_to(stdout);
+		usage_to(stdout, "");
 
+	/* try to find exact command */
 	name = t_str_new(100);
 	for (i = 1; i < argc; i++) {
 		str_append(name, argv[i]);
@@ -105,7 +179,12 @@
 
 		str_append_c(name, ' ');
 	}
-	usage_to(stdout);
+
+	/* see if there are subcommands we can list */
+	if (doveadm_has_subcommands(argv[1]))
+		usage_to(stdout, argv[1]);
+
+	usage_to(stdout, "");
 }
 
 static struct doveadm_cmd doveadm_cmd_help = {
@@ -250,7 +329,7 @@
 	doveadm_load_modules();
 
 	if (optind == argc)
-		usage_to(stdout);
+		usage_to(stdout, "");
 
 	cmd_name = argv[optind];
 	argc -= optind;
@@ -264,8 +343,11 @@
 	}
 
 	if (!doveadm_try_run(cmd_name, argc, argv) &&
-	    !doveadm_mail_try_run(cmd_name, argc, argv))
+	    !doveadm_mail_try_run(cmd_name, argc, argv)) {
+		if (doveadm_has_subcommands(argv[0]))
+			usage_to(stdout, argv[0]);
 		usage();
+	}
 
 	doveadm_mail_deinit();
 	module_dir_unload(&modules);


More information about the dovecot-cvs mailing list