1998-07-24 05:32:46 +02:00
|
|
|
/*
|
|
|
|
* This file contains public functions for conversion between
|
|
|
|
* client encoding and server internal encoding.
|
|
|
|
* (currently mule internal code (mic) is used)
|
|
|
|
* Tatsuo Ishii
|
2001-07-15 13:07:37 +02:00
|
|
|
* $Id: mbutils.c,v 1.18 2001/07/15 11:07:36 ishii Exp $
|
2001-02-10 03:31:31 +01:00
|
|
|
*/
|
1999-07-17 18:25:28 +02:00
|
|
|
#include "postgres.h"
|
2000-06-13 09:35:40 +02:00
|
|
|
|
1999-07-17 18:25:28 +02:00
|
|
|
#include "miscadmin.h"
|
1998-07-24 05:32:46 +02:00
|
|
|
#include "mb/pg_wchar.h"
|
2000-06-13 09:35:40 +02:00
|
|
|
#include "utils/builtins.h"
|
1998-07-24 05:32:46 +02:00
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
static int client_encoding = -1;
|
1998-09-01 06:40:42 +02:00
|
|
|
static void (*client_to_mic) ();/* something to MIC */
|
|
|
|
static void (*client_from_mic) (); /* MIC to something */
|
|
|
|
static void (*server_to_mic) ();/* something to MIC */
|
|
|
|
static void (*server_from_mic) (); /* MIC to something */
|
1998-07-24 05:32:46 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* find encoding table entry by encoding
|
|
|
|
*/
|
2000-10-12 08:06:50 +02:00
|
|
|
pg_encoding_conv_tbl *
|
|
|
|
pg_get_enc_ent(int encoding)
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
pg_encoding_conv_tbl *p = pg_conv_tbl;
|
|
|
|
|
|
|
|
for (; p->encoding >= 0; p++)
|
|
|
|
{
|
|
|
|
if (p->encoding == encoding)
|
|
|
|
return (p);
|
|
|
|
}
|
|
|
|
return (0);
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-10-12 08:06:50 +02:00
|
|
|
* set the client encoding. if encoding conversion between
|
|
|
|
* client/server encoding is not supported, returns -1
|
1998-07-24 05:32:46 +02:00
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
int
|
|
|
|
pg_set_client_encoding(int encoding)
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
int current_server_encoding = GetDatabaseEncoding();
|
|
|
|
|
|
|
|
client_encoding = encoding;
|
|
|
|
|
|
|
|
if (client_encoding == current_server_encoding)
|
|
|
|
{ /* server == client? */
|
|
|
|
client_to_mic = client_from_mic = 0;
|
|
|
|
server_to_mic = server_from_mic = 0;
|
|
|
|
}
|
|
|
|
else if (current_server_encoding == MULE_INTERNAL)
|
|
|
|
{ /* server == MULE_INETRNAL? */
|
2000-10-12 08:06:50 +02:00
|
|
|
client_to_mic = pg_get_enc_ent(encoding)->to_mic;
|
|
|
|
client_from_mic = pg_get_enc_ent(encoding)->from_mic;
|
1998-09-01 06:40:42 +02:00
|
|
|
server_to_mic = server_from_mic = 0;
|
|
|
|
if (client_to_mic == 0 || client_from_mic == 0)
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
else if (encoding == MULE_INTERNAL)
|
|
|
|
{ /* client == MULE_INETRNAL? */
|
|
|
|
client_to_mic = client_from_mic = 0;
|
2000-10-12 08:06:50 +02:00
|
|
|
server_to_mic = pg_get_enc_ent(current_server_encoding)->to_mic;
|
|
|
|
server_from_mic = pg_get_enc_ent(current_server_encoding)->from_mic;
|
|
|
|
if (server_to_mic == 0 || server_from_mic == 0)
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
else if (current_server_encoding == UNICODE)
|
|
|
|
{ /* server == UNICODE? */
|
|
|
|
client_to_mic = pg_get_enc_ent(encoding)->to_unicode;
|
|
|
|
client_from_mic = pg_get_enc_ent(encoding)->from_unicode;
|
|
|
|
server_to_mic = server_from_mic = 0;
|
|
|
|
if (client_to_mic == 0 || client_from_mic == 0)
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
else if (encoding == UNICODE)
|
|
|
|
{ /* client == UNICODE? */
|
|
|
|
client_to_mic = client_from_mic = 0;
|
|
|
|
server_to_mic = pg_get_enc_ent(current_server_encoding)->to_unicode;
|
|
|
|
server_from_mic = pg_get_enc_ent(current_server_encoding)->from_unicode;
|
1998-09-01 06:40:42 +02:00
|
|
|
if (server_to_mic == 0 || server_from_mic == 0)
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-10-12 08:06:50 +02:00
|
|
|
client_to_mic = pg_get_enc_ent(encoding)->to_mic;
|
|
|
|
client_from_mic = pg_get_enc_ent(encoding)->from_mic;
|
|
|
|
server_to_mic = pg_get_enc_ent(current_server_encoding)->to_mic;
|
|
|
|
server_from_mic = pg_get_enc_ent(current_server_encoding)->from_mic;
|
1998-09-01 06:40:42 +02:00
|
|
|
if (client_to_mic == 0 || client_from_mic == 0)
|
|
|
|
return (-1);
|
|
|
|
if (server_to_mic == 0 || server_from_mic == 0)
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
return (0);
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* returns the current client encoding
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
int
|
|
|
|
pg_get_client_encoding()
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
if (client_encoding == -1)
|
|
|
|
{
|
|
|
|
/* this is the first time */
|
|
|
|
client_encoding = GetDatabaseEncoding();
|
|
|
|
}
|
|
|
|
return (client_encoding);
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1999-09-12 00:28:11 +02:00
|
|
|
* convert client encoding to server encoding.
|
|
|
|
*
|
|
|
|
* CASE 1: if no conversion is required, then the given pointer s is returned.
|
|
|
|
*
|
|
|
|
* CASE 2: if conversion is required, a palloc'd string is returned.
|
|
|
|
*
|
|
|
|
* Callers must check whether return value differs from passed value
|
|
|
|
* to determine whether to pfree the result or not!
|
|
|
|
*
|
|
|
|
* Note: we assume that conversion cannot cause more than a 4-to-1 growth
|
|
|
|
* in the length of the string --- is this enough?
|
1998-07-24 05:32:46 +02:00
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
unsigned char *
|
|
|
|
pg_client_to_server(unsigned char *s, int len)
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
1999-09-12 00:28:11 +02:00
|
|
|
unsigned char *result = s;
|
|
|
|
unsigned char *buf;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
|
|
|
if (client_encoding == GetDatabaseEncoding())
|
1999-09-12 00:28:11 +02:00
|
|
|
return result;
|
1998-09-01 06:40:42 +02:00
|
|
|
if (client_to_mic)
|
|
|
|
{
|
1999-09-12 00:28:11 +02:00
|
|
|
buf = (unsigned char *) palloc(len * 4 + 1);
|
|
|
|
(*client_to_mic) (result, buf, len);
|
|
|
|
result = buf;
|
|
|
|
len = strlen(result);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
|
|
|
if (server_from_mic)
|
|
|
|
{
|
1999-09-12 00:28:11 +02:00
|
|
|
buf = (unsigned char *) palloc(len * 4 + 1);
|
|
|
|
(*server_from_mic) (result, buf, len);
|
|
|
|
if (result != s)
|
|
|
|
pfree(result); /* release first buffer */
|
|
|
|
result = buf;
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
1999-09-12 00:28:11 +02:00
|
|
|
return result;
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1999-09-12 00:28:11 +02:00
|
|
|
* convert server encoding to client encoding.
|
|
|
|
*
|
|
|
|
* CASE 1: if no conversion is required, then the given pointer s is returned.
|
|
|
|
*
|
|
|
|
* CASE 2: if conversion is required, a palloc'd string is returned.
|
|
|
|
*
|
|
|
|
* Callers must check whether return value differs from passed value
|
|
|
|
* to determine whether to pfree the result or not!
|
|
|
|
*
|
|
|
|
* Note: we assume that conversion cannot cause more than a 4-to-1 growth
|
|
|
|
* in the length of the string --- is this enough?
|
1998-07-24 05:32:46 +02:00
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
unsigned char *
|
|
|
|
pg_server_to_client(unsigned char *s, int len)
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
1999-09-12 00:28:11 +02:00
|
|
|
unsigned char *result = s;
|
|
|
|
unsigned char *buf;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
|
|
|
if (client_encoding == GetDatabaseEncoding())
|
1999-09-12 00:28:11 +02:00
|
|
|
return result;
|
1998-09-01 06:40:42 +02:00
|
|
|
if (server_to_mic)
|
|
|
|
{
|
1999-09-12 00:28:11 +02:00
|
|
|
buf = (unsigned char *) palloc(len * 4 + 1);
|
|
|
|
(*server_to_mic) (result, buf, len);
|
|
|
|
result = buf;
|
|
|
|
len = strlen(result);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
|
|
|
if (client_from_mic)
|
|
|
|
{
|
1999-09-12 00:28:11 +02:00
|
|
|
buf = (unsigned char *) palloc(len * 4 + 1);
|
|
|
|
(*client_from_mic) (result, buf, len);
|
|
|
|
if (result != s)
|
|
|
|
pfree(result); /* release first buffer */
|
|
|
|
result = buf;
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
1999-09-12 00:28:11 +02:00
|
|
|
return result;
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* convert a multi-byte string to a wchar */
|
2000-08-27 12:40:48 +02:00
|
|
|
int
|
1998-09-01 06:40:42 +02:00
|
|
|
pg_mb2wchar(const unsigned char *from, pg_wchar * to)
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
2000-08-27 12:40:48 +02:00
|
|
|
return (*pg_wchar_table[GetDatabaseEncoding()].mb2wchar_with_len) (from, to, strlen(from));
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* convert a multi-byte string to a wchar with a limited length */
|
2000-08-27 12:40:48 +02:00
|
|
|
int
|
1998-09-01 06:40:42 +02:00
|
|
|
pg_mb2wchar_with_len(const unsigned char *from, pg_wchar * to, int len)
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
2000-08-27 12:40:48 +02:00
|
|
|
return (*pg_wchar_table[GetDatabaseEncoding()].mb2wchar_with_len) (from, to, len);
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* returns the byte length of a multi-byte word */
|
1998-09-01 06:40:42 +02:00
|
|
|
int
|
|
|
|
pg_mblen(const unsigned char *mbstr)
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
return ((*pg_wchar_table[GetDatabaseEncoding()].mblen) (mbstr));
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* returns the length (counted as a wchar) of a multi-byte string */
|
1998-09-01 06:40:42 +02:00
|
|
|
int
|
|
|
|
pg_mbstrlen(const unsigned char *mbstr)
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
while (*mbstr)
|
|
|
|
{
|
|
|
|
mbstr += pg_mblen(mbstr);
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
return (len);
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
/* returns the length (counted as a wchar) of a multi-byte string
|
1998-07-24 05:32:46 +02:00
|
|
|
(not necessarily NULL terminated) */
|
1998-09-01 06:40:42 +02:00
|
|
|
int
|
|
|
|
pg_mbstrlen_with_len(const unsigned char *mbstr, int limit)
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
int len = 0;
|
|
|
|
int l;
|
|
|
|
|
2001-03-08 01:24:34 +01:00
|
|
|
while (limit > 0 && *mbstr)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
|
|
|
l = pg_mblen(mbstr);
|
|
|
|
limit -= l;
|
|
|
|
mbstr += l;
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
return (len);
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
1998-09-25 03:46:25 +02:00
|
|
|
/*
|
2001-07-15 13:07:37 +02:00
|
|
|
* returns the byte length of a multi-byte string
|
1998-09-25 03:46:25 +02:00
|
|
|
* (not necessarily NULL terminated)
|
2001-07-15 13:07:37 +02:00
|
|
|
* that is no longer than limit.
|
1998-09-25 03:46:25 +02:00
|
|
|
* this function does not break multi-byte word boundary.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pg_mbcliplen(const unsigned char *mbstr, int len, int limit)
|
|
|
|
{
|
|
|
|
int clen = 0;
|
|
|
|
int l;
|
|
|
|
|
2001-03-08 01:24:34 +01:00
|
|
|
while (len > 0 && *mbstr)
|
1998-09-25 03:46:25 +02:00
|
|
|
{
|
|
|
|
l = pg_mblen(mbstr);
|
1999-05-25 18:15:34 +02:00
|
|
|
if ((clen + l) > limit)
|
1998-09-25 03:46:25 +02:00
|
|
|
break;
|
|
|
|
clen += l;
|
1999-05-25 18:15:34 +02:00
|
|
|
if (clen == limit)
|
1998-09-25 03:46:25 +02:00
|
|
|
break;
|
|
|
|
len -= l;
|
|
|
|
mbstr += l;
|
|
|
|
}
|
|
|
|
return (clen);
|
|
|
|
}
|
|
|
|
|
1998-07-24 05:32:46 +02:00
|
|
|
/*
|
2001-07-15 13:07:37 +02:00
|
|
|
* Similar to pg_mbcliplen but the limit parameter specifies the
|
|
|
|
* character length, not the byte length. */
|
|
|
|
int
|
|
|
|
pg_mbcharcliplen(const unsigned char *mbstr, int len, int limit)
|
|
|
|
{
|
|
|
|
int clen = 0;
|
|
|
|
int nch = 0;
|
|
|
|
int l;
|
|
|
|
|
|
|
|
while (len > 0 && *mbstr)
|
|
|
|
{
|
|
|
|
l = pg_mblen(mbstr);
|
|
|
|
nch++;
|
|
|
|
if (nch > limit)
|
|
|
|
break;
|
|
|
|
clen += l;
|
|
|
|
len -= l;
|
|
|
|
mbstr += l;
|
|
|
|
}
|
|
|
|
return (clen);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* functions for utils/init */
|
1998-09-01 06:40:42 +02:00
|
|
|
static int DatabaseEncoding = MULTIBYTE;
|
2000-11-14 19:37:49 +01:00
|
|
|
|
1998-07-24 05:32:46 +02:00
|
|
|
void
|
|
|
|
SetDatabaseEncoding(int encoding)
|
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
DatabaseEncoding = encoding;
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
GetDatabaseEncoding()
|
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
return (DatabaseEncoding);
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* for builtin-function */
|
2000-06-13 09:35:40 +02:00
|
|
|
Datum
|
|
|
|
getdatabaseencoding(PG_FUNCTION_ARGS)
|
1998-07-24 05:32:46 +02:00
|
|
|
{
|
2001-04-16 04:42:01 +02:00
|
|
|
const char *encoding_name = pg_encoding_to_char(DatabaseEncoding);
|
|
|
|
|
|
|
|
return DirectFunctionCall1(namein, CStringGetDatum(encoding_name));
|
1998-07-24 05:32:46 +02:00
|
|
|
}
|