Coverage Report

Created: 2026-08-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/oficonv/libsrc/citrus_iso2022.c
Line
Count
Source
1
/*-
2
 * Copyright (c)1999, 2002 Citrus Project,
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 *
26
 */
27
28
#include "dcmtk/config/osconfig.h"
29
#include "citrus_iso2022.h"
30
31
#include <sys/types.h>
32
#include <errno.h>
33
#include <limits.h>
34
#include <stdbool.h>
35
#include <stddef.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <wchar.h>
40
41
#include "citrus_bcs.h"
42
#include "citrus_types.h"
43
#include "citrus_module.h"
44
#include "citrus_stdenc.h"
45
46
47
/* ----------------------------------------------------------------------
48
 * private stuffs used by templates
49
 */
50
51
52
/*
53
 * _citrus_wc_t mappings:
54
 * ASCII (ESC ( B)      00000000 00000000 00000000 0xxxxxxx
55
 * iso-8859-1 (ESC , A)     00000000 00000000 00000000 1xxxxxxx
56
 * 94 charset (ESC ( F)     0fffffff 00000000 00000000 0xxxxxxx
57
 * 94 charset (ESC ( M F)   0fffffff 1mmmmmmm 00000000 0xxxxxxx
58
 * 96 charset (ESC , F)     0fffffff 00000000 00000000 1xxxxxxx
59
 * 96 charset (ESC , M F)   0fffffff 1mmmmmmm 00000000 1xxxxxxx
60
 * 94x94 charset (ESC $ ( F)    0fffffff 00000000 0xxxxxxx 0xxxxxxx
61
 * 96x96 charset (ESC $ , F)    0fffffff 00000000 0xxxxxxx 1xxxxxxx
62
 * 94x94 charset (ESC & V ESC $ ( F)
63
 *              0fffffff 1vvvvvvv 0xxxxxxx 0xxxxxxx
64
 * 94x94x94 charset (ESC $ ( F) 0fffffff 0xxxxxxx 0xxxxxxx 0xxxxxxx
65
 * 96x96x96 charset (ESC $ , F) 0fffffff 0xxxxxxx 0xxxxxxx 1xxxxxxx
66
 * reserved for UCS4 co-existence (UCS4 is 31bit encoding thanks to mohta bit)
67
 *              1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
68
 */
69
70
0
#define CS94        (0U)
71
0
#define CS96        (1U)
72
0
#define CS94MULTI   (2U)
73
0
#define CS96MULTI   (3U)
74
75
typedef struct {
76
    unsigned char    interm;
77
    unsigned char    final;
78
    unsigned char    type;
79
    unsigned char    vers;
80
} _ISO2022Charset;
81
82
static const _ISO2022Charset ascii    = { CS94, 'B', '\0', '\0' };
83
static const _ISO2022Charset iso88591 = { CS96, 'A', '\0', '\0' };
84
85
typedef struct {
86
    _ISO2022Charset g[4];
87
    /* need 3 bits to hold -1, 0, ..., 3 */
88
    int gl:3,
89
        gr:3,
90
        singlegl:3,
91
        singlegr:3;
92
    char ch[7]; /* longest escape sequence (ESC & V ESC $ ( F) */
93
    size_t chlen;
94
    int flags;
95
0
#define _ISO2022STATE_FLAG_INITIALIZED  1
96
} _ISO2022State;
97
98
typedef struct {
99
    _ISO2022Charset *recommend[4];
100
    size_t  recommendsize[4];
101
    _ISO2022Charset initg[4];
102
    int maxcharset;
103
    int flags;
104
0
#define F_8BIT  0x0001
105
0
#define F_NOOLD 0x0002
106
0
#define F_SI    0x0010  /*0F*/
107
0
#define F_SO    0x0020  /*0E*/
108
0
#define F_LS0   0x0010  /*0F*/
109
0
#define F_LS1   0x0020  /*0E*/
110
0
#define F_LS2   0x0040  /*ESC n*/
111
0
#define F_LS3   0x0080  /*ESC o*/
112
0
#define F_LS1R  0x0100  /*ESC ~*/
113
0
#define F_LS2R  0x0200  /*ESC }*/
114
0
#define F_LS3R  0x0400  /*ESC |*/
115
0
#define F_SS2   0x0800  /*ESC N*/
116
0
#define F_SS3   0x1000  /*ESC O*/
117
0
#define F_SS2R  0x2000  /*8E*/
118
0
#define F_SS3R  0x4000  /*8F*/
119
} _ISO2022EncodingInfo;
120
121
#define _CEI_TO_EI(_cei_)       (&(_cei_)->ei)
122
#define _CEI_TO_STATE(_cei_, _func_)    (_cei_)->states.s_##_func_
123
124
0
#define _FUNCNAME(m)            _citrus_ISO2022_##m
125
0
#define _ENCODING_INFO          _ISO2022EncodingInfo
126
#define _ENCODING_STATE         _ISO2022State
127
0
#define _ENCODING_MB_CUR_MAX(_ei_)  MB_LEN_MAX
128
0
#define _ENCODING_IS_STATE_DEPENDENT    1
129
#define _STATE_NEEDS_EXPLICIT_INIT(_ps_)    \
130
    (!((_ps_)->flags & _ISO2022STATE_FLAG_INITIALIZED))
131
132
133
0
#define _ISO2022INVALID (_citrus_wc_t)-1
134
135
static __inline bool isc0(uint8_t x)
136
0
{
137
138
0
    return ((x & 0x1f) == x);
139
0
}
140
141
static __inline bool isc1(uint8_t x)
142
0
{
143
144
0
    return (0x80 <= x && x <= 0x9f);
145
0
}
146
147
static __inline bool iscntl(uint8_t x)
148
0
{
149
150
0
    return (isc0(x) || isc1(x) || x == 0x7f);
151
0
}
152
153
static __inline bool is94(uint8_t x)
154
0
{
155
156
0
    return (0x21 <= x && x <= 0x7e);
157
0
}
158
159
static __inline bool is96(uint8_t x)
160
0
{
161
162
0
    return (0x20 <= x && x <= 0x7f);
163
0
}
164
165
static __inline bool isecma(uint8_t x)
166
0
{
167
168
0
    return (0x30 <= x && x <= 0x7f);
169
0
}
170
171
static __inline bool isinterm(uint8_t x)
172
0
{
173
174
0
    return (0x20 <= x && x <= 0x2f);
175
0
}
176
177
static __inline bool isthree(uint8_t x)
178
0
{
179
180
0
    return (0x60 <= x && x <= 0x6f);
181
0
}
182
183
static __inline int
184
getcs(const char * p, _ISO2022Charset * cs)
185
0
{
186
187
0
    if (!strncmp(p, "94$", 3) && p[3] && !p[4]) {
188
0
        cs->final = (unsigned char)(p[3] & 0xff);
189
0
        cs->interm = '\0';
190
0
        cs->vers = '\0';
191
0
        cs->type = CS94MULTI;
192
0
    } else if (!strncmp(p, "96$", 3) && p[3] && !p[4]) {
193
0
        cs->final = (unsigned char)(p[3] & 0xff);
194
0
        cs->interm = '\0';
195
0
        cs->vers = '\0';
196
0
        cs->type = CS96MULTI;
197
0
    } else if (!strncmp(p, "94", 2) && p[2] && !p[3]) {
198
0
        cs->final = (unsigned char)(p[2] & 0xff);
199
0
        cs->interm = '\0';
200
0
        cs->vers = '\0';
201
0
        cs->type = CS94;
202
0
    } else if (!strncmp(p, "96", 2) && p[2] && !p[3]) {
203
0
        cs->final = (unsigned char )(p[2] & 0xff);
204
0
        cs->interm = '\0';
205
0
        cs->vers = '\0';
206
0
        cs->type = CS96;
207
0
    } else
208
0
        return (1);
209
210
0
    return (0);
211
0
}
212
213
214
0
#define _NOTMATCH   0
215
0
#define _MATCH      1
216
0
#define _PARSEFAIL  2
217
218
static __inline int
219
get_recommend(_ISO2022EncodingInfo * ei,
220
    const char * token)
221
0
{
222
0
    _ISO2022Charset cs, *p;
223
0
    int i;
224
225
0
    if (!strchr("0123", token[0]) || token[1] != '=')
226
0
        return (_NOTMATCH);
227
228
0
    if (getcs(&token[2], &cs) == 0)
229
0
        ;
230
0
    else if (!strcmp(&token[2], "94")) {
231
0
        cs.final = (unsigned char)(token[4]);
232
0
        cs.interm = '\0';
233
0
        cs.vers = '\0';
234
0
        cs.type = CS94;
235
0
    } else if (!strcmp(&token[2], "96")) {
236
0
        cs.final = (unsigned char)(token[4]);
237
0
        cs.interm = '\0';
238
0
        cs.vers = '\0';
239
0
        cs.type = CS96;
240
0
    } else if (!strcmp(&token[2], "94$")) {
241
0
        cs.final = (unsigned char)(token[5]);
242
0
        cs.interm = '\0';
243
0
        cs.vers = '\0';
244
0
        cs.type = CS94MULTI;
245
0
    } else if (!strcmp(&token[2], "96$")) {
246
0
        cs.final = (unsigned char)(token[5]);
247
0
        cs.interm = '\0';
248
0
        cs.vers = '\0';
249
0
        cs.type = CS96MULTI;
250
0
    } else
251
0
        return (_PARSEFAIL);
252
253
0
    i = token[0] - '0';
254
0
    if (!ei->recommend[i])
255
0
        ei->recommend[i] = malloc(sizeof(_ISO2022Charset));
256
0
    else {
257
0
        p = realloc(ei->recommend[i], (ei->recommendsize[i] + 1) * sizeof(_ISO2022Charset));
258
259
0
        if (!p)
260
0
            return (_PARSEFAIL);
261
0
        ei->recommend[i] = p;
262
0
    }
263
0
    if (!ei->recommend[i])
264
0
        return (_PARSEFAIL);
265
0
    ei->recommendsize[i]++;
266
267
0
    (ei->recommend[i] + (ei->recommendsize[i] - 1))->final = cs.final;
268
0
    (ei->recommend[i] + (ei->recommendsize[i] - 1))->interm = cs.interm;
269
0
    (ei->recommend[i] + (ei->recommendsize[i] - 1))->vers = cs.vers;
270
0
    (ei->recommend[i] + (ei->recommendsize[i] - 1))->type = cs.type;
271
272
0
    return (_MATCH);
273
0
}
274
275
static __inline int
276
get_initg(_ISO2022EncodingInfo * ei,
277
    const char * token)
278
0
{
279
0
    _ISO2022Charset cs;
280
281
0
    if (strncmp("INIT", &token[0], 4) ||
282
0
        !strchr("0123", token[4]) ||
283
0
        token[5] != '=')
284
0
        return (_NOTMATCH);
285
286
0
    if (getcs(&token[6], &cs) != 0)
287
0
        return (_PARSEFAIL);
288
289
/* suppress spurious GCC warnings */
290
#if ( defined(__GNUC__) && (__GNUC__ >= 10) )
291
#pragma GCC diagnostic push
292
#pragma GCC diagnostic ignored "-Wstringop-overflow"
293
#endif
294
295
0
    ei->initg[token[4] - '0'].type = cs.type;
296
0
    ei->initg[token[4] - '0'].final = cs.final;
297
0
    ei->initg[token[4] - '0'].interm = cs.interm;
298
0
    ei->initg[token[4] - '0'].vers = cs.vers;
299
300
#if ( defined(__GNUC__) && (__GNUC__ >= 10) )
301
#pragma GCC diagnostic pop
302
#endif
303
304
0
    return (_MATCH);
305
0
}
306
307
static __inline int
308
get_max(_ISO2022EncodingInfo * ei,
309
    const char * token)
310
0
{
311
0
    if (!strcmp(token, "MAX1"))
312
0
        ei->maxcharset = 1;
313
0
    else if (!strcmp(token, "MAX2"))
314
0
        ei->maxcharset = 2;
315
0
    else if (!strcmp(token, "MAX3"))
316
0
        ei->maxcharset = 3;
317
0
    else
318
0
        return (_NOTMATCH);
319
320
0
    return (_MATCH);
321
0
}
322
323
324
static __inline int
325
get_flags(_ISO2022EncodingInfo * ei,
326
    const char * token)
327
0
{
328
0
    static struct {
329
0
        const char  *tag;
330
0
        int     flag;
331
0
    } const tags[] = {
332
0
        { "DUMMY",  0   },
333
0
        { "8BIT",   F_8BIT  },
334
0
        { "NOOLD",  F_NOOLD },
335
0
        { "SI",     F_SI    },
336
0
        { "SO",     F_SO    },
337
0
        { "LS0",    F_LS0   },
338
0
        { "LS1",    F_LS1   },
339
0
        { "LS2",    F_LS2   },
340
0
        { "LS3",    F_LS3   },
341
0
        { "LS1R",   F_LS1R  },
342
0
        { "LS2R",   F_LS2R  },
343
0
        { "LS3R",   F_LS3R  },
344
0
        { "SS2",    F_SS2   },
345
0
        { "SS3",    F_SS3   },
346
0
        { "SS2R",   F_SS2R  },
347
0
        { "SS3R",   F_SS3R  },
348
0
        { NULL,     0 }
349
0
    };
350
0
    int i;
351
352
0
    for (i = 0; tags[i].tag; i++)
353
0
        if (!strcmp(token, tags[i].tag)) {
354
0
            ei->flags |= tags[i].flag;
355
0
            return (_MATCH);
356
0
        }
357
358
0
    return (_NOTMATCH);
359
0
}
360
361
362
static __inline int
363
_citrus_ISO2022_parse_variable(_ISO2022EncodingInfo * ei,
364
    const void * var, size_t lenvar )
365
0
{
366
0
    char const *e, *v;
367
0
    char buf[20];
368
0
    size_t len;
369
0
    int i, ret;
370
0
    (void) lenvar;
371
372
    /*
373
     * parse VARIABLE section.
374
     */
375
376
0
    if (!var)
377
0
        return (EFTYPE);
378
379
0
    v = (const char *) var;
380
381
    /* initialize structure */
382
0
    ei->maxcharset = 0;
383
0
    for (i = 0; i < 4; i++) {
384
0
        ei->recommend[i] = NULL;
385
0
        ei->recommendsize[i] = 0;
386
0
    }
387
0
    ei->flags = 0;
388
389
0
    while (*v) {
390
0
        while (*v == ' ' || *v == '\t')
391
0
            ++v;
392
393
        /* find the token */
394
0
        e = v;
395
0
        while (*e && *e != ' ' && *e != '\t')
396
0
            ++e;
397
398
0
        len = e - v;
399
0
        if (len == 0)
400
0
            break;
401
0
        if (len >= sizeof(buf))
402
0
            goto parsefail;
403
0
        snprintf(buf, sizeof(buf), "%.*s", (int)len, v);
404
405
0
        if ((ret = get_recommend(ei, buf)) != _NOTMATCH)
406
0
            ;
407
0
        else if ((ret = get_initg(ei, buf)) != _NOTMATCH)
408
0
            ;
409
0
        else if ((ret = get_max(ei, buf)) != _NOTMATCH)
410
0
            ;
411
0
        else if ((ret = get_flags(ei, buf)) != _NOTMATCH)
412
0
            ;
413
0
        else
414
0
            ret = _PARSEFAIL;
415
0
        if (ret == _PARSEFAIL)
416
0
            goto parsefail;
417
0
        v = e;
418
419
0
    }
420
421
0
    return (0);
422
423
0
parsefail:
424
0
    free(ei->recommend[0]);
425
0
    free(ei->recommend[1]);
426
0
    free(ei->recommend[2]);
427
0
    free(ei->recommend[3]);
428
429
0
    return (EFTYPE);
430
0
}
431
432
static __inline void
433
/*ARGSUSED*/
434
_citrus_ISO2022_init_state(_ISO2022EncodingInfo * ei,
435
    _ISO2022State * s)
436
0
{
437
0
    int i;
438
439
0
    memset(s, 0, sizeof(*s));
440
0
    s->gl = 0;
441
0
    s->gr = (ei->flags & F_8BIT) ? 1 : -1;
442
443
0
    for (i = 0; i < 4; i++)
444
0
        if (ei->initg[i].final) {
445
0
            s->g[i].type = ei->initg[i].type;
446
0
            s->g[i].final = ei->initg[i].final;
447
0
            s->g[i].interm = ei->initg[i].interm;
448
0
        }
449
0
    s->singlegl = s->singlegr = -1;
450
0
    s->flags |= _ISO2022STATE_FLAG_INITIALIZED;
451
0
}
452
453
static int
454
/*ARGSUSED*/
455
_citrus_ISO2022_encoding_module_init(_ISO2022EncodingInfo * ei,
456
    const void * var, size_t lenvar)
457
0
{
458
459
0
    return (_citrus_ISO2022_parse_variable(ei, var, lenvar));
460
0
}
461
462
static void
463
/*ARGSUSED*/
464
_citrus_ISO2022_encoding_module_uninit(_ISO2022EncodingInfo *ei )
465
0
{
466
0
    (void) ei;
467
0
}
468
469
#define ESC '\033'
470
0
#define ECMA    -1
471
0
#define INTERM  -2
472
0
#define OECMA   -3
473
static const struct seqtable {
474
    int type;
475
    int csoff;
476
    int finaloff;
477
    int intermoff;
478
    int versoff;
479
    int len;
480
    int chars[10];
481
} seqtable[] = {
482
    /* G0 94MULTI special */
483
    { CS94MULTI, -1, 2, -1, -1, 3, { ESC, '$', OECMA }, },
484
    /* G0 94MULTI special with version identification */
485
    { CS94MULTI, -1, 5, -1, 2,  6, { ESC, '&', ECMA, ESC, '$', OECMA }, },
486
    /* G? 94 */
487
    { CS94, 1, 2, -1, -1,       3, { ESC, CS94, ECMA, }, },
488
    /* G? 94 with 2nd intermediate char */
489
    { CS94, 1, 3, 2, -1,        4, { ESC, CS94, INTERM, ECMA, }, },
490
    /* G? 96 */
491
    { CS96, 1, 2, -1, -1,       3, { ESC, CS96, ECMA, }, },
492
    /* G? 96 with 2nd intermediate char */
493
    { CS96, 1, 3, 2, -1,        4, { ESC, CS96, INTERM, ECMA, }, },
494
    /* G? 94MULTI */
495
    { CS94MULTI, 2, 3, -1, -1,  4, { ESC, '$', CS94, ECMA, }, },
496
    /* G? 96MULTI */
497
    { CS96MULTI, 2, 3, -1, -1,  4, { ESC, '$', CS96, ECMA, }, },
498
    /* G? 94MULTI with version specification */
499
    { CS94MULTI, 5, 6, -1, 2,   7, { ESC, '&', ECMA, ESC, '$', CS94, ECMA, }, },
500
    /* LS2/3 */
501
    { -1, -1, -1, -1, -1,       2, { ESC, 'n', }, },
502
    { -1, -1, -1, -1, -1,       2, { ESC, 'o', }, },
503
    /* LS1/2/3R */
504
    { -1, -1, -1, -1, -1,       2, { ESC, '~', }, },
505
    { -1, -1, -1, -1, -1,       2, { ESC, /*{*/ '}', }, },
506
    { -1, -1, -1, -1, -1,       2, { ESC, '|', }, },
507
    /* SS2/3 */
508
    { -1, -1, -1, -1, -1,       2, { ESC, 'N', }, },
509
    { -1, -1, -1, -1, -1,       2, { ESC, 'O', }, },
510
    /* end of records */
511
/*  { 0, } */
512
    {  0,  0,  0,  0,  0,       0, { ESC,  0, }, }
513
};
514
515
static int
516
seqmatch(const char * s, size_t n,
517
    const struct seqtable * sp)
518
0
{
519
0
    const int *p;
520
521
0
    p = sp->chars;
522
0
    while ((size_t)(p - sp->chars) < n && p - sp->chars < sp->len) {
523
0
        switch (*p) {
524
0
        case ECMA:
525
0
            if (!isecma(*s))
526
0
                goto terminate;
527
0
            break;
528
0
        case OECMA:
529
0
            if (*s && strchr("@AB", *s))
530
0
                break;
531
0
            else
532
0
                goto terminate;
533
0
        case INTERM:
534
0
            if (!isinterm(*s))
535
0
                goto terminate;
536
0
            break;
537
0
        case CS94:
538
0
            if (*s && strchr("()*+", *s))
539
0
                break;
540
0
            else
541
0
                goto terminate;
542
0
        case CS96:
543
0
            if (*s && strchr(",-./", *s))
544
0
                break;
545
0
            else
546
0
                goto terminate;
547
0
        default:
548
0
            if (*s != *p)
549
0
                goto terminate;
550
0
            break;
551
0
        }
552
553
0
        p++;
554
0
        s++;
555
0
    }
556
557
0
terminate:
558
0
    return (int) (p - sp->chars);
559
0
}
560
561
static _citrus_wc_t
562
_ISO2022_sgetwchar(_ISO2022EncodingInfo * ei ,
563
    char * string, size_t n, char ** result,
564
    _ISO2022State * psenc)
565
0
{
566
0
    const struct seqtable *sp;
567
0
    _citrus_wc_t wchar = 0;
568
0
    int i, cur, nmatch;
569
0
    (void) ei;
570
571
0
    while (1) {
572
        /* SI/SO */
573
0
        if (1 <= n && string[0] == '\017') {
574
0
            psenc->gl = 0;
575
0
            string++;
576
0
            n--;
577
0
            continue;
578
0
        }
579
0
        if (1 <= n && string[0] == '\016') {
580
0
            psenc->gl = 1;
581
0
            string++;
582
0
            n--;
583
0
            continue;
584
0
        }
585
586
        /* SS2/3R */
587
0
        if (1 <= n && string[0] && strchr("\217\216", string[0])) {
588
0
            psenc->singlegl = psenc->singlegr =
589
0
                (string[0] - '\216') + 2;
590
0
            string++;
591
0
            n--;
592
0
            continue;
593
0
        }
594
595
        /* eat the letter if this is not ESC */
596
0
        if (1 <= n && string[0] != '\033')
597
0
            break;
598
599
        /* look for a perfect match from escape sequences */
600
0
        for (sp = &seqtable[0]; sp->len; sp++) {
601
0
            nmatch = seqmatch(string, n, sp);
602
0
            if (sp->len == nmatch && n >= (size_t)(sp->len))
603
0
                break;
604
0
        }
605
606
0
        if (!sp->len)
607
0
            goto notseq;
608
609
0
        if (sp->type != -1) {
610
0
            if (sp->csoff == -1)
611
0
                i = 0;
612
0
            else {
613
0
                switch (sp->type) {
614
0
                case CS94:
615
0
                case CS94MULTI:
616
0
                    i = string[sp->csoff] - '(';
617
0
                    break;
618
0
                case CS96:
619
0
                case CS96MULTI:
620
0
                    i = string[sp->csoff] - ',';
621
0
                    break;
622
0
                default:
623
0
                    return (_ISO2022INVALID);
624
0
                }
625
0
            }
626
0
            psenc->g[i].type = (unsigned char) sp->type;
627
0
            psenc->g[i].final = '\0';
628
0
            psenc->g[i].interm = '\0';
629
0
            psenc->g[i].vers = '\0';
630
            /* sp->finaloff must not be -1 */
631
0
            if (sp->finaloff != -1)
632
0
                psenc->g[i].final = string[sp->finaloff];
633
0
            if (sp->intermoff != -1)
634
0
                psenc->g[i].interm = string[sp->intermoff];
635
0
            if (sp->versoff != -1)
636
0
                psenc->g[i].vers = string[sp->versoff];
637
638
0
            string += sp->len;
639
0
            n -= sp->len;
640
0
            continue;
641
0
        }
642
643
        /* LS2/3 */
644
0
        if (2 <= n && string[0] == '\033' &&
645
0
            string[1] && strchr("no", string[1])) {
646
0
            psenc->gl = string[1] - 'n' + 2;
647
0
            string += 2;
648
0
            n -= 2;
649
0
            continue;
650
0
        }
651
652
        /* LS1/2/3R */
653
            /* XXX: { for vi showmatch */
654
0
        if (2 <= n && string[0] == '\033' &&
655
0
            string[1] && strchr("~}|", string[1])) {
656
0
            psenc->gr = 3 - (string[1] - '|');
657
0
            string += 2;
658
0
            n -= 2;
659
0
            continue;
660
0
        }
661
662
        /* SS2/3 */
663
0
        if (2 <= n && string[0] == '\033' && string[1] &&
664
0
            strchr("NO", string[1])) {
665
0
            psenc->singlegl = (string[1] - 'N') + 2;
666
0
            string += 2;
667
0
            n -= 2;
668
0
            continue;
669
0
        }
670
671
0
    notseq:
672
        /*
673
         * if we've got an unknown escape sequence, eat the ESC at the
674
         * head.  otherwise, wait till full escape sequence comes.
675
         */
676
0
        for (sp = &seqtable[0]; sp->len; sp++) {
677
0
            nmatch = seqmatch(string, n, sp);
678
0
            if (!nmatch)
679
0
                continue;
680
681
            /*
682
             * if we are in the middle of escape sequence,
683
             * we still need to wait for more characters to come
684
             */
685
0
            if (n < (size_t)(sp->len)) {
686
0
                if ((size_t)(nmatch) == n) {
687
0
                    if (result)
688
0
                        *result = string;
689
0
                    return (_ISO2022INVALID);
690
0
                }
691
0
            } else {
692
0
                if (nmatch == sp->len) {
693
                    /* this case should not happen */
694
0
                    goto eat;
695
0
                }
696
0
            }
697
0
        }
698
699
0
        break;
700
0
    }
701
702
0
eat:
703
    /* no letter to eat */
704
0
    if (n < 1) {
705
0
        if (result)
706
0
            *result = string;
707
0
        return (_ISO2022INVALID);
708
0
    }
709
710
    /* normal chars.  always eat C0/C1 as is. */
711
0
    if (iscntl(*string & 0xff))
712
0
        cur = -1;
713
0
    else if (*string & 0x80)
714
0
        cur = (psenc->singlegr == -1) ? psenc->gr : psenc->singlegr;
715
0
    else
716
0
        cur = (psenc->singlegl == -1) ? psenc->gl : psenc->singlegl;
717
718
0
    if (cur == -1) {
719
0
asis:
720
0
        wchar = *string++ & 0xff;
721
0
        if (result)
722
0
            *result = string;
723
        /* reset single shift state */
724
0
        psenc->singlegr = psenc->singlegl = -1;
725
0
        return (wchar);
726
0
    }
727
728
    /* length error check */
729
0
    switch (psenc->g[cur].type) {
730
0
    case CS94MULTI:
731
0
    case CS96MULTI:
732
0
        if (!isthree(psenc->g[cur].final)) {
733
0
            if (2 <= n &&
734
0
                (string[0] & 0x80) == (string[1] & 0x80))
735
0
                break;
736
0
        } else {
737
0
            if (3 <= n &&
738
0
                (string[0] & 0x80) == (string[1] & 0x80) &&
739
0
                (string[0] & 0x80) == (string[2] & 0x80))
740
0
                break;
741
0
        }
742
743
        /* we still need to wait for more characters to come */
744
0
        if (result)
745
0
            *result = string;
746
0
        return (_ISO2022INVALID);
747
748
0
    case CS94:
749
0
    case CS96:
750
0
        if (1 <= n)
751
0
            break;
752
753
        /* we still need to wait for more characters to come */
754
0
        if (result)
755
0
            *result = string;
756
0
        return (_ISO2022INVALID);
757
0
    }
758
759
    /* range check */
760
0
    switch (psenc->g[cur].type) {
761
0
    case CS94:
762
0
        if (!(is94(string[0] & 0x7f)))
763
0
            goto asis;
764
0
        break;
765
0
    case CS96:
766
0
        if (!(is96(string[0] & 0x7f)))
767
0
            goto asis;
768
0
        break;
769
0
    case CS94MULTI:
770
0
        if (!(is94(string[0] & 0x7f) && is94(string[1] & 0x7f)))
771
0
            goto asis;
772
0
        break;
773
0
    case CS96MULTI:
774
0
        if (!(is96(string[0] & 0x7f) && is96(string[1] & 0x7f)))
775
0
            goto asis;
776
0
        break;
777
0
    }
778
779
    /* extract the character. */
780
0
    switch (psenc->g[cur].type) {
781
0
    case CS94:
782
        /* special case for ASCII. */
783
0
        if (psenc->g[cur].final == 'B' && !psenc->g[cur].interm) {
784
0
            wchar = *string++;
785
0
            wchar &= 0x7f;
786
0
            break;
787
0
        }
788
0
        wchar = psenc->g[cur].final;
789
0
        wchar = (wchar << 8);
790
0
        wchar |= (psenc->g[cur].interm ? (0x80 | psenc->g[cur].interm) : 0);
791
0
        wchar = (wchar << 8);
792
0
        wchar = (wchar << 8) | (*string++ & 0x7f);
793
0
        break;
794
0
    case CS96:
795
        /* special case for ISO-8859-1. */
796
0
        if (psenc->g[cur].final == 'A' && !psenc->g[cur].interm) {
797
0
            wchar = *string++;
798
0
            wchar &= 0x7f;
799
0
            wchar |= 0x80;
800
0
            break;
801
0
        }
802
0
        wchar = psenc->g[cur].final;
803
0
        wchar = (wchar << 8);
804
0
        wchar |= (psenc->g[cur].interm ? (0x80 | psenc->g[cur].interm) : 0);
805
0
        wchar = (wchar << 8);
806
0
        wchar = (wchar << 8) | (*string++ & 0x7f);
807
0
        wchar |= 0x80;
808
0
        break;
809
0
    case CS94MULTI:
810
0
    case CS96MULTI:
811
0
        wchar = psenc->g[cur].final;
812
0
        wchar = (wchar << 8);
813
0
        if (isthree(psenc->g[cur].final))
814
0
            wchar |= (*string++ & 0x7f);
815
0
        wchar = (wchar << 8) | (*string++ & 0x7f);
816
0
        wchar = (wchar << 8) | (*string++ & 0x7f);
817
0
        if (psenc->g[cur].type == CS96MULTI)
818
0
            wchar |= 0x80;
819
0
        break;
820
0
    }
821
822
0
    if (result)
823
0
        *result = string;
824
    /* reset single shift state */
825
0
    psenc->singlegr = psenc->singlegl = -1;
826
0
    return (wchar);
827
0
}
828
829
830
831
static int
832
_citrus_ISO2022_mbrtowc_priv(_ISO2022EncodingInfo * ei,
833
    _citrus_wc_t * pwc, char ** s,
834
    size_t n, _ISO2022State * psenc, size_t * nresult)
835
0
{
836
0
    char *p, *result, *s0;
837
0
    _citrus_wc_t wchar;
838
0
    int chlenbak;
839
0
    size_t c;
840
841
0
    if (*s == NULL) {
842
0
        _citrus_ISO2022_init_state(ei, psenc);
843
0
        *nresult = _ENCODING_IS_STATE_DEPENDENT;
844
0
        return (0);
845
0
    }
846
0
    s0 = *s;
847
0
    c = 0;
848
0
    chlenbak = (int) psenc->chlen;
849
850
    /*
851
     * if we have something in buffer, use that.
852
     * otherwise, skip here
853
     */
854
0
    if (psenc->chlen > sizeof(psenc->ch)) {
855
        /* illgeal state */
856
0
        _citrus_ISO2022_init_state(ei, psenc);
857
0
        goto encoding_error;
858
0
    }
859
0
    if (psenc->chlen == 0)
860
0
        goto emptybuf;
861
862
    /* buffer is not empty */
863
0
    p = psenc->ch;
864
0
    while (psenc->chlen < sizeof(psenc->ch)) {
865
0
        if (n > 0) {
866
0
            psenc->ch[psenc->chlen++] = *s0++;
867
0
            n--;
868
0
        }
869
870
0
        wchar = _ISO2022_sgetwchar(ei, p, psenc->chlen - (p-psenc->ch),
871
0
            &result, psenc);
872
0
        c += result - p;
873
0
        if (wchar != _ISO2022INVALID) {
874
0
            if (psenc->chlen > (size_t)c)
875
0
                memmove(psenc->ch, result, psenc->chlen - c);
876
0
            if (psenc->chlen < (size_t)c)
877
0
                psenc->chlen = 0;
878
0
            else
879
0
                psenc->chlen -= c;
880
0
            goto output;
881
0
        }
882
883
0
        if (n == 0) {
884
0
            if ((size_t)(result - p) == psenc->chlen)
885
                /* complete shift sequence. */
886
0
                psenc->chlen = 0;
887
0
            goto restart;
888
0
        }
889
890
0
        p = result;
891
0
    }
892
893
    /* escape sequence too long? */
894
0
    goto encoding_error;
895
896
0
emptybuf:
897
0
    wchar = _ISO2022_sgetwchar(ei, s0, n, &result, psenc);
898
0
    if (wchar != _ISO2022INVALID) {
899
0
        c += result - s0;
900
0
        psenc->chlen = 0;
901
0
        s0 = result;
902
0
        goto output;
903
0
    }
904
0
    if (result > s0) {
905
0
        c += (result - s0);
906
0
        n -= (result - s0);
907
0
        s0 = result;
908
0
        if (n > 0)
909
0
            goto emptybuf;
910
        /* complete shift sequence. */
911
0
        goto restart;
912
0
    }
913
0
    n += c;
914
0
    if (n < sizeof(psenc->ch)) {
915
0
        memcpy(psenc->ch, s0 - c, n);
916
0
        psenc->chlen = n;
917
0
        s0 = result;
918
0
        goto restart;
919
0
    }
920
921
    /* escape sequence too long? */
922
923
0
encoding_error:
924
0
    psenc->chlen = 0;
925
0
    *nresult = (size_t)-1;
926
0
    return (EILSEQ);
927
928
0
output:
929
0
    *s = s0;
930
0
    if (pwc)
931
0
        *pwc = wchar;
932
0
    *nresult = wchar ? c - chlenbak : 0;
933
0
    return (0);
934
935
0
restart:
936
0
    *s = s0;
937
0
    *nresult = (size_t)-2;
938
939
0
    return (0);
940
0
}
941
942
static int
943
recommendation(_ISO2022EncodingInfo * ei,
944
    _ISO2022Charset * cs)
945
0
{
946
0
    _ISO2022Charset *recommend;
947
0
    size_t j;
948
0
    int i;
949
950
    /* first, try a exact match. */
951
0
    for (i = 0; i < 4; i++) {
952
0
        recommend = ei->recommend[i];
953
0
        for (j = 0; j < ei->recommendsize[i]; j++) {
954
0
            if (cs->type != recommend[j].type)
955
0
                continue;
956
0
            if (cs->final != recommend[j].final)
957
0
                continue;
958
0
            if (cs->interm != recommend[j].interm)
959
0
                continue;
960
961
0
            return (i);
962
0
        }
963
0
    }
964
965
    /* then, try a wildcard match over final char. */
966
0
    for (i = 0; i < 4; i++) {
967
0
        recommend = ei->recommend[i];
968
0
        for (j = 0; j < ei->recommendsize[i]; j++) {
969
0
            if (cs->type != recommend[j].type)
970
0
                continue;
971
0
            if (cs->final && (cs->final != recommend[j].final))
972
0
                continue;
973
0
            if (cs->interm && (cs->interm != recommend[j].interm))
974
0
                continue;
975
976
0
            return (i);
977
0
        }
978
0
    }
979
980
    /* there's no recommendation. make a guess. */
981
0
    if (ei->maxcharset == 0) {
982
0
        return (0);
983
0
    } else {
984
0
        switch (cs->type) {
985
0
        case CS94:
986
0
        case CS94MULTI:
987
0
            return (0);
988
0
        case CS96:
989
0
        case CS96MULTI:
990
0
            return (1);
991
0
        }
992
0
    }
993
0
    return (0);
994
0
}
995
996
static int
997
_ISO2022_sputwchar(_ISO2022EncodingInfo * ei, _citrus_wc_t wc,
998
    char * string, size_t n, char ** result,
999
    _ISO2022State * psenc, size_t * nresult)
1000
0
{
1001
0
    _ISO2022Charset cs;
1002
0
    char *p;
1003
0
    char tmp[MB_LEN_MAX];
1004
0
    size_t len;
1005
0
    int bit8, i = 0, target;
1006
0
    unsigned char mask;
1007
1008
0
    if (isc0(wc & 0xff)) {
1009
        /* go back to INIT0 or ASCII on control chars */
1010
0
        cs = ei->initg[0].final ? ei->initg[0] : ascii;
1011
0
    } else if (isc1(wc & 0xff)) {
1012
        /* go back to INIT1 or ISO-8859-1 on control chars */
1013
0
        cs = ei->initg[1].final ? ei->initg[1] : iso88591;
1014
0
    } else if (!(wc & ~0xff)) {
1015
0
        if (wc & 0x80) {
1016
            /* special treatment for ISO-8859-1 */
1017
0
            cs = iso88591;
1018
0
        } else {
1019
            /* special treatment for ASCII */
1020
0
            cs = ascii;
1021
0
        }
1022
0
    } else {
1023
0
        cs.final = (wc >> 24) & 0x7f;
1024
0
        if ((wc >> 16) & 0x80)
1025
0
            cs.interm = (wc >> 16) & 0x7f;
1026
0
        else
1027
0
            cs.interm = '\0';
1028
0
        if (wc & 0x80)
1029
0
            cs.type = (wc & 0x00007f00) ? CS96MULTI : CS96;
1030
0
        else
1031
0
            cs.type = (wc & 0x00007f00) ? CS94MULTI : CS94;
1032
0
    }
1033
0
    target = recommendation(ei, &cs);
1034
0
    p = tmp;
1035
0
    bit8 = ei->flags & F_8BIT;
1036
1037
    /* designate the charset onto the target plane(G0/1/2/3). */
1038
0
    if (psenc->g[target].type == cs.type &&
1039
0
        psenc->g[target].final == cs.final &&
1040
0
        psenc->g[target].interm == cs.interm)
1041
0
        goto planeok;
1042
1043
0
    *p++ = '\033';
1044
0
    if (cs.type == CS94MULTI || cs.type == CS96MULTI)
1045
0
        *p++ = '$';
1046
0
    if (target == 0 && cs.type == CS94MULTI && strchr("@AB", cs.final) &&
1047
0
        !cs.interm && !(ei->flags & F_NOOLD))
1048
0
        ;
1049
0
    else if (cs.type == CS94 || cs.type == CS94MULTI)
1050
0
        *p++ = "()*+"[target];
1051
0
    else
1052
0
        *p++ = ",-./"[target];
1053
0
    if (cs.interm)
1054
0
        *p++ = cs.interm;
1055
0
    *p++ = cs.final;
1056
1057
0
    psenc->g[target].type = cs.type;
1058
0
    psenc->g[target].final = cs.final;
1059
0
    psenc->g[target].interm = cs.interm;
1060
1061
0
planeok:
1062
    /* invoke the plane onto GL or GR. */
1063
0
    if (psenc->gl == target)
1064
0
        goto sideok;
1065
0
    if (bit8 && psenc->gr == target)
1066
0
        goto sideok;
1067
1068
0
    if (target == 0 && (ei->flags & F_LS0)) {
1069
0
        *p++ = '\017';
1070
0
        psenc->gl = 0;
1071
0
    } else if (target == 1 && (ei->flags & F_LS1)) {
1072
0
        *p++ = '\016';
1073
0
        psenc->gl = 1;
1074
0
    } else if (target == 2 && (ei->flags & F_LS2)) {
1075
0
        *p++ = '\033';
1076
0
        *p++ = 'n';
1077
0
        psenc->gl = 2;
1078
0
    } else if (target == 3 && (ei->flags & F_LS3)) {
1079
0
        *p++ = '\033';
1080
0
        *p++ = 'o';
1081
0
        psenc->gl = 3;
1082
0
    } else if (bit8 && target == 1 && (ei->flags & F_LS1R)) {
1083
0
        *p++ = '\033';
1084
0
        *p++ = '~';
1085
0
        psenc->gr = 1;
1086
0
    } else if (bit8 && target == 2 && (ei->flags & F_LS2R)) {
1087
0
        *p++ = '\033';
1088
        /*{*/
1089
0
        *p++ = '}';
1090
0
        psenc->gr = 2;
1091
0
    } else if (bit8 && target == 3 && (ei->flags & F_LS3R)) {
1092
0
        *p++ = '\033';
1093
0
        *p++ = '|';
1094
0
        psenc->gr = 3;
1095
0
    } else if (target == 2 && (ei->flags & F_SS2)) {
1096
0
        *p++ = '\033';
1097
0
        *p++ = 'N';
1098
0
        psenc->singlegl = 2;
1099
0
    } else if (target == 3 && (ei->flags & F_SS3)) {
1100
0
        *p++ = '\033';
1101
0
        *p++ = 'O';
1102
0
        psenc->singlegl = 3;
1103
0
    } else if (bit8 && target == 2 && (ei->flags & F_SS2R)) {
1104
0
        *p++ = '\216';
1105
0
        *p++ = 'N';
1106
0
        psenc->singlegl = psenc->singlegr = 2;
1107
0
    } else if (bit8 && target == 3 && (ei->flags & F_SS3R)) {
1108
0
        *p++ = '\217';
1109
0
        *p++ = 'O';
1110
0
        psenc->singlegl = psenc->singlegr = 3;
1111
0
    } else
1112
0
        goto ilseq;
1113
1114
0
sideok:
1115
0
    if (psenc->singlegl == target)
1116
0
        mask = 0x00;
1117
0
    else if (psenc->singlegr == target)
1118
0
        mask = 0x80;
1119
0
    else if (psenc->gl == target)
1120
0
        mask = 0x00;
1121
0
    else if ((ei->flags & F_8BIT) && psenc->gr == target)
1122
0
        mask = 0x80;
1123
0
    else
1124
0
        goto ilseq;
1125
1126
0
    switch (cs.type) {
1127
0
    case CS94:
1128
0
    case CS96:
1129
0
        i = 1;
1130
0
        break;
1131
0
    case CS94MULTI:
1132
0
    case CS96MULTI:
1133
0
        i = !iscntl(wc & 0xff) ?
1134
0
            (isthree(cs.final) ? 3 : 2) : 1;
1135
0
        break;
1136
0
    }
1137
0
    while (i-- > 0)
1138
0
        *p++ = ((wc >> (i << 3)) & 0x7f) | mask;
1139
1140
    /* reset single shift state */
1141
0
    psenc->singlegl = psenc->singlegr = -1;
1142
1143
0
    len = (size_t)(p - tmp);
1144
0
    if (n < len) {
1145
0
        if (result)
1146
0
            *result = (char *)0;
1147
0
        *nresult = (size_t)-1;
1148
0
        return (E2BIG);
1149
0
    }
1150
0
    if (result)
1151
0
        *result = string + len;
1152
0
    memcpy(string, tmp, len);
1153
0
    *nresult = len;
1154
1155
0
    return (0);
1156
1157
0
ilseq:
1158
0
    *nresult = (size_t)-1;
1159
0
    return (EILSEQ);
1160
0
}
1161
1162
static int
1163
_citrus_ISO2022_put_state_reset(_ISO2022EncodingInfo * ei,
1164
    char * s, size_t n, _ISO2022State * psenc,
1165
    size_t * nresult)
1166
0
{
1167
0
    char *result;
1168
0
    char buf[MB_LEN_MAX];
1169
0
    size_t len;
1170
0
    int ret;
1171
1172
    /* XXX state will be modified after this operation... */
1173
0
    ret = _ISO2022_sputwchar(ei, L'\0', buf, sizeof(buf), &result, psenc,
1174
0
        &len);
1175
0
    if (ret) {
1176
0
        *nresult = len;
1177
0
        return (ret);
1178
0
    }
1179
1180
0
    if (sizeof(buf) < len || n < len-1) {
1181
        /* XXX should recover state? */
1182
0
        *nresult = (size_t)-1;
1183
0
        return (E2BIG);
1184
0
    }
1185
1186
0
    memcpy(s, buf, len - 1);
1187
0
    *nresult = len - 1;
1188
0
    return (0);
1189
0
}
1190
1191
static int
1192
_citrus_ISO2022_wcrtomb_priv(_ISO2022EncodingInfo * ei,
1193
    char * s, size_t n, _citrus_wc_t wc,
1194
    _ISO2022State * psenc, size_t * nresult)
1195
0
{
1196
0
    char *result;
1197
0
    char buf[MB_LEN_MAX];
1198
0
    size_t len;
1199
0
    int ret;
1200
1201
    /* XXX state will be modified after this operation... */
1202
0
    ret = _ISO2022_sputwchar(ei, wc, buf, sizeof(buf), &result, psenc,
1203
0
        &len);
1204
0
    if (ret) {
1205
0
        *nresult = len;
1206
0
        return (ret);
1207
0
    }
1208
1209
0
    if (sizeof(buf) < len || n < len) {
1210
        /* XXX should recover state? */
1211
0
        *nresult = (size_t)-1;
1212
0
        return (E2BIG);
1213
0
    }
1214
1215
0
    memcpy(s, buf, len);
1216
0
    *nresult = len;
1217
0
    return (0);
1218
0
}
1219
1220
static __inline int
1221
/*ARGSUSED*/
1222
_citrus_ISO2022_stdenc_wctocs(_ISO2022EncodingInfo * ei ,
1223
    _citrus_csid_t * csid, _citrus_index_t * idx, _citrus_wc_t wc)
1224
0
{
1225
0
    _citrus_wc_t m, nm;
1226
0
    (void) ei;
1227
1228
0
    m = wc & 0x7FFF8080;
1229
0
    nm = wc & 0x007F7F7F;
1230
0
    if (m & 0x00800000)
1231
0
        nm &= 0x00007F7F;
1232
0
    else
1233
0
        m &= 0x7F008080;
1234
0
    if (nm & 0x007F0000) {
1235
        /* ^3 mark */
1236
0
        m |= 0x007F0000;
1237
0
    } else if (nm & 0x00007F00) {
1238
        /* ^2 mark */
1239
0
        m |= 0x00007F00;
1240
0
    }
1241
0
    *csid = (_citrus_csid_t)m;
1242
0
    *idx  = (_citrus_index_t)nm;
1243
1244
0
    return (0);
1245
0
}
1246
1247
static __inline int
1248
/*ARGSUSED*/
1249
_citrus_ISO2022_stdenc_cstowc(_ISO2022EncodingInfo * ei ,
1250
    _citrus_wc_t * wc, _citrus_csid_t csid, _citrus_index_t idx)
1251
0
{
1252
0
    (void) ei;
1253
1254
0
    *wc = (_citrus_wc_t)(csid & 0x7F808080) | (_citrus_wc_t)idx;
1255
1256
0
    return (0);
1257
0
}
1258
1259
static __inline int
1260
/*ARGSUSED*/
1261
_citrus_ISO2022_stdenc_get_state_desc_generic(_ISO2022EncodingInfo * ei ,
1262
    _ISO2022State * psenc, int * rstate)
1263
0
{
1264
0
    (void) ei;
1265
1266
0
    if (psenc->chlen == 0) {
1267
        /* XXX: it should distinguish initial and stable. */
1268
0
        *rstate = _CITRUS_STDENC_SDGEN_STABLE;
1269
0
    } else
1270
0
        *rstate = (psenc->ch[0] == '\033') ?
1271
0
            _CITRUS_STDENC_SDGEN_INCOMPLETE_SHIFT :
1272
0
            _CITRUS_STDENC_SDGEN_INCOMPLETE_CHAR;
1273
0
    return (0);
1274
0
}
1275
1276
/* ----------------------------------------------------------------------
1277
 * public interface for stdenc
1278
 */
1279
1280
_CITRUS_STDENC_DECLS(ISO2022);
1281
_CITRUS_STDENC_DEF_OPS(ISO2022);
1282
1283
#include "citrus_stdenc_template.h"