Commit 2a28ab58 2a28ab58762f9ae9cd00ca3e467ee6f90f241201 by Sergey Poznyakoff

Rewrite parseopt help routines using wordwrap streams

* include/mailutils/stream.h (MU_IOCTL_WORDWRAP_SET_NEXT_MARGIN)
(MU_IOCTL_WORDWRAP_GET_OFFSET): New opcodes.
* libmailutils/stream/wordwrap.c (_wordwrap_flush_line): Replace
whitespace-only lines with single newline on output.
(_wordwrap_flush): Fix condition.
(set_margin): Bugfix.
(_wordwrap_ctl): Handle new opcodes.

* include/mailutils/cli.h (mu_version_func): Change signature.
* include/mailutils/opt.h (mu_parseopt) <po_help_hook>
<po_version_hook>: Change signature.
(mu_parseopt_fmt_text): Remove.
(mu_option_describe_options, mu_program_help)
(mu_program_usage): Change signature.
(mu_program_version): New prototype.
* libmailutils/cli/cli.c (mu_version_func): Take mu_stream_t as
2nd argument.  Use mu_stream_printf for output.
(extra_help_hook): Likewise.
* libmailutils/opt/help.c: Rewrite using wordwrap streams.
* libmailutils/opt/opt.c (fn_help, fn_usage, fn_version): Update.
* libmailutils/tests/parseopt.c (version_hook): Write to mu_stream_t.

* libmailutils/tests/parseopt_help00.at: Fix expected output.
* libmailutils/tests/parseopt_help01.at: Likewise.
* libmailutils/tests/parseopt_help02.at: Likewise.
* libmailutils/tests/parseopt_help03.at: Likewise.
* libmailutils/tests/parseopt_help04.at: Likewise.
* libmailutils/tests/parseopt_help05.at: Likewise.
* libmailutils/tests/parseopt_help06.at: Likewise.
* libmailutils/tests/parseopt_help07.at: Likewise.
* libmailutils/tests/parseopt_help08.at: Likewise.
* libmailutils/tests/parseopt_help09.at: Likewise.
* libmailutils/tests/parseopt_help10.at: Likewise.
* libmailutils/tests/parseopt_help11.at: Likewise.
1 parent 06c13b34
...@@ -50,7 +50,7 @@ struct mu_cli_setup ...@@ -50,7 +50,7 @@ struct mu_cli_setup
50 errors */ 50 errors */
51 }; 51 };
52 52
53 void mu_version_func (struct mu_parseopt *po, FILE *stream); 53 void mu_version_func (struct mu_parseopt *po, mu_stream_t stream);
54 void mu_cli (int argc, char **argv, struct mu_cli_setup *setup, 54 void mu_cli (int argc, char **argv, struct mu_cli_setup *setup,
55 char **capa, void *data, 55 char **capa, void *data,
56 int *ret_argc, char ***ret_argv); 56 int *ret_argc, char ***ret_argv);
......
...@@ -131,9 +131,8 @@ struct mu_parseopt ...@@ -131,9 +131,8 @@ struct mu_parseopt
131 char const *po_package_url; 131 char const *po_package_url;
132 char const *po_extra_info; 132 char const *po_extra_info;
133 133
134 /* FIXME: should these take mu_stream_t ?*/ 134 void (*po_help_hook) (struct mu_parseopt *po, mu_stream_t stream);
135 void (*po_help_hook) (struct mu_parseopt *po, FILE *stream); 135 void (*po_version_hook) (struct mu_parseopt *po, mu_stream_t stream);
136 void (*po_version_hook) (struct mu_parseopt *po, FILE *stream);
137 136
138 /* Output data */ 137 /* Output data */
139 int po_ind; /* Index of the next option */ 138 int po_ind; /* Index of the next option */
...@@ -169,11 +168,12 @@ int mu_parseopt_apply (struct mu_parseopt *p); ...@@ -169,11 +168,12 @@ int mu_parseopt_apply (struct mu_parseopt *p);
169 void mu_parseopt_free (struct mu_parseopt *p); 168 void mu_parseopt_free (struct mu_parseopt *p);
170 169
171 unsigned mu_parseopt_getcolumn (const char *name); 170 unsigned mu_parseopt_getcolumn (const char *name);
172 void mu_parseopt_fmt_text (const char *text, size_t col);
173 171
174 void mu_option_describe_options (struct mu_option **optbuf, size_t optcnt); 172 void mu_option_describe_options (mu_stream_t str,
175 void mu_program_help (struct mu_parseopt *p); 173 struct mu_option **optbuf, size_t optcnt);
176 void mu_program_usage (struct mu_parseopt *p); 174 void mu_program_help (struct mu_parseopt *p, mu_stream_t str);
175 void mu_program_usage (struct mu_parseopt *p, mu_stream_t str);
176 void mu_program_version (struct mu_parseopt *po, mu_stream_t str);
177 177
178 void mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt, 178 void mu_option_set_value (struct mu_parseopt *po, struct mu_option *opt,
179 char const *arg); 179 char const *arg);
......
...@@ -211,6 +211,8 @@ enum mu_buffer_type ...@@ -211,6 +211,8 @@ enum mu_buffer_type
211 #define MU_IOCTL_WORDWRAP_GET_MARGIN 0 211 #define MU_IOCTL_WORDWRAP_GET_MARGIN 0
212 #define MU_IOCTL_WORDWRAP_SET_MARGIN 1 212 #define MU_IOCTL_WORDWRAP_SET_MARGIN 1
213 #define MU_IOCTL_WORDWRAP_MOVE_MARGIN 2 213 #define MU_IOCTL_WORDWRAP_MOVE_MARGIN 2
214 #define MU_IOCTL_WORDWRAP_SET_NEXT_MARGIN 3
215 #define MU_IOCTL_WORDWRAP_GET_OFFSET 4
214 216
215 struct mu_nullstream_pattern 217 struct mu_nullstream_pattern
216 { 218 {
......
...@@ -53,40 +53,37 @@ const char mu_version_copyright[] = ...@@ -53,40 +53,37 @@ const char mu_version_copyright[] =
53 "Copyright %s 2007-2016 Free Software Foundation, inc."; 53 "Copyright %s 2007-2016 Free Software Foundation, inc.";
54 54
55 void 55 void
56 mu_version_func (struct mu_parseopt *po, FILE *stream) 56 mu_version_func (struct mu_parseopt *po, mu_stream_t stream)
57 { 57 {
58 #ifdef GIT_DESCRIBE 58 #ifdef GIT_DESCRIBE
59 fprintf (stream, "%s (%s) %s [%s]\n", 59 mu_stream_printf (stream, "%s (%s) %s [%s]\n",
60 mu_program_name, PACKAGE_NAME, PACKAGE_VERSION, GIT_DESCRIBE); 60 mu_program_name, PACKAGE_NAME, PACKAGE_VERSION,
61 GIT_DESCRIBE);
61 #else 62 #else
62 fprintf (stream, "%s (%s) %s\n", mu_program_name, 63 mu_stream_printf (stream, "%s (%s) %s\n", mu_program_name,
63 PACKAGE_NAME, PACKAGE_VERSION); 64 PACKAGE_NAME, PACKAGE_VERSION);
64 #endif 65 #endif
65 /* TRANSLATORS: Translate "(C)" to the copyright symbol 66 /* TRANSLATORS: Translate "(C)" to the copyright symbol
66 (C-in-a-circle), if this symbol is available in the user's 67 (C-in-a-circle), if this symbol is available in the user's
67 locale. Otherwise, do not translate "(C)"; leave it as-is. */ 68 locale. Otherwise, do not translate "(C)"; leave it as-is. */
68 fprintf (stream, mu_version_copyright, _("(C)")); 69 mu_stream_printf (stream, mu_version_copyright, _("(C)"));
69 fputs (_("\ 70 mu_stream_printf (stream, _("\
70 \n\ 71 \n\
71 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\ 72 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\
72 There is NO WARRANTY, to the extent permitted by law.\n\ 73 There is NO WARRANTY, to the extent permitted by law.\n\
73 \n\ 74 \n\
74 "), 75 "));
75 stream);
76 } 76 }
77 77
78 static char gnu_general_help_url[] = 78 static char gnu_general_help_url[] =
79 N_("General help using GNU software: <http://www.gnu.org/gethelp/>"); 79 N_("General help using GNU software: <http://www.gnu.org/gethelp/>");
80 80
81 static void 81 static void
82 extra_help_hook (struct mu_parseopt *po, FILE *stream) 82 extra_help_hook (struct mu_parseopt *po, mu_stream_t stream)
83 { 83 {
84 struct mu_cfg_parse_hints *hints = po->po_data; 84 struct mu_cfg_parse_hints *hints = po->po_data;
85 struct mu_cli_setup *setup = hints->data; 85 struct mu_cli_setup *setup = hints->data;
86 char *extra_doc = _(setup->prog_extra_doc); 86 mu_stream_printf (stream, "%s\n", _(setup->prog_extra_doc));
87 /* FIXME: mu_parseopt help output should get FILE * argument */
88 mu_parseopt_fmt_text (extra_doc, 0);
89 fputc ('\n', stdout);
90 } 87 }
91 88
92 static void 89 static void
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
24 #include <mailutils/opt.h> 24 #include <mailutils/opt.h>
25 #include <mailutils/nls.h> 25 #include <mailutils/nls.h>
26 #include <mailutils/errno.h> 26 #include <mailutils/errno.h>
27 #include <mailutils/stdstream.h>
27 28
28 #define EXIT_SUCCESS 0 29 #define EXIT_SUCCESS 0
29 #define EXIT_ERROR 1 30 #define EXIT_ERROR 1
...@@ -78,7 +79,7 @@ sort_group (struct mu_option **optbuf, size_t start) ...@@ -78,7 +79,7 @@ sort_group (struct mu_option **optbuf, size_t start)
78 static void 79 static void
79 fn_help (struct mu_parseopt *po, struct mu_option *opt, char const *unused) 80 fn_help (struct mu_parseopt *po, struct mu_option *opt, char const *unused)
80 { 81 {
81 mu_program_help (po); 82 mu_program_help (po, mu_strout);
82 exit (EXIT_SUCCESS); 83 exit (EXIT_SUCCESS);
83 } 84 }
84 85
...@@ -86,14 +87,14 @@ fn_help (struct mu_parseopt *po, struct mu_option *opt, char const *unused) ...@@ -86,14 +87,14 @@ fn_help (struct mu_parseopt *po, struct mu_option *opt, char const *unused)
86 static void 87 static void
87 fn_usage (struct mu_parseopt *po, struct mu_option *opt, char const *unused) 88 fn_usage (struct mu_parseopt *po, struct mu_option *opt, char const *unused)
88 { 89 {
89 mu_program_usage (po); 90 mu_program_usage (po, mu_strout);
90 exit (EXIT_SUCCESS); 91 exit (EXIT_SUCCESS);
91 } 92 }
92 93
93 static void 94 static void
94 fn_version (struct mu_parseopt *po, struct mu_option *opt, char const *unused) 95 fn_version (struct mu_parseopt *po, struct mu_option *opt, char const *unused)
95 { 96 {
96 po->po_version_hook (po, stdout); 97 mu_program_version (po, mu_strout);
97 exit (EXIT_SUCCESS); 98 exit (EXIT_SUCCESS);
98 } 99 }
99 100
......
...@@ -88,7 +88,7 @@ _wordwrap_flush_line (struct mu_wordwrap_stream *str, int lookahead) ...@@ -88,7 +88,7 @@ _wordwrap_flush_line (struct mu_wordwrap_stream *str, int lookahead)
88 } 88 }
89 } 89 }
90 90
91 while (length > 0 && mu_isblank (str->buffer[length - 1])) 91 while (length > 0 && mu_isspace (str->buffer[length - 1]))
92 length--; 92 length--;
93 93
94 if (length == 0 || str->buffer[length - 1] != '\n') 94 if (length == 0 || str->buffer[length - 1] != '\n')
...@@ -147,7 +147,7 @@ static int ...@@ -147,7 +147,7 @@ static int
147 _wordwrap_flush (mu_stream_t stream) 147 _wordwrap_flush (mu_stream_t stream)
148 { 148 {
149 struct mu_wordwrap_stream *str = (struct mu_wordwrap_stream *)stream; 149 struct mu_wordwrap_stream *str = (struct mu_wordwrap_stream *)stream;
150 if (str->offset) 150 if (str->offset > str->left_margin)
151 _wordwrap_flush_line (str, 0); 151 _wordwrap_flush_line (str, 0);
152 return mu_stream_flush (str->transport); 152 return mu_stream_flush (str->transport);
153 } 153 }
...@@ -177,18 +177,19 @@ set_margin (mu_stream_t stream, unsigned lmargin, int off) ...@@ -177,18 +177,19 @@ set_margin (mu_stream_t stream, unsigned lmargin, int off)
177 177
178 if (lmargin >= str->right_margin) 178 if (lmargin >= str->right_margin)
179 return EINVAL; 179 return EINVAL;
180 if (lmargin < str->offset) 180
181 {
182 str->left_margin = lmargin; 181 str->left_margin = lmargin;
182 if (lmargin < str->offset ||
183 (str->offset > 0 && str->buffer[str->offset - 1] == '\n'))
184 {
183 _wordwrap_flush (stream); 185 _wordwrap_flush (stream);
184 } 186 }
185 else if (lmargin > str->offset) 187 else if (lmargin > str->offset)
186 { 188 {
187 memset (str->buffer + str->offset, ' ', 189 memset (str->buffer + str->offset, ' ', lmargin - str->offset);
188 lmargin - str->offset);
189 str->left_margin = lmargin;
190 str->offset = lmargin; 190 str->offset = lmargin;
191 } 191 }
192
192 return 0; 193 return 0;
193 } 194 }
194 195
...@@ -217,12 +218,30 @@ _wordwrap_ctl (mu_stream_t stream, int code, int opcode, void *arg) ...@@ -217,12 +218,30 @@ _wordwrap_ctl (mu_stream_t stream, int code, int opcode, void *arg)
217 else 218 else
218 return set_margin (stream, *(unsigned*)arg, 0); 219 return set_margin (stream, *(unsigned*)arg, 0);
219 220
221 case MU_IOCTL_WORDWRAP_SET_NEXT_MARGIN:
222 if (!arg)
223 return EINVAL;
224 else
225 {
226 unsigned marg = *(unsigned*)arg;
227 if (marg >= str->right_margin)
228 return EINVAL;
229 str->left_margin = marg;
230 }
231 break;
232
220 case MU_IOCTL_WORDWRAP_MOVE_MARGIN: 233 case MU_IOCTL_WORDWRAP_MOVE_MARGIN:
221 if (!arg) 234 if (!arg)
222 return EINVAL; 235 return EINVAL;
223 else 236 else
224 return set_margin (stream, str->offset, *(int*)arg); 237 return set_margin (stream, str->offset, *(int*)arg);
225 238
239 case MU_IOCTL_WORDWRAP_GET_OFFSET:
240 if (!arg)
241 return EINVAL;
242 *(unsigned*)arg = str->offset;
243 break;
244
226 default: 245 default:
227 return EINVAL; 246 return EINVAL;
228 } 247 }
......
...@@ -64,9 +64,9 @@ struct mu_option group_b[] = { ...@@ -64,9 +64,9 @@ struct mu_option group_b[] = {
64 struct mu_option *optv[] = { group_a, group_b, NULL }; 64 struct mu_option *optv[] = { group_a, group_b, NULL };
65 65
66 static void 66 static void
67 version_hook (struct mu_parseopt *po, FILE *fp) 67 version_hook (struct mu_parseopt *po, mu_stream_t str)
68 { 68 {
69 fputs ("version hook called\n", fp); 69 mu_stream_printf (str, "version hook called\n");
70 } 70 }
71 71
72 #define S(s) ((s)?(s):"(null)") 72 #define S(s) ((s)?(s):"(null)")
......
...@@ -30,8 +30,8 @@ parseopt --help ...@@ -30,8 +30,8 @@ parseopt --help
30 -x short-only option 30 -x short-only option
31 31
32 Group B 32 Group B
33 -F, --find=VALUE find VALUE
34 -d, -v, --debug, --verbose another option 33 -d, -v, --debug, --verbose another option
34 -F, --find=VALUE find VALUE
35 -j, --jobs=N sets numeric value 35 -j, --jobs=N sets numeric value
36 36
37 -?, --help give this help list 37 -?, --help give this help list
......
...@@ -21,8 +21,8 @@ PARSEOPT_DEFAULT ...@@ -21,8 +21,8 @@ PARSEOPT_DEFAULT
21 parseopt --usage 21 parseopt --usage
22 ], 22 ],
23 [0], 23 [0],
24 [[Usage: parseopt [-advx?] [-f FILE] [-F VALUE] [-j N] [-o FILE] [--all] 24 [[Usage: parseopt [-advx?] [-f FILE] [-F VALUE] [-j N] [-o[FILE]] [--all]
25 [--debug] [--file=FILE] [--find=VALUE] [--help] [--jobs=N] 25 [--debug] [--file=FILE] [--find=VALUE] [--help] [--jobs=N]
26 [--optional=FILE] [--usage] [--verbose] 26 [--optional[=FILE]] [--usage] [--verbose]
27 ]]) 27 ]])
28 AT_CLEANUP 28 AT_CLEANUP
......
...@@ -30,8 +30,8 @@ MU_PARSEOPT_PROG_NAME=newname parseopt --help ...@@ -30,8 +30,8 @@ MU_PARSEOPT_PROG_NAME=newname parseopt --help
30 -x short-only option 30 -x short-only option
31 31
32 Group B 32 Group B
33 -F, --find=VALUE find VALUE
34 -d, -v, --debug, --verbose another option 33 -d, -v, --debug, --verbose another option
34 -F, --find=VALUE find VALUE
35 -j, --jobs=N sets numeric value 35 -j, --jobs=N sets numeric value
36 36
37 -?, --help give this help list 37 -?, --help give this help list
......
...@@ -31,8 +31,8 @@ Tests option parsing ...@@ -31,8 +31,8 @@ Tests option parsing
31 -x short-only option 31 -x short-only option
32 32
33 Group B 33 Group B
34 -F, --find=VALUE find VALUE
35 -d, -v, --debug, --verbose another option 34 -d, -v, --debug, --verbose another option
35 -F, --find=VALUE find VALUE
36 -j, --jobs=N sets numeric value 36 -j, --jobs=N sets numeric value
37 37
38 -?, --help give this help list 38 -?, --help give this help list
......
...@@ -30,8 +30,8 @@ MU_PARSEOPT_PROG_ARGS="SOME MORE ARGS" parseopt --help ...@@ -30,8 +30,8 @@ MU_PARSEOPT_PROG_ARGS="SOME MORE ARGS" parseopt --help
30 -x short-only option 30 -x short-only option
31 31
32 Group B 32 Group B
33 -F, --find=VALUE find VALUE
34 -d, -v, --debug, --verbose another option 33 -d, -v, --debug, --verbose another option
34 -F, --find=VALUE find VALUE
35 -j, --jobs=N sets numeric value 35 -j, --jobs=N sets numeric value
36 36
37 -?, --help give this help list 37 -?, --help give this help list
......
...@@ -30,8 +30,8 @@ MU_PARSEOPT_BUG_ADDRESS='gray@gnu.org' parseopt --help ...@@ -30,8 +30,8 @@ MU_PARSEOPT_BUG_ADDRESS='gray@gnu.org' parseopt --help
30 -x short-only option 30 -x short-only option
31 31
32 Group B 32 Group B
33 -F, --find=VALUE find VALUE
34 -d, -v, --debug, --verbose another option 33 -d, -v, --debug, --verbose another option
34 -F, --find=VALUE find VALUE
35 -j, --jobs=N sets numeric value 35 -j, --jobs=N sets numeric value
36 36
37 -?, --help give this help list 37 -?, --help give this help list
......
...@@ -30,8 +30,8 @@ MU_PARSEOPT_PACKAGE_NAME='GNU Mailutils' MU_PARSEOPT_PACKAGE_URL='http://mailuti ...@@ -30,8 +30,8 @@ MU_PARSEOPT_PACKAGE_NAME='GNU Mailutils' MU_PARSEOPT_PACKAGE_URL='http://mailuti
30 -x short-only option 30 -x short-only option
31 31
32 Group B 32 Group B
33 -F, --find=VALUE find VALUE
34 -d, -v, --debug, --verbose another option 33 -d, -v, --debug, --verbose another option
34 -F, --find=VALUE find VALUE
35 -j, --jobs=N sets numeric value 35 -j, --jobs=N sets numeric value
36 36
37 -?, --help give this help list 37 -?, --help give this help list
......
...@@ -37,8 +37,8 @@ Tests option parsing ...@@ -37,8 +37,8 @@ Tests option parsing
37 -x short-only option 37 -x short-only option
38 38
39 Group B 39 Group B
40 -F, --find=VALUE find VALUE
41 -d, -v, --debug, --verbose another option 40 -d, -v, --debug, --verbose another option
41 -F, --find=VALUE find VALUE
42 -j, --jobs=N sets numeric value 42 -j, --jobs=N sets numeric value
43 43
44 -?, --help give this help list 44 -?, --help give this help list
......
...@@ -31,8 +31,8 @@ ARGP_HELP_FMT=dup-args,no-dup-args-note,short-opt-col=1,opt-doc-col=32,header-co ...@@ -31,8 +31,8 @@ ARGP_HELP_FMT=dup-args,no-dup-args-note,short-opt-col=1,opt-doc-col=32,header-co
31 -x short-only option 31 -x short-only option
32 32
33 Group B 33 Group B
34 -F VALUE, --find=VALUE find VALUE
35 -d, -v, --debug, --verbose another option 34 -d, -v, --debug, --verbose another option
35 -F VALUE, --find=VALUE find VALUE
36 -j N, --jobs=N sets numeric value 36 -j N, --jobs=N sets numeric value
37 37
38 -?, --help give this help list 38 -?, --help give this help list
......
...@@ -23,7 +23,7 @@ ARGP_HELP_FMT=rmargin=62,usage-indent=1\ ...@@ -23,7 +23,7 @@ ARGP_HELP_FMT=rmargin=62,usage-indent=1\
23 ], 23 ],
24 [0], 24 [0],
25 [[Usage: parseopt [-advx?] [-f FILE] [-F VALUE] [-j N] 25 [[Usage: parseopt [-advx?] [-f FILE] [-F VALUE] [-j N]
26 [-o FILE] [--all] [--debug] [--file=FILE] [--find=VALUE] 26 [-o[FILE]] [--all] [--debug] [--file=FILE] [--find=VALUE]
27 [--help] [--jobs=N] [--optional=FILE] [--usage] [--verbose] 27 [--help] [--jobs=N] [--optional[=FILE]] [--usage] [--verbose]
28 ]]) 28 ]])
29 AT_CLEANUP 29 AT_CLEANUP
......
...@@ -21,8 +21,8 @@ PARSEOPT_DEFAULT ...@@ -21,8 +21,8 @@ PARSEOPT_DEFAULT
21 MU_PARSEOPT_VERSION_HOOK=1 parseopt --usage 21 MU_PARSEOPT_VERSION_HOOK=1 parseopt --usage
22 ], 22 ],
23 [0], 23 [0],
24 [[Usage: parseopt [-advVx?] [-f FILE] [-F VALUE] [-j N] [-o FILE] [--all] 24 [[Usage: parseopt [-advVx?] [-f FILE] [-F VALUE] [-j N] [-o[FILE]] [--all]
25 [--debug] [--file=FILE] [--find=VALUE] [--help] [--jobs=N] 25 [--debug] [--file=FILE] [--find=VALUE] [--help] [--jobs=N]
26 [--optional=FILE] [--usage] [--verbose] [--version] 26 [--optional[=FILE]] [--usage] [--verbose] [--version]
27 ]]) 27 ]])
28 AT_CLEANUP 28 AT_CLEANUP
......
...@@ -30,8 +30,8 @@ MU_PARSEOPT_VERSION_HOOK=1 parseopt --help ...@@ -30,8 +30,8 @@ MU_PARSEOPT_VERSION_HOOK=1 parseopt --help
30 -x short-only option 30 -x short-only option
31 31
32 Group B 32 Group B
33 -F, --find=VALUE find VALUE
34 -d, -v, --debug, --verbose another option 33 -d, -v, --debug, --verbose another option
34 -F, --find=VALUE find VALUE
35 -j, --jobs=N sets numeric value 35 -j, --jobs=N sets numeric value
36 36
37 -?, --help give this help list 37 -?, --help give this help list
......