Indentation updates
[lttv.git] / lttv / lttv / option.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
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 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <popt.h>
24 #include <glib.h>
25 #include <lttv/module.h>
26 #include <lttv/option.h>
27
28 typedef struct _LttvOption {
29 char *long_name;
30 char char_name;
31 char *description;
32 char *arg_description;
33 LttvOptionType t;
34 gpointer p;
35 LttvOptionHook hook;
36 gpointer hook_data;
37
38 /* Keep the order of addition */
39 guint val;
40 } LttvOption;
41
42 GHashTable *options;
43
44
45 static void list_options(gpointer key, gpointer value, gpointer user_data)
46 {
47 GPtrArray *list = (GPtrArray *)user_data;
48 LttvOption *option = (LttvOption *)value;
49
50 if(list->len < option->val)
51 g_ptr_array_set_size(list, option->val);
52 list->pdata[option->val-1] = option;
53 }
54
55
56 static void free_option(LttvOption *option)
57 {
58 g_free(option->long_name);
59 g_free(option->description);
60 g_free(option->arg_description);
61 g_free(option);
62 }
63
64
65 void lttv_option_add(const char *long_name, const char char_name,
66 const char *description, const char *arg_description,
67 const LttvOptionType t, void *p,
68 const LttvOptionHook h, void *hook_data)
69 {
70 LttvOption *option;
71
72 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Add option %s", long_name);
73 if(g_hash_table_lookup(options, long_name) != NULL) {
74 g_warning("duplicate option");
75 return;
76 }
77
78 option = g_new(LttvOption, 1);
79 option->long_name = g_strdup(long_name);
80 option->char_name = char_name;
81 option->description = g_strdup(description);
82 option->arg_description = g_strdup(arg_description);
83 option->t = t;
84 option->p = p;
85 option->hook = h;
86 option->hook_data = hook_data;
87 option->val = g_hash_table_size(options) + 1;
88 g_hash_table_insert(options, option->long_name, option);
89 }
90
91
92 void lttv_option_remove(const char *long_name)
93 {
94 LttvOption *option = g_hash_table_lookup(options, long_name);
95
96 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Remove option %s", long_name);
97 if(option == NULL) {
98 g_warning("trying to remove unknown option %s", long_name);
99 return;
100 }
101 g_hash_table_remove(options, long_name);
102 free_option(option);
103 }
104
105
106 static int poptToLTT[] = {
107 POPT_ARG_NONE, POPT_ARG_STRING, POPT_ARG_INT, POPT_ARG_LONG
108 };
109
110 static struct poptOption endOption = { NULL, '\0', 0, NULL, 0, NULL, NULL };
111
112
113 static void build_popts(GPtrArray **plist, struct poptOption **ppopts,
114 poptContext *pc, int argc, char **argv)
115 {
116 LttvOption *option;
117
118 GPtrArray *list;
119
120 struct poptOption *popts;
121
122 poptContext c;
123
124 guint i;
125
126 list = g_ptr_array_sized_new(g_hash_table_size(options));
127
128 g_hash_table_foreach(options, list_options, list);
129
130 /* Build a popt options array from our list */
131
132 popts = g_new(struct poptOption, list->len + 1);
133
134 /* add the options in the reverse order, so last additions are parsed first */
135 for(i = 0 ; i < list->len ; i++) {
136 guint reverse_i = list->len-1-i;
137 option = (LttvOption *)list->pdata[i];
138 popts[reverse_i].longName = option->long_name;
139 popts[reverse_i].shortName = option->char_name;
140 popts[reverse_i].descrip = option->description;
141 popts[reverse_i].argDescrip = option->arg_description;
142 popts[reverse_i].argInfo = poptToLTT[option->t];
143 popts[reverse_i].arg = option->p;
144 popts[reverse_i].val = option->val;
145 }
146
147 /* Terminate the array for popt and create the context */
148
149 popts[list->len] = endOption;
150 c = poptGetContext(argv[0], argc, (const char**)argv, popts, 0);
151
152 *plist = list;
153 *ppopts = popts;
154 *pc = c;
155 }
156
157
158 static void destroy_popts(GPtrArray **plist, struct poptOption **ppopts,
159 poptContext *pc)
160 {
161 g_ptr_array_free(*plist, TRUE); *plist = NULL;
162 g_free(*ppopts); *ppopts = NULL;
163 poptFreeContext(*pc);
164 }
165
166
167 void lttv_option_parse(int argc, char **argv)
168 {
169 GPtrArray *list;
170
171 LttvOption *option;
172
173 int i, rc, first_arg;
174
175 struct poptOption *popts;
176
177 poptContext c;
178
179 i = 0;
180
181 first_arg = 0;
182
183 guint hash_size = 0;
184
185 build_popts(&list, &popts, &c, argc, argv);
186
187 /* Parse options while not end of options event */
188
189 while((rc = poptGetNextOpt(c)) != -1) {
190
191 /* The option was recognized and the rc value returned is the argument
192 position in the array. Call the associated hook if present. */
193
194 if(rc > 0) {
195 option = (LttvOption *)(list->pdata[rc - 1]);
196 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Option %s encountered",
197 option->long_name);
198 hash_size = g_hash_table_size(options);
199 if(option->hook != NULL) {
200 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Option %s hook called",
201 option->long_name);
202 option->hook(option->hook_data);
203 }
204 i++;
205
206 /* If the size of the option hash changed, add new options
207 * right now. It resolves the conflict of multiple same short
208 * option use.
209 */
210 if(hash_size != g_hash_table_size(options)) {
211 destroy_popts(&list, &popts, &c);
212 build_popts(&list, &popts, &c, argc, argv);
213
214 /* Get back to the same argument */
215
216 first_arg = i;
217 for(i = 0; i < first_arg; i++) {
218 rc = poptGetNextOpt(c);
219 option = (LttvOption *)(list->pdata[rc - 1]);
220 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Option %s rescanned, skipped",
221 option->long_name);
222 }
223 }
224 }
225
226 else if(rc == POPT_ERROR_BADOPT && i != first_arg) {
227 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
228 "Option %s not recognized, rescan options with new additions",
229 poptBadOption(c,0));
230
231 /* Perhaps this option is newly added, restart parsing */
232
233 destroy_popts(&list, &popts, &c);
234 build_popts(&list, &popts, &c, argc, argv);
235
236 /* Get back to the same argument */
237
238 first_arg = i;
239 for(i = 0; i < first_arg; i++) {
240 rc = poptGetNextOpt(c);
241 option = (LttvOption *)(list->pdata[rc - 1]);
242 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Option %s rescanned, skipped",
243 option->long_name);
244 }
245 }
246
247 else {
248
249 /* The option has some error and it is not because this is a newly
250 added option not recognized. */
251
252 g_error("option %s: %s", poptBadOption(c,0), poptStrerror(rc));
253 break;
254 }
255
256 }
257
258 destroy_popts(&list, &popts, &c);
259 }
260
261 /* CHECK */
262 static void show_help(LttvOption *option)
263 {
264 printf("--%s -%c argument: %s\n" , option->long_name,
265 option->char_name, option->arg_description);
266 printf(" %s\n" , option->description);
267
268 }
269
270 void lttv_option_show_help(void)
271 {
272 GPtrArray *list = g_ptr_array_new();
273
274 guint i;
275
276 g_hash_table_foreach(options, list_options, list);
277
278 printf("Built-in commands available:\n");
279 printf("\n");
280
281 for(i = 0 ; i < list->len ; i++) {
282 show_help((LttvOption *)list->pdata[i]);
283 }
284 g_ptr_array_free(list, TRUE);
285 }
286
287 static void init()
288 {
289 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Init option.c");
290 options = g_hash_table_new(g_str_hash, g_str_equal);
291 }
292
293
294 static void destroy()
295 {
296 GPtrArray *list = g_ptr_array_new();
297
298 guint i;
299
300 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Destroy option.c");
301 g_hash_table_foreach(options, list_options, list);
302 g_hash_table_destroy(options);
303
304 for(i = 0 ; i < list->len ; i++) {
305 free_option((LttvOption *)list->pdata[i]);
306 }
307 g_ptr_array_free(list, TRUE);
308 }
309
310 LTTV_MODULE("option", "Command line options processing", \
311 "Functions to add, remove and parse command line options", \
312 init, destroy)
This page took 0.035414 seconds and 4 git commands to generate.