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