(linenum→info "unix/slp.c:2238")

binutils/2.18/binutils/resrc.c

    1: /* resrc.c -- read and write Windows rc files.
    2:    Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007
    3:    Free Software Foundation, Inc.
    4:    Written by Ian Lance Taylor, Cygnus Support.
    5:    Rewritten by Kai Tietz, Onevision.
    6: 
    7:    This file is part of GNU Binutils.
    8: 
    9:    This program is free software; you can redistribute it and/or modify
   10:    it under the terms of the GNU General Public License as published by
   11:    the Free Software Foundation; either version 3 of the License, or
   12:    (at your option) any later version.
   13: 
   14:    This program is distributed in the hope that it will be useful,
   15:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   16:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17:    GNU General Public License for more details.
   18: 
   19:    You should have received a copy of the GNU General Public License
   20:    along with this program; if not, write to the Free Software
   21:    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
   22:    02110-1301, USA.  */
   23: 
   24: /* This file contains functions that read and write Windows rc files.
   25:    These are text files that represent resources.  */
   26: 
   27: #include "sysdep.h"
   28: #include "bfd.h"
   29: #include "bucomm.h"
   30: #include "libiberty.h"
   31: #include "safe-ctype.h"
   32: #include "windres.h"
   33: 
   34: #include <assert.h>
   35: #include <errno.h>
   36: #include <sys/stat.h>
   37: #ifdef HAVE_UNISTD_H
   38: #include <unistd.h>
   39: #endif
   40: 
   41: #ifdef HAVE_SYS_WAIT_H
   42: #include <sys/wait.h>
   43: #else /* ! HAVE_SYS_WAIT_H */
   44: #if ! defined (_WIN32) || defined (__CYGWIN__)
   45: #ifndef WIFEXITED
   46: #define WIFEXITED(w)    (((w)&0377) == 0)
   47: #endif
   48: #ifndef WIFSIGNALED
   49: #define WIFSIGNALED(w)  (((w)&0377) != 0177 && ((w)&~0377) == 0)
   50: #endif
   51: #ifndef WTERMSIG
   52: #define WTERMSIG(w)     ((w) & 0177)
   53: #endif
   54: #ifndef WEXITSTATUS
   55: #define WEXITSTATUS(w)  (((w) >> 8) & 0377)
   56: #endif
   57: #else /* defined (_WIN32) && ! defined (__CYGWIN__) */
   58: #ifndef WIFEXITED
   59: #define WIFEXITED(w)    (((w) & 0xff) == 0)
   60: #endif
   61: #ifndef WIFSIGNALED
   62: #define WIFSIGNALED(w)  (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
   63: #endif
   64: #ifndef WTERMSIG
   65: #define WTERMSIG(w)     ((w) & 0x7f)
   66: #endif
   67: #ifndef WEXITSTATUS
   68: #define WEXITSTATUS(w)  (((w) & 0xff00) >> 8)
   69: #endif
   70: #endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
   71: #endif /* ! HAVE_SYS_WAIT_H */
   72: 
   73: #ifndef STDOUT_FILENO
   74: #define STDOUT_FILENO 1
   75: #endif
   76: 
   77: #if defined (_WIN32) && ! defined (__CYGWIN__)
   78: #define popen _popen
   79: #define pclose _pclose
   80: #endif
   81: 
   82: /* The default preprocessor.  */
   83: 
   84: #define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
   85: 
   86: /* We read the directory entries in a cursor or icon file into
   87:    instances of this structure.  */
   88: 
   89: struct icondir
   90: {
   91:   /* Width of image.  */
   92:   bfd_byte width;
   93:   /* Height of image.  */
   94:   bfd_byte height;
   95:   /* Number of colors in image.  */
   96:   bfd_byte colorcount;
   97:   union
   98:   {
   99:     struct
  100:     {
  101:       /* Color planes.  */
  102:       unsigned short planes;
  103:       /* Bits per pixel.  */
  104:       unsigned short bits;
  105:     } icon;
  106:     struct
  107:     {
  108:       /* X coordinate of hotspot.  */
  109:       unsigned short xhotspot;
  110:       /* Y coordinate of hotspot.  */
  111:       unsigned short yhotspot;
  112:     } cursor;
  113:   } u;
  114:   /* Bytes in image.  */
  115:   unsigned long bytes;
  116:   /* File offset of image.  */
  117:   unsigned long offset;
  118: };
  119: 
  120: /* The name of the rc file we are reading.  */
  121: 
  122: char *rc_filename;
  123: 
  124: /* The line number in the rc file.  */
  125: 
  126: int rc_lineno;
  127: 
  128: /* The pipe we are reading from, so that we can close it if we exit.  */
  129: 
  130: FILE *cpp_pipe;
  131: 
  132: /* The temporary file used if we're not using popen, so we can delete it
  133:    if we exit.  */
  134: 
  135: static char *cpp_temp_file;
  136: 
  137: /* Input stream is either a file or a pipe.  */
  138: 
  139: static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
  140: 
  141: /* As we read the rc file, we attach information to this structure.  */
  142: 
  143: static rc_res_directory *resources;
  144: 
  145: /* The number of cursor resources we have written out.  */
  146: 
  147: static int cursors;
  148: 
  149: /* The number of font resources we have written out.  */
  150: 
  151: static int fonts;
  152: 
  153: /* Font directory information.  */
  154: 
  155: rc_fontdir *fontdirs;
  156: 
  157: /* Resource info to use for fontdirs.  */
  158: 
  159: rc_res_res_info fontdirs_resinfo;
  160: 
  161: /* The number of icon resources we have written out.  */
  162: 
  163: static int icons;
  164: 
  165: /* The windres target bfd .  */
  166: 
  167: static windres_bfd wrtarget =
  168: {
  169:   (bfd *) NULL, (asection *) NULL, WR_KIND_TARGET
  170: };
  171: 
  172: /* Local functions for rcdata based resource definitions.  */
  173: 
  174: static void define_font_rcdata (rc_res_id, const rc_res_res_info *,
  175:                                 rc_rcdata_item *);
  176: static void define_icon_rcdata (rc_res_id, const rc_res_res_info *,
  177:                                 rc_rcdata_item *);
  178: static void define_bitmap_rcdata (rc_res_id, const rc_res_res_info *,
  179:                                   rc_rcdata_item *);
  180: static void define_cursor_rcdata (rc_res_id, const rc_res_res_info *,
  181:                                   rc_rcdata_item *);
  182: static void define_fontdir_rcdata (rc_res_id, const rc_res_res_info *,
  183:                                    rc_rcdata_item *);
  184: static void define_messagetable_rcdata (rc_res_id, const rc_res_res_info *,
  185:                                         rc_rcdata_item *);
  186: static rc_uint_type rcdata_copy (const rc_rcdata_item *, bfd_byte *);
  187: static bfd_byte *rcdata_render_as_buffer (const rc_rcdata_item *, rc_uint_type *);
  188: 
  189: static int run_cmd (char *, const char *);
  190: static FILE *open_input_stream (char *);
  191: static FILE *look_for_default
  192:   (char *, const char *, int, const char *, const char *);
  193: static void close_input_stream (void);
  194: static void unexpected_eof (const char *);
  195: static int get_word (FILE *, const char *);
  196: static unsigned long get_long (FILE *, const char *);
  197: static void get_data (FILE *, bfd_byte *, rc_uint_type, const char *);
  198: static void define_fontdirs (void);
  199: ^L
  200: /* Run `cmd' and redirect the output to `redir'.  */
  201: 
  202: static int
  203: run_cmd (char *cmd, const char *redir)
  204: {
  205:   char *s;
  206:   int pid, wait_status, retcode;
  207:   int i;
  208:   const char **argv;
  209:   char *errmsg_fmt, *errmsg_arg;
  210:   char *temp_base = choose_temp_base ();
  211:   int in_quote;
  212:   char sep;
  213:   int redir_handle = -1;
  214:   int stdout_save = -1;
  215: 
  216:   /* Count the args.  */
  217:   i = 0;
  218: 
  219:   for (s = cmd; *s; s++)
  220:     if (*s == ' ')
  221:       i++;
  222: 
  223:   i++;
  224:   argv = alloca (sizeof (char *) * (i + 3));
  225:   i = 0;
  226:   s = cmd;
  227: 
  228:   while (1)
  229:     {
  230:       while (*s == ' ' && *s != 0)
  231:         s++;
  232: 
  233:       if (*s == 0)
  234:         break;
  235: 
  236:       in_quote = (*s == '\'' || *s == '"');
  237:       sep = (in_quote) ? *s++ : ' ';
  238:       argv[i++] = s;
  239: 
  240:       while (*s != sep && *s != 0)
  241:         s++;
  242: 
  243:       if (*s == 0)
  244:         break;
  245: 
  246:       *s++ = 0;
  247: 
  248:       if (in_quote)
  249:         s++;
  250:     }
  251:   argv[i++] = NULL;
  252: 
  253:   /* Setup the redirection.  We can't use the usual fork/exec and redirect
  254:      since we may be running on non-POSIX Windows host.  */
  255: 
  256:   fflush (stdout);
  257:   fflush (stderr);
  258: 
  259:   /* Open temporary output file.  */
  260:   redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
  261:   if (redir_handle == -1)
  262:     fatal (_("can't open temporary file `%s': %s"), redir,
  263:            strerror (errno));
  264: 
  265:   /* Duplicate the stdout file handle so it can be restored later.  */
  266:   stdout_save = dup (STDOUT_FILENO);
  267:   if (stdout_save == -1)
  268:     fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
  269: 
  270:   /* Redirect stdout to our output file.  */
  271:   dup2 (redir_handle, STDOUT_FILENO);
  272: 
  273:   pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
  274:                   &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
  275: 
  276:   /* Restore stdout to its previous setting.  */
  277:   dup2 (stdout_save, STDOUT_FILENO);
  278: 
  279:   /* Close response file.  */
  280:   close (redir_handle);
  281: 
  282:   if (pid == -1)
  283:     {
  284:       fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
  285:       return 1;
  286:     }
  287: 
  288:   retcode = 0;
  289:   pid = pwait (pid, &wait_status, 0);
  290: 
  291:   if (pid == -1)
  292:     {
  293:       fatal (_("wait: %s"), strerror (errno));
  294:       retcode = 1;
  295:     }
  296:   else if (WIFSIGNALED (wait_status))
  297:     {
  298:       fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
  299:       retcode = 1;
  300:     }
  301:   else if (WIFEXITED (wait_status))
  302:     {
  303:       if (WEXITSTATUS (wait_status) != 0)
  304:         {
  305:           fatal (_("%s exited with status %d"), cmd,
  306:                  WEXITSTATUS (wait_status));
  307:           retcode = 1;
  308:         }
  309:     }
  310:   else
  311:     retcode = 1;
  312: 
  313:   return retcode;
  314: }
  315: 
  316: static FILE *
  317: open_input_stream (char *cmd)
  318: {
  319:   if (istream_type == ISTREAM_FILE)
  320:     {
  321:       char *fileprefix;
  322: 
  323:       fileprefix = choose_temp_base ();
  324:       cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
  325:       sprintf (cpp_temp_file, "%s.irc", fileprefix);
  326:       free (fileprefix);
  327: 
  328:       if (run_cmd (cmd, cpp_temp_file))
  329:         fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
  330: 
  331:       cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
  332:       if (cpp_pipe == NULL)
  333:         fatal (_("can't open temporary file `%s': %s"),
  334:                cpp_temp_file, strerror (errno));
  335: 
  336:       if (verbose)
  337:         fprintf (stderr,
  338:                  _("Using temporary file `%s' to read preprocessor output\n"),
  339:                  cpp_temp_file);
  340:     }
  341:   else
  342:     {
  343:       cpp_pipe = popen (cmd, FOPEN_RT);
  344:       if (cpp_pipe == NULL)
  345:         fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
  346:       if (verbose)
  347:         fprintf (stderr, _("Using popen to read preprocessor output\n"));
  348:     }
  349: 
  350:   xatexit (close_input_stream);
  351:   return cpp_pipe;
  352: }
  353: 
  354: /* Determine if FILENAME contains special characters that
  355:    can cause problems unless the entire filename is quoted.  */
  356: 
  357: static int
  358: filename_need_quotes (const char *filename)
  359: {
  360:   if (filename == NULL || (filename[0] == '-' && filename[1] == 0))
  361:     return 0;
  362: 
  363:   while (*filename != 0)
  364:     {
  365:       switch (*filename)
  366:         {
  367:         case '&':
  368:         case ' ':
  369:         case '<':
  370:         case '>':
  371:         case '|':
  372:         case '%':
  373:           return 1;
  374:         }
  375:       ++filename;
  376:     }
  377:   return 0;
  378: }
  379: 
  380: /* Look for the preprocessor program.  */
  381: 
  382: static FILE *
  383: look_for_default (char *cmd, const char *prefix, int end_prefix,
  384:                   const char *preprocargs, const char *filename)
  385: {
  386:   char *space;
  387:   int found;
  388:   struct stat s;
  389:   const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
  390: 
  391:   strcpy (cmd, prefix);
  392: 
  393:   sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
  394:   space = strchr (cmd + end_prefix, ' ');
  395:   if (space)
  396:     *space = 0;
  397: 
  398:   if (
  399: #if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
  400:       strchr (cmd, '\\') ||
  401: #endif
  402:       strchr (cmd, '/'))
  403:     {
  404:       found = (stat (cmd, &s) == 0
  405: #ifdef HAVE_EXECUTABLE_SUFFIX
  406:                || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
  407: #endif
  408:                );
  409: 
  410:       if (! found)
  411:         {
  412:           if (verbose)
  413:             fprintf (stderr, _("Tried `%s'\n"), cmd);
  414:           return NULL;
  415:         }
  416:     }
  417: 
  418:   strcpy (cmd, prefix);
  419: 
  420:   sprintf (cmd + end_prefix, "%s %s %s%s%s",
  421:            DEFAULT_PREPROCESSOR, preprocargs, fnquotes, filename, fnquotes);
  422: 
  423:   if (verbose)
  424:     fprintf (stderr, _("Using `%s'\n"), cmd);
  425: 
  426:   cpp_pipe = open_input_stream (cmd);
  427:   return cpp_pipe;
  428: }
  429: 
  430: /* Read an rc file.  */
  431: 
  432: rc_res_directory *
  433: read_rc_file (const char *filename, const char *preprocessor,
  434:               const char *preprocargs, int language, int use_temp_file)
  435: {
  436:   char *cmd;
  437:   const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
  438: 
  439:   /* Setup the default resource import path taken from input file.  */
  440:   if (strchr (filename, '/') != NULL || strchr (filename, '\\') != NULL)
  441:     {
  442:       char *e, *c;
  443: 
  444:       if (filename[0] == '/'
  445:           || filename[0] == '\\'
  446:           || filename[1] == ':')
  447:         e = c = xstrdup (filename);
  448:       else
  449:         {
  450:           e = c = xmalloc (strlen (filename) + 3);
  451:           sprintf (c, "./%s", filename);
  452:         }
  453:       e += strlen (c);
  454:       while (e > c && (e[-1] != '\\' && e[-1] != '/'))
  455:         {
  456:           --e;
  457:           e[0] = 0;
  458:         }
  459:       /* Cut off trailing slash.  */
  460:       --e;
  461:       e[0] = 0;
  462:       while ((e = strchr (c, '\\')) != NULL)
  463:         *e = '/';
  464: 
  465:       windres_add_include_dir (e);
  466:     }
  467: 
  468:   istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
  469: 
  470:   if (preprocargs == NULL)
  471:     preprocargs = "";
  472:   if (filename == NULL)
  473:     filename = "-";
  474: 
  475:   if (preprocessor)
  476:     {
  477:       cmd = xmalloc (strlen (preprocessor)
  478:                      + strlen (preprocargs)
  479:                      + strlen (filename)
  480:                      + strlen (fnquotes) * 2
  481:                      + 10);
  482:       sprintf (cmd, "%s %s %s%s%s", preprocessor, preprocargs,
  483:                fnquotes, filename, fnquotes);
  484: 
  485:       cpp_pipe = open_input_stream (cmd);
  486:     }
  487:   else
  488:     {
  489:       char *dash, *slash, *cp;
  490: 
  491:       preprocessor = DEFAULT_PREPROCESSOR;
  492: 
  493:       cmd = xmalloc (strlen (program_name)
  494:                      + strlen (preprocessor)
  495:                      + strlen (preprocargs)
  496:                      + strlen (filename)
  497:                      + strlen (fnquotes) * 2
  498: #ifdef HAVE_EXECUTABLE_SUFFIX
  499:                      + strlen (EXECUTABLE_SUFFIX)
  500: #endif
  501:                      + 10);
  502: 
  503: 
  504:       dash = slash = 0;
  505:       for (cp = program_name; *cp; cp++)
  506:         {
  507:           if (*cp == '-')
  508:             dash = cp;
  509:           if (
  510: #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
  511:               *cp == ':' || *cp == '\\' ||
  512: #endif
  513:               *cp == '/')
  514:             {
  515:               slash = cp;
  516:               dash = 0;
  517:             }
  518:         }
  519: 
  520:       cpp_pipe = 0;
  521: 
  522:       if (dash)
  523:         {
  524:           /* First, try looking for a prefixed gcc in the windres
  525:              directory, with the same prefix as windres */
  526: 
  527:           cpp_pipe = look_for_default (cmd, program_name, dash - program_name + 1,
  528:                                        preprocargs, filename);
  529:         }
  530: 
  531:       if (slash && ! cpp_pipe)
  532:         {
  533:           /* Next, try looking for a gcc in the same directory as
  534:              that windres */
  535: 
  536:           cpp_pipe = look_for_default (cmd, program_name, slash - program_name + 1,
  537:                                        preprocargs, filename);
  538:         }
  539: 
  540:       if (! cpp_pipe)
  541:         {
  542:           /* Sigh, try the default */
  543: 
  544:           cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
  545:         }
  546: 
  547:     }
  548: 
  549:   free (cmd);
  550: 
  551:   rc_filename = xstrdup (filename);
  552:   rc_lineno = 1;
  553:   if (language != -1)
  554:     rcparse_set_language (language);
  555:   yyparse ();
  556:   rcparse_discard_strings ();
  557: 
  558:   close_input_stream ();
  559: 
  560:   if (fontdirs != NULL)
  561:     define_fontdirs ();
  562: 
  563:   free (rc_filename);
  564:   rc_filename = NULL;
  565: 
  566:   return resources;
  567: }
  568: 
  569: /* Close the input stream if it is open.  */
  570: 
  571: static void
  572: close_input_stream (void)
  573: {
  574:   if (istream_type == ISTREAM_FILE)
  575:     {
  576:       if (cpp_pipe != NULL)
  577:         fclose (cpp_pipe);
  578: 
  579:       if (cpp_temp_file != NULL)
  580:         {
  581:           int errno_save = errno;
  582: 
  583:           unlink (cpp_temp_file);
  584:           errno = errno_save;
  585:           free (cpp_temp_file);
  586:         }
  587:     }
  588:   else
  589:     {
  590:       if