OSDN Git Service

Bumped version 2.4.4.
[chasen-legacy/chasen.git] / lib / jfgets.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  * NOTE: An idea of these procedures are taken from youhcan's jutils.c
31  *       for wais-japanese
32  * 
33  * $Id: jfgets.c,v 1.1.1.1 2007/03/13 07:40:10 masayu-a Exp $
34  */
35
36
37 #include <stdio.h>
38 #include <string.h>
39
40 #define INNER_BUFSIZE   8192
41
42 /*
43  * delimiter for cha_jfgets() 
44  */
45 static char jfgets_delimiter[256] = "¡¥¡£¡ª¡©";
46
47 void
48 cha_set_jfgets_delimiter(char *delimiter)
49 {
50     strncpy(jfgets_delimiter, delimiter, sizeof(jfgets_delimiter));
51 }
52
53 int
54 cha_jistoeuc(unsigned char *ibuffer, unsigned char *obuffer)
55 {
56     unsigned char *p, *o;
57     int level, flag;
58
59     level = 0;
60     flag = 0;
61     o = obuffer;
62
63     for (p = ibuffer; *p; p++) {
64         if (*p == 0x1b) {
65             level = 1;
66         } else if (level == 1) {
67             if (*p == '$')
68                 level = 2;      /* ESC $ */
69             else if (*p == '(')
70                 level = 12;     /* ESC ( */
71             else
72                 level = 0;
73         } else if (level) {
74             /*
75              * Translation 
76              */
77             if (level == 2 && *p == '@')
78                 flag = 1;       /* ESC $ @ */
79             if (level == 2 && *p == 'B')
80                 flag = 1;       /* ESC $ B */
81             if (level == 12 && *p == 'B')
82                 flag = 0;       /* ESC ( B */
83             if (level == 12 && *p == 'J')
84                 flag = 0;       /* ESC ( J */
85
86             /*
87              * Give up to parse escape sequence 
88              */
89             level = 0;
90         } else if (flag && *p >= 0x20) {
91             /*
92              * KANJI mode without control characters 
93              */
94             *o++ = *p++ | 0x80;
95             *o++ = *p | 0x80;
96         }
97         /*
98          * ASCII mode or control character in KANJI mode 
99          */
100         /*
101          * plural space characters -> single space 
102          */
103         else if (*p == ' ' || *p == '\t') {
104             if (o == obuffer || o[-1] != ' ')
105                 *o++ = ' ';
106         } else {
107             *o++ = *p;
108         }
109     }
110     *o = '\0';
111
112     return 0;
113 }
114
115 /*
116  * isterminator - check it is terminator or not
117  *
118  * return
119  *               1: terminator
120  *               0: not terminator
121  *              -1:     error
122  */
123
124 static int
125 isterminator(unsigned char *target, unsigned char *termlist)
126 {
127     if (termlist == NULL || target == NULL) {
128         return -1;
129     }
130
131     while (*termlist) {
132         if (*termlist & 0x80) {
133             if (*termlist == *target && *(termlist + 1) == *(target + 1))
134                 return 1;
135             termlist += 2;
136         } else {
137             if (*termlist == *target)
138                 return 1;
139             termlist++;
140         }
141     }
142     return 0;
143 }
144
145 /*
146  * inner buffer and inner position.
147  *      if stream is empty. 'pos' point NULL.
148  *
149  */
150 static int
151 iskanji1(unsigned char *str, int idx)
152 {
153     int n;
154
155     for (n = 0; idx >= 0 && str[idx] >= 0x80; n++, idx--);
156
157     return n & 1;
158 }
159
160 /*
161  * cha_fget_line - get line via fgets(). So it is really reading function :-)
162  */
163 char *
164 cha_fget_line(char *buffer, int bufsize, FILE * stream)
165 {
166     static unsigned char tmp_buf[INNER_BUFSIZE];
167     int last;
168
169     if (fgets(tmp_buf, bufsize, stream) == NULL)
170         return NULL;
171
172     /*
173      * remove the last extra character 
174      */
175     last = strlen(tmp_buf) - 1;
176     if (iskanji1(tmp_buf, last)) {
177         ungetc(tmp_buf[last], stream);
178         tmp_buf[last] = 0;
179     }
180
181     /*
182      * call convertor
183      * NOTE: EUC string is short than JIS string.
184      *       if you want to other conversion,
185      *       you must care about string length.
186      */
187
188     cha_jistoeuc(tmp_buf, buffer);
189
190     return buffer;
191 }
192
193 /*
194  * cha_jfgets - fgets() for Japanese Text.
195  *
196  */
197 char *
198 cha_jfgets(char *buffer, int bufsize, FILE * stream)
199 {
200     static unsigned char ibuf[INNER_BUFSIZE];
201     /* set to the end of line */
202     static unsigned char *pos = (unsigned char *) "";
203     unsigned char *q;
204     int count;
205     int kflag;  /* kanji flag(0=not found, 1=found) */
206
207     if (pos == NULL &&
208         (pos = cha_fget_line(ibuf, sizeof(ibuf), stream)) == NULL)
209         return NULL;
210
211     kflag = 0;
212     q = (unsigned char *) buffer;
213     bufsize--;
214
215     for (count = bufsize; count > 0; count--) {
216         /*
217          * line is end without '\n', long string read more 
218          */
219         if (*pos == '\0')
220             if ((pos = cha_fget_line(ibuf, sizeof(ibuf), stream)) == NULL)
221                 break;
222
223         /*
224          * KANJI 
225          */
226         if (*pos >= 0x80 && *(pos + 1)) {
227             if (count < 2)
228                 break;
229             kflag = 1;
230             count--;
231             *q++ = *pos++;
232             *q++ = *pos++;
233
234             /*
235              * hit delimiter 
236              */
237             if (isterminator(pos - 2, jfgets_delimiter)) {
238                 if (*pos == '\n')
239                     pos++;
240                 break;
241             }
242         }
243         /*
244          * not KANJI 
245          */
246         else {
247             /*
248              * line is end 
249              */
250             if (*pos == '\n') {
251                 /*
252                  * eliminate space characters at the end of line 
253                  */
254                 while (q > (unsigned char *) buffer
255                        && (q[-1] == ' ' || q[-1] == '\t'))
256                     q--;
257
258                 if ((pos =
259                      cha_fget_line(ibuf, sizeof(ibuf), stream)) == NULL)
260                     break;
261
262                 while (*pos == ' ' || *pos == '\t')
263                     pos++;
264
265                 /*
266                  * not have kanji or no space, return with this line 
267                  */
268                 if (count <= 0)
269                     break;
270
271                 /*
272                  * have kanji, connect next line 
273                  */
274                 /*
275                  * double '\n' is paragraph end. so it is delimiter 
276                  */
277                 if (*pos == '\n')
278                     break;
279
280                 /*
281                  * "ASCII\nASCII" -> "ASCII ASCII" 
282                  */
283                 if (!kflag && !(*pos & 0x80))
284                     *q++ = ' ';
285             } else {
286                 if (*pos != ' ' && *pos != '\t')
287                     kflag = 0;
288                 *q++ = *pos++;
289
290                 /*
291                  * hit delimiter 
292                  */
293                 if (isterminator(pos - 1, jfgets_delimiter)) {
294                     if (*pos == '\n')
295                         pos++;
296                     break;
297                 }
298             }
299         }
300
301     }
302
303     *q = '\0';
304
305     return buffer;
306 }