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 | |
| 32 | struct option *long_options = (struct option *) |
| 33 | calloc(count, sizeof(struct option)); |
| 34 | for (int i = 0; options[i].longName; i++) { |
| 35 | long_options[i].name = options[i].longName; |
| 36 | long_options[i].flag = 0; |
| 37 | |
| 38 | if (!options[i].val) { |
| 39 | fprintf(stderr, __FILE__ ": val required\n"); |
| 40 | abort(); |
| 41 | } |
| 42 | long_options[i].val = options[i].val; |
| 43 | |
| 44 | switch (options[i].argInfo) { |
| 45 | case POPT_ARG_NONE: |
| 46 | long_options[i].has_arg = no_argument; |
| 47 | break; |
| 48 | case POPT_ARG_STRING: |
| 49 | case POPT_ARG_INT: |
| 50 | if (!options[i].arg) { |
| 51 | fprintf(stderr, __FILE__ ": arg required\n"); |
| 52 | abort(); |
| 53 | } |
| 54 | long_options[i].has_arg = required_argument; |
| 55 | break; |
| 56 | default: |
| 57 | fprintf(stderr, __FILE__ ": unsupported argInfo\n"); |
| 58 | abort(); |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | poptContext con = (poptContext) calloc(1, sizeof(struct _poptContext)); |
| 63 | con->argc = argc; |
| 64 | con->argv = argv; |
| 65 | con->options = options; |
| 66 | con->long_options = long_options; |
| 67 | return con; |
| 68 | } |
| 69 | |
| 70 | poptContext poptFreeContext(poptContext con) { |
| 71 | free(con->long_options); |
| 72 | free(con); |
| 73 | return 0; |
| 74 | } |
| 75 | |
| 76 | void poptResetContext(poptContext con) { |
| 77 | optind = 1; |
| 78 | } |
| 79 | |
| 80 | void poptSetOtherOptionHelp(poptContext con, const char *text) { |
| 81 | con->otherHelp = text; |
| 82 | } |
| 83 | |
| 84 | void poptPrintUsage(poptContext con, FILE *fp, int flags) { |
| 85 | fprintf(fp, "USAGE: %s %s\n", con->argv[0], con->otherHelp); |
| 86 | int i = 0; |
| 87 | for (; con->options[i].longName; i++) { |
| 88 | fprintf(fp, "\t--%s\t%s\n", con->options[i].longName, |
| 89 | con->options[i].descrip); |
| 90 | } |
| 91 | fprintf(fp, "\n"); |
| 92 | } |
| 93 | |
| 94 | int poptGetNextOpt(poptContext con) { |
| 95 | int i = -1; |
| 96 | int res = getopt_long(con->argc, (char *const *) con->argv, "", |
| 97 | con->long_options, &i); |
| 98 | #ifdef LOCAL_DEBUG |
| 99 | fprintf(stderr, "getopt_long()=%c\n", res); |
| 100 | #endif |
| 101 | if (res == 0 || res == '?') { |
| 102 | return -1; |
| 103 | } |
| 104 | |
| 105 | // Copy over found argument value |
| 106 | switch (con->options[i].argInfo) { |
| 107 | case POPT_ARG_STRING: |
| 108 | *((char**) con->options[i].arg) = strdup(optarg); |
| 109 | break; |
| 110 | case POPT_ARG_INT: |
| 111 | *((int*) con->options[i].arg) = atoi(optarg); |
| 112 | break; |
| 113 | } |
| 114 | |
| 115 | return res; |
| 116 | } |
| 117 | |
| 118 | const char *poptGetArg(poptContext con) { |
| 119 | const char *res = con->argv[optind++]; |
| 120 | #ifdef LOCAL_DEBUG |
| 121 | fprintf(stderr, "poptGetArg()=%s\n", res); |
| 122 | #endif |
| 123 | return res; |
| 124 | } |