X-Recipient: archive-cygwin AT delorie DOT com X-SWARE-Spam-Status: No, hits=-1.4 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_21 X-Spam-Check-By: sourceware.org X-RZG-AUTH: :Ln4Re0+Ic/6oZXR1YgKryK8brksyK8dozXDwHXjf9hj/zDNRavQ46ybK X-RZG-CLASS-ID: mo00 From: Bruno Haible To: cygwin AT cygwin DOT com Subject: how to pass non-ASCII environment variable values to cygwin programs? Date: Thu, 13 Aug 2009 16:24:31 +0200 User-Agent: KMail/1.9.9 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200908131624.31681.bruno@clisp.org> Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com Hi, I'm trying to pass non-ASCII strings as environment variable values from one program to another. It does not work when a mingw program invokes a cygwin program, but works when the caller is a cygwin program or the callee is a mingw program. Cygwin in use is 1.5.25, on Windows XP. How to reproduce: Save these two files. ================================== caller.c ================================== #include #include #include #include extern char **environ; int main () { char *argv[4]; putenv ("VARIABLE=Oc\xe9"); printf ("Output from caller program:\n"); printf ("ANSI codepage = CP%d, OEM codepage = CP%d\n", GetACP(), GetOEMCP()); { const char *v = getenv ("VARIABLE"); if (v != NULL) { printf ("env: "); while (*v) { printf (" %02X", (unsigned char)*v); v++; } printf ("\n"); } } { char buf[10]; if (GetEnvironmentVariableA ("VARIABLE", buf, 10)) { const char *v = buf; printf ("Env: "); while (*v) { printf (" %02X", (unsigned char)*v); v++; } printf ("\n"); } } #ifndef __CYGWIN__ { const wchar_t *w = _wgetenv (L"VARIABLE"); if (w != NULL) { printf ("wenv:"); while (*w) { printf (" %04X", (unsigned short)*w); w++; } printf ("\n"); } } #endif { wchar_t buf[10]; if (GetEnvironmentVariableW (L"VARIABLE", buf, 10)) { const wchar_t *w = buf; printf ("WEnv:"); while (*w) { printf (" %04X", (unsigned short)*w); w++; } printf ("\n"); } } printf ("\n"); fflush (stdout); argv[0] = "./callee-mingw.exe"; argv[1] = NULL; spawnvpe (_P_WAIT, argv[0], (const char **) argv, (const char **) environ); argv[0] = "./callee-cygwin.exe"; argv[1] = NULL; spawnvpe (_P_WAIT, argv[0], (const char **) argv, (const char **) environ); return 0; } ================================== callee.c ================================== #include #include #include int main (int argc, char* argv[]) { #ifdef __MINGW32__ printf("Output from the callee, compiled as a mingw program:\n"); #endif #ifdef __CYGWIN__ printf("Output from the callee, compiled as a cygwin program:\n"); #endif { const char *v = getenv ("VARIABLE"); if (v != NULL) { printf ("env: "); while (*v) { printf (" %02X", (unsigned char)*v); v++; } printf ("\n"); } } { char buf[10]; if (GetEnvironmentVariableA ("VARIABLE", buf, 10)) { const char *v = buf; printf ("Env: "); while (*v) { printf (" %02X", (unsigned char)*v); v++; } printf ("\n"); } } #ifndef __CYGWIN__ { const wchar_t *w = _wgetenv (L"VARIABLE"); if (w != NULL) { printf ("wenv:"); while (*w) { printf (" %04X", (unsigned short)*w); w++; } printf ("\n"); } } #endif { wchar_t buf[10]; if (GetEnvironmentVariableW (L"VARIABLE", buf, 10)) { const wchar_t *w = buf; printf ("WEnv:"); while (*w) { printf (" %04X", (unsigned short)*w); w++; } printf ("\n"); } } printf ("\n"); fflush (stdout); return 0; } ============================================================================== $ gcc -O -Wall caller.c -o caller-cygwin.exe $ gcc -mno-cygwin -O -Wall caller.c -o caller-mingw.exe $ gcc -O -Wall callee.c -o callee-cygwin.exe $ gcc -mno-cygwin -O -Wall callee.c -o callee-mingw.exe Then execute the caller: $ ./caller-cygwin.exe Output from caller program: ANSI codepage = CP1252, OEM codepage = CP850 env: 4F 63 E9 Output from the callee, compiled as a mingw program: env: 4F 63 E9 Env: 4F 63 E9 wenv: 004F 0063 00E9 WEnv: 004F 0063 00E9 Output from the callee, compiled as a cygwin program: env: 4F 63 E9 $ ./caller-mingw.exe Output from caller program: ANSI codepage = CP1252, OEM codepage = CP850 env: 4F 63 E9 Env: 4F 63 E9 wenv: 004F 0063 00E9 WEnv: 004F 0063 00E9 Output from the callee, compiled as a mingw program: env: 4F 63 E9 Env: 4F 63 E9 wenv: 004F 0063 00E9 WEnv: 004F 0063 00E9 Output from the callee, compiled as a cygwin program: env: 4F 63 82 Env: 4F 63 E9 WEnv: 004F 0063 00E9 You can see that when the caller is mingw-compiled and the callee is cygwin-compiled, getenv("VARIABLE") returns a string that has been converted to CP850 (which is the OEM codepage) instead of CP1252 (which is the ANSI codepage). (U+00E9 = LATIN SMALL LETTER E WITH ACUTE is 0xE9 in CP1252 but 0x82 in CP850.) Whereas GetEnvironmentVariableA returns the correct value in CP1252. But that does not help me much, because the desired callee is Cygwin's /usr/bin/sh.exe, which happens to use getenv(), not GetEnvironmentVariableA(). How can I pass non-ASCII strings from a mingw program so that Cygwin programs see the right value through getenv()? Just speculating: Could this be due to the use of the function GetEnvironmentStrings() in winsup/cygwin/environ.cc? Note that the Microsoft doc says: "Note that the ANSI version of this function, GetEnvironmentStringsA, returns OEM characters." Bruno -- Problem reports: http://cygwin.com/problems.html FAQ: http://cygwin.com/faq/ Documentation: http://cygwin.com/docs.html Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple