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