1219019Sgabor/* $FreeBSD$ */ 2219019Sgabor/* $NetBSD: citrus_hz.c,v 1.2 2008/06/14 16:01:07 tnozaki Exp $ */ 3219019Sgabor 4219019Sgabor/*- 5219019Sgabor * Copyright (c)2004, 2006 Citrus Project, 6219019Sgabor * All rights reserved. 7219019Sgabor * 8219019Sgabor * Redistribution and use in source and binary forms, with or without 9219019Sgabor * modification, are permitted provided that the following conditions 10219019Sgabor * are met: 11219019Sgabor * 1. Redistributions of source code must retain the above copyright 12219019Sgabor * notice, this list of conditions and the following disclaimer. 13219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright 14219019Sgabor * notice, this list of conditions and the following disclaimer in the 15219019Sgabor * documentation and/or other materials provided with the distribution. 16219019Sgabor * 17219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219019Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219019Sgabor * SUCH DAMAGE. 28219019Sgabor * 29219019Sgabor */ 30219019Sgabor 31219019Sgabor#include <sys/cdefs.h> 32219019Sgabor#include <sys/queue.h> 33219019Sgabor#include <sys/types.h> 34219019Sgabor 35219019Sgabor#include <assert.h> 36219019Sgabor#include <errno.h> 37219019Sgabor#include <limits.h> 38219019Sgabor#include <stddef.h> 39219019Sgabor#include <stdint.h> 40219019Sgabor#include <stdlib.h> 41219019Sgabor#include <string.h> 42219019Sgabor#include <wchar.h> 43219019Sgabor 44219019Sgabor#include "citrus_namespace.h" 45219019Sgabor#include "citrus_types.h" 46219019Sgabor#include "citrus_bcs.h" 47219019Sgabor#include "citrus_module.h" 48219019Sgabor#include "citrus_stdenc.h" 49219019Sgabor 50219019Sgabor#include "citrus_hz.h" 51219019Sgabor#include "citrus_prop.h" 52219019Sgabor 53219019Sgabor/* 54219019Sgabor * wchar_t mapping: 55219019Sgabor * 56219019Sgabor * CTRL/ASCII 00000000 00000000 00000000 gxxxxxxx 57219019Sgabor * GB2312 00000000 00000000 0xxxxxxx gxxxxxxx 58219019Sgabor * 94/96*n (~M) 0mmmmmmm 0xxxxxxx 0xxxxxxx gxxxxxxx 59219019Sgabor */ 60219019Sgabor 61219019Sgabor#define ESCAPE_CHAR '~' 62219019Sgabor 63219019Sgabortypedef enum { 64219019Sgabor CTRL = 0, ASCII = 1, GB2312 = 2, CS94 = 3, CS96 = 4 65219019Sgabor} charset_t; 66219019Sgabor 67219019Sgabortypedef struct { 68267829Sdelphij int start; 69219019Sgabor int end; 70219019Sgabor int width; 71219019Sgabor} range_t; 72219019Sgabor 73219019Sgaborstatic const range_t ranges[] = { 74219019Sgabor#define RANGE(start, end) { start, end, (end - start) + 1 } 75219019Sgabor/* CTRL */ RANGE(0x00, 0x1F), 76219019Sgabor/* ASCII */ RANGE(0x20, 0x7F), 77219019Sgabor/* GB2312 */ RANGE(0x21, 0x7E), 78219019Sgabor/* CS94 */ RANGE(0x21, 0x7E), 79219019Sgabor/* CS96 */ RANGE(0x20, 0x7F), 80219019Sgabor#undef RANGE 81219019Sgabor}; 82219019Sgabor 83219019Sgabortypedef struct escape_t escape_t; 84219019Sgabortypedef struct { 85219019Sgabor charset_t charset; 86219019Sgabor escape_t *escape; 87219019Sgabor ssize_t length; 88219019Sgabor#define ROWCOL_MAX 3 89219019Sgabor} graphic_t; 90219019Sgabor 91219019Sgabortypedef TAILQ_HEAD(escape_list, escape_t) escape_list; 92219019Sgaborstruct escape_t { 93219019Sgabor TAILQ_ENTRY(escape_t) entry; 94219019Sgabor escape_list *set; 95219019Sgabor graphic_t *left; 96219019Sgabor graphic_t *right; 97219019Sgabor int ch; 98219019Sgabor}; 99219019Sgabor 100219019Sgabor#define GL(escape) ((escape)->left) 101219019Sgabor#define GR(escape) ((escape)->right) 102219019Sgabor#define SET(escape) ((escape)->set) 103219019Sgabor#define ESC(escape) ((escape)->ch) 104219019Sgabor#define INIT(escape) (TAILQ_FIRST(SET(escape))) 105219019Sgabor 106219019Sgaborstatic __inline escape_t * 107219019Sgaborfind_escape(escape_list *set, int ch) 108219019Sgabor{ 109219019Sgabor escape_t *escape; 110219019Sgabor 111219019Sgabor TAILQ_FOREACH(escape, set, entry) { 112219019Sgabor if (ESC(escape) == ch) 113219019Sgabor break; 114219019Sgabor } 115219019Sgabor 116219019Sgabor return (escape); 117219019Sgabor} 118219019Sgabor 119219019Sgabortypedef struct { 120219019Sgabor escape_list e0; 121219019Sgabor escape_list e1; 122219019Sgabor graphic_t *ascii; 123219019Sgabor graphic_t *gb2312; 124219019Sgabor} _HZEncodingInfo; 125219019Sgabor 126219019Sgabor#define E0SET(ei) (&(ei)->e0) 127219019Sgabor#define E1SET(ei) (&(ei)->e1) 128219019Sgabor#define INIT0(ei) (TAILQ_FIRST(E0SET(ei))) 129219019Sgabor#define INIT1(ei) (TAILQ_FIRST(E1SET(ei))) 130219019Sgabor 131219019Sgabortypedef struct { 132219019Sgabor escape_t *inuse; 133219019Sgabor int chlen; 134219019Sgabor char ch[ROWCOL_MAX]; 135219019Sgabor} _HZState; 136219019Sgabor 137219019Sgabor#define _CEI_TO_EI(_cei_) (&(_cei_)->ei) 138219019Sgabor#define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_ 139219019Sgabor 140219019Sgabor#define _FUNCNAME(m) _citrus_HZ_##m 141219019Sgabor#define _ENCODING_INFO _HZEncodingInfo 142219019Sgabor#define _ENCODING_STATE _HZState 143219019Sgabor#define _ENCODING_MB_CUR_MAX(_ei_) MB_LEN_MAX 144219019Sgabor#define _ENCODING_IS_STATE_DEPENDENT 1 145219019Sgabor#define _STATE_NEEDS_EXPLICIT_INIT(_ps_) ((_ps_)->inuse == NULL) 146219019Sgabor 147219019Sgaborstatic __inline void 148219019Sgabor_citrus_HZ_init_state(_HZEncodingInfo * __restrict ei, 149219019Sgabor _HZState * __restrict psenc) 150219019Sgabor{ 151219019Sgabor 152219019Sgabor psenc->chlen = 0; 153219019Sgabor psenc->inuse = INIT0(ei); 154219019Sgabor} 155219019Sgabor 156219019Sgaborstatic __inline void 157219019Sgabor/*ARGSUSED*/ 158219019Sgabor_citrus_HZ_pack_state(_HZEncodingInfo * __restrict ei __unused, 159219019Sgabor void *__restrict pspriv, const _HZState * __restrict psenc) 160219019Sgabor{ 161219019Sgabor 162219019Sgabor memcpy(pspriv, (const void *)psenc, sizeof(*psenc)); 163219019Sgabor} 164219019Sgabor 165219019Sgaborstatic __inline void 166219019Sgabor/*ARGSUSED*/ 167219019Sgabor_citrus_HZ_unpack_state(_HZEncodingInfo * __restrict ei __unused, 168219019Sgabor _HZState * __restrict psenc, const void * __restrict pspriv) 169219019Sgabor{ 170219019Sgabor 171219019Sgabor memcpy((void *)psenc, pspriv, sizeof(*psenc)); 172219019Sgabor} 173219019Sgabor 174219019Sgaborstatic int 175219019Sgabor_citrus_HZ_mbrtowc_priv(_HZEncodingInfo * __restrict ei, 176252583Speter wchar_t * __restrict pwc, const char ** __restrict s, size_t n, 177219019Sgabor _HZState * __restrict psenc, size_t * __restrict nresult) 178219019Sgabor{ 179219019Sgabor escape_t *candidate, *init; 180219019Sgabor graphic_t *graphic; 181219019Sgabor const range_t *range; 182252583Speter const char *s0; 183219019Sgabor wchar_t wc; 184219019Sgabor int bit, ch, head, len, tail; 185219019Sgabor 186219019Sgabor if (*s == NULL) { 187219019Sgabor _citrus_HZ_init_state(ei, psenc); 188219019Sgabor *nresult = 1; 189219019Sgabor return (0); 190219019Sgabor } 191219019Sgabor s0 = *s; 192219019Sgabor if (psenc->chlen < 0 || psenc->inuse == NULL) 193219019Sgabor return (EINVAL); 194219019Sgabor 195219019Sgabor wc = (wchar_t)0; 196219019Sgabor bit = head = tail = 0; 197219019Sgabor graphic = NULL; 198219019Sgabor for (len = 0; len <= MB_LEN_MAX;) { 199219019Sgabor if (psenc->chlen == tail) { 200219019Sgabor if (n-- < 1) { 201219019Sgabor *s = s0; 202219019Sgabor *nresult = (size_t)-2; 203219019Sgabor return (0); 204219019Sgabor } 205219019Sgabor psenc->ch[psenc->chlen++] = *s0++; 206219019Sgabor ++len; 207219019Sgabor } 208219019Sgabor ch = (unsigned char)psenc->ch[tail++]; 209219019Sgabor if (tail == 1) { 210219019Sgabor if ((ch & ~0x80) <= 0x1F) { 211219019Sgabor if (psenc->inuse != INIT0(ei)) 212219019Sgabor break; 213219019Sgabor wc = (wchar_t)ch; 214219019Sgabor goto done; 215219019Sgabor } 216219019Sgabor if (ch & 0x80) { 217219019Sgabor graphic = GR(psenc->inuse); 218219019Sgabor bit = 0x80; 219219019Sgabor ch &= ~0x80; 220219019Sgabor } else { 221219019Sgabor graphic = GL(psenc->inuse); 222219019Sgabor if (ch == ESCAPE_CHAR) 223219019Sgabor continue; 224219019Sgabor bit = 0x0; 225219019Sgabor } 226219019Sgabor if (graphic == NULL) 227219019Sgabor break; 228219019Sgabor } else if (tail == 2 && psenc->ch[0] == ESCAPE_CHAR) { 229219019Sgabor if (tail < psenc->chlen) 230219019Sgabor return (EINVAL); 231219019Sgabor if (ch == ESCAPE_CHAR) { 232219019Sgabor ++head; 233219019Sgabor } else if (ch == '\n') { 234219019Sgabor if (psenc->inuse != INIT0(ei)) 235219019Sgabor break; 236219019Sgabor tail = psenc->chlen = 0; 237219019Sgabor continue; 238219019Sgabor } else { 239219019Sgabor candidate = NULL; 240219019Sgabor init = INIT0(ei); 241219019Sgabor if (psenc->inuse == init) { 242219019Sgabor init = INIT1(ei); 243219019Sgabor } else if (INIT(psenc->inuse) == init) { 244219019Sgabor if (ESC(init) != ch) 245219019Sgabor break; 246219019Sgabor candidate = init; 247219019Sgabor } 248219019Sgabor if (candidate == NULL) { 249219019Sgabor candidate = find_escape( 250219019Sgabor SET(psenc->inuse), ch); 251219019Sgabor if (candidate == NULL) { 252219019Sgabor if (init == NULL || 253219019Sgabor ESC(init) != ch) 254219019Sgabor break; 255219019Sgabor candidate = init; 256219019Sgabor } 257219019Sgabor } 258219019Sgabor psenc->inuse = candidate; 259219019Sgabor tail = psenc->chlen = 0; 260219019Sgabor continue; 261219019Sgabor } 262219019Sgabor } else if (ch & 0x80) { 263219019Sgabor if (graphic != GR(psenc->inuse)) 264219019Sgabor break; 265219019Sgabor ch &= ~0x80; 266219019Sgabor } else { 267219019Sgabor if (graphic != GL(psenc->inuse)) 268219019Sgabor break; 269219019Sgabor } 270219019Sgabor range = &ranges[(size_t)graphic->charset]; 271219019Sgabor if (range->start > ch || range->end < ch) 272219019Sgabor break; 273219019Sgabor wc <<= 8; 274219019Sgabor wc |= ch; 275219019Sgabor if (graphic->length == (tail - head)) { 276219019Sgabor if (graphic->charset > GB2312) 277219019Sgabor bit |= ESC(psenc->inuse) << 24; 278219019Sgabor wc |= bit; 279219019Sgabor goto done; 280219019Sgabor } 281219019Sgabor } 282219019Sgabor *nresult = (size_t)-1; 283219019Sgabor return (EILSEQ); 284219019Sgabordone: 285219019Sgabor if (tail < psenc->chlen) 286219019Sgabor return (EINVAL); 287219019Sgabor *s = s0; 288219019Sgabor if (pwc != NULL) 289219019Sgabor *pwc = wc; 290219019Sgabor psenc->chlen = 0; 291219019Sgabor *nresult = (wc == 0) ? 0 : len; 292219019Sgabor 293219019Sgabor return (0); 294219019Sgabor} 295219019Sgabor 296219019Sgaborstatic int 297219019Sgabor_citrus_HZ_wcrtomb_priv(_HZEncodingInfo * __restrict ei, 298219019Sgabor char * __restrict s, size_t n, wchar_t wc, 299219019Sgabor _HZState * __restrict psenc, size_t * __restrict nresult) 300219019Sgabor{ 301219019Sgabor escape_t *candidate, *init; 302219019Sgabor graphic_t *graphic; 303219019Sgabor const range_t *range; 304219019Sgabor size_t len; 305219019Sgabor int bit, ch; 306219019Sgabor 307219019Sgabor if (psenc->chlen != 0 || psenc->inuse == NULL) 308219019Sgabor return (EINVAL); 309219019Sgabor if (wc & 0x80) { 310219019Sgabor bit = 0x80; 311219019Sgabor wc &= ~0x80; 312219019Sgabor } else { 313219019Sgabor bit = 0x0; 314219019Sgabor } 315219019Sgabor if ((uint32_t)wc <= 0x1F) { 316219019Sgabor candidate = INIT0(ei); 317219019Sgabor graphic = (bit == 0) ? candidate->left : candidate->right; 318219019Sgabor if (graphic == NULL) 319219019Sgabor goto ilseq; 320219019Sgabor range = &ranges[(size_t)CTRL]; 321219019Sgabor len = 1; 322219019Sgabor } else if ((uint32_t)wc <= 0x7F) { 323219019Sgabor graphic = ei->ascii; 324219019Sgabor if (graphic == NULL) 325219019Sgabor goto ilseq; 326219019Sgabor candidate = graphic->escape; 327219019Sgabor range = &ranges[(size_t)graphic->charset]; 328219019Sgabor len = graphic->length; 329219019Sgabor } else if ((uint32_t)wc <= 0x7F7F) { 330219019Sgabor graphic = ei->gb2312; 331219019Sgabor if (graphic == NULL) 332219019Sgabor goto ilseq; 333219019Sgabor candidate = graphic->escape; 334219019Sgabor range = &ranges[(size_t)graphic->charset]; 335219019Sgabor len = graphic->length; 336219019Sgabor } else { 337219019Sgabor ch = (wc >> 24) & 0xFF; 338219019Sgabor candidate = find_escape(E0SET(ei), ch); 339219019Sgabor if (candidate == NULL) { 340219019Sgabor candidate = find_escape(E1SET(ei), ch); 341219019Sgabor if (candidate == NULL) 342219019Sgabor goto ilseq; 343219019Sgabor } 344219019Sgabor wc &= ~0xFF000000; 345219019Sgabor graphic = (bit == 0) ? candidate->left : candidate->right; 346219019Sgabor if (graphic == NULL) 347219019Sgabor goto ilseq; 348219019Sgabor range = &ranges[(size_t)graphic->charset]; 349219019Sgabor len = graphic->length; 350219019Sgabor } 351219019Sgabor if (psenc->inuse != candidate) { 352219019Sgabor init = INIT0(ei); 353219019Sgabor if (SET(psenc->inuse) == SET(candidate)) { 354219019Sgabor if (INIT(psenc->inuse) != init || 355219019Sgabor psenc->inuse == init || candidate == init) 356219019Sgabor init = NULL; 357219019Sgabor } else if (candidate == (init = INIT(candidate))) { 358219019Sgabor init = NULL; 359219019Sgabor } 360219019Sgabor if (init != NULL) { 361219019Sgabor if (n < 2) 362219019Sgabor return (E2BIG); 363219019Sgabor n -= 2; 364219019Sgabor psenc->ch[psenc->chlen++] = ESCAPE_CHAR; 365219019Sgabor psenc->ch[psenc->chlen++] = ESC(init); 366219019Sgabor } 367219019Sgabor if (n < 2) 368219019Sgabor return (E2BIG); 369219019Sgabor n -= 2; 370219019Sgabor psenc->ch[psenc->chlen++] = ESCAPE_CHAR; 371219019Sgabor psenc->ch[psenc->chlen++] = ESC(candidate); 372219019Sgabor psenc->inuse = candidate; 373219019Sgabor } 374219019Sgabor if (n < len) 375219019Sgabor return (E2BIG); 376219019Sgabor while (len-- > 0) { 377219019Sgabor ch = (wc >> (len * 8)) & 0xFF; 378219019Sgabor if (range->start > ch || range->end < ch) 379219019Sgabor goto ilseq; 380219019Sgabor psenc->ch[psenc->chlen++] = ch | bit; 381219019Sgabor } 382219019Sgabor memcpy(s, psenc->ch, psenc->chlen); 383219019Sgabor *nresult = psenc->chlen; 384219019Sgabor psenc->chlen = 0; 385219019Sgabor 386219019Sgabor return (0); 387219019Sgabor 388219019Sgaborilseq: 389219019Sgabor *nresult = (size_t)-1; 390219019Sgabor return (EILSEQ); 391219019Sgabor} 392219019Sgabor 393219019Sgaborstatic __inline int 394219019Sgabor_citrus_HZ_put_state_reset(_HZEncodingInfo * __restrict ei, 395219019Sgabor char * __restrict s, size_t n, _HZState * __restrict psenc, 396219019Sgabor size_t * __restrict nresult) 397219019Sgabor{ 398219019Sgabor escape_t *candidate; 399219019Sgabor 400219019Sgabor if (psenc->chlen != 0 || psenc->inuse == NULL) 401219019Sgabor return (EINVAL); 402219019Sgabor candidate = INIT0(ei); 403219019Sgabor if (psenc->inuse != candidate) { 404219019Sgabor if (n < 2) 405219019Sgabor return (E2BIG); 406219019Sgabor n -= 2; 407219019Sgabor psenc->ch[psenc->chlen++] = ESCAPE_CHAR; 408219019Sgabor psenc->ch[psenc->chlen++] = ESC(candidate); 409219019Sgabor } 410219019Sgabor if (n < 1) 411219019Sgabor return (E2BIG); 412219019Sgabor if (psenc->chlen > 0) 413219019Sgabor memcpy(s, psenc->ch, psenc->chlen); 414219019Sgabor *nresult = psenc->chlen; 415219019Sgabor _citrus_HZ_init_state(ei, psenc); 416219019Sgabor 417219019Sgabor return (0); 418219019Sgabor} 419219019Sgabor 420219019Sgaborstatic __inline int 421219019Sgabor_citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo * __restrict ei, 422219019Sgabor _HZState * __restrict psenc, int * __restrict rstate) 423219019Sgabor{ 424219019Sgabor 425219019Sgabor if (psenc->chlen < 0 || psenc->inuse == NULL) 426219019Sgabor return (EINVAL); 427219019Sgabor *rstate = (psenc->chlen == 0) 428219019Sgabor ? ((psenc->inuse == INIT0(ei)) 429219019Sgabor ? _STDENC_SDGEN_INITIAL 430219019Sgabor : _STDENC_SDGEN_STABLE) 431219019Sgabor : ((psenc->ch[0] == ESCAPE_CHAR) 432219019Sgabor ? _STDENC_SDGEN_INCOMPLETE_SHIFT 433219019Sgabor : _STDENC_SDGEN_INCOMPLETE_CHAR); 434219019Sgabor 435219019Sgabor return (0); 436219019Sgabor} 437219019Sgabor 438219019Sgaborstatic __inline int 439219019Sgabor/*ARGSUSED*/ 440219019Sgabor_citrus_HZ_stdenc_wctocs(_HZEncodingInfo * __restrict ei __unused, 441219019Sgabor _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc) 442219019Sgabor{ 443219019Sgabor int bit; 444219019Sgabor 445219019Sgabor if (wc & 0x80) { 446219019Sgabor bit = 0x80; 447219019Sgabor wc &= ~0x80; 448219019Sgabor } else 449219019Sgabor bit = 0x0; 450219019Sgabor if ((uint32_t)wc <= 0x7F) { 451219019Sgabor *csid = (_csid_t)bit; 452219019Sgabor *idx = (_index_t)wc; 453219019Sgabor } else if ((uint32_t)wc <= 0x7F7F) { 454219019Sgabor *csid = (_csid_t)(bit | 0x8000); 455219019Sgabor *idx = (_index_t)wc; 456219019Sgabor } else { 457219019Sgabor *csid = (_index_t)(wc & ~0x00FFFF7F); 458219019Sgabor *idx = (_csid_t)(wc & 0x00FFFF7F); 459219019Sgabor } 460219019Sgabor 461219019Sgabor return (0); 462219019Sgabor} 463219019Sgabor 464219019Sgaborstatic __inline int 465219019Sgabor/*ARGSUSED*/ 466219019Sgabor_citrus_HZ_stdenc_cstowc(_HZEncodingInfo * __restrict ei __unused, 467219019Sgabor wchar_t * __restrict wc, _csid_t csid, _index_t idx) 468219019Sgabor{ 469219019Sgabor 470219019Sgabor *wc = (wchar_t)idx; 471219019Sgabor switch (csid) { 472219019Sgabor case 0x80: 473219019Sgabor case 0x8080: 474219019Sgabor *wc |= (wchar_t)0x80; 475219019Sgabor /*FALLTHROUGH*/ 476219019Sgabor case 0x0: 477219019Sgabor case 0x8000: 478219019Sgabor break; 479219019Sgabor default: 480219019Sgabor *wc |= (wchar_t)csid; 481219019Sgabor } 482219019Sgabor 483219019Sgabor return (0); 484219019Sgabor} 485219019Sgabor 486219019Sgaborstatic void 487219019Sgabor_citrus_HZ_encoding_module_uninit(_HZEncodingInfo *ei) 488219019Sgabor{ 489219019Sgabor escape_t *escape; 490219019Sgabor 491219019Sgabor while ((escape = TAILQ_FIRST(E0SET(ei))) != NULL) { 492219019Sgabor TAILQ_REMOVE(E0SET(ei), escape, entry); 493219019Sgabor free(GL(escape)); 494219019Sgabor free(GR(escape)); 495219019Sgabor free(escape); 496219019Sgabor } 497219019Sgabor while ((escape = TAILQ_FIRST(E1SET(ei))) != NULL) { 498219019Sgabor TAILQ_REMOVE(E1SET(ei), escape, entry); 499219019Sgabor free(GL(escape)); 500219019Sgabor free(GR(escape)); 501219019Sgabor free(escape); 502219019Sgabor } 503219019Sgabor} 504219019Sgabor 505219019Sgaborstatic int 506267829Sdelphij_citrus_HZ_parse_char(void *context, const char *name __unused, const char *s) 507219019Sgabor{ 508219019Sgabor escape_t *escape; 509219019Sgabor void **p; 510219019Sgabor 511267829Sdelphij p = (void **)context; 512219019Sgabor escape = (escape_t *)p[0]; 513219019Sgabor if (escape->ch != '\0') 514219019Sgabor return (EINVAL); 515219019Sgabor escape->ch = *s++; 516219019Sgabor if (escape->ch == ESCAPE_CHAR || *s != '\0') 517219019Sgabor return (EINVAL); 518219019Sgabor 519219019Sgabor return (0); 520219019Sgabor} 521219019Sgabor 522219019Sgaborstatic int 523267829Sdelphij_citrus_HZ_parse_graphic(void *context, const char *name, const char *s) 524219019Sgabor{ 525219019Sgabor _HZEncodingInfo *ei; 526219019Sgabor escape_t *escape; 527219019Sgabor graphic_t *graphic; 528219019Sgabor void **p; 529219019Sgabor 530267829Sdelphij p = (void **)context; 531219019Sgabor escape = (escape_t *)p[0]; 532219019Sgabor ei = (_HZEncodingInfo *)p[1]; 533219019Sgabor graphic = malloc(sizeof(*graphic)); 534219019Sgabor if (graphic == NULL) 535219019Sgabor return (ENOMEM); 536219019Sgabor memset(graphic, 0, sizeof(*graphic)); 537219019Sgabor if (strcmp("GL", name) == 0) { 538219019Sgabor if (GL(escape) != NULL) 539219019Sgabor goto release; 540219019Sgabor GL(escape) = graphic; 541219019Sgabor } else if (strcmp("GR", name) == 0) { 542219019Sgabor if (GR(escape) != NULL) 543219019Sgabor goto release; 544219019Sgabor GR(escape) = graphic; 545219019Sgabor } else { 546219019Sgaborrelease: 547219019Sgabor free(graphic); 548219019Sgabor return (EINVAL); 549219019Sgabor } 550219019Sgabor graphic->escape = escape; 551219019Sgabor if (_bcs_strncasecmp("ASCII", s, 5) == 0) { 552219019Sgabor if (s[5] != '\0') 553219019Sgabor return (EINVAL); 554219019Sgabor graphic->charset = ASCII; 555219019Sgabor graphic->length = 1; 556219019Sgabor ei->ascii = graphic; 557219019Sgabor return (0); 558219019Sgabor } else if (_bcs_strncasecmp("GB2312", s, 6) == 0) { 559219019Sgabor if (s[6] != '\0') 560219019Sgabor return (EINVAL); 561219019Sgabor graphic->charset = GB2312; 562219019Sgabor graphic->length = 2; 563219019Sgabor ei->gb2312 = graphic; 564219019Sgabor return (0); 565219019Sgabor } else if (strncmp("94*", s, 3) == 0) 566219019Sgabor graphic->charset = CS94; 567219019Sgabor else if (strncmp("96*", s, 3) == 0) 568219019Sgabor graphic->charset = CS96; 569219019Sgabor else 570219019Sgabor return (EINVAL); 571219019Sgabor s += 3; 572219019Sgabor switch(*s) { 573219019Sgabor case '1': case '2': case '3': 574219019Sgabor graphic->length = (size_t)(*s - '0'); 575219019Sgabor if (*++s == '\0') 576219019Sgabor break; 577219019Sgabor /*FALLTHROUGH*/ 578219019Sgabor default: 579219019Sgabor return (EINVAL); 580219019Sgabor } 581219019Sgabor return (0); 582219019Sgabor} 583219019Sgabor 584219019Sgaborstatic const _citrus_prop_hint_t escape_hints[] = { 585219019Sgabor_CITRUS_PROP_HINT_STR("CH", &_citrus_HZ_parse_char), 586219019Sgabor_CITRUS_PROP_HINT_STR("GL", &_citrus_HZ_parse_graphic), 587219019Sgabor_CITRUS_PROP_HINT_STR("GR", &_citrus_HZ_parse_graphic), 588219019Sgabor_CITRUS_PROP_HINT_END 589219019Sgabor}; 590219019Sgabor 591219019Sgaborstatic int 592267829Sdelphij_citrus_HZ_parse_escape(void *context, const char *name, const char *s) 593219019Sgabor{ 594219019Sgabor _HZEncodingInfo *ei; 595219019Sgabor escape_t *escape; 596219019Sgabor void *p[2]; 597219019Sgabor 598267829Sdelphij ei = (_HZEncodingInfo *)context; 599219019Sgabor escape = malloc(sizeof(*escape)); 600219019Sgabor if (escape == NULL) 601219019Sgabor return (EINVAL); 602219019Sgabor memset(escape, 0, sizeof(*escape)); 603219019Sgabor if (strcmp("0", name) == 0) { 604219019Sgabor escape->set = E0SET(ei); 605219019Sgabor TAILQ_INSERT_TAIL(E0SET(ei), escape, entry); 606219019Sgabor } else if (strcmp("1", name) == 0) { 607219019Sgabor escape->set = E1SET(ei); 608219019Sgabor TAILQ_INSERT_TAIL(E1SET(ei), escape, entry); 609219019Sgabor } else { 610219019Sgabor free(escape); 611219019Sgabor return (EINVAL); 612219019Sgabor } 613219019Sgabor p[0] = (void *)escape; 614219019Sgabor p[1] = (void *)ei; 615219019Sgabor return (_citrus_prop_parse_variable( 616219019Sgabor escape_hints, (void *)&p[0], s, strlen(s))); 617219019Sgabor} 618219019Sgabor 619219019Sgaborstatic const _citrus_prop_hint_t root_hints[] = { 620219019Sgabor_CITRUS_PROP_HINT_STR("0", &_citrus_HZ_parse_escape), 621219019Sgabor_CITRUS_PROP_HINT_STR("1", &_citrus_HZ_parse_escape), 622219019Sgabor_CITRUS_PROP_HINT_END 623219019Sgabor}; 624219019Sgabor 625219019Sgaborstatic int 626219019Sgabor_citrus_HZ_encoding_module_init(_HZEncodingInfo * __restrict ei, 627219019Sgabor const void * __restrict var, size_t lenvar) 628219019Sgabor{ 629219019Sgabor int errnum; 630219019Sgabor 631219019Sgabor memset(ei, 0, sizeof(*ei)); 632219019Sgabor TAILQ_INIT(E0SET(ei)); 633219019Sgabor TAILQ_INIT(E1SET(ei)); 634219019Sgabor errnum = _citrus_prop_parse_variable( 635219019Sgabor root_hints, (void *)ei, var, lenvar); 636219019Sgabor if (errnum != 0) 637219019Sgabor _citrus_HZ_encoding_module_uninit(ei); 638219019Sgabor return (errnum); 639219019Sgabor} 640219019Sgabor 641219019Sgabor/* ---------------------------------------------------------------------- 642219019Sgabor * public interface for stdenc 643219019Sgabor */ 644219019Sgabor 645219019Sgabor_CITRUS_STDENC_DECLS(HZ); 646219019Sgabor_CITRUS_STDENC_DEF_OPS(HZ); 647219019Sgabor 648219019Sgabor#include "citrus_stdenc_template.h" 649