Starting fixing character set handling to handle multi-byte encodings.
[kopensolaris-gnu/glibc.git] / locale / programs / stringtrans.c
1 /* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <assert.h>
25 #include <stdlib.h>
26
27 #include "charset.h"
28 #include "stringtrans.h"
29
30
31 /* Global variable.  */
32 enum encoding_method encoding_method = ENC_UCS4;
33
34
35 void *xmalloc (size_t __n);
36 void *xrealloc (void *__p, size_t __n);
37
38
39 #define ADDC(ch)                                                              \
40   do                                                                          \
41     {                                                                         \
42       char *cp;                                                               \
43       if (bufact + (encoding_method == ENC_UCS4 ? 4 : 1) >= bufmax)           \
44         {                                                                     \
45           bufmax *= 2;                                                        \
46           buf = xrealloc (buf, bufmax);                                       \
47         }                                                                     \
48       cp = &buf[bufact];                                                      \
49       if (encode_char (ch, &cp) < 0)                                          \
50         {                                                                     \
51           free (buf);                                                         \
52           return NULL;                                                        \
53         }                                                                     \
54       bufact = cp - buf;                                                      \
55     }                                                                         \
56   while (0)
57
58
59 char *
60 translate_string (char *str, struct charset_t *charset)
61 {
62   char *buf;
63   size_t bufact = 0;
64   size_t bufmax = 56;
65
66   buf = (char *) xmalloc (bufmax);
67
68   while (str[0] != '\0')
69     {
70       char *tp;
71       unsigned int value;
72
73       if (str[0] != '<')
74         {
75           ADDC (*str++);
76           continue;
77         }
78
79       tp = &str[1];
80       while (tp[0] != '\0' && tp[0] != '>')
81         if (tp[0] == '\\')
82           if (tp[1] != '\0')
83             tp += 2;
84           else
85             ++tp;
86         else
87           ++tp;
88
89       if (tp[0] == '\0')
90         {
91           free (buf);
92           return NULL;
93         }
94
95       value = charset_find_value (&charset->char_table, str + 1,
96                                   tp - (str + 1));
97       if ((wchar_t) value == ILLEGAL_CHAR_VALUE)
98         {
99           free (buf);
100           return NULL;
101         }
102       else
103         /* Encode string using current method.  */
104         ADDC (value);
105
106       str = &tp[1];
107     }
108
109   ADDC ('\0');
110
111   return buf;
112 }
113
114
115 int
116 encode_char (unsigned int value, char **cpp)
117 {
118   switch (encoding_method)
119     {
120     case ENC_UCS1:
121       if (value > 255)
122         return -1;
123       *(*cpp)++ = (char) value;
124       break;
125
126     case ENC_UCS4:
127 #if __BYTE_ORDER == __BIG_ENDIAN
128       *(*cpp)++ = (char) (value >> 24);
129       *(*cpp)++ = (char) ((value >> 16) & 0xff);
130       *(*cpp)++ = (char) ((value >> 8) & 0xff);
131       *(*cpp)++ = (char) (value & 0xff);
132 #else
133       *(*cpp)++ = (char) (value & 0xff);
134       *(*cpp)++ = (char) ((value >>= 8) & 0xff);
135       *(*cpp)++ = (char) ((value >>= 8) & 0xff);
136       *(*cpp)++ = (char) ((value >>= 8) & 0xff);
137 #endif
138       break;
139
140     default:
141       return -1;
142     }
143
144   return 0;
145 }