This is the mail archive of the binutils@sourceware.cygnus.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

(patch) Windres use temp file as well as popen


Certain non-English versions of Win9x runtimes have buggy popen 
implementation, where stdout goes to the console instead of to
the pipe. This patch adds a new option, --use-temp-file, that
uses a temporary file instead to avoid that problem. The 
--no-use-temp-file option uses popen instead, which is the
default behavior.

This bug also shows up on "good" versions of Win9x that have 
certain Y2K patches applied, but we have yet to isolate exactly
which one causes it.

Note that method used to redirect to a temporary file may seem
odd (cf: resrc.c:run_cmd()), but we can't depend on fork on 
host, and this is what is used in parts of GCC as well for the 
same reason.

2000-01-03  Mumit Khan  <khan@xraylith.wisc.edu>

	* windres.c (long_options): Add --use-temp-file and 
	--no-use-temp-file options.
	(usage): Document.
	(main): Handle.
	* windres.h: Update read_rc_file prototype.
	* resrc.c (cpp_temp_file): New static variable.
	(istream_type): New static variable.
	(close_pipe): Delete function.
	(run_cmd): New static function.
	(open_input_stream): New static function.
	(close_input_stream): New static function.
	(look_for_default): Handle DOS directory separator. Use 
	open_input_stream instead of popen.
	(read_rc_file): Likewise.
	* binutils.texi: Document --use-temp-file, --no-use-temp-file options.

Index: windres.c
===================================================================
RCS file: /homes/khan/src/CVSROOT/binutils-19990911/binutils/windres.c,v
retrieving revision 1.1.1.1
diff -u -3 -p -r1.1.1.1 windres.c
--- windres.c	1999/12/23 07:19:35	1.1.1.1
+++ windres.c	2000/01/03 08:52:11
@@ -113,7 +113,9 @@ static struct include_dir *include_dirs;
 #define OPTION_INCLUDE_DIR (OPTION_HELP + 1)
 #define OPTION_LANGUAGE (OPTION_INCLUDE_DIR + 1)
 #define OPTION_PREPROCESSOR (OPTION_LANGUAGE + 1)
-#define OPTION_VERSION (OPTION_PREPROCESSOR + 1)
+#define OPTION_USE_TEMP_FILE (OPTION_PREPROCESSOR + 1)
+#define OPTION_NO_USE_TEMP_FILE (OPTION_USE_TEMP_FILE + 1)
+#define OPTION_VERSION (OPTION_NO_USE_TEMP_FILE + 1)
 #define OPTION_YYDEBUG (OPTION_VERSION + 1)
 
 static const struct option long_options[] =
@@ -126,6 +128,8 @@ static const struct option long_options[
   {"output-format", required_argument, 0, 'O'},
   {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
   {"target", required_argument, 0, 'F'},
+  {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
+  {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
   {"verbose", no_argument, 0, 'v'},
   {"version", no_argument, 0, OPTION_VERSION},
   {"yydebug", no_argument, 0, OPTION_YYDEBUG},
@@ -713,7 +717,10 @@ Options:\n\
   -DSYM[=VAL], --define SYM[=VAL]\n\
                               Define SYM when preprocessing rc file\n\
   -v                          Verbose - tells you what it's doing\n\
-  --language VAL              Set language when reading rc file\n"));
+  --language VAL              Set language when reading rc file\n\
+  --use-temp-file             Use a temporary file instead of popen to read\n\
+                              the preprocessor output\n\
+  --no-use-temp-file          Use popen (default)\n"));
 #ifdef YYDEBUG
   fprintf (stream, _("\
   --yydebug                   Turn on parser debugging\n"));
@@ -777,6 +784,7 @@ main (argc, argv)
   const char *quotedarg;
   int language;
   struct res_directory *resources;
+  int use_temp_file;
 
 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
   setlocale (LC_MESSAGES, "");
@@ -800,6 +808,7 @@ main (argc, argv)
   preprocessor = NULL;
   preprocargs = NULL;
   language = -1;
+  use_temp_file = 0;
 
   while ((c = getopt_long (argc, argv, "i:o:I:O:F:D:v", long_options,
 			   (int *) 0)) != EOF)
@@ -890,6 +899,14 @@ main (argc, argv)
 	  language = strtol (optarg, (char **) NULL, 16);
 	  break;
 
+	case OPTION_USE_TEMP_FILE:
+	  use_temp_file = 1;
+	  break;
+
+	case OPTION_NO_USE_TEMP_FILE:
+	  use_temp_file = 0;
+	  break;
+
 #ifdef YYDEBUG
 	case OPTION_YYDEBUG:
 	  yydebug = 1;
@@ -949,7 +966,7 @@ main (argc, argv)
       abort ();
     case RES_FORMAT_RC:
       resources = read_rc_file (input_filename, preprocessor, preprocargs,
-				language);
+				language, use_temp_file);
       break;
     case RES_FORMAT_RES:
       resources = read_res_file (input_filename);
Index: windres.h
===================================================================
RCS file: /homes/khan/src/CVSROOT/binutils-19990911/binutils/windres.h,v
retrieving revision 1.1.1.1
diff -u -3 -p -r1.1.1.1 windres.h
--- windres.h	1999/12/23 07:19:35	1.1.1.1
+++ windres.h	2000/01/03 06:28:19
@@ -747,7 +747,7 @@ extern int verbose;
 /* Function declarations.  */
 
 extern struct res_directory *read_rc_file
-  PARAMS ((const char *, const char *, const char *, int));
+  PARAMS ((const char *, const char *, const char *, int, int));
 extern struct res_directory *read_res_file PARAMS ((const char *));
 extern struct res_directory *read_coff_rsrc
   PARAMS ((const char *, const char *));
Index: resrc.c
===================================================================
RCS file: /homes/khan/src/CVSROOT/binutils-19990911/binutils/resrc.c,v
retrieving revision 1.3
diff -u -3 -p -r1.3 resrc.c
--- resrc.c	2000/01/03 06:27:50	1.3
+++ resrc.c	2000/01/03 08:56:43
@@ -29,9 +29,49 @@
 
 #include <assert.h>
 #include <ctype.h>
+#include <errno.h>
 #include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#else /* ! HAVE_SYS_WAIT_H */
+#if ! defined (_WIN32) || defined (__CYGWIN__)
+#ifndef WIFEXITED
+#define WIFEXITED(w)	(((w)&0377) == 0)
+#endif
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(w)	(((w)&0377) != 0177 && ((w)&~0377) == 0)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(w)	((w) & 0177)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(w)	(((w) >> 8) & 0377)
+#endif
+#else /* defined (_WIN32) && ! defined (__CYGWIN__) */
+#ifndef WIFEXITED
+#define WIFEXITED(w)	(((w) & 0xff) == 0)
+#endif
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(w)	(((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(w)	((w) & 0x7f)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(w)	(((w) & 0xff00) >> 8)
+#endif
+#endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
+#endif /* ! HAVE_SYS_WAIT_H */
 
-#if defined (_WIN32) && ! defined (__CYGWIN32__)
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+ 
+#if defined (_WIN32) && ! defined (__CYGWIN__)
 #define popen _popen
 #define pclose _pclose
 #endif
@@ -86,6 +126,15 @@ int rc_lineno;
 
 static FILE *cpp_pipe;
 
+/* The temporary file used if we're not using popen, so we can delete it
+   if we exit.  */
+
+static char *cpp_temp_file;
+
+/* Input stream is either a file or a pipe. */
+
+static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
+
 /* As we read the rc file, we attach information to this structure.  */
 
 static struct res_directory *resources;
@@ -112,9 +161,11 @@ static int icons;
 
 /* Local functions.  */
 
+static int run_cmd PARAMS ((char *, const char *));
+static FILE *open_input_stream PARAMS ((char *));
 static FILE *look_for_default PARAMS ((char *, const char *, int,
 				       const char *, const char *));
-static void close_pipe PARAMS ((void));
+static void close_input_stream PARAMS ((void));
 static void unexpected_eof PARAMS ((const char *));
 static int get_word PARAMS ((FILE *, const char *));
 static unsigned long get_long PARAMS ((FILE *, const char *));
@@ -122,6 +173,153 @@ static void get_data
   PARAMS ((FILE *, unsigned char *, unsigned long, const char *));
 static void define_fontdirs PARAMS ((void));
 
+
+/* Run `cmd' and redirect the output to `redir'. */
+
+static int
+run_cmd (cmd, redir)
+     char *cmd;
+     const char *redir;
+{
+  char *s;
+  int pid, wait_status, retcode;
+  int i;
+  const char **argv;
+  char *errmsg_fmt, *errmsg_arg;
+  char *temp_base = choose_temp_base ();
+  int in_quote;
+  char sep;
+  int redir_handle = -1;
+  int stdout_save = -1;
+
+  /* Count the args */
+  i = 0;
+  for (s = cmd; *s; s++)
+    if (*s == ' ')
+      i++;
+  i++;
+  argv = alloca (sizeof (char *) * (i + 3));
+  i = 0;
+  s = cmd;
+  while (1)
+    {
+      while (*s == ' ' && *s != 0)
+	s++;
+      if (*s == 0)
+	break;
+      in_quote = (*s == '\'' || *s == '"');
+      sep = (in_quote) ? *s++ : ' ';
+      argv[i++] = s;
+      while (*s != sep && *s != 0)
+	s++;
+      if (*s == 0)
+	break;
+      *s++ = 0;
+      if (in_quote)
+        s++;
+    }
+  argv[i++] = NULL;
+
+  /* setup the redirection. We can't use the usual fork/exec and redirect
+     since we may be running on non-POSIX Windows host. */
+
+  fflush (stdout);
+  fflush (stderr);
+
+  /* Open temporary output file.  */
+  redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+  if (redir_handle == -1)
+    fatal (_("can't open temporary file `%s': %s"), redir, 
+           strerror (errno));
+
+  /* Duplicate the stdout file handle so it can be restored later.  */
+  stdout_save = dup (STDOUT_FILENO);
+  if (stdout_save == -1)
+    fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
+
+  /* Redirect stdout to our output file.  */
+  dup2 (redir_handle, STDOUT_FILENO);
+
+  pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
+		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
+
+  /* Restore stdout to its previous setting.  */
+  dup2 (stdout_save, STDOUT_FILENO);
+
+  /* Close reponse file.  */
+  close (redir_handle);
+
+  if (pid == -1)
+    {
+      fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
+      return 1;
+    }
+
+  retcode = 0;
+  pid = pwait (pid, &wait_status, 0);
+  if (pid == -1)
+    {
+      fatal (_("wait: %s"), strerror (errno));
+      retcode = 1;
+    }
+  else if (WIFSIGNALED (wait_status))
+    {
+      fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
+      retcode = 1;
+    }
+  else if (WIFEXITED (wait_status))
+    {
+      if (WEXITSTATUS (wait_status) != 0)
+	{
+	  fatal (_("%s exited with status %d"), cmd, 
+	         WEXITSTATUS (wait_status));
+	  retcode = 1;
+	}
+    }
+  else
+    retcode = 1;
+  
+  return retcode;
+}
+
+static FILE *
+open_input_stream (cmd)
+     char *cmd;
+{
+  if (istream_type == ISTREAM_FILE)
+    {
+      char *fileprefix;
+
+      fileprefix = choose_temp_base ();
+      cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
+      sprintf (cpp_temp_file, "%s.irc", fileprefix);
+      free (fileprefix);
+
+      if (run_cmd (cmd, cpp_temp_file))
+	fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
+
+      cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
+      if (cpp_pipe == NULL)
+        fatal (_("can't open temporary file `%s': %s"), 
+	       cpp_temp_file, strerror (errno));
+      if (verbose)
+	fprintf (stderr, 
+	         _("Using temporary file `%s' to read preprocessor output\n"),
+		 cpp_temp_file);
+    }
+  else
+    {
+      cpp_pipe = popen (cmd, FOPEN_RT);
+      if (cpp_pipe == NULL)
+        fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
+      if (verbose)
+	fprintf (stderr, _("Using popen to read preprocessor output\n"));
+    }
+
+  xatexit (close_input_stream);
+  return cpp_pipe;
+}
+
 /* look for the preprocessor program */
 
 static FILE *
@@ -143,7 +341,11 @@ look_for_default (cmd, prefix, end_prefi
   if (space)
     *space = 0;
 
-  if (strchr (cmd, '/'))
+  if (
+#if defined(__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
+      strchr (cmd, '\\') ||
+#endif
+      strchr (cmd, '/'))
     {
       found = (stat (cmd, &s) == 0
 #ifdef HAVE_EXECUTABLE_SUFFIX
@@ -154,7 +356,7 @@ look_for_default (cmd, prefix, end_prefi
       if (! found)
 	{
 	  if (verbose)
-	    fprintf (stderr, "Tried `%s'\n", cmd);
+	    fprintf (stderr, _("Tried `%s'\n"), cmd);
 	  return NULL;
 	}
     }
@@ -165,23 +367,26 @@ look_for_default (cmd, prefix, end_prefi
 	   DEFAULT_PREPROCESSOR, preprocargs, filename);
 
   if (verbose)
-    fprintf (stderr, "Using `%s'\n", cmd);
+    fprintf (stderr, _("Using `%s'\n"), cmd);
 
-  cpp_pipe = popen (cmd, FOPEN_RT);
+  cpp_pipe = open_input_stream (cmd);
   return cpp_pipe;
 }
 
 /* Read an rc file.  */
 
 struct res_directory *
-read_rc_file (filename, preprocessor, preprocargs, language)
+read_rc_file (filename, preprocessor, preprocargs, language, use_temp_file)
      const char *filename;
      const char *preprocessor;
      const char *preprocargs;
      int language;
+     int use_temp_file;
 {
   char *cmd;
 
+  istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
+
   if (preprocargs == NULL)
     preprocargs = "";
   if (filename == NULL)
@@ -195,7 +400,7 @@ read_rc_file (filename, preprocessor, pr
 		     + 10);
       sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
 
-      cpp_pipe = popen (cmd, FOPEN_RT);
+      cpp_pipe = open_input_stream (cmd);
     }
   else
     {
@@ -219,7 +424,7 @@ read_rc_file (filename, preprocessor, pr
 	  if (*cp == '-')
 	    dash = cp;
 	  if (
-#if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
+#if defined(__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
 	      *cp == ':' || *cp == '\\' ||
 #endif
 	      *cp == '/')
@@ -257,12 +462,8 @@ read_rc_file (filename, preprocessor, pr
 	}
 
     }
-  if (cpp_pipe == NULL)
-    fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
   free (cmd);
 
-  xatexit (close_pipe);
-
   rc_filename = xstrdup (filename);
   rc_lineno = 1;
   if (language != -1)
@@ -270,9 +471,7 @@ read_rc_file (filename, preprocessor, pr
   yyin = cpp_pipe;
   yyparse ();
 
-  if (pclose (cpp_pipe) != 0)
-    fprintf (stderr, _("%s: warning: preprocessor failed\n"), program_name);
-  cpp_pipe = NULL;
+  close_input_stream ();
 
   if (fontdirs != NULL)
     define_fontdirs ();
@@ -283,13 +482,33 @@ read_rc_file (filename, preprocessor, pr
   return resources;
 }
 
-/* Close the pipe if it is open.  This is called via xatexit.  */
+/* Close the input stream if it is open.  */
 
-void
-close_pipe ()
+static void
+close_input_stream ()
 {
-  if (cpp_pipe != NULL)
-    pclose (cpp_pipe);
+  if (istream_type == ISTREAM_FILE)
+    {
+      if (cpp_pipe != NULL)
+	fclose (cpp_pipe);
+
+      if (cpp_temp_file != NULL)
+	{
+	  int errno_save = errno;
+	  unlink (cpp_temp_file);
+	  errno = errno_save;
+	  free (cpp_temp_file);
+	}
+    }
+  else
+    {
+      if (cpp_pipe != NULL)
+	pclose (cpp_pipe);
+    }
+
+  /* Since this is also run via xatexit, safeguard. */
+  cpp_pipe = NULL;
+  cpp_temp_file = NULL;
 }
 
 /* Report an error while reading an rc file.  */
@@ -307,7 +526,7 @@ void
 rcparse_warning (msg)
      const char *msg;
 {
-  fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
+  fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
 }
 
 /* Die if we get an unexpected end of file.  */
Index: binutils.texi
===================================================================
RCS file: /homes/khan/src/CVSROOT/binutils-19990911/binutils/binutils.texi,v
retrieving revision 1.1.1.1
diff -u -3 -p -r1.1.1.1 binutils.texi
--- binutils.texi	1999/12/23 07:19:35	1.1.1.1
+++ binutils.texi	2000/01/03 06:37:00
@@ -2104,6 +2104,17 @@ Specify the default language to use when
 @var{val} should be a hexadecimal language code.  The low eight bits are
 the language, and the high eight bits are the sublanguage.
 
+@item --use-temp-file
+Use a temporary file to instead of using popen to read the output of
+the preprocessor. Use this option if the popen implementation is buggy 
+on the host (eg., certain non-English language versions of Windows 95 and 
+Windows 98 are known to have buggy popen where the output will instead
+go the console).
+
+@item --no-use-temp-file
+Use popen, not a temporary file, to read the output of the preprocessor.
+This is the default behaviour.
+
 @item --help
 Prints a usage summary.
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]