1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
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;
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.
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,
25 #include <lttv/module.h>
26 #include <lttv/option.h>
28 typedef struct _LttvOption
{
32 char *arg_description
;
38 /* Keep the order of addition */
45 static void list_options(gpointer key
, gpointer value
, gpointer user_data
)
47 GPtrArray
*list
= (GPtrArray
*)user_data
;
48 LttvOption
*option
= (LttvOption
*)value
;
50 if(list
->len
< option
->val
)
51 g_ptr_array_set_size(list
, option
->val
);
52 list
->pdata
[option
->val
-1] = option
;
56 static void free_option(LttvOption
*option
)
58 g_free(option
->long_name
);
59 g_free(option
->description
);
60 g_free(option
->arg_description
);
64 static gboolean
compare_short_option(gpointer key
,
68 LttvOption
*option
= value
;
69 const char short_option
= *(const char *)user_data
;
72 if(option
->char_name
== short_option
) {
79 void lttv_option_add(const char *long_name
, const char char_name
,
80 const char *description
, const char *arg_description
,
81 const LttvOptionType t
, void *p
,
82 const LttvOptionHook h
, void *hook_data
)
86 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Add option %s", long_name
);
87 if(g_hash_table_lookup(options
, long_name
) != NULL
) {
88 g_warning("duplicate long-option: %s", long_name
);
91 if(char_name
&& g_hash_table_find(options
, compare_short_option
, (gpointer
)&char_name
) != NULL
) {
92 g_warning("duplicate short-option: %c for option %s",
99 option
= g_new(LttvOption
, 1);
100 option
->long_name
= g_strdup(long_name
);
101 option
->char_name
= char_name
;
102 option
->description
= g_strdup(description
);
103 option
->arg_description
= g_strdup(arg_description
);
107 option
->hook_data
= hook_data
;
108 option
->val
= g_hash_table_size(options
) + 1;
109 g_hash_table_insert(options
, option
->long_name
, option
);
113 void lttv_option_remove(const char *long_name
)
115 LttvOption
*option
= g_hash_table_lookup(options
, long_name
);
117 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Remove option %s", long_name
);
119 g_warning("trying to remove unknown option %s", long_name
);
122 g_hash_table_remove(options
, long_name
);
127 static int poptToLTT
[] = {
128 POPT_ARG_NONE
, POPT_ARG_STRING
, POPT_ARG_INT
, POPT_ARG_LONG
131 static struct poptOption endOption
= { NULL
, '\0', 0, NULL
, 0, NULL
, NULL
};
134 static void build_popts(GPtrArray
**plist
, struct poptOption
**ppopts
,
135 poptContext
*pc
, int argc
, char **argv
)
141 struct poptOption
*popts
;
147 list
= g_ptr_array_sized_new(g_hash_table_size(options
));
149 g_hash_table_foreach(options
, list_options
, list
);
151 /* Build a popt options array from our list */
153 popts
= g_new(struct poptOption
, list
->len
+ 1);
155 /* add the options in the reverse order, so last additions are parsed first */
156 for(i
= 0 ; i
< list
->len
; i
++) {
157 guint reverse_i
= list
->len
-1-i
;
158 option
= (LttvOption
*)list
->pdata
[i
];
159 popts
[reverse_i
].longName
= option
->long_name
;
160 popts
[reverse_i
].shortName
= option
->char_name
;
161 popts
[reverse_i
].descrip
= option
->description
;
162 popts
[reverse_i
].argDescrip
= option
->arg_description
;
163 popts
[reverse_i
].argInfo
= poptToLTT
[option
->t
];
164 popts
[reverse_i
].arg
= option
->p
;
165 popts
[reverse_i
].val
= option
->val
;
168 /* Terminate the array for popt and create the context */
170 popts
[list
->len
] = endOption
;
171 c
= poptGetContext(argv
[0], argc
, (const char**)argv
, popts
, 0);
179 static void destroy_popts(GPtrArray
**plist
, struct poptOption
**ppopts
,
182 g_ptr_array_free(*plist
, TRUE
); *plist
= NULL
;
183 g_free(*ppopts
); *ppopts
= NULL
;
184 poptFreeContext(*pc
);
188 void lttv_option_parse(int argc
, char **argv
)
194 int i
, rc
, first_arg
;
196 struct poptOption
*popts
;
206 build_popts(&list
, &popts
, &c
, argc
, argv
);
208 /* Parse options while not end of options event */
210 while((rc
= poptGetNextOpt(c
)) != -1) {
212 /* The option was recognized and the rc value returned is the argument
213 position in the array. Call the associated hook if present. */
216 option
= (LttvOption
*)(list
->pdata
[rc
- 1]);
217 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Option %s encountered",
219 hash_size
= g_hash_table_size(options
);
220 if(option
->hook
!= NULL
) {
221 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "Option %s hook called",
223 option
->hook(option
->hook_data
);
227 /* If the size of the option hash changed, add new options
228 * right now. It resolves the conflict of multiple same short
231 if(hash_size
!= g_hash_table_size(options
)) {
232 destroy_popts(&list
, &popts
, &c
);
233 build_popts(&list
, &popts
, &c
, argc
, argv
);
235 /* Get back to the same argument */
238 for(i
= 0; i
< first_arg
; i
++) {
239 rc
= poptGetNextOpt(c
);
240 option
= (LttvOption
*)(list
->pdata
[rc
- 1]);
241 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "Option %s rescanned, skipped",
247 else if(rc
== POPT_ERROR_BADOPT
&& i
!= first_arg
) {
248 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
,
249 "Option %s not recognized, rescan options with new additions",
252 /* Perhaps this option is newly added, restart parsing */
254 destroy_popts(&list
, &popts
, &c
);
255 build_popts(&list
, &popts
, &c
, argc
, argv
);
257 /* Get back to the same argument */
260 for(i
= 0; i
< first_arg
; i
++) {
261 rc
= poptGetNextOpt(c
);
262 option
= (LttvOption
*)(list
->pdata
[rc
- 1]);
263 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "Option %s rescanned, skipped",
270 /* The option has some error and it is not because this is a newly
271 added option not recognized. */
273 g_error("option %s: %s", poptBadOption(c
,0), poptStrerror(rc
));
279 destroy_popts(&list
, &popts
, &c
);
283 static void show_help(LttvOption
*option
)
285 printf("--%s -%c argument: %s\n" , option
->long_name
,
286 option
->char_name
, option
->arg_description
);
287 printf(" %s\n" , option
->description
);
291 void lttv_option_show_help(void)
293 GPtrArray
*list
= g_ptr_array_new();
297 g_hash_table_foreach(options
, list_options
, list
);
299 printf("Built-in commands available:\n");
302 for(i
= 0 ; i
< list
->len
; i
++) {
303 show_help((LttvOption
*)list
->pdata
[i
]);
305 g_ptr_array_free(list
, TRUE
);
310 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Init option.c");
311 options
= g_hash_table_new(g_str_hash
, g_str_equal
);
315 static void destroy()
317 GPtrArray
*list
= g_ptr_array_new();
321 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Destroy option.c");
322 g_hash_table_foreach(options
, list_options
, list
);
323 g_hash_table_destroy(options
);
325 for(i
= 0 ; i
< list
->len
; i
++) {
326 free_option((LttvOption
*)list
->pdata
[i
]);
328 g_ptr_array_free(list
, TRUE
);
331 LTTV_MODULE("option", "Command line options processing", \
332 "Functions to add, remove and parse command line options", \
This page took 0.041315 seconds and 4 git commands to generate.