From 850b209e49e01cb304b298355bcb977577758700 Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Tue, 19 Feb 2019 15:28:33 +0100
Subject: [PATCH] Added command line option to list module parameters in built
 executables (bug 540052)

Change-Id: I477ecce4dbf03f44702c7457775e411a0b688e2a
Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
---
 compiler2/ttcn3/AST_ttcn3.cc |  6 +++++
 core/Module_list.cc          | 44 ++++++++++++++++++++++++++++++++++++
 core/Module_list.hh          |  5 ++++
 core/Parallel_main.cc        | 30 ++++++++++++++++--------
 core/Single_main.cc          | 34 +++++++++++++++++++---------
 5 files changed, 99 insertions(+), 20 deletions(-)

diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc
index f4dae1e76..c0f57ea43 100644
--- a/compiler2/ttcn3/AST_ttcn3.cc
+++ b/compiler2/ttcn3/AST_ttcn3.cc
@@ -4099,6 +4099,9 @@ namespace Ttcn {
     }
     target->functions.log_param = mputprintf(target->functions.log_param,
       "%s.log();\n", name);
+    
+    target->functions.pre_init = mputprintf(target->functions.pre_init,
+      "module_object.add_modulepar(\"%s\");\n", dispname);
   }
 
   void Def_Modulepar::generate_code(Common::CodeGenHelper& cgh) {
@@ -4272,6 +4275,9 @@ namespace Ttcn {
     }
     target->functions.log_param = mputprintf(target->functions.log_param,
       "%s.log();\n", name);
+    
+    target->functions.pre_init = mputprintf(target->functions.pre_init,
+      "module_object.add_modulepar(\"%s\");\n", dispname);
   }
 
   void Def_Modulepar_Template::generate_code(Common::CodeGenHelper& cgh) {
diff --git a/core/Module_list.cc b/core/Module_list.cc
index 658176564..116c7ac7c 100644
--- a/core/Module_list.cc
+++ b/core/Module_list.cc
@@ -417,6 +417,12 @@ void Module_List::list_testcases()
     list_iter = list_iter->list_next) list_iter->list_testcases();
 }
 
+void Module_List::list_modulepars()
+{
+  for (TTCN_Module *list_iter = list_head; list_iter != NULL;
+    list_iter = list_iter->list_next) list_iter->list_modulepars();
+}
+
 void Module_List::push_version(Text_Buf& text_buf)
 {
   int n_modules = 0;
@@ -781,6 +787,11 @@ struct TTCN_Module::testcase_list_item {
   testcase_list_item *next_testcase;
 };
 
+struct TTCN_Module::modulepar_list_item {
+  const char* name;
+  modulepar_list_item* next;
+};
+
 /** Constructor for TTCN modules */
 TTCN_Module::TTCN_Module(const char *par_module_name,
   const char *par_compilation_date,
@@ -834,6 +845,8 @@ TTCN_Module::TTCN_Module(const char *par_module_name,
 , altstep_tail(NULL)
 , testcase_head(NULL)
 , testcase_tail(NULL)
+, modulepar_head(NULL)
+, modulepar_tail(NULL)
 {
   Module_List::add_module(this);
 }
@@ -875,6 +888,8 @@ TTCN_Module::TTCN_Module(const char *par_module_name,
 , altstep_tail(NULL)
 , testcase_head(NULL)
 , testcase_tail(NULL)
+, modulepar_head(NULL)
+, modulepar_tail(NULL)
 {
   Module_List::add_module(this);
 }
@@ -914,6 +929,8 @@ TTCN_Module::TTCN_Module(const char *par_module_name,
 , altstep_tail(NULL)
 , testcase_head(NULL)
 , testcase_tail(NULL)
+, modulepar_head(NULL)
+, modulepar_tail(NULL)
 {
   Module_List::add_module(this);
  }
@@ -936,6 +953,11 @@ TTCN_Module::~TTCN_Module()
     delete testcase_head;
     testcase_head = tmp_ptr;
   }
+  while (modulepar_head != NULL) {
+    modulepar_list_item *tmp_ptr = modulepar_head->next;
+    delete modulepar_head;
+    modulepar_head = tmp_ptr;
+  }
 }
 
 void TTCN_Module::pre_init_module()
@@ -1016,6 +1038,20 @@ void TTCN_Module::add_testcase_pard(const char *testcase_name,
   testcase_tail = new_item;
 }
 
+void TTCN_Module::add_modulepar(const char* name)
+{
+  modulepar_list_item* new_item = new modulepar_list_item;
+  new_item->name = name;
+  new_item->next = NULL;
+  if (modulepar_head == NULL) {
+    modulepar_head = new_item;
+  }
+  else {
+    modulepar_tail->next = new_item;
+  }
+  modulepar_tail = new_item;
+}
+
 void TTCN_Module::execute_testcase(const char *testcase_name)
 {
   for (testcase_list_item *list_iter = testcase_head; list_iter != NULL;
@@ -1227,6 +1263,14 @@ void TTCN_Module::list_testcases()
       printf("%s.%s\n", module_name, list_iter->testcase_name);
 }
 
+void TTCN_Module::list_modulepars()
+{
+  for (modulepar_list_item *list_iter = modulepar_head; list_iter != NULL;
+       list_iter = list_iter->next) {
+    printf("%s.%s\n", module_name, list_iter->name);
+  }
+}
+
 void TTCN_Module::push_version(Text_Buf& text_buf)
 {
   text_buf.push_string(module_name);
diff --git a/core/Module_list.hh b/core/Module_list.hh
index 0e04f1e98..43e6f4275 100644
--- a/core/Module_list.hh
+++ b/core/Module_list.hh
@@ -78,6 +78,7 @@ public:
   static void clean_up_usage_stats(pthread_t thread, thread_data* data);
 #endif
   static void list_testcases();
+  static void list_modulepars();
   static void push_version(Text_Buf& text_buf);
 
   static void encode_function(Text_Buf& text_buf,
@@ -165,6 +166,8 @@ private:
   altstep_list_item *altstep_head, *altstep_tail;
   struct testcase_list_item;
   testcase_list_item *testcase_head, *testcase_tail;
+  struct modulepar_list_item;
+  modulepar_list_item *modulepar_head, *modulepar_tail;
 
   /// Copy constructor disabled
   TTCN_Module(const TTCN_Module&);
@@ -215,6 +218,7 @@ public:
     testcase_t testcase_function);
   void add_testcase_pard(const char *testcase_name,
     genericfunc_t testcase_address);
+  void add_modulepar(const char* name);
 
   void execute_testcase(const char *testcase_name);
   void execute_all_testcases();
@@ -232,6 +236,7 @@ public:
   void print_version();
   ModuleVersion* get_version() const;
   void list_testcases();
+  void list_modulepars();
   void push_version(Text_Buf& text_buf);
   size_t get_num_ns() const { return num_namespaces; }
   const namespace_t *get_ns(size_t p_index) const;
diff --git a/core/Parallel_main.cc b/core/Parallel_main.cc
index 58e3a4762..85d37d5b2 100644
--- a/core/Parallel_main.cc
+++ b/core/Parallel_main.cc
@@ -84,47 +84,54 @@ static void usage(const char* program_name)
   fprintf(stderr, "\n"
     "usage: %s [-s local_addr] MC_host MC_port\n"
     "   or  %s -l\n"
+    "   or  %s -p\n"
     "   or  %s -v\n"
     "\n"
     "OPTIONS:\n"
     "	-s local_addr:	use the given source IP address for control "
     "connections\n"
     "	-l:		list startable test cases and control parts\n"
+    "	-p:		list module parameters\n"
     "	-v:		show version and module information\n",
-    program_name, program_name, program_name);
+    program_name, program_name, program_name, program_name);
 }
 
 /** Returns whether the caller should exit immediately */
 static boolean process_options(int argc, char *argv[], int& ret_val,
     const char*& local_addr, const char*& MC_host, unsigned short& MC_port)
 {
-  boolean lflag = FALSE, sflag = FALSE, vflag = FALSE, errflag = FALSE;
+  boolean lflag = FALSE, sflag = FALSE, vflag = FALSE, pflag = FALSE,
+    errflag = FALSE;
   for ( ; ; ) {
-    int c = getopt(argc, argv, "ls:v");
+    int c = getopt(argc, argv, "ls:vp");
     if (c == -1) break;
     switch (c) {
     case 'l':
-      if (lflag || sflag || vflag) errflag = TRUE;
+      if (lflag || pflag || sflag || vflag) errflag = TRUE;
       else lflag = TRUE;
       break;
     case 's':
-      if (lflag || sflag || vflag) errflag = TRUE;
+      if (lflag || pflag || sflag || vflag) errflag = TRUE;
       else {
         local_addr = optarg;
         sflag = TRUE;
       }
       break;
     case 'v':
-      if (lflag || sflag || vflag) errflag = TRUE;
+      if (lflag || pflag || sflag || vflag) errflag = TRUE;
       else vflag = TRUE;
       break;
+    case 'p':
+      if (pflag || lflag || sflag || vflag) errflag = TRUE;
+      else pflag = TRUE;
+      break;
     default:
       errflag = TRUE;
       break;
     }
   }
 
-  if (lflag || vflag) {
+  if (lflag || vflag || pflag) {
     if (optind != argc) errflag = TRUE;
   } else {
     if (optind == argc - 2) {
@@ -145,14 +152,19 @@ static boolean process_options(int argc, char *argv[], int& ret_val,
     usage(argv[0]);
     ret_val = EXIT_FAILURE;
     return TRUE;
-  } else if (lflag) {
+  } else if (lflag || pflag) {
     // list of testcases
     try {
       // create buffer for error messages
       TTCN_Runtime::install_signal_handlers();
       TTCN_Logger::initialize_logger();
       Module_List::pre_init_modules();
-      Module_List::list_testcases();
+      if (lflag) {
+        Module_List::list_testcases();
+      }
+      else { // pflag
+        Module_List::list_modulepars();
+      }
     } catch (...) {
       ret_val = EXIT_FAILURE;
     }
diff --git a/core/Single_main.cc b/core/Single_main.cc
index 372021537..93eefd3f2 100644
--- a/core/Single_main.cc
+++ b/core/Single_main.cc
@@ -82,14 +82,16 @@ static void usage(const char* program_name)
   fprintf(stderr, "\n"
     "usage: %s [-h] [-b file] configuration_file\n"
     "   or  %s -l\n"
+    "   or  %s -p\n"
     "   or  %s -v\n"
     "\n"
     "OPTIONS:\n"
     "	-b file:	run specified batch file at start (debugger must be activated)\n"
     "	-h:		automatically halt execution at start (debugger must be activated)\n"
     "	-l:		list startable test cases and control parts\n"
+    "	-p:		list module parameters\n"
     "	-v:		show version and module information\n",
-    program_name, program_name, program_name);
+    program_name, program_name, program_name, program_name);
 }
 
 int main(int argc, char *argv[])
@@ -107,32 +109,37 @@ int main(int argc, char *argv[])
 #endif
   errno = 0;
   int c, i, ret_val = EXIT_SUCCESS;
-  boolean bflag = FALSE, hflag = FALSE, lflag = FALSE, vflag = FALSE, errflag = FALSE;
+  boolean bflag = FALSE, hflag = FALSE, lflag = FALSE, vflag = FALSE, pflag = FALSE,
+    errflag = FALSE;
   const char *config_file = NULL;
   TTCN_Module *only_runnable = Module_List::single_control_part();
 
-  while ((c = getopt(argc, argv, "b:hlv")) != -1) {
+  while ((c = getopt(argc, argv, "b:hlvp")) != -1) {
     switch (c) {
     case 'b':
-      if (bflag || lflag || vflag) errflag = TRUE; // duplicate or conflicting
+      if (bflag || lflag || vflag || pflag) errflag = TRUE; // duplicate or conflicting
       else {
         bflag = TRUE;
         ttcn3_debugger.set_initial_batch_file(optarg);
       }
       break;
     case 'h':
-      if (hflag || lflag || vflag) errflag = TRUE; // duplicate or conflicting
+      if (hflag || lflag || vflag || pflag) errflag = TRUE; // duplicate or conflicting
       else {
         hflag = TRUE;
         ttcn3_debugger.set_halt_at_start();
       }
       break;
     case 'l':
-      if (lflag || vflag) errflag = TRUE; // duplicate or conflicting
+      if (lflag || vflag || pflag || bflag || hflag) errflag = TRUE; // duplicate or conflicting
       else lflag = TRUE;
       break;
+    case 'p':
+      if (pflag || lflag || vflag || bflag || hflag) errflag = TRUE; // duplicate or conflicting
+      else pflag = TRUE;
+      break;
     case 'v':
-      if (lflag || vflag) errflag = TRUE; // duplicate or conflicting
+      if (lflag || vflag || pflag || bflag || hflag) errflag = TRUE; // duplicate or conflicting
       else vflag = TRUE;
       break;
     default:
@@ -141,8 +148,8 @@ int main(int argc, char *argv[])
   }
 
   if (!errflag) {
-    if (lflag || vflag) {
-      if (optind != argc) errflag = TRUE; // -l or -v and non-option arg
+    if (lflag || vflag || pflag) {
+      if (optind != argc) errflag = TRUE; // -l, -p or -v and non-option arg
     } else {
       if (optind > argc - 1) { // no config file argument
         errflag = (only_runnable == 0);
@@ -157,12 +164,17 @@ int main(int argc, char *argv[])
     usage(argv[0]);
     TCov::close_file();
     return EXIT_FAILURE;
-  } else if (lflag) {
+  } else if (lflag || pflag) {
     try {
       // create buffer for error messages
       TTCN_Logger::initialize_logger();
       Module_List::pre_init_modules();
-      Module_List::list_testcases();
+      if (lflag) {
+        Module_List::list_testcases();
+      }
+      else { // pflag
+        Module_List::list_modulepars();
+      }
     } catch (...) {
       ret_val = EXIT_FAILURE;
     }
-- 
GitLab