delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2009/08/13/10:25:25

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 <bruno AT clisp DOT org>
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
Message-Id: <200908131624.31681.bruno@clisp.org>
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
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 <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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019