Imported Debian patch 0.63.0-6
[hcoop/debian/courier-authlib.git] / unicode / unicode.c
diff --git a/unicode/unicode.c b/unicode/unicode.c
new file mode 100644 (file)
index 0000000..1591355
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+** Copyright 2000-2003 Double Precision, Inc.
+** See COPYING for distribution information.
+**
+** $Id: unicode.c,v 1.9 2004/02/08 04:59:15 mrsam Exp $
+*/
+
+#include       "unicode_config.h"
+#include       "unicode.h"
+#include       <string.h>
+#include       <ctype.h>
+#include       <stdlib.h>
+#include       <errno.h>
+
+const char *unicode_default_chset()
+{
+const char *p=UNICODECHARSET;
+
+       if (unicode_find(p))
+               return (p);
+
+       return (unicode_ISO8859_1.chset);
+}
+
+const struct unicode_info *unicode_find(const char *chset)
+{
+char *p, *q;
+int    i;
+
+       if (!chset)     /* Default character set */
+               return (&unicode_ISO8859_1);
+
+       p=strdup(chset);
+       if (!p)
+               return (0);
+
+       for (q=p; *q; q++)
+               *q=toupper(*q);
+
+       if (strcmp(unicode_ISO8859_1.chset, p) == 0)
+       {
+               free(p);
+               return (&unicode_ISO8859_1);
+       }
+
+       for (i=0; unicode_chsetlist[i].chsetname; i++)
+               if (strcmp(unicode_chsetlist[i].chsetname, p) == 0)
+               {
+                       free(p);
+                       return (unicode_chsetlist[i].ptr);
+               }
+       free(p);
+       return (0);
+}
+
+char *unicode_convert(const char *txt, const struct unicode_info *from,
+                     const struct unicode_info *to)
+{
+       unicode_char *uc;
+       char *s;
+       int dummy;
+
+       if (strcmp(from->chset, to->chset) == 0)        /* NOOP */
+               return (strdup(txt));
+
+       uc=(*from->c2u)(from, txt, &dummy);
+       if (!uc)
+       {
+               if (dummy >= 0)
+                       errno=EINVAL;
+
+               return (0);
+       }
+
+       s=(*to->u2c)(to, uc, &dummy);
+
+       free(uc);
+
+       if (dummy >= 0)
+               errno=EINVAL;
+
+       return (s);
+}
+
+char *unicode_convert_fromchset(const char *txt, const char *from,
+                     const struct unicode_info *to)
+{
+       const struct unicode_info *fromu=unicode_find(from);
+
+       if (!fromu)
+       {
+               errno=EINVAL;
+               return (0);
+       }
+       return (unicode_convert(txt, fromu, to));
+}
+
+/*
+** Convert being character sets, except ignore errors.
+*/
+
+struct ux_buf {
+       char *buffer;
+       size_t bufsize;
+} ;
+
+static int ux_alloc(struct ux_buf *p, size_t l)
+{
+       char *newbuf;
+
+       if (l < p->bufsize)
+               return (0);
+
+       l += 64;
+
+       newbuf=p->buffer ? realloc(p->buffer, l):malloc(l);
+
+       if (!newbuf)
+               return (-1);
+
+       p->buffer=newbuf;
+       p->bufsize=l;
+       return (0);
+}
+
+char *unicode_xconvert(const char *txt, const struct unicode_info *from,
+                      const struct unicode_info *to)
+{
+       unicode_char *uc;
+       char *s, *cur_conv;
+       int dummy, dummy2;
+       struct ux_buf dst_str;
+
+       char *orig_str=strdup(txt);
+
+       if (!orig_str)
+               return (0);
+
+       if (strcmp(from->chset, to->chset) == 0)        /* NOOP */
+               return (orig_str);
+
+       dst_str.bufsize=0;
+       dst_str.buffer=0;
+
+       if (ux_alloc(&dst_str, strlen(txt)*2))
+       {
+               free(orig_str);
+               return (NULL);
+       }
+
+       dst_str.buffer[0]=0;
+
+       cur_conv=orig_str;
+
+       while (*cur_conv)
+       {
+               size_t l;
+               unicode_char *ucptr;
+
+               l=strlen(cur_conv);
+
+               if (from->flags & UNICODE_REPLACEABLE)
+               {
+                       uc=(*from->c2u)(from, cur_conv, NULL);
+                       if (!uc)
+                       {
+                               free(orig_str);
+                               free(dst_str.buffer);
+                               return NULL;
+                       }
+               }
+               else
+                       uc=(*from->c2u)(from, cur_conv, &dummy);
+
+               if (!uc)
+               {
+                       char save_char;
+
+                       if (dummy < 0)
+                       {
+                               free(orig_str);
+                               free(dst_str.buffer);
+                               return (NULL);
+                       }
+
+                       /* Error converting original text to unicode.
+                       ** Back up, and convert all the characters up until
+                       ** the error character.
+                       */
+
+                       l=dummy;
+
+                       save_char=cur_conv[dummy];
+
+                       cur_conv[dummy]=0;
+
+                       uc=(*from->c2u)(from, cur_conv, &dummy2);
+                       cur_conv[dummy]=save_char;
+
+                       if (!uc)
+                       {
+                               free(orig_str);
+                               free(dst_str.buffer);
+                               return (NULL);
+                       }
+               }
+
+               /* Ok, now convert unicode to dest charset, using the same
+               ** trial-and-error process.
+               */
+
+               ucptr=uc;
+
+               while (*ucptr)
+               {
+                       size_t cnt_done;
+
+                       for (cnt_done=0; ucptr[cnt_done]; cnt_done++)
+                               ;
+
+                       if (to->flags & UNICODE_REPLACEABLE)
+                       {
+                               s=(*to->u2c)(to, ucptr, NULL);
+                               if (!s)
+                               {
+                                       free(orig_str);
+                                       free(dst_str.buffer);
+                                       free(uc);
+                                       return NULL;
+                               }
+                       }
+                       else
+                               s=(*to->u2c)(to, ucptr, &dummy);
+
+                       if (!s)
+                       {
+                               unicode_char save_char;
+
+                               if (dummy < 0)
+                               {
+                                       free(orig_str);
+                                       free(dst_str.buffer);
+                                       free(uc);
+                                       return (NULL);
+                               }
+
+                               cnt_done=dummy;
+
+                               save_char=ucptr[dummy];
+                               ucptr[dummy]=0;
+                               s=(*to->u2c)(to, ucptr, &dummy2);
+                               ucptr[dummy]=save_char;
+
+                               if (!s)
+                               {
+                                       free(orig_str);
+                                       free(dst_str.buffer);
+                                       free(uc);
+                                       return (NULL);
+                               }
+                       }
+
+                       if (ux_alloc(&dst_str,
+                                    strlen(dst_str.buffer)+strlen(s)+2))
+                       {
+                               free(s);
+                               free(orig_str);
+                               free(dst_str.buffer);
+                               free(uc);
+                               return (NULL);
+                       }
+
+                       strcat(dst_str.buffer, s);
+                       free(s);
+                       ucptr += cnt_done;
+                       if (*ucptr)
+                       {
+                               strcat(dst_str.buffer, ".");
+                               ++ucptr;
+                       }
+               }
+
+               cur_conv += l;
+
+               if (*cur_conv)
+               {
+                       char buf[2];
+
+                       if (ux_alloc(&dst_str, strlen(dst_str.buffer)+1))
+                       {
+                               free(orig_str);
+                               free(dst_str.buffer);
+                               free(uc);
+                               return (NULL);
+                       }
+
+                       buf[0]= *cur_conv++;
+                       buf[1]=0;
+                       strcat(dst_str.buffer, buf);
+               }
+               free(uc);
+       }
+
+       free(orig_str);
+       return (dst_str.buffer);
+}