mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-31 08:22:16 +01:00 
			
		
		
		
	Basically various trivial instances of the following MSVC compiler warning: ``` ../gio/gio-tool-set.c(50): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data ``` Signed-off-by: Philip Withnall <pwithnall@gnome.org>
		
			
				
	
	
		
			668 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			668 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright © 2012 Red Hat, Inc
 | |
|  *
 | |
|  * SPDX-License-Identifier: LGPL-2.1-or-later
 | |
|  *
 | |
|  * This library is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Lesser General Public
 | |
|  * License as published by the Free Software Foundation; either
 | |
|  * version 2.1 of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This library 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
 | |
|  * Lesser General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General Public
 | |
|  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | |
|  *
 | |
|  * Author: Matthias Clasen
 | |
|  */
 | |
| 
 | |
| #include "config.h"
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #include <string.h>
 | |
| #include <locale.h>
 | |
| 
 | |
| #ifdef HAVE_LIBELF
 | |
| #include <libelf.h>
 | |
| #include <gelf.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef HAVE_MMAP
 | |
| #include <sys/mman.h>
 | |
| #endif
 | |
| 
 | |
| #include <gio/gio.h>
 | |
| #include <glib/gstdio.h>
 | |
| #include <gi18n.h>
 | |
| 
 | |
| #include "glib/glib-private.h"
 | |
| 
 | |
| #if defined(HAVE_LIBELF) && defined(HAVE_MMAP)
 | |
| #define USE_LIBELF
 | |
| #endif
 | |
| 
 | |
| /* GResource functions {{{1 */
 | |
| static GResource *
 | |
| get_resource (const gchar *file)
 | |
| {
 | |
|   gchar *content;
 | |
|   gsize size;
 | |
|   GResource *resource;
 | |
|   GBytes *data;
 | |
| 
 | |
|   resource = NULL;
 | |
| 
 | |
|   if (g_file_get_contents (file, &content, &size, NULL))
 | |
|     {
 | |
|       data = g_bytes_new_take (content, size);
 | |
|       resource = g_resource_new_from_data (data, NULL);
 | |
|       g_bytes_unref (data);
 | |
|     }
 | |
| 
 | |
|   return resource;
 | |
| }
 | |
| 
 | |
| static void
 | |
| list_resource (GResource   *resource,
 | |
|                const gchar *path,
 | |
|                const gchar *section,
 | |
|                const gchar *prefix,
 | |
|                gboolean     details)
 | |
| {
 | |
|   gchar **children;
 | |
|   gsize size;
 | |
|   guint32 flags;
 | |
|   gint i;
 | |
|   gchar *child;
 | |
|   GError *error = NULL;
 | |
|   size_t len;
 | |
| 
 | |
|   children = g_resource_enumerate_children (resource, path, 0, &error);
 | |
|   if (error)
 | |
|     {
 | |
|       g_printerr ("%s\n", error->message);
 | |
|       g_error_free (error);
 | |
|       return;
 | |
|     }
 | |
|   for (i = 0; children[i]; i++)
 | |
|     {
 | |
|       child = g_strconcat (path, children[i], NULL);
 | |
| 
 | |
|       len = MIN (strlen (child), strlen (prefix));
 | |
|       if (strncmp (child, prefix, len) != 0)
 | |
|         {
 | |
|           g_free (child);
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|       if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
 | |
|         {
 | |
|           if (details)
 | |
|             g_print ("%s%s%6"G_GSIZE_FORMAT " %s %s\n", section, section[0] ? " " : "", size, (flags & G_RESOURCE_FLAGS_COMPRESSED) ? "c" : "u", child);
 | |
|           else
 | |
|             g_print ("%s\n", child);
 | |
|         }
 | |
|       else
 | |
|         list_resource (resource, child, section, prefix, details);
 | |
| 
 | |
|       g_free (child);
 | |
|     }
 | |
|   g_strfreev (children);
 | |
| }
 | |
| 
 | |
| static void
 | |
| extract_resource (GResource   *resource,
 | |
|                   const gchar *path)
 | |
| {
 | |
|   GBytes *bytes;
 | |
| 
 | |
|   bytes = g_resource_lookup_data (resource, path, 0, NULL);
 | |
|   if (bytes != NULL)
 | |
|     {
 | |
|       gconstpointer data;
 | |
|       gsize size, written;
 | |
| 
 | |
|       data = g_bytes_get_data (bytes, &size);
 | |
|       written = fwrite (data, 1, size, stdout);
 | |
|       if (written < size)
 | |
|         g_printerr ("Data truncated\n");
 | |
|       g_bytes_unref (bytes);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Elf functions {{{1 */
 | |
| 
 | |
| #ifdef USE_LIBELF
 | |
| 
 | |
| static Elf *
 | |
| get_elf (const gchar *file,
 | |
|          gint        *fd)
 | |
| {
 | |
|   Elf *elf;
 | |
| 
 | |
|   if (elf_version (EV_CURRENT) == EV_NONE )
 | |
|     return NULL;
 | |
| 
 | |
|   *fd = g_open (file, O_RDONLY, 0);
 | |
|   if (*fd < 0)
 | |
|     return NULL;
 | |
| 
 | |
|   elf = elf_begin (*fd, ELF_C_READ, NULL);
 | |
|   if (elf == NULL)
 | |
|     {
 | |
|       g_close (*fd, NULL);
 | |
|       *fd = -1;
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|   if (elf_kind (elf) != ELF_K_ELF)
 | |
|     {
 | |
|       elf_end (elf);
 | |
|       g_close (*fd, NULL);
 | |
|       *fd = -1;
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|   return elf;
 | |
| }
 | |
| 
 | |
| typedef gboolean (*SectionCallback) (GElf_Shdr   *shdr,
 | |
|                                      const gchar *name,
 | |
|                                      gpointer     data);
 | |
| 
 | |
| static void
 | |
| elf_foreach_resource_section (Elf             *elf,
 | |
|                               SectionCallback  callback,
 | |
|                               gpointer         data)
 | |
| {
 | |
|   int ret G_GNUC_UNUSED  /* when compiling with G_DISABLE_ASSERT */;
 | |
|   size_t shstrndx, shnum;
 | |
|   size_t scnidx;
 | |
|   Elf_Scn *scn;
 | |
|   GElf_Shdr *shdr, shdr_mem;
 | |
|   const gchar *section_name;
 | |
| 
 | |
|   ret = elf_getshdrstrndx (elf, &shstrndx);
 | |
|   g_assert (ret == 0);
 | |
| 
 | |
|   ret = elf_getshdrnum (elf, &shnum);
 | |
|   g_assert (ret == 0);
 | |
| 
 | |
|   for (scnidx = 1; scnidx < shnum; scnidx++)
 | |
|     {
 | |
|       scn = elf_getscn (elf, scnidx);
 | |
|       if (scn == NULL)
 | |
|         continue;
 | |
| 
 | |
|       shdr = gelf_getshdr (scn, &shdr_mem);
 | |
|       if (shdr == NULL)
 | |
|         continue;
 | |
| 
 | |
|       if (shdr->sh_type != SHT_PROGBITS)
 | |
|         continue;
 | |
| 
 | |
|       section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
 | |
|       if (section_name == NULL ||
 | |
|           !g_str_has_prefix (section_name, ".gresource."))
 | |
|         continue;
 | |
| 
 | |
|       if (!callback (shdr, section_name + strlen (".gresource."), data))
 | |
|         break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static GResource *
 | |
| resource_from_section (GElf_Shdr *shdr,
 | |
|                        int        fd)
 | |
| {
 | |
|   gsize page_size, page_offset;
 | |
|   char *contents;
 | |
|   GResource *resource;
 | |
| 
 | |
|   resource = NULL;
 | |
| 
 | |
|   page_size = sysconf(_SC_PAGE_SIZE);
 | |
|   page_offset = shdr->sh_offset % page_size;
 | |
|   contents = mmap (NULL,  shdr->sh_size + page_offset,
 | |
|                    PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
 | |
|   if (contents != MAP_FAILED)
 | |
|     {
 | |
|       GBytes *bytes;
 | |
|       GError *error = NULL;
 | |
| 
 | |
|       bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
 | |
|       resource = g_resource_new_from_data (bytes, &error);
 | |
|       g_bytes_unref (bytes);
 | |
|       if (error)
 | |
|         {
 | |
|           g_printerr ("%s\n", error->message);
 | |
|           g_error_free (error);
 | |
|         }
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_printerr ("Can't mmap resource section");
 | |
|     }
 | |
| 
 | |
|   return resource;
 | |
| }
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|   int fd;
 | |
|   const gchar *section;
 | |
|   const gchar *path;
 | |
|   gboolean details;
 | |
|   gboolean found;
 | |
| } CallbackData;
 | |
| 
 | |
| static gboolean
 | |
| list_resources_cb (GElf_Shdr   *shdr,
 | |
|                    const gchar *section,
 | |
|                    gpointer     data)
 | |
| {
 | |
|   CallbackData *d = data;
 | |
|   GResource *resource;
 | |
| 
 | |
|   if (d->section && strcmp (section, d->section) != 0)
 | |
|     return TRUE;
 | |
| 
 | |
|   d->found = TRUE;
 | |
| 
 | |
|   resource = resource_from_section (shdr, d->fd);
 | |
|   list_resource (resource, "/",
 | |
|                  d->section ? "" : section,
 | |
|                  d->path,
 | |
|                  d->details);
 | |
|   g_resource_unref (resource);
 | |
| 
 | |
|   if (d->section)
 | |
|     return FALSE;
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| elf_list_resources (Elf         *elf,
 | |
|                     int          fd,
 | |
|                     const gchar *section,
 | |
|                     const gchar *path,
 | |
|                     gboolean     details)
 | |
| {
 | |
|   CallbackData data;
 | |
| 
 | |
|   data.fd = fd;
 | |
|   data.section = section;
 | |
|   data.path = path;
 | |
|   data.details = details;
 | |
|   data.found = FALSE;
 | |
| 
 | |
|   elf_foreach_resource_section (elf, list_resources_cb, &data);
 | |
| 
 | |
|   if (!data.found)
 | |
|     g_printerr ("Can't find resource section %s\n", section);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| extract_resource_cb (GElf_Shdr   *shdr,
 | |
|                      const gchar *section,
 | |
|                      gpointer     data)
 | |
| {
 | |
|   CallbackData *d = data;
 | |
|   GResource *resource;
 | |
| 
 | |
|   if (d->section && strcmp (section, d->section) != 0)
 | |
|     return TRUE;
 | |
| 
 | |
|   d->found = TRUE;
 | |
| 
 | |
|   resource = resource_from_section (shdr, d->fd);
 | |
|   extract_resource (resource, d->path);
 | |
|   g_resource_unref (resource);
 | |
| 
 | |
|   if (d->section)
 | |
|     return FALSE;
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| elf_extract_resource (Elf         *elf,
 | |
|                       int          fd,
 | |
|                       const gchar *section,
 | |
|                       const gchar *path)
 | |
| {
 | |
|   CallbackData data;
 | |
| 
 | |
|   data.fd = fd;
 | |
|   data.section = section;
 | |
|   data.path = path;
 | |
|   data.found = FALSE;
 | |
| 
 | |
|   elf_foreach_resource_section (elf, extract_resource_cb, &data);
 | |
| 
 | |
|   if (!data.found)
 | |
|     g_printerr ("Can't find resource section %s\n", section);
 | |
| }
 | |
| 
 | |
| static gboolean
 | |
| print_section_name (GElf_Shdr   *shdr,
 | |
|                     const gchar *name,
 | |
|                     gpointer     data)
 | |
| {
 | |
|   g_print ("%s\n", name);
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| #endif /* USE_LIBELF */
 | |
| 
 | |
|   /* Toplevel commands {{{1 */
 | |
| 
 | |
| static void
 | |
| cmd_sections (const gchar *file,
 | |
|               const gchar *section,
 | |
|               const gchar *path,
 | |
|               gboolean     details)
 | |
| {
 | |
|   GResource *resource;
 | |
| 
 | |
| #ifdef USE_LIBELF
 | |
| 
 | |
|   Elf *elf;
 | |
|   gint fd;
 | |
| 
 | |
|   if ((elf = get_elf (file, &fd)))
 | |
|     {
 | |
|       elf_foreach_resource_section (elf, print_section_name, NULL);
 | |
|       elf_end (elf);
 | |
|       close (fd);
 | |
|     }
 | |
|   else
 | |
| 
 | |
| #endif
 | |
| 
 | |
|   if ((resource = get_resource (file)))
 | |
|     {
 | |
|       /* No sections */
 | |
|       g_resource_unref (resource);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_printerr ("Don't know how to handle %s\n", file);
 | |
| #ifndef USE_LIBELF
 | |
|       g_printerr ("gresource is built without elf support\n");
 | |
| #endif
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| cmd_list (const gchar *file,
 | |
|           const gchar *section,
 | |
|           const gchar *path,
 | |
|           gboolean     details)
 | |
| {
 | |
|   GResource *resource;
 | |
| 
 | |
| #ifdef USE_LIBELF
 | |
|   Elf *elf;
 | |
|   int fd;
 | |
| 
 | |
|   if ((elf = get_elf (file, &fd)))
 | |
|     {
 | |
|       elf_list_resources (elf, fd, section, path ? path : "", details);
 | |
|       elf_end (elf);
 | |
|       close (fd);
 | |
|     }
 | |
|   else
 | |
| 
 | |
| #endif
 | |
| 
 | |
|   if ((resource = get_resource (file)))
 | |
|     {
 | |
|       list_resource (resource, "/", "", path ? path : "", details);
 | |
|       g_resource_unref (resource);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_printerr ("Don't know how to handle %s\n", file);
 | |
| #ifndef USE_LIBELF
 | |
|       g_printerr ("gresource is built without elf support\n");
 | |
| #endif
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| cmd_extract (const gchar *file,
 | |
|              const gchar *section,
 | |
|              const gchar *path,
 | |
|              gboolean     details)
 | |
| {
 | |
|   GResource *resource;
 | |
| 
 | |
| #ifdef USE_LIBELF
 | |
| 
 | |
|   Elf *elf;
 | |
|   int fd;
 | |
| 
 | |
|   if ((elf = get_elf (file, &fd)))
 | |
|     {
 | |
|       elf_extract_resource (elf, fd, section, path);
 | |
|       elf_end (elf);
 | |
|       close (fd);
 | |
|     }
 | |
|   else
 | |
| 
 | |
| #endif
 | |
| 
 | |
|   if ((resource = get_resource (file)))
 | |
|     {
 | |
|       extract_resource (resource, path);
 | |
|       g_resource_unref (resource);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_printerr ("Don't know how to handle %s\n", file);
 | |
| #ifndef USE_LIBELF
 | |
|       g_printerr ("gresource is built without elf support\n");
 | |
| #endif
 | |
|     }
 | |
| }
 | |
| 
 | |
| static gint
 | |
| cmd_help (gboolean     requested,
 | |
|           const gchar *command)
 | |
| {
 | |
|   const gchar *description = NULL;
 | |
|   const gchar *synopsis = NULL;
 | |
|   gchar *option;
 | |
|   GString *string;
 | |
| 
 | |
|   option = NULL;
 | |
| 
 | |
|   string = g_string_new (NULL);
 | |
| 
 | |
|   if (command == NULL)
 | |
|     ;
 | |
| 
 | |
|   else if (strcmp (command, "help") == 0)
 | |
|     {
 | |
|       description = _("Print help");
 | |
|       synopsis = _("[COMMAND]");
 | |
|     }
 | |
| 
 | |
|   else if (strcmp (command, "sections") == 0)
 | |
|     {
 | |
|       description = _("List sections containing resources in an elf FILE");
 | |
|       synopsis = _("FILE");
 | |
|     }
 | |
| 
 | |
|   else if (strcmp (command, "list") == 0)
 | |
|     {
 | |
|       description = _("List resources\n"
 | |
|                       "If SECTION is given, only list resources in this section\n"
 | |
|                       "If PATH is given, only list matching resources");
 | |
|       synopsis = _("FILE [PATH]");
 | |
|       option = g_strdup_printf ("[--section %s]", _("SECTION"));
 | |
|     }
 | |
| 
 | |
|   else if (strcmp (command, "details") == 0)
 | |
|     {
 | |
|       description = _("List resources with details\n"
 | |
|                       "If SECTION is given, only list resources in this section\n"
 | |
|                       "If PATH is given, only list matching resources\n"
 | |
|                       "Details include the section, size and compression");
 | |
|       synopsis = _("FILE [PATH]");
 | |
|       option = g_strdup_printf ("[--section %s]", _("SECTION"));
 | |
|     }
 | |
| 
 | |
|   else if (strcmp (command, "extract") == 0)
 | |
|     {
 | |
|       description = _("Extract a resource file to stdout");
 | |
|       synopsis = _("FILE PATH");
 | |
|       option = g_strdup_printf ("[--section %s]", _("SECTION"));
 | |
|     }
 | |
| 
 | |
|   else
 | |
|     {
 | |
|       g_string_printf (string, _("Unknown command %s\n\n"), command);
 | |
|       requested = FALSE;
 | |
|       command = NULL;
 | |
|     }
 | |
| 
 | |
|   if (command == NULL)
 | |
|     {
 | |
|       g_string_append (string,
 | |
|       _("Usage:\n"
 | |
|         "  gresource [--section SECTION] COMMAND [ARGS…]\n"
 | |
|         "\n"
 | |
|         "Commands:\n"
 | |
|         "  help                      Show this information\n"
 | |
|         "  sections                  List resource sections\n"
 | |
|         "  list                      List resources\n"
 | |
|         "  details                   List resources with details\n"
 | |
|         "  extract                   Extract a resource\n"
 | |
|         "\n"
 | |
|         "Use “gresource help COMMAND” to get detailed help.\n\n"));
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       g_string_append_printf (string, _("Usage:\n  gresource %s%s%s %s\n\n%s\n\n"),
 | |
|                               option ? option : "", option ? " " : "", command, synopsis[0] ? synopsis : "", description);
 | |
| 
 | |
|       g_string_append (string, _("Arguments:\n"));
 | |
| 
 | |
|       if (option)
 | |
|         g_string_append (string,
 | |
|                          _("  SECTION   An (optional) elf section name\n"));
 | |
| 
 | |
|       if (strstr (synopsis, _("[COMMAND]")))
 | |
|         g_string_append (string,
 | |
|                        _("  COMMAND   The (optional) command to explain\n"));
 | |
| 
 | |
|       if (strstr (synopsis, _("FILE")))
 | |
|         {
 | |
|           if (strcmp (command, "sections") == 0)
 | |
|             g_string_append (string,
 | |
|                              _("  FILE      An elf file (a binary or a shared library)\n"));
 | |
|           else
 | |
|             g_string_append (string,
 | |
|                              _("  FILE      An elf file (a binary or a shared library)\n"
 | |
|                                "            or a compiled resource file\n"));
 | |
|         }
 | |
| 
 | |
|       if (strstr (synopsis, _("[PATH]")))
 | |
|         g_string_append (string,
 | |
|                        _("  PATH      An (optional) resource path (may be partial)\n"));
 | |
|       else if (strstr (synopsis, _("PATH")))
 | |
|         g_string_append (string,
 | |
|                        _("  PATH      A resource path\n"));
 | |
| 
 | |
|       g_string_append (string, "\n");
 | |
|     }
 | |
| 
 | |
|   if (requested)
 | |
|     g_print ("%s", string->str);
 | |
|   else
 | |
|     g_printerr ("%s\n", string->str);
 | |
| 
 | |
|   g_free (option);
 | |
|   g_string_free (string, TRUE);
 | |
| 
 | |
|   return requested ? 0 : 1;
 | |
| }
 | |
| 
 | |
| /* main {{{1 */
 | |
| 
 | |
| int
 | |
| main (int argc, char *argv[])
 | |
| {
 | |
|   gchar *section = NULL;
 | |
|   gboolean details = FALSE;
 | |
|   void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
 | |
| 
 | |
| #ifdef G_OS_WIN32
 | |
|   gchar *tmp;
 | |
| #endif
 | |
| 
 | |
|   setlocale (LC_ALL, GLIB_DEFAULT_LOCALE);
 | |
|   textdomain (GETTEXT_PACKAGE);
 | |
| 
 | |
| #ifdef G_OS_WIN32
 | |
|   tmp = _glib_get_locale_dir ();
 | |
|   bindtextdomain (GETTEXT_PACKAGE, tmp);
 | |
|   g_free (tmp);
 | |
| #else
 | |
|   bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
 | |
| #endif
 | |
| 
 | |
| #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
 | |
|   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 | |
| #endif
 | |
| 
 | |
|   if (argc < 2)
 | |
|     return cmd_help (FALSE, NULL);
 | |
| 
 | |
|   if (argc > 3 && strcmp (argv[1], "--section") == 0)
 | |
|     {
 | |
|       section = argv[2];
 | |
|       argv = argv + 2;
 | |
|       argc -= 2;
 | |
|     }
 | |
| 
 | |
|   if (strcmp (argv[1], "help") == 0)
 | |
|     return cmd_help (TRUE, argv[2]);
 | |
| 
 | |
|   else if (argc == 4 && strcmp (argv[1], "extract") == 0)
 | |
|     function = cmd_extract;
 | |
| 
 | |
|   else if (argc == 3 && strcmp (argv[1], "sections") == 0)
 | |
|     function = cmd_sections;
 | |
| 
 | |
|   else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
 | |
|     {
 | |
|       function = cmd_list;
 | |
|       details = FALSE;
 | |
|     }
 | |
|   else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
 | |
|     {
 | |
|       function = cmd_list;
 | |
|       details = TRUE;
 | |
|     }
 | |
|   else
 | |
|     return cmd_help (FALSE, argv[1]);
 | |
| 
 | |
|   (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* vim:set foldmethod=marker: */
 |