diff --git a/opal/util/convert-help-files-to-c-code.py b/opal/util/convert-help-files-to-c-code.py index 38489481371..d8814d9fb1b 100755 --- a/opal/util/convert-help-files-to-c-code.py +++ b/opal/util/convert-help-files-to-c-code.py @@ -41,8 +41,8 @@ def parse_ini_files(file_paths, verbose=False): current_section = None with open(file_path) as file: for line in file: - line = line.strip() - if line.startswith('#') or not line: + line = line.rstrip() + if line.startswith('#'): continue if line.startswith('[') and line.endswith(']'): current_section = line[1:-1] @@ -60,18 +60,24 @@ def parse_ini_files(file_paths, verbose=False): def generate_c_code(parsed_data): # Generate C code with an array of filenames and their # corresponding INI sections. - c_code = f"""// THIS FILE IS GENERATED AUTOMATICALLY! EDITS WILL BE LOST! + c_code = [] + c_code.append(f"""// THIS FILE IS GENERATED AUTOMATICALLY! EDITS WILL BE LOST! // This file generated by {sys.argv[0]} -""" +""") # Rather than escaping the C code {} in f strings, make this a # separate (non-f-string) addition to c_code. - c_code += """#include + c_code.append("""#include #include +#include + +#include "opal/util/argv.h" +#include "opal/util/show_help.h" typedef struct { const char *section; - const char *content; + const char **content; + char *joined; } ini_entry; typedef struct { @@ -79,34 +85,44 @@ def generate_c_code(parsed_data): ini_entry *entries; } file_entry; -""" +static file_entry help_files[] = {""") ini_arrays = [] file_entries = [] - for idx, (filename, sections) in enumerate(parsed_data.items()): - var_name = filename.replace('-', '_').replace('.', '_') - - ini_entries = [] - for section, content_list in sections.items(): - content = '\n'.join(content_list) - c_content = content.replace('"','\\"').replace("\n", '\\n"\n"') - ini_entries.append(f' {{ "{section}", "{c_content}" }}') - ini_entries.append(f' {{ NULL, NULL }}') - - ini_array_name = f"ini_entries_{idx}" - ini_arrays.append(f"static ini_entry {ini_array_name}[] = {{\n" + ",\n".join(ini_entries) + "\n};\n") - file_entries.append(f' {{ "{filename}", {ini_array_name} }}') - file_entries.append(f' {{ NULL, NULL }}') - - c_code += "\n".join(ini_arrays) + "\n" - c_code += "static file_entry help_files[] = {\n" + ",\n".join(file_entries) + "\n};\n" - - c_code += """ - + sp4 = f'{" " * 4}' + sp8 = f'{" " * 8}' + sp12 = f'{" " * 12}' + sp16 = f'{" " * 16}' + sp20 = f'{" " * 20}' + + for filename, sections in parsed_data.items(): + c_code.append(f'{sp4}{{') + c_code.append(f'{sp8}.filename = "{filename}",') + c_code.append(f'{sp8}.entries = (ini_entry[]) {{') + + for section_name, lines in sections.items(): + c_code.append(f'{sp12}{{') + c_code.append(f'{sp16}.section = "{section_name}",') + c_code.append(f'{sp16}.content = (const char*[]) {{') + for line in lines: + c_string = line.replace('"','\\"').replace("\n", '\\n"\n"') + c_code.append(f'{sp20}"{c_string}",') + c_code.append(f'{sp20}NULL') + c_code.append(f'{sp16}}},') + c_code.append(f'{sp12}}}, // End of section {section_name}') + + c_code.append(f'{sp12}{{0}}') + c_code.append(f'{sp8}}}, // End of file {filename}') + c_code.append(f'{sp4}}},') + + c_code.append(f'{sp4}{{0}}') + c_code.append(f'}};') + + c_code.append(""" const char *opal_show_help_get_content(const char *filename, const char* topic) { - file_entry *fe; + const file_entry *fe; ini_entry *ie; for (int i = 0; help_files[i].filename != NULL; ++i) { @@ -115,7 +131,10 @@ def generate_c_code(parsed_data): for (int j = 0; fe->entries[j].section != NULL; ++j) { ie = &(fe->entries[j]); if (strcmp(ie->section, topic) == 0) { - return ie->content; + if (NULL == ie->joined) { + ie->joined = opal_argv_join((char**)ie->content, '\\n'); + } + return ie->joined; } } } @@ -123,9 +142,21 @@ def generate_c_code(parsed_data): return NULL; } -""" - return c_code +void opal_show_help_content_free(void) +{ + for (int i = 0; help_files[i].filename != NULL; ++i) { + for (int j = 0; help_files[i].entries[j].section != NULL; j++) { + if (NULL != help_files[i].entries[j].joined) { + free(help_files[i].entries[j].joined); + help_files[i].entries[j].joined = NULL; + } + } + } +} +""") + + return '\n'.join(c_code) #------------------------------- diff --git a/opal/util/show_help.c b/opal/util/show_help.c index 33b912a19fb..a4ab63ca614 100644 --- a/opal/util/show_help.c +++ b/opal/util/show_help.c @@ -43,7 +43,6 @@ /* * Private variables */ -static const char *default_filename = "help-messages"; static const char *dash_line = "--------------------------------------------------------------------------\n"; static int output_stream = -1; @@ -95,6 +94,9 @@ static void opal_show_help_finalize(void) opal_argv_free(search_dirs); search_dirs = NULL; } + + /* free the rendered help strings */ + opal_show_help_content_free(); } static void opal_show_help_output(const char *msg) { diff --git a/opal/util/show_help.h b/opal/util/show_help.h index c497dd235cf..1a24b42c79c 100644 --- a/opal/util/show_help.h +++ b/opal/util/show_help.h @@ -179,6 +179,14 @@ OPAL_DECLSPEC int opal_show_help_add_dir(const char *directory); */ const char *opal_show_help_get_content(const char *filename, const char* topic); +/** + * \internal + * + * Free up any strings that may have been allocated in when rendering + * show_help strings. + */ +void opal_show_help_content_free(void); + END_C_DECLS #endif