From f42addf3b2116842dc11f454dd78f594b4b47913 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Mon, 7 Oct 2024 20:10:16 +0200 Subject: [PATCH] cygpath: New module. * lib/cygpath.h: New file. * lib/cygpath.c: New file, based on lib/javaversion.c. * modules/cygpath: New file. --- ChangeLog | 7 +++ lib/cygpath.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/cygpath.h | 37 +++++++++++ modules/cygpath | 25 ++++++++ 4 files changed, 232 insertions(+) create mode 100644 lib/cygpath.c create mode 100644 lib/cygpath.h create mode 100644 modules/cygpath diff --git a/ChangeLog b/ChangeLog index a02498949a..dfcf07b30d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2024-10-07 Bruno Haible + + cygpath: New module. + * lib/cygpath.h: New file. + * lib/cygpath.c: New file, based on lib/javaversion.c. + * modules/cygpath: New file. + 2024-10-06 Bruno Haible javacomp, javaversion: Fix resource leak. diff --git a/lib/cygpath.c b/lib/cygpath.c new file mode 100644 index 0000000000..7461706089 --- /dev/null +++ b/lib/cygpath.c @@ -0,0 +1,163 @@ +/* Convert file names between Cygwin syntax and Windows syntax. + Copyright (C) 2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Bruno Haible , 2024. */ + +#include + +/* Specification. */ +#include "cygpath.h" + +#include + +#include "xalloc.h" +#include "gettext.h" + +#define _(str) gettext (str) + +#ifdef __CYGWIN__ + +/* Since Cygwin has its own notion of mount points (which can be defined by the + user), it would be wrong to blindly convert '/cygdrive/c/foo' to 'C:\foo'. + We really need to use the Cygwin API or the 'cygpath' program. */ + +# include +# include + +# if 1 + +/* Documentation: + https://cygwin.com/cygwin-api/func-cygwin-conv-path.html */ + +# include + +char * +cygpath_w (const char *filename) +{ + int repeat; + + /* Try several times, since there is a small time window during which the + size returned by the previous call may not be sufficient, namely when a + directory gets renamed. */ + for (repeat = 3; repeat > 0; repeat--) + { + ssize_t size = cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, filename, NULL, 0); + if (size < 0) + error (EXIT_FAILURE, errno, _("cannot convert file name '%s' to Windows syntax"), filename); + char *result = (char *) xmalloc (size); + if (cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, filename, result, size) == 0) + return result; + free (result); + } + error (EXIT_FAILURE, errno, _("cygwin_conv_path failed")); + return NULL; +} + +# else +/* Alternative implementation (slower) */ + +/* Documentation: + https://cygwin.com/cygwin-ug-net/cygpath.html */ + +# include + +# include "spawn-pipe.h" +# include "wait-process.h" + +/* Executes a program. + Returns the first line of its output, as a freshly allocated string, or + NULL. */ +static char * +execute_and_read_line (const char *progname, + const char *prog_path, const char * const *prog_argv) +{ + pid_t child; + int fd[1]; + FILE *fp; + char *line; + size_t linesize; + size_t linelen; + + /* Open a pipe to the program. */ + child = create_pipe_in (progname, prog_path, prog_argv, NULL, + DEV_NULL, false, true, false, fd); + + if (child == -1) + return NULL; + + /* Retrieve its result. */ + fp = fdopen (fd[0], "r"); + if (fp == NULL) + error (EXIT_FAILURE, errno, _("fdopen() failed")); + + line = NULL; linesize = 0; + linelen = getline (&line, &linesize, fp); + if (linelen == (size_t)(-1)) + { + error (0, 0, _("%s subprocess I/O error"), progname); + fclose (fp); + wait_subprocess (child, progname, true, false, true, false, NULL); + } + else + { + int exitstatus; + + if (linelen > 0 && line[linelen - 1] == '\n') + line[linelen - 1] = '\0'; + + /* Read until EOF (otherwise the child process may get a SIGPIPE signal). */ + while (getc (fp) != EOF) + ; + + fclose (fp); + + /* Remove zombie process from process list, and retrieve exit status. */ + exitstatus = + wait_subprocess (child, progname, true, false, true, false, NULL); + if (exitstatus == 0) + return line; + } + free (line); + return NULL; +} + +char * +cygpath_w (const char *filename) +{ + const char *argv[4]; + + argv[0] = "cygpath"; + argv[1] = "-w"; + argv[2] = filename; + argv[3] = NULL; + + char *line = execute_and_read_line ("cygpath", "cygpath", argv); + if (line == NULL || line[0] == '\0') + error (EXIT_FAILURE, 0, _("%s invocation failed"), "cygpath"); + return line; +} + +# endif + +#else + +char * +cygpath_w (const char *filename) +{ + return xstrdup (filename); +} + +#endif diff --git a/lib/cygpath.h b/lib/cygpath.h new file mode 100644 index 0000000000..0843347f7a --- /dev/null +++ b/lib/cygpath.h @@ -0,0 +1,37 @@ +/* Convert file names between Cygwin syntax and Windows syntax. + Copyright (C) 2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Bruno Haible , 2024. */ + +#ifndef _CYGPATH_H +#define _CYGPATH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* On Cygwin, this function converts a file name from Cygwin syntax to + native Windows syntax, like 'cygpath -w' does. + Returns a freshly allocated file name. + On the other platforms, it returns a freshly allocated copy of the + argument file name. */ +extern char *cygpath_w (const char *filename); + +#ifdef __cplusplus +} +#endif + +#endif /* _CYGPATH_H */ diff --git a/modules/cygpath b/modules/cygpath new file mode 100644 index 0000000000..dc48848a98 --- /dev/null +++ b/modules/cygpath @@ -0,0 +1,25 @@ +Description: +Convert file names between Cygwin syntax and Windows syntax. + +Files: +lib/cygpath.h +lib/cygpath.c + +Depends-on: +xalloc +free-posix +gettext-h + +configure.ac: + +Makefile.am: +lib_SOURCES += cygpath.c + +Include: +"cygpath.h" + +License: +GPL + +Maintainer: +all -- 2.39.5