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