Browse Source

parse_opt_long

ithewei 6 years ago
parent
commit
d6400a088d
3 changed files with 224 additions and 84 deletions
  1. 148 20
      hmain.cpp
  2. 25 1
      hmain.h
  3. 51 63
      main.cpp.tmpl

+ 148 - 20
hmain.cpp

@@ -45,12 +45,18 @@ int main_ctx_init(int argc, char** argv) {
     char* argp = (char*)malloc(g_main_ctx.arg_len);
     char* argp = (char*)malloc(g_main_ctx.arg_len);
     memset(argp, 0, g_main_ctx.arg_len);
     memset(argp, 0, g_main_ctx.arg_len);
     g_main_ctx.save_argv = (char**)malloc((g_main_ctx.argc+1) * sizeof(char*));
     g_main_ctx.save_argv = (char**)malloc((g_main_ctx.argc+1) * sizeof(char*));
+    char* cmdline = (char*)malloc(g_main_ctx.arg_len);
+    g_main_ctx.cmdline = cmdline;
     for (i = 0; argv[i]; ++i) {
     for (i = 0; argv[i]; ++i) {
         g_main_ctx.save_argv[i] = argp;
         g_main_ctx.save_argv[i] = argp;
         strcpy(g_main_ctx.save_argv[i], argv[i]);
         strcpy(g_main_ctx.save_argv[i], argv[i]);
         argp += strlen(argv[i]) + 1;
         argp += strlen(argv[i]) + 1;
+
+        strcat(cmdline, argv[i]);
+        strcat(cmdline, " ");
     }
     }
     g_main_ctx.save_argv[g_main_ctx.argc] = NULL;
     g_main_ctx.save_argv[g_main_ctx.argc] = NULL;
+    g_main_ctx.cmdline[g_main_ctx.arg_len-1] = '\0';
 
 
 #if defined(OS_WIN) || defined(OS_LINUX)
 #if defined(OS_WIN) || defined(OS_LINUX)
     // save env
     // save env
@@ -82,26 +88,6 @@ int main_ctx_init(int argc, char** argv) {
     }
     }
 #endif
 #endif
 
 
-    /*
-    // print argv and envp
-    printf("---------------arg------------------------------\n");
-    for (auto& pair : g_main_ctx.arg_kv) {
-        printf("%s=%s\n", pair.first.c_str(), pair.second.c_str());
-    }
-    printf("---------------env------------------------------\n");
-    for (auto& pair : g_main_ctx.env_kv) {
-        printf("%s=%s\n", pair.first.c_str(), pair.second.c_str());
-    }
-
-    printf("PWD=%s\n", get_env("PWD"));
-    printf("USER=%s\n", get_env("USER"));
-    printf("HOME=%s\n", get_env("HOME"));
-    printf("LANG=%s\n", get_env("LANG"));
-    printf("TERM=%s\n", get_env("TERM"));
-    printf("SHELL=%s\n", get_env("SHELL"));
-    printf("================================================\n");
-    */
-
     char logpath[MAX_PATH] = {0};
     char logpath[MAX_PATH] = {0};
     snprintf(logpath, sizeof(logpath), "%s/logs", g_main_ctx.run_path);
     snprintf(logpath, sizeof(logpath), "%s/logs", g_main_ctx.run_path);
     MKDIR(logpath);
     MKDIR(logpath);
@@ -119,6 +105,148 @@ int main_ctx_init(int argc, char** argv) {
     return 0;
     return 0;
 }
 }
 
 
+#define UNDEFINED_OPTION    -1
+static int get_arg_type(int short_opt, const char* options) {
+    if (options == NULL) return UNDEFINED_OPTION;
+    const char* p = options;
+    while (*p && *p != short_opt) ++p;
+    if (*p == '\0')     return UNDEFINED_OPTION;
+    if (*(p+1) == ':')  return REQUIRED_ARGUMENT;
+    return NO_ARGUMENT;
+}
+
+int parse_opt(int argc, char** argv, const char* options) {
+    for (int i = 1; argv[i]; ++i) {
+        char* p = argv[i];
+        if (*p != '-') {
+            g_main_ctx.arg_list.push_back(argv[i]);
+            continue;
+        }
+        while (*++p) {
+            int arg_type = get_arg_type(*p, options);
+            if (arg_type == UNDEFINED_OPTION) {
+                printf("Invalid option '%c'\n", *p);
+                return -20;
+            } else if (arg_type == NO_ARGUMENT) {
+                g_main_ctx.arg_kv[std::string(p, 1)] = OPTION_ENABLE;
+                continue;
+            } else if (arg_type == REQUIRED_ARGUMENT) {
+                if (*(p+1) != '\0') {
+                    g_main_ctx.arg_kv[std::string(p, 1)] = p+1;
+                    break;
+                } else if (argv[i+1] != NULL) {
+                    g_main_ctx.arg_kv[std::string(p, 1)] = argv[++i];
+                    break;
+                } else {
+                    printf("Option '%c' requires param\n", *p);
+                    return -30;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+static const option_t* get_option(const char* opt, const option_t* long_options, int size) {
+    if (opt == NULL || long_options == NULL) return NULL;
+    int len = strlen(opt);
+    if (len == 0)   return NULL;
+    if (len == 1) {
+        for (int i = 0; i < size; ++i) {
+            if (long_options[i].short_opt == *opt) {
+                return &long_options[i];
+            }
+        }
+    } else {
+        for (int i = 0; i < size; ++i) {
+            if (strcmp(long_options[i].long_opt, opt) == 0) {
+                return &long_options[i];
+            }
+        }
+    }
+
+    return NULL;
+}
+
+#define MAX_OPTION      32
+// opt type
+#define NOPREFIX_OPTION 0
+#define SHORT_OPTION    -1
+#define LONG_OPTION     -2
+int parse_opt_long(int argc, char** argv, const option_t* long_options, int size) {
+    char opt[MAX_OPTION+1] = {0};
+    for (int i = 1; argv[i]; ++i) {
+        char* arg = argv[i];
+        int opt_type = NOPREFIX_OPTION;
+        // prefix
+        if (*arg == OPTION_PREFIX) {
+            ++arg;
+            opt_type = SHORT_OPTION;
+            if (*arg == OPTION_PREFIX) {
+                ++arg;
+                opt_type = LONG_OPTION;
+            }
+        }
+        int arg_len  = strlen(arg);
+        // delim
+        char* delim = strchr(arg, OPTION_DELIM);
+        if (delim == arg || delim == arg+arg_len-1 || delim-arg > MAX_OPTION) {
+            printf("Invalid option '%s'\n", argv[i]);
+            return -10;
+        }
+        if (delim) {
+            memcpy(opt, arg, delim-arg);
+            opt[delim-arg] = '\0';
+        } else {
+            if (opt_type == SHORT_OPTION) {
+                *opt = *arg;
+                opt[1] = '\0';
+            } else {
+                strncpy(opt, arg, MAX_OPTION);
+            }
+        }
+        // get_option
+        const option_t* pOption = get_option(opt, long_options, size);
+        if (pOption == NULL) {
+            if (delim == NULL && opt_type == NOPREFIX_OPTION) {
+                g_main_ctx.arg_list.push_back(arg);
+                continue;
+            } else {
+                printf("Invalid option: '%s'\n", argv[i]);
+                return -10;
+            }
+        }
+        const char* value = NULL;
+        if (pOption->arg_type == NO_ARGUMENT) {
+            // -h
+            value = OPTION_ENABLE;
+        } else if (pOption->arg_type == REQUIRED_ARGUMENT) {
+            if (delim) {
+                // --port=80
+                value = delim+1;
+            } else {
+                if (opt_type == SHORT_OPTION && *(arg+1) != '\0') {
+                    // p80
+                    value = arg+1;
+                } else if (argv[i+1] != NULL) {
+                    // --port 80
+                    value = argv[++i];
+                } else {
+                    printf("Option '%s' requires parament\n", opt);
+                    return -20;
+                }
+            }
+        }
+        // preferred to use short_opt as key
+        if (pOption->short_opt > 0) {
+            g_main_ctx.arg_kv[std::string(1, pOption->short_opt)] = value;
+        } else if (pOption->long_opt) {
+            g_main_ctx.arg_kv[pOption->long_opt] = value;
+        }
+    }
+    return 0;
+}
+
 const char* get_arg(const char* key) {
 const char* get_arg(const char* key) {
     auto iter = g_main_ctx.arg_kv.find(key);
     auto iter = g_main_ctx.arg_kv.find(key);
     if (iter == g_main_ctx.arg_kv.end()) {
     if (iter == g_main_ctx.arg_kv.end()) {

+ 25 - 1
hmain.h

@@ -3,6 +3,7 @@
 
 
 #include "hplatform.h"
 #include "hplatform.h"
 #include "hdef.h"
 #include "hdef.h"
+#include "hstring.h"
 
 
 typedef struct main_ctx_s {
 typedef struct main_ctx_s {
     pid_t   oldpid; // getpid_from_pidfile
     pid_t   oldpid; // getpid_from_pidfile
@@ -14,18 +15,19 @@ typedef struct main_ctx_s {
     int     arg_len;
     int     arg_len;
     char**  os_argv;
     char**  os_argv;
     char**  save_argv;
     char**  save_argv;
+    char*   cmdline;
 
 
     int     envc;
     int     envc;
     int     env_len;
     int     env_len;
     char**  os_envp;
     char**  os_envp;
     char**  save_envp;
     char**  save_envp;
 
 
-
     char    confile[MAX_PATH]; // default etc/${program}.conf
     char    confile[MAX_PATH]; // default etc/${program}.conf
     char    pidfile[MAX_PATH]; // default logs/${program}.pid
     char    pidfile[MAX_PATH]; // default logs/${program}.pid
     char    logfile[MAX_PATH]; // default logs/${program}.log
     char    logfile[MAX_PATH]; // default logs/${program}.log
 
 
     keyval_t    arg_kv;
     keyval_t    arg_kv;
+    StringList  arg_list;
     keyval_t    env_kv;
     keyval_t    env_kv;
 
 
     void*   confile_parser; // deprecated
     void*   confile_parser; // deprecated
@@ -33,7 +35,29 @@ typedef struct main_ctx_s {
 
 
 extern main_ctx_t g_main_ctx;
 extern main_ctx_t g_main_ctx;
 
 
+// arg_type
+#define NO_ARGUMENT         0
+#define REQUIRED_ARGUMENT   1
+#define OPTIONAL_ARGUMENT   2
+// option define
+#define OPTION_PREFIX   '-'
+#define OPTION_DELIM    '='
+#define OPTION_ENABLE   "on"
+#define OPTION_DISABLE  "off"
+typedef struct option_s {
+    char        short_opt;
+    const char* long_opt;
+    int         arg_type;
+} option_t;
+
 int main_ctx_init(int argc, char** argv);
 int main_ctx_init(int argc, char** argv);
+// ls -a -l
+// ls -al
+// watch -n 10 ls
+// watch -n10 ls
+int parse_opt(int argc, char** argv, const char* opt);
+// gcc -g -Wall -O3 -std=cpp main.c
+int parse_opt_long(int argc, char** argv, const option_t* long_options, int size);
 const char* get_arg(const char* key);
 const char* get_arg(const char* key);
 const char* get_env(const char* key);
 const char* get_env(const char* key);
 
 

+ 51 - 63
main.cpp.tmpl

@@ -22,7 +22,6 @@ inline void conf_ctx_init(conf_ctx_t* ctx) {
 static void print_version();
 static void print_version();
 static void print_help();
 static void print_help();
 
 
-static int  parse_cmdline(int argc, char** argv);
 static int  parse_confile(const char* confile);
 static int  parse_confile(const char* confile);
 
 
 static int  signal_init();
 static int  signal_init();
@@ -32,17 +31,27 @@ static void handle_signal();
 static void master_proc(void* userdata);
 static void master_proc(void* userdata);
 static void worker_proc(void* userdata);
 static void worker_proc(void* userdata);
 
 
-// unix short style
-static char options[] = "hvc:ts:dp:";
-static char detail_options[] = R"(
--h              : print help
--v              : print version
--c  confile     : set configure file, default etc/${program}.conf
--t              : test configure file and exit
--s  signal      : send signal to process
-                  signal=[start, stop, restart, status]
--d              : daemon
--p  port        : set listen port
+// 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}
+};
+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]
+  -d|--daemon               Daemonize
+  -p|--port <port>          Set listen port
 )";
 )";
 
 
 void print_version() {
 void print_version() {
@@ -54,56 +63,6 @@ void print_help() {
     printf("Options:\n%s\n", detail_options);
     printf("Options:\n%s\n", detail_options);
 }
 }
 
 
-#define INVALID_OPTION      -1
-#define NO_ARGUMENT         0
-#define REQUIRED_ARGUMENT   1
-#define OPTIONAL_ARGUMENT   2
-int get_option(char opt) {
-    char* p = options;
-    while (*p && *p != opt) ++p;
-    if (*p == '\0')     return INVALID_OPTION;
-    if (*(p+1) == ':')  return REQUIRED_ARGUMENT;
-    return NO_ARGUMENT;
-}
-
-int parse_cmdline(int argc, char** argv) {
-    int i = 1;
-    while (argv[i]) {
-        char* p = argv[i];
-        if (*p != '-') {
-            printf("Invalid argv[%d]: %s\n", i, argv[i]);
-            exit(-10);
-        }
-        while (*++p) {
-            switch (get_option(*p)) {
-            case INVALID_OPTION:
-                printf("Invalid option: '%c'\n", *p);
-                exit(-20);
-            case NO_ARGUMENT:
-                g_main_ctx.arg_kv[std::string(p, 1)] = "true";
-                break;
-            case REQUIRED_ARGUMENT:
-                if (*(p+1) != '\0') {
-                    g_main_ctx.arg_kv[std::string(p, 1)] = p+1;
-                    ++i;
-                    goto next_option;
-                } else if (argv[i+1] != NULL) {
-                    g_main_ctx.arg_kv[std::string(p, 1)] = argv[i+1];
-                    i += 2;
-                    goto next_option;
-                } else {
-                    printf("Option '%c' requires param\n", *p);
-                    exit(-30);
-                }
-            }
-        }
-        ++i;
-next_option:
-        continue;
-    }
-    return 0;
-}
-
 int parse_confile(const char* confile) {
 int parse_confile(const char* confile) {
     conf_ctx_init(&g_conf_ctx);
     conf_ctx_init(&g_conf_ctx);
     int ret = g_conf_ctx.parser->LoadFromFile(confile);
     int ret = g_conf_ctx.parser->LoadFromFile(confile);
@@ -292,7 +251,36 @@ void handle_signal() {
 int main(int argc, char** argv) {
 int main(int argc, char** argv) {
     // g_main_ctx
     // g_main_ctx
     main_ctx_init(argc, argv);
     main_ctx_init(argc, argv);
-    parse_cmdline(argc, argv);
+    if (argc == 1) {
+        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();
+        exit(ret);
+    }
+
+    /*
+    printf("---------------arg------------------------------\n");
+    printf("%s\n", g_main_ctx.cmdline);
+    for (auto& pair : g_main_ctx.arg_kv) {
+        printf("%s=%s\n", pair.first.c_str(), pair.second.c_str());
+    }
+    for (auto& item : g_main_ctx.arg_list) {
+        printf("%s\n", item.c_str());
+    }
+    printf("================================================\n");
+    */
+
+    /*
+    printf("---------------env------------------------------\n");
+    for (auto& pair : g_main_ctx.env_kv) {
+        printf("%s=%s\n", pair.first.c_str(), pair.second.c_str());
+    }
+    printf("================================================\n");
+    */
 
 
     // help
     // help
     if (get_arg("h")) {
     if (get_arg("h")) {