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 
14 #include <popt.h>
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 
poptGetContext(const char * name,int argc,const char ** argv,const struct poptOption * options,unsigned int flags)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 
poptFreeContext(poptContext con)70 poptContext poptFreeContext(poptContext con) {
71     free(con->long_options);
72     free(con);
73     return 0;
74 }
75 
poptResetContext(poptContext con)76 void poptResetContext(poptContext con) {
77     optind = 1;
78 }
79 
poptSetOtherOptionHelp(poptContext con,const char * text)80 void poptSetOtherOptionHelp(poptContext con, const char *text) {
81     con->otherHelp = text;
82 }
83 
poptPrintUsage(poptContext con,FILE * fp,int flags)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 
poptGetNextOpt(poptContext con)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 
poptGetArg(poptContext con)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 }
125