view patches/ghostscript-9.15-windows-dxmain.patch @ 6384:bd27c9462d99

Fix mingw::ghostscript unicode commandline args
author Masamichi Hosoda <trueroad@users.noreply.github.com>
date Sat, 14 Mar 2015 23:14:28 +0900
parents
children a0073109b692
line wrap: on
line source

--- a/psi/dxmainc.c	2014-09-22 19:17:33.000000000 +0900
+++ b/psi/dxmainc.c	2015-03-14 23:03:03.633481800 +0900
@@ -28,10 +28,12 @@
  *  gcc -shared -Wl,-soname,libgs.so.7 -o libgs.so.7.00 file.o -lc
  */
 
+#include "windows_.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <io.h>
 #include <fcntl.h>
 #include <errno.h>
 #define __PROTOTYPES__
@@ -52,7 +54,7 @@
 static int
 gsdll_stdin(void *instance, char *buf, int len)
 {
-    return read(fileno(stdin), buf, len);
+    return _read(fileno(stdin), buf, len);
 }
 
 static int
@@ -71,18 +73,196 @@
     return len;
 }
 
+/* porting from dwmainc.c */
+#ifndef GS_NO_UTF8
+/* stdio functions - versions that translate to/from utf-8 */
+static int
+gsdll_stdin_utf8(void *instance, char *buf, int len)
+{
+    static WCHAR thiswchar = 0; /* wide character to convert to multiple bytes */
+    static int nmore = 0;       /* number of additional encoding bytes to generate */
+    UINT consolecp = 0;
+    int nret = 0;               /* number of bytes returned to caller */
+    int i;
+
+    while (len) {
+        while (len && nmore) {
+            nmore--;
+            *buf++ = 0x80 | ((thiswchar >> (6 * nmore)) & 0x3F), nret++;
+            len--;
+        }
+        while (len) {
+            if (0 >= _read(fileno(stdin), buf, 1))
+                return nret;
+            nret++, buf++, len--;
+            if (buf[-1] == '\n')
+                /* return at end of line (note: no traslation needed) */
+                return nret;
+            else if ((unsigned char)buf[-1] <= 0x7F)
+                /* no translation needed for 7-bit ASCII codes */
+                continue;
+            else {
+                /* extended character, may be double */
+                BYTE dbcsstr[2];
+
+                dbcsstr[0] = buf[-1];
+                if (!consolecp)
+                    consolecp = GetConsoleCP();
+                thiswchar = L'?'; /* initialize in case the conversion below fails */
+                if (IsDBCSLeadByteEx(consolecp, dbcsstr[0])) {
+                    /* double-byte character code, fetch the trail byte */
+                    _read(fileno(stdin), &dbcsstr[1], 1);
+                    MultiByteToWideChar(consolecp, 0, dbcsstr, 2, &thiswchar, 1);
+                }
+                else {
+                    MultiByteToWideChar(consolecp, 0, dbcsstr, 1, &thiswchar, 1);
+                }
+                /* convert thiswchar to utf-8 */
+                if (thiswchar <= 0x007F) {          /* encoded as single byte */
+                    buf[-1] = (char)thiswchar;
+                } else if (thiswchar <= 0x07FF) {   /* encoded as 2 bytes */
+                    buf[-1] = 0xC0 | ((thiswchar >> 6) & 0x1F);
+                    nmore = 1;
+                    break;
+                } else if (thiswchar <= 0xFFFF) {   /* encoded as 3 bytes */
+                    buf[-1] = 0xE0 | ((thiswchar >> 12) & 0xF);
+                    nmore = 2;
+                    break;
+                } else
+                    /* note: codes outside the BMP not handled */
+                    buf[-1] = '?';
+            }
+        }
+    }
+    return nret;
+}
+
+static void
+gsdll_utf8write(FILE *stdwr, const char *str, int len, WCHAR *thiswchar, int *nmore)
+{
+    UINT consolecp = 0;
+
+    while (len) {
+        const char *str0;
+
+        /* write ASCII chars without translation */
+        for (str0 = str; len && !(*str & 0x80); str++, len--);
+        if (str > str0) {
+            if (*nmore) {
+                /* output previous, incomplete utf-8 sequence as ASCII "?" */
+                fwrite("?", 1, 1, stdwr);
+                *nmore = 0, *thiswchar = 0;
+            }
+            fwrite(str0, 1, str - str0, stdwr);
+        }
+        /* accumulate lead/trail bytes into *thiswchar */
+        for (; len; str++, len--) {
+            switch (*str & 0xC0) {
+                case 0x80:      /* trail byte */
+                    if (*nmore) {
+                        (*nmore)--;
+                        *thiswchar |= (WCHAR)(unsigned char)(*str & 0x3F) << (6 * *nmore);
+                        }
+                    else {
+                        /* lead byte missing; output unexpected trail byte as ASCII "?" */
+                        *nmore = 0;
+                        *thiswchar = L'?';
+                    }
+                    break;
+                case 0xC0:      /* lead byte */
+                    if (*nmore)
+                        /* output previous, incomplete utf-8 sequence as ASCII "?" */
+                        fwrite("?", 1, 1, stdwr);
+                    if (!(*str & 0x20))
+                        *nmore = 1;     /* 2-byte encoding */
+                    else if (!(*str & 0x10))
+                        *nmore = 2;     /* 3-byte encoding */
+                    else if (!(*str & 0x08))
+                        *nmore = 3;     /* 4-byte encoding */
+                    else
+                        *nmore = 0;     /* restricted (> 4) or invalid encodings */
+                    if (*nmore)
+                        *thiswchar = (WCHAR)(unsigned char)(*str & (0x3F >> *nmore)) << (6 * *nmore);
+                    else {
+                        /* output invalid encoding as ASCII "?" */
+                        *thiswchar = L'?';
+                    }
+                    break;
+                default:        /* cannot happen because *str has MSB set */
+                    break;
+            }
+            /* output wide character if finished */
+            if (!*nmore) {
+                char mbstr[8];
+                int n_mbstr;
+
+                if (!consolecp)
+                    consolecp = GetConsoleOutputCP();
+                n_mbstr = WideCharToMultiByte(consolecp, 0, thiswchar, 1, mbstr, sizeof mbstr, NULL, NULL);
+                if (n_mbstr <= 0)
+                    fwrite("?", 1, 1, stdwr);
+                else
+                    fwrite(mbstr, 1, n_mbstr, stdwr);
+                *thiswchar = 0; /* cleanup */
+                str++, len--;
+                break;
+            }
+        }
+    }
+    fflush(stdwr);
+}
+
+static int
+gsdll_stdout_utf8(void *instance, const char *utf8str, int bytelen)
+{
+    static WCHAR thiswchar = 0; /* accumulates the bits from multiple encoding bytes */
+    static int nmore = 0;       /* expected number of additional encoding bytes */
+
+    gsdll_utf8write(stdout, utf8str, bytelen, &thiswchar, &nmore);
+    return bytelen;
+}
+
+static int
+gsdll_stderr_utf8(void *instance, const char *utf8str, int bytelen)
+{
+    static WCHAR thiswchar = 0; /* accumulates the bits from multiple encoding bytes */
+    static int nmore = 0;       /* expected number of additional encoding bytes */
+
+    gsdll_utf8write(stderr, utf8str, bytelen, &thiswchar, &nmore);
+    return bytelen;
+}
+#endif
+
 /*********************************************************************/
 
+#ifdef GS_NO_UTF8
 int main(int argc, char *argv[])
+#else
+/* porting from dwmainc.c */
+static int main_utf8(int argc, char *argv[])
+#endif
 {
     int exit_status;
     int code = 1, code1;
     void *instance;
     int exit_code;
 
+    if (!_isatty(fileno(stdin)))
+        _setmode(fileno(stdin), _O_BINARY);
+    _setmode(fileno(stdout), _O_BINARY);
+    _setmode(fileno(stderr), _O_BINARY);
+
     /* run Ghostscript */
     if ((code = gsapi_new_instance(&instance, NULL)) == 0) {
+#ifdef GS_NO_UTF8
         gsapi_set_stdio(instance, gsdll_stdin, gsdll_stdout, gsdll_stderr);
+#else
+        /* porting from dwmainc.c */
+        gsapi_set_stdio(instance,
+            _isatty(fileno(stdin)) ?  gsdll_stdin_utf8 : gsdll_stdin,
+            _isatty(fileno(stdout)) ?  gsdll_stdout_utf8 : gsdll_stdout,
+            _isatty(fileno(stderr)) ?  gsdll_stderr_utf8 : gsdll_stderr);
+#endif
         code = gsapi_init_with_args(instance, argc, argv);
 
         if (code == 0)
@@ -111,3 +291,52 @@
 
     return exit_status;
 }
+
+/* porting from dwmainc.c */
+#ifndef GS_NO_UTF8
+int wmain(int argc, wchar_t *argv[], wchar_t *envp[]) {
+    /* Duplicate args as utf8 */
+    char **nargv;
+    int i, code;
+
+    nargv = calloc(argc, sizeof(nargv[0]));
+    if (nargv == NULL)
+        goto err;
+    for (i=0; i < argc; i++) {
+        nargv[i] = malloc(wchar_to_utf8(NULL, argv[i]));
+        if (nargv[i] == NULL)
+            goto err;
+        (void)wchar_to_utf8(nargv[i], argv[i]);
+    }
+    code = main_utf8(argc, nargv);
+
+    if (0) {
+err:
+        fprintf(stderr,
+                "Ghostscript failed to initialise due to malloc failure\n");
+        code = -1;
+    }
+
+    if (nargv) {
+        for (i=0; i<argc; i++) {
+            free(nargv[i]);
+        }
+        free(nargv);
+    }
+
+    return code;
+}
+#endif
+
+/* for mingw non-unicode runtime */
+#ifndef GS_NO_UTF8
+int __wgetmainargs (int *c, wchar_t ***v, wchar_t ***e, int w, int *s);
+
+int main(int argc, wchar_t *argv[], wchar_t *envp[]) {
+    int wargc=0, si=0;
+    wchar_t **wargv, **wenvp;
+
+    __wgetmainargs (&wargc, &wargv, &wenvp, 1, &si);
+    return wmain(wargc, wargv, wenvp);
+}
+#endif