/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * The following vector shows remaining bytes in a UTF-8 character. * Index will be the first byte of the character. This is defined in * u8_textprep.c. */ extern const int8_t u8_number_of_bytes[]; /* * The following is a vector of bit-masks to get used bits in * the first byte of a UTF-8 character. Index is remaining bytes at above of * the character. This is defined in uconv.c. */ extern const uchar_t u8_masks_tbl[]; /* * The following two vectors are to provide valid minimum and * maximum values for the 2'nd byte of a multibyte UTF-8 character for * better illegal sequence checking. The index value must be the value of * the first byte of the UTF-8 character. These are defined in u8_textprep.c. */ extern const uint8_t u8_valid_min_2nd_byte[]; extern const uint8_t u8_valid_max_2nd_byte[]; static kiconv_ja_euc16_t kiconv_ja_ucs2_to_euc16(kiconv_ja_ucs2_t ucs2) { const kiconv_ja_euc16_t *p; if ((p = kiconv_ja_ucs2_to_euc16_index[ucs2 >> 8]) != NULL) return (p[ucs2 & 0xff]); return (KICONV_JA_NODEST); } static size_t utf8_ucs(uint_t *p, uchar_t **pip, size_t *pileft, int *errno) { uint_t l; /* to be copied to *p on successful return */ uchar_t ic; /* current byte */ uchar_t ic1; /* 1st byte */ uchar_t *ip = *pip; /* next byte to read */ size_t ileft = *pileft; /* number of bytes available */ size_t rv = 0; /* return value of this function */ int remaining_bytes; int u8_size; KICONV_JA_NGET(ic1); /* read 1st byte */ if (ic1 < 0x80) { /* successfully converted */ *p = (uint_t)ic1; goto ret; } u8_size = u8_number_of_bytes[ic1]; if (u8_size == U8_ILLEGAL_CHAR) { KICONV_JA_RETERROR(EILSEQ) } else if (u8_size == U8_OUT_OF_RANGE_CHAR) { KICONV_JA_RETERROR(ERANGE) } remaining_bytes = u8_size - 1; if (remaining_bytes != 0) { l = ic1 & u8_masks_tbl[remaining_bytes]; for (; remaining_bytes > 0; remaining_bytes--) { KICONV_JA_NGET(ic); if (ic1 != 0U) { if ((ic < u8_valid_min_2nd_byte[ic1]) || (ic > u8_valid_max_2nd_byte[ic1])) { KICONV_JA_RETERROR(EILSEQ) } ic1 = 0U; /* 2nd byte check done */ } else { if ((ic < 0x80) || (ic > 0xbf)) { KICONV_JA_RETERROR(EILSEQ) } } l = (l << 6) | (ic & 0x3f); } /* successfully converted */ *p = l; } else { KICONV_JA_RETERROR(EILSEQ) } ret: if (rv == 0) { /* * Update rv, *pip, and *pileft on successfule return. */ rv = *pileft - ileft; *pip = ip; *pileft = ileft; } return (rv); } static size_t utf8_ucs_replace(uint_t *p, uchar_t **pip, size_t *pileft, size_t *repnum) { uint_t l; /* to be copied to *p on successful return */ uchar_t ic; /* current byte */ uchar_t ic1; /* 1st byte */ uchar_t *ip = *pip; /* next byte to read */ size_t ileft = *pileft; /* number of bytes available */ size_t rv = 0; /* return value of this function */ int remaining_bytes; int u8_size; KICONV_JA_NGET_REP_TO_MB(ic1); /* read 1st byte */ if (ic1 < 0x80) { /* successfully converted */ l = (uint_t)ic1; goto ret; } u8_size = u8_number_of_bytes[ic1]; if (u8_size == U8_ILLEGAL_CHAR || u8_size == U8_OUT_OF_RANGE_CHAR) { l = KICONV_JA_DEF_SINGLE; (*repnum)++; goto ret; } remaining_bytes = u8_size - 1; if (remaining_bytes != 0) { l = ic1 & u8_masks_tbl[remaining_bytes]; for (; remaining_bytes > 0; remaining_bytes--) { KICONV_JA_NGET_REP_TO_MB(ic); if (ic1 != 0U) { if ((ic < u8_valid_min_2nd_byte[ic1]) || (ic > u8_valid_max_2nd_byte[ic1])) { l = KICONV_JA_DEF_SINGLE; (*repnum)++; ileft -= (remaining_bytes - 1); ip += (remaining_bytes - 1); break; } ic1 = 0U; /* 2nd byte check done */ } else { if ((ic < 0x80) || (ic > 0xbf)) { l = KICONV_JA_DEF_SINGLE; (*repnum)++; ileft -= (remaining_bytes - 1); ip += (remaining_bytes - 1); break; } } l = (l << 6) | (ic & 0x3f); } } else { l = KICONV_JA_DEF_SINGLE; (*repnum)++; } ret: /* successfully converted */ *p = l; rv = *pileft - ileft; *pip = ip; *pileft = ileft; return (rv); } static size_t /* return #bytes read, or -1 */ read_unicode( uint_t *p, /* point variable to store UTF-32 */ uchar_t **pip, /* point pointer to input buf */ size_t *pileft, /* point #bytes left in input buf */ int *errno, /* point variable to errno */ int flag, /* kiconvstr flag */ size_t *rv) /* point return valuse */ { if (flag & KICONV_REPLACE_INVALID) return (utf8_ucs_replace(p, pip, pileft, rv)); else return (utf8_ucs(p, pip, pileft, errno)); } static size_t write_unicode( uint_t u32, /* UTF-32 to write */ char **pop, /* point pointer to output buf */ size_t *poleft, /* point #bytes left in output buf */ int *errno) /* point variable to errno */ { char *op = *pop; size_t oleft = *poleft; size_t rv = 0; /* return value */ if (u32 <= 0x7f) { KICONV_JA_NPUT((uchar_t)(u32)); rv = 1; } else if (u32 <= 0x7ff) { KICONV_JA_NPUT((uchar_t)((((u32)>>6) & 0x1f) | 0xc0)); KICONV_JA_NPUT((uchar_t)(((u32) & 0x3f) | 0x80)); rv = 2; } else if ((u32 >= 0xd800) && (u32 <= 0xdfff)) { KICONV_JA_RETERROR(EILSEQ) } else if (u32 <= 0xffff) { KICONV_JA_NPUT((uchar_t)((((u32)>>12) & 0x0f) | 0xe0)); KICONV_JA_NPUT((uchar_t)((((u32)>>6) & 0x3f) | 0x80)); KICONV_JA_NPUT((uchar_t)(((u32) & 0x3f) | 0x80)); rv = 3; } else if (u32 <= 0x10ffff) { KICONV_JA_NPUT((uchar_t)((((u32)>>18) & 0x07) | 0xf0)); KICONV_JA_NPUT((uchar_t)((((u32)>>12) & 0x3f) | 0x80)); KICONV_JA_NPUT((uchar_t)((((u32)>>6) & 0x3f) | 0x80)); KICONV_JA_NPUT((uchar_t)(((u32) & 0x3f) | 0x80)); rv = 4; } else { KICONV_JA_RETERROR(EILSEQ) } ret: if (rv != (size_t)-1) { /* update *pop and *poleft only on successful return */ *pop = op; *poleft = oleft; } return (rv); } static void * _kiconv_ja_open_unicode(uint8_t id) { kiconv_state_t kcd; kcd = (kiconv_state_t)kmem_alloc(sizeof (kiconv_state_data_t), KM_SLEEP); kcd->id = id; kcd->bom_processed = 0; return ((void *)kcd); } static void * open_eucjp(void) { return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_EUCJP)); } static void * open_eucjpms(void) { return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_EUCJP_MS)); } static void * open_sjis(void) { return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_SJIS)); } static void * open_cp932(void) { return (_kiconv_ja_open_unicode(KICONV_JA_TBLID_CP932)); } int close_ja(void *kcd) { if (! kcd || kcd == (void *)-1) return (EBADF); kmem_free(kcd, sizeof (kiconv_state_data_t)); return (0); } static size_t _do_kiconv_fr_eucjp(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int *errno) { uint_t u32; /* UTF-32 */ uint_t index; /* index for table lookup */ uchar_t ic1, ic2, ic3; /* 1st, 2nd, and 3rd bytes of a char */ size_t rv = 0; /* return value of this function */ uchar_t *ip; size_t ileft; char *op; size_t oleft; size_t id = ((kiconv_state_t)kcd)->id; if ((inbuf == NULL) || (*inbuf == NULL)) { return (0); } ip = (uchar_t *)*inbuf; ileft = *inbytesleft; op = *outbuf; oleft = *outbytesleft; while (ileft != 0) { KICONV_JA_NGET(ic1); /* get 1st byte */ if (KICONV_JA_ISASC(ic1)) { /* ASCII; 1 byte */ u32 = kiconv_ja_jisx0201roman_to_ucs2[ic1]; KICONV_JA_PUTU(u32); } else if (KICONV_JA_ISCS1(ic1)) { /* 0208 or UDC; 2 bytes */ KICONV_JA_NGET(ic2); if (KICONV_JA_ISCS1(ic2)) { /* 2nd byte check passed */ ic1 &= KICONV_JA_CMASK; ic2 &= KICONV_JA_CMASK; KICONV_JA_CNV_JISMS_TO_U2(id, u32, ic1, ic2); if (u32 == KICONV_JA_NODEST) { index = (ic1 - 0x21) * 94 + ic2 - 0x21; u32 = kiconv_ja_jisx0208_to_ucs2[index]; } if (u32 == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(u32); } else { /* 2nd byte check failed */ KICONV_JA_RETERROR(EILSEQ) } } else if (ic1 == SS2) { /* JIS X 0201 Kana; 2 bytes */ KICONV_JA_NGET(ic2); if (KICONV_JA_ISCS2(ic2)) { /* 2nd byte check passed */ index = (ic2 - 0xa1); u32 = kiconv_ja_jisx0201kana_to_ucs2[index]; KICONV_JA_PUTU(u32); } else { /* 2nd byte check failed */ KICONV_JA_RETERROR(EILSEQ) } } else if (ic1 == SS3) { /* JIS X 0212 or UDC; 3 bytes */ KICONV_JA_NGET(ic2); if (KICONV_JA_ISCS3(ic2)) { /* 2nd byte check passed */ KICONV_JA_NGET(ic3); if (KICONV_JA_ISCS3(ic3)) { /* 3rd byte check passed */ ic2 &= KICONV_JA_CMASK; ic3 &= KICONV_JA_CMASK; KICONV_JA_CNV_JIS0212MS_TO_U2(id, u32, ic2, ic3); if (u32 == KICONV_JA_NODEST) { index = ((ic2 - 0x21) * 94 + (ic3 - 0x21)); u32 = kiconv_ja_jisx0212_to_ucs2 [index]; } if (u32 == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(u32); } else { /* 3rd byte check failed */ KICONV_JA_RETERROR(EILSEQ) } } else { /* 2nd byte check failed */ KICONV_JA_RETERROR(EILSEQ) } } else if (KICONV_JA_ISC1CTRLEUC(ic1)) { /* C1 control; 1 byte */ u32 = ic1; KICONV_JA_PUTU(u32); } else { /* 1st byte check failed */ KICONV_JA_RETERROR(EILSEQ) } /* * One character successfully converted so update * values outside of this function's stack. */ *inbuf = (char *)ip; *inbytesleft = ileft; *outbuf = op; *outbytesleft = oleft; } ret: return (rv); } static size_t _do_kiconv_to_eucjp(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int *errno) { uchar_t ic; size_t rv = 0; uint_t ucs4; ushort_t euc16; uchar_t *ip; size_t ileft; char *op; size_t oleft; size_t read_len; size_t id = ((kiconv_state_t)kcd)->id; if ((inbuf == NULL) || (*inbuf == NULL)) { return (0); } ip = (uchar_t *)*inbuf; ileft = *inbytesleft; op = *outbuf; oleft = *outbytesleft; KICONV_JA_CHECK_UTF8_BOM(ip, ileft); while (ileft != 0) { KICONV_JA_GETU(&ucs4, 0); if (ucs4 > 0xffff) { /* non-BMP */ KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); rv++; goto next; } KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4); if (euc16 == KICONV_JA_NODEST) { euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4); } if (euc16 == KICONV_JA_NODEST) { KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); rv++; goto next; } switch (euc16 & 0x8080) { case 0x0000: /* CS0 */ ic = (uchar_t)euc16; KICONV_JA_NPUT(ic); break; case 0x8080: /* CS1 */ ic = (uchar_t)((euc16 >> 8) & 0xff); KICONV_JA_NPUT(ic); ic = (uchar_t)(euc16 & 0xff); KICONV_JA_NPUT(ic); break; case 0x0080: /* CS2 */ KICONV_JA_NPUT(SS2); ic = (uchar_t)euc16; KICONV_JA_NPUT(ic); break; case 0x8000: /* CS3 */ KICONV_JA_NPUT(SS3); ic = (uchar_t)((euc16 >> 8) & 0xff); KICONV_JA_NPUT(ic); ic = (uchar_t)(euc16 & KICONV_JA_CMASK); KICONV_JA_NPUT(ic | KICONV_JA_CMSB); break; } next: /* * One character successfully converted so update * values outside of this function's stack. */ *inbuf = (char *)ip; *inbytesleft = ileft; *outbuf = op; *outbytesleft = oleft; } ret: return (rv); } static size_t _do_kiconvstr_fr_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno, uint8_t id) { uint_t u32; /* UTF-32 */ uint_t index; /* index for table lookup */ uchar_t ic1, ic2, ic3; /* 1st, 2nd, and 3rd bytes of a char */ size_t rv = 0; /* return value of this function */ uchar_t *ip; size_t ileft; char *op; size_t oleft; boolean_t do_not_ignore_null; if ((inbuf == NULL) || (*inbuf == '\0')) { return (0); } ip = (uchar_t *)inbuf; ileft = *inbytesleft; op = outbuf; oleft = *outbytesleft; do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0); while (ileft != 0) { KICONV_JA_NGET(ic1); /* get 1st byte */ if (KICONV_JA_ISASC(ic1)) { /* ASCII; 1 byte */ if (ic1 == '\0' && do_not_ignore_null) { return (0); } u32 = kiconv_ja_jisx0201roman_to_ucs2[ic1]; KICONV_JA_PUTU(u32); } else if (KICONV_JA_ISCS1(ic1)) { /* 0208 or UDC; 2 bytes */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_NGET_REP_FR_MB(ic2); } else { KICONV_JA_NGET(ic2); } if (KICONV_JA_ISCS1(ic2)) { /* 2nd byte check passed */ ic1 &= KICONV_JA_CMASK; ic2 &= KICONV_JA_CMASK; KICONV_JA_CNV_JISMS_TO_U2(id, u32, ic1, ic2); if (u32 == KICONV_JA_NODEST) { index = (ic1 - 0x21) * 94 + ic2 - 0x21; u32 = kiconv_ja_jisx0208_to_ucs2[index]; } if (u32 == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(u32); } else { /* 2nd byte check failed */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU(KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR(EILSEQ) } } } else if (ic1 == SS2) { /* JIS X 0201 Kana; 2bytes */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_NGET_REP_FR_MB(ic2); } else { KICONV_JA_NGET(ic2); } if (KICONV_JA_ISCS2(ic2)) { /* 2nd byte check passed */ index = (ic2 - 0xa1); u32 = kiconv_ja_jisx0201kana_to_ucs2[index]; KICONV_JA_PUTU(u32); } else { /* 2nd byte check failed */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU(KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR(EILSEQ) } } } else if (ic1 == SS3) { /* JIS X 0212 or UDC; 3 bytes */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_NGET_REP_FR_MB(ic2); } else { KICONV_JA_NGET(ic2); } if (KICONV_JA_ISCS3(ic2)) { /* 2nd byte check passed */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_NGET_REP_FR_MB(ic3); } else { KICONV_JA_NGET(ic3); } if (KICONV_JA_ISCS3(ic3)) { /* 3rd byte check passed */ ic2 &= KICONV_JA_CMASK; ic3 &= KICONV_JA_CMASK; KICONV_JA_CNV_JIS0212MS_TO_U2(id, u32, ic2, ic3); if (u32 == KICONV_JA_NODEST) { index = ((ic2 - 0x21) * 94 + (ic3 - 0x21)); u32 = kiconv_ja_jisx0212_to_ucs2 [index]; } if (u32 == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(u32); } else { /* 3rd byte check failed */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU( KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR(EILSEQ) } } } else { /* 2nd byte check failed */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU(KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR(EILSEQ) } } } else if (KICONV_JA_ISC1CTRLEUC(ic1)) { /* C1 control; 1 byte */ u32 = ic1; KICONV_JA_PUTU(u32); } else { /* 1st byte check failed */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU(KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR(EILSEQ) } } next: /* * One character successfully converted so update * values outside of this function's stack. */ *inbytesleft = ileft; *outbytesleft = oleft; } ret: return (rv); } static size_t _do_kiconvstr_to_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno, uint8_t id) { uchar_t ic; size_t rv = 0; uint_t ucs4; ushort_t euc16; uchar_t *ip; size_t ileft; char *op; size_t oleft; size_t read_len; boolean_t do_not_ignore_null; if ((inbuf == NULL) || (*inbuf == '\0')) { return (0); } ip = (uchar_t *)inbuf; ileft = *inbytesleft; op = outbuf; oleft = *outbytesleft; KICONV_JA_CHECK_UTF8_BOM_WITHOUT_STATE(ip, ileft); do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0); while (ileft != 0) { KICONV_JA_GETU(&ucs4, flag); if (ucs4 == 0x0 && do_not_ignore_null) { return (0); } if (ucs4 > 0xffff) { /* non-BMP */ KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); rv++; goto next; } KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4); if (euc16 == KICONV_JA_NODEST) { euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4); } if (euc16 == KICONV_JA_NODEST) { KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); rv++; goto next; } switch (euc16 & 0x8080) { case 0x0000: /* CS0 */ ic = (uchar_t)euc16; KICONV_JA_NPUT(ic); break; case 0x8080: /* CS1 */ ic = (uchar_t)((euc16 >> 8) & 0xff); KICONV_JA_NPUT(ic); ic = (uchar_t)(euc16 & 0xff); KICONV_JA_NPUT(ic); break; case 0x0080: /* CS2 */ KICONV_JA_NPUT(SS2); ic = (uchar_t)euc16; KICONV_JA_NPUT(ic); break; case 0x8000: /* CS3 */ KICONV_JA_NPUT(SS3); ic = (uchar_t)((euc16 >> 8) & 0xff); KICONV_JA_NPUT(ic); ic = (uchar_t)(euc16 & KICONV_JA_CMASK); KICONV_JA_NPUT(ic | KICONV_JA_CMSB); break; } next: /* * One character successfully converted so update * values outside of this function's stack. */ *inbytesleft = ileft; *outbytesleft = oleft; } ret: return (rv); } static size_t kiconv_fr_eucjp(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int *errno) { if (! kcd || kcd == (void *)-1) { *errno = EBADF; return ((size_t)-1); } return (_do_kiconv_fr_eucjp(kcd, inbuf, inbytesleft, outbuf, outbytesleft, errno)); } static size_t kiconv_to_eucjp(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int *errno) { if (! kcd || kcd == (void *)-1) { *errno = EBADF; return ((size_t)-1); } return (_do_kiconv_to_eucjp(kcd, inbuf, inbytesleft, outbuf, outbytesleft, errno)); } static size_t kiconvstr_fr_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno) { return (_do_kiconvstr_fr_eucjp(inbuf, inbytesleft, outbuf, outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP)); } static size_t kiconvstr_to_eucjp(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno) { return (_do_kiconvstr_to_eucjp(inbuf, inbytesleft, outbuf, outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP)); } static size_t kiconvstr_fr_eucjpms(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno) { return (_do_kiconvstr_fr_eucjp(inbuf, inbytesleft, outbuf, outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP_MS)); } static size_t kiconvstr_to_eucjpms(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno) { return (_do_kiconvstr_to_eucjp(inbuf, inbytesleft, outbuf, outbytesleft, flag, errno, KICONV_JA_TBLID_EUCJP_MS)); } static size_t _do_kiconv_fr_sjis(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int *errno) { uint_t uni; /* UTF-32 */ uint_t index; /* index for table lookup */ uchar_t ic1, ic2; /* 1st and 2nd bytes of a char */ size_t rv = 0; /* return value of this function */ uchar_t *ip; size_t ileft; char *op; size_t oleft; size_t id = ((kiconv_state_t)kcd)->id; if ((inbuf == NULL) || (*inbuf == NULL)) { return (0); } ip = (uchar_t *)*inbuf; ileft = *inbytesleft; op = *outbuf; oleft = *outbytesleft; while (ileft != 0) { KICONV_JA_NGET(ic1); /* get 1st byte */ if (KICONV_JA_ISASC((int)ic1)) { /* ASCII; 1 byte */ uni = kiconv_ja_jisx0201roman_to_ucs2[ic1]; KICONV_JA_PUTU(uni); } else if (KICONV_JA_ISSJKANA(ic1)) { /* 0201 Kana; 1byte */ uni = kiconv_ja_jisx0201kana_to_ucs2[(ic1 - 0xa1)]; KICONV_JA_PUTU(uni); } else if (KICONV_JA_ISSJKANJI1(ic1)) { /* 0208/UDC; 2bytes */ KICONV_JA_NGET(ic2); if (KICONV_JA_ISSJKANJI2(ic2)) { ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)]; if (ic2 >= 0x9f) { ic1++; } ic2 = kiconv_ja_sjtojis2[ic2]; KICONV_JA_CNV_JISMS_TO_U2(id, uni, ic1, ic2); if (uni == KICONV_JA_NODEST) { index = ((ic1 - 0x21) * 94) + (ic2 - 0x21); uni = kiconv_ja_jisx0208_to_ucs2[index]; } if (uni == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(uni); } else { /* 2nd byte check failed */ KICONV_JA_RETERROR(EILSEQ) /* NOTREACHED */ } } else if (KICONV_JA_ISSJSUPKANJI1(ic1)) { /* VDC, 2 bytes */ KICONV_JA_NGET(ic2); if (KICONV_JA_ISSJKANJI2(ic2)) { ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)]; if (ic2 >= 0x9f) { ic1++; } index = ((ic1 - 0x21) * 94) + (kiconv_ja_sjtojis2[ic2] - 0x21); uni = kiconv_ja_jisx0212_to_ucs2[index]; if (uni == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(uni); } else { /* 2nd byte check failed */ KICONV_JA_RETERROR(EILSEQ) } } else if (KICONV_JA_ISSJIBM(ic1) || /* Extended IBM area */ KICONV_JA_ISSJNECIBM(ic1)) { /* NEC/IBM area */ /* * We need a special treatment for each codes. * By adding some offset number for them, we * can process them as the same way of that of * extended IBM chars. */ KICONV_JA_NGET(ic2); if (KICONV_JA_ISSJKANJI2(ic2)) { ushort_t dest, upper, lower; dest = (ic1 << 8) + ic2; if ((0xed40 <= dest) && (dest <= 0xeffc)) { KICONV_JA_REMAP_NEC(dest); if (dest == 0xffff) { KICONV_JA_RETERROR(EILSEQ) } } /* * XXX: 0xfa54 and 0xfa5b must be mapped * to JIS0208 area. Therefore we * have to do special treatment. */ if ((dest == 0xfa54) || (dest == 0xfa5b)) { if (dest == 0xfa54) { upper = 0x22; lower = 0x4c; } else { upper = 0x22; lower = 0x68; } KICONV_JA_CNV_JISMS_TO_U2(id, uni, upper, lower); if (uni == KICONV_JA_NODEST) { index = (uint_t)((upper - 0x21) * 94 + (lower - 0x21)); uni = kiconv_ja_jisx0208_to_ucs2 [index]; } if (uni == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(uni); } else { dest = dest - 0xfa40 - (((dest>>8) - 0xfa) * 0x40); dest = kiconv_ja_sjtoibmext[dest]; if (dest == 0xffff) { KICONV_JA_RETERROR(EILSEQ) } upper = (dest >> 8) & KICONV_JA_CMASK; lower = dest & KICONV_JA_CMASK; KICONV_JA_CNV_JIS0212MS_TO_U2(id, uni, upper, lower); if (uni == KICONV_JA_NODEST) { index = (uint_t)((upper - 0x21) * 94 + (lower - 0x21)); uni = kiconv_ja_jisx0212_to_ucs2 [index]; } if (uni == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(uni); } } else { /* 2nd byte check failed */ KICONV_JA_RETERROR(EILSEQ) } } else if ((0xeb <= ic1) && (ic1 <= 0xec)) { /* * Based on the draft convention of OSF-JVC CDEWG, * characters in this area will be mapped to * "CHIKAN-MOJI." (convertible character) * We use U+FFFD in this case. */ KICONV_JA_NGET(ic2); if (KICONV_JA_ISSJKANJI2(ic2)) { uni = 0xfffd; KICONV_JA_PUTU(uni); } else { /* 2nd byte check failed */ KICONV_JA_RETERROR(EILSEQ) } } else { /* 1st byte check failed */ KICONV_JA_RETERROR(EILSEQ) } /* * One character successfully converted so update * values outside of this function's stack. */ *inbuf = (char *)ip; *inbytesleft = ileft; *outbuf = op; *outbytesleft = oleft; } ret: return (rv); } /* * _kiconv_ja_lookuptbl() * Return the index number if its index-ed number * is the same as dest value. */ static ushort_t _kiconv_ja_lookuptbl(ushort_t dest) { ushort_t tmp; int i; int sz = (sizeof (kiconv_ja_sjtoibmext) / sizeof (kiconv_ja_sjtoibmext[0])); for (i = 0; i < sz; i++) { tmp = (kiconv_ja_sjtoibmext[i] & 0x7f7f); if (tmp == dest) return ((i + 0xfa40 + ((i / 0xc0) * 0x40))); } return (0x3f); } static size_t _do_kiconv_to_sjis(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int *errno) { uchar_t ic; size_t rv = 0; uint_t ucs4; ushort_t euc16; ushort_t dest; uchar_t *ip; size_t ileft; char *op; size_t oleft; size_t read_len; size_t id = ((kiconv_state_t)kcd)->id; if ((inbuf == NULL) || (*inbuf == NULL)) { return (0); } ip = (uchar_t *)*inbuf; ileft = *inbytesleft; op = *outbuf; oleft = *outbytesleft; KICONV_JA_CHECK_UTF8_BOM(ip, ileft); while (ileft != 0) { KICONV_JA_GETU(&ucs4, 0); if (ucs4 > 0xffff) { /* non-BMP */ KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); rv++; goto next; } KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4); if (euc16 == KICONV_JA_NODEST) { euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4); } if (euc16 == KICONV_JA_NODEST) { KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); rv++; goto next; } switch (euc16 & 0x8080) { case 0x0000: /* CS0 */ if (KICONV_JA_ISC1CTRL((uchar_t)euc16)) { KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); rv++; } else { ic = (uchar_t)euc16; KICONV_JA_NPUT(ic); } break; case 0x8080: /* CS1 */ ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK); KICONV_JA_NPUT(kiconv_ja_jis208tosj1[ic]); /* * for even number row (Ku), add 0x80 to * look latter half of kiconv_ja_jistosj2[] array */ ic = (uchar_t)((euc16 & KICONV_JA_CMASK) + (((ic % 2) == 0) ? 0x80 : 0x00)); KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]); break; case 0x0080: /* CS2 */ ic = (uchar_t)euc16; KICONV_JA_NPUT(ic); break; case 0x8000: /* CS3 */ ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK); if (euc16 == 0xa271) { /* NUMERO SIGN */ KICONV_JA_NPUT(0x87); KICONV_JA_NPUT(0x82); } else if (ic < 0x75) { /* check if IBM VDC */ dest = _kiconv_ja_lookuptbl(euc16 & 0x7f7f); if (dest == 0xffff) { KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); } else { /* avoid putting NUL ('\0') */ if (dest > 0xff) { KICONV_JA_NPUT( (dest >> 8) & 0xff); KICONV_JA_NPUT(dest & 0xff); } else { KICONV_JA_NPUT(dest & 0xff); } } } else { KICONV_JA_NPUT(kiconv_ja_jis212tosj1[ic]); /* * for even number row (Ku), add 0x80 to * look latter half of kiconv_ja_jistosj2[] */ ic = (ushort_t)((euc16 & KICONV_JA_CMASK) + (((ic % 2) == 0) ? 0x80 : 0x00)); KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]); } break; } next: /* * One character successfully converted so update * values outside of this function's stack. */ *inbuf = (char *)ip; *inbytesleft = ileft; *outbuf = op; *outbytesleft = oleft; } ret: return (rv); } static size_t _do_kiconvstr_fr_sjis(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno, uint8_t id) { uint_t uni; /* UTF-32 */ uint_t index; /* index for table lookup */ uchar_t ic1, ic2; /* 1st and 2nd bytes of a char */ size_t rv = 0; /* return value of this function */ uchar_t *ip; size_t ileft; char *op; size_t oleft; boolean_t do_not_ignore_null; if ((inbuf == NULL) || (*inbuf == '\0')) { return (0); } ip = (uchar_t *)inbuf; ileft = *inbytesleft; op = outbuf; oleft = *outbytesleft; do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0); while (ileft != 0) { KICONV_JA_NGET(ic1); /* get 1st byte */ if (KICONV_JA_ISASC((int)ic1)) { /* ASCII; 1 byte */ if (ic1 == '\0' && do_not_ignore_null) { return (0); } uni = kiconv_ja_jisx0201roman_to_ucs2[ic1]; KICONV_JA_PUTU(uni); } else if (KICONV_JA_ISSJKANA(ic1)) { /* JIS X 0201 Kana; 1 byte */ uni = kiconv_ja_jisx0201kana_to_ucs2[(ic1 - 0xa1)]; KICONV_JA_PUTU(uni); } else if (KICONV_JA_ISSJKANJI1(ic1)) { /* JIS X 0208 or UDC; 2 bytes */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_NGET_REP_FR_MB(ic2); } else { KICONV_JA_NGET(ic2); } if (KICONV_JA_ISSJKANJI2(ic2)) { ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)]; if (ic2 >= 0x9f) { ic1++; } ic2 = kiconv_ja_sjtojis2[ic2]; KICONV_JA_CNV_JISMS_TO_U2(id, uni, ic1, ic2); if (uni == KICONV_JA_NODEST) { index = ((ic1 - 0x21) * 94) + (ic2 - 0x21); uni = kiconv_ja_jisx0208_to_ucs2[index]; } if (uni == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(uni); } else { /* 2nd byte check failed */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU(KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR(EILSEQ) } /* NOTREACHED */ } } else if (KICONV_JA_ISSJSUPKANJI1(ic1)) { /* VDC, 2 bytes */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_NGET_REP_FR_MB(ic2); } else { KICONV_JA_NGET(ic2); } if (KICONV_JA_ISSJKANJI2(ic2)) { ic1 = kiconv_ja_sjtojis1[(ic1 - 0x80)]; if (ic2 >= 0x9f) { ic1++; } index = ((ic1 - 0x21) * 94) + (kiconv_ja_sjtojis2[ic2] - 0x21); uni = kiconv_ja_jisx0212_to_ucs2[index]; if (uni == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(uni); } else { /* 2nd byte check failed */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU(KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR(EILSEQ) } } } else if (KICONV_JA_ISSJIBM(ic1) || /* Extended IBM area */ KICONV_JA_ISSJNECIBM(ic1)) { /* NEC/IBM area */ /* * We need a special treatment for each codes. * By adding some offset number for them, we * can process them as the same way of that of * extended IBM chars. */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_NGET_REP_FR_MB(ic2); } else { KICONV_JA_NGET(ic2); } if (KICONV_JA_ISSJKANJI2(ic2)) { ushort_t dest, upper, lower; dest = (ic1 << 8) + ic2; if ((0xed40 <= dest) && (dest <= 0xeffc)) { KICONV_JA_REMAP_NEC(dest); if (dest == 0xffff) { if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU( KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR( EILSEQ) } } } /* * XXX: 0xfa54 and 0xfa5b must be mapped * to JIS0208 area. Therefore we * have to do special treatment. */ if ((dest == 0xfa54) || (dest == 0xfa5b)) { if (dest == 0xfa54) { upper = 0x22; lower = 0x4c; } else { upper = 0x22; lower = 0x68; } KICONV_JA_CNV_JISMS_TO_U2(id, uni, upper, lower); if (uni == KICONV_JA_NODEST) { index = (uint_t)((upper - 0x21) * 94 + (lower - 0x21)); uni = kiconv_ja_jisx0208_to_ucs2 [index]; } if (uni == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(uni); } else { dest = dest - 0xfa40 - (((dest>>8) - 0xfa) * 0x40); dest = kiconv_ja_sjtoibmext[dest]; if (dest == 0xffff) { if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU( KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR( EILSEQ) } } upper = (dest >> 8) & KICONV_JA_CMASK; lower = dest & KICONV_JA_CMASK; KICONV_JA_CNV_JIS0212MS_TO_U2(id, uni, upper, lower); if (uni == KICONV_JA_NODEST) { index = (uint_t)((upper - 0x21) * 94 + (lower - 0x21)); uni = kiconv_ja_jisx0212_to_ucs2 [index]; } if (uni == KICONV_JA_REPLACE) rv++; KICONV_JA_PUTU(uni); } } else { /* 2nd byte check failed */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU(KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR(EILSEQ) } } } else if ((0xeb <= ic1) && (ic1 <= 0xec)) { /* * Based on the draft convention of OSF-JVC CDEWG, * characters in this area will be mapped to * "CHIKAN-MOJI." (convertible character) * We use U+FFFD in this case. */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_NGET_REP_FR_MB(ic2); } else { KICONV_JA_NGET(ic2); } if (KICONV_JA_ISSJKANJI2(ic2)) { uni = 0xfffd; KICONV_JA_PUTU(uni); } else { /* 2nd byte check failed */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU(KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR(EILSEQ) } } } else { /* 1st byte check failed */ if (flag & KICONV_REPLACE_INVALID) { KICONV_JA_PUTU(KICONV_JA_REPLACE); rv++; } else { KICONV_JA_RETERROR(EILSEQ) } } next: /* * One character successfully converted so update * values outside of this function's stack. */ *inbytesleft = ileft; *outbytesleft = oleft; } ret: return (rv); } static size_t _do_kiconvstr_to_sjis(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno, uint8_t id) { uchar_t ic; size_t rv = 0; uint_t ucs4; ushort_t euc16; ushort_t dest; uchar_t *ip; size_t ileft; char *op; size_t oleft; size_t read_len; boolean_t do_not_ignore_null; if ((inbuf == NULL) || (*inbuf == '\0')) { return (0); } ip = (uchar_t *)inbuf; ileft = *inbytesleft; op = outbuf; oleft = *outbytesleft; KICONV_JA_CHECK_UTF8_BOM_WITHOUT_STATE(ip, ileft); do_not_ignore_null = ((flag & KICONV_IGNORE_NULL) == 0); while (ileft != 0) { KICONV_JA_GETU(&ucs4, flag); if (ucs4 == 0x0 && do_not_ignore_null) { return (0); } if (ucs4 > 0xffff) { /* non-BMP */ KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); rv++; goto next; } KICONV_JA_CNV_U2_TO_EUCJPMS(id, euc16, ucs4); if (euc16 == KICONV_JA_NODEST) { euc16 = kiconv_ja_ucs2_to_euc16((ushort_t)ucs4); } if (euc16 == KICONV_JA_NODEST) { KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); rv++; goto next; } switch (euc16 & 0x8080) { case 0x0000: /* CS0 */ if (KICONV_JA_ISC1CTRL((uchar_t)euc16)) { KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); rv++; } else { ic = (uchar_t)euc16; KICONV_JA_NPUT(ic); } break; case 0x8080: /* CS1 */ ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK); KICONV_JA_NPUT(kiconv_ja_jis208tosj1[ic]); /* * for even number row (Ku), add 0x80 to * look latter half of kiconv_ja_jistosj2[] array */ ic = (uchar_t)((euc16 & KICONV_JA_CMASK) + (((ic % 2) == 0) ? 0x80 : 0x00)); KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]); break; case 0x0080: /* CS2 */ ic = (uchar_t)euc16; KICONV_JA_NPUT(ic); break; case 0x8000: /* CS3 */ ic = (ushort_t)((euc16 >> 8) & KICONV_JA_CMASK); if (euc16 == 0xa271) { /* NUMERO SIGN */ KICONV_JA_NPUT(0x87); KICONV_JA_NPUT(0x82); } else if (ic < 0x75) { /* check if IBM VDC */ dest = _kiconv_ja_lookuptbl(euc16 & 0x7f7f); if (dest == 0xffff) { KICONV_JA_NPUT(KICONV_JA_DEF_SINGLE); } else { /* avoid putting NUL ('\0') */ if (dest > 0xff) { KICONV_JA_NPUT( (dest >> 8) & 0xff); KICONV_JA_NPUT(dest & 0xff); } else { KICONV_JA_NPUT(dest & 0xff); } } } else { KICONV_JA_NPUT(kiconv_ja_jis212tosj1[ic]); /* * for even number row (Ku), add 0x80 to * look latter half of kiconv_ja_jistosj2[] */ ic = (ushort_t)((euc16 & KICONV_JA_CMASK) + (((ic % 2) == 0) ? 0x80 : 0x00)); KICONV_JA_NPUT(kiconv_ja_jistosj2[ic]); } break; } next: /* * One character successfully converted so update * values outside of this function's stack. */ *inbytesleft = ileft; *outbytesleft = oleft; } ret: return (rv); } static size_t kiconv_fr_sjis(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int *errno) { if (! kcd || kcd == (void *)-1) { *errno = EBADF; return ((size_t)-1); } return (_do_kiconv_fr_sjis(kcd, inbuf, inbytesleft, outbuf, outbytesleft, errno)); } static size_t kiconv_to_sjis(void *kcd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int *errno) { if (! kcd || kcd == (void *)-1) { *errno = EBADF; return ((size_t)-1); } return (_do_kiconv_to_sjis(kcd, inbuf, inbytesleft, outbuf, outbytesleft, errno)); } static size_t kiconvstr_fr_sjis(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno) { return (_do_kiconvstr_fr_sjis(inbuf, inbytesleft, outbuf, outbytesleft, flag, errno, KICONV_JA_TBLID_SJIS)); } static size_t kiconvstr_to_sjis(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno) { return (_do_kiconvstr_to_sjis(inbuf, inbytesleft, outbuf, outbytesleft, flag, errno, KICONV_JA_TBLID_SJIS)); } static size_t kiconvstr_fr_cp932(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno) { return (_do_kiconvstr_fr_sjis(inbuf, inbytesleft, outbuf, outbytesleft, flag, errno, KICONV_JA_TBLID_CP932)); } static size_t kiconvstr_to_cp932(char *inbuf, size_t *inbytesleft, char *outbuf, size_t *outbytesleft, int flag, int *errno) { return (_do_kiconvstr_to_sjis(inbuf, inbytesleft, outbuf, outbytesleft, flag, errno, KICONV_JA_TBLID_CP932)); } static kiconv_ops_t kiconv_ja_ops_tbl[] = { { "eucjp", "utf-8", open_eucjp, kiconv_to_eucjp, close_ja, kiconvstr_to_eucjp }, { "utf-8", "eucjp", open_eucjp, kiconv_fr_eucjp, close_ja, kiconvstr_fr_eucjp }, { "eucjpms", "utf-8", open_eucjpms, kiconv_to_eucjp, close_ja, kiconvstr_to_eucjpms }, { "utf-8", "eucjpms", open_eucjpms, kiconv_fr_eucjp, close_ja, kiconvstr_fr_eucjpms }, { "sjis", "utf-8", open_sjis, kiconv_to_sjis, close_ja, kiconvstr_to_sjis }, { "utf-8", "sjis", open_sjis, kiconv_fr_sjis, close_ja, kiconvstr_fr_sjis }, { "cp932", "utf-8", open_cp932, kiconv_to_sjis, close_ja, kiconvstr_to_cp932 }, { "utf-8", "cp932", open_cp932, kiconv_fr_sjis, close_ja, kiconvstr_fr_cp932 } }; static char *kiconv_ja_aliases[] = {"932", "shiftjis", "pck"}; static char *kiconv_ja_canonicals[] = {"cp932", "sjis", "sjis"}; #define KICONV_JA_MAX_JA_OPS \ (sizeof (kiconv_ja_ops_tbl) / sizeof (kiconv_ops_t)) #define KICONV_JA_MAX_JA_ALIAS \ (sizeof (kiconv_ja_aliases) / sizeof (char *)) static kiconv_module_info_t kiconv_ja_info = { "kiconv_ja", /* module name */ KICONV_JA_MAX_JA_OPS, /* number of conversion in kiconv_ja */ kiconv_ja_ops_tbl, /* kiconv_ja ops table */ KICONV_JA_MAX_JA_ALIAS, /* number of alias in kiconv_ja */ kiconv_ja_aliases, /* kiconv_ja aliases */ kiconv_ja_canonicals, /* kiconv_ja canonicals */ 0 }; static struct modlkiconv modlkiconv_ja = { &mod_kiconvops, "kiconv module for Japanese", &kiconv_ja_info }; static struct modlinkage modlinkage = { MODREV_1, (void *)&modlkiconv_ja, NULL }; int _init(void) { int err; err = mod_install(&modlinkage); if (err) cmn_err(CE_WARN, "kiconv_ja: failed to load kernel module"); return (err); } int _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); } int _fini(void) { int err; /* * If this module is being used, then, we cannot remove the module. * The following checking will catch pretty much all usual cases. * * Any remaining will be catached by the kiconv_unregister_module() * during mod_remove() at below. */ if (kiconv_module_ref_count(KICONV_MODULE_ID_JA)) return (EBUSY); err = mod_remove(&modlinkage); if (err) cmn_err(CE_WARN, "kiconv_ja: failed to remove kernel module"); return (err); }