OSDN Git Service

* cygheap.cc (cygheap_init): Default locale.charset to "UTF-8".
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / environ.cc
1 /* environ.cc: Cygwin-adopted functions from newlib to manipulate
2    process's environment.
3
4    Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5    2006, 2007, 2008, 2009 Red Hat, Inc.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include "winsup.h"
12 #include <stdlib.h>
13 #include <wchar.h>
14 #include <wctype.h>
15 #include <ctype.h>
16 #include <locale.h>
17 #include <assert.h>
18 #include <cygwin/version.h>
19 #include <winnls.h>
20 #include "pinfo.h"
21 #include "perprocess.h"
22 #include "path.h"
23 #include "cygerrno.h"
24 #include "fhandler.h"
25 #include "dtable.h"
26 #include "cygheap.h"
27 #include "cygtls.h"
28 #include "tls_pbuf.h"
29 #include "registry.h"
30 #include "environ.h"
31 #include "child_info.h"
32
33 extern bool dos_file_warning;
34 extern bool ignore_case_with_glob;
35 extern bool allow_winsymlinks;
36 bool reset_com = false;
37 static bool envcache = true;
38 static bool create_upcaseenv = false;
39
40 static char **lastenviron;
41
42 /* Helper functions for the below environment variables which have to
43    be converted Win32<->POSIX. */
44 extern "C" ssize_t env_PATH_to_posix (const void *, void *, size_t);
45
46 ssize_t
47 env_plist_to_posix (const void *win32, void *posix, size_t size)
48 {
49   return cygwin_conv_path_list (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, win32,
50                                 posix, size);
51 }
52
53 ssize_t
54 env_plist_to_win32 (const void *posix, void *win32, size_t size)
55 {
56   return cygwin_conv_path_list (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, posix,
57                                 win32, size);
58 }
59
60 ssize_t
61 env_path_to_posix (const void *win32, void *posix, size_t size)
62 {
63   return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, win32,
64                            posix, size);
65 }
66
67 ssize_t
68 env_path_to_win32 (const void *posix, void *win32, size_t size)
69 {
70   return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, posix,
71                            win32, size);
72 }
73
74 #define ENVMALLOC \
75   (CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \
76           <= CYGWIN_VERSION_DLL_MALLOC_ENV)
77
78 #define NL(x) x, (sizeof (x) - 1)
79 /* List of names which are converted from dos to unix
80    on the way in and back again on the way out.
81
82    PATH needs to be here because CreateProcess uses it and gdb uses
83    CreateProcess.  HOME is here because most shells use it and would be
84    confused by Windows style path names.  */
85 static win_env conv_envvars[] =
86   {
87     {NL ("PATH="), NULL, NULL, env_PATH_to_posix, env_plist_to_win32, true},
88     {NL ("HOME="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
89     {NL ("LD_LIBRARY_PATH="), NULL, NULL,
90                                env_plist_to_posix, env_plist_to_win32, true},
91     {NL ("TMPDIR="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
92     {NL ("TMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
93     {NL ("TEMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
94     {NULL, 0, NULL, NULL, 0, 0}
95   };
96
97 static unsigned char conv_start_chars[256] = {0};
98
99 struct win_env&
100 win_env::operator = (struct win_env& x)
101 {
102   name = x.name;
103   namelen = x.namelen;
104   toposix = x.toposix;
105   towin32 = x.towin32;
106   immediate = false;
107   return *this;
108 }
109
110 win_env::~win_env ()
111 {
112   if (posix)
113     free (posix);
114   if (native)
115     free (native);
116 }
117
118 void
119 win_env::add_cache (const char *in_posix, const char *in_native)
120 {
121   MALLOC_CHECK;
122   posix = (char *) realloc (posix, strlen (in_posix) + 1);
123   strcpy (posix, in_posix);
124   if (in_native)
125     {
126       native = (char *) realloc (native, namelen + 1 + strlen (in_native));
127       strcpy (native, name);
128       strcpy (native + namelen, in_native);
129     }
130   else
131     {
132       tmp_pathbuf tp;
133       char *buf = tp.c_get ();
134       strcpy (buf, name + namelen);
135       towin32 (in_posix, buf, NT_MAX_PATH);
136       native = (char *) realloc (native, namelen + 1 + strlen (buf));
137       strcpy (native, name);
138       strcpy (native + namelen, buf);
139     }
140   MALLOC_CHECK;
141   if (immediate && cygwin_finished_initializing)
142     {
143       char s[namelen];
144       size_t n = namelen - 1;
145       memcpy (s, name, n);
146       s[n] = '\0';
147       SetEnvironmentVariable (s, native + namelen);
148     }
149   debug_printf ("posix %s", posix);
150   debug_printf ("native %s", native);
151 }
152
153
154 /* Check for a "special" environment variable name.  *env is the pointer
155   to the beginning of the environment variable name.  *in_posix is any
156   known posix value for the environment variable. Returns a pointer to
157   the appropriate conversion structure.  */
158 win_env * __stdcall
159 getwinenv (const char *env, const char *in_posix, win_env *temp)
160 {
161   if (!conv_start_chars[(unsigned char)*env])
162     return NULL;
163
164   for (int i = 0; conv_envvars[i].name != NULL; i++)
165     if (strncmp (env, conv_envvars[i].name, conv_envvars[i].namelen) == 0)
166       {
167         win_env *we = conv_envvars + i;
168         const char *val;
169         if (!cur_environ () || !(val = in_posix ?: getenv (we->name)))
170           debug_printf ("can't set native for %s since no environ yet",
171                         we->name);
172         else if (!envcache || !we->posix || strcmp (val, we->posix) != 0)
173           {
174             if (temp)
175               {
176                 *temp = *we;
177                 we = temp;
178               }
179             we->add_cache (val);
180           }
181         return we;
182       }
183   return NULL;
184 }
185
186 /* Convert windows path specs to POSIX, if appropriate.
187  */
188 static void __stdcall
189 posify (char **here, const char *value, char *outenv)
190 {
191   char *src = *here;
192   win_env *conv;
193
194   if (!(conv = getwinenv (src)))
195     return;
196
197   int len = strcspn (src, "=") + 1;
198
199   /* Turn all the items from c:<foo>;<bar> into their
200      mounted equivalents - if there is one.  */
201
202   memcpy (outenv, src, len);
203   char *newvalue = outenv + len;
204   if (!conv->toposix (value, newvalue, NT_MAX_PATH - len)
205       || _impure_ptr->_errno != EIDRM)
206     conv->add_cache (newvalue, *value != '/' ? value : NULL);
207   else
208     {
209       /* The conversion routine removed elements from a path list so we have
210          to recalculate the windows path to remove elements there, too. */
211       char cleanvalue[strlen (value) + 1];
212       conv->towin32 (newvalue, cleanvalue, sizeof cleanvalue);
213       conv->add_cache (newvalue, cleanvalue);
214     }
215
216   debug_printf ("env var converted to %s", outenv);
217   *here = strdup (outenv);
218   free (src);
219   MALLOC_CHECK;
220 }
221
222 /* Returns pointer to value associated with name, if any, else NULL.
223   Sets offset to be the offset of the name/value combination in the
224   environment array, for use by setenv(3) and unsetenv(3).
225   Explicitly removes '=' in argument name.  */
226
227 static char * __stdcall
228 my_findenv (const char *name, int *offset)
229 {
230   register int len;
231   register char **p;
232   const char *c;
233
234   c = name;
235   len = 0;
236   while (*c && *c != '=')
237     {
238       c++;
239       len++;
240     }
241
242   for (p = cur_environ (); *p; ++p)
243     if (!strncmp (*p, name, len))
244       if (*(c = *p + len) == '=')
245         {
246           *offset = p - cur_environ ();
247           return (char *) (++c);
248         }
249   MALLOC_CHECK;
250   return NULL;
251 }
252
253 /* Primitive getenv before the environment is built.  */
254
255 static char __stdcall *
256 getearly (const char * name, int *)
257 {
258   char *ret;
259   char **ptr;
260   int len;
261
262   if (spawn_info && (ptr = spawn_info->moreinfo->envp))
263     {
264       len = strlen (name);
265       for (; *ptr; ptr++)
266         if (strncasematch (name, *ptr, len) && (*ptr)[len] == '=')
267           return *ptr + len + 1;
268     }
269   else if ((len = GetEnvironmentVariableA (name, NULL, 0))
270            && (ret = (char *) cmalloc_abort (HEAP_2_STR, len))
271            && GetEnvironmentVariableA (name, ret, len))
272     return ret;
273
274   return NULL;
275 }
276
277 static char * (*findenv_func)(const char *, int *) = (char * (*)(const char *, int *)) getearly;
278
279 /* Returns ptr to value associated with name, if any, else NULL.  */
280
281 extern "C" char *
282 getenv (const char *name)
283 {
284   int offset;
285   return findenv_func (name, &offset);
286 }
287
288 /* This function is required so that newlib uses the same environment
289    as Cygwin. */
290 extern "C" char *
291 _getenv_r (struct _reent *, const char *name)
292 {
293   int offset;
294   return findenv_func (name, &offset);
295 }
296
297 static int __stdcall
298 envsize (const char * const *in_envp)
299 {
300   const char * const *envp;
301   for (envp = in_envp; *envp; envp++)
302     continue;
303   return (1 + envp - in_envp) * sizeof (const char *);
304 }
305
306 /* Takes similar arguments to setenv except that overwrite is
307    either -1, 0, or 1.  0 or 1 signify that the function should
308    perform similarly to setenv.  Otherwise putenv is assumed. */
309 static int __stdcall
310 _addenv (const char *name, const char *value, int overwrite)
311 {
312   int issetenv = overwrite >= 0;
313   int offset;
314   char *p;
315
316   unsigned int valuelen = strlen (value);
317   if ((p = my_findenv (name, &offset)))
318     {                           /* Already exists. */
319       if (!overwrite)           /* Ok to overwrite? */
320         return 0;               /* No.  Wanted to add new value.  FIXME: Right return value? */
321
322       /* We've found the offset into environ.  If this is a setenv call and
323          there is room in the current environment entry then just overwrite it.
324          Otherwise handle this case below. */
325       if (issetenv && strlen (p) >= valuelen)
326         {
327           strcpy (p, value);
328           return 0;
329         }
330     }
331   else
332     {                           /* Create new slot. */
333       int sz = envsize (cur_environ ());
334       int allocsz = sz + (2 * sizeof (char *));
335
336       offset = (sz - 1) / sizeof (char *);
337
338       /* Allocate space for additional element plus terminating NULL. */
339       if (cur_environ () == lastenviron)
340         lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
341                                                             allocsz);
342       else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
343         __cygwin_environ = (char **) memcpy ((char **) lastenviron,
344                                              __cygwin_environ, sz);
345
346       if (!__cygwin_environ)
347         {
348 #ifdef DEBUGGING
349           try_to_debug ();
350 #endif
351           return -1;                            /* Oops.  No more memory. */
352         }
353
354       __cygwin_environ[offset + 1] = NULL;      /* NULL terminate. */
355       update_envptrs ();        /* Update any local copies of 'environ'. */
356     }
357
358   char *envhere;
359   if (!issetenv)
360     /* Not setenv. Just overwrite existing. */
361     envhere = cur_environ ()[offset] = (char *) (ENVMALLOC ? strdup (name) : name);
362   else
363     {                           /* setenv */
364       /* Look for an '=' in the name and ignore anything after that if found. */
365       for (p = (char *) name; *p && *p != '='; p++)
366         continue;
367
368       int namelen = p - name;   /* Length of name. */
369       /* Allocate enough space for name + '=' + value + '\0' */
370       envhere = cur_environ ()[offset] = (char *) malloc (namelen + valuelen + 2);
371       if (!envhere)
372         return -1;              /* Oops.  No more memory. */
373
374       /* Put name '=' value into current slot. */
375       strncpy (envhere, name, namelen);
376       envhere[namelen] = '=';
377       strcpy (envhere + namelen + 1, value);
378     }
379
380   /* Update cygwin's cache, if appropriate */
381   win_env *spenv;
382   if ((spenv = getwinenv (envhere)))
383     spenv->add_cache (value);
384
385   MALLOC_CHECK;
386   return 0;
387 }
388
389 /* Set an environment variable */
390 extern "C" int
391 putenv (char *str)
392 {
393   myfault efault;
394   if (efault.faulted (EFAULT))
395     return -1;
396   if (*str)
397     {
398       char *eq = strchr (str, '=');
399       if (eq)
400         return _addenv (str, eq + 1, -1);
401
402       /* Remove str from the environment. */
403       unsetenv (str);
404     }
405   return 0;
406 }
407
408 /* Set the value of the environment variable "name" to be
409    "value".  If overwrite is set, replace any current value.  */
410 extern "C" int
411 setenv (const char *name, const char *value, int overwrite)
412 {
413   myfault efault;
414   if (efault.faulted (EFAULT))
415     return -1;
416   if (!*name)
417     return 0;
418   if (*value == '=')
419     value++;
420   return _addenv (name, value, !!overwrite);
421 }
422
423 /* Delete environment variable "name".  */
424 extern "C" int
425 unsetenv (const char *name)
426 {
427   register char **e;
428   int offset;
429   myfault efault;
430   if (efault.faulted () || *name == '\0' || strchr (name, '='))
431     {
432       set_errno (EINVAL);
433       return -1;
434     }
435
436   while (my_findenv (name, &offset))    /* if set multiple times */
437     /* Move up the rest of the array */
438     for (e = cur_environ () + offset; ; e++)
439       if (!(*e = *(e + 1)))
440         break;
441
442   return 0;
443 }
444
445 /* Minimal list of Windows vars which must be converted to uppercase.
446    Either for POSIX compatibility of for backward compatibility with
447    existing applications. */
448 static struct renv {
449         const char *name;
450         const size_t namelen;
451 } renv_arr[] = {
452         { NL("ALLUSERSPROFILE=") },             // 0
453         { NL("COMMONPROGRAMFILES=") },          // 1
454         { NL("COMPUTERNAME=") },
455         { NL("COMSPEC=") },
456         { NL("HOME=") },                        // 4
457         { NL("HOMEDRIVE=") },
458         { NL("HOMEPATH=") },
459         { NL("NUMBER_OF_PROCESSORS=") },        // 7
460         { NL("OS=") },                          // 8
461         { NL("PATH=") },                        // 9
462         { NL("PATHEXT=") },
463         { NL("PROCESSOR_ARCHITECTURE=") },
464         { NL("PROCESSOR_IDENTIFIER=") },
465         { NL("PROCESSOR_LEVEL=") },
466         { NL("PROCESSOR_REVISION=") },
467         { NL("PROGRAMFILES=") },
468         { NL("SYSTEMDRIVE=") },                 // 16
469         { NL("SYSTEMROOT=") },
470         { NL("TEMP=") },                        // 18
471         { NL("TERM=") },
472         { NL("TMP=") },
473         { NL("TMPDIR=") },
474         { NL("WINDIR=") }                       // 22
475 };
476 #define RENV_SIZE (sizeof (renv_arr) / sizeof (renv_arr[0]))
477 /* Set of first characters of the above list of variables. */
478 static const char idx_arr[] = "ACHNOPSTW";
479 /* Index into renv_arr at which the variables with this specific character
480    starts. */
481 static const int start_at[] = { 0, 1, 4, 7, 8, 9, 16, 18, 22 };
482
483 /* Turn environment variable part of a=b string into uppercase.
484    Conditionally controlled by upcaseenv CYGWIN setting.  */
485 static __inline__ void
486 ucenv (char *p, const char *eq)
487 {
488   if (create_upcaseenv)
489     {
490       /* Amazingly, NT has a case sensitive environment name list,
491          but only sometimes.
492          It's normal to have NT set your "Path" to something.
493          Later, you set "PATH" to something else.  This alters "Path".
494          But if you try and do a naive getenv on "PATH" you'll get nothing.
495
496          So we upper case the labels here to prevent confusion later but
497          we only do it for processes that are started by non-Cygwin programs. */
498       for (; p < eq; p++)
499         if (islower (*p))
500           *p = cyg_toupper (*p);
501     }
502   else
503     {
504       /* Hopefully as quickly as possible - only upcase specific set of important
505          Windows variables. */
506       char first = cyg_toupper (*p);
507       const char *idx = strchr (idx_arr, first);
508       if (idx)
509         for (size_t i = start_at[idx - idx_arr];
510              i < RENV_SIZE && renv_arr[i].name[0] == first;
511              ++i)
512           if (strncasematch (p, renv_arr[i].name, renv_arr[i].namelen))
513             {
514               strncpy (p, renv_arr[i].name, renv_arr[i].namelen);
515               break;
516             }
517     }
518 }
519
520 /* Parse CYGWIN options */
521
522 static NO_COPY bool export_settings = false;
523
524 enum settings
525   {
526     justset,
527     isfunc,
528     setbit,
529     set_process_state,
530   };
531
532 /* When BUF is:
533    null or empty: disables globbing
534    "ignorecase": enables case-insensitive globbing
535    anything else: enables case-sensitive globbing */
536 static void
537 glob_init (const char *buf)
538 {
539   if (!buf || !*buf)
540     {
541       allow_glob = false;
542       ignore_case_with_glob = false;
543     }
544   else if (ascii_strncasematch (buf, "ignorecase", 10))
545     {
546       allow_glob = true;
547       ignore_case_with_glob = true;
548     }
549   else
550     {
551       allow_glob = true;
552       ignore_case_with_glob = false;
553     }
554 }
555
556 static void
557 set_chunksize (const char *buf)
558 {
559   wincap.set_chunksize (strtoul (buf, NULL, 0));
560 }
561
562 static void
563 set_proc_retry (const char *buf)
564 {
565   child_info::retry_count = strtoul (buf, NULL, 0);
566 }
567
568 /* The structure below is used to set up an array which is used to
569    parse the CYGWIN environment variable or, if enabled, options from
570    the registry.  */
571 static struct parse_thing
572   {
573     const char *name;
574     union parse_setting
575       {
576         bool *b;
577         DWORD *x;
578         int *i;
579         void (*func)(const char *);
580       } setting;
581
582     enum settings disposition;
583     char *remember;
584     union parse_values
585       {
586         DWORD i;
587         const char *s;
588       } values[2];
589   } known[] NO_COPY =
590 {
591   {"dosfilewarning", {&dos_file_warning}, justset, NULL, {{false}, {true}}},
592   {"envcache", {&envcache}, justset, NULL, {{true}, {false}}},
593   {"error_start", {func: &error_start_init}, isfunc, NULL, {{0}, {0}}},
594   {"export", {&export_settings}, justset, NULL, {{false}, {true}}},
595   {"forkchunk", {func: set_chunksize}, isfunc, NULL, {{0}, {0}}},
596   {"glob", {func: &glob_init}, isfunc, NULL, {{0}, {s: "normal"}}},
597   {"proc_retry", {func: set_proc_retry}, isfunc, NULL, {{0}, {5}}},
598   {"reset_com", {&reset_com}, justset, NULL, {{false}, {true}}},
599   {"strip_title", {&strip_title_path}, justset, NULL, {{false}, {true}}},
600   {"title", {&display_title}, justset, NULL, {{false}, {true}}},
601   {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}},
602   {"upcaseenv", {&create_upcaseenv}, justset, NULL, {{false}, {true}}},
603   {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}},
604   {NULL, {0}, justset, 0, {{0}, {0}}}
605 };
606
607 /* Parse a string of the form "something=stuff somethingelse=more-stuff",
608    silently ignoring unknown "somethings".  */
609 static void __stdcall
610 parse_options (char *buf)
611 {
612   int istrue;
613   char *p, *lasts;
614   parse_thing *k;
615
616   if (buf == NULL)
617     {
618       tmp_pathbuf tp;
619       char *newbuf = tp.c_get ();
620       newbuf[0] = '\0';
621       for (k = known; k->name != NULL; k++)
622         if (k->remember)
623           {
624             strcat (strcat (newbuf, " "), k->remember);
625             free (k->remember);
626             k->remember = NULL;
627           }
628
629       if (export_settings)
630         {
631           debug_printf ("%s", newbuf + 1);
632           setenv ("CYGWIN", newbuf + 1, 1);
633         }
634       return;
635     }
636
637   buf = strcpy ((char *) alloca (strlen (buf) + 1), buf);
638   for (p = strtok_r (buf, " \t", &lasts);
639        p != NULL;
640        p = strtok_r (NULL, " \t", &lasts))
641     {
642       char *keyword_here = p;
643       if (!(istrue = !ascii_strncasematch (p, "no", 2)))
644         p += 2;
645       else if (!(istrue = *p != '-'))
646         p++;
647
648       char ch, *eq;
649       if ((eq = strchr (p, '=')) != NULL || (eq = strchr (p, ':')) != NULL)
650         ch = *eq, *eq++ = '\0';
651       else
652         ch = 0;
653
654       for (parse_thing *k = known; k->name != NULL; k++)
655         if (ascii_strcasematch (p, k->name))
656           {
657             switch (k->disposition)
658               {
659               case isfunc:
660                 k->setting.func ((!eq || !istrue) ?
661                   k->values[istrue].s : eq);
662                 debug_printf ("%s (called func)", k->name);
663                 break;
664               case justset:
665                 if (!istrue || !eq)
666                   *k->setting.x = k->values[istrue].i;
667                 else
668                   *k->setting.x = strtol (eq, NULL, 0);
669                 debug_printf ("%s %d", k->name, *k->setting.x);
670                 break;
671               case set_process_state:
672                 k->setting.x = &myself->process_state;
673                 /* fall through */
674               case setbit:
675                 *k->setting.x &= ~k->values[istrue].i;
676                 if (istrue || (eq && strtol (eq, NULL, 0)))
677                   *k->setting.x |= k->values[istrue].i;
678                 debug_printf ("%s %x", k->name, *k->setting.x);
679                 break;
680               }
681
682             if (eq)
683               *--eq = ch;
684
685             int n = eq - p;
686             p = strdup (keyword_here);
687             if (n > 0)
688               p[n] = ':';
689             k->remember = p;
690             break;
691           }
692       }
693   debug_printf ("returning");
694 }
695
696 /* Set options from the registry. */
697 static bool __stdcall
698 regopt (const char *name, char *buf)
699 {
700   bool parsed_something = false;
701   char lname[strlen (name) + 1];
702   strlwr (strcpy (lname, name));
703
704   for (int i = 0; i < 2; i++)
705     {
706       reg_key r (i, KEY_READ, CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL);
707
708       if (r.get_string (lname, buf, NT_MAX_PATH, "") == ERROR_SUCCESS)
709         {
710           parse_options (buf);
711           parsed_something = true;
712           break;
713         }
714     }
715
716   MALLOC_CHECK;
717   return parsed_something;
718 }
719
720 /* Initialize the environ array.  Look for the CYGWIN environment
721    environment variable and set appropriate options from it.  */
722 void
723 environ_init (char **envp, int envc)
724 {
725   PWCHAR rawenv, w;
726   int i;
727   char *p;
728   char *newp;
729   int sawTERM = 0;
730   bool envp_passed_in;
731   bool got_something_from_registry;
732   static char NO_COPY cygterm[] = "TERM=cygwin";
733   myfault efault;
734   tmp_pathbuf tp;
735
736   if (efault.faulted ())
737     api_fatal ("internal error reading the windows environment - too many environment variables?");
738
739   if (!conv_start_chars[0])
740     for (int i = 0; conv_envvars[i].name != NULL; i++)
741       {
742         conv_start_chars[(int) cyg_tolower (conv_envvars[i].name[0])] = 1;
743         conv_start_chars[(int) cyg_toupper (conv_envvars[i].name[0])] = 1;
744       }
745
746   char *tmpbuf = tp.t_get ();
747   got_something_from_registry = regopt ("default", tmpbuf);
748   if (myself->progname[0])
749     got_something_from_registry = regopt (myself->progname, tmpbuf)
750                                   || got_something_from_registry;
751
752   if (!envp)
753     envp_passed_in = 0;
754   else
755     {
756       envc++;
757       envc *= sizeof (char *);
758       char **newenv = (char **) malloc (envc);
759       memcpy (newenv, envp, envc);
760       cfree (envp);
761
762       /* Older applications relied on the fact that cygwin malloced elements of the
763          environment list.  */
764       envp = newenv;
765       if (ENVMALLOC)
766         for (char **e = newenv; *e; e++)
767           {
768             char *p = *e;
769             *e = strdup (p);
770             cfree (p);
771           }
772       envp_passed_in = 1;
773       goto out;
774     }
775
776   /* Allocate space for environment + trailing NULL + CYGWIN env. */
777   lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *));
778
779   /* We also need the CYGWIN variable early to know the value of the
780      CYGWIN=upcaseenv setting for the below loop. */
781   if ((i = GetEnvironmentVariableA ("CYGWIN", NULL, 0)))
782     {
783       char *buf = (char *) alloca (i);
784       GetEnvironmentVariableA ("CYGWIN", buf, i);
785       parse_options (buf);
786     }
787
788   rawenv = GetEnvironmentStringsW ();
789   if (!rawenv)
790     {
791       system_printf ("GetEnvironmentStrings returned NULL, %E");
792       return;
793     }
794   debug_printf ("GetEnvironmentStrings returned %p", rawenv);
795
796   /* Current directory information is recorded as variables of the
797      form "=X:=X:\foo\bar; these must be changed into something legal
798      (we could just ignore them but maybe an application will
799      eventually want to use them).  */
800   for (i = 0, w = rawenv; *w != L'\0'; w = wcschr (w, L'\0') + 1, i++)
801     {
802       sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w);
803       if (i >= envc)
804         envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *));
805       envp[i] = newp;
806       if (*newp == '=')
807         *newp = '!';
808       char *eq = strechr (newp, '=');
809       ucenv (newp, eq); /* (possibly conditionally) uppercase env vars. */
810       if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0)
811         sawTERM = 1;
812       if (*eq && conv_start_chars[(unsigned char) envp[i][0]])
813         posify (envp + i, *++eq ? eq : --eq, tmpbuf);
814       debug_printf ("%p: %s", envp[i], envp[i]);
815     }
816
817   if (!sawTERM)
818     envp[i++] = strdup (cygterm);
819   envp[i] = NULL;
820   FreeEnvironmentStringsW (rawenv);
821
822 out:
823   findenv_func = (char * (*)(const char*, int*)) my_findenv;
824   __cygwin_environ = envp;
825   update_envptrs ();
826   if (envp_passed_in)
827     {
828       p = getenv ("CYGWIN");
829       if (p)
830         parse_options (p);
831     }
832
833   if (got_something_from_registry)
834     parse_options (NULL);       /* possibly export registry settings to
835                                    environment */
836   MALLOC_CHECK;
837 }
838
839 /* Function called by qsort to sort environment strings.  */
840 static int
841 env_sort (const void *a, const void *b)
842 {
843   const char **p = (const char **) a;
844   const char **q = (const char **) b;
845
846   return strcmp (*p, *q);
847 }
848
849 char * __stdcall
850 getwinenveq (const char *name, size_t namelen, int x)
851 {
852   WCHAR name0[namelen - 1];
853   WCHAR valbuf[32768]; /* Max size of an env.var including trailing '\0'. */
854
855   name0[sys_mbstowcs (name0, sizeof name0, name, namelen - 1)] = L'\0';
856   int totlen = GetEnvironmentVariableW (name0, valbuf, 32768);
857   if (totlen > 0)
858     {
859       totlen = sys_wcstombs (NULL, 0, valbuf);
860       if (x == HEAP_1_STR)
861         totlen += namelen;
862       else
863         namelen = 0;
864       char *p = (char *) cmalloc_abort ((cygheap_types) x, totlen);
865       if (namelen)
866         strcpy (p, name);
867       sys_wcstombs (p + namelen, totlen, valbuf);
868       debug_printf ("using value from GetEnvironmentVariable for '%W'", name0);
869       return p;
870     }
871
872   debug_printf ("warning: %s not present in environment", name);
873   return NULL;
874 }
875
876 struct spenv
877 {
878   const char *name;
879   size_t namelen;
880   bool force_into_environment;  /* If true, always add to env if missing */
881   bool add_if_exists;           /* if true, retrieve value from cache */
882   const char * (cygheap_user::*from_cygheap) (const char *, size_t);
883
884   char *retrieve (bool, const char * const = NULL)
885     __attribute__ ((regparm (3)));
886 };
887
888 #define env_dontadd almost_null
889
890 /* Keep this list in upper case and sorted */
891 static NO_COPY spenv spenvs[] =
892 {
893 #ifdef DEBUGGING
894   {NL ("CYGWIN_DEBUG="), false, true, NULL},
895 #endif
896   {NL ("HOMEDRIVE="), false, false, &cygheap_user::env_homedrive},
897   {NL ("HOMEPATH="), false, false, &cygheap_user::env_homepath},
898   {NL ("LOGONSERVER="), false, false, &cygheap_user::env_logsrv},
899   {NL ("PATH="), false, true, NULL},
900   {NL ("SYSTEMDRIVE="), false, true, NULL},
901   {NL ("SYSTEMROOT="), true, true, &cygheap_user::env_systemroot},
902   {NL ("USERDOMAIN="), false, false, &cygheap_user::env_domain},
903   {NL ("USERNAME="), false, false, &cygheap_user::env_name},
904   {NL ("USERPROFILE="), false, false, &cygheap_user::env_userprofile},
905   {NL ("WINDIR="), true, true, &cygheap_user::env_systemroot}
906 };
907
908 char *
909 spenv::retrieve (bool no_envblock, const char *const env)
910 {
911   if (env && !ascii_strncasematch (env, name, namelen))
912     return NULL;
913
914   debug_printf ("no_envblock %d", no_envblock);
915
916   if (from_cygheap)
917     {
918       const char *p;
919       if (env && !cygheap->user.issetuid ())
920         {
921           debug_printf ("duping existing value for '%s'", name);
922           /* Don't really care what it's set to if we're calling a cygwin program */
923           return cstrdup1 (env);
924         }
925
926       /* Calculate (potentially) value for given environment variable.  */
927       p = (cygheap->user.*from_cygheap) (name, namelen);
928       if (!p || (no_envblock && !env) || (p == env_dontadd))
929         return env_dontadd;
930       char *s = (char *) cmalloc_abort (HEAP_1_STR, namelen + strlen (p) + 1);
931       strcpy (s, name);
932       strcpy (s + namelen, p);
933       debug_printf ("using computed value for '%s'", name);
934       return s;
935     }
936
937   if (env)
938     return cstrdup1 (env);
939
940   return getwinenveq (name, namelen, HEAP_1_STR);
941 }
942
943 #define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
944
945 /* Create a Windows-style environment block, i.e. a typical character buffer
946    filled with null terminated strings, terminated by double null characters.
947    Converts environment variables noted in conv_envvars into win32 form
948    prior to placing them in the string.  */
949 char ** __stdcall
950 build_env (const char * const *envp, PWCHAR &envblock, int &envc,
951            bool no_envblock)
952 {
953   int len, n;
954   const char * const *srcp;
955   char **dstp;
956   bool saw_spenv[SPENVS_SIZE] = {0};
957
958   debug_printf ("envp %p", envp);
959
960   /* How many elements? */
961   for (n = 0; envp[n]; n++)
962     continue;
963
964   /* Allocate a new "argv-style" environ list with room for extra stuff. */
965   char **newenv = (char **) cmalloc_abort (HEAP_1_ARGV, sizeof (char *) *
966                                      (n + SPENVS_SIZE + 1));
967
968   int tl = 0;
969   char **pass_dstp;
970   char **pass_env = (char **) alloca (sizeof (char *) * (n + SPENVS_SIZE + 1));
971   /* Iterate over input list, generating a new environment list and refreshing
972      "special" entries, if necessary. */
973   for (srcp = envp, dstp = newenv, pass_dstp = pass_env; *srcp; srcp++)
974     {
975       bool calc_tl = !no_envblock;
976       /* Look for entries that require special attention */
977       for (unsigned i = 0; i < SPENVS_SIZE; i++)
978         if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp)))
979           {
980             saw_spenv[i] = 1;
981             if (*dstp == env_dontadd)
982               goto next1;
983             if (spenvs[i].add_if_exists)
984               calc_tl = true;
985             goto  next0;
986           }
987
988       /* Add entry to new environment */
989       *dstp = cstrdup1 (*srcp);
990
991     next0:
992       if (calc_tl)
993         {
994           *pass_dstp++ = *dstp;
995           tl += strlen (*dstp) + 1;
996         }
997       dstp++;
998     next1:
999       continue;
1000     }
1001
1002   assert ((srcp - envp) == n);
1003   /* Fill in any required-but-missing environment variables. */
1004   for (unsigned i = 0; i < SPENVS_SIZE; i++)
1005     if (!saw_spenv[i] && (spenvs[i].force_into_environment || cygheap->user.issetuid ()))
1006       {
1007           *dstp = spenvs[i].retrieve (false);
1008           if (*dstp && *dstp != env_dontadd)
1009             {
1010               *pass_dstp++ = *dstp;
1011               tl += strlen (*dstp) + 1;
1012               dstp++;
1013             }
1014         }
1015
1016   envc = dstp - newenv;         /* Number of entries in newenv */
1017   assert ((size_t) envc <= (n + SPENVS_SIZE));
1018   *dstp = NULL;                 /* Terminate */
1019
1020   size_t pass_envc = pass_dstp - pass_env;
1021   if (!pass_envc)
1022     envblock = NULL;
1023   else
1024     {
1025       *pass_dstp = NULL;
1026       debug_printf ("env count %d, bytes %d", pass_envc, tl);
1027       win_env temp;
1028       temp.reset ();
1029
1030       /* Windows programs expect the environment block to be sorted.  */
1031       qsort (pass_env, pass_envc, sizeof (char *), env_sort);
1032
1033       /* Create an environment block suitable for passing to CreateProcess.  */
1034       PWCHAR s;
1035       envblock = (PWCHAR) malloc ((2 + tl) * sizeof (WCHAR));
1036       int new_tl = 0;
1037       for (srcp = pass_env, s = envblock; *srcp; srcp++)
1038         {
1039           const char *p;
1040           win_env *conv;
1041           len = strcspn (*srcp, "=") + 1;
1042           const char *rest = *srcp + len;
1043
1044           /* Check for a bad entry.  This is necessary to get rid of empty
1045              strings, induced by putenv and changing the string afterwards.
1046              Note that this doesn't stop invalid strings without '=' in it
1047              etc., but we're opting for speed here for now.  Adding complete
1048              checking would be pretty expensive. */
1049           if (len == 1 || !*rest)
1050             continue;
1051
1052           /* See if this entry requires posix->win32 conversion. */
1053           conv = getwinenv (*srcp, rest, &temp);
1054           if (conv)
1055             p = conv->native;   /* Use win32 path */
1056           else
1057             p = *srcp;          /* Don't worry about it */
1058
1059           len = sys_mbstowcs (NULL, 0, p);
1060           new_tl += len;        /* Keep running total of block length so far */
1061
1062           /* See if we need to increase the size of the block. */
1063           if (new_tl > tl)
1064             {
1065               tl = new_tl + 100;
1066               PWCHAR new_envblock =
1067                         (PWCHAR) realloc (envblock, (2 + tl) * sizeof (WCHAR));
1068               /* If realloc moves the block, move `s' with it. */
1069               if (new_envblock != envblock)
1070                 {
1071                   s += new_envblock - envblock;
1072                   envblock = new_envblock;
1073                 }
1074             }
1075
1076           int slen = sys_mbstowcs (s, len, p);
1077
1078           /* See if environment variable is "special" in a Windows sense.
1079              Under NT, the current directories for visited drives are stored
1080              as =C:=\bar.  Cygwin converts the '=' to '!' for hopefully obvious
1081              reasons.  We need to convert it back when building the envblock */
1082           if (s[0] == L'!' && (iswdrive (s + 1) || (s[1] == L':' && s[2] == L':'))
1083               && s[3] == L'=')
1084             *s = L'=';
1085           s += slen + 1;
1086         }
1087       *s = L'\0';                       /* Two null bytes at the end */
1088       assert ((s - envblock) <= tl);    /* Detect if we somehow ran over end
1089                                            of buffer */
1090     }
1091
1092   debug_printf ("envp %p, envc %d", newenv, envc);
1093   return newenv;
1094 }
1095
1096 /* This idiocy is necessary because the early implementers of cygwin
1097    did not seem to know about importing data variables from the DLL.
1098    So, we have to synchronize cygwin's idea of the environment with the
1099    main program's with each reference to the environment. */
1100 extern "C" char ** __stdcall
1101 cur_environ ()
1102 {
1103   if (*main_environ != __cygwin_environ)
1104     {
1105       __cygwin_environ = *main_environ;
1106       update_envptrs ();
1107     }
1108
1109   return __cygwin_environ;
1110 }