* elf.c (sym_is_global): Return a bfd_boolean.
[binutils.git] / libiberty / cygpath.c
blob2e7b4c9c9686e93ead6c97a1b0945bd1a48b8f7d
1 /* Support Cygwin paths under MinGW.
2 Copyright (C) 2006 Free Software Foundation, Inc.
3 Written by CodeSourcery.
5 This file is part of the libiberty library.
6 Libiberty is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Library General Public License as published
8 by the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 Libiberty is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with libiberty; see the file COPYING.LIB. If not, write
18 to the Free Software Foundation, Inc., 51 Franklin Street - Fifth
19 Floor, Boston, MA 02110-1301, USA. */
21 #include <windows.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <io.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include "libiberty.h"
32 /* If non-zero, we have attempted to use cygpath. CYGPATH_PEX may
33 still be NULL, if cygpath is unavailable. */
34 static int cygpath_initialized;
36 /* If non-NULL, an instance of cygpath connected via a pipe. */
37 static struct pex_obj *cygpath_pex;
39 /* The input to cygpath. */
40 static FILE *cygpath_in;
42 /* The output from cygpath. */
43 static FILE *cygpath_out;
45 /* CYG_PATH is a pointer to a Cygwin path. This function converts the
46 Cygwin path to a Windows path, storing the result in
47 WIN32_PATH. Returns true if the conversion was successful; false
48 otherwise. */
49 static bool
50 cygpath (const char *cyg_path, char win32_path[MAX_PATH + 1])
52 bool ok;
54 if (!cygpath_initialized)
56 const char *argv[] = { "cygpath", "-w", "-f", "-", NULL };
57 const char *cygpath_path;
58 int err;
60 /* If we are unable to invoke cygpath, we do not want to try
61 again. So, we set the initialized flag at this point; if
62 errors occur during the invocation, it will remain set. */
63 cygpath_initialized = 1;
64 /* Check to see if the user wants cygpath support. */
65 cygpath_path = getenv ("CYGPATH");
66 if (!cygpath_path)
67 /* The user doesn't need to support Cygwin paths. */
68 goto error;
69 /* If the environment variable is set to a non-empty string, use
70 that string as the path to cygpath. */
71 if (cygpath_path[0] != '\0')
72 argv[0] = cygpath_path;
73 /* Create the pex object. */
74 cygpath_pex = pex_init (PEX_SEARCH | PEX_USE_PIPES,
75 "cygpath", NULL);
76 if (!cygpath_pex)
77 goto error;
78 /* Get the FILE we will use to write to the child. */
79 cygpath_in = pex_write_input (cygpath_pex, /*binary=*/0);
80 if (!cygpath_in)
81 goto error;
82 /* Start the child process. */
83 if (pex_run (cygpath_pex, PEX_SEARCH | PEX_USE_PIPES,
84 argv[0], (char**) argv,
85 NULL, NULL,
86 &err) != NULL)
87 goto error;
88 /* Get the FILE we will use to read from the child. */
89 cygpath_out = pex_read_output (cygpath_pex, /*binary=*/1);
90 if (!cygpath_out)
91 goto error;
93 else if (!cygpath_pex)
94 /* We previously tried to use cygpath, but something went wrong. */
95 return false;
97 /* Write CYG_PATH to the child, on a line by itself. */
98 if (fprintf (cygpath_in, "%s\n", cyg_path) < 0)
99 goto error;
100 /* Flush the output. (We cannot set the stream into line-buffered
101 mode with setvbuf because Windows treats _IOLBF as a synonym for
102 _IOFBF.) */
103 fflush (cygpath_in);
104 /* Read the output. */
105 ok = true;
106 while (1)
108 size_t pathlen;
109 if (!fgets (win32_path, MAX_PATH, cygpath_out))
110 goto error;
111 pathlen = strlen (win32_path);
112 if (pathlen == 0 && ok)
113 /* This isn't a well-formed response from cygpath. */
114 goto error;
115 if (win32_path[pathlen - 1] == '\n')
117 win32_path[pathlen - 1] = '\0';
118 break;
120 /* We didn't reach the end of the line. There's no point in
121 trying to use this output, since we know the length of
122 paths are limited to MAX_PATH characters, but we read the
123 entire line so that we are still in sync with
124 cygpath. */
125 ok = false;
128 return ok;
130 error:
132 /* Free resources. */
133 if (cygpath_out)
135 fclose (cygpath_out);
136 cygpath_out = NULL;
138 if (cygpath_in)
140 fclose (cygpath_in);
141 cygpath_in = NULL;
143 if (cygpath_pex)
145 pex_free (cygpath_pex);
146 cygpath_pex = NULL;
149 return false;
152 /* Returns the handle for the MVCRT DLL, or NULL if it is not
153 available. */
154 static HANDLE
155 msvcrt_dll (void)
157 static HANDLE dll = INVALID_HANDLE_VALUE;
159 /* After we call LoadLibrary, DLL will be either a valid handle or
160 NULL, so this check ensures that we only try to load the library
161 once. */
162 if (dll == INVALID_HANDLE_VALUE)
163 dll = LoadLibrary ("msvcrt.dll");
165 return dll;
168 /* Call the underlying MSVCRT fopen with PATH and MODE, and return
169 what it returns. */
170 static FILE *
171 msvcrt_fopen (const char *path, const char *mode)
173 typedef FILE *(fopen_type)(const char *path,
174 const char *mode);
176 static fopen_type *f = NULL;
178 /* Get the address of "fopen". */
179 if (!f)
181 HANDLE dll = msvcrt_dll ();
182 if (!dll)
184 errno = ENOSYS;
185 return NULL;
187 f = (fopen_type *) GetProcAddress (dll, "fopen");
188 if (!f)
190 errno = ENOSYS;
191 return NULL;
195 /* Call fopen. */
196 return (*f)(path, mode);
199 FILE *
200 fopen (const char *path, const char *mode)
202 FILE *f;
203 char win32_path[MAX_PATH + 1];
205 /* Assume PATH is a Windows path. */
206 f = msvcrt_fopen (path, mode);
207 if (f || errno != ENOENT)
208 return f;
209 /* Perhaps it is a Cygwin path? */
210 if (cygpath (path, win32_path))
211 f = msvcrt_fopen (win32_path, mode);
212 return f;
215 int
216 open (const char *path, int oflag, ...)
218 int fd;
219 char win32_path[MAX_PATH + 1];
220 int pmode = 0;
222 if ((oflag & _O_CREAT))
224 va_list ap;
225 va_start (ap, oflag);
226 pmode = va_arg (ap, int);
227 va_end (ap);
230 /* Assume PATH is a Windows path. */
231 fd = _open (path, oflag, pmode);
232 if (fd != -1 || errno != ENOENT)
233 return fd;
234 /* Perhaps it is a Cygwin path? */
235 if (cygpath (path, win32_path))
236 fd = _open (win32_path, oflag, pmode);
237 return fd;
241 stat (const char *path, struct stat *buffer)
243 int r;
244 char win32_path[MAX_PATH + 1];
246 /* Assume PATH is a Windows path. */
247 r = _stat (path, (struct _stat *) buffer);
248 if (r != -1 || errno != ENOENT)
249 return r;
250 /* Perhaps it is a Cygwin path? */
251 if (cygpath (path, win32_path))
252 r = _stat (win32_path, (struct _stat *) buffer);
253 return r;
257 access (const char *path, int mode)
259 int r;
260 char win32_path[MAX_PATH + 1];
262 /* Assume PATH is a Windows path. */
263 r = _access (path, mode);
264 if (r != -1 || errno != ENOENT)
265 return r;
266 /* Perhaps it is a Cygwin path? */
267 if (cygpath (path, win32_path))
268 r = _access (win32_path, mode);
269 return r;