summaryrefslogtreecommitdiffstats
path: root/os2/iconv/iconv.c
diff options
context:
space:
mode:
Diffstat (limited to 'os2/iconv/iconv.c')
-rw-r--r--os2/iconv/iconv.c83
1 files changed, 62 insertions, 21 deletions
diff --git a/os2/iconv/iconv.c b/os2/iconv/iconv.c
index b098a96..f26ab45 100644
--- a/os2/iconv/iconv.c
+++ b/os2/iconv/iconv.c
@@ -1,5 +1,5 @@
/* OS/2 iconv() implementation through OS/2 Unicode API
- Copyright (C) 2001 Free Software Foundation, Inc.
+ Copyright (C) 2001-2002 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published
@@ -24,14 +24,15 @@
typedef struct _iconv_t
{
- UconvObject from;
- UconvObject to;
+ UconvObject from; /* "From" conversion handle */
+ UconvObject to; /* "To" conversion handle */
} *iconv_t;
/* Tell "iconv.h" to not define iconv_t by itself. */
#define _ICONV_T
#include "iconv.h"
+#include <errno.h>
#include <alloca.h>
/* Convert an encoding name to te form understood by UniCreateUconvObject. */
@@ -40,19 +41,30 @@ cp_convert (const char *cp, UniChar *ucp)
{
size_t sl = 0;
- /* Transform CPXXX naming style to IBM-XXX style */
- if ((cp[0] == 'C' || cp[0] == 'c') && (cp[1] == 'P' || cp[1] == 'p'))
+ if (!strcasecmp (cp, "EUC-JP"))
+ memcpy (ucp, L"IBM-954", 8*2);
+ else if (!strcasecmp (cp, "EUC-KR"))
+ memcpy (ucp, L"IBM-970", 8*2);
+ else if (!strcasecmp (cp, "EUC-TW"))
+ memcpy (ucp, L"IBM-964", 8*2);
+ else if (!strcasecmp (cp, "EUC-CN"))
+ memcpy (ucp, L"IBM-1383", 9*2);
+ else
{
- ucp[sl++] = 'I';
- ucp[sl++] = 'B';
- ucp[sl++] = 'M';
- ucp[sl++] = '-';
- cp += 2;
- }
+ /* Transform CPXXX naming style to IBM-XXX style */
+ if ((cp[0] == 'C' || cp[0] == 'c') && (cp[1] == 'P' || cp[1] == 'p'))
+ {
+ ucp[sl++] = 'I';
+ ucp[sl++] = 'B';
+ ucp[sl++] = 'M';
+ ucp[sl++] = '-';
+ cp += 2;
+ }
- while (*cp != '\0')
- ucp[sl++] = *cp++;
- ucp[sl] = 0;
+ while (*cp != '\0')
+ ucp[sl++] = *cp++;
+ ucp[sl] = 0;
+ }
}
iconv_t
@@ -60,6 +72,7 @@ iconv_open (const char *cp_to, const char *cp_from)
{
UniChar *ucp;
iconv_t conv;
+ uconv_attribute_t attr;
conv = (iconv_t) malloc (sizeof (struct _iconv_t));
if (conv == NULL)
@@ -87,6 +100,16 @@ iconv_open (const char *cp_to, const char *cp_from)
return (iconv_t)(-1);
}
+ UniQueryUconvObject (conv->from, &attr, sizeof (attr), NULL, NULL, NULL);
+ /* Do not treat 0x7f as a control character
+ (don't understand what it exactly means but without it MBCS prefix
+ character detection sometimes could fail (when 0x7f is a prefix)).
+ And don't treat the string as a path (the docs also don't explain
+ what it exactly means, but I'm pretty sure converted texts will
+ mostly not be paths). */
+ attr.converttype &= ~(CVTTYPE_CTRL7F | CVTTYPE_PATH);
+ UniSetUconvObject (conv->from, &attr);
+
return conv;
}
@@ -95,23 +118,24 @@ iconv (iconv_t conv,
const char **in, size_t *in_left,
char **out, size_t *out_left)
{
- size_t bytes_converted = 0;
int rc;
size_t sl = *in_left, nonid;
UniChar *ucs = (UniChar *) alloca (sl * sizeof (UniChar));
UniChar *orig_ucs = ucs;
+ size_t retval = 0;
- rc = UniUconvToUcs (conv->from, (void **)in, in_left, &ucs, &sl, &nonid);
+ rc = UniUconvToUcs (conv->from, (void **)in, in_left, &ucs, &sl, &retval);
if (rc)
goto error;
sl = ucs - orig_ucs;
ucs = orig_ucs;
- /* Uh-oh, seems like a bug in UniUconvFromUcs, at least when
- translating from KOI8-R to KOI8-R (null translation) */
-#if 0
+ /* UniUconvFromUcs will stop at first NULL byte
+ while we want ALL the bytes converted. */
+#if 1
rc = UniUconvFromUcs (conv->to, &ucs, &sl, (void **)out, out_left, &nonid);
if (rc)
goto error;
+ retval += nonid;
#else
while (sl)
{
@@ -121,6 +145,7 @@ iconv (iconv_t conv,
rc = UniUconvFromUcs (conv->to, &ucs, &usl, (void **)out, out_left, &nonid);
if (rc)
goto error;
+ retval += nonid;
if (sl && *out_left)
{
*(*out)++ = 0;
@@ -130,8 +155,24 @@ iconv (iconv_t conv,
}
#endif
return 0;
- error:
- errno = EILSEQ;
+
+error:
+ /* Convert OS/2 error code to errno. */
+ switch (rc)
+ {
+ case ULS_ILLEGALSEQUENCE:
+ errno = EILSEQ;
+ break;
+ case ULS_INVALID:
+ errno = EINVAL;
+ break;
+ case ULS_BUFFERFULL:
+ errno = E2BIG;
+ break;
+ default:
+ errno = EBADF;
+ break;
+ }
return (size_t)(-1);
}