1 /*
2 *
3 * namazu.c - search client of Namazu
4 *
5 * $Id: namazu-cmd.c,v 1.17.4.16 2007-12-05 16:59:36 opengl2772 Exp $
6 *
7 * Copyright (C) 1997-1999 Satoru Takabayashi All rights reserved.
8 * Copyright (C) 2000-2007 Namazu Project All rights reserved.
9 * This is free software with ABSOLUTELY NO WARRANTY.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24 * 02111-1307, USA
25 *
26 *
27 */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32 #ifdef HAVE_SUPPORT_H
33 # include "support.h"
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <sys/types.h>
39 #include <fcntl.h>
40 #include <ctype.h>
41 #include <sys/stat.h>
42 #include <signal.h>
43 #include <stdarg.h>
44
45 #ifdef HAVE_ERRNO_H
46 # include <errno.h>
47 #endif
48
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #else
52 # ifdef _WIN32
53 # include <io.h>
54 # endif
55 #endif
56
57 #ifdef HAVE_STRING_H
58 # include <string.h>
59 #else
60 # include <strings.h>
61 #endif
62
63 #include "namazu.h"
64 #include "libnamazu.h"
65 #include "getopt.h"
66 #include "util.h"
67 #include "codeconv.h"
68 #include "usage.h"
69 #include "rcfile.h"
70 #include "output.h"
71 #include "search.h"
72 #include "hlist.h"
73 #include "idxname.h"
74 #include "i18n.h"
75 #include "message.h"
76 #include "var.h"
77 #include "result.h"
78 #include "system.h"
79 #include "charset.h"
80
81 /*
82 * Extern variables.
83 */
84
85 NMZ_HANDLE handle_charset = (NMZ_HANDLE)0;
86
87 /*
88 *
89 * Private functions
90 *
91 */
92
93 static int ck_atoi ( char const *str, int *out );
94 static void stdio2file ( const char * fname );
95 static int parse_options ( int argc, char **argv );
96
97 /*
98 * Imported from GNU grep-2.3 [1999-11-08] by satoru-t
99 */
100 /* Convert STR to a positive integer, storing the result in *OUT.
101 If STR is not a valid integer, return -1 (otherwise 0). */
102 static int
ck_atoi(char const * str,int * out)103 ck_atoi (char const *str, int *out)
104 {
105 char const *p;
106 for (p = str; *p; p++)
107 if (*p < '0' || *p > '9')
108 return -1;
109
110 *out = atoi (nmz_optarg);
111 return 0;
112 }
113
114 /*
115 * Redirect stdio to specified file
116 */
117 static void
stdio2file(const char * fname)118 stdio2file(const char * fname)
119 {
120 /*
121 * Old bad routine.
122 *
123 * int fd;
124 * if (-1 == (fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 00600))) {
125 * die("%s", strerror(errno));
126 * return 1;
127 * }
128 * close(STDOUT);
129 * dup(fd);
130 * close(STDERR);
131 * dup(fd);
132 * close(fd);
133 */
134 if (freopen(fname, "wb", stdout) == NULL) {
135 die("%s", strerror(errno));
136 }
137 }
138
139 /*
140 * Command line options.
141 */
142 static const char *short_options = "01:234:5acCedf:FhHlL:n:o:qrRsSUvw:";
143 static struct option long_options[] = {
144 { "norc", no_argument, NULL, 1 },
145 { "help", no_argument, NULL, '0' },
146 { "result", required_argument, NULL, '1' },
147 { "late", no_argument, NULL, '2' },
148 { "early", no_argument, NULL, '3' },
149 { "sort", required_argument, NULL, '4' },
150 { "ascending", no_argument, NULL, '5' },
151 { "all", no_argument, NULL, 'a' },
152 { "count", no_argument, NULL, 'c' },
153 { "show-config", no_argument, NULL, 'C' },
154 { "debug", no_argument, NULL, 'd' },
155 { "config", required_argument, NULL, 'f' },
156 { "form", no_argument, NULL, 'F' },
157 { "html", no_argument, NULL, 'h' },
158 { "page", no_argument, NULL, 'H' },
159 { "list", no_argument, NULL, 'l' },
160 { "lang", required_argument, NULL, 'L' },
161 { "max", required_argument, NULL, 'n' },
162 { "output", required_argument, NULL, 'o' },
163 { "quiet", no_argument, NULL, 'q' },
164 { "no-references", no_argument, NULL, 'r' },
165 { "no-replace", no_argument, NULL, 'R' },
166 { "short", no_argument, NULL, 's' },
167 { "no-decode-uri", no_argument, NULL, 'U' },
168 { "version", no_argument, NULL, 'v' },
169 { "whence", required_argument, NULL, 'w' },
170 { NULL, 0, NULL, 0 }
171 };
172
173 /*
174 * Parse command line options
175 */
176 static int
parse_options(int argc,char ** argv)177 parse_options(int argc, char **argv)
178 {
179 int tmp;
180 int opt_show_config = 0;
181
182 for (;;) {
183 int ch = nmz_getopt_long(argc, argv, short_options, long_options, NULL);
184 if (ch == -1) {
185 break;
186 }
187 switch (ch) {
188 case 1:
189 set_namazunorc("all");
190 break;
191 case '0':
192 show_usage();
193 exit_nmz(EXIT_SUCCESS);
194 break;
195 case '1': /* --result */
196 if (nmz_optarg == NULL) {
197 die("%s: invalid argument for -1 --result", nmz_optarg);
198 }
199 set_templatesuffix(nmz_optarg);
200 break;
201 case '2':
202 nmz_set_sortmethod(SORT_BY_DATE);
203 nmz_set_sortorder(DESCENDING);
204 break;
205 case '3':
206 nmz_set_sortmethod(SORT_BY_DATE);
207 nmz_set_sortorder(ASCENDING);
208 break;
209 case '4': /* --sort */
210 {
211 if (nmz_optarg == NULL) {
212 die("%s: invalid argument for -4 --sort", nmz_optarg);
213 }
214 if (strcasecmp(nmz_optarg, "score") == 0) {
215 nmz_set_sortmethod(SORT_BY_SCORE);
216 } else if (strcasecmp(nmz_optarg, "date") == 0) {
217 nmz_set_sortmethod(SORT_BY_DATE);
218 } else if (nmz_strprefixcasecmp(nmz_optarg, "field:") == 0) {
219 nmz_set_sortmethod(SORT_BY_FIELD);
220 nmz_set_sortfield(nmz_optarg + strlen("field:"));
221 } else {
222 die("%s: invalid argument for -4 --sort", nmz_optarg);
223 }
224 }
225 break;
226 case '5': /* --ascending */
227 nmz_set_sortorder(ASCENDING);
228 break;
229 case 'f': /* --config */
230 if (nmz_optarg == NULL) {
231 die("%s: invalid argument for -f --config", nmz_optarg);
232 }
233 set_namazurc(nmz_optarg);
234 break;
235 case 'n':
236 if (ck_atoi(nmz_optarg, &tmp)) {
237 die("%s: invalid argument for -n, --max", nmz_optarg);
238 }
239 set_maxresult(tmp);
240 break;
241 case 'w':
242 if (ck_atoi(nmz_optarg, &tmp)) {
243 die("%s: invalid argument for -w, --whence", nmz_optarg);
244 }
245 set_listwhence(tmp);
246 break;
247 case 'd':
248 nmz_set_debugmode(1);
249 break;
250 case 's':
251 set_templatesuffix("short");
252 break;
253 case 'l':
254 case 'S': /* 'S' for backward compatibility */
255 set_listmode(1);
256 break;
257 case 'q':
258 set_quietmode(1);
259 break;
260 case 'c':
261 set_countmode(1);
262 break;
263 case 'h':
264 set_htmlmode(1);
265 set_uridecode(0); /* Do no decode URI in results. */
266 break;
267 case 'H':
268 set_pageindex(1);
269 break;
270 case 'F':
271 set_formprint(1);
272 break;
273 case 'a':
274 set_allresult(1);
275 break;
276 case 'R':
277 set_urireplace(0);
278 break;
279 case 'r':
280 set_refprint(0);
281 break;
282 case 'U':
283 set_uridecode(0); /* Do not deocode URI in results. */
284 break;
285 case 'v':
286 show_version();
287 exit_nmz(EXIT_SUCCESS);
288 break;
289 case 'C':
290 opt_show_config = 1;
291 break;
292 case 'o': /* --output */
293 if (nmz_optarg == NULL) {
294 die("%s: invalid argument for -o --output", nmz_optarg);
295 }
296 stdio2file(nmz_optarg);
297 break;
298 }
299 }
300 if (opt_show_config) {
301 if (load_rcfiles() != SUCCESS) {
302 die(nmz_get_dyingmsg());
303 }
304 show_config();
305 exit_nmz(EXIT_SUCCESS);
306 }
307
308 return nmz_optind;
309 }
310
311 int
main(int argc,char ** argv)312 main(int argc, char **argv)
313 {
314 char query[BUFSIZE] = "", subquery[BUFSIZE] = "";
315 char *localedir = getenv("NAMAZULOCALEDIR");
316
317 /*
318 *
319 * create resource.
320 *
321 */
322 handle_charset = create_charset_list();
323
324 /*
325 * To support a binary package for Windows, we should
326 * allow to change LOCALEDIR with the environment
327 * variable `NAMAZULOCALEDIR' after installation is
328 * done.
329 */
330 if (localedir != NULL) {
331 bindtextdomain(PACKAGE, localedir);
332 } else {
333 bindtextdomain(PACKAGE, LOCALEDIR);
334 }
335 textdomain(PACKAGE);
336
337 nmz_set_lang("");
338
339 if (getenv("QUERY_STRING") && getenv("SCRIPT_NAME")) {
340 /*
341 * If invoked as CGI, print a help message and exit.
342 *
343 * NOTE: Since "namazu" command and "namazu.cgi" had
344 * been same until 1.9.13, there might be a lot of
345 * people trying to use "namazu" command as CGI. But
346 * since 1.9.14, they are different and we cannot
347 * use "namazu" command as CGI any longer.
348 */
349 printf("%s %s; %s" CRLF CRLF, MSG_MIME_HEADER,
350 "text/html", _("charset=ISO-8859-1"));
351 printf("<html><body>\n");
352 printf("You should use \"namazu.cgi\" instead of \"namazu\" command.");
353 printf("\n</body></html>\n");
354 exit_nmz(EXIT_FAILURE);
355 } else if (argc == 1) {
356 show_mini_usage();
357 exit_nmz(EXIT_FAILURE);
358 } else {
359 int i = 0;
360
361 set_refprint(1);
362
363 i = parse_options(argc, argv);
364 if (i == argc) {
365 show_mini_usage();
366 exit_nmz(EXIT_FAILURE);
367 }
368
369 if (strlen(argv[i]) > QUERY_MAX) {
370 die(nmz_strerror(ERR_TOO_LONG_QUERY));
371 }
372
373 strncpy(query, argv[i++], BUFSIZE - 1);
374 if (i < argc) {
375 int curidx = nmz_get_idxnum();
376 for (curidx = 0; i < argc && curidx < INDEX_MAX; i++) {
377 if (nmz_add_index(argv[i]) != SUCCESS) {
378 die("invalid idxname: %s", argv[i]);
379 }
380 }
381 }
382 }
383
384 if (load_rcfiles() != SUCCESS) {
385 die(nmz_get_dyingmsg());
386 }
387
388 /*
389 * If no index is explicitly specified, search the default index.
390 * NOTE: This processing must be place after load_rcfiles().
391 * Because default index can be set in namazurc.
392 */
393 if (nmz_get_idxnum() == 0) {
394 /* Use defaultidx for the taget index. */
395 if (nmz_add_index(nmz_get_defaultidx()) != SUCCESS) {
396 die("invalid idxname: %s", nmz_get_defaultidx());
397 }
398 }
399
400 if (namazu_core(query, subquery) == ERR_FATAL) {
401 die(nmz_get_dyingmsg());
402 }
403
404 /*
405 *
406 * free resource.
407 *
408 */
409 nmz_free_handle(handle_charset);
410
411 return EXIT_SUCCESS;
412 }
413