OSDN Git Service

Bumped version 2.4.4.
[chasen-legacy/chasen.git] / lib / iotool.c
1 /*
2  * Copyright (c) 2003 Nara Institute of Science and Technology
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name Nara Institute of Science and Technology may not be used to
15  *    endorse or promote products derived from this software without
16  *    specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY Nara Institute of Science and Technology 
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
21  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE Nara Institute
22  * of Science and Technology BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * $Id: iotool.c,v 1.1.1.1 2007/03/13 07:40:10 masayu-a Exp $
31  */
32
33 #include "config.h"
34
35 #include <stdio.h>
36 #include <stdarg.h>
37 #ifdef HAVE_WINDOWS_H
38 #include <windows.h>
39 #endif
40 #include "chadic.h"
41 #include "literal.h"
42
43 #ifdef PATHTYPE_MSDOS
44 #define RCFILE "\\chasenrc"
45 #define RC2FILE "\\chasen2rc"
46 #else
47 #define RCFILE "/.chasenrc"
48 #define RC2FILE "/.chasen2rc"
49 #endif
50
51 #if defined HAVE_WINDOWS_H && !defined __CYGWIN__
52 #define REG_PATH "Software\\NAIST\\ChaSen"
53 #define REG_RC "chasenrc"
54 #define REG_GRAMMAR "grammar"
55 #endif
56
57 int Cha_lineno, Cha_lineno_error;
58 int Cha_errno = 0;
59
60 static FILE *cha_stderr = NULL;
61 static char progpath[PATH_MAX] = "chasen";
62 static char filepath[PATH_MAX];
63 static char grammar_dir[PATH_MAX];
64 static char chasenrc_path[PATH_MAX];
65
66 /*
67  * cha_convert_escape - convert escape characters
68  */
69 /* XXX: not Shift-JIS safe */
70 char *
71 cha_convert_escape(char *str, int ctrl_only)
72 {
73     char *s1, *s2;
74
75     for (s1 = s2 = str; *s1; s1++, s2++) {
76         if (*s1 != '\\')
77             *s2 = *s1;
78         else {
79             switch (*++s1) {
80             case 't':
81                 *s2 = '\t';
82                 break;
83             case 'n':
84                 *s2 = '\n';
85                 break;
86             default:
87                 if (ctrl_only)
88                     *s2++ = '\\';
89                 *s2 = *s1;
90                 break;
91             }
92         }
93     }
94     *s2 = '\0';
95
96     return str;
97 }
98
99 /*
100  * cha_set_progpath - set program pathname
101  *
102  *      progpath is used in cha_exit() and cha_exit_file()
103  */
104 void
105 cha_set_progpath(char *path)
106 {
107 #if defined _WIN32 && ! defined __CYGWIN__
108     GetModuleFileName(GetModuleHandle(NULL), progpath, PATH_MAX);
109 #else /* not _WIN32 */
110     strncpy(progpath, path, PATH_MAX);
111 #endif /* _WIN32 */
112 }
113
114 /*
115  * cha_set_rcpath - set chasenrc file path
116  *
117  *      this function is called when -r option is used.
118  */
119 void
120 cha_set_rcpath(char *filename)
121 {
122     strncpy(chasenrc_path, filename, PATH_MAX);
123 }
124
125 /*
126  * cha_get_rcpath
127  *
128  *      called only from chasen.c
129  */
130 char *
131 cha_get_rcpath(void)
132 {
133     return chasenrc_path;
134 }
135
136 /*
137  * cha_get_grammar_dir
138  *
139  *      called only from chasen.c
140  */
141 char *
142 cha_get_grammar_dir(void)
143 {
144     return grammar_dir;
145 }
146
147 /*
148  * cha_fopen - open file, or error end
149  *
150  * inputs:
151  *      ret - exit code (don't exit if ret < 0)
152  */
153 FILE *
154 cha_fopen(char *filename, char *mode, int ret)
155 {
156     FILE *fp;
157
158     if (filename[0] == '-' && filename[1] == '\0')
159         return stdin;
160
161     if ((fp = fopen(filename, mode)) != NULL) {
162         /*
163          * filepath is used in cha_exit_file() 
164          */
165         if (*mode == 'r') {
166             if (filename != filepath)
167                 strncpy(filepath, filename, PATH_MAX);
168             Cha_lineno = Cha_lineno_error = 0;
169         }
170     } else if (ret >= 0)
171         cha_exit_perror(filename);
172
173     return fp;
174 }
175
176 /*
177  * cha_fopen_grammar - open file from current or grammar directory
178  *
179  * inputs:
180  *      dir - 0: read from current directory
181  *            1: read from grammar directory
182  *            2: read from current directory or grammar directory
183  *
184  *      ret - return the code when fopen() fails
185  *
186  * outputs:
187  *      filepathp - file path string
188  */
189 FILE *
190 cha_fopen_grammar(char *filename, char *mode, int ret, int dir,
191                   char **filepathp)
192 {
193     FILE *fp;
194
195     *filepathp = filename;
196     switch (dir) {
197     case 0:
198         /*
199          * ¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤«¤éÆɤ߹þ¤à 
200          */
201         return cha_fopen(filename, mode, ret);
202     case 2:
203         /*
204          * ¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤«¤éÆɤ߹þ¤à 
205          */
206         if ((fp = cha_fopen(filename, mode, -1)) != NULL)
207             return fp;
208         /*
209          * FALLTHRU 
210          */
211     default:                    /* should be 1 */
212         /*
213          * Ê¸Ë¡¥Ç¥£¥ì¥¯¥È¥ê¤«¤éÆɤ߹þ¤à 
214          * Ê¸Ë¡¥Ç¥£¥ì¥¯¥È¥ê¤¬ÀßÄꤵ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð .chasenrc ¤òÆɤ߹þ¤à 
215          */
216         if (grammar_dir[0] == '\0')
217             cha_read_grammar_dir();
218         snprintf(filepath, PATH_MAX, "%s%s", grammar_dir, filename);
219         *filepathp = filepath;
220         return cha_fopen(filepath, mode, ret);
221     }
222 }
223
224 /*
225  * cha_malloc()
226  */
227 void *
228 cha_malloc(size_t n)
229 {
230     void *p;
231
232     if ((p = malloc(n)) == NULL)
233         cha_exit_perror("malloc");
234
235     return p;
236 }
237
238 void *
239 cha_realloc(void *ptr, size_t n)
240 {
241     void *p;
242
243     if ((p = realloc(ptr, n)) == NULL)
244         cha_exit_perror("realloc");
245
246     return p;
247 }
248
249 #define CHA_MALLOC_SIZE (1024 * 64)
250 static char *
251 cha_malloc_char(int size)
252 {
253     static int idx = CHA_MALLOC_SIZE;
254     static char *ptr;
255
256     if (idx + size >= CHA_MALLOC_SIZE) {
257         ptr = (char *) cha_malloc(CHA_MALLOC_SIZE);
258         idx = 0;
259     }
260
261     idx += size;
262     return ptr + idx - size;
263 }
264
265 char *
266 cha_strdup(char *str)
267 {
268     char *newstr;
269
270     newstr = cha_malloc_char(strlen(str) + 1);
271     strcpy(newstr, str);
272
273     return newstr;
274 }
275
276 /*
277  * cha_exit() - print error messages on stderr and exit
278  */
279 void
280 cha_set_stderr(FILE * fp)
281 {
282     cha_stderr = fp;
283 }
284
285 void
286 cha_exit(int status, char *format, ...)
287 {
288     va_list ap;
289
290     if (Cha_errno)
291         return;
292
293     if (!cha_stderr)
294         cha_stderr = stderr;
295     else if (cha_stderr != stderr)
296         fputs("500 ", cha_stderr);
297
298     if (progpath)
299         fprintf(cha_stderr, "%s: ", progpath);
300     va_start(ap, format);
301     vfprintf(cha_stderr, format, ap);
302     va_end(ap);
303     if (status >= 0) {
304         fputc('\n', cha_stderr);
305         if (cha_stderr == stderr)
306             exit(status);
307         Cha_errno = 1;
308     }
309 }
310
311 void
312 cha_exit_file(int status, char *format, ...)
313 {
314     va_list ap;
315
316     if (Cha_errno)
317         return;
318
319     if (!cha_stderr)
320         cha_stderr = stderr;
321     else if (cha_stderr != stderr)
322         fputs("500 ", cha_stderr);
323
324     if (progpath)
325         fprintf(cha_stderr, "%s: ", progpath);
326
327     if (Cha_lineno == 0)
328         ;       /* do nothing */
329     else if (Cha_lineno == Cha_lineno_error)
330         fprintf(cha_stderr, "%s:%d: ", filepath, Cha_lineno);
331     else
332         fprintf(cha_stderr, "%s:%d-%d: ", filepath, Cha_lineno_error,
333                 Cha_lineno);
334
335     va_start(ap, format);
336     vfprintf(cha_stderr, format, ap);
337     va_end(ap);
338
339     if (status >= 0) {
340         fputc('\n', cha_stderr);
341         if (cha_stderr == stderr)
342             exit(status);
343         Cha_errno = 1;
344     }
345 }
346
347 void
348 cha_perror(char *s)
349 {
350     cha_exit(-1, "");
351     perror(s);
352 }
353
354 void
355 cha_exit_perror(char *s)
356 {
357     cha_perror(s);
358     exit(1);
359 }
360
361 FILE *
362 cha_fopen_rcfile(void)
363 {
364     FILE *fp;
365     char *home_dir, *rc_env, *getenv();
366
367     /*
368      * -R option (standard alone) 
369      */
370     if (!strcmp(chasenrc_path, "*")) {
371 #if defined HAVE_WINDOWS_H && !defined __CYGWIN__
372         if ((cha_read_registry(REG_PATH, REG_RC, chasenrc_path) != NULL) &&
373             ((fp = cha_fopen(chasenrc_path, "r", -1)) != NULL)) {
374             return fp;
375         }
376 #endif
377         strncpy(chasenrc_path, RCPATH, PATH_MAX);
378         if ((fp = cha_fopen(chasenrc_path, "r", -1)) != NULL)
379             return fp;
380         cha_exit(1, "can't open %s", chasenrc_path);
381     }
382
383     /*
384      * -r option 
385      */
386     if (chasenrc_path[0])
387         return cha_fopen(chasenrc_path, "r", 1);
388
389     /*
390      * environment variable CHASENRC 
391      */
392     if ((rc_env = getenv("CHASENRC")) != NULL) {
393         strncpy(chasenrc_path, rc_env, PATH_MAX);
394         return cha_fopen(chasenrc_path, "r", 1);
395     }
396
397     /*
398      * .chasenrc in the home directory 
399      */
400     if ((home_dir = getenv("HOME")) != NULL) {
401         /*
402          * .chasenrc 
403          */
404         snprintf(chasenrc_path, PATH_MAX, "%s%s", home_dir, RC2FILE);
405         if ((fp = cha_fopen(chasenrc_path, "r", -1)) != NULL)
406             return fp;
407         snprintf(chasenrc_path, PATH_MAX, "%s%s", home_dir, RCFILE);
408         if ((fp = cha_fopen(chasenrc_path, "r", -1)) != NULL)
409             return fp;
410     }
411 #ifdef PATHTYPE_MSDOS
412     else if ((home_dir = getenv("HOMEDRIVE")) != NULL) {
413         snprintf(chasenrc_path, PATH_MAX, 
414                  "%s%s%s", home_dir, getenv("HOMEPATH"), RC2FILE);
415         if ((fp = cha_fopen(chasenrc_path, "r", -1)) != NULL)
416             return fp;
417         snprintf(chasenrc_path, PATH_MAX,
418                  "%s%s%s", home_dir, getenv("HOMEPATH"), RCFILE);
419         if ((fp = cha_fopen(chasenrc_path, "r", -1)) != NULL)
420             return fp;
421     }
422 #endif /* PATHTYPE_MSDOS */
423
424 #if defined HAVE_WINDOWS_H && !defined __CYGWIN__
425     if ((cha_read_registry(REG_PATH, REG_RC, chasenrc_path) != NULL) &&
426         ((fp = cha_fopen(chasenrc_path, "r", -1)) != NULL)) {
427         return fp;
428     }
429 #endif
430     strncpy(chasenrc_path, RCPATH, PATH_MAX);
431
432     if ((fp = cha_fopen(chasenrc_path, "r", -1)) != NULL)
433         return fp;
434
435     cha_exit(1, "can't open chasenrc or %s", chasenrc_path);
436
437     /*
438      * to avoid warning 
439      */
440     return NULL;
441 }
442
443 static void
444 add_delimiter(char *string)
445 {
446     char *s = string + strlen(string);
447
448     if (s[-1] != PATH_DELIMITER) {
449         s[0] = PATH_DELIMITER;
450         s[1] = '\0';
451     }
452 }
453
454 /*
455  * read .chasenrc and set grammar directory
456  */
457 void
458 cha_read_grammar_dir(void)
459 {
460     FILE *fp;
461     chasen_cell_t *cell;
462
463     fp = cha_fopen_rcfile();
464
465     while (!cha_s_feof(fp)) {
466         char *s;
467         cell = cha_s_read(fp);
468         s = cha_s_atom(cha_car(cell));
469         if (cha_litmatch(s, 1, STR_GRAM_FILE)) {
470             strncpy(grammar_dir, cha_s_atom(cha_car(cha_cdr(cell))), PATH_MAX);
471             add_delimiter(grammar_dir);
472             break;
473         }
474     }
475
476     if (grammar_dir[0] == '\0') {
477         char *s;
478
479 #if defined HAVE_WINDOWS_H && !defined __CYGWIN__
480         if (cha_read_registry(REG_PATH, REG_GRAMMAR,
481                               grammar_dir) != NULL) {
482             if (grammar_dir[0] != '\0')
483                 add_delimiter(grammar_dir);
484         } else {
485 #endif
486         strncpy(grammar_dir, chasenrc_path, PATH_MAX);
487         if ((s = strrchr(grammar_dir, PATH_DELIMITER)) != NULL)
488             s[1] = '\0';
489         else
490             grammar_dir[0] = '\0';
491 #if defined HAVE_WINDOWS_H && !defined __CYGWIN__
492         }
493 #endif
494     }
495
496     fclose(fp);
497 }
498
499 char *
500 cha_read_registry(char *path, char *name, char *val)
501 {
502 #if defined HAVE_WINDOWS_H && !defined __CYGWIN__
503     HKEY hKey;
504     DWORD size = PATH_MAX;
505
506     if ((RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, 
507                       KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) &&
508         (RegQueryValueEx(hKey, name, NULL, NULL, (LPBYTE)val, &size) ==
509          ERROR_SUCCESS)) {
510         RegCloseKey(hKey);
511     } else
512         val = NULL;
513
514     return val;
515 #else
516     return NULL;
517 #endif
518 }