]> granicus.if.org Git - postgresql/blob - src/backend/utils/mb/mbutils.c
Restructure the key include files per recent pghackers discussion: there
[postgresql] / src / backend / utils / mb / mbutils.c
1 /*
2  * This file contains public functions for conversion between
3  * client encoding and server internal encoding.
4  * (currently mule internal code (mic) is used)
5  * Tatsuo Ishii
6  * $Id: mbutils.c,v 1.15 2001/02/10 02:31:27 tgl Exp $
7  */
8 #include "postgres.h"
9
10 #include "miscadmin.h"
11 #include "mb/pg_wchar.h"
12 #include "utils/builtins.h"
13
14 static int      client_encoding = -1;
15 static void (*client_to_mic) ();/* something to MIC */
16 static void (*client_from_mic) ();              /* MIC to something */
17 static void (*server_to_mic) ();/* something to MIC */
18 static void (*server_from_mic) ();              /* MIC to something */
19
20 /*
21  * find encoding table entry by encoding
22  */
23 pg_encoding_conv_tbl *
24 pg_get_enc_ent(int encoding)
25 {
26         pg_encoding_conv_tbl *p = pg_conv_tbl;
27
28         for (; p->encoding >= 0; p++)
29         {
30                 if (p->encoding == encoding)
31                         return (p);
32         }
33         return (0);
34 }
35
36 /*
37  * set the client encoding. if encoding conversion between
38  * client/server encoding is not supported, returns -1
39  */
40 int
41 pg_set_client_encoding(int encoding)
42 {
43         int                     current_server_encoding = GetDatabaseEncoding();
44
45         client_encoding = encoding;
46
47         if (client_encoding == current_server_encoding)
48         {                                                       /* server == client? */
49                 client_to_mic = client_from_mic = 0;
50                 server_to_mic = server_from_mic = 0;
51         }
52         else if (current_server_encoding == MULE_INTERNAL)
53         {                                                       /* server == MULE_INETRNAL? */
54                 client_to_mic = pg_get_enc_ent(encoding)->to_mic;
55                 client_from_mic = pg_get_enc_ent(encoding)->from_mic;
56                 server_to_mic = server_from_mic = 0;
57                 if (client_to_mic == 0 || client_from_mic == 0)
58                         return (-1);
59         }
60         else if (encoding == MULE_INTERNAL)
61         {                                                       /* client == MULE_INETRNAL? */
62                 client_to_mic = client_from_mic = 0;
63                 server_to_mic = pg_get_enc_ent(current_server_encoding)->to_mic;
64                 server_from_mic = pg_get_enc_ent(current_server_encoding)->from_mic;
65                 if (server_to_mic == 0 || server_from_mic == 0)
66                         return (-1);
67         }
68         else if (current_server_encoding == UNICODE)
69         {                                                       /* server == UNICODE? */
70                 client_to_mic = pg_get_enc_ent(encoding)->to_unicode;
71                 client_from_mic = pg_get_enc_ent(encoding)->from_unicode;
72                 server_to_mic = server_from_mic = 0;
73                 if (client_to_mic == 0 || client_from_mic == 0)
74                         return (-1);
75         }
76         else if (encoding == UNICODE)
77         {                                                       /* client == UNICODE? */
78                 client_to_mic = client_from_mic = 0;
79                 server_to_mic = pg_get_enc_ent(current_server_encoding)->to_unicode;
80                 server_from_mic = pg_get_enc_ent(current_server_encoding)->from_unicode;
81                 if (server_to_mic == 0 || server_from_mic == 0)
82                         return (-1);
83         }
84         else
85         {
86                 client_to_mic = pg_get_enc_ent(encoding)->to_mic;
87                 client_from_mic = pg_get_enc_ent(encoding)->from_mic;
88                 server_to_mic = pg_get_enc_ent(current_server_encoding)->to_mic;
89                 server_from_mic = pg_get_enc_ent(current_server_encoding)->from_mic;
90                 if (client_to_mic == 0 || client_from_mic == 0)
91                         return (-1);
92                 if (server_to_mic == 0 || server_from_mic == 0)
93                         return (-1);
94         }
95         return (0);
96 }
97
98 /*
99  * returns the current client encoding
100  */
101 int
102 pg_get_client_encoding()
103 {
104         if (client_encoding == -1)
105         {
106                 /* this is the first time */
107                 client_encoding = GetDatabaseEncoding();
108         }
109         return (client_encoding);
110 }
111
112 /*
113  * convert client encoding to server encoding.
114  *
115  * CASE 1: if no conversion is required, then the given pointer s is returned.
116  *
117  * CASE 2: if conversion is required, a palloc'd string is returned.
118  *
119  * Callers must check whether return value differs from passed value
120  * to determine whether to pfree the result or not!
121  *
122  * Note: we assume that conversion cannot cause more than a 4-to-1 growth
123  * in the length of the string --- is this enough?
124  */
125 unsigned char *
126 pg_client_to_server(unsigned char *s, int len)
127 {
128         unsigned char *result = s;
129         unsigned char *buf;
130
131         if (client_encoding == GetDatabaseEncoding())
132                 return result;
133         if (client_to_mic)
134         {
135                 buf = (unsigned char *) palloc(len * 4 + 1);
136                 (*client_to_mic) (result, buf, len);
137                 result = buf;
138                 len = strlen(result);
139         }
140         if (server_from_mic)
141         {
142                 buf = (unsigned char *) palloc(len * 4 + 1);
143                 (*server_from_mic) (result, buf, len);
144                 if (result != s)
145                         pfree(result);          /* release first buffer */
146                 result = buf;
147         }
148         return result;
149 }
150
151 /*
152  * convert server encoding to client encoding.
153  *
154  * CASE 1: if no conversion is required, then the given pointer s is returned.
155  *
156  * CASE 2: if conversion is required, a palloc'd string is returned.
157  *
158  * Callers must check whether return value differs from passed value
159  * to determine whether to pfree the result or not!
160  *
161  * Note: we assume that conversion cannot cause more than a 4-to-1 growth
162  * in the length of the string --- is this enough?
163  */
164 unsigned char *
165 pg_server_to_client(unsigned char *s, int len)
166 {
167         unsigned char *result = s;
168         unsigned char *buf;
169
170         if (client_encoding == GetDatabaseEncoding())
171                 return result;
172         if (server_to_mic)
173         {
174                 buf = (unsigned char *) palloc(len * 4 + 1);
175                 (*server_to_mic) (result, buf, len);
176                 result = buf;
177                 len = strlen(result);
178         }
179         if (client_from_mic)
180         {
181                 buf = (unsigned char *) palloc(len * 4 + 1);
182                 (*client_from_mic) (result, buf, len);
183                 if (result != s)
184                         pfree(result);          /* release first buffer */
185                 result = buf;
186         }
187         return result;
188 }
189
190 /* convert a multi-byte string to a wchar */
191 int
192 pg_mb2wchar(const unsigned char *from, pg_wchar * to)
193 {
194         return (*pg_wchar_table[GetDatabaseEncoding()].mb2wchar_with_len) (from, to, strlen(from));
195 }
196
197 /* convert a multi-byte string to a wchar with a limited length */
198 int
199 pg_mb2wchar_with_len(const unsigned char *from, pg_wchar * to, int len)
200 {
201         return (*pg_wchar_table[GetDatabaseEncoding()].mb2wchar_with_len) (from, to, len);
202 }
203
204 /* returns the byte length of a multi-byte word */
205 int
206 pg_mblen(const unsigned char *mbstr)
207 {
208         return ((*pg_wchar_table[GetDatabaseEncoding()].mblen) (mbstr));
209 }
210
211 /* returns the length (counted as a wchar) of a multi-byte string */
212 int
213 pg_mbstrlen(const unsigned char *mbstr)
214 {
215         int                     len = 0;
216
217         while (*mbstr)
218         {
219                 mbstr += pg_mblen(mbstr);
220                 len++;
221         }
222         return (len);
223 }
224
225 /* returns the length (counted as a wchar) of a multi-byte string
226    (not necessarily  NULL terminated) */
227 int
228 pg_mbstrlen_with_len(const unsigned char *mbstr, int limit)
229 {
230         int                     len = 0;
231         int                     l;
232
233         while (*mbstr && limit > 0)
234         {
235                 l = pg_mblen(mbstr);
236                 limit -= l;
237                 mbstr += l;
238                 len++;
239         }
240         return (len);
241 }
242
243 /*
244  * returns the length of a multi-byte string
245  * (not necessarily  NULL terminated)
246  * that is not longer than limit.
247  * this function does not break multi-byte word boundary.
248  */
249 int
250 pg_mbcliplen(const unsigned char *mbstr, int len, int limit)
251 {
252         int                     clen = 0;
253         int                     l;
254
255         while (*mbstr && len > 0)
256         {
257                 l = pg_mblen(mbstr);
258                 if ((clen + l) > limit)
259                         break;
260                 clen += l;
261                 if (clen == limit)
262                         break;
263                 len -= l;
264                 mbstr += l;
265         }
266         return (clen);
267 }
268
269 /*
270  * fuctions for utils/init
271  */
272 static int      DatabaseEncoding = MULTIBYTE;
273
274 void
275 SetDatabaseEncoding(int encoding)
276 {
277         DatabaseEncoding = encoding;
278 }
279
280 int
281 GetDatabaseEncoding()
282 {
283         return (DatabaseEncoding);
284 }
285
286 /* for builtin-function */
287 Datum
288 getdatabaseencoding(PG_FUNCTION_ARGS)
289 {
290         PG_RETURN_NAME(pg_encoding_to_char(DatabaseEncoding));
291 }