summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSébastien Helleu <flashcode@flashtux.org>2023-03-29 22:38:01 +0200
committerSébastien Helleu <flashcode@flashtux.org>2023-03-30 01:34:55 +0200
commit6dbfb638c6586905b3b29df9cf1e41d9166546ef (patch)
treec2604c334bfea2d5aa59ac3dea6a73f812e674ce /src
parent4548b25b78d0ba8fc61421bda88a5a79b09ff9af (diff)
downloadweechat-6dbfb638c6586905b3b29df9cf1e41d9166546ef.zip
doc: convert docgen.py to C, remove autogen files from repository, add parameter `--doc-gen`
Changes: - build of doc now requires weechat-headless, translations and all plugins - convert docgen.py to C - remove `autogen_*` files from repository - add command line parameter `--doc-gen` in `weechat-headless` to build autogen files - build .mo files with directories like the installed ones (eg: "<lang>/LC_MESSAGES/weechat.mo") - remove javascript chapter from user's guide
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/wee-config-file.h2
-rw-r--r--src/core/wee-doc.c1643
-rw-r--r--src/core/wee-doc.h25
-rw-r--r--src/core/wee-url.h1
-rw-r--r--src/core/weechat.c74
6 files changed, 1724 insertions, 22 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index e4fd70250..754c013bf 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -31,6 +31,7 @@ set(LIB_CORE_SRC
wee-crypto.c wee-crypto.h
wee-debug.c wee-debug.h
wee-dir.c wee-dir.h
+ wee-doc.c wee-doc.h
wee-eval.c wee-eval.h
wee-hashtable.c wee-hashtable.h
wee-hdata.c wee-hdata.h
diff --git a/src/core/wee-config-file.h b/src/core/wee-config-file.h
index ec5cf890e..9d56930b3 100644
--- a/src/core/wee-config-file.h
+++ b/src/core/wee-config-file.h
@@ -181,6 +181,8 @@ struct t_config_option
extern struct t_config_file *config_files;
extern struct t_config_file *last_config_file;
+extern char *config_option_type_string[];
+
extern int config_file_valid (struct t_config_file *config_file);
extern struct t_config_file *config_file_search (const char *name);
extern struct t_config_file *config_file_new (struct t_weechat_plugin *plugin,
diff --git a/src/core/wee-doc.c b/src/core/wee-doc.c
new file mode 100644
index 000000000..fa1e3ac28
--- /dev/null
+++ b/src/core/wee-doc.c
@@ -0,0 +1,1643 @@
+/*
+ * wee-doc.c - documentation generator
+ *
+ * Copyright (C) 2023 Sébastien Helleu <flashcode@flashtux.org>
+ *
+ * This file is part of WeeChat, the extensible chat client.
+ *
+ * WeeChat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * WeeChat is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with WeeChat. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libintl.h>
+#include <locale.h>
+
+#include "weechat.h"
+#include "wee-arraylist.h"
+#include "wee-command.h"
+#include "wee-config-file.h"
+#include "wee-dir.h"
+#include "wee-hashtable.h"
+#include "wee-hdata.h"
+#include "wee-hook.h"
+#include "wee-infolist.h"
+#include "wee-string.h"
+#include "wee-url.h"
+#include "wee-utf8.h"
+#include "../plugins/plugin.h"
+
+#define ESCAPE(msg) (doc_gen_escape (msg))
+#define TRANS(msg) ((msg && msg[0]) ? _(msg) : msg)
+#define TRANS_DEF(msg, def) ((msg && msg[0]) ? _(msg) : def)
+#define PLUGIN(plugin) ((plugin) ? plugin->name : "weechat")
+
+typedef int (t_doc_gen_func)(const char *path, const char *lang);
+
+int index_string_escaped;
+char *string_escaped[32];
+
+
+/*
+ * Escapes a string to display in a table: replace "|" by "\|".
+ */
+
+char *
+doc_gen_escape (const char *message)
+{
+ index_string_escaped = (index_string_escaped + 1) % 32;
+
+ if (string_escaped[index_string_escaped])
+ free (string_escaped[index_string_escaped]);
+
+ string_escaped[index_string_escaped] = string_replace (message, "|", "\\|");
+
+ return string_escaped[index_string_escaped];
+}
+
+/*
+ * Opens a file for write using:
+ * - path
+ * - doc: "api" or "user"
+ * - name
+ * - language (eg: "fr")
+ *
+ * Returns the file opened, NULL if error.
+ */
+
+FILE *
+doc_gen_open_file (const char *path, const char *doc, const char *name,
+ const char *lang)
+{
+ char filename[PATH_MAX];
+ FILE *file;
+
+ snprintf (filename, sizeof (filename),
+ "%s%s" "autogen_%s_%s.%s.adoc",
+ path, DIR_SEPARATOR, doc, name, lang);
+
+ if (weechat_debug_core >= 1)
+ printf ("Writing: %s\n", filename);
+
+ file = fopen (filename, "wb");
+ if (!file)
+ {
+ string_fprintf (stderr,
+ "doc generator: ERROR: unable to write file \"%s\"",
+ filename);
+ return NULL;
+ }
+
+ string_fprintf (
+ file,
+ "//\n"
+ "// This file is auto-generated by WeeChat.\n"
+ "// DO NOT EDIT BY HAND!\n"
+ "//\n"
+ "\n");
+
+ return file;
+}
+
+/*
+ * Checks if a command must be documented or not.
+ *
+ * All commands whose name == plugin name are documented, and all commands for
+ * these plugins are documented as well:
+ * - weechat (core)
+ * - irc
+ * - xfer
+ */
+
+int
+doc_gen_check_command (const char *plugin, const char *command)
+{
+ /* command name is the same as plugin: to document! */
+ if (strcmp (plugin, command) == 0)
+ return 1;
+
+ /* document other options only for weechat, irc, xfer */
+ return((strcmp (plugin, "weechat") == 0)
+ || (strcmp (plugin, "irc") == 0)
+ || (strcmp (plugin, "xfer") == 0)) ?
+ 1 : 0;
+}
+
+/*
+ * Compares two hooks "command" to sort by plugin / command.
+ */
+
+int
+doc_gen_hook_command_cmp_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ struct t_hook *ptr_hook1, *ptr_hook2;
+ int rc;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) arraylist;
+
+ ptr_hook1 = (struct t_hook *)pointer1;
+ ptr_hook2 = (struct t_hook *)pointer2;
+
+ rc = strcmp (PLUGIN(ptr_hook1->plugin), PLUGIN(ptr_hook2->plugin));
+ if (rc != 0)
+ return rc;
+
+ return strcmp (HOOK_COMMAND(ptr_hook1, command),
+ HOOK_COMMAND(ptr_hook2, command));
+}
+
+/*
+ * Generates files with commands.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_user_commands (const char *path, const char *lang)
+{
+ FILE *file;
+ struct t_hook *ptr_hook;
+ struct t_arraylist *list_hooks;
+ int i, list_size, length, first_cmd_plugin, first_line;
+ char old_plugin[1024], format[32], *value;
+ const char *ptr_args, *pos_pipes, *pos_next;
+
+ file = doc_gen_open_file (path, "user", "commands", lang);
+ if (!file)
+ return 0;
+
+ list_hooks = arraylist_new (64, 1, 0,
+ &doc_gen_hook_command_cmp_cb, NULL,
+ NULL, NULL);
+ for (ptr_hook = weechat_hooks[HOOK_TYPE_COMMAND]; ptr_hook;
+ ptr_hook = ptr_hook->next_hook)
+ {
+ if (doc_gen_check_command (PLUGIN(ptr_hook->plugin),
+ HOOK_COMMAND(ptr_hook, command)))
+ {
+ arraylist_add (list_hooks, ptr_hook);
+ }
+ }
+
+ old_plugin[0] = '\0';
+ first_cmd_plugin = 0;
+ list_size = arraylist_size (list_hooks);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_hook = (struct t_hook *)arraylist_get (list_hooks, i);
+ if (strcmp (PLUGIN(ptr_hook->plugin), old_plugin) != 0)
+ {
+ if (i > 0)
+ {
+ string_fprintf (
+ file,
+ "----\n"
+ "// end::%s_commands[]\n"
+ "\n",
+ old_plugin);
+ }
+ string_fprintf (
+ file,
+ "// tag::%s_commands[]\n",
+ PLUGIN(ptr_hook->plugin));
+ strcpy (old_plugin, PLUGIN(ptr_hook->plugin));
+ first_cmd_plugin = 1;
+ }
+ else
+ {
+ first_cmd_plugin = 0;
+ }
+ if (!first_cmd_plugin)
+ string_fprintf (file, "----\n\n");
+ string_fprintf (
+ file,
+ "[[command_%s_%s]]\n"
+ "* `+%s+`: %s\n"
+ "\n"
+ "----\n",
+ PLUGIN(ptr_hook->plugin),
+ HOOK_COMMAND(ptr_hook, command),
+ HOOK_COMMAND(ptr_hook, command),
+ TRANS(HOOK_COMMAND(ptr_hook, description)));
+
+ length = 1 + utf8_strlen (HOOK_COMMAND(ptr_hook, command)) + 2;
+ snprintf (format, sizeof (format), "%%-%ds%%s\n", length);
+ ptr_args = TRANS(HOOK_COMMAND(ptr_hook, args));
+ first_line = 1;
+ while (ptr_args && ptr_args[0])
+ {
+ value = NULL;
+ pos_pipes = strstr (ptr_args, "||");
+ if (pos_pipes)
+ {
+ pos_next = pos_pipes + 2;
+ while (pos_next[0] == ' ')
+ {
+ pos_next++;
+ }
+ if (pos_pipes > ptr_args)
+ {
+ pos_pipes--;
+ while ((pos_pipes > ptr_args) && (pos_pipes[0] == ' '))
+ {
+ pos_pipes--;
+ }
+ value = strndup (ptr_args, pos_pipes - ptr_args + 1);
+ }
+ }
+ else
+ {
+ value = strdup (ptr_args);
+ pos_next = NULL;
+ }
+ if (value)
+ {
+ if (first_line)
+ {
+ string_fprintf (file,
+ "/%s %s\n",
+ HOOK_COMMAND(ptr_hook, command),
+ value);
+ }
+ else
+ {
+ string_fprintf (file, format, " ", value);
+ }
+ first_line = 0;
+ free (value);
+ }
+ ptr_args = pos_next;
+ }
+ if (HOOK_COMMAND(ptr_hook, args_description)
+ && HOOK_COMMAND(ptr_hook, args_description[0]))
+ {
+ string_fprintf (file,
+ "\n%s\n",
+ TRANS(HOOK_COMMAND(ptr_hook, args_description)));
+ }
+ }
+
+ string_fprintf (
+ file,
+ "----\n"
+ "// end::%s_commands[]\n",
+ old_plugin);
+
+ arraylist_free (list_hooks);
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Checks if an option must be documented or not.
+ */
+
+int
+doc_gen_check_option (struct t_config_option *option)
+{
+ if (option->config_file->plugin
+ && (strcmp (option->config_file->plugin->name, "alias") == 0))
+ {
+ return 0;
+ }
+
+ if (option->config_file->plugin
+ && (strcmp (option->config_file->plugin->name, "trigger") == 0)
+ && (strcmp (option->section->name, "trigger") == 0))
+ {
+ return 0;
+ }
+
+ if (!option->config_file->plugin
+ && (strcmp (option->section->name, "bar") == 0))
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Compares two options to sort by plugin / command.
+ */
+
+int
+doc_gen_option_cmp_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ struct t_config_option *ptr_option1, *ptr_option2;
+ int rc;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) arraylist;
+
+ ptr_option1 = (struct t_config_option *)pointer1;
+ ptr_option2 = (struct t_config_option *)pointer2;
+
+ rc = strcmp (ptr_option1->config_file->name,
+ ptr_option2->config_file->name);
+ if (rc != 0)
+ return rc;
+
+ rc = strcmp (ptr_option1->section->name, ptr_option2->section->name);
+ if (rc != 0)
+ return rc;
+
+ return strcmp (ptr_option1->name, ptr_option2->name);
+}
+
+/*
+ * Generates files with commands.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_user_options (const char *path, const char *lang)
+{
+ FILE *file;
+ struct t_config_file *ptr_config, *old_config;
+ struct t_config_section *ptr_section;
+ struct t_config_option *ptr_option;
+ struct t_arraylist *list_options;
+ int i, list_size, index_option;
+ char *name_escaped, *desc_escaped, *values, str_values[256];
+ char *default_value, *tmp;
+
+ file = doc_gen_open_file (path, "user", "options", lang);
+ if (!file)
+ return 0;
+
+ list_options = arraylist_new (64, 1, 0,
+ &doc_gen_option_cmp_cb, NULL,
+ NULL, NULL);
+ for (ptr_config = config_files; ptr_config;
+ ptr_config = ptr_config->next_config)
+ {
+ for (ptr_section = ptr_config->sections; ptr_section;
+ ptr_section = ptr_section->next_section)
+ {
+ for (ptr_option = ptr_section->options; ptr_option;
+ ptr_option = ptr_option->next_option)
+ {
+ if (doc_gen_check_option (ptr_option))
+ arraylist_add (list_options, ptr_option);
+ }
+ }
+ }
+
+ old_config = NULL;
+ index_option = 0;
+ list_size = arraylist_size (list_options);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_option = (struct t_config_option *)arraylist_get (list_options, i);
+ if (ptr_option->config_file != old_config)
+ {
+ if (old_config)
+ {
+ string_fprintf (
+ file,
+ "// end::%s_options[]\n"
+ "\n",
+ old_config->name);
+ }
+ string_fprintf (
+ file,
+ "// tag::%s_options[]\n",
+ ptr_option->config_file->name);
+ old_config = ptr_option->config_file;
+ index_option = 0;
+ }
+ else
+ {
+ index_option++;
+ }
+ if (index_option > 0)
+ string_fprintf (file, "\n");
+ name_escaped = string_replace (ptr_option->name, ",", "_");
+ desc_escaped = (ptr_option->description) ?
+ string_replace (TRANS(ptr_option->description), "]", "\\]") :
+ strdup ("");
+ string_fprintf (file,
+ "* [[option_%s.%s.%s]] *%s.%s.%s*\n",
+ ptr_option->config_file->name,
+ ptr_option->section->name,
+ name_escaped,
+ ptr_option->config_file->name,
+ ptr_option->section->name,
+ ptr_option->name);
+ string_fprintf (file,
+ "** %s: pass:none[%s]\n",
+ _("description"),
+ desc_escaped);
+ string_fprintf (file,
+ "** %s: %s\n",
+ _("type"),
+ TRANS(config_option_type_string[ptr_option->type]));
+ switch (ptr_option->type)
+ {
+ case CONFIG_OPTION_TYPE_BOOLEAN:
+ values = strdup ("on, off");
+ break;
+ case CONFIG_OPTION_TYPE_INTEGER:
+ if (ptr_option->string_values)
+ {
+ values = string_rebuild_split_string (
+ (const char **)ptr_option->string_values, ", ", 0, -1);
+ }
+ else
+ {
+ snprintf (str_values, sizeof (str_values),
+ "%d .. %d",
+ ptr_option->min,
+ ptr_option->max);
+ values = strdup (str_values);
+ }
+ break;
+ case CONFIG_OPTION_TYPE_STRING:
+ if (ptr_option->max <= 0)
+ values = strdup (_("any string"));
+ else if (ptr_option->max == 1)
+ values = strdup (_("any char"));
+ else
+ {
+ snprintf (str_values, sizeof (str_values),
+ "%s (%s: %d)",
+ _("any string"),
+ _("max chars"),
+ ptr_option->max);
+ values = strdup (str_values);
+ }
+ break;
+ case CONFIG_OPTION_TYPE_COLOR:
+ values = strdup (command_help_option_color_values ());
+ break;
+ default:
+ values = NULL;
+ break;
+ }
+ string_fprintf (file, "** %s: %s\n", _("values"), values);
+ default_value = config_file_option_value_to_string (ptr_option,
+ 1, 0, 0);
+ if (ptr_option->type == CONFIG_OPTION_TYPE_STRING)
+ {
+ tmp = string_replace (default_value, "\"", "\\\"");
+ if (default_value)
+ free (default_value);
+ default_value = tmp;
+ }
+ string_fprintf (
+ file,
+ "** %s: `+%s%s%s+`\n",
+ _("default value"),
+ (ptr_option->type == CONFIG_OPTION_TYPE_STRING) ? "\"" : "",
+ default_value,
+ (ptr_option->type == CONFIG_OPTION_TYPE_STRING) ? "\"" : "");
+ if (name_escaped)
+ free (name_escaped);
+ if (desc_escaped)
+ free (desc_escaped);
+ if (values)
+ free (values);
+ if (default_value)
+ free (default_value);
+ }
+
+ string_fprintf (
+ file,
+ "// end::%s_options[]\n",
+ old_config->name);
+
+ arraylist_free (list_options);
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Generates files with default aliases.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_user_default_aliases (const char *path, const char *lang)
+{
+ FILE *file;
+ struct t_infolist *ptr_infolist;
+ const char *ptr_completion;
+
+ file = doc_gen_open_file (path, "user", "default_aliases", lang);
+ if (!file)
+ return 0;
+
+ string_fprintf (
+ file,
+ "// tag::default_aliases[]\n"
+ "[width=\"100%\",cols=\"2m,5m,5\",options=\"header\"]\n"
+ "|===\n"
+ "| %s | %s | %s\n"
+ "\n",
+ ESCAPE(_("Alias")),
+ ESCAPE(_("Command")),
+ ESCAPE(_("Completion")));
+
+ ptr_infolist = hook_infolist_get (NULL, "alias_default", NULL, NULL);
+ while (infolist_next (ptr_infolist))
+ {
+ ptr_completion = infolist_string(ptr_infolist, "completion");
+ string_fprintf (file,
+ "| /%s | /%s | %s\n",
+ ESCAPE(infolist_string(ptr_infolist, "name")),
+ ESCAPE(infolist_string(ptr_infolist, "command")),
+ (ptr_completion && ptr_completion[0]) ?
+ ESCAPE(ptr_completion) : "-");
+ }
+ infolist_free (ptr_infolist);
+
+ string_fprintf (file,
+ "|===\n"
+ "// end::default_aliases[]\n");
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Generates files with IRC colors.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_user_irc_colors (const char *path, const char *lang)
+{
+ FILE *file;
+ struct t_infolist *ptr_infolist;
+
+ file = doc_gen_open_file (path, "user", "irc_colors", lang);
+ if (!file)
+ return 0;
+
+ string_fprintf (
+ file,
+ "// tag::irc_colors[]\n"
+ "[width=\"50%\",cols=\"^2m,3\",options=\"header\"]\n"
+ "|===\n"
+ "| %s | %s\n"
+ "\n",
+ ESCAPE(_("IRC color")),
+ ESCAPE(_("WeeChat color")));
+
+ ptr_infolist = hook_infolist_get (NULL, "irc_color_weechat", NULL, NULL);
+ while (infolist_next (ptr_infolist))
+ {
+ string_fprintf (
+ file,
+ "| %s | %s\n",
+ ESCAPE(infolist_string(ptr_infolist, "color_irc")),
+ ESCAPE(infolist_string(ptr_infolist, "color_weechat")));
+ }
+ infolist_free (ptr_infolist);
+
+ string_fprintf (file,
+ "|===\n"
+ "// end::irc_colors[]\n");
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Compares two hooks "info" to sort by plugin / info.
+ */
+
+int
+doc_gen_hook_info_cmp_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ struct t_hook *ptr_hook1, *ptr_hook2;
+ int rc;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) arraylist;
+
+ ptr_hook1 = (struct t_hook *)pointer1;
+ ptr_hook2 = (struct t_hook *)pointer2;
+
+ rc = strcmp (PLUGIN(ptr_hook1->plugin), PLUGIN(ptr_hook2->plugin));
+ if (rc != 0)
+ return rc;
+
+ return strcmp (HOOK_INFO(ptr_hook1, info_name),
+ HOOK_INFO(ptr_hook2, info_name));
+}
+
+/*
+ * Generates files with infos.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_api_infos (const char *path, const char *lang)
+{
+ FILE *file;
+ struct t_hook *ptr_hook;
+ struct t_arraylist *list_hooks;
+ int i, list_size;
+
+ file = doc_gen_open_file (path, "api", "infos", lang);
+ if (!file)
+ return 0;
+
+ string_fprintf (
+ file,
+ "// tag::infos[]\n"
+ "[width=\"100%\",cols=\"^1,^2,6,6\",options=\"header\"]\n"
+ "|===\n"
+ "| %s | %s | %s | %s\n\n",
+ ESCAPE(_("Plugin")),
+ ESCAPE(_("Name")),
+ ESCAPE(_("Description")),
+ ESCAPE(_("Arguments")));
+
+ list_hooks = arraylist_new (64, 1, 0,
+ &doc_gen_hook_info_cmp_cb, NULL,
+ NULL, NULL);
+ for (ptr_hook = weechat_hooks[HOOK_TYPE_INFO]; ptr_hook;
+ ptr_hook = ptr_hook->next_hook)
+ {
+ arraylist_add (list_hooks, ptr_hook);
+ }
+
+ list_size = arraylist_size (list_hooks);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_hook = (struct t_hook *)arraylist_get (list_hooks, i);
+ string_fprintf (
+ file,
+ "| %s | %s | %s | %s\n\n",
+ ESCAPE(PLUGIN(ptr_hook->plugin)),
+ ESCAPE(HOOK_INFO(ptr_hook, info_name)),
+ ESCAPE(TRANS(HOOK_INFO(ptr_hook, description))),
+ ESCAPE(TRANS_DEF(HOOK_INFO(ptr_hook, args_description), "-")));
+ }
+
+ arraylist_free (list_hooks);
+
+ string_fprintf (file,
+ "|===\n"
+ "// end::infos[]\n");
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Compares two hooks "info_hashtable" to sort by plugin / info.
+ */
+
+int
+doc_gen_hook_info_hashtable_cmp_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ struct t_hook *ptr_hook1, *ptr_hook2;
+ int rc;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) arraylist;
+
+ ptr_hook1 = (struct t_hook *)pointer1;
+ ptr_hook2 = (struct t_hook *)pointer2;
+
+ rc = strcmp (PLUGIN(ptr_hook1->plugin), PLUGIN(ptr_hook2->plugin));
+ if (rc != 0)
+ return rc;
+
+ return strcmp (HOOK_INFO_HASHTABLE(ptr_hook1, info_name),
+ HOOK_INFO_HASHTABLE(ptr_hook2, info_name));
+}
+
+/*
+ * Generates files with infos_hashtable.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_api_infos_hashtable (const char *path, const char *lang)
+{
+ FILE *file;
+ struct t_hook *ptr_hook;
+ struct t_arraylist *list_hooks;
+ int i, list_size;
+
+ file = doc_gen_open_file (path, "api", "infos_hashtable", lang);
+ if (!file)
+ return 0;
+
+ string_fprintf (
+ file,
+ "// tag::infos_hashtable[]\n"
+ "[width=\"100%\",cols=\"^1,^2,6,6,8\",options=\"header\"]\n"
+ "|===\n"
+ "| %s | %s | %s | %s | %s\n\n",
+ ESCAPE(_("Plugin")),
+ ESCAPE(_("Name")),
+ ESCAPE(_("Description")),
+ ESCAPE(_("Hashtable (input)")),
+ ESCAPE(_("Hashtable (output)")));
+
+ list_hooks = arraylist_new (64, 1, 0,
+ &doc_gen_hook_info_hashtable_cmp_cb, NULL,
+ NULL, NULL);
+ for (ptr_hook = weechat_hooks[HOOK_TYPE_INFO_HASHTABLE]; ptr_hook;
+ ptr_hook = ptr_hook->next_hook)
+ {
+ arraylist_add (list_hooks, ptr_hook);
+ }
+
+ list_size = arraylist_size (list_hooks);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_hook = (struct t_hook *)arraylist_get (list_hooks, i);
+ string_fprintf (
+ file,
+ "| %s | %s | %s | %s | %s\n\n",
+ ESCAPE(PLUGIN(ptr_hook->plugin)),
+ ESCAPE(HOOK_INFO(ptr_hook, info_name)),
+ ESCAPE(TRANS(HOOK_INFO_HASHTABLE(ptr_hook, description))),
+ ESCAPE(TRANS_DEF(HOOK_INFO_HASHTABLE(ptr_hook, args_description), "-")),
+ TRANS_DEF(HOOK_INFO_HASHTABLE(ptr_hook, output_description), "-"));
+ }
+
+ arraylist_free (list_hooks);
+
+ string_fprintf (file,
+ "|===\n"
+ "// end::infos_hashtable[]\n");
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Compares two hooks "infolist" to sort by plugin / infolist.
+ */
+
+int
+doc_gen_hook_infolist_cmp_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ struct t_hook *ptr_hook1, *ptr_hook2;
+ int rc;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) arraylist;
+
+ ptr_hook1 = (struct t_hook *)pointer1;
+ ptr_hook2 = (struct t_hook *)pointer2;
+
+ rc = strcmp (PLUGIN(ptr_hook1->plugin), PLUGIN(ptr_hook2->plugin));
+ if (rc != 0)
+ return rc;
+
+ return strcmp (HOOK_INFOLIST(ptr_hook1, infolist_name),
+ HOOK_INFOLIST(ptr_hook2, infolist_name));
+}
+
+/*
+ * Generates files with infolists.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_api_infolists (const char *path, const char *lang)
+{
+ FILE *file;
+ struct t_hook *ptr_hook;
+ struct t_arraylist *list_hooks;
+ int i, list_size;
+
+ file = doc_gen_open_file (path, "api", "infolists", lang);
+ if (!file)
+ return 0;
+
+ string_fprintf (
+ file,
+ "// tag::infolists[]\n"
+ "[width=\"100%\",cols=\"^1,^2,5,5,5\",options=\"header\"]\n"
+ "|===\n"
+ "| %s | %s | %s | %s | %s\n\n",
+ ESCAPE(_("Plugin")),
+ ESCAPE(_("Name")),
+ ESCAPE(_("Description")),
+ ESCAPE(_("Pointer")),
+ ESCAPE(_("Arguments")));
+
+ list_hooks = arraylist_new (64, 1, 0,
+ &doc_gen_hook_infolist_cmp_cb, NULL,
+ NULL, NULL);
+ for (ptr_hook = weechat_hooks[HOOK_TYPE_INFOLIST]; ptr_hook;
+ ptr_hook = ptr_hook->next_hook)
+ {
+ arraylist_add (list_hooks, ptr_hook);
+ }
+
+ list_size = arraylist_size (list_hooks);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_hook = (struct t_hook *)arraylist_get (list_hooks, i);
+ string_fprintf (
+ file,
+ "| %s | %s | %s | %s | %s\n\n",
+ ESCAPE(PLUGIN(ptr_hook->plugin)),
+ ESCAPE(HOOK_INFOLIST(ptr_hook, infolist_name)),
+ ESCAPE(TRANS(HOOK_INFOLIST(ptr_hook, description))),
+ ESCAPE(TRANS_DEF(HOOK_INFOLIST(ptr_hook, pointer_description), "-")),
+ ESCAPE(TRANS_DEF(HOOK_INFOLIST(ptr_hook, args_description), "-")));
+ }
+
+ arraylist_free (list_hooks);
+
+ string_fprintf (file,
+ "|===\n"
+ "// end::infolists[]\n");
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Compares two hooks "hdata" to sort by plugin / hdata.
+ */
+
+int
+doc_gen_hook_hdata_cmp_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ struct t_hook *ptr_hook1, *ptr_hook2;
+ int rc;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) arraylist;
+
+ ptr_hook1 = (struct t_hook *)pointer1;
+ ptr_hook2 = (struct t_hook *)pointer2;
+
+ rc = strcmp (PLUGIN(ptr_hook1->plugin), PLUGIN(ptr_hook2->plugin));
+ if (rc != 0)
+ return rc;
+
+ return strcmp (HOOK_HDATA(ptr_hook1, hdata_name),
+ HOOK_HDATA(ptr_hook2, hdata_name));
+}
+
+/*
+ * Compares two hooks lists to sort by name (and lists beginning with "last_"
+ * at the end).
+ */
+
+int
+doc_gen_hdata_list_cmp_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) arraylist;
+
+ if ((strncmp ((const char *)pointer1, "last_", 5) != 0)
+ && (strncmp ((const char *)pointer2, "last_", 5) == 0))
+ {
+ return -1;
+ }
+
+ if ((strncmp ((const char *)pointer1, "last_", 5) == 0)
+ && (strncmp ((const char *)pointer2, "last_", 5) != 0))
+ {
+ return 1;
+ }
+
+ return strcmp ((const char *)pointer1, (const char *)pointer2);
+}
+
+/*
+ * Compares two hooks hdata keys to sort by offset.
+ */
+
+int
+doc_gen_hdata_key_cmp_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ int offset1, offset2;
+
+ /* make C compiler happy */
+ (void) arraylist;
+
+ offset1 = hdata_get_var_offset ((struct t_hdata *)data,
+ (const char *)pointer1);
+ offset2 = hdata_get_var_offset ((struct t_hdata *)data,
+ (const char *)pointer2);
+ return (offset1 < offset2) ?
+ -1 : ((offset1 > offset2) ? 1 : 0);
+}
+
+/*
+ * Generates content of a hdata.
+ */
+
+void
+doc_gen_api_hdata_content (FILE *file, struct t_hdata *hdata)
+{
+ const char *ptr_lists, *ptr_keys, *var_hdata, *var_array_size, *ptr_key;
+ const char *ptr_list;
+ char **lists, **keys, str_var_hdata[1024], str_var_array_size[1024];
+ int i, num_lists, num_keys, list_size;
+ struct t_arraylist *list_lists, *list_keys, *list_vars_update;
+ struct t_hashtable *hashtable;
+
+ ptr_lists = hdata_get_string (hdata, "list_keys");
+ if (ptr_lists)
+ {
+ lists = string_split (ptr_lists, ",", NULL, 0, 0, &num_lists);
+ if (lists)
+ {
+ string_fprintf (file, "| ");
+ list_lists = arraylist_new (64, 1, 0,
+ &doc_gen_hdata_list_cmp_cb, hdata,
+ NULL, NULL);
+ for (i = 0; i < num_lists; i++)
+ {
+ arraylist_add (list_lists, lists[i]);
+ }
+ list_size = arraylist_size (list_lists);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_list = (const char *)arraylist_get (list_lists, i);
+ string_fprintf (file, "_%s_ +\n", ptr_list);
+ }
+ arraylist_free (list_lists);
+ string_free_split (lists);
+ string_fprintf (file, "\n");
+ }
+ }
+ else
+ {
+ string_fprintf (file, "| -\n");
+ }
+
+ list_vars_update = arraylist_new (64, 0, 1, NULL, NULL, NULL, NULL);
+ hashtable = hashtable_new (16,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_STRING,
+ NULL, NULL);
+
+ ptr_keys = hdata_get_string (hdata, "var_keys");
+ if (ptr_keys)
+ {
+ keys = string_split (ptr_keys, ",", NULL, 0, 0, &num_keys);
+ if (keys)
+ {
+ string_fprintf (file, "| ");
+ list_keys = arraylist_new (64, 1, 0,
+ &doc_gen_hdata_key_cmp_cb, hdata,
+ NULL, NULL);
+ for (i = 0; i < num_keys; i++)
+ {
+ arraylist_add (list_keys, keys[i]);
+ }
+ list_size = arraylist_size (list_keys);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_key = (const char *)arraylist_get (list_keys, i);
+ hashtable_set (hashtable, "__update_allowed", ptr_key);
+ if (hdata_update (hdata, NULL, hashtable))
+ arraylist_add (list_vars_update, (void *)ptr_key);
+ var_array_size = hdata_get_var_array_size_string (
+ hdata, NULL, ptr_key);
+ if (var_array_size)
+ {
+ snprintf (str_var_array_size, sizeof (str_var_array_size),
+ ", array_size: \"%s\"",
+ var_array_size);
+ }
+ else
+ {
+ str_var_array_size[0] = '\0';
+ }
+ var_hdata = hdata_get_var_hdata (hdata, ptr_key);
+ if (var_hdata)
+ {
+ snprintf (str_var_hdata, sizeof (str_var_hdata),
+ ", hdata: \"%s\"",
+ var_hdata);
+ }
+ else
+ {
+ str_var_hdata[0] = '\0';
+ }
+ string_fprintf (file,
+ "_%s_   (%s%s%s) +\n",
+ ptr_key,
+ hdata_get_var_type_string (hdata, ptr_key),
+ str_var_array_size,
+ str_var_hdata);
+ }
+ hashtable_remove_all (hashtable);
+ hashtable_set (hashtable, "__create_allowed", "");
+ if (hdata_update(hdata, NULL, hashtable))
+ arraylist_add (list_vars_update, "{hdata_update_create}");
+ hashtable_remove_all (hashtable);
+ hashtable_set (hashtable, "__delete_allowed", "");
+ if (hdata_update(hdata, NULL, hashtable))
+ arraylist_add (list_vars_update, "{hdata_update_delete}");
+ list_size = arraylist_size (list_vars_update);
+ if (list_size > 0)
+ {
+ string_fprintf (file, "\n");
+ string_fprintf (file, "*%s* +\n", _("Update allowed:"));
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_key = (const char *)arraylist_get (list_vars_update, i);
+ if (ptr_key[0] == '{')
+ {
+ string_fprintf (file, "    _%s_ +\n", ptr_key);
+ }
+ else
+ {
+ string_fprintf (
+ file,
+ "    _%s_ (%s) +\n",
+ ptr_key,
+ hdata_get_var_type_string (hdata, ptr_key));
+ }
+ }
+ }
+ else
+ {
+ string_fprintf (file, "\n");
+ }
+ arraylist_free (list_keys);
+ string_free_split (keys);
+ }
+ }
+
+ hashtable_free (hashtable);
+ arraylist_free (list_vars_update);
+
+ string_fprintf (file, "\n");
+}
+
+/*
+ * Generates files with hdata.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_api_hdata (const char *path, const char *lang)
+{
+ FILE *file;
+ struct t_hook *ptr_hook;
+ struct t_arraylist *list_hooks;
+ struct t_hdata *ptr_hdata;
+ int i, list_size;
+ char str_anchor[256];
+
+ file = doc_gen_open_file (path, "api", "hdata", lang);
+ if (!file)
+ return 0;
+
+ string_fprintf (
+ file,
+ "// tag::hdata[]\n"
+ ":hdata_update_create: __create\n"
+ ":hdata_update_delete: __delete\n"
+ "[width=\"100%\",cols=\"^1,^2,2,2,5\",options=\"header\"]\n"
+ "|===\n"
+ "| %s | %s | %s | %s | %s\n\n",
+ ESCAPE(_("Plugin")),
+ ESCAPE(_("Name")),
+ ESCAPE(_("Description")),
+ ESCAPE(_("Lists")),
+ ESCAPE(_("Variables")));
+
+ list_hooks = arraylist_new (64, 1, 0,
+ &doc_gen_hook_hdata_cmp_cb, NULL,
+ NULL, NULL);
+ for (ptr_hook = weechat_hooks[HOOK_TYPE_HDATA]; ptr_hook;
+ ptr_hook = ptr_hook->next_hook)
+ {
+ arraylist_add (list_hooks, ptr_hook);
+ }
+
+ list_size = arraylist_size (list_hooks);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_hook = (struct t_hook *)arraylist_get (list_hooks, i);
+ snprintf (str_anchor, sizeof (str_anchor),
+ "hdata_%s",
+ HOOK_HDATA(ptr_hook, hdata_name));
+ string_fprintf (file,
+ "| %s\n",
+ ESCAPE(PLUGIN(ptr_hook->plugin)));
+ string_fprintf (file,
+ "| [[%s]]<<%s,%s>>\n",
+ ESCAPE(str_anchor),
+ ESCAPE(str_anchor),
+ ESCAPE(HOOK_HDATA(ptr_hook, hdata_name)));
+ string_fprintf (file,
+ "| %s\n",
+ ESCAPE(TRANS(HOOK_HDATA(ptr_hook, description))));
+ ptr_hdata = hook_hdata_get (NULL, HOOK_HDATA(ptr_hook, hdata_name));
+ if (ptr_hdata)
+ doc_gen_api_hdata_content (file, ptr_hdata);
+ }
+
+ arraylist_free (list_hooks);
+
+ string_fprintf (file,
+ "|===\n"
+ "// end::hdata[]\n");
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Compares two hooks "completion" to sort by plugin / completion.
+ */
+
+int
+doc_gen_hook_completion_cmp_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ struct t_hook *ptr_hook1, *ptr_hook2;
+ int rc;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) arraylist;
+
+ ptr_hook1 = (struct t_hook *)pointer1;
+ ptr_hook2 = (struct t_hook *)pointer2;
+
+ rc = strcmp (PLUGIN(ptr_hook1->plugin), PLUGIN(ptr_hook2->plugin));
+ if (rc != 0)
+ return rc;
+
+ return strcmp (HOOK_COMPLETION(ptr_hook1, completion_item),
+ HOOK_COMPLETION(ptr_hook2, completion_item));
+}
+
+/*
+ * Generates files with completions.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_api_completions (const char *path, const char *lang)
+{
+ FILE *file;
+ struct t_hook *ptr_hook;
+ struct t_arraylist *list_hooks;
+ int i, list_size;
+
+ file = doc_gen_open_file (path, "api", "completions", lang);
+ if (!file)
+ return 0;
+
+ string_fprintf (
+ file,
+ "// tag::completions[]\n"
+ "[width=\"100%\",cols=\"^1,^2,7\",options=\"header\"]\n"
+ "|===\n"
+ "| %s | %s | %s\n\n",
+ ESCAPE(_("Plugin")),
+ ESCAPE(_("Name")),
+ ESCAPE(_("Description")));
+
+ list_hooks = arraylist_new (64, 1, 0,
+ &doc_gen_hook_completion_cmp_cb, NULL,
+ NULL, NULL);
+ for (ptr_hook = weechat_hooks[HOOK_TYPE_COMPLETION]; ptr_hook;
+ ptr_hook = ptr_hook->next_hook)
+ {
+ arraylist_add (list_hooks, ptr_hook);
+ }
+
+ list_size = arraylist_size (list_hooks);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_hook = (struct t_hook *)arraylist_get (list_hooks, i);
+ string_fprintf (
+ file,
+ "| %s | %s | %s\n\n",
+ ESCAPE(PLUGIN(ptr_hook->plugin)),
+ ESCAPE(HOOK_COMPLETION(ptr_hook, completion_item)),
+ ESCAPE(TRANS(HOOK_COMPLETION(ptr_hook, description))));
+ }
+
+ arraylist_free (list_hooks);
+
+ string_fprintf (file,
+ "|===\n"
+ "// end::completions[]\n");
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Generates files with URL options.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_api_url_options (const char *path, const char *lang)
+{
+ FILE *file;
+ int i, j;
+ char *name, *constant;
+
+ file = doc_gen_open_file (path, "api", "url_options", lang);
+ if (!file)
+ return 0;
+
+ string_fprintf (
+ file,
+ "// tag::url_options[]\n"
+ "[width=\"100%\",cols=\"2,^1,7\",options=\"header\"]\n"
+ "|===\n"
+ "| %s | %s ^(1)^ | %s ^(2)^\n",
+ ESCAPE(_("Option")),
+ ESCAPE(_("Type")),
+ ESCAPE(_("Constants")));
+
+ for (i = 0; url_options[i].name; i++)
+ {
+ name = string_tolower (url_options[i].name);
+ string_fprintf (
+ file,
+ "\n"
+ "| %s | %s |",
+ ESCAPE(name),
+ ESCAPE(url_type_string[url_options[i].type]));
+ if (name)
+ free (name);
+ if (url_options[i].constants)
+ {
+ for (j = 0; url_options[i].constants[j].name; j++)
+ {
+ if (j > 0)
+ string_fprintf (file, ",");
+ constant = string_tolower (url_options[i].constants[j].name);
+ string_fprintf (file, " %s", constant);
+ if (constant)
+ free (constant);
+ }
+ }
+ string_fprintf (file, "\n");
+ }
+
+ string_fprintf (file,
+ "\n"
+ "|===\n"
+ "// end::url_options[]\n");
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Compares two plugins to sort by priority (descending).
+ */
+
+int
+doc_gen_plugin_cmp_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ struct t_weechat_plugin *ptr_plugin1, *ptr_plugin2;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) arraylist;
+
+ ptr_plugin1 = (struct t_weechat_plugin *)pointer1;
+ ptr_plugin2 = (struct t_weechat_plugin *)pointer2;
+
+ if (ptr_plugin1->priority != ptr_plugin2->priority)
+ return (ptr_plugin1->priority > ptr_plugin2->priority) ?
+ -1 : ((ptr_plugin1->priority < ptr_plugin2->priority) ? 1 : 0);
+
+ return strcmp (ptr_plugin1->name, ptr_plugin2->name);
+}
+
+/*
+ * Generates files with plugins priority.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_api_plugins_priority (const char *path, const char *lang)
+{
+ FILE *file;
+ struct t_weechat_plugin *ptr_plugin;
+ struct t_arraylist *list_plugins;
+ int i, index, list_size;
+
+ file = doc_gen_open_file (path, "api", "plugins_priority", lang);
+ if (!file)
+ return 0;
+
+ string_fprintf (
+ file,
+ "// tag::plugins_priority[]\n"
+ "[width=\"30%\",cols=\"1,3,2\",options=\"header\"]\n"
+ "|===\n"
+ "| %s | %s | %s\n",
+ ESCAPE(_("Rank")),
+ ESCAPE(_("Plugin")),
+ ESCAPE(_("Priority")));
+
+ list_plugins = arraylist_new (64, 1, 0,
+ &doc_gen_plugin_cmp_cb, NULL,
+ NULL, NULL);
+ for (ptr_plugin = weechat_plugins; ptr_plugin;
+ ptr_plugin = ptr_plugin->next_plugin)
+ {
+ arraylist_add (list_plugins, ptr_plugin);
+ }
+
+ index = 1;
+ list_size = arraylist_size (list_plugins);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_plugin = (struct t_weechat_plugin *)arraylist_get (list_plugins, i);
+ string_fprintf (file,
+ "| %d | %s | %d\n",
+ index,
+ ptr_plugin->name,
+ ptr_plugin->priority);
+ index++;
+ }
+
+ arraylist_free (list_plugins);
+
+ string_fprintf (file,
+ "|===\n"
+ "// end::plugins_priority[]\n");
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Compares two configurations to sort by priority (descending).
+ */
+
+int
+doc_gen_config_cmp_cb (void *data, struct t_arraylist *arraylist,
+ void *pointer1, void *pointer2)
+{
+ struct t_config_file *ptr_config1, *ptr_config2;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) arraylist;
+
+ ptr_config1 = (struct t_config_file *)pointer1;
+ ptr_config2 = (struct t_config_file *)pointer2;
+
+ if (ptr_config1->priority != ptr_config2->priority)
+ return (ptr_config1->priority > ptr_config2->priority) ?
+ -1 : ((ptr_config1->priority < ptr_config2->priority) ? 1 : 0);
+
+ return strcmp (ptr_config1->name, ptr_config2->name);
+}
+
+/*
+ * Generates files with config priority.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_gen_api_config_priority (const char *path, const char *lang)
+{
+ FILE *file;
+ struct t_config_file *ptr_config;
+ struct t_arraylist *list_configs;
+ int i, index, list_size;
+
+ file = doc_gen_open_file (path, "api", "config_priority", lang);
+ if (!file)
+ return 0;
+
+ string_fprintf (
+ file,
+ "// tag::config_priority[]\n"
+ "[width=\"30%\",cols=\"1,3,2\",options=\"header\"]\n"
+ "|===\n"
+ "| %s | %s | %s\n",
+ ESCAPE(_("Rank")),
+ ESCAPE(_("File")),
+ ESCAPE(_("Priority")));
+
+ list_configs = arraylist_new (64, 1, 0,
+ &doc_gen_config_cmp_cb, NULL,
+ NULL, NULL);
+ for (ptr_config = config_files; ptr_config;
+ ptr_config = ptr_config->next_config)
+ {
+ arraylist_add (list_configs, ptr_config);
+ }
+
+ index = 1;
+ list_size = arraylist_size (list_configs);
+ for (i = 0; i < list_size; i++)
+ {
+ ptr_config = (struct t_config_file *)arraylist_get (list_configs, i);
+ string_fprintf (file,
+ "| %d | %s.conf | %d\n",
+ index,
+ ptr_config->name,
+ ptr_config->priority);
+ index++;
+ }
+
+ arraylist_free (list_configs);
+
+ string_fprintf (file,
+ "|===\n"
+ "// end::config_priority[]\n");
+
+ fclose (file);
+
+ return 1;
+}
+
+/*
+ * Generates WeeChat files used to build documentation.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+doc_generate (const char *path)
+{
+ int i, j, rc_doc_gen, rc, num_files;
+ char *locales[] = {
+ "de_DE.UTF-8",
+ "en_US.UTF-8",
+ "fr_FR.UTF-8",
+ "it_IT.UTF-8",
+ "ja_JP.UTF-8",
+ "pl_PL.UTF-8",
+ "sr_RS.UTF-8",
+ NULL,
+ };
+ t_doc_gen_func *doc_gen_functions[] = {
+ doc_gen_user_commands,
+ doc_gen_user_options,
+ doc_gen_user_default_aliases,
+ doc_gen_user_irc_colors,
+ doc_gen_api_infos,
+ doc_gen_api_infos_hashtable,
+ doc_gen_api_infolists,
+ doc_gen_api_hdata,
+ doc_gen_api_completions,
+ doc_gen_api_url_options,
+ doc_gen_api_plugins_priority,
+ doc_gen_api_config_priority,
+ NULL,
+ };
+ char lang[3], *localedir;
+
+ rc_doc_gen = 0;
+ num_files = 0;
+
+ index_string_escaped = 0;
+ memset (string_escaped, 0, sizeof (string_escaped));
+
+ if (!weechat_plugins)
+ {
+ string_fprintf (stderr,
+ "doc generator: ERROR: plugins are not loaded\n");
+ goto end;
+ }
+
+ if (!dir_mkdir_parents (path, 0755))
+ {
+ string_fprintf (
+ stderr,
+ "doc generator: ERROR: failed to create directory \"%s\")",
+ path);
+ goto end;
+ }
+
+ /*
+ * set a specific localedir to find .mo files
+ * (this is used to generate documentation without installing WeeChat,
+ * that means no need to run `make install`)
+ */
+ localedir = getenv ("WEECHAT_DOCGEN_LOCALEDIR");
+ if (localedir && localedir[0])
+ bindtextdomain (PACKAGE, localedir);
+
+ for (i = 0; locales[i]; i++)
+ {
+ setenv ("LANGUAGE", locales[i], 1);
+ setlocale (LC_ALL, locales[i]);
+ memcpy (lang, locales[i], 2);
+ lang[2] = '\0';
+ for (j = 0; doc_gen_functions[j]; j++)
+ {
+ rc = (int) (doc_gen_functions[j] (path, lang));
+ if (!rc)
+ goto end;
+ num_files++;
+ }
+ }
+
+ printf ("doc generator: build OK: %d files written in %s\n",
+ num_files, path);
+
+ rc_doc_gen = 1;
+
+end:
+ for (i = 0; i < 32; i++)
+ {
+ if (string_escaped[i])
+ free (string_escaped[i]);
+ }
+ return rc_doc_gen;
+}
diff --git a/src/core/wee-doc.h b/src/core/wee-doc.h
new file mode 100644
index 000000000..9d3ca7788
--- /dev/null
+++ b/src/core/wee-doc.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 Sébastien Helleu <flashcode@flashtux.org>
+ *
+ * This file is part of WeeChat, the extensible chat client.
+ *
+ * WeeChat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * WeeChat is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with WeeChat. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef WEECHAT_DOC_H
+#define WEECHAT_DOC_H
+
+extern int doc_generate (const char *path);
+
+#endif /* WEECHAT_DOC_H */
diff --git a/src/core/wee-url.h b/src/core/wee-url.h
index 0c62f7476..a70e29842 100644
--- a/src/core/wee-url.h
+++ b/src/core/wee-url.h
@@ -54,6 +54,7 @@ struct t_url_file
FILE *stream; /* file stream */
};
+extern char *url_type_string[];
extern struct t_url_option url_options[];
extern int weeurl_download (const char *url, struct t_hashtable *options);
diff --git a/src/core/weechat.c b/src/core/weechat.c
index 982b41bea..eb24822c0 100644
--- a/src/core/weechat.c
+++ b/src/core/weechat.c
@@ -61,6 +61,7 @@
#include "wee-config.h"
#include "wee-debug.h"
#include "wee-dir.h"
+#include "wee-doc.h"
#include "wee-eval.h"
#include "wee-hdata.h"
#include "wee-hook.h"
@@ -86,10 +87,11 @@
#include "../plugins/plugin.h"
#include "../plugins/plugin-api.h"
-/* debug command line options */
-#define OPTION_NO_DLCLOSE 1000
-#define OPTION_NO_GNUTLS 1001
-#define OPTION_NO_GCRYPT 1002
+/* some command line options */
+#define OPTION_DOCGEN 1000
+#define OPTION_NO_DLCLOSE 1001
+#define OPTION_NO_GNUTLS 1002
+#define OPTION_NO_GCRYPT 1003
int weechat_headless = 0; /* 1 if running headless (no GUI) */
int weechat_daemon = 0; /* 1 if daemonized (no foreground) */
@@ -118,6 +120,9 @@ int weechat_locale_ok = 0; /* is locale OK? */
char *weechat_local_charset = NULL; /* example: ISO-8859-1, UTF-8 */
int weechat_server_cmd_line = 0; /* at least 1 server on cmd line */
char *weechat_force_plugin_autoload = NULL; /* force load of plugins */
+int weechat_doc_gen = 0; /* doc generation */
+char *weechat_doc_gen_path = NULL; /* path for doc generation */
+int weechat_doc_gen_ok = 0; /* doc generation was successful? */
int weechat_plugin_no_dlclose = 0; /* remove calls to dlclose for libs */
/* (useful with valgrind) */
int weechat_no_gnutls = 0; /* remove init/deinit of gnutls */
@@ -168,7 +173,8 @@ weechat_display_usage ()
stdout,
_(" -a, --no-connect disable auto-connect to servers at "
"startup\n"
- " -c, --colors display default colors in terminal\n"
+ " -c, --colors display default colors in terminal "
+ "and exit\n"
" -d, --dir <path> force a single WeeChat home directory\n"
" or 4 different directories separated "
"by colons (in this order: config, data, cache, runtime)\n"
@@ -177,8 +183,8 @@ weechat_display_usage ()
" -t, --temp-dir create a temporary WeeChat home "
"directory and delete it on exit\n"
" (incompatible with option \"-d\")\n"
- " -h, --help display this help\n"
- " -l, --license display WeeChat license\n"
+ " -h, --help display this help and exit\n"
+ " -l, --license display WeeChat license and exit\n"
" -p, --no-plugin don't load any plugin at startup\n"
" -P, --plugins <plugins> load only these plugins at startup\n"
" (see /help weechat.plugin.autoload)\n"
@@ -190,7 +196,7 @@ weechat_display_usage ()
" -s, --no-script don't load any script at startup\n"
" --upgrade upgrade WeeChat using session files "
"(see /help upgrade in WeeChat)\n"
- " -v, --version display WeeChat version\n"
+ " -v, --version display WeeChat version and exit\n"
" plugin:option option for plugin (see man weechat)\n"));
string_fprintf (stdout, "\n");
@@ -200,6 +206,10 @@ weechat_display_usage ()
string_fprintf (stdout, _("Extra options in headless mode:\n"));
string_fprintf (
stdout,
+ _(" --doc-gen <path> generate files to build "
+ "documentation and exit\n"));
+ string_fprintf (
+ stdout,
_(" --daemon run WeeChat as a daemon (fork, "
"new process group, file descriptors closed);\n"));
string_fprintf (
@@ -240,23 +250,24 @@ weechat_parse_args (int argc, char *argv[])
int opt;
struct option long_options[] = {
/* standard options */
- { "no-connect", no_argument, NULL, 'a' },
- { "colors", no_argument, NULL, 'c' },
- { "dir", required_argument, NULL, 'd' },
- { "temp-dir", no_argument, NULL, 't' },
- { "help", no_argument, NULL, 'h' },
- { "license", no_argument, NULL, 'l' },
- { "no-plugin", no_argument, NULL, 'p' },
- { "plugins", required_argument, NULL, 'P' },
- { "run-command", required_argument, NULL, 'r' },
- { "no-script", no_argument, NULL, 's' },
- { "upgrade", no_argument, NULL, 'u' },
- { "version", no_argument, NULL, 'v' },
+ { "no-connect", no_argument, NULL, 'a' },
+ { "colors", no_argument, NULL, 'c' },
+ { "dir", required_argument, NULL, 'd' },
+ { "temp-dir", no_argument, NULL, 't' },
+ { "help", no_argument, NULL, 'h' },
+ { "license", no_argument, NULL, 'l' },
+ { "no-plugin", no_argument, NULL, 'p' },
+ { "plugins", required_argument, NULL, 'P' },
+ { "run-command", required_argument, NULL, 'r' },
+ { "no-script", no_argument, NULL, 's' },
+ { "upgrade", no_argument, NULL, 'u' },
+ { "doc-gen", required_argument, NULL, OPTION_DOCGEN },
+ { "version", no_argument, NULL, 'v' },
/* debug options */
{ "no-dlclose", no_argument, NULL, OPTION_NO_DLCLOSE },
{ "no-gnutls", no_argument, NULL, OPTION_NO_GNUTLS },
{ "no-gcrypt", no_argument, NULL, OPTION_NO_GCRYPT },
- { NULL, 0, NULL, 0 },
+ { NULL, 0, NULL, 0 },
};
weechat_argv0 = (argv[0]) ? strdup (argv[0]) : NULL;
@@ -266,6 +277,7 @@ weechat_parse_args (int argc, char *argv[])
weechat_home_delete_on_exit = 0;
weechat_server_cmd_line = 0;
weechat_force_plugin_autoload = NULL;
+ weechat_doc_gen = 0;
weechat_plugin_no_dlclose = 0;
optind = 0;
@@ -330,6 +342,13 @@ weechat_parse_args (int argc, char *argv[])
case 'u': /* --upgrade */
weechat_upgrading = 1;
break;
+ case OPTION_DOCGEN: /* --doc-gen */
+ if (weechat_headless)
+ {
+ weechat_doc_gen = 1;
+ weechat_doc_gen_path = strdup (optarg);
+ }
+ break;
case 'v': /* -v / --version */
string_fprintf (stdout, version_get_version ());
fprintf (stdout, "\n");
@@ -572,9 +591,13 @@ weechat_shutdown (int return_code, int crash)
free (weechat_force_plugin_autoload);
if (weechat_startup_commands)
weelist_free (weechat_startup_commands);
+ if (weechat_doc_gen_path)
+ free (weechat_doc_gen_path);
if (crash)
abort ();
+ else if (weechat_doc_gen)
+ exit ((weechat_doc_gen_ok) ? 0 : 1);
else if (return_code >= 0)
exit (return_code);
}
@@ -650,7 +673,8 @@ weechat_init (int argc, char *argv[], void (*gui_init_cb)())
else
weechat_upgrading = 0;
}
- weechat_startup_message (); /* display WeeChat startup message */
+ if (!weechat_doc_gen)
+ weechat_startup_message (); /* display WeeChat startup message */
gui_chat_print_lines_waiting_buffer (NULL); /* display lines waiting */
weechat_term_check (); /* warning about wrong $TERM */
weechat_locale_check (); /* warning about wrong locale */
@@ -662,6 +686,12 @@ weechat_init (int argc, char *argv[], void (*gui_init_cb)())
gui_layout_window_apply (gui_layout_current, -1);
if (weechat_upgrading)
upgrade_weechat_end (); /* remove .upgrade files + signal */
+
+ if (weechat_doc_gen)
+ {
+ weechat_doc_gen_ok = doc_generate (weechat_doc_gen_path);
+ weechat_quit = 1;
+ }
}
/*