Jeff Sharkey | 873988a | 2015-02-21 13:30:14 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 The Android Open Source Project |
| 3 | * |
| 4 | * This software is licensed under the terms of the GNU General Public |
| 5 | * License version 2, as published by the Free Software Foundation, and |
| 6 | * may be copied, distributed, and modified under those terms. |
| 7 | * |
| 8 | * This program is distributed in the hope that it will be useful, |
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | * GNU General Public License for more details. |
| 12 | */ |
| 13 | |
Greg Hartman | 08372d7 | 2015-02-23 20:04:52 -0800 | [diff] [blame] | 14 | #include <popt.h> |
Jeff Sharkey | 873988a | 2015-02-21 13:30:14 -0800 | [diff] [blame] | 15 | |
| 16 | // #define LOCAL_DEBUG |
| 17 | |
| 18 | /* |
| 19 | * popt has been deprecated for some time, and is replaced by GNOME's glib |
| 20 | * option parser. Instead of pulling in either of those dependencies, this |
| 21 | * stub implements just enough of popt to get things working. |
| 22 | */ |
| 23 | |
| 24 | poptContext poptGetContext(const char *name, int argc, const char **argv, |
| 25 | const struct poptOption *options, unsigned int flags) { |
| 26 | // Convert into getopt format, sanity checking our limited |
| 27 | // capabilities along the way |
| 28 | int count = 0; |
| 29 | for (; options[count].longName; count++) { |
| 30 | } |
| 31 | |
bohu | 7404144 | 2019-02-26 15:34:08 -0800 | [diff] [blame] | 32 | // getopt_long expects the last element to be null |
| 33 | // so allocate count + 1 |
Jeff Sharkey | 873988a | 2015-02-21 13:30:14 -0800 | [diff] [blame] | 34 | struct option *long_options = (struct option *) |
bohu | 7404144 | 2019-02-26 15:34:08 -0800 | [diff] [blame] | 35 | calloc(count + 1, sizeof(struct option)); |
Jeff Sharkey | 873988a | 2015-02-21 13:30:14 -0800 | [diff] [blame] | 36 | for (int i = 0; options[i].longName; i++) { |
| 37 | long_options[i].name = options[i].longName; |
| 38 | long_options[i].flag = 0; |
| 39 | |
| 40 | if (!options[i].val) { |
| 41 | fprintf(stderr, __FILE__ ": val required\n"); |
| 42 | abort(); |
| 43 | } |
| 44 | long_options[i].val = options[i].val; |
| 45 | |
| 46 | switch (options[i].argInfo) { |
| 47 | case POPT_ARG_NONE: |
| 48 | long_options[i].has_arg = no_argument; |
| 49 | break; |
| 50 | case POPT_ARG_STRING: |
| 51 | case POPT_ARG_INT: |
| 52 | if (!options[i].arg) { |
| 53 | fprintf(stderr, __FILE__ ": arg required\n"); |
| 54 | abort(); |
| 55 | } |
| 56 | long_options[i].has_arg = required_argument; |
| 57 | break; |
| 58 | default: |
| 59 | fprintf(stderr, __FILE__ ": unsupported argInfo\n"); |
| 60 | abort(); |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | poptContext con = (poptContext) calloc(1, sizeof(struct _poptContext)); |
| 65 | con->argc = argc; |
| 66 | con->argv = argv; |
| 67 | con->options = options; |
| 68 | con->long_options = long_options; |
| 69 | return con; |
| 70 | } |
| 71 | |
| 72 | poptContext poptFreeContext(poptContext con) { |
| 73 | free(con->long_options); |
| 74 | free(con); |
| 75 | return 0; |
| 76 | } |
| 77 | |
| 78 | void poptResetContext(poptContext con) { |
| 79 | optind = 1; |
| 80 | } |
| 81 | |
| 82 | void poptSetOtherOptionHelp(poptContext con, const char *text) { |
| 83 | con->otherHelp = text; |
| 84 | } |
| 85 | |
| 86 | void poptPrintUsage(poptContext con, FILE *fp, int flags) { |
| 87 | fprintf(fp, "USAGE: %s %s\n", con->argv[0], con->otherHelp); |
| 88 | int i = 0; |
| 89 | for (; con->options[i].longName; i++) { |
| 90 | fprintf(fp, "\t--%s\t%s\n", con->options[i].longName, |
| 91 | con->options[i].descrip); |
| 92 | } |
| 93 | fprintf(fp, "\n"); |
| 94 | } |
| 95 | |
| 96 | int poptGetNextOpt(poptContext con) { |
| 97 | int i = -1; |
| 98 | int res = getopt_long(con->argc, (char *const *) con->argv, "", |
| 99 | con->long_options, &i); |
| 100 | #ifdef LOCAL_DEBUG |
| 101 | fprintf(stderr, "getopt_long()=%c\n", res); |
| 102 | #endif |
bohu | 69e46b9 | 2017-08-01 11:40:14 -0700 | [diff] [blame] | 103 | if (res <= 0 || res == '?' || i == -1) { |
Jeff Sharkey | 873988a | 2015-02-21 13:30:14 -0800 | [diff] [blame] | 104 | return -1; |
| 105 | } |
| 106 | |
| 107 | // Copy over found argument value |
| 108 | switch (con->options[i].argInfo) { |
| 109 | case POPT_ARG_STRING: |
| 110 | *((char**) con->options[i].arg) = strdup(optarg); |
| 111 | break; |
| 112 | case POPT_ARG_INT: |
| 113 | *((int*) con->options[i].arg) = atoi(optarg); |
| 114 | break; |
| 115 | } |
| 116 | |
| 117 | return res; |
| 118 | } |
| 119 | |
| 120 | const char *poptGetArg(poptContext con) { |
| 121 | const char *res = con->argv[optind++]; |
| 122 | #ifdef LOCAL_DEBUG |
| 123 | fprintf(stderr, "poptGetArg()=%s\n", res); |
| 124 | #endif |
| 125 | return res; |
| 126 | } |