1 /*
2 * lexgrog_test.c: test whatis extraction from man/cat pages
3 *
4 * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.)
5 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
6 * 2011 Colin Watson.
7 *
8 * This file is part of man-db.
9 *
10 * man-db is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * man-db is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with man-db; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif /* HAVE_CONFIG_H */
28
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 #include <sys/stat.h>
35
36 #include "argp.h"
37 #include "attribute.h"
38 #include "error.h"
39 #include "gl_list.h"
40 #include "progname.h"
41 #include "xalloc.h"
42
43 #include "gettext.h"
44 #define _(String) gettext (String)
45 #define N_(String) gettext_noop (String)
46
47 #include "manconfig.h"
48
49 #include "cleanup.h"
50 #include "debug.h"
51 #include "glcontainers.h"
52 #include "pipeline.h"
53 #include "sandbox.h"
54 #include "security.h"
55 #include "util.h"
56
57 #include "convert.h"
58 #include "descriptions.h"
59 #include "lexgrog.h"
60 #include "ult_src.h"
61
62 int quiet = 1;
63 man_sandbox *sandbox;
64
65 static bool parse_man = false, parse_cat = false;
66 static bool show_whatis = false, show_filters = false;
67 static const char *encoding = NULL;
68 static char **files;
69 static int num_files;
70
71 const char *argp_program_version = "lexgrog " PACKAGE_VERSION;
72 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
73 error_t argp_err_exit_status = FAIL;
74
75 static const char args_doc[] = N_("FILE...");
76 static const char doc[] = "\v" N_("The defaults are --man and --whatis.");
77
78 static struct argp_option options[] = {
79 OPT ("debug", 'd', 0, N_("emit debugging messages")),
80 OPT ("man", 'm', 0, N_("parse as man page"), 1),
81 OPT ("cat", 'c', 0, N_("parse as cat page")),
82 OPT ("whatis", 'w', 0, N_("show whatis information"), 2),
83 OPT ("filters", 'f', 0,
84 N_("show guessed series of preprocessing filters")),
85 OPT ("encoding", 'E', N_("ENCODING"),
86 N_("use selected output encoding"), 3),
87 OPT_HELP_COMPAT,
88 { 0 }
89 };
90
91 static error_t parse_opt (int key, char *arg, struct argp_state *state)
92 {
93 switch (key) {
94 case 'd':
95 debug_level = true;
96 return 0;
97 case 'm':
98 parse_man = true;
99 return 0;
100 case 'c':
101 parse_cat = true;
102 return 0;
103 case 'w':
104 show_whatis = true;
105 return 0;
106 case 'f':
107 show_filters = true;
108 return 0;
109 case 'E':
110 encoding = arg;
111 return 0;
112 case 'h':
113 argp_state_help (state, state->out_stream,
114 ARGP_HELP_STD_HELP &
115 ~ARGP_HELP_PRE_DOC);
116 break;
117 case ARGP_KEY_ARGS:
118 files = state->argv + state->next;
119 num_files = state->argc - state->next;
120 return 0;
121 case ARGP_KEY_NO_ARGS:
122 argp_usage (state);
123 break;
124 case ARGP_KEY_SUCCESS:
125 if (parse_man && parse_cat)
126 /* This slightly odd construction allows us
127 * to reuse a translation.
128 */
129 argp_error (state,
130 _("%s: incompatible options"),
131 "-m -c");
132 /* defaults: --man, --whatis */
133 if (!parse_man && !parse_cat)
134 parse_man = true;
135 if (!show_whatis && !show_filters)
136 show_whatis = true;
137 return 0;
138 }
139 return ARGP_ERR_UNKNOWN;
140 }
141
142 static char *help_filter (int key, const char *text, void *input MAYBE_UNUSED)
143 {
144 switch (key) {
145 case ARGP_KEY_HELP_PRE_DOC:
146 /* We have no pre-options help text, but the input
147 * text may contain header junk due to gettext ("").
148 */
149 return NULL;
150 default:
151 return (char *) text;
152 }
153 }
154
155 static struct argp argp = { options, parse_opt, args_doc, doc, 0,
156 help_filter };
157
158 int main (int argc, char **argv)
159 {
160 int type = MANPAGE;
161 int i;
162 bool some_failed = false;
163
164 set_program_name (argv[0]);
165
166 init_debug ();
167 pipeline_install_post_fork (pop_all_cleanups);
168 sandbox = sandbox_init ();
169 init_locale ();
170
171 if (argp_parse (&argp, argc, argv, 0, 0, 0))
172 exit (FAIL);
173
174 /* We aren't setuid, but this allows generic code in lexgrog.l to
175 * use drop_effective_privs/regain_effective_privs.
176 */
177 init_security ();
178
179 if (parse_man)
180 type = MANPAGE;
181 else
182 type = CATPAGE;
183
184 for (i = 0; i < num_files; ++i) {
185 lexgrog lg;
186 const char *file = NULL;
187 bool found = false;
188
189 lg.type = type;
190
191 if (STREQ (files[i], "-"))
192 file = files[i];
193 else {
194 char *path, *pathend;
195 struct stat statbuf;
196 const struct ult_value *ult;
197
198 path = xstrdup (files[i]);
199 pathend = strrchr (path, '/');
200 if (pathend) {
201 *pathend = '\0';
202 pathend = strrchr (path, '/');
203 if (pathend && STRNEQ (pathend + 1, "man", 3))
204 *pathend = '\0';
205 else {
206 free (path);
207 path = NULL;
208 }
209 } else {
210 free (path);
211 path = NULL;
212 }
213
214 ult = ult_src (files[i], path ? path : ".",
215 &statbuf, SO_LINK);
216 if (ult)
217 file = ult->path;
218 free (path);
219 }
220
221 if (file && find_name (file, "-", &lg, encoding)) {
222 gl_list_t descs = parse_descriptions (NULL, lg.whatis);
223 const struct page_description *desc;
224 GL_LIST_FOREACH (descs, desc) {
225 if (!desc->name || !desc->whatis)
226 continue;
227 found = true;
228 printf ("%s", files[i]);
229 if (show_filters)
230 printf (" (%s)", lg.filters);
231 if (show_whatis) {
232 char *name_conv = convert_to_locale
233 (desc->name);
234 char *whatis_conv = convert_to_locale
235 (desc->whatis);
236 printf (": \"%s - %s\"",
237 name_conv, whatis_conv);
238 free (whatis_conv);
239 free (name_conv);
240 }
241 printf ("\n");
242 }
243 gl_list_free (descs);
244 free (lg.filters);
245 free (lg.whatis);
246 }
247
248 if (!found) {
249 printf ("%s: parse failed\n", files[i]);
250 some_failed = true;
251 }
252 }
253
254 sandbox_free (sandbox);
255
256 if (some_failed)
257 return FATAL;
258 else
259 return OK;
260 }