[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tyndur-devel] [PATCH] libc: mbs(r)towcs() und wcs(r)tombs()



+ libc: mbs(r)towcs() und wcs(r)tombs()

Signed-off-by: Antoine Kaufmann <toni@xxxxxxxxxx>
---
 src/include/stdlib.h            |   47 +++++++++++++
 src/lib/string/multibyte.c      |  146 +++++++++++++++++++++++++++++++++++++++
 src/modules/include/wchar.h     |   20 +++++
 src/modules/lib/stdlibc/wchar.c |   45 ++++++++++++
 4 files changed, 258 insertions(+), 0 deletions(-)

diff --git a/src/include/stdlib.h b/src/include/stdlib.h
index 97b70d4..6ef072a 100644
--- a/src/include/stdlib.h
+++ b/src/include/stdlib.h
@@ -145,6 +145,53 @@ int mbtowc(wchar_t* wc, const char* s, size_t len);
  */
 int wctomb(char* buf, wchar_t wc);
 
+/**
+ * String aus breiten Zeichen in Multibyte-String umwandeln. Wird ein Zeichen
+ * angetroffen, das nicht umgewandeld werden kann, wird -1 zurueckgegeben. Es
+ * werden maximal len Bytes geschrieben. Das abschliessende L'\0' wird
+ * mitkonvertiert, aber beim Rueckgabewert, wird es nicht mit beruecksichtigt.
+ * Falls der String nicht vollstaendig konvertiert werden konnte, weil buf zu
+ * klein ist, ist das Ergebnis nicht nullterminiert.
+ *
+ * Ist buf == NULL wird len ignoriert und es wird nur die Laenge bestimmt, die
+ * der String haette, ohne das abschliessende 0-Byte.
+ *
+ * Um einen String vollstaendig zu konvertieren, muss buf mindestens die Groesse
+ * wcstombs(NULL, wcs, 0) + 1 haben.
+ *
+ * @param buf Puffer in dem der Multibytestring abgelegt werden soll oder NULL
+ * @param wcs Zeiger auf den String aus breiten Zeichen
+ * @param len Groesse von buf
+ *
+ * @return Anzahl der in buf geschriebenen Bytes ohne abschliessendes '\0', oder
+ *         (size_t) -1 wenn ein Zeichen nicht konvertiert werden konnte.
+ */
+size_t wcstombs(char* buf, const wchar_t* wcs, size_t len);
+
+/**
+ * Multibyte-String in String aus breiten Zeichen umwandeln. Wird ein Zeichen
+ * angetroffen, das nicht umgewandeld werden kann, wird -1 zurueckgegeben. Es
+ * werden maximal len breite Zeichen geschrieben. Das abschliessende '\0' wird
+ * mitkonvertiert, aber beim Rueckgabewert, wird es nicht mit beruecksichtigt.
+ * Falls der String nicht vollstaendig konvertiert werden konnte, weil buf zu
+ * klein ist, ist das Ergebnis nicht L'\0'-terminiert.
+ *
+ * Ist buf == NULL wird len ignoriert und es wird nur die Laenge bestimmt, die
+ * der String haette, ohne das abschliessende L'\0'.
+ *
+ * Um einen String vollstaendig zu konvertieren, muss buf mindestens die Groesse
+ * von mbstowcs(NULL, str, 0) + 1 breiten Zeichen haben.
+ *
+ * @param buf Puffer in dem der String aus breiten Zeichen abgelegt werden soll
+ *            oder NULL
+ * @param wcs Zeiger auf den Multibytestring
+ * @param len Groesse von buf in Zeichen
+ *
+ * @return Anzahl der in buf geschriebenen Zeichen ohne abschliessendes L'\0',
+ *          oder (size_t) -1 wenn ein Zeichen nicht konvertiert werden konnte.
+ */
+size_t mbstowcs(wchar_t* buf, const char* str, size_t len);
+
 
 /**
  * Seed fuer Zufallszahlgenerator setzen
diff --git a/src/lib/string/multibyte.c b/src/lib/string/multibyte.c
index 34b90c4..a791d5f 100644
--- a/src/lib/string/multibyte.c
+++ b/src/lib/string/multibyte.c
@@ -194,3 +194,149 @@ int wctomb(char* buf, wchar_t wc)
     }
 }
 
+/**
+ * Wird sowohl von wcstombs als auch von wcsrtombs benutzt, und entspricht
+ * abgesehen vom wcstate-Kram wcsrtombs.
+ *
+ * @see wcstombs
+ * @see wcsrtombs
+ */
+size_t __internal_wcsrtombs(char* buf, const wchar_t** wcs, size_t len)
+{
+    char intbuf[MB_CUR_MAX];
+    size_t bufpos = 0;
+    int curlen;
+    const wchar_t* our_wcs;
+
+    if (!buf) {
+        // Wenn buf == NULL ist, duerfen wir auch *wcs nicht veraendern, deshalb
+        // setzen wir wcs auf den lokalen Pointer
+        our_wcs = *wcs;
+        wcs = &our_wcs;
+    }
+
+    while (**wcs && (!buf || (bufpos < len))) {
+        if ((curlen = wctomb(intbuf, *(*wcs)++)) == -1) {
+            return (size_t) -1;
+        }
+
+        if (buf && ((len - bufpos) < curlen)) {
+            // Schade, zu eng, das Zeichen passt nicht mehr vollstaendig in den
+            // Puffer
+            break;
+        }
+
+        // Passt noch rein
+        if (buf) {
+            memcpy(buf + bufpos, intbuf, curlen);
+        }
+        bufpos += curlen;
+    }
+
+    // Wenn wir am Ende angekommen sind, und noch Platz frei ist, terminieren
+    // wir das ganze noch mit einem netten kleinen '\0'.
+    if (buf && !**wcs && (bufpos < len)) {
+        *wcs = NULL;
+        buf[bufpos] = '\0';
+    }
+
+    return bufpos;
+}
+
+/**
+ * Wird sowohl von mbstowcs als auch von mbsrtowc benutzt, und entspricht
+ * abgesehen vom wcstate-Kram mbstowcs.
+ *
+ * @see mbstowcs
+ * @see mbsrtowcs
+ */
+size_t __internal_mbsrtowcs(wchar_t* buf, const char** str, size_t len)
+{
+    wchar_t wc;
+    size_t bufpos = 0;
+    int curlen;
+    const char* our_str;
+
+    if (!buf) {
+        // Wenn buf == NULL ist, duerfen wir auch *str nicht veraendern, deshalb
+        // setzen wir str auf den lokalen Pointer
+        our_str = *str;
+        str = &our_str;
+    }
+
+    while (**str && (!buf || (bufpos < len))) {
+        if ((curlen = mbtowc(&wc, *str, MB_CUR_MAX)) == -1) {
+            // Ein ungueltiges Zeichen wurde angetroffen
+            return (size_t) -1;
+        }
+
+        if (buf) {
+            buf[bufpos] = wc;
+        }
+
+        bufpos++;
+        *str += curlen;
+    }
+
+    // Wenn noch Platz ist, schreiben wir jetzt das abschliessende L'\0'
+    if (buf && !**str && (bufpos < len)) {
+        *str = NULL;
+        buf[bufpos] = L'\0';
+    }
+
+    return bufpos;
+}
+
+/**
+ * String aus breiten Zeichen in Multibyte-String umwandeln. Wird ein Zeichen
+ * angetroffen, das nicht umgewandeld werden kann, wird -1 zurueckgegeben. Es
+ * werden maximal len Bytes geschrieben. Das abschliessende L'\0' wird
+ * mitkonvertiert, aber beim Rueckgabewert, wird es nicht mit beruecksichtigt.
+ * Falls der String nicht vollstaendig konvertiert werden konnte, weil buf zu
+ * klein ist, ist das Ergebnis nicht nullterminiert.
+ *
+ * Ist buf == NULL wird len ignoriert und es wird nur die Laenge bestimmt, die
+ * der String haette, ohne das abschliessende 0-Byte.
+ *
+ * Um einen String vollstaendig zu konvertieren, muss buf mindestens die Groesse
+ * wcstombs(NULL, wcs, 0) + 1 haben.
+ *
+ * @param buf Puffer in dem der Multibytestring abgelegt werden soll oder NULL
+ * @param wcs Zeiger auf den String aus breiten Zeichen
+ * @param len Groesse von buf
+ *
+ * @return Anzahl der in buf geschriebenen Bytes ohne abschliessendes '\0', oder
+ *         (size_t) -1 wenn ein Zeichen nicht konvertiert werden konnte.
+ */
+size_t wcstombs(char* buf, const wchar_t* wcs, size_t len)
+{
+    return __internal_wcsrtombs(buf, &wcs, len);
+}
+
+/**
+ * Multibyte-String in String aus breiten Zeichen umwandeln. Wird ein Zeichen
+ * angetroffen, das nicht umgewandeld werden kann, wird -1 zurueckgegeben. Es
+ * werden maximal len breite Zeichen geschrieben. Das abschliessende '\0' wird
+ * mitkonvertiert, aber beim Rueckgabewert, wird es nicht mit beruecksichtigt.
+ * Falls der String nicht vollstaendig konvertiert werden konnte, weil buf zu
+ * klein ist, ist das Ergebnis nicht L'\0'-terminiert.
+ *
+ * Ist buf == NULL wird len ignoriert und es wird nur die Laenge bestimmt, die
+ * der String haette, ohne das abschliessende L'\0'.
+ *
+ * Um einen String vollstaendig zu konvertieren, muss buf mindestens die Groesse
+ * von mbstowcs(NULL, str, 0) + 1 breiten Zeichen haben.
+ *
+ * @param buf Puffer in dem der String aus breiten Zeichen abgelegt werden soll
+ *            oder NULL
+ * @param wcs Zeiger auf den Multibytestring
+ * @param len Groesse von buf in Zeichen
+ *
+ * @return Anzahl der in buf geschriebenen Zeichen ohne abschliessendes L'\0',
+ *          oder (size_t) -1 wenn ein Zeichen nicht konvertiert werden konnte.
+ */
+size_t mbstowcs(wchar_t* buf, const char* str, size_t len)
+{
+    return __internal_mbsrtowcs(buf, &str, len);
+}
+
diff --git a/src/modules/include/wchar.h b/src/modules/include/wchar.h
index ed9bfca..a6c0a32 100644
--- a/src/modules/include/wchar.h
+++ b/src/modules/include/wchar.h
@@ -62,6 +62,26 @@ size_t mbrtowc(wchar_t* wc, const char* s, size_t len, mbstate_t* ps);
  */
 size_t wcrtomb(char* buf, wchar_t wc, mbstate_t* ps);
 
+/**
+ * Reentrante Variante von wcstombs. Der einzige wesentliche Unterschied fuer
+ * uns mit UTF8 ist, dass *wcs so aktualisiert wird, dass es bei einem Abbruch,
+ * sei es weil buf zu klein ist oder weil ein ungueltiges Zeichen angetroffen
+ * wurde, auf das betreffende Zeichen zeigt. Wird der String erfolgreich
+ * verarbeitet, wird *wcs auf NULL gesetzt.
+ * @see wcstombs
+ */
+size_t wcsrtombs(char* buf, const wchar_t** wcs, size_t len, mbstate_t* ps);
+
+/**
+ * Reentrante Variante von mbstowcs. Der einzige wesentliche Unterschied fuer
+ * uns mit UTF8 ist, dass *str so aktualisiert wird, dass es bei einem Abbruch,
+ * sei es weil buf zu klein ist oder weil ein ungueltiges Zeichen angetroffen
+ * wurde, auf das betreffende Zeichen zeigt. Wird der String erfolgreich
+ * verarbeitet, wird *str auf NULL gesetzt.
+ * @see mbstowcs
+ */
+size_t mbsrtowcs(wchar_t* buf, const char** str, size_t len, mbstate_t* ps);
+
 
 /**
  * Anzahl der Spalten, die ein Zeichen in Anspruch nimmt, errechnen. Fuer c = 0
diff --git a/src/modules/lib/stdlibc/wchar.c b/src/modules/lib/stdlibc/wchar.c
index 255abd0..43397b6 100644
--- a/src/modules/lib/stdlibc/wchar.c
+++ b/src/modules/lib/stdlibc/wchar.c
@@ -28,6 +28,12 @@
 
 #include <wchar.h>
 #include <stdlib.h>
+#include <errno.h>
+
+// Diese werden auch fuer wcstombs und mbstowcs benutzt
+extern size_t __internal_wcsrtombs(char* buf, const wchar_t** wcs, size_t len);
+extern size_t __internal_mbsrtowcs(wchar_t* buf, const char** str, size_t len);
+
 
 /**
  * Reentrante Variante von mbtowc, bei uns mit UTF-8 aber identisch.
@@ -48,6 +54,45 @@ size_t wcrtomb(char* buf, wchar_t wc, mbstate_t* ps)
 }
 
 /**
+ * Reentrante Variante von wcstombs. Der einzige wesentliche Unterschied fuer
+ * uns mit UTF8 ist, dass *wcs so aktualisiert wird, dass es bei einem Abbruch,
+ * sei es weil buf zu klein ist oder weil ein ungueltiges Zeichen angetroffen
+ * wurde, auf das betreffende Zeichen zeigt. Wird der String erfolgreich
+ * verarbeitet, wird *wcs auf NULL gesetzt.
+ * @see wcstombs
+ */
+size_t wcsrtombs(char* buf, const wchar_t** wcs, size_t len, mbstate_t* ps)
+{
+    size_t result;
+
+    if ((result = __internal_wcsrtombs(buf, wcs, len)) == (size_t) -1) {
+        errno = EILSEQ;
+    }
+
+    return result;
+}
+
+/**
+ * Reentrante Variante von mbstowcs. Der einzige wesentliche Unterschied fuer
+ * uns mit UTF8 ist, dass *str so aktualisiert wird, dass es bei einem Abbruch,
+ * sei es weil buf zu klein ist oder weil ein ungueltiges Zeichen angetroffen
+ * wurde, auf das betreffende Zeichen zeigt. Wird der String erfolgreich
+ * verarbeitet, wird *str auf NULL gesetzt.
+ * @see mbstowcs
+ */
+size_t mbsrtowcs(wchar_t* buf, const char** str, size_t len, mbstate_t* ps)
+{
+    size_t result;
+
+    if ((result = __internal_mbsrtowcs(buf, str, len)) == (size_t) -1) {
+        errno = EILSEQ;
+    }
+
+    return result;
+}
+
+
+/**
  * Anzahl der Spalten, die ein Zeichen in Anspruch nimmt, errechnen. Fuer c = 0
  * wird 0 zuruekgegeben. Falls es sich nicht um ein druckbares Zeichen handelt,
  * wird -1 zurueckgegeben.
-- 
1.6.0.6