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 static size_t _EUC_mbrtowc(wchar_t * __restrict, const char * __restrict, 53 size_t, mbstate_t * __restrict); 54 static int _EUC_mbsinit(const mbstate_t *); 55 static size_t _EUC_wcrtomb(char * __restrict, wchar_t, 56 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 static 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 140 c &= 0xff; 141 return ((c & 0x80) ? c == _SS3 ? 3 : c == _SS2 ? 2 : 1 : 0); 142 } 143 144 static size_t 145 _EUC_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n, 146 mbstate_t * __restrict ps) 147 { 148 _EucState *es; 149 int i, set, want; 150 wchar_t wc; 151 const char *os; 152 153 es = (_EucState *)ps; 154 155 if (es->want < 0 || es->want > MB_CUR_MAX || es->set < 0 || 156 es->set > 3) { 157 errno = EINVAL; 158 return ((size_t)-1); 159 } 160 161 if (s == NULL) { 162 s = ""; 163 n = 1; 164 pwc = NULL; 165 } 166 167 if (n == 0) 168 /* Incomplete multibyte sequence */ 169 return ((size_t)-2); 170 171 os = s; 172 173 if (es->want == 0) { 174 want = CEI->count[set = _euc_set(*s)]; 175 if (set == 2 || set == 3) { 176 --want; 177 if (--n == 0) { 178 /* Incomplete multibyte sequence */ 179 es->set = set; 180 es->want = want; 181 es->ch = 0; 182 return ((size_t)-2); 183 } 184 ++s; 185 if (*s == '\0') { 186 errno = EILSEQ; 187 return ((size_t)-1); 188 } 189 } 190 wc = (unsigned char)*s++; 191 } else { 192 set = es->set; 193 want = es->want; 194 wc = es->ch; 195 } 196 for (i = (es->want == 0) ? 1 : 0; i < MIN(want, n); i++) { 197 if (*s == '\0') { 198 errno = EILSEQ; 199 return ((size_t)-1); 200 } 201 wc = (wc << 8) | (unsigned char)*s++; 202 } 203 if (i < want) { 204 /* Incomplete multibyte sequence */ 205 es->set = set; 206 es->want = want - i; 207 es->ch = wc; 208 return ((size_t)-2); 209 } 210 wc = (wc & ~CEI->mask) | CEI->bits[set]; 211 if (pwc != NULL) 212 *pwc = wc; 213 es->want = 0; 214 return (wc == L'\0' ? 0 : s - os); 215 } 216 217 static size_t 218 _EUC_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps) 219 { 220 _EucState *es; 221 wchar_t m, nm; 222 int i, len; 223 224 es = (_EucState *)ps; 225 226 if (es->want != 0) { 227 errno = EINVAL; 228 return ((size_t)-1); 229 } 230 231 if (s == NULL) 232 /* Reset to initial shift state (no-op) */ 233 return (1); 234 235 m = wc & CEI->mask; 236 nm = wc & ~m; 237 238 if (m == CEI->bits[1]) { 239 CodeSet1: 240 /* Codeset 1: The first byte must have 0x80 in it. */ 241 i = len = CEI->count[1]; 242 while (i-- > 0) 243 *s++ = (nm >> (i << 3)) | 0x80; 244 } else { 245 if (m == CEI->bits[0]) 246 i = len = CEI->count[0]; 247 else if (m == CEI->bits[2]) { 248 i = len = CEI->count[2]; 249 *s++ = _SS2; 250 --i; 251 /* SS2 designates G2 into GR */ 252 nm |= GR_BITS; 253 } else if (m == CEI->bits[3]) { 254 i = len = CEI->count[3]; 255 *s++ = _SS3; 256 --i; 257 /* SS3 designates G3 into GR */ 258 nm |= GR_BITS; 259 } else 260 goto CodeSet1; /* Bletch */ 261 while (i-- > 0) 262 *s++ = (nm >> (i << 3)) & 0xff; 263 } 264 return (len); 265 } 266