123338178SMark Peek /*
223338178SMark Peek * tc.nls.c: NLS handling
323338178SMark Peek */
423338178SMark Peek /*-
523338178SMark Peek * Copyright (c) 1980, 1991 The Regents of the University of California.
623338178SMark Peek * All rights reserved.
723338178SMark Peek *
823338178SMark Peek * Redistribution and use in source and binary forms, with or without
923338178SMark Peek * modification, are permitted provided that the following conditions
1023338178SMark Peek * are met:
1123338178SMark Peek * 1. Redistributions of source code must retain the above copyright
1223338178SMark Peek * notice, this list of conditions and the following disclaimer.
1323338178SMark Peek * 2. Redistributions in binary form must reproduce the above copyright
1423338178SMark Peek * notice, this list of conditions and the following disclaimer in the
1523338178SMark Peek * documentation and/or other materials provided with the distribution.
1623338178SMark Peek * 3. Neither the name of the University nor the names of its contributors
1723338178SMark Peek * may be used to endorse or promote products derived from this software
1823338178SMark Peek * without specific prior written permission.
1923338178SMark Peek *
2023338178SMark Peek * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2123338178SMark Peek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2223338178SMark Peek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2323338178SMark Peek * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2423338178SMark Peek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2523338178SMark Peek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2623338178SMark Peek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2723338178SMark Peek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2823338178SMark Peek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2923338178SMark Peek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3023338178SMark Peek * SUCH DAMAGE.
3123338178SMark Peek */
3223338178SMark Peek #include "sh.h"
3323338178SMark Peek
3445e5710bSMark Peek #ifdef WIDE_STRINGS
359ccc37e3SMark Peek # ifdef HAVE_WCWIDTH
369ccc37e3SMark Peek # ifdef UTF16_STRINGS
379ccc37e3SMark Peek int
xwcwidth(wint_t wchar)389ccc37e3SMark Peek xwcwidth (wint_t wchar)
399ccc37e3SMark Peek {
409ccc37e3SMark Peek wchar_t ws[2];
419ccc37e3SMark Peek
429ccc37e3SMark Peek if (wchar <= 0xffff)
439ccc37e3SMark Peek return wcwidth ((wchar_t) wchar);
449ccc37e3SMark Peek /* UTF-16 systems can't handle these values directly in calls to wcwidth.
459ccc37e3SMark Peek However, they can handle them as surrogate pairs in calls to wcswidth.
469ccc37e3SMark Peek What we do here is to convert UTF-32 values >= 0x10000 into surrogate
479ccc37e3SMark Peek pairs and compute the width by calling wcswidth. */
489ccc37e3SMark Peek wchar -= 0x10000;
499ccc37e3SMark Peek ws[0] = 0xd800 | (wchar >> 10);
509ccc37e3SMark Peek ws[1] = 0xdc00 | (wchar & 0x3ff);
519ccc37e3SMark Peek return wcswidth (ws, 2);
529ccc37e3SMark Peek }
539ccc37e3SMark Peek # else
549ccc37e3SMark Peek #define xwcwidth wcwidth
559ccc37e3SMark Peek # endif /* !UTF16_STRINGS */
569ccc37e3SMark Peek # endif /* HAVE_WCWIDTH */
579ccc37e3SMark Peek
5823338178SMark Peek int
NLSWidth(Char c)5945e5710bSMark Peek NLSWidth(Char c)
6023338178SMark Peek {
6123338178SMark Peek # ifdef HAVE_WCWIDTH
6223338178SMark Peek int l;
63*19d2e3deSDmitry Chagin #if INVALID_BYTE != 0
64*19d2e3deSDmitry Chagin if ((c & INVALID_BYTE) == INVALID_BYTE) /* c >= INVALID_BYTE */
65*19d2e3deSDmitry Chagin #else
6645e5710bSMark Peek if (c & INVALID_BYTE)
67*19d2e3deSDmitry Chagin #endif
6823338178SMark Peek return 1;
699ccc37e3SMark Peek l = xwcwidth((wchar_t) c);
7023338178SMark Peek return l >= 0 ? l : 0;
7123338178SMark Peek # else
7245e5710bSMark Peek return iswprint(c) != 0;
7323338178SMark Peek # endif
7423338178SMark Peek }
7545e5710bSMark Peek
7645e5710bSMark Peek int
NLSStringWidth(const Char * s)7745e5710bSMark Peek NLSStringWidth(const Char *s)
7845e5710bSMark Peek {
7945e5710bSMark Peek int w = 0, l;
8045e5710bSMark Peek Char c;
8145e5710bSMark Peek
8245e5710bSMark Peek while (*s) {
8345e5710bSMark Peek c = *s++;
8445e5710bSMark Peek #ifdef HAVE_WCWIDTH
859ccc37e3SMark Peek if ((l = xwcwidth((wchar_t) c)) < 0)
8645e5710bSMark Peek l = 2;
8745e5710bSMark Peek #else
8845e5710bSMark Peek l = iswprint(c) != 0;
8945e5710bSMark Peek #endif
9045e5710bSMark Peek w += l;
9145e5710bSMark Peek }
9245e5710bSMark Peek return w;
9345e5710bSMark Peek }
9423338178SMark Peek #endif
9523338178SMark Peek
9623338178SMark Peek Char *
NLSChangeCase(const Char * p,int mode)9745e5710bSMark Peek NLSChangeCase(const Char *p, int mode)
9823338178SMark Peek {
9945e5710bSMark Peek Char c, *n, c2 = 0;
10045e5710bSMark Peek const Char *op = p;
10145e5710bSMark Peek
10223338178SMark Peek for (; (c = *p) != 0; p++) {
10323338178SMark Peek if (mode == 0 && Islower(c)) {
10423338178SMark Peek c2 = Toupper(c);
10523338178SMark Peek break;
10623338178SMark Peek } else if (mode && Isupper(c)) {
10723338178SMark Peek c2 = Tolower(c);
10823338178SMark Peek break;
10923338178SMark Peek }
11023338178SMark Peek }
11123338178SMark Peek if (!*p)
11223338178SMark Peek return 0;
11323338178SMark Peek n = Strsave(op);
11423338178SMark Peek n[p - op] = c2;
11523338178SMark Peek return n;
11623338178SMark Peek }
11723338178SMark Peek
11823338178SMark Peek int
NLSClassify(Char c,int nocomb,int drawPrompt)119*19d2e3deSDmitry Chagin NLSClassify(Char c, int nocomb, int drawPrompt)
12023338178SMark Peek {
12123338178SMark Peek int w;
122*19d2e3deSDmitry Chagin #ifndef SHORT_STRINGS
123*19d2e3deSDmitry Chagin if ((c & 0x80) != 0) /* c >= 0x80 */
12423338178SMark Peek return NLSCLASS_ILLEGAL;
125*19d2e3deSDmitry Chagin #endif
126*19d2e3deSDmitry Chagin if (!drawPrompt) { /* draw command-line */
127*19d2e3deSDmitry Chagin #if INVALID_BYTE != 0
128*19d2e3deSDmitry Chagin if ((c & INVALID_BYTE) == INVALID_BYTE) /* c >= INVALID_BYTE */
129*19d2e3deSDmitry Chagin return NLSCLASS_ILLEGAL;
130*19d2e3deSDmitry Chagin if ((c & INVALID_BYTE) == QUOTE && (c & 0x80) == 0) /* c >= QUOTE */
131*19d2e3deSDmitry Chagin return 1;
132*19d2e3deSDmitry Chagin if (c >= 0x10000000) /* U+10000000 = FC 90 80 80 80 80 */
133*19d2e3deSDmitry Chagin return NLSCLASS_ILLEGAL5;
134*19d2e3deSDmitry Chagin if (c >= 0x1000000) /* U+1000000 = F9 80 80 80 80 */
135*19d2e3deSDmitry Chagin return NLSCLASS_ILLEGAL4;
136*19d2e3deSDmitry Chagin if (c >= 0x100000) /* U+100000 = F4 80 80 80 */
137*19d2e3deSDmitry Chagin return NLSCLASS_ILLEGAL3;
138*19d2e3deSDmitry Chagin #endif
139*19d2e3deSDmitry Chagin if (c >= 0x10000) /* U+10000 = F0 90 80 80 */
140*19d2e3deSDmitry Chagin return NLSCLASS_ILLEGAL2;
141*19d2e3deSDmitry Chagin }
14245e5710bSMark Peek if (Iscntrl(c) && (c & CHAR) < 0x100) {
14323338178SMark Peek if (c == '\n')
14423338178SMark Peek return NLSCLASS_NL;
14523338178SMark Peek if (c == '\t')
14623338178SMark Peek return NLSCLASS_TAB;
14723338178SMark Peek return NLSCLASS_CTRL;
14823338178SMark Peek }
149*19d2e3deSDmitry Chagin w = NLSWidth(c);
150*19d2e3deSDmitry Chagin if (drawPrompt) { /* draw prompt */
151*19d2e3deSDmitry Chagin if (w > 0)
152*19d2e3deSDmitry Chagin return w;
153*19d2e3deSDmitry Chagin if (w == 0)
154*19d2e3deSDmitry Chagin return 1;
155*19d2e3deSDmitry Chagin }
156*19d2e3deSDmitry Chagin if ((w > 0 && !(Iscntrl(c) && (c & CHAR) < 0x100)) || (Isprint(c) && !nocomb))
157*19d2e3deSDmitry Chagin return w;
15823338178SMark Peek return NLSCLASS_ILLEGAL;
15923338178SMark Peek }
160