premilinary add of modular user interface implementation with a few test modules.
[lttv.git] / ltt / branches / poly / lttv / option.c
CommitLineData
eccb5352 1
2#include <lttv/lttv.h>
3#include <popt.h>
4
5/* Extensible array of popt command line options. Modules add options as
6 they are loaded and initialized. */
7
8typedef struct _lttv_option {
9 lttv_option_hook hook;
10 void *hook_data;
11} lttv_option;
12
13extern lttv_attributes *attributes_global;
14
15static GArray *lttv_options_command;
16
17static GArray *lttv_options_command_popt;
18
19// unneeded static lttv_key *key ;
20
21static int command_argc;
22
23static char **command_argv;
24
25/* Lists of hooks to be called at different places */
26
27static lttv_hooks
28 *hooks_options_before,
29 *hooks_options_after;
30
31static gboolean init_done = FALSE;
32
33void lttv_options_command_parse(void *hook_data, void *call_data);
34
35
36void lttv_option_init(int argc, char **argv) {
37
38 lttv_hooks *hooks_init_after;
39
40 if(init_done) return;
41 else init_done = TRUE;
42
43 command_argc = argc;
44 command_argv = argv;
45
46 hooks_options_before = lttv_hooks_new();
47 hooks_options_after = lttv_hooks_new();
48
49 lttv_attributes_set_pointer_pathname(attributes_global,
50 "hooks/options/before", hooks_options_before);
51
52 lttv_attributes_set_pointer_pathname(attributes_global,
53 "hooks/options/after", hooks_options_after);
54
55 lttv_options_command_popt = g_array_new(0,0,sizeof(struct poptOption));
56 lttv_options_command = g_array_new(0,0,sizeof(lttv_option));
57
58 hooks_init_after = lttv_attributes_get_pointer_pathname(attributes_global,
59 "hooks/init/after");
60 lttv_hooks_add(hooks_init_after, lttv_options_command_parse, NULL);
61
62}
63
64void lttv_option_destroy() {
65
66 g_array_free(lttv_options_command_popt,TRUE) ;
67 g_array_free(lttv_options_command,TRUE) ;
68
69 lttv_attributes_set_pointer_pathname(attributes_global,
70 "hooks/options/before", NULL);
71
72 lttv_attributes_set_pointer_pathname(attributes_global,
73 "hooks/options/after", NULL);
74
75 lttv_hooks_destroy(hooks_options_before);
76 lttv_hooks_destroy(hooks_options_after);
77
78}
79
80
81static int poptToLTT[] = {
82 POPT_ARG_NONE, POPT_ARG_STRING, POPT_ARG_INT, POPT_ARG_LONG
83};
84
85
86void lttv_option_add(char *long_name, char char_name, char *description,
87 char *argDescription, lttv_option_type t, void *p,
88 lttv_option_hook h, void *hook_data)
89{
90 struct poptOption poption;
91
92 lttv_option option;
93
94 poption.longName = long_name;
95 poption.shortName = char_name;
96 poption.descrip = description;
97 poption.argDescrip = argDescription;
98 poption.argInfo = poptToLTT[t];
99 poption.arg = p;
100 poption.val = lttv_options_command->len + 1;
101
102 option.hook = h;
103 option.hook_data = hook_data;
104
105 g_array_append_val(lttv_options_command_popt,poption);
106 g_array_append_val(lttv_options_command,option);
107}
108
109
110static struct poptOption endOption = { NULL, '\0', 0, NULL, 0};
111
112/* As we may load modules in the hooks called for argument processing,
113 * we have to recreate the argument context each time the
114 * lttv_options_command_popt is modified. This way we will be able to
115 * parse arguments defined by the modules
116 */
117
118void lttv_options_command_parse(void *hook_data, void *call_data)
119{
120 int rc;
121 int lastrc;
122 poptContext c;
123 lttv_option *option;
124
125 lttv_hooks_call(hooks_options_before,NULL);
126 /* Always add then remove the null option around the get context */
127 g_array_append_val(lttv_options_command_popt, endOption);
128 /* Compiler warning caused by const char ** for command_argv in header */
129 /* Nothing we can do about it. Header should not put it const. */
130 c = poptGetContext("lttv", command_argc, (const char**)command_argv,
131 (struct poptOption *)(lttv_options_command_popt->data),0);
132
133 /* We remove the null option here to be able to add options correctly */
134 g_array_remove_index(lttv_options_command_popt,
135 lttv_options_command_popt->len - 1);
136
137 /* There is no last good offset */
138 lastrc = -1;
139
140 /* Parse options while not end of options event */
141 while((rc = poptGetNextOpt(c)) != -1) {
142
143 if(rc == POPT_ERROR_BADOPT) {
144 /* We need to redo the context with information added by modules */
145 g_array_append_val(lttv_options_command_popt, endOption);
146 poptFreeContext(c);
147 c = poptGetContext("lttv", command_argc, (const char**)command_argv,
148 (struct poptOption *)lttv_options_command_popt->data,0);
149 g_array_remove_index(lttv_options_command_popt,
150 lttv_options_command_popt->len);
151
152 /* Cut out the already parsed elements */
153 if(lastrc != -1)
154 while(poptGetNextOpt(c) != lastrc) { } ;
155
156 /* Get the same option once again */
157 g_assert(rc = poptGetNextOpt(c) != -1) ;
158 if(rc == POPT_ERROR_BADOPT) {
159 /* If here again we have a parsing error with all context info ok,
160 * then there is a problem in the arguments themself, give up */
161 g_critical("option %s: %s", poptBadOption(c,0), poptStrerror(rc));
162 break ;
163 }
164 }
165
166 /* Remember this offset as the last good option value */
167 lastrc = rc;
168
169 /* Execute the hook registered with this option */
170 option = ((lttv_option *)lttv_options_command->data) + rc - 1;
171 if(option->hook != NULL) option->hook(option->hook_data);
172
173 }
174
175 poptFreeContext(c);
176
177 lttv_hooks_call(hooks_options_after,NULL);
178
179}
180
This page took 0.028054 seconds and 4 git commands to generate.