File Coverage

getcode.c
Criterion Covered Total %
statement 74 116 63.7
branch 49 74 66.2
condition n/a
subroutine n/a
pod n/a
total 123 190 64.7


line stmt bran cond sub pod time code
1              
2             /* $Id: getcode.c 5404 2008-02-01 05:07:01Z hio $ */
3              
4             #include "Japanese.h"
5             #include "getcode.h"
6              
7             #include
8              
9             #ifndef dAX
10             /* 5.6.x? */
11             #define dAX I32 ax = MARK - PL_stack_base + 1
12             #endif
13              
14             #define PERL_PATCHLEVEL_H_IMPLICIT
15             #include "patchlevel.h"
16              
17             #if !defined(PERL_VERSION) && defined(PATCHLEVEL)
18             /* 5.005_xx and prior */
19             #define PERL_REVISION 5
20             #define PERL_VERSION PATCHLEVEL
21             #define PERL_SUBVERSION SUBVERSION
22             #endif
23              
24             #if PERL_VERSION <= 4 && !defined(PL_stack_base)
25             /* 5.004 */
26             extern SV ** Perl_stack_base;
27             #define PL_stack_base Perl_stack_base
28             #endif
29              
30             #define GC_DISP 0
31              
32             /* 文字コード定数 */
33             enum charcode_t
34             {
35             cc_unknown,
36             cc_ascii,
37             cc_sjis,
38             cc_eucjp,
39             cc_jis_au,
40             cc_jis_jsky,
41             cc_jis,
42             cc_utf8,
43             cc_utf16,
44             cc_utf32,
45             cc_utf32_be,
46             cc_utf32_le,
47             cc_sjis_jsky,
48             cc_sjis_au,
49             cc_sjis_imode,
50             cc_sjis_doti,
51             cc_last,
52             };
53             typedef enum charcode_t charcode_t;
54              
55             /* 文字コード名文字列(SV*) */
56             #define new_CC_UNKNOWN() newSVpvn("unknown", 7)
57             #define new_CC_ASCII() newSVpvn("ascii", 5)
58             #define new_CC_SJIS() newSVpvn("sjis", 4)
59             #define new_CC_JIS_AU() newSVpvn("jis-au", 6)
60             #define new_CC_JIS_JSKY() newSVpvn("jis-jsky",8)
61             #define new_CC_JIS() newSVpvn("jis", 3)
62             #define new_CC_EUCJP() newSVpvn("euc", 3)
63             #define new_CC_UTF8() newSVpvn("utf8", 4)
64             #define new_CC_UTF16() newSVpvn("utf16", 5)
65             #define new_CC_UTF32() newSVpvn("utf32", 5)
66             #define new_CC_UTF32_BE() newSVpvn("utf32-be",8)
67             #define new_CC_UTF32_LE() newSVpvn("utf32-le",8)
68             #define new_CC_SJIS_JSKY() newSVpvn("sjis-jsky",9)
69             #define new_CC_SJIS_IMODE() newSVpvn("sjis-imode",10)
70             #define new_CC_SJIS_DOTI() newSVpvn("sjis-doti",9)
71             #define new_CC_SJIS_AU() newSVpvn("sjis-au",7)
72              
73             /* */
74             #define RE_BOM2_BE "\xfe\xff"
75             #define RE_BOM2_LE "\xff\xfe"
76             #define RE_BOM4_BE "\x00\x00\xfe\xff"
77             #define RE_BOM4_LE "\xff\xfe\x00\x00"
78              
79             #if defined(TEST) && GC_DISP
80             /* 文字コード定数を文字コード名に. */
81             static const char* charcodeToStr(charcode_t code)
82             {
83             switch(code)
84             {
85             case cc_unknown: return "unknown";
86             case cc_ascii: return "ascii";
87             case cc_sjis: return "sjis";
88             case cc_eucjp: return "eucjp";
89             case cc_jis_au: return "jis-au";
90             case cc_jis_jsky: return "jis-jsky";
91             case cc_jis: return "jis";
92             case cc_utf8: return "utf8";
93             case cc_utf32: return "utf32";
94             case cc_utf32_be: return "utf32-be";
95             case cc_utf32_le: return "utf32-le";
96             case cc_sjis_jsky: return "sjis-jsky";
97             case cc_sjis_imode: return "sjis-imode";
98             case cc_sjis_doti: return "sjis-doti";
99             case cc_sjis_au: return "sjis-au";
100             default: return NULL;
101             }
102             }
103             #endif
104             #ifdef TEST
105             DECL_MAP_MODE(ascii,1) = { "ascii", };
106             DECL_MAP_MODE(eucjp,5) =
107             { "eucjp", "0212:3.1","0212:3.2","c:2.1","kana:2.1",};
108             DECL_MAP_MODE(sjis,2) = { "sjis","c:2.1", };
109             DECL_MAP_MODE(jis,11) =
110             {
111             "jis","jis#1","jis#2","jis#3","jis#4","jis#5","jis#6",
112             "jis#7","jis#loop1","jis#loop2","jis#kana",
113             };
114             DECL_MAP_MODE(jis_au,12) =
115             {
116             "jis","jis#1","jis#2","jis#3","jis#4","jis#5","jis#6",
117             "jis#7","jis#loop1","jis#loop2","jis#kana","jis#au",
118             };
119             DECL_MAP_MODE(jis_jsky,13) =
120             {
121             "jis","jis#1","jis#2","jis#3","jis#4","jis#5","jis#6",
122             "jis#7","jis#loop1","jis#loop2","jis#kana","jis#j2","jis#jend",
123             };
124             DECL_MAP_MODE(utf8,6) =
125             {
126             "utf8",
127             "u8:6.1","u8:6.2","u8:6.3","u8:6.4","u8:6.5",
128             };
129             DECL_MAP_MODE(utf32_be,4) =
130             {
131             "utf32-be","utf32-be:4:1","utf32-be:4:2","utf32-be:4:3",
132             };
133             DECL_MAP_MODE(utf32_le,4) =
134             {
135             "utf32-le","utf32-le:4:1","utf32-le:4:2","utf32-le:4:3",
136             };
137             DECL_MAP_MODE(sjis_jsky,5) =
138             {
139             "sjis","c:2.1",
140             "jsky:start:1","jsky:start:2","jsky:code1",
141             };
142             DECL_MAP_MODE(sjis_imode,4) =
143             {
144             "sjis","c:2.1",
145             "imode1:1","imode2:1",
146             };
147             DECL_MAP_MODE(sjis_doti,7) =
148             {
149             "sjis","c:2.1",
150             "doti1:1", "doti2:1", "doti3:1", "doti4:1", "doti5:1",
151             };
152             DECL_MAP_MODE(sjis_au,3) =
153             {
154             "sjis","c:2.1",
155             "au:1",
156             };
157             #endif
158              
159             /* 文字コード判定時に使用する構造体. */
160             struct CodeCheck
161             {
162             charcode_t code;
163             const unsigned char* base;
164             const unsigned char* table;
165             #ifdef TEST
166             const char** msg;
167             #endif
168             };
169             typedef struct CodeCheck CodeCheck;
170              
171             /* 文字コード判定の初期状態. */
172             #ifndef TEST
173             #define GEN_CODE(name) \
174             { cc_##name, (const unsigned char*)map_##name, (const unsigned char*)map_##name, }
175             #else
176             #define GEN_CODE(name) \
177             { cc_##name, (const unsigned char*)map_##name, (const unsigned char*)map_##name, mode_##name, }
178             #endif
179             #define cc_tmpl_max 13
180             const CodeCheck cc_tmpl[cc_tmpl_max] =
181             {
182             GEN_CODE(utf32_be),
183             GEN_CODE(utf32_le),
184             GEN_CODE(ascii),
185             GEN_CODE(jis),
186             GEN_CODE(jis_au),
187             GEN_CODE(jis_jsky),
188             GEN_CODE(eucjp),
189             GEN_CODE(sjis),
190             GEN_CODE(sjis_jsky),
191             GEN_CODE(sjis_imode),
192             GEN_CODE(sjis_au),
193             GEN_CODE(sjis_doti),
194             GEN_CODE(utf8),
195             };
196              
197             /* 判定結果の構造体. */
198             struct CodeResult
199             {
200             charcode_t code;
201             int begin;
202             int len;
203             };
204             typedef struct CodeResult CodeResult;
205              
206 14           static bool _is_acceptable_state(const CodeCheck* check)
207             {
208             /* special cases. */
209 14 50         if( check->table==map_jis_jsky[11] )
210             { /* jis-jsky, jis#j2 */
211 0           return true;
212             }
213 14 50         if( check->table==map_sjis_jsky[4] )
214             { /* sjis-jsky, sjis#j2 */
215 0           return true;
216             }
217 14           return false;
218             }
219              
220 100           static int getcode_list(SV* sv_str, CodeCheck* check)
221             {
222             unsigned char* src;
223             STRLEN len;
224             const unsigned char* src_end;
225             int cc_max;
226            
227 100 50         if( sv_str==&PL_sv_undef )
228             {
229 0           return 0;
230             }
231 100 50         if( SvGMAGICAL(sv_str) )
232             {
233 0           mg_get(sv_str);
234             }
235 100 50         if( !SvOK(sv_str) )
236             {
237 0           return 0;
238             }
239            
240 100           src = (unsigned char*)SvPV(sv_str, len);
241 100           src_end = src+len;
242            
243             /* empty string */
244             /* (jp:) 空文字列は unknown */
245 100 100         if( len==0 )
246             {
247 1           return 0;
248             }
249            
250             /* BOM of UTF32 */
251 99 100         if( (len%4)==0 && len>=4 &&
    50          
252 13 100         ( memcmp(src,RE_BOM4_BE,4)==0 || memcmp(src,RE_BOM4_LE,4)==0 ) )
    100          
253             {
254 2           check[0].code = cc_utf32;
255 2           return 1;
256             }
257            
258             /* BOM of UTF16 */
259 97 100         if( (len%2)==0 && len>=2 &&
    50          
260 17 100         ( memcmp(src,RE_BOM2_BE,2)==0 || memcmp(src,RE_BOM2_LE,2)==0 ) )
    100          
261             {
262 2           check[0].code = cc_utf16;
263 2           return 1;
264             }
265              
266             /* fprintf(stderr,"Unicode::Japanese::(xs)getcode[%d]\n",len); */
267             /* fprintf(stderr,">>%s<<\n",src); */
268             /* bin_dump("in ",src,len); */
269              
270 95           memcpy(check,cc_tmpl,sizeof(cc_tmpl));
271 95           cc_max = cc_tmpl_max;
272              
273 578 100         for( ; src
274             {
275             int invalids;
276             int i;
277             #if TEST && GC_DISP
278             fprintf(stderr,"[%d] '%c' 0x%02x (%d)\n",len-(src_end-src),(0x20<=*src&&*src<=0x7f?*src:'.'),*src,*src);
279             #endif
280             /* 遷移を1つ進める〜 */
281 484           invalids = 0;
282 3513 100         for( i=0; i
283             {
284 3029           int nxt = check[i].table[*src];
285             #if TEST && GC_DISP
286             fprintf(stderr," %s : %d (%s)\n",charcodeToStr(check[i].code),nxt,nxt!=map_invalid?check[i].msg[nxt]:"invalid");
287             #endif
288 3029 100         if( nxt!=map_invalid )
289             {
290 1942           check[i].table = check[i].base+nxt*256;
291             }else
292             {
293 1087           ++invalids;
294 1087           check[i].table = NULL;
295             }
296             }
297 484 100         if( invalids==0 )
298             { /* 全部継続 */
299 214           continue;
300 270 100         }else if( cc_max-invalids>0 )
301             { /* まだあり〜 */
302 269           int rd = 0;
303 269           int wr = 0;
304 2480 100         for( ;rd
305             {
306 2211 100         if( check[rd].table )
307             {
308 1129 100         if( rd!=wr )
309             {
310 1121           check[wr] = check[rd];
311             }
312 1129           ++wr;
313             }
314             }
315 269           cc_max = wr;
316             }else
317             { /* 全部だめ〜 */
318 1           return 0;
319             }
320             }
321              
322             /* check if we have stopped at a valid (final?) state */
323             {
324 94           int wr = 0;
325             int i;
326 242 100         for( i=0; i
327             {
328 148 100         if( check[i].table == check[i].base || _is_acceptable_state(&check[i]) )
    50          
329             {
330 134 100         if( wr!=i )
331             {
332 18           check[wr] = check[i];
333             }
334 134           ++wr;
335             }
336             }
337 94           cc_max = wr;
338             }
339              
340             #if TEST && GC_DISP
341             fprintf(stderr,"\n");
342             {
343             int i;
344             for( i=0; i
345             {
346             fprintf(stderr," %s\n",charcodeToStr(check[i].code));
347             }
348             }
349             #endif
350            
351 94           return cc_max;
352             }
353              
354             #ifndef NO_XSUBS
355              
356             /* getcode関数 */
357 100           SV* xs_getcode(SV* sv_str)
358             {
359             int matches;
360             CodeCheck check[cc_tmpl_max];
361            
362 100 50         if( sv_str==&PL_sv_undef )
363             {
364 0           return new_SV_UNDEF();
365             }
366 100 50         if( SvGMAGICAL(sv_str) )
367             {
368 0           mg_get(sv_str);
369             }
370 100 50         if( !SvOK(sv_str) )
371             {
372 0           return newSVsv(&PL_sv_undef);
373             }
374 100           matches = getcode_list(sv_str, check);
375 100 100         if( matches>0 )
376             {
377 98           int index = 0;
378             #if TEST && GC_DISP
379             fprintf(stderr,"\n");
380             fprintf(stderr," %d of 0..%d\n",index,matches-1);
381             fprintf(stderr," %s\n",charcodeToStr(check[index].code));
382             #endif
383 98           switch(check[index].code)
384             {
385 0           case cc_unknown: return new_CC_UNKNOWN();
386 1           case cc_ascii: return new_CC_ASCII();
387 2           case cc_sjis: return new_CC_SJIS();
388 1           case cc_eucjp: return new_CC_EUCJP();
389 2           case cc_jis: return new_CC_JIS();
390 1           case cc_jis_au: return new_CC_JIS_AU();
391 1           case cc_jis_jsky: return new_CC_JIS_JSKY();
392 1           case cc_utf8: return new_CC_UTF8();
393 2           case cc_utf16: return new_CC_UTF16();
394 2           case cc_utf32: return new_CC_UTF32();
395 1           case cc_utf32_be: return new_CC_UTF32_BE();
396 1           case cc_utf32_le: return new_CC_UTF32_LE();
397 2           case cc_sjis_jsky: return new_CC_SJIS_JSKY();
398 77           case cc_sjis_imode: return new_CC_SJIS_IMODE();
399 2           case cc_sjis_doti: return new_CC_SJIS_DOTI();
400 2           case cc_sjis_au: return new_CC_SJIS_AU();
401            
402 0           default:
403             #ifdef TEST
404             return NULL;
405             #else
406 0           return new_CC_UNKNOWN();
407             #endif
408             }
409             }else
410             {
411 2           return new_CC_UNKNOWN();
412             }
413             }
414              
415             /* getcode_list関数 */
416 0           int xs_getcode_list(SV* sv_str)
417             {
418             int matches;
419             CodeCheck check[cc_tmpl_max];
420             int i;
421 0           dSP; dMARK; dAX; /* XSARGS; - items */
422            
423 0 0         if( sv_str==&PL_sv_undef )
424             {
425 0           return 0;
426             }
427 0 0         if( SvGMAGICAL(sv_str) )
428             {
429 0           mg_get(sv_str);
430             }
431 0 0         if( !SvOK(sv_str) )
432             {
433 0           return 0;
434             }
435 0           matches = getcode_list(sv_str, check);
436 0 0         if( matches<=0 )
437             {
438 0           return 0;
439             }
440 0 0         EXTEND(SP, matches);
    0          
441 0 0         for( i=0; i
442             {
443 0           switch(check[i].code)
444             {
445 0           case cc_unknown: ST(i) = sv_2mortal( new_CC_UNKNOWN() ); break;
446 0           case cc_ascii: ST(i) = sv_2mortal( new_CC_ASCII() ); break;
447 0           case cc_sjis: ST(i) = sv_2mortal( new_CC_SJIS() ); break;
448 0           case cc_eucjp: ST(i) = sv_2mortal( new_CC_EUCJP() ); break;
449 0           case cc_jis: ST(i) = sv_2mortal( new_CC_JIS() ); break;
450 0           case cc_jis_au: ST(i) = sv_2mortal( new_CC_JIS_AU() ); break;
451 0           case cc_jis_jsky: ST(i) = sv_2mortal( new_CC_JIS_JSKY() ); break;
452 0           case cc_utf8: ST(i) = sv_2mortal( new_CC_UTF8() ); break;
453 0           case cc_utf16: ST(i) = sv_2mortal( new_CC_UTF16() ); break;
454 0           case cc_utf32: ST(i) = sv_2mortal( new_CC_UTF32() ); break;
455 0           case cc_utf32_be: ST(i) = sv_2mortal( new_CC_UTF32_BE() ); break;
456 0           case cc_utf32_le: ST(i) = sv_2mortal( new_CC_UTF32_LE() ); break;
457 0           case cc_sjis_jsky: ST(i) = sv_2mortal( new_CC_SJIS_JSKY() ); break;
458 0           case cc_sjis_imode: ST(i) = sv_2mortal( new_CC_SJIS_IMODE() ); break;
459 0           case cc_sjis_doti: ST(i) = sv_2mortal( new_CC_SJIS_DOTI() ); break;
460 0           default: ST(i) = sv_2mortal( new_CC_UNKNOWN() ); break;
461             }
462             }
463 0           return matches;
464             }
465              
466             #endif
467              
468             /* ----------------------------------------------------------------------------
469             * End of File.
470             * ------------------------------------------------------------------------- */