This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

how to pass non-ASCII environment variable values to cygwin programs?


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 <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
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 <stdio.h>
#include <stdlib.h>
#include <windows.h>
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 <http://msdn.microsoft.com/en-us/library/ms683187(VS.85).aspx>
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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]