1 /*- 2 * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved. 3 * Copyright (c) 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Paul Borman at Krystal Technologies. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #if defined(LIBC_SCCS) && !defined(lint) 39 static char sccsid[] = "@(#)euc.c 8.1 (Berkeley) 6/4/93"; 40 #endif /* LIBC_SCCS and not lint */ 41 #include <sys/param.h> 42 __FBSDID("$FreeBSD$"); 43 44 #include <errno.h> 45 #include <limits.h> 46 #include <runetype.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <wchar.h> 50 #include "mblocal.h" 51 52 int _EUC_init(_RuneLocale *); 53 size_t _EUC_mbrtowc(wchar_t * __restrict, const char * __restrict, size_t, 54 mbstate_t * __restrict); 55 int _EUC_mbsinit(const mbstate_t *); 56 size_t _EUC_wcrtomb(char * __restrict, wchar_t, mbstate_t * __restrict); 57 58 typedef struct { 59 int count[4]; 60 wchar_t bits[4]; 61 wchar_t mask; 62 } _EucInfo; 63 64 typedef struct { 65 wchar_t ch; 66 int set; 67 int want; 68 } _EucState; 69 70 int 71 _EUC_init(_RuneLocale *rl) 72 { 73 _EucInfo *ei; 74 int x, new__mb_cur_max; 75 char *v, *e; 76 77 if (rl->__variable == NULL) 78 return (EFTYPE); 79 80 v = (char *)rl->__variable; 81 82 while (*v == ' ' || *v == '\t') 83 ++v; 84 85 if ((ei = malloc(sizeof(_EucInfo))) == NULL) 86 return (errno == 0 ? ENOMEM : errno); 87 88 new__mb_cur_max = 0; 89 for (x = 0; x < 4; ++x) { 90 ei->count[x] = (int)strtol(v, &e, 0); 91 if (v == e || !(v = e)) { 92 free(ei); 93 return (EFTYPE); 94 } 95 if (new__mb_cur_max < ei->count[x]) 96 new__mb_cur_max = ei->count[x]; 97 while (*v == ' ' || *v == '\t') 98 ++v; 99 ei->bits[x] = (int)strtol(v, &e, 0); 100 if (v == e || !(v = e)) { 101 free(ei); 102 return (EFTYPE); 103 } 104 while (*v == ' ' || *v == '\t') 105 ++v; 106 } 107 ei->mask = (int)strtol(v, &e, 0); 108 if (v == e || !(v = e)) { 109 free(ei); 110 return (EFTYPE); 111 } 112 rl->__variable = ei; 113 rl->__variable_len = sizeof(_EucInfo); 114 _CurrentRuneLocale = rl; 115 __mb_cur_max = new__mb_cur_max; 116 __mbrtowc = _EUC_mbrtowc; 117 __wcrtomb = _EUC_wcrtomb; 118 __mbsinit = _EUC_mbsinit; 119 return (0); 120 } 121 122 int 123 _EUC_mbsinit(const mbstate_t *ps) 124 { 125 126 return (ps == NULL || ((const _EucState *)ps)->want == 0); 127 } 128 129 #define CEI ((_EucInfo *)(_CurrentRuneLocale->__variable)) 130 131 #define _SS2 0x008e 132 #define _SS3 0x008f 133 134 #define GR_BITS 0x80808080 /* XXX: to be fixed */ 135 136 static __inline int 137 _euc_set(u_int c) 138 { 139 c &= 0xff; 140 return ((c & 0x80) ? c == _SS3 ? 3 : c == _SS2 ? 2 : 1 : 0); 141 } 142 143 size_t 144 _EUC_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n, 145 mbstate_t * __restrict ps) 146 { 147 _EucState *es; 148 int i, set, want; 149 wchar_t wc; 150 const char *os; 151 152 es = (_EucState *)ps; 153 154 if (es->want < 0 || es->want > MB_CUR_MAX || es->set < 0 || 155 es->set > 3) { 156 errno = EINVAL; 157 return ((size_t)-1); 158 } 159 160 if (s == NULL) { 161 s = ""; 162 n = 1; 163 pwc = NULL; 164 } 165 166 if (n == 0) 167 /* Incomplete multibyte sequence */ 168 return ((size_t)-2); 169 170 os = s; 171 172 if (es->want == 0) { 173 want = CEI->count[set = _euc_set(*s)]; 174 if (set == 2 || set == 3) { 175 --want; 176 if (--n == 0) { 177 /* Incomplete multibyte sequence */ 178 es->set = set; 179 es->want = want; 180 es->ch = 0; 181 return ((size_t)-2); 182 } 183 ++s; 184 if (*s == '\0') { 185 errno = EILSEQ; 186 return ((size_t)-1); 187 } 188 } 189 wc = (unsigned char)*s++; 190 } else { 191 set = es->set; 192 want = es->want; 193 wc = es->ch; 194 } 195 for (i = (es->want == 0) ? 1 : 0; i < MIN(want, n); i++) { 196 if (*s == '\0') { 197 errno = EILSEQ; 198 return ((size_t)-1); 199 } 200 wc = (wc << 8) | (unsigned char)*s++; 201 } 202 if (i < want) { 203 /* Incomplete multibyte sequence */ 204 es->set = set; 205 es->want = want - i; 206 es->ch = wc; 207 return ((size_t)-2); 208 } 209 wc = (wc & ~CEI->mask) | CEI->bits[set]; 210 if (pwc != NULL) 211 *pwc = wc; 212 es->want = 0; 213 return (wc == L'\0' ? 0 : s - os); 214 } 215 216 size_t 217 _EUC_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps) 218 { 219 _EucState *es; 220 wchar_t m, nm; 221 int i, len; 222 223 es = (_EucState *)ps; 224 225 if (es->want != 0) { 226 errno = EINVAL; 227 return ((size_t)-1); 228 } 229 230 if (s == NULL) 231 /* Reset to initial shift state (no-op) */ 232 return (1); 233 234 m = wc & CEI->mask; 235 nm = wc & ~m; 236 237 if (m == CEI->bits[1]) { 238 CodeSet1: 239 /* Codeset 1: The first byte must have 0x80 in it. */ 240 i = len = CEI->count[1]; 241 while (i-- > 0) 242 *s++ = (nm >> (i << 3)) | 0x80; 243 } else { 244 if (m == CEI->bits[0]) 245 i = len = CEI->count[0]; 246 else if (m == CEI->bits[2]) { 247 i = len = CEI->count[2]; 248 *s++ = _SS2; 249 --i; 250 /* SS2 designates G2 into GR */ 251 nm |= GR_BITS; 252 } else if (m == CEI->bits[3]) { 253 i = len = CEI->count[3]; 254 *s++ = _SS3; 255 --i; 256 /* SS3 designates G3 into GR */ 257 nm |= GR_BITS; 258 } else 259 goto CodeSet1; /* Bletch */ 260 while (i-- > 0) 261 *s++ = (nm >> (i << 3)) & 0xff; 262 } 263 return (len); 264 } 265