(root)/
man-db-2.12.0/
src/
descriptions.c
       1  /*
       2   * descriptions.c: manipulate man page descriptions
       3   *
       4   * Copyright (C) 2002, 2003, 2006, 2007, 2008, 2009, 2010, 2011 Colin Watson.
       5   *
       6   * This file is part of man-db.
       7   *
       8   * man-db is free software; you can redistribute it and/or modify it
       9   * under the terms of the GNU General Public License as published by
      10   * the Free Software Foundation; either version 2 of the License, or
      11   * (at your option) any later version.
      12   *
      13   * man-db is distributed in the hope that it will be useful, but
      14   * WITHOUT ANY WARRANTY; without even the implied warranty of
      15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16   * GNU General Public License for more details.
      17   *
      18   * You should have received a copy of the GNU General Public License
      19   * along with man-db; if not, write to the Free Software Foundation,
      20   * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      21   */
      22  
      23  #ifdef HAVE_CONFIG_H
      24  #  include "config.h"
      25  #endif /* HAVE_CONFIG_H */
      26  
      27  #include <stdbool.h>
      28  #include <string.h>
      29  #include <stdlib.h>
      30  
      31  #include "gl_array_list.h"
      32  #include "gl_xlist.h"
      33  #include "xalloc.h"
      34  #include "xstrndup.h"
      35  
      36  #include "manconfig.h"
      37  
      38  #include "debug.h"
      39  #include "util.h"
      40  
      41  #include "descriptions.h"
      42  
      43  /* Free a page description. */
      44  static void page_description_free (const void *value)
      45  {
      46  	struct page_description *desc = (struct page_description *) value;
      47  
      48  	free (desc->name);
      49  	free (desc->whatis);
      50  	free (desc);
      51  }
      52  
      53  /* Parse the description in a whatis line returned by find_name() into a
      54   * list of names and whatis descriptions.
      55   */
      56  gl_list_t parse_descriptions (const char *base, const char *whatis)
      57  {
      58  	const char *sep, *nextsep;
      59  	gl_list_t descs;
      60  	bool seen_base = false;
      61  
      62  	descs = gl_list_create_empty (GL_ARRAY_LIST, NULL, NULL,
      63  				      page_description_free, true);
      64  
      65  	if (!whatis)
      66  		return descs;
      67  
      68  	sep = whatis;
      69  
      70  	while (sep) {
      71  		char *record;
      72  		size_t length;
      73  		const char *dash;
      74  		char *names;
      75  		const char *token;
      76  
      77  		/* Use a while loop so that we skip over things like the
      78  		 * result of double line breaks.
      79  		 */
      80  		while (*sep == 0x11 || *sep == ' ')
      81  			++sep;
      82  		nextsep = strchr (sep, 0x11);
      83  
      84  		/* Get this record as a null-terminated string. */
      85  		if (nextsep)
      86  			length = (size_t) (nextsep - sep);
      87  		else
      88  			length = strlen (sep);
      89  		if (length == 0)
      90  			break;
      91  
      92  		record = xstrndup (sep, length);
      93  		debug ("record = '%s'\n", record);
      94  
      95  		/* Split the record into name and whatis description. */
      96  		dash = strstr (record, " - ");
      97  		if (dash)
      98  			names = xstrndup (record, dash - record);
      99  		else if (!gl_list_size (descs))
     100  			/* Some pages have a NAME section with just the page
     101  			 * name and no whatis.  We might as well include
     102  			 * this.
     103  			 */
     104  			names = xstrdup (record);
     105  		else
     106  			/* Once at least one record has been seen, further
     107  			 * cases where there is no whatis usually amount to
     108  			 * garbage following the useful records, and can
     109  			 * cause problems due to false WHATIS_MAN entries in
     110  			 * the database.  On the whole it seems best to
     111  			 * ignore these.
     112  			 */
     113  			goto next;
     114  
     115  		for (token = strtok (names, ","); token;
     116  		     token = strtok (NULL, ",")) {
     117  			char *name = trim_spaces (token);
     118  			struct page_description *desc;
     119  
     120  			/* Skip name tokens containing whitespace. They are
     121  			 * almost never useful as manual page names.
     122  			 */
     123  			if (strpbrk (name, " \t") != NULL) {
     124  				free (name);
     125  				continue;
     126  			}
     127  
     128  			/* Allocate new description node. */
     129  			desc = xmalloc (sizeof *desc);
     130  			desc->name   = name; /* steal memory */
     131  			desc->whatis = dash ? trim_spaces (dash + 3) : NULL;
     132  			gl_list_add_last (descs, desc);
     133  
     134  			if (base && STREQ (base, desc->name))
     135  				seen_base = true;
     136  		}
     137  
     138  		free (names);
     139  next:
     140  		free (record);
     141  
     142  		sep = nextsep;
     143  	}
     144  
     145  	/* If it isn't there already, add the base name onto the returned
     146  	 * list.
     147  	 */
     148  	if (base && !seen_base) {
     149  		struct page_description *desc = xmalloc (sizeof *desc);
     150  
     151  		desc->name = xstrdup (base);
     152  		desc->whatis = NULL;
     153  		if (gl_list_size (descs)) {
     154  			const struct page_description *first =
     155  				gl_list_get_at (descs, 0);
     156  			if (first->whatis)
     157  				desc->whatis = xstrdup (first->whatis);
     158  		}
     159  		gl_list_add_last (descs, desc);
     160  	}
     161  
     162  	return descs;
     163  }