Changed automake files to reflect the new header files.
[lttv.git] / ltt / branches / poly / lttv / option.c
CommitLineData
1cab0928 1#include <popt.h>
eccb5352 2
fcdf0ec2 3#include <lttv/option.h>
eccb5352 4
dc877563 5typedef struct _LttvOption {
6 const char *long_name;
7 char char_name;
8 const char *description;
9 const char *arg_description;
10 LttvOptionType t;
11 gpointer p;
12 LttvOptionHook h;
13 gpointer hook_data;
14} LttvOption;
eccb5352 15
dc877563 16GHashTable *options;
eccb5352 17
eccb5352 18
dc877563 19static void
20list_options(gpointer key, gpointer value, gpointer user_data)
21{
22 g_ptr_array_add((GPtrArray *)user_data, value);
23}
eccb5352 24
eccb5352 25
dc877563 26static void
27free_option(LttvOption *option)
28{
29 g_free(option->long_name);
30 g_free(option->description);
31 g_free(option->arg_description);
32 g_free(option);
33}
eccb5352 34
eccb5352 35
dc877563 36void lttv_option_init(int argc, char **argv)
37{
38 options = g_hash_table_new(g_str_hash, g_str_equal);
39}
eccb5352 40
eccb5352 41
dc877563 42void lttv_option_destroy()
43{
44 LttvOption option;
eccb5352 45
dc877563 46 GPtrArray list = g_ptr_array_new();
eccb5352 47
dc877563 48 int i;
eccb5352 49
dc877563 50 g_hash_table_foreach(options, list_options, list);
51 g_hash_table_destroy(options);
eccb5352 52
dc877563 53 for(i = 0 ; i < list->len ; i++) {
54 free_option((LttvOption *)list->pdata[i]);
55 }
56 g_ptr_array_free(list, TRUE);
57}
eccb5352 58
eccb5352 59
dc877563 60void lttv_option_add(const char *long_name, const char char_name,
61 const char *description, const char *arg_description,
62 const LttvOptionType t, void *p,
63 const LttvOptionHook h, void *hook_data)
64{
65 LttvOption *option;
eccb5352 66
dc877563 67 if(g_hash_table_lookup(options, long_name) != NULL) {
68 g_warning("duplicate option");
69 return;
70 }
eccb5352 71
dc877563 72 option = g_new(LttvOption, 1);
73 option->long_name = g_strdup(long_name);
74 option->char_name = char_name;
75 option->description = g_strdup(description);
76 option->arg_description = g_strdup(arg_description);
77 option->t = t;
78 option->p = p;
79 option->h = h;
80 option->hook_data = hook_data;
81 g_hash_table_insert(options, option->long_name, option);
82}
eccb5352 83
eccb5352 84
dc877563 85void
86lttv_option_remove(const char *long_name)
87{
88 LttvOption *option = g_hash_table_lookup(options, long_name);
eccb5352 89
dc877563 90 if(option == NULL) {
91 g_warning("trying to remove unknown option %s", long_name);
92 return;
93 }
94 g_hash_table_remove(options, long_name);
95 free_option(option);
eccb5352 96}
97
eccb5352 98
dc877563 99static int poptToLTT[] = {
100 POPT_ARG_NONE, POPT_ARG_STRING, POPT_ARG_INT, POPT_ARG_LONG
101};
150ef81a 102
dc877563 103static struct poptOption endOption = { NULL, '\0', 0, NULL, 0};
f68ad60d 104
eccb5352 105
dc877563 106static void
107build_popts(GPtrArray **plist, struct poptOption **ppopts, poptContext *pc,
108 int argv, char **argv)
109{
110 LttvOption *option;
eccb5352 111
dc877563 112 GPtrArray *list;
eccb5352 113
dc877563 114 struct poptOption *popts;
eccb5352 115
dc877563 116 poptContext c;
eccb5352 117
dc877563 118 guint i;
eccb5352 119
dc877563 120 list = g_ptr_array_new();
eccb5352 121
dc877563 122 g_hash_table_foreach(options, list_options, list);
eccb5352 123
dc877563 124 /* Build a popt options array from our list */
eccb5352 125
dc877563 126 popts = g_new(struct poptOption, list->len + 1);
eccb5352 127
dc877563 128 for(i = 0 ; i < list->len ; i++) {
129 option = (LttvOption *)list->pdata[i];
130 popts[i].longName = option->long_name;
131 popts[i].shortName = option->char_name;
132 popts[i].descrip = option->description;
133 popts[i].argDescrip = option->arg_description;
134 popts[i].argInfo = poptToLTT[option->t];
135 popts[i].arg = option->p;
136 popts[i].val = i + 1;
137 }
138
139 /* Terminate the array for popt and create the context */
eccb5352 140
dc877563 141 popts[list->len] = endOption;
142 c = poptGetContext(argv[0], argc, (const char**)argv, popts, 0);
eccb5352 143
dc877563 144 *plist = list;
145 *ppopts = popts;
146 *pc = c;
eccb5352 147}
148
149
dc877563 150static void
151destroy_popts(GPtrArray **plist, struct poptOption **ppopts, poptContext *pc)
152{
153 g_ptr_array_free(*plist, TRUE); *plist = NULL;
154 g_free(*ppopts); *ppopts = NULL;
155 poptFreeContext(*c);
156}
eccb5352 157
eccb5352 158
dc877563 159void lttv_option_parse(int argc, char **argv)
eccb5352 160{
dc877563 161 GPtrArray *list;
162
163 LttvOption *option;
164
165 int i, rc, first_arg;
166
167 struct poptOption *popts;
168
eccb5352 169 poptContext c;
eccb5352 170
dc877563 171 i = 0;
eccb5352 172
dc877563 173 first_arg = 0;
eccb5352 174
dc877563 175 build_popts(&list, &popts, &c, argc, argv);
eccb5352 176
177 /* Parse options while not end of options event */
dc877563 178
eccb5352 179 while((rc = poptGetNextOpt(c)) != -1) {
dc877563 180
181 /* The option was recognized and the rc value returned is the argument
182 position in the array. Call the associated hook if present. */
183
184 if(rc > 0) {
185 option = (LttvOption *)(list->pdata[rc - 1]);
186 if(option->hook != NULL) option->hook(option->hook_data);
187 i++;
188 }
189
190 else if(rc == POPT_ERROR_BADOPT && i != first_arg) {
191
192 /* Perhaps this option is newly added, restart parsing */
193
194 destroy_popts(&list, &popts, &c);
195 build_popts(&list, &popts, &c, argc, argv);
196
197 /* Get back to the same argument */
198
199 first_arg = i;
200 for(i = 0; i < first_arg; i++) poptGetNextOpt(c);
eccb5352 201 }
eccb5352 202
dc877563 203 else {
eccb5352 204
dc877563 205 /* The option has some error and it is not because this is a newly
206 added option not recognized. */
eccb5352 207
dc877563 208 g_error("option %s: %s", poptBadOption(c,0), poptStrerror(rc));
209 break;
210 }
211
212 }
213
214 destroy_popts(&list, &popts, &c);
eccb5352 215}
216
This page took 0.032064 seconds and 4 git commands to generate.