premilinary add of modular user interface implementation with a few test modules.
[lttv.git] / ltt / branches / poly / lttv / option.c
diff --git a/ltt/branches/poly/lttv/option.c b/ltt/branches/poly/lttv/option.c
new file mode 100644 (file)
index 0000000..aa8656f
--- /dev/null
@@ -0,0 +1,180 @@
+
+#include <lttv/lttv.h>
+#include <popt.h>
+
+/* Extensible array of popt command line options. Modules add options as
+   they are loaded and initialized. */
+
+typedef struct _lttv_option {
+  lttv_option_hook hook;
+  void *hook_data;
+} lttv_option;
+
+extern lttv_attributes *attributes_global;
+
+static GArray *lttv_options_command;
+
+static GArray *lttv_options_command_popt;
+
+// unneeded   static lttv_key *key ;
+
+static int command_argc;
+
+static char **command_argv;
+
+/* Lists of hooks to be called at different places */
+
+static lttv_hooks
+  *hooks_options_before,
+  *hooks_options_after;
+
+static gboolean init_done = FALSE;
+
+void lttv_options_command_parse(void *hook_data, void *call_data);
+
+
+void lttv_option_init(int argc, char **argv) {
+
+  lttv_hooks *hooks_init_after;
+
+  if(init_done) return;
+  else init_done = TRUE;
+
+  command_argc = argc;
+  command_argv = argv;
+
+  hooks_options_before = lttv_hooks_new();
+  hooks_options_after = lttv_hooks_new();
+
+  lttv_attributes_set_pointer_pathname(attributes_global, 
+      "hooks/options/before", hooks_options_before);
+
+  lttv_attributes_set_pointer_pathname(attributes_global,
+      "hooks/options/after",  hooks_options_after);
+
+  lttv_options_command_popt = g_array_new(0,0,sizeof(struct poptOption));
+  lttv_options_command = g_array_new(0,0,sizeof(lttv_option));
+
+  hooks_init_after = lttv_attributes_get_pointer_pathname(attributes_global,
+                 "hooks/init/after");
+  lttv_hooks_add(hooks_init_after, lttv_options_command_parse, NULL);
+
+}
+
+void lttv_option_destroy() {
+
+  g_array_free(lttv_options_command_popt,TRUE) ;
+  g_array_free(lttv_options_command,TRUE) ;
+
+  lttv_attributes_set_pointer_pathname(attributes_global, 
+      "hooks/options/before", NULL);
+
+  lttv_attributes_set_pointer_pathname(attributes_global,
+      "hooks/options/after",  NULL);
+
+  lttv_hooks_destroy(hooks_options_before);
+  lttv_hooks_destroy(hooks_options_after);
+
+}
+
+
+static int poptToLTT[] = { 
+  POPT_ARG_NONE, POPT_ARG_STRING, POPT_ARG_INT, POPT_ARG_LONG
+};
+
+
+void lttv_option_add(char *long_name, char char_name, char *description, 
+    char *argDescription, lttv_option_type t, void *p, 
+    lttv_option_hook h, void *hook_data)
+{
+  struct poptOption poption;
+
+  lttv_option option;
+
+  poption.longName = long_name;
+  poption.shortName = char_name;
+  poption.descrip = description;
+  poption.argDescrip = argDescription;
+  poption.argInfo = poptToLTT[t];
+  poption.arg = p;
+  poption.val = lttv_options_command->len + 1;
+
+  option.hook = h;
+  option.hook_data = hook_data;
+
+  g_array_append_val(lttv_options_command_popt,poption);
+  g_array_append_val(lttv_options_command,option);
+}
+
+
+static struct poptOption endOption = { NULL, '\0', 0, NULL, 0};
+
+/* As we may load modules in the hooks called for argument processing,
+ * we have to recreate the argument context each time the
+ * lttv_options_command_popt is modified. This way we will be able to
+ * parse arguments defined by the modules
+ */
+
+void lttv_options_command_parse(void *hook_data, void *call_data) 
+{
+  int rc;
+  int lastrc;
+  poptContext c;
+  lttv_option *option;
+
+  lttv_hooks_call(hooks_options_before,NULL);
+  /* Always add then remove the null option around the get context */
+  g_array_append_val(lttv_options_command_popt, endOption);
+  /* Compiler warning caused by const char ** for command_argv in header */
+  /* Nothing we can do about it. Header should not put it const. */
+  c = poptGetContext("lttv", command_argc, (const char**)command_argv,
+      (struct poptOption *)(lttv_options_command_popt->data),0);
+
+  /* We remove the null option here to be able to add options correctly */
+  g_array_remove_index(lttv_options_command_popt,
+                 lttv_options_command_popt->len - 1);
+
+  /* There is no last good offset */
+  lastrc = -1;
+
+  /* Parse options while not end of options event */
+  while((rc = poptGetNextOpt(c)) != -1) {
+         
+    if(rc == POPT_ERROR_BADOPT) {
+      /* We need to redo the context with information added by modules */
+      g_array_append_val(lttv_options_command_popt, endOption);
+      poptFreeContext(c);  
+      c = poptGetContext("lttv", command_argc, (const char**)command_argv,
+          (struct poptOption *)lttv_options_command_popt->data,0);
+      g_array_remove_index(lttv_options_command_popt,
+                 lttv_options_command_popt->len);
+
+      /* Cut out the already parsed elements */
+      if(lastrc != -1)
+        while(poptGetNextOpt(c) != lastrc) { } ;
+      
+      /* Get the same option once again */
+      g_assert(rc = poptGetNextOpt(c) != -1) ;
+      if(rc == POPT_ERROR_BADOPT) {
+        /* If here again we have a parsing error with all context info ok,
+        * then there is a problem in the arguments themself, give up */
+        g_critical("option %s: %s", poptBadOption(c,0), poptStrerror(rc));
+       break ;
+      }
+    }
+    
+    /* Remember this offset as the last good option value */
+    lastrc = rc;
+
+    /* Execute the hook registered with this option */
+    option = ((lttv_option *)lttv_options_command->data) + rc - 1;
+    if(option->hook != NULL) option->hook(option->hook_data);
+  }
+
+  poptFreeContext(c);
+
+  lttv_hooks_call(hooks_options_after,NULL);
+  
+}
+
This page took 0.024581 seconds and 4 git commands to generate.