second update 960907 from main archive
[kopensolaris-gnu/glibc.git] / locale / programs / stringtrans.c
1 /* Copyright (C) 1996 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
17 not, 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, str + 1, tp - (str + 1));
96       if (value == ILLEGAL_CHAR_VALUE)
97         {
98           free (buf);
99           return NULL;
100         }
101       else
102         /* Encode string using current method.  */
103         ADDC (value);
104
105       str = &tp[1];
106     }
107
108   ADDC ('\0');
109
110   return buf;
111 }
112
113
114 int
115 encode_char (unsigned int value, char **cpp)
116 {
117   switch (encoding_method)
118     {
119     case ENC_UCS1:
120       if (value > 255)
121         return -1;
122       *(*cpp)++ = (char) value;
123       break;
124
125     case ENC_UCS4:
126 #if __BYTE_ORDER == __BIG_ENDIAN
127       *(*cpp)++ = (char) (value >> 24);
128       *(*cpp)++ = (char) ((value >> 16) & 0xff);
129       *(*cpp)++ = (char) ((value >> 8) & 0xff);
130       *(*cpp)++ = (char) (value & 0xff);
131 #else
132       *(*cpp)++ = (char) (value & 0xff);
133       *(*cpp)++ = (char) ((value >>= 8) & 0xff);
134       *(*cpp)++ = (char) ((value >>= 8) & 0xff);
135       *(*cpp)++ = (char) ((value >>= 8) & 0xff);
136 #endif
137       break;
138
139     default:
140       return -1;
141     }
142
143   return 0;
144 }