create directories branches, tags, trunk
[lttv.git] / ltt / branches / poly / lttv / lttv / option.c
index 7532073ed95c6e9f90f902c4833c66e7694512ed..f0d44254577565d404e1720acb88a30d7b7b6479 100644 (file)
@@ -16,6 +16,9 @@
  * MA 02111-1307, USA.
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include <popt.h>
 #include <glib.h>
@@ -31,6 +34,9 @@ typedef struct _LttvOption {
   gpointer p;
   LttvOptionHook hook;
   gpointer hook_data;
+
+  /* Keep the order of addition */
+  guint val;
 } LttvOption;
 
 GHashTable *options;
@@ -39,7 +45,12 @@ GHashTable *options;
 static void
 list_options(gpointer key, gpointer value, gpointer user_data)
 {
-  g_ptr_array_add((GPtrArray *)user_data, value);
+  GPtrArray *list = (GPtrArray *)user_data;
+  LttvOption *option = (LttvOption *)value;
+
+  if(list->len < option->val)
+    g_ptr_array_set_size(list, option->val);
+  list->pdata[option->val-1] = option;
 }
 
 
@@ -75,6 +86,7 @@ void lttv_option_add(const char *long_name, const char char_name,
   option->p = p;
   option->hook = h;
   option->hook_data = hook_data;
+  option->val = g_hash_table_size(options) + 1;
   g_hash_table_insert(options, option->long_name, option);
 }
 
@@ -98,7 +110,7 @@ static int poptToLTT[] = {
   POPT_ARG_NONE, POPT_ARG_STRING, POPT_ARG_INT, POPT_ARG_LONG
 };
 
-static struct poptOption endOption = { NULL, '\0', 0, NULL, 0};
+static struct poptOption endOption = { NULL, '\0', 0, NULL, 0, NULL, NULL };
 
 
 static void 
@@ -115,7 +127,7 @@ build_popts(GPtrArray **plist, struct poptOption **ppopts, poptContext *pc,
 
   guint i;
 
-  list = g_ptr_array_new();
+  list = g_ptr_array_sized_new(g_hash_table_size(options));
 
   g_hash_table_foreach(options, list_options, list);
 
@@ -123,15 +135,17 @@ build_popts(GPtrArray **plist, struct poptOption **ppopts, poptContext *pc,
 
   popts = g_new(struct poptOption, list->len + 1);
 
+  /* add the options in the reverse order, so last additions are parsed first */
   for(i = 0 ; i < list->len ; i++) {
+    guint reverse_i = list->len-1-i;
     option = (LttvOption *)list->pdata[i];
-    popts[i].longName = option->long_name;
-    popts[i].shortName = option->char_name;
-    popts[i].descrip = option->description;
-    popts[i].argDescrip = option->arg_description;
-    popts[i].argInfo = poptToLTT[option->t];
-    popts[i].arg = option->p;
-    popts[i].val = i + 1;
+    popts[reverse_i].longName = option->long_name;
+    popts[reverse_i].shortName = option->char_name;
+    popts[reverse_i].descrip = option->description;
+    popts[reverse_i].argDescrip = option->arg_description;
+    popts[reverse_i].argInfo = poptToLTT[option->t];
+    popts[reverse_i].arg = option->p;
+    popts[reverse_i].val = option->val;
   }
 
   /* Terminate the array for popt and create the context */
@@ -170,6 +184,8 @@ void lttv_option_parse(int argc, char **argv)
 
   first_arg = 0;
 
+  guint hash_size = 0;
+
   build_popts(&list, &popts, &c, argc, argv);
 
   /* Parse options while not end of options event */
@@ -183,12 +199,32 @@ void lttv_option_parse(int argc, char **argv)
       option = (LttvOption *)(list->pdata[rc - 1]);
       g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Option %s encountered", 
           option->long_name);
+      hash_size = g_hash_table_size(options);
       if(option->hook != NULL) { 
         g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Option %s hook called", 
             option->long_name);
         option->hook(option->hook_data);
       }
       i++;
+
+      /* If the size of the option hash changed, add new options
+       * right now. It resolves the conflict of multiple same short
+       * option use.
+       */
+      if(hash_size != g_hash_table_size(options)) {
+        destroy_popts(&list, &popts, &c);
+        build_popts(&list, &popts, &c, argc, argv);
+
+        /* Get back to the same argument */
+
+        first_arg = i;
+        for(i = 0; i < first_arg; i++) {
+          rc = poptGetNextOpt(c);
+          option = (LttvOption *)(list->pdata[rc - 1]);
+          g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Option %s rescanned, skipped",
+              option->long_name);
+        }
+      }
     } 
 
     else if(rc == POPT_ERROR_BADOPT && i != first_arg) {
@@ -238,11 +274,9 @@ static void show_help(LttvOption *option)
 
 void lttv_option_show_help(void)
 {
-       LttvOption option;
-
   GPtrArray *list = g_ptr_array_new();
 
-  int i;
+  guint i;
 
   g_hash_table_foreach(options, list_options, list);
 
@@ -253,8 +287,6 @@ void lttv_option_show_help(void)
     show_help((LttvOption *)list->pdata[i]);
   }
   g_ptr_array_free(list, TRUE);
-
-
 }
 
 static void init()
@@ -266,11 +298,9 @@ static void init()
 
 static void destroy()
 {
-  LttvOption option;
-
   GPtrArray *list = g_ptr_array_new();
 
-  int i;
+  guint i;
 
   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Destroy option.c");
   g_hash_table_foreach(options, list_options, list);
This page took 0.024741 seconds and 4 git commands to generate.