/* $Id$ */ #include "Japanese.h" #include "getcode.h" #include #ifndef dAX /* 5.6.x? */ #define dAX I32 ax = MARK - PL_stack_base + 1 #endif #define PERL_PATCHLEVEL_H_IMPLICIT #include "patchlevel.h" #if !defined(PERL_VERSION) && defined(PATCHLEVEL) /* 5.005_xx and prior */ #define PERL_REVISION 5 #define PERL_VERSION PATCHLEVEL #define PERL_SUBVERSION SUBVERSION #endif #if PERL_VERSION <= 4 && !defined(PL_stack_base) /* 5.004 */ extern SV ** Perl_stack_base; #define PL_stack_base Perl_stack_base #endif #define GC_DISP 0 #ifndef __cplusplus #undef bool #undef true #undef false typedef enum bool { false, true, } bool; #endif /* 文字コード定数 */ enum charcode_t { cc_unknown, cc_ascii, cc_sjis, cc_eucjp, cc_jis_au, cc_jis_jsky, cc_jis, cc_utf8, cc_utf16, cc_utf32, cc_utf32_be, cc_utf32_le, cc_sjis_jsky, cc_sjis_au, cc_sjis_imode, cc_sjis_doti, cc_last, }; typedef enum charcode_t charcode_t; /* 文字コード名文字列(SV*) */ #define new_CC_UNKNOWN() newSVpvn("unknown", 7) #define new_CC_ASCII() newSVpvn("ascii", 5) #define new_CC_SJIS() newSVpvn("sjis", 4) #define new_CC_JIS_AU() newSVpvn("jis-au", 6) #define new_CC_JIS_JSKY() newSVpvn("jis-jsky",8) #define new_CC_JIS() newSVpvn("jis", 3) #define new_CC_EUCJP() newSVpvn("euc", 3) #define new_CC_UTF8() newSVpvn("utf8", 4) #define new_CC_UTF16() newSVpvn("utf16", 5) #define new_CC_UTF32() newSVpvn("utf32", 5) #define new_CC_UTF32_BE() newSVpvn("utf32-be",8) #define new_CC_UTF32_LE() newSVpvn("utf32-le",8) #define new_CC_SJIS_JSKY() newSVpvn("sjis-jsky",9) #define new_CC_SJIS_IMODE() newSVpvn("sjis-imode",10) #define new_CC_SJIS_DOTI() newSVpvn("sjis-doti",9) #define new_CC_SJIS_AU() newSVpvn("sjis-au",7) /* */ #define RE_BOM2_BE "\xfe\xff" #define RE_BOM2_LE "\xff\xfe" #define RE_BOM4_BE "\x00\x00\xfe\xff" #define RE_BOM4_LE "\xff\xfe\x00\x00" #if defined(TEST) && GC_DISP /* 文字コード定数を文字コード名に. */ static const char* charcodeToStr(charcode_t code) { switch(code) { case cc_unknown: return "unknown"; case cc_ascii: return "ascii"; case cc_sjis: return "sjis"; case cc_eucjp: return "eucjp"; case cc_jis_au: return "jis-au"; case cc_jis_jsky: return "jis-jsky"; case cc_jis: return "jis"; case cc_utf8: return "utf8"; case cc_utf32: return "utf32"; case cc_utf32_be: return "utf32-be"; case cc_utf32_le: return "utf32-le"; case cc_sjis_jsky: return "sjis-jsky"; case cc_sjis_imode: return "sjis-imode"; case cc_sjis_doti: return "sjis-doti"; case cc_sjis_au: return "sjis-au"; default: return NULL; } } #endif #ifdef TEST DECL_MAP_MODE(ascii,1) = { "ascii", }; DECL_MAP_MODE(eucjp,5) = { "eucjp", "0212:3.1","0212:3.2","c:2.1","kana:2.1",}; DECL_MAP_MODE(sjis,2) = { "sjis","c:2.1", }; DECL_MAP_MODE(jis,11) = { "jis","jis#1","jis#2","jis#3","jis#4","jis#5","jis#6", "jis#7","jis#loop1","jis#loop2","jis#kana", }; DECL_MAP_MODE(jis_au,12) = { "jis","jis#1","jis#2","jis#3","jis#4","jis#5","jis#6", "jis#7","jis#loop1","jis#loop2","jis#kana","jis#au", }; DECL_MAP_MODE(jis_jsky,13) = { "jis","jis#1","jis#2","jis#3","jis#4","jis#5","jis#6", "jis#7","jis#loop1","jis#loop2","jis#kana","jis#j2","jis#jend", }; DECL_MAP_MODE(utf8,6) = { "utf8", "u8:6.1","u8:6.2","u8:6.3","u8:6.4","u8:6.5", }; DECL_MAP_MODE(utf32_be,4) = { "utf32-be","utf32-be:4:1","utf32-be:4:2","utf32-be:4:3", }; DECL_MAP_MODE(utf32_le,4) = { "utf32-le","utf32-le:4:1","utf32-le:4:2","utf32-le:4:3", }; DECL_MAP_MODE(sjis_jsky,5) = { "sjis","c:2.1", "jsky:start:1","jsky:start:2","jsky:code1", }; DECL_MAP_MODE(sjis_imode,4) = { "sjis","c:2.1", "imode1:1","imode2:1", }; DECL_MAP_MODE(sjis_doti,7) = { "sjis","c:2.1", "doti1:1", "doti2:1", "doti3:1", "doti4:1", "doti5:1", }; DECL_MAP_MODE(sjis_au,3) = { "sjis","c:2.1", "au:1", }; #endif /* 文字コード判定時に使用する構造体. */ struct CodeCheck { charcode_t code; const unsigned char* base; const unsigned char* table; #ifdef TEST const char** msg; #endif }; typedef struct CodeCheck CodeCheck; /* 文字コード判定の初期状態. */ #ifndef TEST #define GEN_CODE(name) \ { cc_##name, (const unsigned char*)map_##name, (const unsigned char*)map_##name, } #else #define GEN_CODE(name) \ { cc_##name, (const unsigned char*)map_##name, (const unsigned char*)map_##name, mode_##name, } #endif #define cc_tmpl_max 13 const CodeCheck cc_tmpl[cc_tmpl_max] = { GEN_CODE(utf32_be), GEN_CODE(utf32_le), GEN_CODE(ascii), GEN_CODE(jis), GEN_CODE(jis_au), GEN_CODE(jis_jsky), GEN_CODE(eucjp), GEN_CODE(sjis), GEN_CODE(sjis_jsky), GEN_CODE(sjis_imode), GEN_CODE(sjis_au), GEN_CODE(sjis_doti), GEN_CODE(utf8), }; /* 判定結果の構造体. */ struct CodeResult { charcode_t code; int begin; int len; }; typedef struct CodeResult CodeResult; static bool _is_acceptable_state(const CodeCheck* check) { /* special cases. */ if( check->table==map_jis_jsky[11] ) { /* jis-jsky, jis#j2 */ return true; } if( check->table==map_sjis_jsky[4] ) { /* sjis-jsky, sjis#j2 */ return true; } return false; } static int getcode_list(SV* sv_str, CodeCheck* check) { unsigned char* src; int len; const unsigned char* src_end; int cc_max; if( sv_str==&PL_sv_undef ) { return 0; } src = (unsigned char*)SvPV(sv_str,PL_na); len = sv_len(sv_str); src_end = src+len; /* empty string */ /* (jp:) 空文字列は unknown */ if( len==0 ) { return 0; } /* BOM of UTF32 */ if( (len%4)==0 && len>=4 && ( memcmp(src,RE_BOM4_BE,4)==0 || memcmp(src,RE_BOM4_LE,4)==0 ) ) { check[0].code = cc_utf32; return 1; } /* BOM of UTF16 */ if( (len%2)==0 && len>=2 && ( memcmp(src,RE_BOM2_BE,2)==0 || memcmp(src,RE_BOM2_LE,2)==0 ) ) { check[0].code = cc_utf16; return 1; } /* fprintf(stderr,"Unicode::Japanese::(xs)getcode[%d]\n",len); */ /* fprintf(stderr,">>%s<<\n",src); */ /* bin_dump("in ",src,len); */ memcpy(check,cc_tmpl,sizeof(cc_tmpl)); cc_max = cc_tmpl_max; for( ; src0 ) { /* まだあり〜 */ int rd = 0; int wr = 0; for( ;rd\n"); { int i; for( i=0; i0 ) { int index = 0; #if TEST && GC_DISP fprintf(stderr,"\n"); fprintf(stderr," %d of 0..%d\n",index,matches-1); fprintf(stderr," %s\n",charcodeToStr(check[index].code)); #endif switch(check[index].code) { case cc_unknown: return new_CC_UNKNOWN(); case cc_ascii: return new_CC_ASCII(); case cc_sjis: return new_CC_SJIS(); case cc_eucjp: return new_CC_EUCJP(); case cc_jis: return new_CC_JIS(); case cc_jis_au: return new_CC_JIS_AU(); case cc_jis_jsky: return new_CC_JIS_JSKY(); case cc_utf8: return new_CC_UTF8(); case cc_utf16: return new_CC_UTF16(); case cc_utf32: return new_CC_UTF32(); case cc_utf32_be: return new_CC_UTF32_BE(); case cc_utf32_le: return new_CC_UTF32_LE(); case cc_sjis_jsky: return new_CC_SJIS_JSKY(); case cc_sjis_imode: return new_CC_SJIS_IMODE(); case cc_sjis_doti: return new_CC_SJIS_DOTI(); case cc_sjis_au: return new_CC_SJIS_AU(); default: #ifdef TEST return NULL; #else return new_CC_UNKNOWN(); #endif } }else { return new_CC_UNKNOWN(); } } /* getcode_list関数 */ int xs_getcode_list(SV* sv_str) { int matches; CodeCheck check[cc_tmpl_max]; int i; dSP; dMARK; dAX; /* XSARGS; - items */ if( sv_str==&PL_sv_undef ) { return 0; } matches = getcode_list(sv_str, check); if( matches<=0 ) { return 0; } EXTEND(SP, matches); for( i=0; i