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