Merge branch 'debian'
[hcoop/debian/courier-authlib.git] / libs / unicode / unicode.h
diff --git a/libs/unicode/unicode.h b/libs/unicode/unicode.h
new file mode 100644 (file)
index 0000000..4e018b7
--- /dev/null
@@ -0,0 +1,1692 @@
+#ifndef        unicode_h
+#define        unicode_h
+
+/*
+** Copyright 2000-2011 Double Precision, Inc.
+** See COPYING for distribution information.
+**
+*/
+
+#ifdef __cplusplus
+
+#include <string>
+#include <vector>
+#include <list>
+
+extern "C" {
+#endif
+
+#if 0
+}
+#endif
+
+#include       "unicode/unicode_config.h"
+
+#include       <stdlib.h>
+
+#include       <stdio.h>
+#if HAVE_WCHAR_H
+#include       <wchar.h>
+#endif
+
+#if HAVE_STDDEF_H
+#include       <stddef.h>
+#endif
+#include       <stdint.h>
+
+#include       <sys/types.h>
+
+typedef uint32_t unicode_char;
+
+/*
+** The system default character set, from the locale.
+*/
+
+extern const char *unicode_default_chset();
+
+/* Unicode upper/lower/title case conversion functions */
+
+extern unicode_char unicode_uc(unicode_char);
+extern unicode_char unicode_lc(unicode_char);
+extern unicode_char unicode_tc(unicode_char);
+
+/*
+** Look up HTML 4.0/XHTML entity.
+**
+** n="amp", etc...
+**
+** Returns the unicode entity value, or 0 if no such entity is defined.
+*/
+
+unicode_char unicode_html40ent_lookup(const char *n);
+
+/*
+**
+** Return "width" of unicode character.
+**
+** This is defined as follows: for characters having the F or W property in
+** tr11 (EastAsianWidth), unicode_wcwidth() returns 2.
+**
+** Otherwise, characters having the BK, CR, LF, CM, NL, WJ, and ZW line
+** breaking property as per tr14, unicode_wcwdith() returns 0. For all other
+** cases, 1.
+**
+** This provides a rough estimate of the "width" of the character if its
+** shown on a text console.
+*/
+
+extern int unicode_wcwidth(unicode_char c);
+extern size_t unicode_wcwidth_str(const unicode_char *c);
+
+/*
+** The unicode-ish isspace()
+*/
+extern int unicode_isspace(unicode_char ch);
+
+/* Internal unicode table lookup function */
+
+extern uint8_t unicode_tab_lookup(unicode_char ch,
+                                 const size_t *unicode_indextab,
+                                 size_t unicode_indextab_sizeof,
+                                 const uint8_t (*unicode_rangetab)[2],
+                                 const uint8_t *unicode_classtab,
+                                 uint8_t uclass);
+
+/*
+** Implementation of grapheme cluster boundary rules, as per tr29,
+** including  GB9a and GB9b.
+**
+** Returns non-zero if there's a grapheme break between the two referenced
+** characters.
+*/
+
+int unicode_grapheme_break(unicode_char a, unicode_char b);
+
+/*
+** Implementation of line break rules, as per tr14.
+**
+** Invoke unicode_lb_init() to initialize the linebreaking algorithm. The
+** first parameter is a callback function that gets invoked with two
+** arguments: UNICODE_LB_{MANDATORY|NONE|ALLOWED}, and a passthrough argument.
+** The second parameter to unicode_lb_init() is the opaque passthrough
+** pointer, that is passed as the second argument to the callback function
+** with no further interpretation.
+**
+** unicode_lb_init() returns an opaque handle. Invoke unicode_lb_next(),
+** passing the handle and one unicode character. Repeatedly invoke
+** unicode_lb_next() to specify the input string for the linebreaking
+** algorithm, then invoke unicode_lb_end() to finish calculating the
+** linebreaking algorithm, and deallocate the opaque linebreaking handle.
+**
+** The callback function gets invoked once for each invocation of
+** unicode_lb_next(). The contract is that before unicode_lb_end() returns,
+** the callback function will get invoked the exact number of times that
+** unicode_lb_next(), as long as each invocation of the callback function
+** returned 0; nothing more, nothing less. The first parameter to the callback
+** function will be one of the following values:
+**
+** UNICODE_LB_MANDATORY - a linebreak is MANDATORY before the corresponding
+** character.
+** UNICODE_LB_NONE - a linebreak is PROHIBITED before the corresponding
+** character.
+** UNICODE_LB_ALLOWED - a linebreak is OPTIONAL before the corresponding
+** character (the preceding character is a space, or an equivalent).
+**
+** The callback function should return 0. A non-zero value indicates an
+** error, which gets propagated up to the caller. The contract that the
+** callback function gets invoked the same number of times that
+** unicode_lb_next() gets invoked is now broken.
+*/
+
+#define UNICODE_LB_MANDATORY   -1
+#define UNICODE_LB_NONE                0
+#define UNICODE_LB_ALLOWED     1
+
+struct unicode_lb_info;
+
+typedef struct unicode_lb_info *unicode_lb_info_t;
+
+/*
+** Allocate a linebreaking handle.
+*/
+extern unicode_lb_info_t unicode_lb_init(int (*cb_func)(int, void *),
+                                        void *cb_arg);
+
+/*
+** Feed the next character through the linebreaking algorithm.
+** A non-zero return code indicates that the callback function was invoked
+** and it returned a non-zero return code (which is propagated as a return
+** value). unicode_lb_end() must still be invoked, in this case.
+**
+** A zero return code indicates that if the callback function was invoked,
+** it returned 0.
+*/
+
+extern int unicode_lb_next(unicode_lb_info_t i, unicode_char ch);
+
+/*
+** Convenience function that invokes unicode_lb_next() with a list of
+** unicode chars. Returns 0 if all invocations of unicode_lb_next() returned
+** 0, or the first non-zero return value from unicode_lb_next().
+*/
+
+extern int unicode_lb_next_cnt(unicode_lb_info_t i,
+                              const unicode_char *chars,
+                              size_t cnt);
+
+/*
+** Finish the linebreaking algorithm.
+**
+** A non-zero return code indicates that the callback function was invoked
+** and it returned a non-zero return code (which is propagated as a return
+** value).
+**
+** A zero return code indicates that if the callback function was invoked,
+** it returned 0, and that the callback function was invoked exactly the same
+** number of times that unicode_lb_next() was invoked.
+**
+** In all case, the linebreak handle will no longer be valid when this
+** function returns.
+*/
+
+extern int unicode_lb_end(unicode_lb_info_t i);
+
+/*
+** An alternative linebreak API where the callback function receives the
+** original unicode character in addition to its linebreak value.
+**
+** User unicode_lbc_init(), unicode_lbc_next(), and unicode_lbc_end(), whose
+** semantics are the same as their _lb_ counterparts.
+*/
+
+struct unicode_lbc_info;
+
+typedef struct unicode_lbc_info *unicode_lbc_info_t;
+
+extern unicode_lbc_info_t unicode_lbc_init(int (*cb_func)(int, unicode_char,
+                                                         void *),
+                                          void *cb_arg);
+extern int unicode_lbc_next(unicode_lbc_info_t i, unicode_char ch);
+extern int unicode_lbc_end(unicode_lbc_info_t i);
+
+/*
+** Set linebreaking options.
+**
+** OPTIONS SUBJECT TO CHANGE.
+*/
+
+extern void unicode_lb_set_opts(unicode_lb_info_t i, int opts);
+
+extern void unicode_lbc_set_opts(unicode_lbc_info_t i, int opts);
+
+/*
+** Tailorization of LB24: Prevent pluses, as in "C++", from breaking.
+**
+** Adds the following to LB24:
+**
+**            PR x PR
+**
+**            AL x PR
+**
+**            ID x PR
+**/
+#define UNICODE_LB_OPT_PRBREAK 0x0001
+
+
+/*
+** Tailored / breaking rules.
+**
+** Adds the following rule to LB13:
+**
+**            SY x EX
+**
+**            SY x AL
+**
+**            SY x ID
+**
+**            SP รท SY, which takes precedence over "x SY".
+*/
+#define UNICODE_LB_OPT_SYBREAK 0x0002
+
+/*
+** Tailored / breaking rules.
+**
+** This reclassifies U+2013 and U+2014 as class WJ, prohibiting breaks before
+** and after mdash and ndash.
+*/
+#define UNICODE_LB_OPT_DASHWJ 0x0004
+
+/*
+** Implemention of word break rules, as per tr29.
+**
+** Invoke unicode_wb_init() to initialize the wordbreaking algorithm. The
+** first parameter is a callback function that gets invoked with two
+** arguments: an int flag, and a passthrough argument. The second parameter to
+** unicode_wb_init() is the opaque passthrough pointer, that is passed as the
+** second argument to the callback function with no further interpretation.
+**
+** unicode_wb_init() returns an opaque handle. Invoke unicode_wb_next(),
+** passing the handle and one unicode character. Repeatedly invoke
+** unicode_wb_next() to specify the input string for the wordbreaking
+** algorithm, then invoke unicode_wb_end() to finish calculating the
+** wordbreaking algorithm, and deallocate the opaque wordbreaking handle.
+**
+** The callback function gets invoked once for each invocation of
+** unicode_wb_next(). The contract is that before unicode_wb_end() returns,
+** the callback function will get invoked the exact number of times that
+** unicode_wb_next(), as long as each invocation of the callback function
+** returned 0; nothing more, nothing less. The first parameter to the callback
+** function will be an int. A non-zero value indicates that there is a word
+** break between this character and the preceding one.
+**
+** The callback function should return 0. A non-zero value indicates an
+** error, which gets propagated up to the caller. The contract that the
+** callback function gets invoked the same number of times that
+** unicode_lb_next() gets invoked is now broken.
+*/
+
+struct unicode_wb_info;
+
+typedef struct unicode_wb_info *unicode_wb_info_t;
+
+/*
+** Allocate a wordbreaking handle.
+*/
+extern unicode_wb_info_t unicode_wb_init(int (*cb_func)(int, void *),
+                                        void *cb_arg);
+
+/*
+** Feed the next character through the wordbreaking algorithm.
+** A non-zero return code indicates that the callback function was invoked
+** and it returned a non-zero return code (which is propagated as a return
+** value). unicode_wb_end() must still be invoked, in this case.
+**
+** A zero return code indicates that if the callback function was invoked,
+** it returned 0.
+*/
+
+extern int unicode_wb_next(unicode_wb_info_t i, unicode_char ch);
+
+/*
+** Convenience function that invokes unicode_wb_next() with a list of
+** unicode chars. Returns 0 if all invocations of unicode_wb_next() returned
+** 0, or the first non-zero return value from unicode_wb_next().
+*/
+
+extern int unicode_wb_next_cnt(unicode_wb_info_t i,
+                              const unicode_char *chars,
+                              size_t cnt);
+
+/*
+** Finish the wordbreaking algorithm.
+**
+** A non-zero return code indicates that the callback function was invoked
+** and it returned a non-zero return code (which is propagated as a return
+** value).
+**
+** A zero return code indicates that if the callback function was invoked,
+** it returned 0, and that the callback function was invoked exactly the same
+** number of times that unicode_wb_next() was invoked.
+**
+** In all case, the wordbreak handle will no longer be valid when this
+** function returns.
+*/
+
+extern int unicode_wb_end(unicode_wb_info_t i);
+
+/*
+** Search for a word boundary.
+**
+** Obtain a handle by calling unicode_wbscan_init(), then invoke
+** unicode_wbscan_next() to provide a unicode stream, then invoke
+** unicode_wbscan_end(). unicode_wbscan_end() returns the number of unicode
+** characters from the beginning of the stream until the first word boundary.
+**
+** You may prematurely stop calling unicode_wbscan_next() once it returns a
+** non-0 value, which means that there is sufficient context to compute the
+** first word boundary, and all further calls to unicode_wbscan_next() will
+** be internal no-ops.
+*/
+
+struct unicode_wbscan_info;
+
+typedef struct unicode_wbscan_info *unicode_wbscan_info_t;
+
+unicode_wbscan_info_t unicode_wbscan_init();
+
+int unicode_wbscan_next(unicode_wbscan_info_t i, unicode_char ch);
+
+size_t unicode_wbscan_end(unicode_wbscan_info_t i);
+
+/*
+** A buffer that holds unicode characters, and dynamically grows as needed.
+*/
+
+struct unicode_buf {
+       unicode_char *ptr;      /* The unicode characters */
+       size_t size,            /* Buffer size */
+               len,            /* How many characters in ptr are initialized */
+               max;            /* Maximum size the buffer can grow to */
+};
+
+/*
+** Initialize a buffer. Constructor.
+*/
+
+void unicode_buf_init(/* Initialize this structure. ptr, size, len cleared */
+                     struct unicode_buf *p,
+
+                     /*
+                     ** Maximum size the buffer can grow to. (size_t)-1
+                     ** means unlimited.
+                     */
+                     size_t max);
+/*
+** Like unicode_buf_init, and initialize the new buffer with the contents of
+** another buffer. The maximum size of the initialized buffer is exactly the
+** number of characters in the existing buffer. This copies a buffer using
+** the minimum amount of heap space.
+*/
+
+#define unicode_buf_init_copy(a,b)                             \
+       do {                                                    \
+               unicode_buf_init((a), unicode_buf_len(b));      \
+               unicode_buf_append_buf((a),(b));                \
+       } while (0)
+
+/*
+** Deinitialize the buffer. Destructor. Frees memory.
+*/
+
+void unicode_buf_deinit(struct unicode_buf *p);
+
+/*
+** Official way to access the characters in the unicode buffer.
+*/
+#define unicode_buf_ptr(p) ((p)->ptr)
+
+/*
+** Official way of obtaining the number of characters in the unicode buffer.
+*/
+#define unicode_buf_len(p) ((p)->len)
+
+/*
+** Remove all existing characters from an initialized buffer. Sets len to 0.
+*/
+
+#define unicode_buf_clear(p) ((p)->len=0)
+
+/*
+** Append characters to the existing characters in the unicode buffer.
+** The buffer grows, if needed. If the buffer would exceed its maximum size,
+** the extra characters get truncated.
+**
+** Returns 0 if the characters were appended. -1 for a malloc failure.
+*/
+
+int unicode_buf_append(struct unicode_buf *p,  /* The buffer */
+                      const unicode_char *uc,  /* Characters to append */
+                      size_t l);               /* How many of them */
+
+/*
+** Convert an iso-8859-1 char string and invoke unicode_buf_append().
+*/
+
+void unicode_buf_append_char(struct unicode_buf *dst,
+                            const char *str,
+                            size_t cnt);
+
+/*
+** Remove some portion of the unicode buffer
+*/
+
+void unicode_buf_remove(struct unicode_buf *p, /* The buffer */
+                       size_t pos, /* Offset in buffer */
+                       size_t cnt); /* How many to remove */
+
+/*
+** Append the contents of an existing buffer to another one.
+*/
+
+#define unicode_buf_append_buf(a,b)                                    \
+       unicode_buf_append((a), unicode_buf_ptr(b), unicode_buf_len(b))
+
+
+/*
+** The equivalent of strcmp() for unicode buffers.
+*/
+
+int unicode_buf_cmp(const struct unicode_buf *a,
+                   const struct unicode_buf *b);
+
+/*
+** The equivalent of unicode_buf_cmp, except that the second buffer is an
+** iso-8859-1 string.
+*/
+
+int unicode_buf_cmp_str(const struct unicode_buf *p,
+                       const char *c,  /* iso-8859-1 string */
+                       size_t cl);     /* Number of chars in c */
+
+/*
+** A wrapper for iconv(3). This wrapper provides a different API for iconv(3).
+** A handle gets created by libmail_u_convert_init().
+** libmail_u_convert_init() receives a pointer to the output function
+** which receives converted character text.
+**
+** The output function receives a pointer to the converted character text, and
+** the number of characters in the converted text.
+**
+** The character text to convert gets passed, repeatedly, to
+** libmail_u_convert(). Each call to libmail_u_convert() results in
+** the output function being invoked, zero or more times, with the converted
+** text. Finally, libmail_u_convert_deinit() stops the conversion and
+** deallocates the conversion handle.
+**
+** Internal buffering takes place. libmail_u_convert_deinit() may result
+** in the output function being called one or more times, to receive the final
+** part of the converted character stream.
+**
+** The output function should return 0. A non-0 value causes
+** libmail_u_convert() and/or libmail_u_convert_deinit() returning
+** non-0.
+*/
+
+struct libmail_u_convert_hdr;
+
+typedef struct libmail_u_convert_hdr *libmail_u_convert_handle_t;
+
+/*
+** libmail_u_convert_init() returns a non-NULL handle for the requested
+** conversion, or NULL if the requested conversion is not available.
+*/
+
+libmail_u_convert_handle_t
+libmail_u_convert_init(/* Convert from this chset */
+                      const char *src_chset,
+
+                      /* Convert to this chset */
+                      const char *dst_chset,
+
+                      /* The output function */
+
+                      int (*output_func)(const char *, size_t, void *),
+
+                      /* Passthrough arg */
+                      void *convert_arg);
+
+/*
+** Repeatedly pass the character text to convert to libmail_u_convert().
+**
+** Returns non-0 if the output function returned non-0, or 0 if all invocations
+** of the output function returned 0.
+*/
+
+int libmail_u_convert(/* The conversion handle */
+                     libmail_u_convert_handle_t handle,
+
+                     /* Text to convert */
+                     const char *text,
+
+                     /* Number of bytes to convert */
+                     size_t cnt);
+
+/*
+** Finish character set conversion. The handle gets deallocated.
+**
+** May still result in one or more invocations of the output function.
+** Returns non-zero if any previous invocation of the output function returned
+** non-zero (this includes any invocations of the output function resulting
+** from this call, or prior libmail_u_convert() calls), or 0 if all
+** invocations of the output function returned 0.
+**
+** If the errptr is not NULL, *errptr is set to non-zero if there were any
+** conversion errors -- if there was any text that could not be converted to
+** the destination character text.
+*/
+
+int libmail_u_convert_deinit(libmail_u_convert_handle_t handle,
+                            int *errptr);
+
+
+/*
+** Specialization: save converted character text in a buffer.
+**
+** Implementation: call libmail_u_convert_tocbuf_init() instead of
+** libmail_u_convert_init(), then call libmail_u_convert() and
+** libmail_u_convert_deinit(), as usual.
+**
+** If libmail_u_convert_deinit() returns 0, *cbufptr_ret gets initialized to a
+** malloc()ed buffer, and the number of converted characters, the size of the
+** malloc()ed buffer, are placed into *csize_ret arguments, that were passed
+** to libmail_u_convert_tou_init().
+**
+** Note: if the converted string is an empty string, *cbufsize_ret is set to 0,
+** but *cbufptr_ptr still gets initialized (to a dummy malloced buffer).
+**
+** The optional nullterminate places a trailing \0 character after the
+** converted string (this is included in *cbufsize_ret).
+*/
+
+libmail_u_convert_handle_t
+libmail_u_convert_tocbuf_init(/* Convert from this chset */
+                             const char *src_chset,
+
+                             /* Convert to this chset */
+                             const char *dst_chset,
+
+                             /* malloced buffer */
+                             char **cbufptr_ret,
+
+                             /* size of the malloced buffer */
+                             size_t *cbufsize_ret,
+
+                             /* null terminate the resulting string */
+                             int nullterminate
+                             );
+
+
+/*
+** Specialization: convert some character text to a unicode_char array.
+**
+** This is like libmail_u_convert_tocbuf_init(), but converts to a unicode_char
+** array.
+**
+** The returned *ucsize_ret is initialized with the number of unicode_chars,
+** rather than the byte count.
+**
+** In all other ways, this function behaves identically to
+** libmail_u_convert_tocbuf_init().
+*/
+
+libmail_u_convert_handle_t
+libmail_u_convert_tou_init(/* Convert from this chset */
+                          const char *src_chset,
+
+                          /* malloc()ed buffer pointer, on exit. */
+                          unicode_char **ucptr_ret,
+
+                          /* size of the malloc()ed buffer, upon exit */
+                          size_t *ucsize_ret,
+
+                          /* If true, terminate with U+0x0000, for convenience */
+                          int nullterminate
+                          );
+
+/*
+** Specialization: convert a unicode_char array to some character text.
+**
+** This is the opposite of libmail_u_convert_tou_init(). Call this to
+** initialize the conversion handle, then use libmail_u_convert_uc()
+** instead of libmail_u_convert.
+*/
+
+libmail_u_convert_handle_t
+libmail_u_convert_fromu_init(/* Convert to this chset */
+                            const char *dst_chset,
+
+                            /* malloc()ed buffer pointer, on exit. */
+                            char **cbufptr_ret,
+
+                            /* size of the malloc()ed buffer, upon exit */
+                            size_t *cbufsize_ret,
+
+                            /* If true, terminate with U+0x0000, for convenience */
+                            int nullterminate
+                            );
+
+int libmail_u_convert_uc(/* The conversion handle */
+                        libmail_u_convert_handle_t handle,
+
+                        /* Text to convert */
+                        const unicode_char *text,
+
+                        /* Number of bytes to convert */
+                        size_t cnt);
+
+/*
+** Initialize conversion to UTF-8.
+**
+** This is a wrapper for libmail_u_convert_tocbuf_init() that specifies the
+** destination charset as UTF-8.
+*/
+
+libmail_u_convert_handle_t
+libmail_u_convert_tocbuf_toutf8_init(const char *src_chset,
+                                    char **cbufptr_ret,
+                                    size_t *cbufsize_ret,
+                                    int nullterminate);
+
+/*
+** Initialize conversion from UTF-8.
+**
+** This is a wrapper for libmail_u_convert_tocbuf_init() that specifies the
+** source charset as UTF-8.
+*/
+
+libmail_u_convert_handle_t
+libmail_u_convert_tocbuf_fromutf8_init(const char *dst_chset,
+                                      char **cbufptr_ret,
+                                      size_t *cbufsize_ret,
+                                      int nullterminate);
+
+/*
+** Convert a character string to UTF-8.
+**
+** Returns a malloc-ed buffer holding the UTF-8 string, or NULL if an
+** error occured.
+*/
+char *libmail_u_convert_toutf8(/* Text to convert to UTF-8 */
+                              const char *text,
+
+                              /* Character set to convert to UTF-8 */
+                              const char *charset,
+
+                              /*
+                              ** If non-NULL, and a non-NULL pointer is
+                              ** returned, *error is set to non-zero if
+                              ** a character conversion error has occured.
+                              */
+                              int *error);
+
+/*
+** Convert UTF-8 text to another character set.
+**
+** Returns a malloc-ed buffer holding the string converted to the specified
+** character set, or NULL if an error occured.
+*/
+
+char *libmail_u_convert_fromutf8(/* A UTF-8 string */
+                                const char *text,
+
+                                /*
+                                ** Convert the UTF-8 string to this character
+                                ** set.
+                                */
+
+                                const char *charset,
+
+                                /*
+                                ** If non-NULL, and a non-NULL pointer is
+                                ** returned, *error is set to non-zero if
+                                ** a character conversion error has occured.
+                                */
+                                int *error);
+
+/*
+** Convert one charset to another charset, placing the result in a malloc-ed
+** buffer.
+**
+** Returns a malloc-ed buffer holding the string converted to the specified
+** character set, or NULL if an error occured.
+*/
+
+char *libmail_u_convert_tobuf(/* A string to convert */
+                             const char *text,
+
+                             /*
+                             ** String's charset.
+                             */
+
+                             const char *charset,
+
+                             /*
+                             ** Destination charset
+                             */
+                             const char *dstcharset,
+
+                             /*
+                             ** If non-NULL, and a non-NULL pointer is
+                             ** returned, *error is set to non-zero if
+                             ** a character conversion error has occured.
+                             */
+                             int *error);
+
+/*
+** Convenience function: call libmail_u_convert_tou_init(), feed the
+** character string through libmail_u_convert(), then call
+** libmail_u_convert_deinit().
+**
+** If this function returns 0, *uc and *ucsize is set to a malloced buffer+size
+** holding the unicode char array.
+*/
+
+int libmail_u_convert_tou_tobuf(/* Character text to convert */
+                               const char *text,
+
+                               /* Number of characters */
+                               size_t text_l,
+
+                               /* text's charset */
+                               const char *charset,
+
+                               /*
+                               ** If this function returns 0, this gets
+                               ** initialized
+                               */
+                               unicode_char **uc,
+
+                               /*
+                               ** Size of the allocated buffer
+                               */
+                               size_t *ucsize,
+
+                               /*
+                               ** If not null and this function returns 0,
+                               ** this is set to non-0 if there
+                               ** was a conversion error (but the output
+                               ** buffer gets still allocated and
+                               ** initialized)
+                               */
+                               int *err);
+
+/*
+** Convenience function: call libmail_u_convert_fromu_init(), feed the
+** unicode_array through libmail_u_convert_uc(), then call
+** libmail_u_convert_deinit().
+**
+** If this function returns 0, *uc and *ucsize is set to a malloced buffer+size
+** holding the converted character string
+*/
+
+int libmail_u_convert_fromu_tobuf(/* Unicode array to convert to a char str */
+                                 const unicode_char *utext,
+
+                                 /*
+                                 ** Size of the unicode array.
+                                 ** If this is (size_t)-1, utext is a
+                                 ** 0-terminated array.
+                                 */
+                                 size_t utext_l,
+
+                                 /*
+                                 ** Convert the unicode array to this charset.
+                                 */
+                                 const char *charset,
+
+                                 /*
+                                 ** If libmail_u_convert_fromu_tobuf()
+                                 ** returns 0, this is initialized to a
+                                 ** malloced buffer with a 0-terminated
+                                 ** string is kept.
+                                 */
+                                 char **c,
+
+                                 /*
+                                 ** Size of the initialized array, including
+                                 ** the 0-terminator.
+                                 */
+                                 size_t *csize,
+
+                                 /*
+                                 ** If libmail_u_convert_fromu_tobuf()
+                                 ** returns 0 and this is not NULL,
+                                 ** *err is set to non-0 if there was a
+                                 ** conversion error to the requested
+                                 ** character set.
+                                 */
+                                 int *err);
+
+/*
+** Convenience function: convert a string in a given character set
+** to/from uppercase, lowercase, or something else.
+**
+** This is done by calling libmail_u_convert_tou_tobuf() first,
+** applying the title_func and char_func, then using
+** libmail_u_convert_fromu_tobuf().
+**
+** A NULL return indicates that the requested conversion cannot be performed.
+*/
+
+char *libmail_u_convert_tocase( /* String to convert */
+                              const char *str,
+
+                              /* String's character set */
+
+                              const char *charset,
+
+                              /*
+                              ** Conversion of the first character in
+                              ** str: unicode_uc, unicode_lc, or unicode_tc:
+                              */
+
+                              unicode_char (*first_char_func)(unicode_char),
+
+                              /*
+                              ** Conversion of the second and the remaining
+                              ** character in str. If NULL, same as
+                              ** first_char_func.
+                              */
+                              unicode_char (*char_func)(unicode_char));
+
+
+
+/* Either UCS-4BE or UCS-4LE, matching the native unicode_char endianness */
+
+extern const char libmail_u_ucs4_native[];
+
+/* Either UCS-2BE or UCS-2LE, matching the native unicode_char endianness */
+
+extern const char libmail_u_ucs2_native[];
+
+/*
+** Modified-UTF7 encoding used for IMAP folder names. Pass it for a charset
+** parameter.
+**
+** This can be followed by a " " and up to 15 characters to be escaped in
+** addition to unicode chars.
+*/
+
+#define unicode_x_imap_modutf7 "x-imap-modutf7"
+
+#if 0
+{
+#endif
+
+#ifdef __cplusplus
+}
+
+extern size_t unicode_wcwidth(const std::vector<unicode_char> &uc);
+
+namespace mail {
+
+       /*
+       ** Interface to iconv.
+       **
+       ** Subclass converted(). Invoke begin(), then operator(), repeatedly,
+       ** then end().
+       **
+       ** converted() receives the converted text.
+       */
+
+       class iconvert {
+
+               libmail_u_convert_handle_t handle;
+
+       public:
+               iconvert();
+               virtual ~iconvert();
+
+               /* Start conversion.
+               ** Returns false if the requested conversion cannot be done.
+               **/
+
+               bool begin(/* Convert from */
+                          const std::string &src_chset,
+
+                          /* Convert to */
+                          const std::string &dst_chset);
+
+               /* Feed iconv(3). Returns false if the conversion was aborted.
+                */
+
+               bool operator()(const char *, size_t);
+
+               bool operator()(const unicode_char *, size_t);
+
+               /*
+               ** Get the results here. If the subclass returns a non-0
+               ** value, the conversion is aborted.
+               */
+
+               virtual int converted(const char *, size_t);
+
+               /*
+               ** End of conversion.
+               **
+               ** Returns true if all calls to converted() returned 0,
+               ** false if the conversion was aborted.
+               **
+               ** errflag is set to true if there was a character that could
+               ** not be converted, and passed to converted().
+               */
+
+               bool end(bool &errflag)
+               {
+                       return end(&errflag);
+               }
+
+               bool end()
+               {
+                       return end(NULL);
+               }
+
+               /* Convert between two different charsets */
+
+               static std::string convert(const std::string &text,
+                                          const std::string &charset,
+                                          const std::string &dstcharset,
+                                          bool &errflag);
+
+               /* Convert between two different charsets */
+
+               static std::string convert(const std::string &text,
+                                          const std::string &charset,
+                                          const std::string &dstcharset)
+               {
+                       bool dummy;
+
+                       return convert(text, charset, dstcharset, dummy);
+               }
+
+               /* Convert from unicode to a charset */
+
+               static std::string convert(const std::vector<unicode_char> &uc,
+                                          const std::string &dstcharset,
+                                          bool &errflag);
+
+               /* Convert from unicode to a charset */
+
+               static std::string convert(const std::vector<unicode_char> &uc,
+                                          const std::string &dstcharset)
+               {
+                       bool dummy;
+
+                       return convert(uc, dstcharset, dummy);
+               }
+
+               /* Convert charset to unicode */
+
+               static bool convert(const std::string &text,
+                                   const std::string &charset,
+                                   std::vector<unicode_char> &uc);
+
+
+               /* Convert to upper/lower/title case */
+
+               static std::string
+                       convert_tocase(/* Text string */
+                                      const std::string &text,
+
+                                      /* Its charset */
+                                      const std::string &charset,
+
+                                      /* First character: unicode_uc, unicode_lc, or unicode_tc */
+                                      unicode_char (*first_char_func)(unicode_char),
+
+                                      /* If not NULL, second and subsequent chars */
+                                      unicode_char (*char_func)(unicode_char)
+                                      =NULL)
+               {
+                       bool dummy;
+
+                       return convert_tocase(text, charset, dummy,
+                                             first_char_func,
+                                             char_func);
+               }
+
+               /* Convert to upper/lower/title case */
+
+               static std::string
+                       convert_tocase(/* Text string */
+                                      const std::string &text,
+
+                                      /* Its charset */
+                                      const std::string &charset,
+
+                                      /* Set if there's a conversion error */
+                                      bool &err,
+
+                                      /* First character: unicode_uc, unicode_lc, or unicode_tc */
+                                      unicode_char (*first_char_func)(unicode_char),
+
+                                      /* If not NULL, second and subsequent chars */
+                                      unicode_char (*char_func)(unicode_char)
+                                      =NULL);
+       private:
+               bool end(bool *);
+
+       public:
+               class tou;
+               class fromu;
+       };
+
+       /* Convert output of iconvert to unicode_chars. */
+
+       class iconvert::tou : public iconvert {
+
+       public:
+               bool begin(const std::string &chset);
+
+               virtual int converted(const unicode_char *, size_t);
+
+               using iconvert::operator();
+       private:
+               int converted(const char *ptr, size_t cnt);
+
+       public:
+               template<typename iter_t> class to_iter_class;
+
+               template<typename input_iter_t,
+                       typename output_iter_t>
+                       static output_iter_t convert(input_iter_t from_iter,
+                                                    input_iter_t to_iter,
+                                                    const std::string &chset,
+                                                    output_iter_t out_iter);
+
+               template<typename input_iter_t>
+                       static void convert(input_iter_t from_iter,
+                                           input_iter_t to_iter,
+                                           const std::string &chset,
+                                           std::vector<unicode_char> &out_buf)
+               {
+                       out_buf.clear();
+                       std::back_insert_iterator<std::vector<unicode_char> >
+                               insert_iter(out_buf);
+
+                       convert(from_iter, to_iter, chset, insert_iter);
+               }
+
+               static void convert(const std::string &str,
+                                   const std::string &chset,
+                                   std::vector<unicode_char> &out_buf);
+       };
+
+       /* Helper class that saves unicode output into an output iterator */
+
+       template<typename iter_t>
+               class iconvert::tou::to_iter_class : public iconvert::tou {
+
+               iter_t iter;
+       public:
+
+       to_iter_class(iter_t iterValue)
+               : iter(iterValue) {}
+
+               using tou::operator();
+
+               operator iter_t() const { return iter; }
+
+       private:
+               int converted(const unicode_char *ptr, size_t cnt)
+               {
+                       while (cnt)
+                       {
+                               *iter=*ptr;
+
+                               ++iter;
+                               ++ptr;
+                               --cnt;
+                       }
+                       return 0;
+               }
+       };
+               
+       template<typename input_iter_t,
+               typename output_iter_t>
+               output_iter_t iconvert::tou::convert(input_iter_t from_iter,
+                                                    input_iter_t to_iter,
+                                                    const std::string &chset,
+                                                    output_iter_t out_iter)
+               {
+                       class to_iter_class<output_iter_t> out(out_iter);
+
+                       if (!out.begin(chset))
+                               return out;
+
+                       std::vector<char> string;
+
+                       while (from_iter != to_iter)
+                       {
+                               string.push_back(*from_iter++);
+
+                               if (string.size() > 31)
+                               {
+                                       out(&string[0], string.size());
+                                       string.clear();
+                               }
+                       }
+
+                       if (string.size() > 0)
+                               out(&string[0], string.size());
+
+                       out.end();
+                       return out;
+               }
+               
+       /* Convert output of iconvert from unicode_chars. */
+
+       class iconvert::fromu : public iconvert {
+
+       public:
+               bool begin(const std::string &chset);
+
+               using iconvert::operator();
+
+               template<typename iter_t> class to_iter_class;
+
+               template<typename input_iter_t,
+                       typename output_iter_t>
+                       static output_iter_t convert(input_iter_t from_iter,
+                                                    input_iter_t to_iter,
+                                                    const std::string &chset,
+                                                    output_iter_t out_iter);
+
+               template<typename input_iter_t>
+                       static void convert(input_iter_t from_iter,
+                                           input_iter_t to_iter,
+                                           const std::string &chset,
+                                           std::string &out_buf)
+               {
+                       out_buf="";
+                       std::back_insert_iterator<std::string>
+                               insert_iter(out_buf);
+
+                       convert(from_iter, to_iter, chset, insert_iter);
+               }
+
+               static void convert(const std::vector<unicode_char> &ubuf,
+                                   const std::string &chset,
+                                   std::string &out_buf);
+
+               static std::string convert(const std::vector<unicode_char>
+                                          &ubuf,
+                                          const std::string &chset);
+       };
+
+       /* Helper class that saves unicode output into an output iterator */
+
+       template<typename iter_t>
+               class iconvert::fromu::to_iter_class : public iconvert::fromu {
+
+               iter_t iter;
+       public:
+
+       to_iter_class(iter_t iterValue)
+               : iter(iterValue) {}
+
+               using fromu::operator();
+
+               operator iter_t() const { return iter; }
+
+       private:
+               int converted(const char *ptr, size_t cnt)
+               {
+                       while (cnt)
+                       {
+                               *iter=*ptr;
+
+                               ++iter;
+                               ++ptr;
+                               --cnt;
+                       }
+                       return 0;
+               }
+       };
+               
+       template<typename input_iter_t,
+               typename output_iter_t>
+               output_iter_t iconvert::fromu::convert(input_iter_t from_iter,
+                                                      input_iter_t to_iter,
+                                                      const std::string &chset,
+                                                      output_iter_t out_iter)
+               {
+                       class to_iter_class<output_iter_t> out(out_iter);
+
+                       if (!out.begin(chset))
+                               return out;
+
+                       std::vector<unicode_char> string;
+
+                       while (from_iter != to_iter)
+                       {
+                               string.push_back(*from_iter++);
+
+                               if (string.size() > 31)
+                               {
+                                       out(&string[0], string.size());
+                                       string.clear();
+                               }
+                       }
+
+                       if (string.size() > 0)
+                               out(&string[0], string.size());
+
+                       out.end();
+                       return out;
+               }
+
+       /*
+       ** Unicode linebreaking algorithm, tr14.
+       */
+
+       extern "C" int linebreak_trampoline(int value, void *ptr);
+       extern "C" int linebreakc_trampoline(int value, unicode_char ch,
+                                            void *ptr);
+
+       /*
+       ** Subclass linebreak_callback_base, implement operator()(int).
+       **
+       ** Use operator<< or operator()(iterator, iterator) to feed
+       ** unicode_chars into the linebreaking algorithm. The subclass receives
+       ** UNICODE_LB values, as they become available.
+       */
+
+       class linebreak_callback_base {
+
+               unicode_lb_info_t handle;
+
+               int opts;
+
+               linebreak_callback_base(const linebreak_callback_base &);
+               /* NOT IMPLEMENTED */
+
+               linebreak_callback_base &operator==(const
+                                                   linebreak_callback_base &);
+               /* NOT IMPLEMENTED */
+
+       public:
+               linebreak_callback_base();
+               virtual ~linebreak_callback_base();
+
+               void finish();
+
+               void set_opts(int opts);
+
+               friend int linebreak_trampoline(int, void *);
+
+               linebreak_callback_base &operator<<(unicode_char uc);
+
+               template<typename iter_type>
+                       linebreak_callback_base &operator()(iter_type beg_iter,
+                                                           iter_type end_iter)
+               {
+                       while (beg_iter != end_iter)
+                               operator<<(*beg_iter++);
+                       return *this;
+               }
+
+               linebreak_callback_base &operator<<(const
+                                                   std::vector<unicode_char>
+                                                   &vec)
+               {
+                       return operator()(vec.begin(), vec.end());
+               }
+       private:
+               virtual int operator()(int);
+       };
+
+       class linebreak_callback_save_buf : public linebreak_callback_base {
+
+       public:
+               std::list<int> lb_buf;
+
+               linebreak_callback_save_buf();
+               ~linebreak_callback_save_buf();
+
+       private:
+               int operator()(int value);
+       };
+
+       /*
+       ** Convert an input iterator sequence over unicode_chars into
+       ** an input iterator sequence over linebreak values.
+       */
+
+       template<typename input_t> class linebreak_iter
+               : public std::iterator<std::input_iterator_tag, int, void>
+       {
+               mutable input_t iter_value, end_iter_value;
+
+               mutable linebreak_callback_save_buf *buf;
+
+               void fill() const
+               {
+                       if (buf == NULL)
+                               return;
+
+                       while (buf->lb_buf.empty())
+                       {
+                               if (iter_value == end_iter_value)
+                               {
+                                       buf->finish();
+                                       if (buf->lb_buf.empty())
+                                       {
+                                               delete buf;
+                                               buf=NULL;
+                                       }
+                                       break;
+                               }
+
+                               buf->operator<<(*iter_value++);
+                       }
+               }
+
+               mutable value_type bufvalue;
+
+       public:
+               linebreak_iter(const input_t &iter_valueArg,
+                              const input_t &iter_endvalueArg)
+                       : iter_value(iter_valueArg),
+                       end_iter_value(iter_endvalueArg),
+                       buf(new linebreak_callback_save_buf)
+                       {
+                       }
+
+               linebreak_iter() : buf(NULL)
+               {
+               }
+
+               void set_opts(int opts)
+               {
+                       if (buf)
+                               buf->set_opts(opts);
+               }
+
+               ~linebreak_iter()
+               {
+                       if (buf)
+                               delete buf;
+               }
+
+               linebreak_iter(const linebreak_iter<input_t> &v)
+                       : buf(NULL)
+               {
+                       operator=(v);
+               }
+
+               linebreak_iter<input_t> &operator=(const
+                                                  linebreak_iter<input_t> &v)
+               {
+                       if (buf)
+                               delete buf;
+                       buf=v.buf;
+                       iter_value=v.iter_value;
+                       end_iter_value=v.end_iter_value;
+                       v.buf=NULL;
+                       return *this;
+               }
+
+               bool operator==(const linebreak_iter<input_t> &v) const
+               {
+                       fill();
+                       v.fill();
+
+                       return buf == NULL && v.buf == NULL;
+               }
+
+               bool operator!=(const linebreak_iter<input_t> &v) const
+               {
+                       return !operator==(v);
+               }
+
+               value_type operator*() const
+               {
+                       fill();
+                       return buf == NULL ? UNICODE_LB_MANDATORY:
+                               buf->lb_buf.front();
+               }
+
+               linebreak_iter<input_t> &operator++()
+               {
+                       bufvalue=operator*();
+
+                       if (buf)
+                               buf->lb_buf.pop_front();
+                       return *this;
+               }
+
+               const value_type *operator++(int)
+               {
+                       operator++();
+                       return &bufvalue;
+               }
+       };
+
+       /*
+       ** Like linebreak_callback_base, except the subclass receives both
+       ** the linebreaking value, and the unicode character.
+       */
+
+       class linebreakc_callback_base {
+
+               unicode_lbc_info_t handle;
+
+               int opts;
+
+               linebreakc_callback_base(const linebreakc_callback_base &);
+               /* NOT IMPLEMENTED */
+
+               linebreakc_callback_base &operator==(const
+                                                    linebreakc_callback_base
+                                                    &);
+               /* NOT IMPLEMENTED */
+
+
+       public:
+               linebreakc_callback_base();
+               virtual ~linebreakc_callback_base();
+
+               void finish();
+
+               void set_opts(int opts);
+
+               friend int linebreakc_trampoline(int, unicode_char, void *);
+
+               linebreakc_callback_base &operator<<(unicode_char uc);
+
+               template<typename iter_type>
+                       linebreakc_callback_base &operator()(iter_type beg_iter,
+                                                           iter_type end_iter)
+               {
+                       while (beg_iter != end_iter)
+                               operator<<(*beg_iter++);
+                       return *this;
+               }
+
+               linebreakc_callback_base &operator<<(const
+                                                   std::vector<unicode_char>
+                                                   &vec)
+               {
+                       return operator()(vec.begin(), vec.end());
+               }
+       private:
+               virtual int operator()(int, unicode_char);
+       };
+
+       class linebreakc_callback_save_buf : public linebreakc_callback_base {
+
+       public:
+               std::list<std::pair<int, unicode_char> > lb_buf;
+
+               linebreakc_callback_save_buf();
+               ~linebreakc_callback_save_buf();
+
+       private:
+               int operator()(int, unicode_char);
+       };
+
+
+       /*
+       ** Convert an input iterator sequence over unicode_chars into
+       ** an input iterator sequence over std::pair<int, unicode_char>,
+       ** the original unicode character, and the linebreaking value before
+       ** the character.
+       */
+
+       template<typename input_t> class linebreakc_iter
+               : public std::iterator<std::input_iterator_tag,
+               std::pair<int, unicode_char>, void>
+       {
+               mutable input_t iter_value, end_iter_value;
+
+               mutable linebreakc_callback_save_buf *buf;
+
+               void fill() const
+               {
+                       if (buf == NULL)
+                               return;
+
+                       while (buf->lb_buf.empty())
+                       {
+                               if (iter_value == end_iter_value)
+                               {
+                                       buf->finish();
+                                       if (buf->lb_buf.empty())
+                                       {
+                                               delete buf;
+                                               buf=NULL;
+                                       }
+                                       break;
+                               }
+
+                               buf->operator<<(*iter_value);
+                               ++iter_value;
+                       }
+               }
+
+               mutable value_type bufvalue;
+
+       public:
+               linebreakc_iter(const input_t &iter_valueArg,
+                               const input_t &iter_endvalueArg)
+                       : iter_value(iter_valueArg),
+                       end_iter_value(iter_endvalueArg),
+                       buf(new linebreakc_callback_save_buf)
+                       {
+                       }
+
+               linebreakc_iter() : buf(NULL)
+               {
+               }
+
+               ~linebreakc_iter()
+               {
+                       if (buf)
+                               delete buf;
+               }
+
+               linebreakc_iter(const linebreakc_iter<input_t> &v)
+                       : buf(NULL)
+               {
+                       operator=(v);
+               }
+
+               linebreakc_iter<input_t> &operator=(const
+                                                  linebreakc_iter<input_t> &v)
+               {
+                       if (buf)
+                               delete buf;
+                       buf=v.buf;
+                       iter_value=v.iter_value;
+                       end_iter_value=v.end_iter_value;
+                       v.buf=NULL;
+                       return *this;
+               }
+
+               bool operator==(const linebreakc_iter<input_t> &v) const
+               {
+                       fill();
+                       v.fill();
+
+                       return buf == NULL && v.buf == NULL;
+               }
+
+               bool operator!=(const linebreakc_iter<input_t> &v) const
+               {
+                       return !operator==(v);
+               }
+
+               value_type operator*() const
+               {
+                       fill();
+                       return buf == NULL ?
+                               std::make_pair(UNICODE_LB_MANDATORY,
+                                              (unicode_char)0):
+                               buf->lb_buf.front();
+               }
+
+               linebreakc_iter<input_t> &operator++()
+               {
+                       bufvalue=operator*();
+
+                       if (buf)
+                               buf->lb_buf.pop_front();
+                       return *this;
+               }
+
+               const value_type *operator++(int)
+               {
+                       operator++();
+                       return &bufvalue;
+               }
+       };
+
+
+       /*
+       ** Subclass wordbreak_callback_base, implement operator()(int).
+       **
+       ** Use operator<< or operator()(iterator, iterator) to feed
+       ** unicode_chars into the wordbreaking algorithm. The subclass receives
+       ** word flags, as they become available.
+       */
+
+       extern "C" int wordbreak_trampoline(int value, void *ptr);
+
+       class wordbreak_callback_base {
+
+               unicode_wb_info_t handle;
+
+               wordbreak_callback_base(const wordbreak_callback_base &);
+               /* NOT IMPLEMENTED */
+
+               wordbreak_callback_base &operator==(const
+                                                   wordbreak_callback_base &);
+               /* NOT IMPLEMENTED */
+
+       public:
+               wordbreak_callback_base();
+               virtual ~wordbreak_callback_base();
+
+               void finish();
+
+               friend int wordbreak_trampoline(int, void *);
+
+               wordbreak_callback_base &operator<<(unicode_char uc);
+
+               template<typename iter_type>
+                       wordbreak_callback_base &operator()(iter_type beg_iter,
+                                                           iter_type end_iter)
+               {
+                       while (beg_iter != end_iter)
+                               operator<<(*beg_iter++);
+                       return *this;
+               }
+
+               wordbreak_callback_base &operator<<(const
+                                                   std::vector<unicode_char>
+                                                   &vec)
+               {
+                       return operator()(vec.begin(), vec.end());
+               }
+       private:
+               virtual int operator()(bool);
+       };
+
+       /*
+       ** A C++ wrapper for unicode_wbscan.
+       */
+
+       class wordbreakscan {
+
+               unicode_wbscan_info_t handle;
+
+               wordbreakscan(const wordbreakscan &);
+               /* NOT IMPLEMENTED */
+
+               wordbreakscan &operator==(const wordbreakscan &);
+               /* NOT IMPLEMENTED */
+       public:
+
+               wordbreakscan();
+               ~wordbreakscan();
+
+               bool operator<<(unicode_char uc);
+
+               size_t finish();
+       };
+               
+}
+#endif
+
+#endif