Imported Upstream version 2.8.4
[platform/upstream/man-db.git] / 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 <string.h>
28 #include <stdlib.h>
29
30 #include "manconfig.h"
31 #include "descriptions.h"
32
33 /* Parse the description in a whatis line returned by find_name() into a
34  * sequence of names and whatis descriptions.
35  */
36 struct page_description *parse_descriptions (const char *base,
37                                              const char *whatis)
38 {
39         const char *sep, *nextsep;
40         struct page_description *desc = NULL, *head = NULL;
41         int seen_base = 0;
42
43         if (!whatis)
44                 return NULL;
45
46         sep = whatis;
47
48         while (sep) {
49                 char *record;
50                 size_t length;
51                 const char *dash;
52                 char *names;
53                 const char *token;
54
55                 /* Use a while loop so that we skip over things like the
56                  * result of double line breaks.
57                  */
58                 while (*sep == 0x11 || *sep == ' ')
59                         ++sep;
60                 nextsep = strchr (sep, 0x11);
61
62                 /* Get this record as a null-terminated string. */
63                 if (nextsep)
64                         length = (size_t) (nextsep - sep);
65                 else
66                         length = strlen (sep);
67                 if (length == 0)
68                         break;
69
70                 record = xstrndup (sep, length);
71                 debug ("record = '%s'\n", record);
72
73                 /* Split the record into name and whatis description. */
74                 dash = strstr (record, " - ");
75                 if (dash)
76                         names = xstrndup (record, dash - record);
77                 else if (!desc)
78                         /* Some pages have a NAME section with just the page
79                          * name and no whatis.  We might as well include
80                          * this.
81                          */
82                         names = xstrdup (record);
83                 else
84                         /* Once at least one record has been seen, further
85                          * cases where there is no whatis usually amount to
86                          * garbage following the useful records, and can
87                          * cause problems due to false WHATIS_MAN entries in
88                          * the database.  On the whole it seems best to
89                          * ignore these.
90                          */
91                         goto next;
92
93                 for (token = strtok (names, ","); token;
94                      token = strtok (NULL, ",")) {
95                         char *name = trim_spaces (token);
96
97                         /* Skip name tokens containing whitespace. They are
98                          * almost never useful as manual page names.
99                          */
100                         if (strpbrk (name, " \t") != NULL) {
101                                 free (name);
102                                 continue;
103                         }
104
105                         /* Allocate new description node. */
106                         if (head) {
107                                 desc->next = xmalloc (sizeof *desc);
108                                 desc = desc->next;
109                         } else {
110                                 desc = xmalloc (sizeof *desc);
111                                 head = desc;
112                         }
113                         desc->name   = name; /* steal memory */
114                         desc->whatis = dash ? trim_spaces (dash + 3) : NULL;
115                         desc->next   = NULL;
116
117                         if (base && STREQ (base, desc->name))
118                                 seen_base = 1;
119                 }
120
121                 free (names);
122 next:
123                 free (record);
124
125                 sep = nextsep;
126         }
127
128         /* If it isn't there already, add the base name onto the returned
129          * list.
130          */
131         if (base && !seen_base) {
132                 if (head) {
133                         desc->next = xmalloc (sizeof *desc);
134                         desc = desc->next;
135                         desc->whatis =
136                                 head->whatis ? xstrdup (head->whatis) : NULL;
137                 } else {
138                         desc = xmalloc (sizeof *desc);
139                         head = desc;
140                         desc->whatis = NULL;
141                 }
142                 desc->name = xstrdup (base);
143                 desc->next = NULL;
144         }
145
146         return head;
147 }
148
149 /* Free a description list and all its contents. */
150 void free_descriptions (struct page_description *head)
151 {
152         struct page_description *desc = head, *prev;
153
154         while (desc) {
155                 free (desc->name);
156                 free (desc->whatis);
157                 prev = desc;
158                 desc = desc->next;
159                 free (prev);
160         }
161 }