gettext: Sync with gettext 0.23.
[gnulib.git] / lib / windows-path.c
blobd238653fe17312048af439878844a2e832ebb856
1 /* Auxiliary functions for the creation of subprocesses on Windows.
2 Copyright (C) 2024 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2024.
5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
10 This file is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 #include <config.h>
20 /* Specification. */
21 #include "windows-path.h"
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
28 char *
29 extended_PATH (const char * const *dll_dirs)
31 /* Create a string PATH=(dll_dirs[0];dll_dirs[1];...;)old_PATH */
32 const char *old_PATH = getenv ("PATH");
33 if (old_PATH == NULL)
34 old_PATH = "";
35 size_t size;
37 size = 5;
39 size_t i;
40 for (i = 0; dll_dirs[i] != NULL; i++)
41 size += strlen (dll_dirs[i]) + 1;
43 size += strlen (old_PATH) + 1;
45 char *new_PATH = (char *) malloc (size);
46 if (new_PATH == NULL)
47 return NULL;
49 char *p = new_PATH;
51 memcpy (p, "PATH=", 5);
52 p += 5;
55 size_t i;
56 for (i = 0; dll_dirs[i] != NULL; i++)
58 size_t l = strlen (dll_dirs[i]);
59 memcpy (p, dll_dirs[i], l);
60 p += l;
61 #if defined _WIN32 && !defined __CYGWIN__
62 *p++ = ';';
63 #else
64 *p++ = ':';
65 #endif
69 size_t l = strlen (old_PATH);
70 memcpy (p, old_PATH, l);
71 p += l;
72 *p = '\0';
75 return new_PATH;
78 char **
79 extended_environ (const char * const *dll_dirs)
81 char *child_PATH = extended_PATH (dll_dirs);
82 if (child_PATH == NULL)
83 return NULL;
85 /* Create a shallow copy of environ, adding the child_PATH and removing
86 the original "PATH=..." string.
87 This is a bit hairy, because we don't have a lock that would prevent
88 other threads from making modifications in ENVP. So, just make sure
89 we don't crash; but if other threads are making modifications, part
90 of the result may be wrong. */
91 char **envp;
93 #if defined _WIN32 && !defined __CYGWIN__
94 envp = _environ;
95 #else
96 envp = environ;
97 #endif
99 retry:
101 /* Guess the size of the needed block of memory.
102 The guess will be exact if other threads don't make modifications. */
103 size_t size = 0;
105 char **ep;
106 char *p;
107 for (ep = envp; (p = *ep) != NULL; ep++)
108 if (strncmp (p, "PATH=", 5) != 0)
109 size += 1;
111 char **new_environ = (char **) malloc ((1 + size + 1) * sizeof (char *));
112 if (new_environ == NULL)
114 free (child_PATH);
115 errno = ENOMEM;
116 return NULL;
118 char **nep = new_environ;
119 *nep++ = child_PATH;
121 size_t i = 0;
122 char **ep;
123 char *p;
124 for (ep = envp; (p = *ep) != NULL; ep++)
125 if (strncmp (p, "PATH=", 5) != 0)
127 if (i == size)
129 /* Other threads did modifications. Restart. */
130 free (new_environ);
131 goto retry;
133 *nep++ = p;
134 i += 1;
136 if (i < size)
138 /* Other threads did modifications. Restart. */
139 free (new_environ);
140 goto retry;
143 *nep = NULL;
144 return new_environ;