Commit f434857b f434857b8318b05b7036025605ab18cdf3e7c238 by Sergey Poznyakoff

Begin rewriting MH to get rid of argp stuff.

MH utilities will use only single-dash long options.

* include/mailutils/opt.h (mu_option) <opt_default>: New member.
* libmailutils/opt/opt.c (find_long_option): Improve detection
of ambiguous options.
(mu_option_set_value): Use default value (opt_default), if
supplied.
* mh/mh_argp.c: Delete.
* mh/Makefile.am (libmh_a_SOURCES): Remove mh_argp.c
* mh/mh_getopt.c: Rewrite from scratch using mailutils/opt
* mh/mh_getopt.h: Likewise.
* mh/mh.h: Add missing includes
(mh_read_formfile, mh_alias_read): Change signatures.
* mh/mh_alias.l (mh_alias_read): Name is const
* mh/mh_init.c (mh_read_formfile): Name is const.

* mh/ali.c: Convert to mh_getopt.
* mh/anno.c: Likewise.
* mh/burst.c: Likewise.
* mh/comp.c: Likewise.
* mh/fmtcheck.c: Likewise.
* mh/folder.c: Likewise.
* mh/forw.c: Likewise.
* mh/inc.c: Likewise.
* mh/install-mh.c: Likewise.
* mh/mark.c: Likewise.
* mh/mhl.c: Likewise.
* mh/scan.c: Likewise.

* mh/tests/burst.at: Don't use double-dash options
* mh/tests/folder.at: Likewise.
1 parent 53eb6813
...@@ -47,6 +47,7 @@ struct mu_option ...@@ -47,6 +47,7 @@ struct mu_option
47 void *opt_ptr; /* Data pointer */ 47 void *opt_ptr; /* Data pointer */
48 void (*opt_set) (struct mu_parseopt *, struct mu_option *, char const *); 48 void (*opt_set) (struct mu_parseopt *, struct mu_option *, char const *);
49 /* Function to set the option */ 49 /* Function to set the option */
50 char const *opt_default;/* Default value */
50 }; 51 };
51 52
52 #define MU_OPTION_GROUP(text) { NULL, 0, NULL, 0, text } 53 #define MU_OPTION_GROUP(text) { NULL, 0, NULL, 0, text }
......
...@@ -189,6 +189,31 @@ find_short_option (struct mu_parseopt *po, int chr) ...@@ -189,6 +189,31 @@ find_short_option (struct mu_parseopt *po, int chr)
189 return NULL; 189 return NULL;
190 } 190 }
191 191
192 enum neg_match
193 {
194 neg_nomatch,
195 neg_match_inexact,
196 neg_match_exact
197 };
198
199 static enum neg_match
200 negmatch (struct mu_parseopt *po, size_t i, char const *optstr, size_t optlen)
201 {
202 if (mu_option_possible_negation (po, po->po_optv[i]))
203 {
204 size_t neglen = strlen (po->po_negation);
205 size_t len = strlen (po->po_optv[i]->opt_long);
206 if (optlen <= neglen + len
207 && memcmp (optstr, po->po_negation, neglen) == 0
208 && memcmp (optstr + neglen, po->po_optv[i]->opt_long,
209 optlen - neglen) == 0)
210 {
211 return (optlen == neglen + len) ? neg_match_exact : neg_match_inexact;
212 }
213 }
214 return neg_nomatch;
215 }
216
192 /* Find a descriptor of long option OPTSTR. If it has argument, return 217 /* Find a descriptor of long option OPTSTR. If it has argument, return
193 it in *ARGPTR. */ 218 it in *ARGPTR. */
194 struct mu_option * 219 struct mu_option *
...@@ -200,14 +225,11 @@ find_long_option (struct mu_parseopt *po, char const *optstr, ...@@ -200,14 +225,11 @@ find_long_option (struct mu_parseopt *po, char const *optstr,
200 size_t i; 225 size_t i;
201 size_t optlen; /* Length of the option in optstr */ 226 size_t optlen; /* Length of the option in optstr */
202 int found = 0; /* 1 if the match was found, 2 if option is ambiguous */ 227 int found = 0; /* 1 if the match was found, 2 if option is ambiguous */
203 int neglen; /* Length of the negation prefix, if any */ 228 enum neg_match neg; /* 1 if a boolean option is negated */
204 int neg = 0; /* 1 if a boolean option is negated */
205 struct mu_option *ret_opt = NULL; 229 struct mu_option *ret_opt = NULL;
206 struct mu_option *used_opt; 230 struct mu_option *used_opt;
207 231
208 optlen = strcspn (optstr, "="); 232 optlen = strcspn (optstr, "=");
209 if (po->po_negation)
210 neglen = strlen (po->po_negation);
211 233
212 for (i = 0; i < po->po_optc; i++) 234 for (i = 0; i < po->po_optc; i++)
213 { 235 {
...@@ -215,14 +237,10 @@ find_long_option (struct mu_parseopt *po, char const *optstr, ...@@ -215,14 +237,10 @@ find_long_option (struct mu_parseopt *po, char const *optstr,
215 { 237 {
216 size_t len = strlen (po->po_optv[i]->opt_long); 238 size_t len = strlen (po->po_optv[i]->opt_long);
217 struct mu_option *opt = option_unalias (po, i); 239 struct mu_option *opt = option_unalias (po, i);
218 240 neg = neg_nomatch;
219 if ((optlen <= len 241 if ((optlen <= len
220 && memcmp (po->po_optv[i]->opt_long, optstr, optlen) == 0) 242 && memcmp (po->po_optv[i]->opt_long, optstr, optlen) == 0)
221 || (neg = (mu_option_possible_negation (po, opt) 243 || (neg = negmatch (po, i, optstr, optlen)))
222 && optlen <= neglen + len
223 && memcmp (optstr, po->po_negation, neglen) == 0
224 && memcmp (optstr + neglen, po->po_optv[i]->opt_long,
225 optlen - neglen) == 0)))
226 { 244 {
227 switch (found) 245 switch (found)
228 { 246 {
...@@ -230,7 +248,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr, ...@@ -230,7 +248,7 @@ find_long_option (struct mu_parseopt *po, char const *optstr,
230 used_opt = po->po_optv[i]; 248 used_opt = po->po_optv[i];
231 ret_opt = opt; 249 ret_opt = opt;
232 found++; 250 found++;
233 if (optlen == len || (neg && optlen == neglen + len)) 251 if (optlen == len || neg == neg_match_exact)
234 i = po->po_optc - 1; /* exact match: break the loop */ 252 i = po->po_optc - 1; /* exact match: break the loop */
235 break; 253 break;
236 254
...@@ -247,6 +265,11 @@ find_long_option (struct mu_parseopt *po, char const *optstr, ...@@ -247,6 +265,11 @@ find_long_option (struct mu_parseopt *po, char const *optstr,
247 po->po_long_opt_start, 265 po->po_long_opt_start,
248 neg ? po->po_negation : "", 266 neg ? po->po_negation : "",
249 used_opt->opt_long); 267 used_opt->opt_long);
268 if (neg == neg_nomatch && negmatch (po, i, optstr, optlen))
269 fprintf (stderr, "%s%s%s\n",
270 po->po_long_opt_start,
271 po->po_negation,
272 po->po_optv[i]->opt_long);
250 found++; 273 found++;
251 274
252 case 2: 275 case 2:
...@@ -254,6 +277,11 @@ find_long_option (struct mu_parseopt *po, char const *optstr, ...@@ -254,6 +277,11 @@ find_long_option (struct mu_parseopt *po, char const *optstr,
254 po->po_long_opt_start, 277 po->po_long_opt_start,
255 neg ? po->po_negation : "", 278 neg ? po->po_negation : "",
256 po->po_optv[i]->opt_long); 279 po->po_optv[i]->opt_long);
280 if (neg == neg_nomatch && negmatch (po, i, optstr, optlen))
281 fprintf (stderr, "%s%s%s\n",
282 po->po_long_opt_start,
283 po->po_negation,
284 po->po_optv[i]->opt_long);
257 } 285 }
258 } 286 }
259 } 287 }
...@@ -719,7 +747,9 @@ mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt, ...@@ -719,7 +747,9 @@ mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt,
719 747
720 if (arg == NULL) 748 if (arg == NULL)
721 { 749 {
722 if (opt->opt_arg == NULL) 750 if (opt->opt_default)
751 arg = opt->opt_default;
752 else if (opt->opt_arg == NULL)
723 arg = "1"; 753 arg = "1";
724 else 754 else
725 { 755 {
...@@ -737,7 +767,8 @@ mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt, ...@@ -737,7 +767,8 @@ mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt,
737 errtext = mu_strerror (rc); 767 errtext = mu_strerror (rc);
738 768
739 if (opt->opt_long) 769 if (opt->opt_long)
740 mu_parseopt_error (po, "--%s: %s", opt->opt_long, errtext); 770 mu_parseopt_error (po, "%s%s: %s", po->po_long_opt_start,
771 opt->opt_long, errtext);
741 else 772 else
742 mu_parseopt_error (po, "-%c: %s", opt->opt_short, errtext); 773 mu_parseopt_error (po, "-%c: %s", opt->opt_short, errtext);
743 free (errmsg); 774 free (errmsg);
......
...@@ -70,7 +70,6 @@ libmh_a_SOURCES= \ ...@@ -70,7 +70,6 @@ libmh_a_SOURCES= \
70 mboxprop.c\ 70 mboxprop.c\
71 mh_alias_gram.c\ 71 mh_alias_gram.c\
72 mh_alias_lex.c\ 72 mh_alias_lex.c\
73 mh_argp.c\
74 mh_getopt.c\ 73 mh_getopt.c\
75 mh_global.c\ 74 mh_global.c\
76 mh_format.c\ 75 mh_format.c\
......
...@@ -23,73 +23,41 @@ ...@@ -23,73 +23,41 @@
23 #include <sys/ioctl.h> 23 #include <sys/ioctl.h>
24 #include <sys/stat.h> 24 #include <sys/stat.h>
25 25
26 static char doc[] = N_("GNU MH ali")"\v" 26 static char prog_doc[] = N_("GNU MH ali");
27 N_("Use -help to obtain the list of traditional MH options.");
28 static char args_doc[] = N_("ALIAS [ALIAS...]"); 27 static char args_doc[] = N_("ALIAS [ALIAS...]");
29 28
30 /* GNU options */
31 static struct argp_option options[] = {
32 {"alias", ARG_ALIAS, N_("FILE"), 0,
33 N_("use the additional alias FILE")},
34 {"noalias", ARG_NOALIAS, NULL, 0,
35 N_("do not read the system alias file") },
36 {"list", ARG_LIST, N_("BOOL"), OPTION_ARG_OPTIONAL,
37 N_("list each address on a separate line") },
38 {"normalize", ARG_NORMALIZE, N_("BOOL"), OPTION_ARG_OPTIONAL,
39 N_("try to determine the official hostname for each address") },
40 {"user", ARG_USER, N_("BOOL"), OPTION_ARG_OPTIONAL,
41 N_("list the aliases that expand to given addresses") },
42 { 0 }
43 };
44
45 /* Traditional MH options */
46 struct mh_option mh_option[] = {
47 { "alias", MH_OPT_ARG, "aliasfile" },
48 { "noalias", },
49 { "list", MH_OPT_BOOL },
50 { "normalize", MH_OPT_BOOL },
51 { "user", MH_OPT_BOOL },
52 { NULL }
53 };
54
55 static int list_mode; 29 static int list_mode;
56 static int user_mode; 30 static int user_mode;
57 static int normalize_mode; 31 static int normalize_mode;
58 static int nolist_mode; 32 static int nolist_mode;
59 33
60 static error_t 34 static void
61 opt_handler (int key, char *arg, struct argp_state *state) 35 alias_handler (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
62 { 36 {
63 switch (key) 37 mh_alias_read (arg, 1);
64 {
65 case ARG_ALIAS:
66 mh_alias_read (arg, 1);
67 break;
68
69 case ARG_NOALIAS:
70 nolist_mode = 1;
71 break;
72
73 case ARG_LIST:
74 list_mode = is_true (arg);
75 break;
76
77 case ARG_NORMALIZE:
78 normalize_mode = is_true (arg);
79 break;
80
81 case ARG_USER:
82 user_mode = is_true (arg);
83 break;
84
85 default:
86 return ARGP_ERR_UNKNOWN;
87 }
88 return 0;
89 } 38 }
90 39
40 static struct mu_option options[] = {
41 { "alias", 0, N_("FILE"), MU_OPTION_DEFAULT,
42 N_("use the additional alias FILE"),
43 mu_c_string, NULL, alias_handler },
44 { "noalias", 0, NULL, 0,
45 N_("do not read the system alias file"),
46 mu_c_int, &nolist_mode, NULL, "1" },
47 { "list", 0, NULL, MU_OPTION_DEFAULT,
48 N_("list each address on a separate line"),
49 mu_c_bool, &list_mode },
50 { "normalize", 0, NULL, MU_OPTION_DEFAULT,
51 N_("try to determine the official hostname for each address"),
52 mu_c_bool, &normalize_mode },
53 { "user", 0, NULL, MU_OPTION_DEFAULT,
54 N_("list the aliases that expand to given addresses"),
55 mu_c_bool, &user_mode },
56 MU_OPTION_END
57 };
58
91 static int 59 static int
92 getcols () 60 getcols (void)
93 { 61 {
94 struct winsize ws; 62 struct winsize ws;
95 63
...@@ -174,17 +142,10 @@ ali_print_name (char *name) ...@@ -174,17 +142,10 @@ ali_print_name (char *name)
174 int 142 int
175 main (int argc, char **argv) 143 main (int argc, char **argv)
176 { 144 {
177 int index;
178
179 /* Native Language Support */ 145 /* Native Language Support */
180 MU_APP_INIT_NLS (); 146 MU_APP_INIT_NLS ();
181 147
182 mh_argp_init (); 148 mh_getopt (&argc, &argv, options, 0, args_doc, prog_doc, NULL);
183 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
184 opt_handler, NULL, &index);
185
186 argc -= index;
187 argv += index;
188 149
189 if (!nolist_mode) 150 if (!nolist_mode)
190 mh_read_aliases (); 151 mh_read_aliases ();
......
...@@ -19,81 +19,29 @@ ...@@ -19,81 +19,29 @@
19 19
20 #include <mh.h> 20 #include <mh.h>
21 21
22 static char doc[] = N_("GNU MH anno")"\v" 22 static char prog_doc[] = N_("GNU MH anno");
23 N_("Options marked with `*' are not yet implemented.\n\
24 Use -help to obtain the list of traditional MH options.");
25 static char args_doc[] = N_("[MSGLIST]"); 23 static char args_doc[] = N_("[MSGLIST]");
26 24
27 /* GNU options */ 25 //static int inplace; /* Annotate the message in place */
28 static struct argp_option options[] = {
29 {"folder", ARG_FOLDER, N_("FOLDER"), 0,
30 N_("specify folder to operate upon")},
31 {"inplace", ARG_INPLACE, N_("BOOL"), OPTION_ARG_OPTIONAL,
32 N_("* annotate the message in place")},
33 {"noinplace", ARG_NOINPLACE, NULL, OPTION_HIDDEN, "" },
34 {"date", ARG_DATE, N_("BOOL"), OPTION_ARG_OPTIONAL,
35 N_("add FIELD: date header") },
36 {"nodate", ARG_NODATE, NULL, OPTION_HIDDEN, "" },
37 {"component", ARG_COMPONENT, N_("FIELD"), 0,
38 N_("add this FIELD to the message header") },
39 {"text", ARG_TEXT, N_("STRING"), 0,
40 N_("field value for the component") },
41 { NULL }
42 };
43
44 struct mh_option mh_option[] = {
45 { "inplace", MH_OPT_BOOL },
46 { "date", MH_OPT_BOOL },
47 { "component", MH_OPT_ARG, "field" },
48 { "text", MH_OPT_ARG, "body" },
49 { NULL }
50 };
51
52 static int inplace; /* Annotate the message in place */
53 static int anno_date = 1; /* Add date to the annotation */ 26 static int anno_date = 1; /* Add date to the annotation */
54 static char *component; /* header field */ 27 static char *component; /* header field */
55 static char *anno_text; /* header field value */ 28 static char *anno_text; /* header field value */
56 29
57 static error_t 30 static struct mu_option options[] = {
58 opt_handler (int key, char *arg, struct argp_state *state) 31 { "inplace", 0, NULL, MU_OPTION_HIDDEN,
59 { 32 N_("annotate the message in place"),
60 switch (key) 33 mu_c_string, NULL, mh_opt_notimpl_warning },
61 { 34 { "date", 0, NULL, MU_OPTION_DEFAULT,
62 case ARG_FOLDER: 35 N_("add FIELD: date header"),
63 mh_set_current_folder (arg); 36 mu_c_bool, &anno_date },
64 break; 37 { "component", 0, N_("FIELD"), MU_OPTION_DEFAULT,
65 38 N_("add this FIELD to the message header"),
66 case ARG_INPLACE: 39 mu_c_string, &component },
67 mh_opt_notimpl_warning ("-inplace"); 40 { "text", 0, N_("STRING"), MU_OPTION_DEFAULT,
68 inplace = is_true (arg); 41 N_("field value for the component"),
69 break; 42 mu_c_string, &anno_text },
70 43 MU_OPTION_END
71 case ARG_NOINPLACE: 44 };
72 mh_opt_notimpl_warning ("-noinplace");
73 inplace = 0;
74 break;
75
76 case ARG_DATE:
77 anno_date = is_true (arg);
78 break;
79
80 case ARG_NODATE:
81 anno_date = 0;
82 break;
83
84 case ARG_COMPONENT:
85 component = arg;
86 break;
87
88 case ARG_TEXT:
89 mh_quote (arg, &anno_text);
90 break;
91
92 default:
93 return ARGP_ERR_UNKNOWN;
94 }
95 return 0;
96 }
97 45
98 int 46 int
99 anno (size_t n, mu_message_t msg, void *call_data) 47 anno (size_t n, mu_message_t msg, void *call_data)
...@@ -106,17 +54,21 @@ int ...@@ -106,17 +54,21 @@ int
106 main (int argc, char **argv) 54 main (int argc, char **argv)
107 { 55 {
108 int rc; 56 int rc;
109 int index;
110 mu_mailbox_t mbox; 57 mu_mailbox_t mbox;
111 mu_msgset_t msgset; 58 mu_msgset_t msgset;
112 size_t len; 59 size_t len;
113 60
114 MU_APP_INIT_NLS (); 61 MU_APP_INIT_NLS ();
115 62
116 mh_argp_init (); 63 mh_getopt (&argc, &argv, options, MH_GETOPT_DEFAULT_FOLDER,
117 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, 64 args_doc, prog_doc, NULL);
118 opt_handler, NULL, &index); 65 if (anno_text)
119 66 {
67 char *arg = anno_text;
68 mh_quote (arg, &anno_text);
69 free (arg);
70 }
71
120 mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR); 72 mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR);
121 73
122 if (!component) 74 if (!component)
...@@ -152,9 +104,6 @@ main (int argc, char **argv) ...@@ -152,9 +104,6 @@ main (int argc, char **argv)
152 if (len > 0 && component[len-1] == ':') 104 if (len > 0 && component[len-1] == ':')
153 component[len-1] = 0; 105 component[len-1] = 0;
154 106
155 argc -= index;
156 argv += index;
157
158 mh_msgset_parse (&msgset, mbox, argc, argv, "cur"); 107 mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
159 rc = mu_msgset_foreach_message (msgset, anno, NULL); 108 rc = mu_msgset_foreach_message (msgset, anno, NULL);
160 if (rc) 109 if (rc)
......
...@@ -18,40 +18,9 @@ ...@@ -18,40 +18,9 @@
18 18
19 #include <mh.h> 19 #include <mh.h>
20 20
21 static char doc[] = N_("GNU MH burst")"\v" 21 static char prog_doc[] = N_("GNU MH burst");
22 N_("Options marked with `*' are not yet implemented.\n\
23 Use -help to obtain the list of traditional MH options.");
24 static char args_doc[] = N_("[MSGLIST]"); 22 static char args_doc[] = N_("[MSGLIST]");
25 23
26 /* GNU options */
27 static struct argp_option options[] = {
28 {"folder", ARG_FOLDER, N_("FOLDER"), 0,
29 N_("specify folder to operate upon")},
30 {"inplace", ARG_INPLACE, N_("BOOL"), OPTION_ARG_OPTIONAL,
31 N_("replace the source message with the table of contents, insert extracted messages after it") },
32 {"noinplace", ARG_NOINPLACE, 0, OPTION_HIDDEN, ""},
33 {"quiet", ARG_QUIET, N_("BOOL"), OPTION_ARG_OPTIONAL,
34 N_("be quiet about the messages that are not in digest format") },
35 {"noquiet", ARG_NOQUIET, 0, OPTION_HIDDEN, ""},
36 {"verbose", ARG_VERBOSE, N_("BOOL"), OPTION_ARG_OPTIONAL,
37 N_("verbosely list the actions taken") },
38 {"noverbose", ARG_NOVERBOSE, 0, OPTION_HIDDEN, ""},
39 {"recursive", ARG_RECURSIVE, N_("BOOL"), OPTION_ARG_OPTIONAL,
40 N_("recursively expand MIME messages") },
41 {"norecursive", ARG_NORECURSIVE, 0, OPTION_HIDDEN, ""},
42 {"length", ARG_LENGTH, N_("NUMBER"), 0,
43 N_("set minimal length of digest encapsulation boundary (default 1)") },
44 { NULL }
45 };
46
47 /* Traditional MH options */
48 struct mh_option mh_option[] = {
49 { "inplace", MH_OPT_BOOL },
50 { "quiet", MH_OPT_BOOL },
51 { "verbose", MH_OPT_BOOL },
52 { NULL }
53 };
54
55 /* Command line switches */ 24 /* Command line switches */
56 int inplace; 25 int inplace;
57 int quiet; 26 int quiet;
...@@ -61,59 +30,24 @@ int eb_min_length = 1; /* Minimal length of encapsulation boundary */ ...@@ -61,59 +30,24 @@ int eb_min_length = 1; /* Minimal length of encapsulation boundary */
61 30
62 #define VERBOSE(c) do { if (verbose) { printf c; putchar ('\n'); } } while (0) 31 #define VERBOSE(c) do { if (verbose) { printf c; putchar ('\n'); } } while (0)
63 32
64 static error_t 33 static struct mu_option options[] = {
65 opt_handler (int key, char *arg, struct argp_state *state) 34 { "inplace", 0, NULL, MU_OPTION_DEFAULT,
66 { 35 N_("replace the source message with the table of contents, insert extracted messages after it"),
67 switch (key) 36 mu_c_bool, &inplace },
68 { 37 { "quiet", 0, NULL, MU_OPTION_DEFAULT,
69 case ARG_FOLDER: 38 N_("be quiet about the messages that are not in digest format"),
70 mh_set_current_folder (arg); 39 mu_c_bool, &quiet },
71 break; 40 { "verbose", 0, NULL, MU_OPTION_DEFAULT,
72 41 N_("verbosely list the actions taken"),
73 case ARG_INPLACE: 42 mu_c_bool, &verbose },
74 inplace = is_true (arg); 43 { "recursive", 0, NULL, MU_OPTION_DEFAULT,
75 break; 44 N_("recursively expand MIME messages"),
76 45 mu_c_bool, &recursive },
77 case ARG_NOINPLACE: 46 { "length", 0, N_("NUM"), MU_OPTION_DEFAULT,
78 inplace = 0; 47 N_("set minimal length of digest encapsulation boundary (default 1)"),
79 break; 48 mu_c_int, &eb_min_length },
80 49 MU_OPTION_END
81 case ARG_LENGTH: 50 };
82 eb_min_length = strtoul (arg, NULL, 0);
83 if (eb_min_length == 0)
84 eb_min_length = 1;
85 break;
86
87 case ARG_VERBOSE:
88 verbose = is_true (arg);
89 break;
90
91 case ARG_NOVERBOSE:
92 verbose = 0;
93 break;
94
95 case ARG_RECURSIVE:
96 recursive = is_true (arg);
97 break;
98
99 case ARG_NORECURSIVE:
100 recursive = 0;
101 break;
102
103 case ARG_QUIET:
104 quiet = is_true (arg);
105 break;
106
107 case ARG_NOQUIET:
108 quiet = 0;
109 break;
110
111 default:
112 return ARGP_ERR_UNKNOWN;
113 }
114 return 0;
115 }
116
117 51
118 /* General-purpose data structures */ 52 /* General-purpose data structures */
119 struct burst_map 53 struct burst_map
...@@ -713,7 +647,7 @@ finalize_inplace (size_t lastuid) ...@@ -713,7 +647,7 @@ finalize_inplace (size_t lastuid)
713 int 647 int
714 main (int argc, char **argv) 648 main (int argc, char **argv)
715 { 649 {
716 int index, rc; 650 int rc;
717 mu_mailbox_t mbox; 651 mu_mailbox_t mbox;
718 mu_msgset_t msgset; 652 mu_msgset_t msgset;
719 const char *tempfolder = mh_global_profile_get ("Temp-Folder", ".temp"); 653 const char *tempfolder = mh_global_profile_get ("Temp-Folder", ".temp");
...@@ -721,13 +655,11 @@ main (int argc, char **argv) ...@@ -721,13 +655,11 @@ main (int argc, char **argv)
721 /* Native Language Support */ 655 /* Native Language Support */
722 MU_APP_INIT_NLS (); 656 MU_APP_INIT_NLS ();
723 657
724 mh_argp_init (); 658 mh_getopt (&argc, &argv, options, MH_GETOPT_DEFAULT_FOLDER,
725 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, 659 args_doc, prog_doc, NULL);
726 opt_handler, NULL, &index); 660 if (eb_min_length == 0)
727 661 eb_min_length = 1;
728 argc -= index; 662
729 argv += index;
730
731 VERBOSE ((_("Opening folder `%s'"), mh_current_folder ())); 663 VERBOSE ((_("Opening folder `%s'"), mh_current_folder ()));
732 mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR); 664 mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR);
733 mh_msgset_parse (&msgset, mbox, argc, argv, "cur"); 665 mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
......
...@@ -21,143 +21,73 @@ ...@@ -21,143 +21,73 @@
21 #include <sys/types.h> 21 #include <sys/types.h>
22 #include <sys/stat.h> 22 #include <sys/stat.h>
23 23
24 static char doc[] = N_("GNU MH comp")"\v" 24 static char prog_doc[] = N_("GNU MH comp");
25 N_("Options marked with `*' are not yet implemented.\n"
26 "Use -help to obtain the list of traditional MH options.");
27 static char args_doc[] = N_("[MSG]"); 25 static char args_doc[] = N_("[MSG]");
28 26
29 /* GNU options */
30 static struct argp_option options[] = {
31 {"build", ARG_BUILD, 0, 0,
32 N_("build the draft and quit immediately.")},
33 {"draftfolder", ARG_DRAFTFOLDER, N_("FOLDER"), 0,
34 N_("specify the folder for message drafts")},
35 {"nodraftfolder", ARG_NODRAFTFOLDER, 0, 0,
36 N_("undo the effect of the last --draftfolder option")},
37 {"draftmessage" , ARG_DRAFTMESSAGE, N_("MSG"), 0,
38 N_("invoke the draftmessage facility")},
39 {"folder", ARG_FOLDER, N_("FOLDER"), 0,
40 N_("specify folder to operate upon")},
41 {"file", ARG_FILE, N_("FILE"), 0,
42 N_("use FILE as the message draft")},
43 {"editor", ARG_EDITOR, N_("PROG"), 0,
44 N_("set the editor program to use")},
45 {"noedit", ARG_NOEDIT, 0, 0,
46 N_("suppress the initial edit")},
47 {"form", ARG_FORM, N_("FILE"), 0,
48 N_("read format from given file")},
49 {"whatnowproc", ARG_WHATNOWPROC, N_("PROG"), 0,
50 N_("set the replacement for whatnow program")},
51 {"nowhatnowproc", ARG_NOWHATNOWPROC, NULL, 0,
52 N_("don't run whatnowproc")},
53 {"use", ARG_USE, N_("BOOL"), OPTION_ARG_OPTIONAL,
54 N_("use draft file preserved after the last session") },
55 {"nouse", ARG_NOUSE, NULL, OPTION_HIDDEN, ""},
56 { 0 }
57 };
58
59 /* Traditional MH options */
60 struct mh_option mh_option[] = {
61 { "build" },
62 { "file", MH_OPT_ARG, "draftfile" },
63 { "form", MH_OPT_ARG, "formatfile" },
64 { "draftfolder", MH_OPT_ARG, "folder" },
65 { "nodraftfolder" },
66 { "draftmessage" },
67 { "editor", MH_OPT_ARG, "program" },
68 { "noedit" },
69 { "whatnowproc", MH_OPT_ARG, "program" },
70 { "nowhatnowproc" },
71 { "use" },
72 { NULL }
73 };
74
75 struct mh_whatnow_env wh_env = { 0 }; 27 struct mh_whatnow_env wh_env = { 0 };
76 static int initial_edit = 1; 28 static int initial_edit = 1;
77 static const char *whatnowproc; 29 static const char *whatnowproc;
78 static int nowhatnowproc; 30 static int nowhatnowproc;
79 char *formfile; 31 char *formfile;
80 static int build_only = 0; /* --build flag */ 32 static int build_only = 0; /* -build flag */
81 static int use_draft = 0; /* --use flag */ 33 static int use_draft = 0; /* -use flag */
82 static char *draftmessage = "new"; 34 static char *draftmessage = "new";
83 static const char *draftfolder = NULL; 35 static const char *draftfolder = NULL;
84 static int folder_set; /* Folder is set on the command line */ 36 static int folder_set; /* Folder is set on the command line */
85 37
86 static error_t 38 static void
87 opt_handler (int key, char *arg, struct argp_state *state) 39 set_folder (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
88 { 40 {
89 switch (key) 41 mh_set_current_folder (arg);
90 { 42 folder_set = 1;
91 case ARGP_KEY_INIT: 43 }
92 draftfolder = mh_global_profile_get ("Draft-Folder", NULL);
93 whatnowproc = mh_global_profile_get ("whatnowproc", NULL);
94 break;
95
96 case ARG_BUILD:
97 build_only = 1;
98 break;
99
100 case ARG_DRAFTFOLDER:
101 draftfolder = arg;
102 break;
103
104 case ARG_EDITOR:
105 wh_env.editor = arg;
106 break;
107
108 case ARG_FOLDER:
109 mh_set_current_folder (arg);
110 folder_set = 1;
111 break;
112
113 case ARG_FORM:
114 mh_find_file (arg, &formfile);
115 break;
116
117 case ARG_DRAFTMESSAGE:
118 draftmessage = arg;
119 break;
120
121 case ARG_USE:
122 use_draft = is_true (arg);
123 draftmessage = "cur";
124 break;
125
126 case ARG_NOUSE:
127 use_draft = 0;
128 break;
129
130 case ARG_FILE:
131 wh_env.file = mh_expand_name (NULL, arg, NAME_ANY);
132 break;
133
134 case ARG_NODRAFTFOLDER:
135 draftfolder = NULL;
136 break;
137
138 case ARG_NOEDIT:
139 initial_edit = 0;
140 break;
141
142 case ARG_WHATNOWPROC:
143 whatnowproc = arg;
144 break;
145
146 case ARG_NOWHATNOWPROC:
147 nowhatnowproc = 1;
148 break;
149 44
150 case ARGP_KEY_FINI: 45 static void
151 if (!formfile) 46 set_file (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
152 mh_find_file ("components", &formfile); 47 {
153 break; 48 wh_env.file = mh_expand_name (NULL, arg, NAME_ANY);
154
155 default:
156 return ARGP_ERR_UNKNOWN;
157 }
158 return 0;
159 } 49 }
160 50
51 static struct mu_option options[] = {
52 { "build", 0, NULL, MU_OPTION_DEFAULT,
53 N_("build the draft and quit immediately."),
54 mu_c_bool, &build_only },
55 { "draftfolder", 0, N_("FOLDER"), MU_OPTION_DEFAULT,
56 N_("specify the folder for message drafts"),
57 mu_c_string, &draftfolder },
58 { "nodraftfolder", 0, NULL, MU_OPTION_DEFAULT,
59 N_("undo the effect of the last --draftfolder option"),
60 mu_c_string, &draftfolder, mh_opt_clear_string },
61 { "draftmessage" , 0, N_("MSG"), MU_OPTION_DEFAULT,
62 N_("invoke the draftmessage facility"),
63 mu_c_string, &draftmessage },
64 { "folder", 0, N_("FOLDER"), MU_OPTION_DEFAULT,
65 N_("specify folder to operate upon"),
66 mu_c_string, NULL, set_folder },
67 { "file", 0, N_("FILE"), MU_OPTION_DEFAULT,
68 N_("use FILE as the message draft"),
69 mu_c_string, NULL, set_file },
70 { "editor", 0, N_("PROG"), MU_OPTION_DEFAULT,
71 N_("set the editor program to use"),
72 mu_c_string, &wh_env.editor },
73 { "noedit", 0, NULL, MU_OPTION_DEFAULT,
74 N_("suppress the initial edit"),
75 mu_c_int, &initial_edit, NULL, "0" },
76 { "form", 0, N_("FILE"), MU_OPTION_DEFAULT,
77 N_("read format from given file"),
78 mu_c_string, &formfile, mh_opt_find_file },
79 { "whatnowproc", 0, N_("PROG"), MU_OPTION_DEFAULT,
80 N_("set the replacement for whatnow program"),
81 mu_c_string, &whatnowproc },
82 { "nowhatnowproc", 0, NULL, MU_OPTION_DEFAULT,
83 N_("don't run whatnowproc"),
84 mu_c_string, &nowhatnowproc, NULL, "1" },
85 { "use", 0, NULL, MU_OPTION_DEFAULT,
86 N_("use draft file preserved after the last session"),
87 mu_c_bool, &use_draft },
88 MU_OPTION_END
89 };
90
161 /* Copy Nth message from mailbox MBOX to FILE. */ 91 /* Copy Nth message from mailbox MBOX to FILE. */
162 int 92 int
163 copy_message (mu_mailbox_t mbox, size_t n, const char *file) 93 copy_message (mu_mailbox_t mbox, size_t n, const char *file)
...@@ -201,14 +131,18 @@ copy_message (mu_mailbox_t mbox, size_t n, const char *file) ...@@ -201,14 +131,18 @@ copy_message (mu_mailbox_t mbox, size_t n, const char *file)
201 int 131 int
202 main (int argc, char **argv) 132 main (int argc, char **argv)
203 { 133 {
204 int index;
205
206 /* Native Language Support */ 134 /* Native Language Support */
207 MU_APP_INIT_NLS (); 135 MU_APP_INIT_NLS ();
208 136
209 mh_argp_init (); 137 draftfolder = mh_global_profile_get ("Draft-Folder", NULL);
210 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, 138 whatnowproc = mh_global_profile_get ("whatnowproc", NULL);
211 opt_handler, NULL, &index); 139
140 mh_getopt (&argc, &argv, options, 0,
141 args_doc, prog_doc, NULL);
142 if (use_draft)
143 draftmessage = "cur";
144 if (!formfile)
145 mh_find_file ("components", &formfile);
212 146
213 if (wh_env.file) 147 if (wh_env.file)
214 { 148 {
...@@ -226,14 +160,14 @@ main (int argc, char **argv) ...@@ -226,14 +160,14 @@ main (int argc, char **argv)
226 { 160 {
227 if (build_only || !draftfolder) 161 if (build_only || !draftfolder)
228 { 162 {
229 switch (argc - index) 163 switch (argc)
230 { 164 {
231 case 0: 165 case 0:
232 wh_env.file = mh_expand_name (NULL, "draft", 0); 166 wh_env.file = mh_expand_name (NULL, "draft", 0);
233 break; 167 break;
234 168
235 case 1: 169 case 1:
236 wh_env.file = mh_expand_name (NULL, argv[index], 0); 170 wh_env.file = mh_expand_name (NULL, argv[0], 0);
237 break; 171 break;
238 172
239 default: 173 default:
...@@ -245,7 +179,7 @@ main (int argc, char **argv) ...@@ -245,7 +179,7 @@ main (int argc, char **argv)
245 { 179 {
246 /* Comp accepts a `file', and it will, if given 180 /* Comp accepts a `file', and it will, if given
247 `-draftfolder +folder' treat this arguments as `msg'. */ 181 `-draftfolder +folder' treat this arguments as `msg'. */
248 if (use_draft || index < argc) 182 if (use_draft || argc)
249 { 183 {
250 mu_msgset_t msgset; 184 mu_msgset_t msgset;
251 mu_mailbox_t mbox; 185 mu_mailbox_t mbox;
...@@ -253,7 +187,7 @@ main (int argc, char **argv) ...@@ -253,7 +187,7 @@ main (int argc, char **argv)
253 mbox = mh_open_folder (draftfolder, 187 mbox = mh_open_folder (draftfolder,
254 MU_STREAM_RDWR|MU_STREAM_CREAT); 188 MU_STREAM_RDWR|MU_STREAM_CREAT);
255 mh_msgset_parse (&msgset, mbox, 189 mh_msgset_parse (&msgset, mbox,
256 argc - index, argv + index, 190 argc, argv,
257 use_draft ? "cur" : "new"); 191 use_draft ? "cur" : "new");
258 if (!mh_msgset_single_message (msgset)) 192 if (!mh_msgset_single_message (msgset))
259 { 193 {
...@@ -271,13 +205,13 @@ main (int argc, char **argv) ...@@ -271,13 +205,13 @@ main (int argc, char **argv)
271 } 205 }
272 wh_env.draftfile = wh_env.file; 206 wh_env.draftfile = wh_env.file;
273 207
274 if (folder_set && index < argc) 208 if (folder_set && argc)
275 { 209 {
276 mu_msgset_t msgset; 210 mu_msgset_t msgset;
277 mu_mailbox_t mbox; 211 mu_mailbox_t mbox;
278 212
279 mbox = mh_open_folder (mh_current_folder (), MU_STREAM_READ); 213 mbox = mh_open_folder (mh_current_folder (), MU_STREAM_READ);
280 mh_msgset_parse (&msgset, mbox, argc - index, argv + index, "cur"); 214 mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
281 if (!mh_msgset_single_message (msgset)) 215 if (!mh_msgset_single_message (msgset))
282 { 216 {
283 mu_error (_("only one message at a time!")); 217 mu_error (_("only one message at a time!"));
...@@ -304,7 +238,7 @@ main (int argc, char **argv) ...@@ -304,7 +238,7 @@ main (int argc, char **argv)
304 } 238 }
305 } 239 }
306 240
307 /* Exit immediately if --build is given */ 241 /* Exit immediately if -build is given */
308 if (build_only || nowhatnowproc) 242 if (build_only || nowhatnowproc)
309 return 0; 243 return 0;
310 244
......
...@@ -19,37 +19,33 @@ ...@@ -19,37 +19,33 @@
19 19
20 #include <mh.h> 20 #include <mh.h>
21 21
22 static char doc[] = N_("GNU MH fmtcheck")"\v" 22 static char prog_doc[] = N_("GNU MH fmtcheck");
23 N_("Use -help to obtain the list of traditional MH options.");
24
25 /* GNU options */
26 static struct argp_option options[] = {
27 {"form", ARG_FORM, N_("FILE"), 0,
28 N_("read format from given file")},
29 {"format", ARG_FORMAT, N_("FORMAT"), 0,
30 N_("use this format string")},
31 {"dump", ARG_DUMP, NULL, 0,
32 N_("dump the listing of compiled format code")},
33 { "debug", ARG_DEBUG, NULL, 0,
34 N_("enable parser debugging output"),},
35
36 { NULL }
37 };
38
39 /* Traditional MH options */
40 struct mh_option mh_option[] = {
41 { "form", MH_OPT_ARG, "formatfile" },
42 { "format", MH_OPT_ARG, "string" },
43 { NULL }
44 };
45 23
46 char *format_str; 24 char *format_str;
47 static mh_format_t format; 25 static mh_format_t format;
48 26 int dump_option;
49 typedef int (*action_fp) (void); 27 int debug_option;
28
29 static struct mu_option options[] = {
30 { "form", 0, N_("FILE"), MU_OPTION_DEFAULT,
31 N_("read format from given file"),
32 mu_c_string, &format_str, mh_opt_read_formfile },
33
34 { "format", 0, N_("FORMAT"), MU_OPTION_DEFAULT,
35 N_("use this format string"),
36 mu_c_string, &format_str },
37 { "dump", 0, NULL, MU_OPTION_HIDDEN,
38 N_("dump the listing of compiled format code"),
39 mu_c_bool, &dump_option },
40 { "debug", 0, NULL, MU_OPTION_DEFAULT,
41 N_("enable parser debugging output"),
42 mu_c_bool, &debug_option },
43
44 MU_OPTION_END
45 };
50 46
51 static int 47 static int
52 action_dump () 48 action_dump (void)
53 { 49 {
54 if (!format_str) 50 if (!format_str)
55 { 51 {
...@@ -60,49 +56,18 @@ action_dump () ...@@ -60,49 +56,18 @@ action_dump ()
60 return 0; 56 return 0;
61 } 57 }
62 58
63 static action_fp action = action_dump;
64
65 static error_t
66 opt_handler (int key, char *arg, struct argp_state *state)
67 {
68 switch (key)
69 {
70 case ARG_FORM:
71 mh_read_formfile (arg, &format_str);
72 break;
73
74 case ARG_FORMAT:
75 format_str = arg;
76 break;
77
78 case ARG_DUMP:
79 action = action_dump;
80 break;
81
82 case ARG_DEBUG:
83 mh_format_debug (1);
84 break;
85
86 default:
87 return ARGP_ERR_UNKNOWN;
88 }
89 return 0;
90 }
91
92 int 59 int
93 main (int argc, char **argv) 60 main (int argc, char **argv)
94 { 61 {
95 /* Native Language Support */ 62 /* Native Language Support */
96 MU_APP_INIT_NLS (); 63 MU_APP_INIT_NLS ();
97 64
98 mh_argp_init (); 65 mh_getopt (&argc, &argv, options, 0, NULL, prog_doc, NULL);
99 mh_argp_parse (&argc, &argv, 0, options, mh_option, NULL, doc, 66 mh_format_debug (debug_option);
100 opt_handler, NULL, NULL);
101
102 if (format_str && mh_format_parse (format_str, &format)) 67 if (format_str && mh_format_parse (format_str, &format))
103 { 68 {
104 mu_error (_("Bad format string")); 69 mu_error (_("Bad format string"));
105 exit (1); 70 exit (1);
106 } 71 }
107 return (*action) (); 72 return action_dump ();
108 } 73 }
......
...@@ -28,78 +28,16 @@ ...@@ -28,78 +28,16 @@
28 28
29 #include <dirent.h> 29 #include <dirent.h>
30 30
31 static char doc[] = N_("GNU MH folder")"\v" 31 static char prog_doc[] = N_("GNU MH folder");
32 N_("Use -help to obtain the list of traditional MH options.");
33 static char args_doc[] = N_("[ACTION] [MSG]"); 32 static char args_doc[] = N_("[ACTION] [MSG]");
34 33
35 static struct argp_option options[] = { 34 typedef int (*folder_action) (void);
36 {N_("Actions are:"), 0, 0, OPTION_DOC, NULL, 0 },
37 {"print", ARG_PRINT, NULL, 0,
38 N_("list the folders (default)"), 1 },
39 {"list", ARG_LIST, NULL, 0,
40 N_("list the contents of the folder stack"), 1},
41 {"pack", ARG_PACK, N_("NUMBER"), OPTION_ARG_OPTIONAL,
42 N_("remove holes in message numbering, begin numbering from NUMBER (default: first message number)"), 1},
43 {"push", ARG_PUSH, N_("FOLDER"), OPTION_ARG_OPTIONAL,
44 N_("push the folder on the folder stack. If FOLDER is specified, it is pushed. "
45 "Otherwise, if a folder is given in the command line (via + or --folder), "
46 "it is pushed on stack. Otherwise, the current folder and the top of the folder "
47 "stack are exchanged"), 1},
48 {"pop", ARG_POP, NULL, 0,
49 N_("pop the folder off the folder stack"), 1},
50
51 {N_("Options are:"), 0, 0, OPTION_DOC, NULL, 2 },
52
53 {"folder", ARG_FOLDER, N_("FOLDER"), 0,
54 N_("specify folder to operate upon"), 3},
55 {"all", ARG_ALL, NULL, 0,
56 N_("list all folders"), 3},
57 {"create", ARG_CREATE, N_("BOOL"), OPTION_ARG_OPTIONAL,
58 N_("create non-existing folders"), 3},
59 {"nocreate", ARG_NOCREATE, NULL, OPTION_HIDDEN, ""},
60 {"fast", ARG_FAST, N_("BOOL"), OPTION_ARG_OPTIONAL,
61 N_("list only the folder names"), 3},
62 {"nofast", ARG_NOFAST, NULL, OPTION_HIDDEN, ""},
63 {"header", ARG_HEADER, N_("BOOL"), OPTION_ARG_OPTIONAL,
64 N_("print the header line"), 3},
65 {"noheader", ARG_NOHEADER, NULL, OPTION_HIDDEN, ""},
66 {"recurse",ARG_RECURSIVE, N_("BOOL"), OPTION_ARG_OPTIONAL,
67 N_("scan folders recursively"), 3},
68 {"norecurse", ARG_NORECURSIVE, NULL, OPTION_HIDDEN, ""},
69 {"total", ARG_TOTAL, N_("BOOL"), OPTION_ARG_OPTIONAL,
70 N_("output the total statistics"), 3},
71 {"nototal", ARG_NOTOTAL, NULL, OPTION_HIDDEN, ""},
72 {"verbose", ARG_VERBOSE, NULL, 0,
73 N_("verbosely list actions taken"), 3},
74 {"dry-run", ARG_DRY_RUN, NULL, 0,
75 N_("do nothing, print what would be done (with --pack)"), 3},
76
77 {NULL},
78 };
79
80 /* Traditional MH options */
81 struct mh_option mh_option[] = {
82 { "print" },
83 { "list" },
84 { "push" },
85 { "pop" },
86 { "all" },
87 { "pack" },
88 { "create", MH_OPT_BOOL },
89 { "fast", MH_OPT_BOOL },
90 { "header", MH_OPT_BOOL },
91 { "recurse", MH_OPT_BOOL },
92 { "total", MH_OPT_BOOL },
93 { NULL }
94 };
95
96 typedef int (*folder_action) ();
97 35
98 static int action_print (); 36 static int action_print (void);
99 static int action_list (); 37 static int action_list (void);
100 static int action_push (); 38 static int action_push (void);
101 static int action_pop (); 39 static int action_pop (void);
102 static int action_pack (); 40 static int action_pack (void);
103 static folder_action action = action_print; 41 static folder_action action = action_print;
104 42
105 int show_all = 0; /* List all folders. Raised by --all switch */ 43 int show_all = 0; /* List all folders. Raised by --all switch */
...@@ -121,110 +59,105 @@ const char *push_folder; /* Folder name to push on stack */ ...@@ -121,110 +59,105 @@ const char *push_folder; /* Folder name to push on stack */
121 const char *mh_seq_name; /* Name of the mh sequence file (defaults to 59 const char *mh_seq_name; /* Name of the mh sequence file (defaults to
122 .mh_sequences) */ 60 .mh_sequences) */
123 int has_folder; /* Folder has been explicitely given */ 61 int has_folder; /* Folder has been explicitely given */
62 int recurse_option = 0;
124 size_t max_depth = 1; /* Maximum recursion depth (0 means infinity) */ 63 size_t max_depth = 1; /* Maximum recursion depth (0 means infinity) */
125 64
126 #define OPTION_IS_SET(opt) ((opt) == -1 ? show_all : opt) 65 #define OPTION_IS_SET(opt) ((opt) == -1 ? show_all : opt)
127 66
128 static int 67 void
129 opt_handler (int key, char *arg, struct argp_state *state) 68 set_action (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
130 { 69 {
131 switch (key) 70 if (strcmp (opt->opt_long, "print") == 0)
71 action = action_print;
72 else if (strcmp (opt->opt_long, "pack") == 0)
132 { 73 {
133 case ARG_DRY_RUN:
134 dry_run++;
135 break;
136
137 case ARG_PACK:
138 action = action_pack; 74 action = action_pack;
139 if (arg) 75 if (arg)
140 { 76 {
141 char *p; 77 if (mu_str_to_c (arg, mu_c_size, &pack_start, NULL))
142 pack_start = strtoul (arg, &p, 10); 78 {
143 if (*p) 79 mu_parseopt_error (po, _("%s: invalid number"), arg);
144 argp_error (state, _("invalid number")); 80 exit (po->po_exit_error);
81 }
145 } 82 }
146 break; 83 }
147 84 else if (strcmp (opt->opt_long, "list") == 0)
148 case ARG_PRINT: 85 action = action_list;
149 action = action_print; 86 else if (strcmp (opt->opt_long, "push") == 0)
150 break; 87 {
151
152 case ARG_LIST:
153 action = action_list;
154 break;
155
156 case ARG_PUSH:
157 action = action_push; 88 action = action_push;
158 if (arg) 89 if (arg)
159 { 90 {
160 push_folder = mh_current_folder (); 91 push_folder = mh_current_folder ();
161 mh_set_current_folder (arg); 92 mh_set_current_folder (arg);
162 } 93 }
163 break;
164
165 case ARG_POP:
166 action = action_pop;
167 break;
168
169 case ARG_ALL:
170 show_all = 1;
171 break;
172
173 case ARG_CREATE:
174 create_flag = is_true (arg);
175 break;
176
177 case ARG_NOCREATE:
178 create_flag = 0;
179
180 case ARG_FAST:
181 fast_mode = is_true (arg);
182 break;
183
184 case ARG_NOFAST:
185 fast_mode = 0;
186 break;
187
188 case ARG_HEADER:
189 print_header = is_true (arg);
190 break;
191
192 case ARG_NOHEADER:
193 print_header = 0;
194 break;
195
196 case ARG_RECURSIVE:
197 max_depth = is_true (arg) ? 0 : 1;
198 break;
199
200 case ARG_NORECURSIVE:
201 max_depth = 0;
202 break;
203
204 case ARG_TOTAL:
205 print_total = is_true (arg);
206 break;
207
208 case ARG_NOTOTAL:
209 print_total = 0;
210 break;
211
212 case ARG_FOLDER:
213 has_folder = 1;
214 push_folder = mh_current_folder ();
215 mh_set_current_folder (arg);
216 break;
217
218 case ARG_VERBOSE:
219 verbose++;
220 break;
221
222 default:
223 return ARGP_ERR_UNKNOWN;
224 } 94 }
225 return 0; 95 else if (strcmp (opt->opt_long, "pop") == 0)
96 action = action_pop;
97 else
98 abort ();
99 }
100
101 void
102 set_folder (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
103 {
104 has_folder = 1;
105 push_folder = mh_current_folder ();
106 mh_set_current_folder (arg);
226 } 107 }
227 108
109 static struct mu_option options[] = {
110 MU_OPTION_GROUP (N_("Actions are:")),
111 { "print", 0, NULL, MU_OPTION_DEFAULT,
112 N_("list the folders (default)"),
113 mu_c_string, NULL, set_action },
114 { "list", 0, NULL, MU_OPTION_DEFAULT,
115 N_("list the contents of the folder stack"),
116 mu_c_string, NULL, set_action },
117 { "pack", 0, N_("NUMBER"), MU_OPTION_ARG_OPTIONAL,
118 N_("remove holes in message numbering, begin numbering from NUMBER (default: first message number)"),
119 mu_c_string, NULL, set_action },
120 { "push", 0, N_("FOLDER"), MU_OPTION_ARG_OPTIONAL,
121 N_("push the folder on the folder stack. If FOLDER is specified, it is pushed. "
122 "Otherwise, if a folder is given in the command line (via + or --folder), "
123 "it is pushed on stack. Otherwise, the current folder and the top of the folder "
124 "stack are exchanged"),
125 mu_c_string, NULL, set_action },
126 { "pop", 0, NULL, MU_OPTION_DEFAULT,
127 N_("pop the folder off the folder stack"),
128 mu_c_string, NULL, set_action },
129
130 MU_OPTION_GROUP (N_("Options are:")),
131
132 { "folder", 0, N_("FOLDER"), MU_OPTION_DEFAULT,
133 N_("specify folder to operate upon"),
134 mu_c_string, NULL, set_folder },
135 { "all", 0, NULL, MU_OPTION_DEFAULT,
136 N_("list all folders"),
137 mu_c_bool, &show_all },
138 { "create", 0, NULL, MU_OPTION_DEFAULT,
139 N_("create non-existing folders"),
140 mu_c_bool, &create_flag },
141 { "fast", 0, NULL, MU_OPTION_DEFAULT,
142 N_("list only the folder names"),
143 mu_c_bool, &fast_mode },
144 { "header", 0, NULL, MU_OPTION_DEFAULT,
145 N_("print the header line"),
146 mu_c_bool, &print_header },
147 { "recurse",0, NULL, MU_OPTION_DEFAULT,
148 N_("scan folders recursively"),
149 mu_c_bool, &recurse_option },
150 { "total", 0, NULL, MU_OPTION_DEFAULT,
151 N_("output the total statistics"),
152 mu_c_bool, &print_total },
153 { "verbose", 0, NULL, MU_OPTION_DEFAULT,
154 N_("verbosely list actions taken"),
155 mu_c_bool, &verbose },
156 { "dry-run", 0, NULL, MU_OPTION_DEFAULT,
157 N_("do nothing, print what would be done (with --pack)"),
158 mu_c_bool, &dry_run },
159 MU_OPTION_END
160 };
228 161
229 /* ************************************************************* */ 162 /* ************************************************************* */
230 /* Printing */ 163 /* Printing */
...@@ -430,19 +363,19 @@ _folder_name_printer (void *item, void *data) ...@@ -430,19 +363,19 @@ _folder_name_printer (void *item, void *data)
430 } 363 }
431 364
432 static void 365 static void
433 print_all () 366 print_all (void)
434 { 367 {
435 mu_list_foreach (folder_info_list, _folder_info_printer, NULL); 368 mu_list_foreach (folder_info_list, _folder_info_printer, NULL);
436 } 369 }
437 370
438 static void 371 static void
439 print_fast () 372 print_fast (void)
440 { 373 {
441 mu_list_foreach (folder_info_list, _folder_name_printer, NULL); 374 mu_list_foreach (folder_info_list, _folder_name_printer, NULL);
442 } 375 }
443 376
444 static int 377 static int
445 action_print () 378 action_print (void)
446 { 379 {
447 const char *folder_dir = mu_folder_directory (); 380 const char *folder_dir = mu_folder_directory ();
448 mh_seq_name = mh_global_profile_get ("mh-sequences", MH_SEQUENCES_FILE); 381 mh_seq_name = mh_global_profile_get ("mh-sequences", MH_SEQUENCES_FILE);
...@@ -502,7 +435,7 @@ action_print () ...@@ -502,7 +435,7 @@ action_print ()
502 /* Listing */ 435 /* Listing */
503 436
504 static int 437 static int
505 action_list () 438 action_list (void)
506 { 439 {
507 const char *stack = mh_global_context_get ("Folder-Stack", NULL); 440 const char *stack = mh_global_context_get ("Folder-Stack", NULL);
508 441
...@@ -598,7 +531,7 @@ pop_val (size_t *pc, char ***pv) ...@@ -598,7 +531,7 @@ pop_val (size_t *pc, char ***pv)
598 } 531 }
599 532
600 static int 533 static int
601 action_push () 534 action_push (void)
602 { 535 {
603 size_t c; 536 size_t c;
604 char **v; 537 char **v;
...@@ -623,7 +556,7 @@ action_push () ...@@ -623,7 +556,7 @@ action_push ()
623 } 556 }
624 557
625 static int 558 static int
626 action_pop () 559 action_pop (void)
627 { 560 {
628 size_t c; 561 size_t c;
629 char **v; 562 char **v;
...@@ -849,7 +782,7 @@ fixup_private (const char *name, const char *value, void *data) ...@@ -849,7 +782,7 @@ fixup_private (const char *name, const char *value, void *data)
849 } 782 }
850 783
851 int 784 int
852 action_pack () 785 action_pack (void)
853 { 786 {
854 const char *folder_dir = mh_expand_name (NULL, mh_current_folder (), 787 const char *folder_dir = mh_expand_name (NULL, mh_current_folder (),
855 NAME_ANY); 788 NAME_ANY);
...@@ -959,9 +892,9 @@ main (int argc, char **argv) ...@@ -959,9 +892,9 @@ main (int argc, char **argv)
959 /* Native Language Support */ 892 /* Native Language Support */
960 MU_APP_INIT_NLS (); 893 MU_APP_INIT_NLS ();
961 894
962 mh_argp_init (); 895 mh_getopt (&argc, &argv, options, 0, args_doc, prog_doc, NULL);
963 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, 896 if (recurse_option)
964 opt_handler, NULL, &index); 897 max_depth = 0;
965 898
966 /* If folder is invoked by a name ending with "s" (e.g., folders), 899 /* If folder is invoked by a name ending with "s" (e.g., folders),
967 `-all' is assumed */ 900 `-all' is assumed */
......
...@@ -19,79 +19,9 @@ ...@@ -19,79 +19,9 @@
19 19
20 #include <mh.h> 20 #include <mh.h>
21 21
22 static char doc[] = N_("GNU MH forw")"\v" 22 static char prog_doc[] = N_("GNU MH forw");
23 N_("Options marked with `*' are not yet implemented.\n\
24 Use -help to obtain the list of traditional MH options.");
25 static char args_doc[] = N_("[MSGLIST]"); 23 static char args_doc[] = N_("[MSGLIST]");
26 24
27 /* GNU options */
28 static struct argp_option options[] = {
29 {"annotate", ARG_ANNOTATE, N_("BOOL"), OPTION_ARG_OPTIONAL,
30 N_("add Forwarded: header to each forwarded message")},
31 {"build", ARG_BUILD, 0, 0,
32 N_("build the draft and quit immediately")},
33 {"draftfolder", ARG_DRAFTFOLDER, N_("FOLDER"), 0,
34 N_("specify the folder for message drafts")},
35 {"nodraftfolder", ARG_NODRAFTFOLDER, 0, 0,
36 N_("undo the effect of the last --draftfolder option")},
37 {"draftmessage" , ARG_DRAFTMESSAGE, N_("MSG"), 0,
38 N_("invoke the draftmessage facility")},
39 {"folder", ARG_FOLDER, N_("FOLDER"), 0,
40 N_("specify folder to operate upon")},
41 {"editor", ARG_EDITOR, N_("PROG"), 0,
42 N_("set the editor program to use")},
43 {"noedit", ARG_NOEDIT, 0, 0,
44 N_("suppress the initial edit")},
45 {"file", ARG_FILE, N_("FILE"), 0,
46 N_("read message from FILE")},
47 {"format", ARG_FORMAT, N_("BOOL"), 0,
48 N_("format messages")},
49 {"noformat", ARG_NOFORMAT, NULL, 0,
50 N_("undo the effect of the last --format option") },
51 {"form", ARG_FORM, N_("FILE"), 0,
52 N_("read format from given file")},
53 {"filter", ARG_FILTER, N_("FILE"), 0,
54 N_("use filter FILE to preprocess the body of the message") },
55 {"nofilter", ARG_NOFILTER, NULL, 0,
56 N_("undo the effect of the last --filter option") },
57 {"inplace", ARG_INPLACE, N_("BOOL"), OPTION_ARG_OPTIONAL,
58 N_("* annotate the message in place")},
59 {"noinplace", ARG_NOINPLACE, 0, OPTION_HIDDEN, "" },
60 {"mime", ARG_MIME, N_("BOOL"), OPTION_ARG_OPTIONAL,
61 N_("use MIME encapsulation") },
62 {"nomime", ARG_NOMIME, NULL, OPTION_HIDDEN, "" },
63 {"width", ARG_WIDTH, N_("NUMBER"), 0, N_("Set output width")},
64 {"whatnowproc", ARG_WHATNOWPROC, N_("PROG"), 0,
65 N_("set the replacement for whatnow program")},
66 {"nowhatnowproc", ARG_NOWHATNOWPROC, NULL, 0,
67 N_("don't run whatnowproc")},
68 {"use", ARG_USE, N_("BOOL"), OPTION_ARG_OPTIONAL,
69 N_("use draft file preserved after the last session") },
70 {"nouse", ARG_NOUSE, N_("BOOL"), OPTION_HIDDEN, "" },
71
72 {NULL},
73 };
74
75 /* Traditional MH options */
76 struct mh_option mh_option[] = {
77 { "annotate", MH_OPT_BOOL },
78 { "build" },
79 { "file", MH_OPT_ARG, "msgfile" },
80 { "form", MH_OPT_ARG, "formatfile" },
81 { "format", MH_OPT_BOOL },
82 { "draftfolder", MH_OPT_ARG, "folder" },
83 { "nodraftfolder" },
84 { "draftmessage" },
85 { "editor", MH_OPT_ARG, "program" },
86 { "noedit" },
87 { "filter", MH_OPT_ARG, "program" },
88 { "inplace", MH_OPT_BOOL },
89 { "whatnowproc", MH_OPT_ARG, "program" },
90 { "nowhatnowproc" },
91 { "mime", MH_OPT_BOOL },
92 { NULL }
93 };
94
95 enum encap_type 25 enum encap_type
96 { 26 {
97 encap_clear, 27 encap_clear,
...@@ -120,123 +50,99 @@ static char *input_file; /* input file name (--file option) */ ...@@ -120,123 +50,99 @@ static char *input_file; /* input file name (--file option) */
120 static mu_msgset_t msgset; 50 static mu_msgset_t msgset;
121 static mu_mailbox_t mbox; 51 static mu_mailbox_t mbox;
122 52
123 static int 53 static void
124 opt_handler (int key, char *arg, struct argp_state *state) 54 set_filter (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
125 { 55 {
126 switch (key) 56 mh_find_file (arg, &mhl_filter_file);
127 { 57 encap = encap_mhl;
128 case ARGP_KEY_INIT: 58 }
129 draftfolder = mh_global_profile_get ("Draft-Folder", NULL);
130 whatnowproc = mh_global_profile_get ("whatnowproc", NULL);
131 break;
132
133 case ARG_ANNOTATE:
134 annotate = is_true (arg);
135 break;
136
137 case ARG_BUILD:
138 build_only = 1;
139 break;
140
141 case ARG_FILE:
142 input_file = arg;
143 break;
144
145 case ARG_DRAFTFOLDER:
146 draftfolder = arg;
147 break;
148
149 case ARG_NODRAFTFOLDER:
150 draftfolder = NULL;
151 break;
152
153 case ARG_DRAFTMESSAGE:
154 draftmessage = arg;
155 break;
156
157 case ARG_USE:
158 use_draft = is_true (arg);
159 break;
160
161 case ARG_NOUSE:
162 use_draft = 0;
163 break;
164
165 case ARG_WIDTH:
166 width = strtoul (arg, NULL, 0);
167 if (!width)
168 {
169 argp_error (state, _("invalid width"));
170 exit (1);
171 }
172 break;
173
174 case ARG_EDITOR:
175 wh_env.editor = arg;
176 break;
177
178 case ARG_FOLDER:
179 mh_set_current_folder (arg);
180 break;
181 59
182 case ARG_FORM: 60 static void
183 mh_find_file (arg, &formfile); 61 clear_filter (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
184 break; 62 {
63 mhl_filter_file = NULL;
64 encap = encap_clear;
65 }
185 66
186 case ARG_FORMAT: 67 static void
187 if (is_true (arg)) 68 set_mime (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
188 { 69 {
189 encap = encap_mhl; 70 if (strcmp (arg, "1") == 0)
190 mh_find_file ("mhl.forward", &mhl_filter_file); 71 encap = encap_mime;
191 } 72 else
192 else 73 encap = encap_clear;
193 encap = encap_clear; 74 }
194 break;
195
196 case ARG_NOFORMAT:
197 encap = encap_clear;
198 break;
199 75
200 case ARG_FILTER: 76 static void
201 mh_find_file (arg, &mhl_filter_file); 77 set_format (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
78 {
79 if (arg)
80 {
202 encap = encap_mhl; 81 encap = encap_mhl;
203 break; 82 mh_find_file ("mhl.forward", &mhl_filter_file);
204
205 case ARG_MIME:
206 if (is_true (arg))
207 {
208 encap = encap_mime;
209 break;
210 }
211 /*FALLTHRU*/
212 case ARG_NOMIME:
213 if (encap == encap_mime)
214 encap = encap_clear;
215 break;
216
217 case ARG_INPLACE:
218 mh_opt_notimpl_warning ("-inplace");
219 break;
220
221 case ARG_WHATNOWPROC:
222 whatnowproc = arg;
223 break;
224
225 case ARG_NOWHATNOWPROC:
226 nowhatnowproc = 1;
227 break;
228
229 case ARGP_KEY_FINI:
230 if (!formfile)
231 mh_find_file ("forwcomps", &formfile);
232 break;
233
234 default:
235 return ARGP_ERR_UNKNOWN;
236 } 83 }
237 return 0; 84 else
85 encap = encap_clear;
238 } 86 }
239 87
88 static struct mu_option options[] = {
89 { "annotate", 0, NULL, MU_OPTION_DEFAULT,
90 N_("add Forwarded: header to each forwarded message"),
91 mu_c_bool, &annotate },
92 { "build", 0, NULL, MU_OPTION_DEFAULT,
93 N_("build the draft and quit immediately"),
94 mu_c_bool, &build_only },
95 { "draftfolder", 0, N_("FOLDER"), MU_OPTION_DEFAULT,
96 N_("specify the folder for message drafts"),
97 mu_c_string, &draftfolder },
98 { "nodraftfolder", 0, NULL, MU_OPTION_DEFAULT,
99 N_("undo the effect of the last --draftfolder option"),
100 mu_c_string, &draftfolder, mh_opt_clear_string },
101 { "draftmessage" , 0, N_("MSG"), MU_OPTION_DEFAULT,
102 N_("invoke the draftmessage facility"),
103 mu_c_string, &draftmessage },
104 { "editor", 0, N_("PROG"), MU_OPTION_DEFAULT,
105 N_("set the editor program to use"),
106 mu_c_string, &wh_env.editor },
107 { "noedit", 0, NULL, MU_OPTION_DEFAULT,
108 N_("suppress the initial edit"),
109 mu_c_int, &initial_edit, NULL, "0" },
110 { "file", 0, N_("FILE"), MU_OPTION_DEFAULT,
111 N_("read message from FILE"),
112 mu_c_string, &input_file },
113 { "format", 0, NULL, MU_OPTION_DEFAULT,
114 N_("format messages"),
115 mu_c_bool, NULL, set_format },
116 { "form", 0, N_("FILE"), MU_OPTION_DEFAULT,
117 N_("read format from given file"),
118 mu_c_string, &formfile, mh_opt_find_file },
119 { "filter", 0, N_("FILE"), MU_OPTION_DEFAULT,
120 N_("use filter FILE to preprocess the body of the message"),
121 mu_c_string, NULL, set_filter },
122 { "nofilter", 0, NULL, MU_OPTION_DEFAULT,
123 N_("undo the effect of the last --filter option"),
124 mu_c_string, NULL, clear_filter },
125 { "inplace", 0, NULL, MU_OPTION_HIDDEN,
126 N_("annotate the message in place"),
127 mu_c_bool, NULL, mh_opt_notimpl_warning },
128 { "mime", 0, NULL, MU_OPTION_DEFAULT,
129 N_("use MIME encapsulation"),
130 mu_c_bool, NULL, set_mime },
131 { "width", 0, N_("NUMBER"), MU_OPTION_DEFAULT,
132 N_("Set output width"),
133 mu_c_int, &width },
134 { "whatnowproc", 0, N_("PROG"), MU_OPTION_DEFAULT,
135 N_("set the replacement for whatnow program"),
136 mu_c_string, &whatnowproc },
137 { "nowhatnowproc", 0, NULL, MU_OPTION_DEFAULT,
138 N_("don't run whatnowproc"),
139 mu_c_int, &nowhatnowproc, NULL, "1" },
140 { "use", 0, NULL, MU_OPTION_DEFAULT,
141 N_("use draft file preserved after the last session"),
142 mu_c_bool, &use_draft },
143 MU_OPTION_END
144 };
145
240 struct format_data 146 struct format_data
241 { 147 {
242 int num; 148 int num;
...@@ -475,18 +381,18 @@ finish_draft () ...@@ -475,18 +381,18 @@ finish_draft ()
475 int 381 int
476 main (int argc, char **argv) 382 main (int argc, char **argv)
477 { 383 {
478 int index, rc; 384 int rc;
479 385
480 /* Native Language Support */ 386 /* Native Language Support */
481 MU_APP_INIT_NLS (); 387 MU_APP_INIT_NLS ();
482 388
483 mh_argp_init (); 389 draftfolder = mh_global_profile_get ("Draft-Folder", NULL);
484 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, 390 whatnowproc = mh_global_profile_get ("whatnowproc", NULL);
485 opt_handler, NULL, &index); 391 mh_getopt (&argc, &argv, options, MH_GETOPT_DEFAULT_FOLDER,
486 392 args_doc, prog_doc, NULL);
487 argc -= index; 393 if (!formfile)
488 argv += index; 394 mh_find_file ("forwcomps", &formfile);
489 395
490 if (input_file) 396 if (input_file)
491 { 397 {
492 if (encap == encap_mime) 398 if (encap == encap_mime)
......
...@@ -20,71 +20,14 @@ ...@@ -20,71 +20,14 @@
20 #include <mh.h> 20 #include <mh.h>
21 #include "muscript.h" 21 #include "muscript.h"
22 22
23 static char doc[] = N_("GNU MH inc")"\v" 23 static char prog_doc[] = N_("GNU MH inc");
24 N_("Debug flags are:\n\ 24 static char extra_doc[] = N_("Debug flags are:\n\
25 g - guile stack traces\n\ 25 g - guile stack traces\n\
26 t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\ 26 t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\
27 i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n\ 27 i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n\
28 l - sieve action logs\n\n\ 28 l - sieve action logs");
29 Use -help to obtain the list of traditional MH options.");
30 static char args_doc[] = N_("[+FOLDER]"); 29 static char args_doc[] = N_("[+FOLDER]");
31 30
32 /* GNU options */
33 static struct argp_option options[] = {
34 {"file", ARG_FILE, N_("FILE"), 0,
35 N_("incorporate mail from named file")},
36 {"folder", ARG_FOLDER, N_("FOLDER"), 0,
37 N_("specify folder to incorporate mail to")},
38 {"audit", ARG_AUDIT, N_("FILE"), 0,
39 N_("enable audit")},
40 {"noaudit", ARG_NOAUDIT, 0, 0,
41 N_("disable audit")},
42 {"changecur", ARG_CHANGECUR, N_("BOOL"), OPTION_ARG_OPTIONAL,
43 N_("mark first incorporated message as current (default)")},
44 {"nochangecur", ARG_NOCHANGECUR, NULL, OPTION_HIDDEN, ""},
45 {"form", ARG_FORM, N_("FILE"), 0,
46 N_("read format from given file")},
47 {"format", ARG_FORMAT, N_("FORMAT"), 0,
48 N_("use this format string")},
49 {"truncate", ARG_TRUNCATE, N_("BOOL"), OPTION_ARG_OPTIONAL,
50 N_("truncate source mailbox after incorporating (default)")},
51 {"notruncate", ARG_NOTRUNCATE, NULL, OPTION_HIDDEN, ""},
52 {"moveto", ARG_MOVETO, N_("MAILBOX"), 0,
53 N_("move incorporated messages to MAILBOX instead of deleting them") },
54 {"width", ARG_WIDTH, N_("NUMBER"), 0,
55 N_("set output width")},
56 {"quiet", ARG_QUIET, 0, 0,
57 N_("be quiet")},
58 {"notify", ARG_NOTIFY,N_("BOOL"), OPTION_ARG_OPTIONAL,
59 N_("enable biff notification"), },
60 {"language",ARG_LANG, N_("LANG"), 0,
61 N_("set language for the --script option") },
62 {"script", ARG_SCRIPT,N_("FILE"), 0,
63 N_("filter incoming messages using script FILE") },
64 {"debug", ARG_DEBUG, N_("FLAGS"), 0,
65 N_("enable debugging") },
66 { 0 }
67 };
68
69 /* Traditional MH options */
70 struct mh_option mh_option[] = {
71 { "audit", MH_OPT_ARG, "audit-file" },
72 { "noaudit" },
73 { "changecur", MH_OPT_BOOL },
74 { "file", MH_OPT_ARG, "input-file" },
75 { "form", MH_OPT_ARG, "format-file" },
76 { "format", MH_OPT_ARG, "string" },
77 { "truncate", MH_OPT_BOOL },
78 { "moveto", MH_OPT_ARG, "folder" },
79 { "width", MH_OPT_ARG, "number" },
80 { "notify", MH_OPT_BOOL },
81 { "quiet" },
82 { "language", MH_OPT_ARG, "lang" },
83 { "script", MH_OPT_ARG, "file" },
84 { "debug", MH_OPT_ARG, "flags" },
85 { NULL }
86 };
87
88 static char *format_str = mh_list_format; 31 static char *format_str = mh_list_format;
89 static int width = 80; 32 static int width = 80;
90 static mu_list_t input_file_list; 33 static mu_list_t input_file_list;
...@@ -99,114 +42,89 @@ static const char *move_to_mailbox; ...@@ -99,114 +42,89 @@ static const char *move_to_mailbox;
99 static const char *script_file; 42 static const char *script_file;
100 static const char *script_lang; 43 static const char *script_lang;
101 44
102 static error_t 45 static void
103 opt_handler (int key, char *arg, struct argp_state *state) 46 add_file (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
104 { 47 {
105 int rc; 48 int rc;
106 char *p; 49 if (!input_file_list)
107
108 switch (key)
109 { 50 {
110 case ARGP_KEY_FINI: 51 rc = mu_list_create (&input_file_list);
111 if (!append_folder)
112 append_folder = mh_global_profile_get ("Inbox", "inbox");
113 break;
114
115 case ARG_AUDIT:
116 audit_file = arg;
117 break;
118
119 case ARG_NOAUDIT:
120 audit_file = NULL;
121 break;
122
123 case ARG_CHANGECUR:
124 changecur = is_true (arg);
125 break;
126
127 case ARG_DEBUG:
128 if (mu_script_debug_flags (arg, &p))
129 argp_error (state, _("invalid debug flag near %s"), p);
130 break;
131
132 case ARG_NOCHANGECUR:
133 changecur = 0;
134 break;
135
136 case ARG_FOLDER:
137 append_folder = arg;
138 break;
139
140 case ARG_FORM:
141 mh_read_formfile (arg, &format_str);
142 break;
143
144 case ARG_FORMAT:
145 format_str = arg;
146 break;
147
148 case ARG_FILE:
149 if (!input_file_list)
150 {
151 rc = mu_list_create (&input_file_list);
152 if (rc)
153 {
154 mu_diag_funcall (MU_DIAG_ERROR,
155 "mu_list_create", "&input_file_list", rc);
156 exit (1);
157 }
158 }
159 rc = mu_list_append (input_file_list, arg);
160 if (rc) 52 if (rc)
161 { 53 {
162 mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", arg, rc); 54 mu_diag_funcall (MU_DIAG_ERROR,
163 exit (1); 55 "mu_list_create", "&input_file_list", rc);
164 }
165 break;
166
167 case ARG_TRUNCATE:
168 truncate_source = is_true (arg);
169 break;
170
171 case ARG_NOTRUNCATE:
172 truncate_source = 0;
173 break;
174
175 case ARG_MOVETO:
176 move_to_mailbox = arg;
177 break;
178
179 case ARG_WIDTH:
180 width = strtoul (arg, NULL, 0);
181 if (!width)
182 {
183 argp_error (state, _("invalid width"));
184 exit (1); 56 exit (1);
185 } 57 }
186 break; 58 }
187 59 rc = mu_list_append (input_file_list, mu_strdup (arg));
188 case ARG_QUIET: 60 if (rc)
189 quiet = 1; 61 {
190 break; 62 mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", arg, rc);
191 63 exit (1);
192 case ARG_NOTIFY: 64 }
193 notify = is_true (arg);; 65 }
194 break;
195
196 case ARG_LANG:
197 script_lang = arg;
198 break;
199 66
200 case ARG_SCRIPT: 67 static void
201 script_file = arg; 68 set_debug (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
202 break; 69 {
203 70 char *p;
204 default: 71
205 return ARGP_ERR_UNKNOWN; 72 if (mu_script_debug_flags (arg, &p))
73 {
74 mu_parseopt_error (po, _("invalid debug flag near %s"), p);
75 exit (po->po_exit_error);
206 } 76 }
207 return 0;
208 } 77 }
209 78
79 static struct mu_option options[] = {
80 { "file", 0, N_("FILE"), MU_OPTION_DEFAULT,
81 N_("incorporate mail from named file"),
82 mu_c_string, NULL, add_file },
83 { "folder", 0, N_("FOLDER"), MU_OPTION_DEFAULT,
84 N_("specify folder to incorporate mail to"),
85 mu_c_string, &append_folder },
86 { "audit", 0, N_("FILE"), MU_OPTION_DEFAULT,
87 N_("enable audit"),
88 mu_c_string, &audit_file },
89 { "noaudit", 0, NULL, MU_OPTION_DEFAULT,
90 N_("disable audit"),
91 mu_c_string, &audit_file, mh_opt_clear_string },
92 { "changecur", 0, NULL, MU_OPTION_DEFAULT,
93 N_("mark first incorporated message as current (default)"),
94 mu_c_bool, &changecur },
95 { "form", 0, N_("FILE"), MU_OPTION_DEFAULT,
96 N_("read format from given file"),
97 mu_c_string, &format_str, mh_opt_read_formfile },
98 { "format", 0, N_("FORMAT"), MU_OPTION_DEFAULT,
99 N_("use this format string"),
100 mu_c_string, &format_str },
101 { "truncate", 0, NULL, MU_OPTION_DEFAULT,
102 N_("truncate source mailbox after incorporating (default)"),
103 mu_c_bool, &truncate_source },
104 { "moveto", 0, N_("MAILBOX"), MU_OPTION_DEFAULT,
105 N_("move incorporated messages to MAILBOX instead of deleting them"),
106 mu_c_string, &move_to_mailbox },
107 { "width", 0, N_("NUMBER"), MU_OPTION_DEFAULT,
108 N_("set output width"),
109 mu_c_int, &width },
110 { "quiet", 0, NULL, MU_OPTION_DEFAULT,
111 N_("be quiet"),
112 mu_c_bool, &quiet },
113 { "notify", 0, NULL, MU_OPTION_DEFAULT,
114 N_("enable biff notification"),
115 mu_c_bool, &notify },
116 { "language", 0, N_("LANG"), MU_OPTION_DEFAULT,
117 N_("set language for the --script option"),
118 mu_c_string, &script_lang },
119 { "script", 0, N_("FILE"), MU_OPTION_DEFAULT,
120 N_("filter incoming messages using script FILE"),
121 mu_c_string, &script_file },
122 { "debug", 0, N_("FLAGS"), MU_OPTION_DEFAULT,
123 N_("enable debugging"),
124 mu_c_string, 0, set_debug },
125 MU_OPTION_END
126 };
127
210 void 128 void
211 list_message (mh_format_t *format, mu_mailbox_t mbox, size_t msgno, 129 list_message (mh_format_t *format, mu_mailbox_t mbox, size_t msgno,
212 size_t width) 130 size_t width)
...@@ -430,9 +348,10 @@ main (int argc, char **argv) ...@@ -430,9 +348,10 @@ main (int argc, char **argv)
430 /* Native Language Support */ 348 /* Native Language Support */
431 MU_APP_INIT_NLS (); 349 MU_APP_INIT_NLS ();
432 350
433 mh_argp_init (); 351 mh_getopt (&argc, &argv, options, 0, args_doc, prog_doc, extra_doc);
434 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, 352 if (!append_folder)
435 opt_handler, NULL, NULL); 353 append_folder = mh_global_profile_get ("Inbox", "inbox");
354
436 mu_registrar_set_default_scheme ("mh"); 355 mu_registrar_set_default_scheme ("mh");
437 356
438 /* Inc sets missing cur to 1 */ 357 /* Inc sets missing cur to 1 */
......
...@@ -17,41 +17,17 @@ ...@@ -17,41 +17,17 @@
17 17
18 #include <mh.h> 18 #include <mh.h>
19 19
20 static char doc[] = N_("GNU MH install-mh")"\v" 20 static char prog_doc[] = N_("GNU MH install-mh");
21 N_("Use -help to obtain the list of traditional MH options.");
22
23 /* GNU options */
24 static struct argp_option options[] = {
25 {"auto", ARG_AUTO, NULL, 0, N_("do not ask for anything")},
26 {"compat", ARG_COMPAT, NULL, OPTION_HIDDEN, ""},
27 {NULL}
28 };
29
30 struct mh_option mh_option[] = {
31 { "auto" },
32 { "compat" },
33 { NULL }
34 };
35 21
36 int automode; 22 int automode;
37 23
38 static error_t 24 static struct mu_option options[] = {
39 opt_handler (int key, char *arg, struct argp_state *state) 25 { "auto", 0, NULL, MU_OPTION_DEFAULT,
40 { 26 N_("do not ask for anything"),
41 switch (key) 27 mu_c_bool, &automode },
42 { 28 { "compat", 0, NULL, MU_OPTION_HIDDEN, "", mu_c_void },
43 case ARG_AUTO: 29 MU_OPTION_END
44 automode = 1; 30 };
45 break;
46
47 case ARG_COMPAT:
48 break;
49
50 default:
51 return ARGP_ERR_UNKNOWN;
52 }
53 return 0;
54 }
55 31
56 int 32 int
57 main (int argc, char **argv) 33 main (int argc, char **argv)
...@@ -62,10 +38,8 @@ main (int argc, char **argv) ...@@ -62,10 +38,8 @@ main (int argc, char **argv)
62 /* Native Language Support */ 38 /* Native Language Support */
63 MU_APP_INIT_NLS (); 39 MU_APP_INIT_NLS ();
64 40
65 mh_argp_init ();
66 mh_auto_install = 0; 41 mh_auto_install = 0;
67 mh_argp_parse (&argc, &argv, 0, options, mh_option, NULL, doc, 42 mh_getopt (&argc, &argv, options, 0, NULL, prog_doc, NULL);
68 opt_handler, NULL, NULL);
69 43
70 name = getenv ("MH"); 44 name = getenv ("MH");
71 if (name) 45 if (name)
......
...@@ -17,105 +17,77 @@ ...@@ -17,105 +17,77 @@
17 17
18 #include <mh.h> 18 #include <mh.h>
19 19
20 static char doc[] = N_("GNU MH mark")"\v" 20 static char prog_doc[] = N_("GNU MH mark");
21 N_("Use -help to obtain the list of traditional MH options.");
22 static char args_doc[] = N_("[MSGLIST]"); 21 static char args_doc[] = N_("[MSGLIST]");
23 22
24 /* GNU options */ 23 enum action_type
25 static struct argp_option options[] = { 24 {
26 {"folder", ARG_FOLDER, N_("FOLDER"), 0, 25 action_undef,
27 N_("specify folder to operate upon")}, 26 action_list,
28 {"sequence", ARG_SEQUENCE, N_("NAME"), 0, 27 action_add,
29 N_("specify sequence name to operate upon")}, 28 action_delete
30 {"add", ARG_ADD, NULL, 0, 29 };
31 N_("add messages to the sequence")}, 30 static enum action_type action = action_undef; /* Action to perform */
32 {"delete", ARG_DELETE, NULL, 0,
33 N_("delete messages from the sequence")},
34 {"list", ARG_LIST, NULL, 0,
35 N_("list the sequences")},
36 {"public", ARG_PUBLIC, N_("BOOL"), OPTION_ARG_OPTIONAL,
37 N_("create public sequence")},
38 {"nopublic", ARG_NOPUBLIC, NULL, OPTION_HIDDEN, "" },
39 {"zero", ARG_ZERO, N_("BOOL"), OPTION_ARG_OPTIONAL,
40 N_("empty the sequence before adding messages")},
41 {"nozero", ARG_NOZERO, NULL, OPTION_HIDDEN, "" },
42 {NULL}
43 };
44
45 struct mh_option mh_option[] = {
46 { "sequence" },
47 { "add" },
48 { "delete" },
49 { "list" },
50 { "public", MH_OPT_BOOL },
51 { "zero", MH_OPT_BOOL },
52 { NULL }
53 };
54 31
55 static int action; /* Action to perform */
56 static int seq_flags = 0; /* Create public sequences; 32 static int seq_flags = 0; /* Create public sequences;
57 Do not zero the sequence before addition */ 33 Do not zero the sequence before addition */
58 static mu_list_t seq_list; /* List of sequence names to operate upon */ 34 static mu_list_t seq_list; /* List of sequence names to operate upon */
59 35
60 static const char *mbox_dir; 36 static const char *mbox_dir;
37 static int public_option = -1;
38 static int zero_option = -1;
61 39
62 static void 40 static void
63 add_sequence (char *name) 41 set_action_add (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
64 { 42 {
65 if (!seq_list && mu_list_create (&seq_list)) 43 action = action_add;
66 {
67 mu_error (_("cannot create sequence list"));
68 exit (1);
69 }
70 mu_list_append (seq_list, name);
71 } 44 }
72 45
73 static error_t 46 static void
74 opt_handler (int key, char *arg, struct argp_state *state) 47 set_action_delete (struct mu_parseopt *po, struct mu_option *opt,
48 char const *arg)
75 { 49 {
76 switch (key) 50 action = action_delete;
77 { 51 }
78 case ARG_FOLDER:
79 mh_set_current_folder (arg);
80 break;
81
82 case ARG_SEQUENCE:
83 add_sequence (arg);
84 break;
85 52
86 case ARG_ADD: 53 static void
87 case ARG_DELETE: 54 set_action_list (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
88 case ARG_LIST: 55 {
89 action = key; 56 action = action_list;
90 break; 57 }
91
92 case ARG_PUBLIC:
93 if (is_true (arg))
94 seq_flags &= ~SEQ_PRIVATE;
95 else
96 seq_flags |= SEQ_PRIVATE;
97 break;
98
99 case ARG_NOPUBLIC:
100 seq_flags |= SEQ_PRIVATE;
101 break;
102
103 case ARG_ZERO:
104 if (is_true (arg))
105 seq_flags |= SEQ_ZERO;
106 else
107 seq_flags &= ~SEQ_ZERO;
108 break;
109 58
110 case ARG_NOZERO: 59 static void
111 seq_flags &= ~SEQ_ZERO; 60 add_sequence (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
112 break; 61 {
113 62 if (!seq_list && mu_list_create (&seq_list))
114 default: 63 {
115 return ARGP_ERR_UNKNOWN; 64 mu_error (_("cannot create sequence list"));
65 exit (1);
116 } 66 }
117 return 0; 67 mu_list_append (seq_list, mu_strdup (arg));
118 } 68 }
69
70 static struct mu_option options[] = {
71 { "sequence", 0, N_("NAME"), MU_OPTION_DEFAULT,
72 N_("specify sequence name to operate upon"),
73 mu_c_string, NULL, add_sequence },
74 { "add", 0, NULL, MU_OPTION_DEFAULT,
75 N_("add messages to the sequence"),
76 mu_c_string, NULL, set_action_add },
77 { "delete", 0, NULL, MU_OPTION_DEFAULT,
78 N_("delete messages from the sequence"),
79 mu_c_string, NULL, set_action_delete },
80 { "list", 0, NULL, MU_OPTION_DEFAULT,
81 N_("list the sequences"),
82 mu_c_string, NULL, set_action_list },
83 { "public", 0, NULL, MU_OPTION_DEFAULT,
84 N_("create public sequence"),
85 mu_c_bool, &public_option },
86 { "zero", 0, NULL, MU_OPTION_DEFAULT,
87 N_("empty the sequence before adding messages"),
88 mu_c_bool, &zero_option },
89 MU_OPTION_END
90 };
119 91
120 92
121 struct mark_closure 93 struct mark_closure
...@@ -125,7 +97,7 @@ struct mark_closure ...@@ -125,7 +97,7 @@ struct mark_closure
125 }; 97 };
126 98
127 static int 99 static int
128 action_add (void *item, void *data) 100 do_add (void *item, void *data)
129 { 101 {
130 struct mark_closure *clos = data; 102 struct mark_closure *clos = data;
131 mh_seq_add (clos->mbox, (char *)item, clos->msgset, seq_flags); 103 mh_seq_add (clos->mbox, (char *)item, clos->msgset, seq_flags);
...@@ -133,7 +105,7 @@ action_add (void *item, void *data) ...@@ -133,7 +105,7 @@ action_add (void *item, void *data)
133 } 105 }
134 106
135 static int 107 static int
136 action_delete (void *item, void *data) 108 do_delete (void *item, void *data)
137 { 109 {
138 struct mark_closure *clos = data; 110 struct mark_closure *clos = data;
139 mh_seq_delete (clos->mbox, (char *)item, clos->msgset, seq_flags); 111 mh_seq_delete (clos->mbox, (char *)item, clos->msgset, seq_flags);
...@@ -141,7 +113,7 @@ action_delete (void *item, void *data) ...@@ -141,7 +113,7 @@ action_delete (void *item, void *data)
141 } 113 }
142 114
143 static int 115 static int
144 action_list (void *item, void *data) 116 do_list (void *item, void *data)
145 { 117 {
146 struct mark_closure *clos = data; 118 struct mark_closure *clos = data;
147 char *name = item; 119 char *name = item;
...@@ -190,25 +162,45 @@ list_all (mu_mailbox_t mbox) ...@@ -190,25 +162,45 @@ list_all (mu_mailbox_t mbox)
190 int 162 int
191 main (int argc, char **argv) 163 main (int argc, char **argv)
192 { 164 {
193 int index;
194 mu_msgset_t msgset; 165 mu_msgset_t msgset;
195 mu_mailbox_t mbox; 166 mu_mailbox_t mbox;
196 mu_url_t url; 167 mu_url_t url;
197 struct mark_closure clos; 168 struct mark_closure clos;
198 169
199 MU_APP_INIT_NLS (); 170 MU_APP_INIT_NLS ();
200 mh_argp_init ();
201 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
202 opt_handler, NULL, &index);
203 171
172 mh_getopt (&argc, &argv, options, MH_GETOPT_DEFAULT_FOLDER,
173 args_doc, prog_doc, NULL);
174 if (public_option == -1)
175 /* use default */;
176 else if (public_option)
177 seq_flags &= ~SEQ_PRIVATE;
178 else
179 seq_flags |= SEQ_PRIVATE;
180
181 if (zero_option == -1)
182 /* use default */;
183 else if (zero_option)
184 seq_flags |= SEQ_ZERO;
185 else
186 seq_flags &= ~SEQ_ZERO;
187
188 if (action == action_undef)
189 {
190 /* If no explicit action is given, assume -add if a sequence
191 was specified, and -list otherwise. */
192 if (mu_list_is_empty (seq_list))
193 action = action_list;
194 else
195 action = action_add;
196 }
197
204 mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR); 198 mbox = mh_open_folder (mh_current_folder (), MU_STREAM_RDWR);
205 mu_mailbox_get_url (mbox, &url); 199 mu_mailbox_get_url (mbox, &url);
206 mbox_dir = mu_url_to_string (url); 200 mbox_dir = mu_url_to_string (url);
207 if (memcmp (mbox_dir, "mh:", 3) == 0) 201 if (memcmp (mbox_dir, "mh:", 3) == 0)
208 mbox_dir += 3; 202 mbox_dir += 3;
209 203
210 argc -= index;
211 argv += index;
212 mh_msgset_parse (&msgset, mbox, argc, argv, "cur"); 204 mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
213 205
214 clos.mbox = mbox; 206 clos.mbox = mbox;
...@@ -216,32 +208,34 @@ main (int argc, char **argv) ...@@ -216,32 +208,34 @@ main (int argc, char **argv)
216 //FIXME: msgset operates on UIDs but there's no way to inform it about that. 208 //FIXME: msgset operates on UIDs but there's no way to inform it about that.
217 switch (action) 209 switch (action)
218 { 210 {
219 case ARG_ADD: 211 case action_add:
220 if (!seq_list) 212 if (!seq_list)
221 { 213 {
222 mu_error (_("--add requires at least one --sequence argument")); 214 mu_error (_("--add requires at least one --sequence argument"));
223 return 1; 215 return 1;
224 } 216 }
225 mu_list_foreach (seq_list, action_add, (void *) &clos); 217 mu_list_foreach (seq_list, do_add, (void *) &clos);
226 mh_global_save_state (); 218 mh_global_save_state ();
227 break; 219 break;
228 220
229 case ARG_DELETE: 221 case action_delete:
230 if (!seq_list) 222 if (!seq_list)
231 { 223 {
232 mu_error (_("--delete requires at least one --sequence argument")); 224 mu_error (_("--delete requires at least one --sequence argument"));
233 return 1; 225 return 1;
234 } 226 }
235 mu_list_foreach (seq_list, action_delete, (void *) &clos); 227 mu_list_foreach (seq_list, do_delete, (void *) &clos);
236 mh_global_save_state (); 228 mh_global_save_state ();
237 break; 229 break;
238 230
239 case ARG_LIST: 231 case action_list:
240 if (!seq_list) 232 if (!seq_list)
241 list_all (mbox); 233 list_all (mbox);
242 else 234 else
243 mu_list_foreach (seq_list, action_list, &clos); 235 mu_list_foreach (seq_list, do_list, &clos);
244 break; 236 break;
237 default:
238 abort ();
245 } 239 }
246 mu_mailbox_close (mbox); 240 mu_mailbox_close (mbox);
247 mu_mailbox_destroy (&mbox); 241 mu_mailbox_destroy (&mbox);
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
57 #include <mailutils/io.h> 57 #include <mailutils/io.h>
58 #include <mailutils/property.h> 58 #include <mailutils/property.h>
59 #include <mailutils/prog.h> 59 #include <mailutils/prog.h>
60 #include <mailutils/opool.h>
60 #include <mailutils/mh.h> 61 #include <mailutils/mh.h>
61 #include <mailutils/stdstream.h> 62 #include <mailutils/stdstream.h>
62 #include <mailutils/datetime.h> 63 #include <mailutils/datetime.h>
...@@ -230,7 +231,7 @@ extern int mh_mailbox_cur_default; ...@@ -230,7 +231,7 @@ extern int mh_mailbox_cur_default;
230 void mh_init (void); 231 void mh_init (void);
231 void mh_init2 (void); 232 void mh_init2 (void);
232 void mh_read_profile (void); 233 void mh_read_profile (void);
233 int mh_read_formfile (char *name, char **pformat); 234 int mh_read_formfile (char const *name, char **pformat);
234 mu_message_t mh_file_to_message (const char *folder, const char *file_name); 235 mu_message_t mh_file_to_message (const char *folder, const char *file_name);
235 mu_message_t mh_stream_to_message (mu_stream_t stream); 236 mu_message_t mh_stream_to_message (mu_stream_t stream);
236 void mh_install (char *name, int automode); 237 void mh_install (char *name, int automode);
...@@ -342,7 +343,7 @@ void mh_set_reply_regex (const char *str); ...@@ -342,7 +343,7 @@ void mh_set_reply_regex (const char *str);
342 int mh_decode_2047 (char *text, char **decoded_text); 343 int mh_decode_2047 (char *text, char **decoded_text);
343 const char *mh_charset (const char *); 344 const char *mh_charset (const char *);
344 345
345 int mh_alias_read (char *name, int fail); 346 int mh_alias_read (char const *name, int fail);
346 int mh_alias_get (const char *name, mu_list_t *return_list); 347 int mh_alias_get (const char *name, mu_list_t *return_list);
347 int mh_alias_get_address (const char *name, mu_address_t *addr, int *incl); 348 int mh_alias_get_address (const char *name, mu_address_t *addr, int *incl);
348 int mh_alias_get_alias (const char *uname, mu_list_t *return_list); 349 int mh_alias_get_alias (const char *uname, mu_list_t *return_list);
......
...@@ -419,7 +419,7 @@ yywrap () ...@@ -419,7 +419,7 @@ yywrap ()
419 419
420 /* Parses the named alias file */ 420 /* Parses the named alias file */
421 int 421 int
422 mh_alias_read (char *name, int fail) 422 mh_alias_read (char const *name, int fail)
423 { 423 {
424 extern int yydebug; 424 extern int yydebug;
425 char *p = getenv("ALI_YYDEBUG"); 425 char *p = getenv("ALI_YYDEBUG");
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2002, 2005-2007, 2009-2012, 2014-2016 Free
3 Software Foundation, Inc.
4
5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9
10 GNU Mailutils is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17
18 /* Coexistence between GNU long options, traditional UNIX-style short
19 options and traditional MH long options. */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <mh.h>
26 #include <string.h>
27 #include <mailutils/argcv.h>
28 #include "argp.h"
29 #ifdef MU_ALPHA_RELEASE
30 # include <git-describe.h>
31 #endif
32
33 static error_t
34 parse_opt (int key, char *arg, struct argp_state *state)
35 {
36 struct mh_argp_data *data = state->input;
37 error_t ret = ARGP_ERR_UNKNOWN;
38
39 switch (key)
40 {
41 case ARGP_KEY_ARG:
42 if (arg[0] == '+')
43 ret = data->handler (ARG_FOLDER, arg + 1, state);
44 break;
45
46 default:
47 ret = data->handler (key, arg, state);
48 if (ret == 0)
49 {
50 if (key == ARGP_KEY_ERROR)
51 data->errind = state->next;
52 }
53 }
54
55 return ret;
56 }
57
58 static int
59 my_argp_parse (struct argp *argp, int argc, char **argv, int flags,
60 int *end_index, struct mh_argp_data *data)
61 {
62 int rc;
63 int f = 0;
64 int index = 0;
65
66 if (flags & ARGP_NO_ERRS)
67 {
68 while (argc > 0
69 && (rc = argp_parse (argp, argc, argv, flags|f, end_index, data))
70 == EINVAL)
71 {
72 if (data->errind == -1)
73 break;
74 data->errind--;
75 if (f)
76 data->errind--;
77 argc -= data->errind;
78 argv += data->errind;
79 index += data->errind;
80 if (argc < 2 || memcmp (argv[1], "--", 2))
81 {
82 if (end_index)
83 *end_index = index + 1;
84 break;
85 }
86 f = ARGP_PARSE_ARGV0;
87 }
88 if (rc == 0 && end_index)
89 *end_index += index;
90 rc = 0;
91 }
92 else
93 rc = argp_parse (argp, argc, argv, flags, end_index, data);
94 return rc;
95 }
96
97 const char version_etc_copyright[] =
98 /* Do *not* mark this string for translation. %s is a copyright
99 symbol suitable for this locale, and %d is the copyright
100 year. */
101 "Copyright %s 2010 Free Software Foundation, inc.";
102
103 /* This is almost the same as mu_program_version_hook from muinit.c,
104 except for different formatting of the first line. MH uses:
105
106 progname (GNU Mailutils X.Y.Z)
107
108 where X.Y.Z stands for the version number. Emacs MH-E uses this
109 to determine Mailutils presence and its version number (see
110 lisp/mh-e/mh-e.el, function mh-variant-mu-mh-info). */
111 static void
112 mh_program_version_hook (FILE *stream, struct argp_state *state)
113 {
114 #ifdef GIT_DESCRIBE
115 fprintf (stream, "%s (%s %s) [%s]\n",
116 mu_program_name, PACKAGE_NAME, PACKAGE_VERSION, GIT_DESCRIBE);
117 #else
118 fprintf (stream, "%s (%s %s)\n", mu_program_name,
119 PACKAGE_NAME, PACKAGE_VERSION);
120 #endif
121 /* TRANSLATORS: Translate "(C)" to the copyright symbol
122 (C-in-a-circle), if this symbol is available in the user's
123 locale. Otherwise, do not translate "(C)"; leave it as-is. */
124 fprintf (stream, version_etc_copyright, _("(C)"));
125
126 fputs (_("\
127 \n\
128 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\n\
129 There is NO WARRANTY, to the extent permitted by law.\n\
130 \n\
131 "),
132 stream);
133 }
134
135 void
136 mh_argp_init ()
137 {
138 argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
139 argp_program_version_hook = mh_program_version_hook;
140 }
141
142
143 enum
144 {
145 OPT_DEBUG_LEVEL = 256,
146 OPT_DEBUG_LINE_INFO,
147 };
148
149 static struct argp_option mu_debug_argp_options[] =
150 {
151 { "debug-level", OPT_DEBUG_LEVEL, N_("LEVEL"), 0,
152 N_("set Mailutils debugging level"), 0 },
153 { "debug-line-info", OPT_DEBUG_LINE_INFO, NULL, 0,
154 N_("show source info with debugging messages"), 0 },
155 { NULL }
156 };
157
158 static error_t
159 mu_debug_argp_parser (int key, char *arg, struct argp_state *state)
160 {
161 switch (key)
162 {
163 case OPT_DEBUG_LEVEL:
164 mu_debug_parse_spec (arg);
165 break;
166
167 case OPT_DEBUG_LINE_INFO:
168 mu_debug_line_info = 1;
169 break;
170
171 default:
172 return ARGP_ERR_UNKNOWN;
173 }
174 return 0;
175 }
176
177 struct argp mu_debug_argp = {
178 mu_debug_argp_options,
179 mu_debug_argp_parser,
180 };
181
182 struct argp_child mh_argp_children[] = {
183 { &mu_debug_argp, 0, N_("Global debugging settings"), -2 },
184 { NULL }
185 };
186
187 int
188 mh_argp_parse (int *pargc, char **pargv[],
189 int flags,
190 struct argp_option *option,
191 struct mh_option *mh_option,
192 char *argp_doc, char *doc,
193 argp_parser_t handler,
194 void *closure, int *pindex)
195 {
196 struct argp argp;
197 struct mh_argp_data data;
198 const char *val;
199 int index;
200 int extra = 0;
201
202 mu_set_program_name ((*pargv)[0]);
203 mh_init ();
204
205 mh_option_init (mh_option);
206 memset (&argp, 0, sizeof (argp));
207 argp.options = option;
208 argp.parser = parse_opt;
209 argp.args_doc = argp_doc;
210 argp.doc = doc;
211 argp.children = mh_argp_children;
212 data.mh_option = mh_option;
213 data.closure = closure;
214 data.handler = handler;
215 data.doc = argp_doc;
216 data.errind = -1;
217
218 val = mh_global_profile_get (mu_program_name, NULL);
219 if (val)
220 {
221 int argc;
222 char **argv;
223 int i, j;
224 struct mu_wordsplit ws;
225
226 if (mu_wordsplit (val, &ws, MU_WRDSF_DEFFLAGS))
227 {
228 mu_error (_("cannot split line `%s': %s"), val,
229 mu_wordsplit_strerror (&ws));
230 exit (1);
231 }
232
233 argc = *pargc + ws.ws_wordc;
234 argv = calloc (argc + 1, sizeof *argv);
235 if (!argv)
236 mh_err_memory (1);
237
238 i = 0;
239 argv[i++] = (*pargv)[0];
240 for (j = 0; j < ws.ws_wordc; i++, j++)
241 argv[i] = ws.ws_wordv[j];
242 for (j = 1; i < argc; i++, j++)
243 argv[i] = (*pargv)[j];
244 argv[i] = NULL;
245
246 ws.ws_wordc = 0;
247 mu_wordsplit_free (&ws);
248
249 mh_argv_preproc (argc, argv, &data);
250
251 my_argp_parse (&argp, argc, argv, flags, &index, &data);
252
253 extra = index < argc;
254
255 *pargc = argc;
256 *pargv = argv;
257 }
258 else
259 {
260 mh_argv_preproc (*pargc, *pargv, &data);
261 my_argp_parse (&argp, *pargc, *pargv, flags, &index, &data);
262 extra = index < *pargc;
263 }
264 if (pindex)
265 *pindex = index;
266 else if (extra)
267 {
268 mu_error (_("Extra arguments"));
269 exit (1);
270 }
271 mh_init2 ();
272 return 0;
273 }
274
275 void
276 mh_license (const char *name)
277 {
278 printf (_("This is %s\n\n"), name);
279 printf (
280 _(" GNU Mailutils is free software; you can redistribute it and/or modify\n"
281 " it under the terms of the GNU General Public License as published by\n"
282 " the Free Software Foundation; either version 3 of the License, or\n"
283 " (at your option) any later version.\n"
284 "\n"
285 " GNU Mailutils is distributed in the hope that it will be useful,\n"
286 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
287 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
288 " GNU General Public License for more details.\n"
289 "\n"
290 " You should have received a copy of the GNU General Public License along\n"
291 " with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.\n"
292 "\n"
293 "\n"
294 ));
295
296 exit (0);
297 }
298
...@@ -20,11 +20,10 @@ ...@@ -20,11 +20,10 @@
20 #include <mh.h> 20 #include <mh.h>
21 #include <mh_format.h> 21 #include <mh_format.h>
22 #include <mailutils/mime.h> 22 #include <mailutils/mime.h>
23 #include <mailutils/opool.h>
23 24
24 #ifdef HAVE_STRINGS_H
25 # include <strings.h>
26 #endif
27 #include <string.h> 25 #include <string.h>
26 #include <ctype.h>
28 #include "mbiter.h" 27 #include "mbiter.h"
29 #include "mbchar.h" 28 #include "mbchar.h"
30 #include "mbswidth.h" 29 #include "mbswidth.h"
......
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
15 You should have received a copy of the GNU General Public License 15 You should have received a copy of the GNU General Public License
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ 16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17 17
18 /* Parse traditional MH options. */
19
20 #ifdef HAVE_CONFIG_H 18 #ifdef HAVE_CONFIG_H
21 # include <config.h> 19 # include <config.h>
22 #endif 20 #endif
...@@ -24,197 +22,224 @@ ...@@ -24,197 +22,224 @@
24 #include <stdio.h> 22 #include <stdio.h>
25 #include <stdlib.h> 23 #include <stdlib.h>
26 #include <string.h> 24 #include <string.h>
27 #include <mh_getopt.h> 25 #include "mh.h"
26 #include <mailutils/stream.h>
27 #include <mailutils/wordsplit.h>
28 #include <mailutils/io.h> 28 #include <mailutils/io.h>
29 29
30 static int mh_optind = 1; 30 struct getopt_data
31 static char *mh_optarg; 31 {
32 static char *mh_optptr; 32 char *extra_doc;
33 33 };
34 void (*mh_help_hook) ();
35 34
36 int 35 static void
37 mh_getopt (int argc, char **argv, struct mh_option *mh_opt, const char *doc) 36 mh_extra_help_hook (struct mu_parseopt *po, mu_stream_t stream)
38 { 37 {
39 struct mh_option *p; 38 struct getopt_data *data = po->po_data;
40 int optlen; 39 mu_stream_printf (stream, "%s\n", _(data->extra_doc));
41 40 }
42 if (mh_optind >= argc || argv[mh_optind] == NULL)
43 return EOF;
44 mh_optptr = argv[mh_optind];
45 41
46 if (mh_optptr[0] == '+') 42 static void
43 augment_argv (int *pargc, char ***pargv)
44 {
45 int argc;
46 char **argv;
47 int i, j;
48 struct mu_wordsplit ws;
49 char const *val = mh_global_profile_get (mu_program_name, NULL);
50
51 if (!val)
52 return;
53
54 if (mu_wordsplit (val, &ws, MU_WRDSF_DEFFLAGS))
47 { 55 {
48 mh_optarg = mh_optptr + 1; 56 mu_error (_("cannot split line `%s': %s"), val,
49 mh_optind++; 57 mu_wordsplit_strerror (&ws));
50 return '+'; 58 exit (1);
51 } 59 }
60
61 argc = *pargc + ws.ws_wordc;
62 argv = calloc (argc + 1, sizeof *argv);
63 if (!argv)
64 mh_err_memory (1);
65
66 i = 0;
67 argv[i++] = (*pargv)[0];
68 for (j = 0; j < ws.ws_wordc; i++, j++)
69 argv[i] = ws.ws_wordv[j];
70 for (j = 1; i < argc; i++, j++)
71 argv[i] = (*pargv)[j];
72 argv[i] = NULL;
52 73
53 if (mh_optptr[0] != '-' || mh_optptr[1] == '-') 74 ws.ws_wordc = 0;
75 mu_wordsplit_free (&ws);
76
77 *pargc = argc;
78 *pargv = argv;
79 }
80
81 static void
82 process_folder_arg (int *pargc, char **argv, struct mu_parseopt *po)
83 {
84 int i, j;
85 int argc = *pargc;
86 struct mu_option *opt;
87
88 /* Find folder option */
89 for (i = 0; ; i++)
54 { 90 {
55 mh_optind++; 91 if (!po->po_optv[i])
56 return 0; 92 return; /* Nothing to do */
93 if (MU_OPTION_IS_VALID_LONG_OPTION (po->po_optv[i])
94 && strcmp (po->po_optv[i]->opt_long, "folder") == 0)
95 break;
57 } 96 }
58 97 opt = po->po_optv[i];
59 if (strcmp (mh_optptr, "-version") == 0) 98
60 mu_asprintf (&argv[mh_optind], "--version"); 99 for (i = j = 0; i < argc; i++)
61 else
62 { 100 {
63 int negation = 0; 101 if (argv[i][0] == '+')
64
65 optlen = strlen (mh_optptr+1);
66 for (p = mh_opt; p->opt; p++)
67 { 102 {
68 if (p->match_len <= optlen 103 opt->opt_set (po, opt, argv[i] + 1);
69 && memcmp (mh_optptr+1, p->opt, optlen) == 0)
70 break;
71 if (p->flags == MH_OPT_BOOL
72 && optlen > 2
73 && memcmp (mh_optptr+1, "no", 2) == 0
74 && strlen (p->opt) >= optlen-2
75 && memcmp (mh_optptr+3, p->opt, optlen-2) == 0)
76 {
77 negation = 1;
78 break;
79 }
80 }
81
82 if (p->opt)
83 {
84 char *longopt = p->opt;
85 switch (p->flags)
86 {
87 case MH_OPT_BOOL:
88 mh_optarg = negation ? "no" : "yes";
89 mu_asprintf (&argv[mh_optind], "--%s=%s", longopt, mh_optarg);
90 break;
91
92 case MH_OPT_ARG:
93 mu_asprintf (&argv[mh_optind], "--%s", longopt);
94 mh_optarg = argv[++mh_optind];
95 break;
96
97 default:
98 mu_asprintf (&argv[mh_optind], "--%s", longopt);
99 mh_optarg = NULL;
100 }
101 mh_optind++;
102 return 1;
103 }
104 else if (!strcmp (mh_optptr+1, "help"))
105 {
106 mh_help (mh_opt, doc);
107 exit (1);
108 } 104 }
109 else 105 else
110 mh_optind++; 106 argv[j++] = argv[i];
111 } 107 }
112 return '?'; 108 argv[j] = NULL;
109 *pargc = j;
113 } 110 }
114 111
115 void 112 static void
116 mh_argv_preproc (int argc, char **argv, struct mh_argp_data *data) 113 set_folder (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
117 { 114 {
118 mh_optind = 1; 115 mh_set_current_folder (arg);
119 while (mh_getopt (argc, argv, data->mh_option, data->doc) != EOF)
120 ;
121 } 116 }
122 117
118 static struct mu_option folder_option[] = {
119 { "folder", 0, NULL, MU_OPTION_DEFAULT,
120 N_("set current folder"),
121 mu_c_string, NULL, set_folder },
122 MU_OPTION_END
123 };
124
123 void 125 void
124 mh_help (struct mh_option *mh_opt, const char *doc) 126 mh_getopt (int *pargc, char ***pargv, struct mu_option *options,
127 int mhflags,
128 char *argdoc, char *progdoc, char *extradoc)
125 { 129 {
126 struct mh_option *p; 130 int argc = *pargc;
131 char **argv = *pargv;
132 struct mu_parseopt po;
133 struct mu_option *optv[3];
134 struct getopt_data getopt_data;
135 char const *args[2];
136 int flags = MU_PARSEOPT_SINGLE_DASH | MU_PARSEOPT_IMMEDIATE;
137 int i;
138
139 po.po_negation = "no";
140 flags |= MU_PARSEOPT_NEGATION;
127 141
128 printf (_("Compatibility syntax:\n")); 142 if (argdoc)
129 printf (_("%s [switches] %s\n"), mu_program_name, doc); 143 {
130 printf (_(" switches are:\n")); 144 args[0] = argdoc;
145 args[1] = NULL;
146 po.po_prog_args = args;
147 flags |= MU_PARSEOPT_PROG_ARGS;
148 }
149 if (progdoc)
150 {
151 po.po_prog_doc = progdoc;
152 flags |= MU_PARSEOPT_PROG_DOC;
153 }
154
155 getopt_data.extra_doc = extradoc;
156 if (extradoc)
157 {
158 po.po_help_hook = mh_extra_help_hook;
159 flags |= MU_PARSEOPT_HELP_HOOK;
160 }
161
162 po.po_data = &getopt_data;
163 flags |= MU_PARSEOPT_DATA;
131 164
132 for (p = mh_opt; p->opt; p++) 165 po.po_exit_error = 1;
166 flags |= MU_PARSEOPT_EXIT_ERROR;
167
168 po.po_package_name = PACKAGE_NAME;
169 flags |= MU_PARSEOPT_PACKAGE_NAME;
170
171 po.po_package_url = PACKAGE_URL;
172 flags |= MU_PARSEOPT_PACKAGE_URL;
173
174 po.po_bug_address = PACKAGE_BUGREPORT;
175 flags |= MU_PARSEOPT_BUG_ADDRESS;
176
177 //po.po_extra_info = gnu_general_help_url;
178 //flags |= MU_PARSEOPT_EXTRA_INFO;
179
180 mu_set_program_name (argv[0]);
181 mh_init ();
182 augment_argv (&argc, &argv);
183
184 i = 0;
185 if (mhflags & MH_GETOPT_DEFAULT_FOLDER)
186 optv[i++] = folder_option;
187 optv[i++] = options;
188 optv[i] = NULL;
189
190 if (mu_parseopt (&po, argc, argv, optv, flags))
191 exit (po.po_exit_error);
192
193 argc -= po.po_arg_start;
194 argv += po.po_arg_start;
195
196 process_folder_arg (&argc, argv, &po);
197
198 if (!argdoc && argc)
133 { 199 {
134 int len = strlen (p->opt); 200 mu_error (_("Extra arguments"));
135 201 exit (1);
136 printf (" -");
137 if (p->flags == MH_OPT_BOOL)
138 printf ("[no]");
139 if (len > p->match_len)
140 printf ("(%*.*s)%s",
141 (int) p->match_len, (int) p->match_len, p->opt,
142 p->opt + p->match_len);
143 else
144 printf ("%s", p->opt);
145
146 if (p->flags == MH_OPT_ARG)
147 printf (" %s", p->arg);
148 printf ("\n");
149 } 202 }
150 if (mh_help_hook) 203
151 mh_help_hook (); 204 *pargc = argc;
152 printf (" -help\n"); 205 *pargv = argv;
153 printf (" -version\n"); 206
154 printf (_("\nPlease use GNU long options instead.\n" 207 mh_init2 ();
155 "Run %s --help for more info on these.\n"),
156 mu_program_name);
157 } 208 }
158 209
159 210 void
160 static int 211 mh_opt_notimpl (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
161 optcmp (const void *a, const void *b)
162 { 212 {
163 struct mh_option const *opta = a, *optb = b; 213 mu_error (_("option is not yet implemented: %s"), opt->opt_long);
164 return strcmp (opta->opt, optb->opt); 214 exit (1);
165 } 215 }
166 216
167 void 217 void
168 mh_option_init (struct mh_option *opt) 218 mh_opt_notimpl_warning (struct mu_parseopt *po, struct mu_option *opt,
219 char const *arg)
169 { 220 {
170 size_t count, i; 221 mu_error (_("ignoring not implemented option %s"), opt->opt_long);
171
172 /* Count number of elements and initialize minimum abbreviation
173 lengths to 1. */
174 for (count = 0; opt[count].opt; count++)
175 opt[count].match_len = 1;
176 /* Sort them alphabetically */
177 qsort (opt, count, sizeof (opt[0]), optcmp);
178 /* Determine minimum abbreviations */
179 for (i = 0; i < count; i++)
180 {
181 const char *sample = opt[i].opt;
182 size_t sample_len = strlen (sample);
183 size_t minlen = opt[i].match_len;
184 size_t j;
185
186 for (j = i + 1; j < count; j++)
187 {
188 size_t len = strlen (opt[j].opt);
189 if (len >= minlen && memcmp (opt[j].opt, sample, minlen) == 0)
190 do
191 {
192 minlen++;
193 if (minlen <= strlen (opt[j].opt))
194 opt[j].match_len = minlen;
195 if (minlen == sample_len)
196 break;
197 }
198 while (len >= minlen && memcmp (opt[j].opt, sample, minlen) == 0);
199 else if (opt[j].opt[0] == sample[0])
200 opt[j].match_len = minlen;
201 else
202 break;
203 }
204 if (minlen <= sample_len)
205 opt[i].match_len = minlen;
206 }
207 } 222 }
208 223
209 void 224 void
210 mh_opt_notimpl (const char *name) 225 mh_opt_clear_string (struct mu_parseopt *po, struct mu_option *opt,
226 char const *arg)
211 { 227 {
212 mu_error (_("option is not yet implemented: %s"), name); 228 char **sptr = opt->opt_ptr;
213 exit (1); 229 free (*sptr);
230 *sptr = NULL;
231 }
232
233 void
234 mh_opt_find_file (struct mu_parseopt *po, struct mu_option *opt,
235 char const *arg)
236 {
237 mh_find_file (arg, opt->opt_ptr);
214 } 238 }
215 239
216 void 240 void
217 mh_opt_notimpl_warning (const char *name) 241 mh_opt_read_formfile (struct mu_parseopt *po, struct mu_option *opt,
242 char const *arg)
218 { 243 {
219 mu_error (_("ignoring not implemented option %s"), name); 244 mh_read_formfile (arg, opt->opt_ptr);
220 } 245 }
......
...@@ -16,198 +16,24 @@ ...@@ -16,198 +16,24 @@
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ 16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17 17
18 #include <mailutils/nls.h> 18 #include <mailutils/nls.h>
19 #include "argp.h" 19 #include <mailutils/opt.h>
20 #include "mailutils/libargp.h"
21 20
22 #define MH_OPT_BOOL 1 21 #define MH_GETOPT_DEFAULT_FOLDER 0x1
23 #define MH_OPT_ARG 2
24 22
25 struct mh_option 23 void mh_getopt (int *pargc, char ***pargv, struct mu_option *options,
26 { 24 int flags,
27 char *opt; 25 char *argdoc, char *progdoc, char *extradoc);
28 int flags;
29 char *arg;
30 size_t match_len;
31 };
32 26
33 struct mh_argp_data 27 void mh_opt_notimpl (struct mu_parseopt *po, struct mu_option *opt,
34 { 28 char const *arg);
35 struct mh_option *mh_option; 29 void mh_opt_notimpl_warning (struct mu_parseopt *po, struct mu_option *opt,
36 argp_parser_t handler; 30 char const *arg);
37 int errind; 31 void mh_opt_clear_string (struct mu_parseopt *po, struct mu_option *opt,
38 void *closure; 32 char const *arg);
39 char *doc;
40 };
41 33
42 enum mh_arg { 34 void mh_opt_find_file (struct mu_parseopt *po, struct mu_option *opt,
43 ARG_ADD = 256, 35 char const *arg);
44 ARG_AFTER, 36 void mh_opt_read_formfile (struct mu_parseopt *po, struct mu_option *opt,
45 ARG_ALIAS, 37 char const *arg);
46 ARG_ALL,
47 ARG_AND,
48 ARG_ANNOTATE,
49 ARG_APOP,
50 ARG_AUDIT,
51 ARG_AUTO,
52 ARG_BEFORE,
53 ARG_BELL,
54 ARG_BUILD,
55 ARG_CC,
56 ARG_CFLAGS,
57 ARG_CHANGECUR,
58 ARG_CHARSET,
59 ARG_CHECK,
60 ARG_CHUNKSIZE,
61 ARG_CLEAR,
62 ARG_COMPAT,
63 ARG_COMPONENT,
64 ARG_COMPOSE,
65 ARG_CREATE,
66 ARG_DATE,
67 ARG_DATEFIELD,
68 ARG_DEBUG,
69 ARG_DELETE,
70 ARG_DRAFT,
71 ARG_DRAFTFOLDER,
72 ARG_DRAFTMESSAGE,
73 ARG_DRY_RUN,
74 ARG_DUMP,
75 ARG_EDITOR,
76 ARG_FAST,
77 ARG_FCC,
78 ARG_FILE,
79 ARG_FILTER,
80 ARG_FOLDER,
81 ARG_FORM,
82 ARG_FORMAT,
83 ARG_FORWARD,
84 ARG_FROM,
85 ARG_GROUP,
86 ARG_HEADER,
87 ARG_HOST,
88 ARG_INPLACE,
89 ARG_INTERACTIVE,
90 ARG_LANG,
91 ARG_LBRACE,
92 ARG_LENGTH,
93 ARG_LIMIT,
94 ARG_LINK,
95 ARG_LIST,
96 ARG_MIME,
97 ARG_MOREPROC,
98 ARG_MOVETO,
99 ARG_MSGID,
100 ARG_NOALIAS,
101 ARG_NOAPOP,
102 ARG_NOAUDIT,
103 ARG_NOAUTO,
104 ARG_NOBELL,
105 ARG_NOCC,
106 ARG_NOCHANGECUR,
107 ARG_NOCHECK,
108 ARG_NOCLEAR,
109 ARG_NOCOMPOSE,
110 ARG_NOCREATE,
111 ARG_NODATE,
112 ARG_NODATEFIELD,
113 ARG_NODRAFTFOLDER,
114 ARG_NOEDIT,
115 ARG_NOFAST,
116 ARG_NOFILTER,
117 ARG_NOFORMAT,
118 ARG_NOFORWARD,
119 ARG_NOHEADER,
120 ARG_NOHEADERS,
121 ARG_NOINPLACE,
122 ARG_NOINTERACTIVE,
123 ARG_NOLIMIT,
124 ARG_NOLIST,
125 ARG_NOMIME,
126 ARG_NOMOREPROC,
127 ARG_NOMSGID,
128 ARG_NONOTIFY,
129 ARG_NOPAUSE,
130 ARG_NOPUBLIC,
131 ARG_NOPUSH,
132 ARG_NOQUIET,
133 ARG_NOREALSIZE,
134 ARG_NORECURSIVE,
135 ARG_NOREVERSE,
136 ARG_NORMALIZE,
137 ARG_NOSERIALONLY,
138 ARG_NOSHOW,
139 ARG_NOSHOWPROC,
140 ARG_NOSTORE,
141 ARG_NOT,
142 ARG_NOTEXTFIELD,
143 ARG_NOTIFY,
144 ARG_NOTOTAL,
145 ARG_NOTRUNCATE,
146 ARG_NOUSE,
147 ARG_NOVERBOSE,
148 ARG_NOWATCH,
149 ARG_NOWHATNOWPROC,
150 ARG_NOZERO,
151 ARG_NUMFIELD,
152 ARG_OR,
153 ARG_PACK,
154 ARG_PART,
155 ARG_PATTERN,
156 ARG_PAUSE,
157 ARG_POP,
158 ARG_PRESERVE,
159 ARG_PRINT,
160 ARG_PROMPT,
161 ARG_PUBLIC,
162 ARG_PUSH,
163 ARG_QUERY,
164 ARG_QUIET,
165 ARG_RBRACE,
166 ARG_REALSIZE,
167 ARG_RECURSIVE,
168 ARG_REORDER,
169 ARG_REVERSE,
170 ARG_SCRIPT,
171 ARG_SEQUENCE,
172 ARG_SERIALONLY,
173 ARG_SHOW,
174 ARG_SHOWPROC,
175 ARG_SOURCE,
176 ARG_SPLIT,
177 ARG_STORE,
178 ARG_SUBJECT,
179 ARG_TEXT,
180 ARG_TEXTFIELD,
181 ARG_TO,
182 ARG_TOTAL,
183 ARG_TRUNCATE,
184 ARG_TYPE,
185 ARG_USE,
186 ARG_USER,
187 ARG_VERBOSE,
188 ARG_WATCH,
189 ARG_WHATNOWPROC,
190 ARG_WIDTH,
191 ARG_ZERO
192 };
193 38
194 extern void (*mh_help_hook) (void);
195 39
196 void mh_option_init (struct mh_option *opt);
197
198 void mh_argp_init (void);
199 void mh_argv_preproc (int argc, char **argv, struct mh_argp_data *data);
200 int mh_getopt (int argc, char **argv, struct mh_option *mh_opt, const char *doc);
201 int mh_argp_parse (int *argc, char **argv[],
202 int flags,
203 struct argp_option *option,
204 struct mh_option *mh_option,
205 char *argp_doc, char *doc,
206 argp_parser_t handler,
207 void *closure, int *index);
208
209 void mh_help (struct mh_option *mh_option, const char *doc);
210 void mh_license (const char *name);
211
212 void mh_opt_notimpl (const char *name);
213 void mh_opt_notimpl_warning (const char *name);
......
...@@ -59,7 +59,7 @@ mh_init2 () ...@@ -59,7 +59,7 @@ mh_init2 ()
59 } 59 }
60 60
61 int 61 int
62 mh_read_formfile (char *name, char **pformat) 62 mh_read_formfile (char const *name, char **pformat)
63 { 63 {
64 FILE *fp; 64 FILE *fp;
65 struct stat st; 65 struct stat st;
......
...@@ -21,48 +21,15 @@ ...@@ -21,48 +21,15 @@
21 #include <sys/stat.h> 21 #include <sys/stat.h>
22 #include <unistd.h> 22 #include <unistd.h>
23 23
24 static char doc[] = N_("GNU MH mhl")"\v" 24 static char prog_doc[] = N_("GNU MH mhl");
25 N_("Use -help to obtain the list of traditional MH options.");
26 static char args_doc[] = N_("[FILE [FILE...]]"); 25 static char args_doc[] = N_("[FILE [FILE...]]");
27 26
28 /* GNU options */ 27 static int bell_option;
29 static struct argp_option options[] = { 28 static int clear_option;
30 {"folder", ARG_FOLDER, N_("FOLDER"), 0,
31 N_("specify folder to operate upon")},
32 { "bell", ARG_BELL, N_("BOOL"), OPTION_ARG_OPTIONAL,
33 N_("ring the bell at the end of each output page") },
34 {"nobell", ARG_NOBELL, NULL, OPTION_HIDDEN, "" },
35 { "clear", ARG_CLEAR, N_("BOOL"), OPTION_ARG_OPTIONAL,
36 N_("clear the screen after each page of output")},
37 {"noclear", ARG_NOCLEAR, NULL, OPTION_HIDDEN, "" },
38 {"form", ARG_FORM, N_("FILE"), 0,
39 N_("read format from given file")},
40 {"width", ARG_WIDTH, N_("NUMBER"), 0,
41 N_("set output width")},
42 {"length", ARG_LENGTH, N_("NUMBER"), 0,
43 N_("set output screen length")},
44 {"moreproc", ARG_MOREPROC, N_("PROG"), 0,
45 N_("use given PROG instead of the default") },
46 {"nomoreproc", ARG_NOMOREPROC, NULL, 0,
47 N_("disable use of moreproc program") },
48 { NULL }
49 };
50
51 /* Traditional MH options */
52 struct mh_option mh_option[] = {
53 { "bell", MH_OPT_BOOL },
54 { "clear", MH_OPT_BOOL },
55 { "form", MH_OPT_ARG, "formatfile"},
56 { "width", MH_OPT_ARG, "number"},
57 { "length", MH_OPT_ARG, "number"},
58 { "moreproc", MH_OPT_ARG, "program"},
59 { "nomoreproc" },
60 { NULL }
61 };
62 29
63 static int interactive; /* Using interactive output */ 30 static int interactive; /* Using interactive output */
64 static int mhl_fmt_flags; /* MHL format flags. Controlled by --bell 31 static int mhl_fmt_flags; /* MHL format flags. Controlled by -bell
65 and --clear */ 32 and -clear */
66 static int length = 40; /* Length of output page */ 33 static int length = 40; /* Length of output page */
67 static int width = 80; /* Width of output page */ 34 static int width = 80; /* Width of output page */
68 static char *formfile = MHLIBDIR "/mhl.format"; 35 static char *formfile = MHLIBDIR "/mhl.format";
...@@ -71,69 +38,31 @@ static int nomoreproc; ...@@ -71,69 +38,31 @@ static int nomoreproc;
71 38
72 static mu_list_t format; 39 static mu_list_t format;
73 40
74 static error_t 41 static struct mu_option options[] = {
75 opt_handler (int key, char *arg, struct argp_state *state) 42 { "bell", 0, NULL, MU_OPTION_DEFAULT,
76 { 43 N_("ring the bell at the end of each output page"),
77 switch (key) 44 mu_c_bool, &bell_option },
78 { 45 { "clear", 0, NULL, MU_OPTION_DEFAULT,
79 case ARG_FOLDER: 46 N_("clear the screen after each page of output"),
80 mh_set_current_folder (arg); 47 mu_c_bool, &clear_option },
81 break; 48 { "form", 0, N_("FILE"), MU_OPTION_DEFAULT,
82 49 N_("read format from given file"),
83 case ARG_BELL: 50 mu_c_string, &formfile, mh_opt_find_file },
84 if (is_true (arg)) 51 { "width", 0, N_("NUMBER"), MU_OPTION_DEFAULT,
85 mhl_fmt_flags |= MHL_BELL; 52 N_("set output width"),
86 break; 53 mu_c_int, &width },
87 54 { "length", 0, N_("NUMBER"), MU_OPTION_DEFAULT,
88 case ARG_NOBELL: 55 N_("set output screen length"),
89 mhl_fmt_flags &= ~MHL_BELL; 56 mu_c_int, &length },
90 break; 57 { "moreproc", 0, N_("PROG"), MU_OPTION_DEFAULT,
91 58 N_("use given PROG instead of the default"),
92 case ARG_CLEAR: 59 mu_c_string, &moreproc },
93 if (is_true (arg)) 60 { "nomoreproc", 0, NULL, MU_OPTION_DEFAULT,
94 mhl_fmt_flags |= MHL_CLEARSCREEN; 61 N_("disable use of moreproc program"),
95 break; 62 mu_c_bool, &nomoreproc },
96 63 MU_OPTION_END
97 case ARG_NOCLEAR: 64 };
98 mhl_fmt_flags &= ~MHL_CLEARSCREEN; 65
99 break;
100
101 case ARG_FORM:
102 mh_find_file (arg, &formfile);
103 break;
104
105 case ARG_WIDTH:
106 width = strtoul (arg, NULL, 0);
107 if (!width)
108 {
109 argp_error (state, _("invalid width"));
110 exit (1);
111 }
112 break;
113
114 case ARG_LENGTH:
115 length = strtoul (arg, NULL, 0);
116 if (!length)
117 {
118 argp_error (state, _("invalid length"));
119 exit (1);
120 }
121 break;
122
123 case ARG_MOREPROC:
124 moreproc = arg;
125 break;
126
127 case ARG_NOMOREPROC:
128 nomoreproc = 1;
129 break;
130
131 default:
132 return ARGP_ERR_UNKNOWN;
133 }
134 return 0;
135 }
136
137 static mu_stream_t 66 static mu_stream_t
138 open_output () 67 open_output ()
139 { 68 {
...@@ -205,23 +134,33 @@ list_message (char *name, mu_stream_t output) ...@@ -205,23 +134,33 @@ list_message (char *name, mu_stream_t output)
205 int 134 int
206 main (int argc, char **argv) 135 main (int argc, char **argv)
207 { 136 {
208 int index;
209 mu_stream_t output; 137 mu_stream_t output;
210 138
211 interactive = isatty (1) && isatty (0); 139 interactive = isatty (1) && isatty (0);
212 140
213 MU_APP_INIT_NLS (); 141 MU_APP_INIT_NLS ();
214 mh_argp_init ();
215 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
216 opt_handler, NULL, &index);
217 142
143 mh_getopt (&argc, &argv, options, MH_GETOPT_DEFAULT_FOLDER,
144 args_doc, prog_doc, NULL);
145
146 if (bell_option == -1)
147 /* use default */;
148 else if (bell_option)
149 mhl_fmt_flags |= MHL_BELL;
150 else
151 mhl_fmt_flags &= ~MHL_BELL;
152
153 if (clear_option == -1)
154 /* use default */;
155 else if (clear_option)
156 mhl_fmt_flags |= MHL_CLEARSCREEN;
157 else
158 mhl_fmt_flags &= ~MHL_CLEARSCREEN;
159
218 format = mhl_format_compile (formfile); 160 format = mhl_format_compile (formfile);
219 if (!format) 161 if (!format)
220 exit (1); 162 exit (1);
221 163
222 argc -= index;
223 argv += index;
224
225 if (argc == 0) 164 if (argc == 0)
226 nomoreproc = 1; 165 nomoreproc = 1;
227 166
......
...@@ -26,46 +26,9 @@ ...@@ -26,46 +26,9 @@
26 #include <time.h> 26 #include <time.h>
27 #include <mailutils/observer.h> 27 #include <mailutils/observer.h>
28 28
29 static char doc[] = N_("GNU MH scan")"\v" 29 static char progdoc[] = N_("GNU MH scan");
30 N_("Use -help to obtain the list of traditional MH options.");
31 static char args_doc[] = N_("[+FOLDER] [MSGLIST]"); 30 static char args_doc[] = N_("[+FOLDER] [MSGLIST]");
32 31
33 /* GNU options */
34 static struct argp_option options[] = {
35 {"folder", ARG_FOLDER, N_("FOLDER"), 0,
36 N_("specify folder to scan")},
37 {"clear", ARG_CLEAR, N_("BOOL"), OPTION_ARG_OPTIONAL,
38 N_("clear screen after displaying the list")},
39 {"noclear", ARG_NOCLEAR, NULL, OPTION_HIDDEN, ""},
40 {"form", ARG_FORM, N_("FILE"), 0,
41 N_("read format from given file")},
42 {"format", ARG_FORMAT, N_("FORMAT"), 0,
43 N_("use this format string")},
44 {"header", ARG_HEADER, N_("BOOL"), OPTION_ARG_OPTIONAL,
45 N_("display header")},
46 {"width", ARG_WIDTH, N_("NUMBER"), 0,
47 N_("set output width")},
48 {"reverse", ARG_REVERSE, N_("BOOL"), OPTION_ARG_OPTIONAL,
49 N_("list messages in reverse order")},
50 {"noreverse", ARG_NOREVERSE, NULL, OPTION_HIDDEN, ""},
51 {"file", ARG_FILE, N_("FILE"), 0,
52 N_("[not yet implemented]")},
53
54 { 0 }
55 };
56
57 /* Traditional MH options */
58 struct mh_option mh_option[] = {
59 { "clear", MH_OPT_BOOL },
60 { "form", MH_OPT_ARG, "formatfile" },
61 { "format", MH_OPT_ARG, "string" },
62 { "header", MH_OPT_BOOL },
63 { "width", MH_OPT_ARG, "number" },
64 { "reverse", MH_OPT_BOOL },
65 { "file", MH_OPT_ARG, "file" },
66 { NULL }
67 };
68
69 static int clear; 32 static int clear;
70 static char *format_str = mh_list_format; 33 static char *format_str = mh_list_format;
71 34
...@@ -77,66 +40,41 @@ static mh_format_t format; ...@@ -77,66 +40,41 @@ static mh_format_t format;
77 40
78 static mu_msgset_t msgset; 41 static mu_msgset_t msgset;
79 42
80 static int list_message (size_t num, mu_message_t msg, void *data); 43 static void
81 void print_header (mu_mailbox_t mbox); 44 form_handler (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
82 void clear_screen (void);
83
84 static error_t
85 opt_handler (int key, char *arg, struct argp_state *state)
86 { 45 {
87 switch (key) 46 if (mh_read_formfile (arg, &format_str))
88 { 47 exit (1);
89 case ARG_FOLDER: 48 }
90 mh_set_current_folder (arg);
91 break;
92
93 case ARG_CLEAR:
94 clear = is_true(arg);
95 break;
96 49
97 case ARG_NOCLEAR: 50 static struct mu_option options[] = {
98 clear = 0; 51 { "clear", 0, NULL, MU_OPTION_DEFAULT,
99 break; 52 N_("clear screen after displaying the list"),
100 53 mu_c_bool, &clear },
101 case ARG_FORM: 54 { "form", 0, N_("FILE"), MU_OPTION_DEFAULT,
102 if (mh_read_formfile (arg, &format_str)) 55 N_("read format from given file"),
103 exit (1); 56 mu_c_string, NULL, form_handler },
104 break; 57 { "format", 0, N_("FORMAT"), MU_OPTION_DEFAULT,
105 58 N_("use this format string"),
106 case ARG_FORMAT: 59 mu_c_string, &format_str },
107 format_str = arg; 60 { "header", 0, NULL, MU_OPTION_DEFAULT,
108 break; 61 N_("display header"),
109 62 mu_c_bool, &header },
110 case ARG_HEADER: 63 { "width", 0, N_("NUMBER"), MU_OPTION_DEFAULT,
111 header = is_true(arg); 64 N_("set output width"),
112 break; 65 mu_c_int, &width },
113 66 { "reverse", 0, NULL, MU_OPTION_DEFAULT,
114 case ARG_WIDTH: 67 N_("list messages in reverse order"),
115 width = strtoul (arg, NULL, 0); 68 mu_c_bool, &reverse },
116 if (!width) 69 { "file", 0, N_("FILE"), MU_OPTION_HIDDEN,
117 { 70 N_("[not yet implemented]"),
118 argp_error (state, _("invalid width")); 71 mu_c_string, NULL, mh_opt_notimpl },
119 exit (1); 72 MU_OPTION_END
120 } 73 };
121 break;
122
123 case ARG_REVERSE:
124 reverse = is_true(arg);
125 break;
126 74
127 case ARG_NOREVERSE: 75 static int list_message (size_t num, mu_message_t msg, void *data);
128 reverse = 0; 76 void print_header (mu_mailbox_t mbox);
129 break; 77 void clear_screen (void);
130
131 case ARG_FILE:
132 mh_opt_notimpl ("-file");
133 break;
134
135 default:
136 return ARGP_ERR_UNKNOWN;
137 }
138 return 0;
139 }
140 78
141 /* Observable Action this is called at every message discover. */ 79 /* Observable Action this is called at every message discover. */
142 static int 80 static int
...@@ -161,7 +99,6 @@ action (mu_observer_t o, size_t type, void *data, void *action_data) ...@@ -161,7 +99,6 @@ action (mu_observer_t o, size_t type, void *data, void *action_data)
161 int 99 int
162 main (int argc, char **argv) 100 main (int argc, char **argv)
163 { 101 {
164 int index;
165 mu_mailbox_t mbox; 102 mu_mailbox_t mbox;
166 int status; 103 int status;
167 size_t total = 0; 104 size_t total = 0;
...@@ -169,9 +106,8 @@ main (int argc, char **argv) ...@@ -169,9 +106,8 @@ main (int argc, char **argv)
169 /* Native Language Support */ 106 /* Native Language Support */
170 MU_APP_INIT_NLS (); 107 MU_APP_INIT_NLS ();
171 108
172 mh_argp_init (); 109 mh_getopt (&argc, &argv, options, MH_GETOPT_DEFAULT_FOLDER,
173 mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, 110 args_doc, progdoc, NULL);
174 opt_handler, NULL, &index);
175 111
176 if (mh_format_parse (format_str, &format)) 112 if (mh_format_parse (format_str, &format))
177 { 113 {
...@@ -181,8 +117,6 @@ main (int argc, char **argv) ...@@ -181,8 +117,6 @@ main (int argc, char **argv)
181 117
182 mbox = mh_open_folder (mh_current_folder (), MU_STREAM_READ); 118 mbox = mh_open_folder (mh_current_folder (), MU_STREAM_READ);
183 119
184 argc -= index;
185 argv += index;
186 if ((argc == 0 || strcmp (argv[0], "all") == 0) && !reverse) 120 if ((argc == 0 || strcmp (argv[0], "all") == 0) && !reverse)
187 { 121 {
188 /* Fast approach */ 122 /* Fast approach */
......
...@@ -90,7 +90,7 @@ Regards, ...@@ -90,7 +90,7 @@ Regards,
90 Sergey 90 Sergey
91 ]) 91 ])
92 92
93 burst +inbox --length=7 1 || exit $? 93 burst +inbox -length 7 1 || exit $?
94 grep -v ^X-Envelope- Mail/inbox/2 94 grep -v ^X-Envelope- Mail/inbox/2
95 grep -v ^X-Envelope- Mail/inbox/3 95 grep -v ^X-Envelope- Mail/inbox/3
96 grep -v ^X-Envelope- Mail/inbox/4 96 grep -v ^X-Envelope- Mail/inbox/4
...@@ -140,7 +140,7 @@ With gently smiling jaws! ...@@ -140,7 +140,7 @@ With gently smiling jaws!
140 140
141 MH_CHECK([burst mime recursive],[burst03 burst-mime-recursive],[ 141 MH_CHECK([burst mime recursive],[burst03 burst-mime-recursive],[
142 MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) 142 MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
143 burst +inbox --recursive 4 || exit $? 143 burst +inbox -recursive 4 || exit $?
144 grep -v ^X-Envelope- Mail/inbox/6 144 grep -v ^X-Envelope- Mail/inbox/6
145 grep -v ^X-Envelope- Mail/inbox/7 145 grep -v ^X-Envelope- Mail/inbox/7
146 grep -v ^X-Envelope- Mail/inbox/8 146 grep -v ^X-Envelope- Mail/inbox/8
......
...@@ -99,13 +99,13 @@ Mail/inbox/4 ...@@ -99,13 +99,13 @@ Mail/inbox/4
99 Mail/inbox/5 99 Mail/inbox/5
100 ]) 100 ])
101 101
102 MH_CHECK([folder --pack=N],[folder06 folder--pack=N],[ 102 MH_CHECK([folder -pack=N],[folder06 folder-pack=N],[
103 MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) 103 MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
104 for i in 1 2 3 4 5 104 for i in 1 2 3 4 5
105 do 105 do
106 mv Mail/inbox/$i Mail/inbox/${i}0 106 mv Mail/inbox/$i Mail/inbox/${i}0
107 done 107 done
108 folder --pack=1 || exit $? 108 folder -pack=1 || exit $?
109 find Mail/inbox -not -name '.mu-prop' | sort 109 find Mail/inbox -not -name '.mu-prop' | sort
110 ], 110 ],
111 [0], 111 [0],
......