Browse Source

Add dump_opt_long for #548

ithewei 1 year ago
parent
commit
031684d58a
8 changed files with 112 additions and 97 deletions
  1. 63 0
      base/hmain.c
  2. 3 1
      base/hmain.h
  3. 1 0
      base/hplatform.h
  4. 1 0
      docs/API.md
  5. 10 22
      examples/hmain_test.cpp
  6. 10 22
      examples/httpd/httpd.cpp
  7. 12 26
      examples/kcptun/client/main.cpp
  8. 12 26
      examples/kcptun/server/main.cpp

+ 63 - 0
base/hmain.c

@@ -343,6 +343,69 @@ int parse_opt_long(int argc, char** argv, const option_t* long_options, int size
     return 0;
 }
 
+int dump_opt_long(const option_t* long_options, int opt_size, char* out_str, int out_size) {
+    /*
+     * Usage: program_name [short_options]
+     * Options:
+     *   -%c|--%s          description
+     *   -%c|--%s <value>  description
+     *   -%c|--%s [value]  description
+     */
+    int align = 0, max_align = 0;
+    char short_options[256] = {0};
+    char* p = short_options;
+    for (int i = 0; i < opt_size; ++i) {
+        if (long_options[i].short_opt > 0) {
+            *p++ = long_options[i].short_opt;
+        }
+        if (long_options[i].arg_type == NO_ARGUMENT) {
+            // "  -%c|--%s  "
+            align = 9 + strlen(long_options[i].long_opt);
+        } else {
+            // "  -%c|--%s <value>  "
+            align = 17 + strlen(long_options[i].long_opt);
+            if (long_options[i].short_opt > 0) {
+                *p++ = ':';
+            }
+        }
+        if (align > max_align) max_align = align;
+    }
+
+    int offset = 0;
+    if (*g_main_ctx.program_name) {
+        offset = snprintf(out_str, out_size, "Usage: %s [%s]\n", g_main_ctx.program_name, short_options);
+    }
+    offset += snprintf(out_str + offset, out_size - offset, "Options:\n");
+    char short_opt_chars[4] = {0};
+    for (int i = 0; i < opt_size; ++i) {
+        if (long_options[i].short_opt > 0) {
+            // -%c|
+            short_opt_chars[0] = '-';
+            short_opt_chars[1] = long_options[i].short_opt;
+            short_opt_chars[2] = '|';
+        } else {
+            short_opt_chars[0] = ' ';
+            short_opt_chars[1] = ' ';
+            short_opt_chars[2] = ' ';
+        }
+        if (long_options[i].arg_type == NO_ARGUMENT) {
+            // "  -%c|--%s  "
+            align = 9 + strlen(long_options[i].long_opt);
+        } else {
+            // "  -%c|--%s <value>  "
+            align = 17 + strlen(long_options[i].long_opt);
+        }
+        offset += snprintf(out_str + offset, out_size - offset, "  %s--%s%s  %*s%s\n",
+                short_opt_chars,
+                long_options[i].long_opt,
+                long_options[i].arg_type == REQUIRED_ARGUMENT ? " <value>" :
+                long_options[i].arg_type == OPTIONAL_ARGUMENT ? " [value]" : "",
+                max_align - align, "",
+                long_options[i].description ? long_options[i].description : "");
+    }
+    return offset;
+}
+
 #if defined(OS_UNIX) && !HAVE_SETPROCTITLE
 /*
  * memory layout

+ 3 - 1
base/hmain.h

@@ -65,6 +65,7 @@ typedef struct option_s {
     char        short_opt;
     const char* long_opt;
     int         arg_type;
+    const char* description;
 } option_t;
 
 HV_EXPORT int  main_ctx_init(int argc, char** argv);
@@ -76,7 +77,8 @@ HV_EXPORT void main_ctx_free(void);
 // watch -n10 ls
 HV_EXPORT int parse_opt(int argc, char** argv, const char* opt);
 // gcc -g -Wall -O3 -std=cpp main.c
-HV_EXPORT int parse_opt_long(int argc, char** argv, const option_t* long_options, int size);
+HV_EXPORT int parse_opt_long(int argc, char** argv, const option_t* long_options, int opt_size);
+HV_EXPORT int dump_opt_long(const option_t* long_options, int opt_size, char* out_str, int out_size);
 HV_EXPORT const char* get_arg(const char* key);
 HV_EXPORT const char* get_env(const char* key);
 

+ 1 - 0
base/hplatform.h

@@ -41,6 +41,7 @@
     #undef  OS_UNIX
     #define OS_WIN
 #else
+    #undef  OS_WIN
     #define OS_UNIX
 #endif
 

+ 1 - 0
docs/API.md

@@ -269,6 +269,7 @@
 - main_ctx_init
 - parse_opt
 - parse_opt_long
+- dump_opt_long
 - get_arg
 - get_env
 - setproctitle

+ 10 - 22
examples/hmain_test.cpp

@@ -38,36 +38,25 @@ static void print_help();
 static int  parse_confile(const char* confile);
 static void worker_fn(void* userdata);
 
-// short options
-static const char options[] = "hvc:ts:dp:";
 // long options
 static const option_t long_options[] = {
-    {'h', "help",       NO_ARGUMENT},
-    {'v', "version",    NO_ARGUMENT},
-    {'c', "confile",    REQUIRED_ARGUMENT},
-    {'t', "test",       NO_ARGUMENT},
-    {'s', "signal",     REQUIRED_ARGUMENT},
-    {'d', "daemon",     NO_ARGUMENT},
-    {'p', "port",       REQUIRED_ARGUMENT}
+    {'h', "help",       NO_ARGUMENT,        "Print this information"},
+    {'v', "version",    NO_ARGUMENT,        "Print version"},
+    {'c', "confile",    REQUIRED_ARGUMENT,  "Set configure file, default etc/{program}.conf"},
+    {'t', "test",       NO_ARGUMENT,        "Test configure file and exit"},
+    {'s', "signal",     REQUIRED_ARGUMENT,  "send signal to process, signal=[start,stop,restart,status,reload]"},
+    {'d', "daemon",     NO_ARGUMENT,        "Daemonize"},
+    {'p', "port",       REQUIRED_ARGUMENT,  "Set listen port"}
 };
-static const char detail_options[] = R"(
-  -h|--help                 Print this information
-  -v|--version              Print version
-  -c|--confile <confile>    Set configure file, default etc/{program}.conf
-  -t|--test                 Test configure file and exit
-  -s|--signal <signal>      Send <signal> to process,
-                            <signal>=[start,stop,restart,status,reload]
-  -d|--daemon               Daemonize
-  -p|--port <port>          Set listen port
-)";
 
 void print_version() {
     printf("%s version %s\n", g_main_ctx.program_name, hv_compile_version());
 }
 
 void print_help() {
-    printf("Usage: %s [%s]\n", g_main_ctx.program_name, options);
-    printf("Options:\n%s\n", detail_options);
+    char detail_options[1024] = {0};
+    dump_opt_long(long_options, ARRAY_SIZE(long_options), detail_options, sizeof(detail_options));
+    printf("%s\n", detail_options);
 }
 
 int parse_confile(const char* confile) {
@@ -170,7 +159,6 @@ int main(int argc, char** argv) {
         print_help();
         exit(10);
     }
-    // int ret = parse_opt(argc, argv, options);
     int ret = parse_opt_long(argc, argv, long_options, ARRAY_SIZE(long_options));
     if (ret != 0) {
         print_help();

+ 10 - 22
examples/httpd/httpd.cpp

@@ -16,36 +16,25 @@ static void print_help();
 
 static int  parse_confile(const char* confile);
 
-// short options
-static const char options[] = "hvc:ts:dp:";
 // long options
 static const option_t long_options[] = {
-    {'h', "help",       NO_ARGUMENT},
-    {'v', "version",    NO_ARGUMENT},
-    {'c', "confile",    REQUIRED_ARGUMENT},
-    {'t', "test",       NO_ARGUMENT},
-    {'s', "signal",     REQUIRED_ARGUMENT},
-    {'d', "daemon",     NO_ARGUMENT},
-    {'p', "port",       REQUIRED_ARGUMENT}
+    {'h', "help",       NO_ARGUMENT,        "Print this information"},
+    {'v', "version",    NO_ARGUMENT,        "Print version"},
+    {'c', "confile",    REQUIRED_ARGUMENT,  "Set configure file, default etc/{program}.conf"},
+    {'t', "test",       NO_ARGUMENT,        "Test configure file and exit"},
+    {'s', "signal",     REQUIRED_ARGUMENT,  "send signal to process, signal=[start,stop,restart,status,reload]"},
+    {'d', "daemon",     NO_ARGUMENT,        "Daemonize"},
+    {'p', "port",       REQUIRED_ARGUMENT,  "Set listen port"}
 };
-static const char detail_options[] = R"(
-  -h|--help                 Print this information
-  -v|--version              Print version
-  -c|--confile <confile>    Set configure file, default etc/{program}.conf
-  -t|--test                 Test configure file and exit
-  -s|--signal <signal>      Send <signal> to process,
-                            <signal>=[start,stop,restart,status,reload]
-  -d|--daemon               Daemonize
-  -p|--port <port>          Set listen port
-)";
 
 void print_version() {
     printf("%s version %s\n", g_main_ctx.program_name, hv_compile_version());
 }
 
 void print_help() {
-    printf("Usage: %s [%s]\n", g_main_ctx.program_name, options);
-    printf("Options:\n%s\n", detail_options);
+    char detail_options[1024] = {0};
+    dump_opt_long(long_options, ARRAY_SIZE(long_options), detail_options, sizeof(detail_options));
+    printf("%s\n", detail_options);
 }
 
 int parse_confile(const char* confile) {
@@ -275,7 +264,6 @@ static void on_reload(void* userdata) {
 int main(int argc, char** argv) {
     // g_main_ctx
     main_ctx_init(argc, argv);
-    //int ret = parse_opt(argc, argv, options);
     int ret = parse_opt_long(argc, argv, long_options, ARRAY_SIZE(long_options));
     if (ret != 0) {
         print_help();

+ 12 - 26
examples/kcptun/client/main.cpp

@@ -27,40 +27,27 @@ static int mtu = 1350;
 static int sndwnd = 128;
 static int rcvwnd = 512;
 
-// short options
-static const char options[] = "hvdl:r:m:";
 // long options
 static const option_t long_options[] = {
-    {'h', "help",       NO_ARGUMENT},
-    {'v', "version",    NO_ARGUMENT},
-    {'d', "daemon",     NO_ARGUMENT},
-    {'l', "localaddr",  REQUIRED_ARGUMENT},
-    {'r', "remoteaddr", REQUIRED_ARGUMENT},
-    {'m', "mode",       REQUIRED_ARGUMENT},
-    { 0,  "mtu",        REQUIRED_ARGUMENT},
-    { 0,  "sndwnd",     REQUIRED_ARGUMENT},
-    { 0,  "rcvwnd",     REQUIRED_ARGUMENT},
+    {'h', "help",       NO_ARGUMENT,        "Print this information"},
+    {'v', "version",    NO_ARGUMENT,        "Print version"},
+    {'d', "daemon",     NO_ARGUMENT,        "Daemonize"},
+    {'l', "localaddr",  REQUIRED_ARGUMENT,  "local listen address (default: \":8388\")"},
+    {'r', "remoteaddr", REQUIRED_ARGUMENT,  "kcp server address (default: \"127.0.0.1:4000\")"},
+    {'m', "mode",       REQUIRED_ARGUMENT,  "profiles: fast3, fast2, fast, normal, (default: \"fast\")"},
+    { 0,  "mtu",        REQUIRED_ARGUMENT,  "set maxinum transmission unit for UDP packets (default: 1350)"},
+    { 0,  "sndwnd",     REQUIRED_ARGUMENT,  "set send window size(num of packets) (default: 128)"},
+    { 0,  "rcvwnd",     REQUIRED_ARGUMENT,  "set receive window size(num of packets) (default: 512)"},
 };
 
-static const char detail_options[] = R"(
-  -h|--help                 Print this information
-  -v|--version              Print version
-  -d|--daemon               Daemonize
-  -l|--localaddr value      local listen address (default: ":8388")
-  -r|--remoteaddr value     kcp server address (default: "127.0.0.1:4000")
-  -m|--mode value           profiles: fast3, fast2, fast, normal (default: "fast")
-     --mtu value            set maximum transmission unit for UDP packets (default: 1350)
-     --sndwnd value         set send window size(num of packets) (default: 128)
-     --rcvwnd value         set receive window size(num of packets) (default: 512)
-)";
-
 static void print_version() {
     printf("%s version %s\n", g_main_ctx.program_name, hv_compile_version());
 }
 
 static void print_help() {
-    printf("Usage: %s [%s]\n", g_main_ctx.program_name, options);
-    printf("Options:\n%s\n", detail_options);
+    char detail_options[1024] = {0};
+    dump_opt_long(long_options, ARRAY_SIZE(long_options), detail_options, sizeof(detail_options));
+    printf("%s\n", detail_options);
 }
 
 static char listen_host[64] = "0.0.0.0";
@@ -260,7 +247,6 @@ int main(int argc, char** argv) {
 
     // g_main_ctx
     main_ctx_init(argc, argv);
-    //int ret = parse_opt(argc, argv, options);
     int ret = parse_opt_long(argc, argv, long_options, ARRAY_SIZE(long_options));
     if (ret != 0) {
         print_help();

+ 12 - 26
examples/kcptun/server/main.cpp

@@ -26,40 +26,27 @@ static int mtu = 1350;
 static int sndwnd = 1024;
 static int rcvwnd = 1024;
 
-// short options
-static const char options[] = "hvdl:t:m:";
 // long options
 static const option_t long_options[] = {
-    {'h', "help",       NO_ARGUMENT},
-    {'v', "version",    NO_ARGUMENT},
-    {'d', "daemon",     NO_ARGUMENT},
-    {'l', "listen",     REQUIRED_ARGUMENT},
-    {'t', "target",     REQUIRED_ARGUMENT},
-    {'m', "mode",       REQUIRED_ARGUMENT},
-    { 0,  "mtu",        REQUIRED_ARGUMENT},
-    { 0,  "sndwnd",     REQUIRED_ARGUMENT},
-    { 0,  "rcvwnd",     REQUIRED_ARGUMENT},
+    {'h', "help",       NO_ARGUMENT,        "Print this information"},
+    {'v', "version",    NO_ARGUMENT,        "Print version"},
+    {'d', "daemon",     NO_ARGUMENT,        "Daemonize"},
+    {'l', "listen",     REQUIRED_ARGUMENT,  "kcp server listen address (default: \":4000\")"},
+    {'t', "target",     REQUIRED_ARGUMENT,  "target server address (default: \"127.0.0.1:8080\")"},
+    {'m', "mode",       REQUIRED_ARGUMENT,  "profiles: fast3, fast2, fast, normal, (default: \"fast\")"},
+    { 0,  "mtu",        REQUIRED_ARGUMENT,  "set maxinum transmission unit for UDP packets (default: 1350)"},
+    { 0,  "sndwnd",     REQUIRED_ARGUMENT,  "set send window size(num of packets) (default: 1024)"},
+    { 0,  "rcvwnd",     REQUIRED_ARGUMENT,  "set receive window size(num of packets) (default: 1024)"},
 };
 
-static const char detail_options[] = R"(
-  -h|--help                 Print this information
-  -v|--version              Print version
-  -d|--daemon               Daemonize
-  -l|--listen value         kcp server listen address (default: ":4000")
-  -t|--target value         target server address (default: "127.0.0.1:8080")
-  -m|--mode value           profiles: fast3, fast2, fast, normal (default: "fast")
-     --mtu value            set maximum transmission unit for UDP packets (default: 1350)
-     --sndwnd value         set send window size(num of packets) (default: 1024)
-     --rcvwnd value         set receive window size(num of packets) (default: 1024)
-)";
-
 static void print_version() {
     printf("%s version %s\n", g_main_ctx.program_name, hv_compile_version());
 }
 
 static void print_help() {
-    printf("Usage: %s [%s]\n", g_main_ctx.program_name, options);
-    printf("Options:\n%s\n", detail_options);
+    char detail_options[1024] = {0};
+    dump_opt_long(long_options, ARRAY_SIZE(long_options), detail_options, sizeof(detail_options));
+    printf("%s\n", detail_options);
 }
 
 static kcp_setting_t s_kcp_setting;
@@ -237,7 +224,6 @@ int main(int argc, char** argv) {
 
     // g_main_ctx
     main_ctx_init(argc, argv);
-    //int ret = parse_opt(argc, argv, options);
     int ret = parse_opt_long(argc, argv, long_options, ARRAY_SIZE(long_options));
     if (ret != 0) {
         print_help();