resrc.c revision 60484
1267843Sdelphij/* resrc.c -- read and write Windows rc files. 2267843Sdelphij Copyright 1997, 1998, 1999 Free Software Foundation, Inc. 3267843Sdelphij Written by Ian Lance Taylor, Cygnus Support. 4267843Sdelphij 5267843Sdelphij This file is part of GNU Binutils. 6267843Sdelphij 7267843Sdelphij This program is free software; you can redistribute it and/or modify 8267843Sdelphij it under the terms of the GNU General Public License as published by 9267843Sdelphij the Free Software Foundation; either version 2 of the License, or 10267843Sdelphij (at your option) any later version. 11267843Sdelphij 12267843Sdelphij This program is distributed in the hope that it will be useful, 13267843Sdelphij but WITHOUT ANY WARRANTY; without even the implied warranty of 14267843Sdelphij MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15267843Sdelphij GNU General Public License for more details. 16267843Sdelphij 17267843Sdelphij You should have received a copy of the GNU General Public License 18267843Sdelphij along with this program; if not, write to the Free Software 19267843Sdelphij Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 20267843Sdelphij 02111-1307, USA. */ 21267843Sdelphij 22267843Sdelphij/* This file contains functions that read and write Windows rc files. 23267843Sdelphij These are text files that represent resources. */ 24267843Sdelphij 25267843Sdelphij#include "bfd.h" 26267843Sdelphij#include "bucomm.h" 27267843Sdelphij#include "libiberty.h" 28267843Sdelphij#include "windres.h" 29267843Sdelphij 30267843Sdelphij#include <assert.h> 31267843Sdelphij#include <ctype.h> 32267843Sdelphij#include <errno.h> 33267843Sdelphij#include <sys/stat.h> 34267843Sdelphij#ifdef HAVE_UNISTD_H 35267843Sdelphij#include <unistd.h> 36267843Sdelphij#endif 37267843Sdelphij 38267843Sdelphij#ifdef HAVE_SYS_WAIT_H 39267843Sdelphij#include <sys/wait.h> 40267843Sdelphij#else /* ! HAVE_SYS_WAIT_H */ 41267843Sdelphij#if ! defined (_WIN32) || defined (__CYGWIN__) 42267843Sdelphij#ifndef WIFEXITED 43267843Sdelphij#define WIFEXITED(w) (((w)&0377) == 0) 44267843Sdelphij#endif 45267843Sdelphij#ifndef WIFSIGNALED 46267843Sdelphij#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0) 47267843Sdelphij#endif 48267843Sdelphij#ifndef WTERMSIG 49267843Sdelphij#define WTERMSIG(w) ((w) & 0177) 50267843Sdelphij#endif 51267843Sdelphij#ifndef WEXITSTATUS 52267843Sdelphij#define WEXITSTATUS(w) (((w) >> 8) & 0377) 53267843Sdelphij#endif 54267843Sdelphij#else /* defined (_WIN32) && ! defined (__CYGWIN__) */ 55267843Sdelphij#ifndef WIFEXITED 56267843Sdelphij#define WIFEXITED(w) (((w) & 0xff) == 0) 57267843Sdelphij#endif 58267843Sdelphij#ifndef WIFSIGNALED 59267843Sdelphij#define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f) 60267843Sdelphij#endif 61267843Sdelphij#ifndef WTERMSIG 62267843Sdelphij#define WTERMSIG(w) ((w) & 0x7f) 63267843Sdelphij#endif 64267843Sdelphij#ifndef WEXITSTATUS 65267843Sdelphij#define WEXITSTATUS(w) (((w) & 0xff00) >> 8) 66267843Sdelphij#endif 67267843Sdelphij#endif /* defined (_WIN32) && ! defined (__CYGWIN__) */ 68267843Sdelphij#endif /* ! HAVE_SYS_WAIT_H */ 69267843Sdelphij 70267843Sdelphij#ifndef STDOUT_FILENO 71267843Sdelphij#define STDOUT_FILENO 1 72267843Sdelphij#endif 73267843Sdelphij 74267843Sdelphij#if defined (_WIN32) && ! defined (__CYGWIN__) 75267843Sdelphij#define popen _popen 76267843Sdelphij#define pclose _pclose 77267843Sdelphij#endif 78267843Sdelphij 79267843Sdelphij/* The default preprocessor. */ 80267843Sdelphij 81267843Sdelphij#define DEFAULT_PREPROCESSOR "gcc -E -xc-header -DRC_INVOKED" 82267843Sdelphij 83267843Sdelphij/* We read the directory entries in a cursor or icon file into 84267843Sdelphij instances of this structure. */ 85267843Sdelphij 86267843Sdelphijstruct icondir 87267843Sdelphij{ 88267843Sdelphij /* Width of image. */ 89267843Sdelphij unsigned char width; 90267843Sdelphij /* Height of image. */ 91267843Sdelphij unsigned char height; 92267843Sdelphij /* Number of colors in image. */ 93267843Sdelphij unsigned char colorcount; 94267843Sdelphij union 95267843Sdelphij { 96267843Sdelphij struct 97267843Sdelphij { 98267843Sdelphij /* Color planes. */ 99267843Sdelphij unsigned short planes; 100267843Sdelphij /* Bits per pixel. */ 101267843Sdelphij unsigned short bits; 102267843Sdelphij } icon; 103267843Sdelphij struct 104267843Sdelphij { 105267843Sdelphij /* X coordinate of hotspot. */ 106267843Sdelphij unsigned short xhotspot; 107267843Sdelphij /* Y coordinate of hotspot. */ 108267843Sdelphij unsigned short yhotspot; 109267843Sdelphij } cursor; 110267843Sdelphij } u; 111267843Sdelphij /* Bytes in image. */ 112267843Sdelphij unsigned long bytes; 113267843Sdelphij /* File offset of image. */ 114267843Sdelphij unsigned long offset; 115267843Sdelphij}; 116267843Sdelphij 117267843Sdelphij/* The name of the rc file we are reading. */ 118267843Sdelphij 119267843Sdelphijchar *rc_filename; 120267843Sdelphij 121267843Sdelphij/* The line number in the rc file. */ 122267843Sdelphij 123267843Sdelphijint rc_lineno; 124267843Sdelphij 125267843Sdelphij/* The pipe we are reading from, so that we can close it if we exit. */ 126267843Sdelphij 127267843Sdelphijstatic FILE *cpp_pipe; 128267843Sdelphij 129267843Sdelphij/* The temporary file used if we're not using popen, so we can delete it 130267843Sdelphij if we exit. */ 131267843Sdelphij 132267843Sdelphijstatic char *cpp_temp_file; 133267843Sdelphij 134267843Sdelphij/* Input stream is either a file or a pipe. */ 135267843Sdelphij 136267843Sdelphijstatic enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type; 137267843Sdelphij 138267843Sdelphij/* As we read the rc file, we attach information to this structure. */ 139267843Sdelphij 140267843Sdelphijstatic struct res_directory *resources; 141267843Sdelphij 142267843Sdelphij/* The number of cursor resources we have written out. */ 143267843Sdelphij 144267843Sdelphijstatic int cursors; 145267843Sdelphij 146267843Sdelphij/* The number of font resources we have written out. */ 147267843Sdelphij 148267843Sdelphijstatic int fonts; 149267843Sdelphij 150267843Sdelphij/* Font directory information. */ 151267843Sdelphij 152267843Sdelphijstruct fontdir *fontdirs; 153267843Sdelphij 154267843Sdelphij/* Resource info to use for fontdirs. */ 155267843Sdelphij 156267843Sdelphijstruct res_res_info fontdirs_resinfo; 157267843Sdelphij 158267843Sdelphij/* The number of icon resources we have written out. */ 159267843Sdelphij 160267843Sdelphijstatic int icons; 161267843Sdelphij 162267843Sdelphij/* Local functions. */ 163267843Sdelphij 164267843Sdelphijstatic int run_cmd PARAMS ((char *, const char *)); 165267843Sdelphijstatic FILE *open_input_stream PARAMS ((char *)); 166267843Sdelphijstatic FILE *look_for_default PARAMS ((char *, const char *, int, 167267843Sdelphij const char *, const char *)); 168267843Sdelphijstatic void close_input_stream PARAMS ((void)); 169267843Sdelphijstatic void unexpected_eof PARAMS ((const char *)); 170267843Sdelphijstatic int get_word PARAMS ((FILE *, const char *)); 171267843Sdelphijstatic unsigned long get_long PARAMS ((FILE *, const char *)); 172267843Sdelphijstatic void get_data 173267843Sdelphij PARAMS ((FILE *, unsigned char *, unsigned long, const char *)); 174267843Sdelphijstatic void define_fontdirs PARAMS ((void)); 175267843Sdelphij 176267843Sdelphij/* Run `cmd' and redirect the output to `redir'. */ 177267843Sdelphij 178267843Sdelphijstatic int 179267843Sdelphijrun_cmd (cmd, redir) 180267843Sdelphij char *cmd; 181267843Sdelphij const char *redir; 182267843Sdelphij{ 183267843Sdelphij char *s; 184267843Sdelphij int pid, wait_status, retcode; 185267843Sdelphij int i; 186267843Sdelphij const char **argv; 187267843Sdelphij char *errmsg_fmt, *errmsg_arg; 188267843Sdelphij char *temp_base = choose_temp_base (); 189267843Sdelphij int in_quote; 190267843Sdelphij char sep; 191267843Sdelphij int redir_handle = -1; 192267843Sdelphij int stdout_save = -1; 193267843Sdelphij 194267843Sdelphij /* Count the args. */ 195267843Sdelphij i = 0; 196267843Sdelphij 197267843Sdelphij for (s = cmd; *s; s++) 198267843Sdelphij if (*s == ' ') 199267843Sdelphij i++; 200267843Sdelphij 201267843Sdelphij i++; 202267843Sdelphij argv = alloca (sizeof (char *) * (i + 3)); 203267843Sdelphij i = 0; 204267843Sdelphij s = cmd; 205267843Sdelphij 206267843Sdelphij while (1) 207267843Sdelphij { 208267843Sdelphij while (*s == ' ' && *s != 0) 209267843Sdelphij s++; 210267843Sdelphij 211267843Sdelphij if (*s == 0) 212267843Sdelphij break; 213267843Sdelphij 214267843Sdelphij in_quote = (*s == '\'' || *s == '"'); 215267843Sdelphij sep = (in_quote) ? *s++ : ' '; 216267843Sdelphij argv[i++] = s; 217267843Sdelphij 218267843Sdelphij while (*s != sep && *s != 0) 219267843Sdelphij s++; 220267843Sdelphij 221267843Sdelphij if (*s == 0) 222267843Sdelphij break; 223267843Sdelphij 224267843Sdelphij *s++ = 0; 225267843Sdelphij 226267843Sdelphij if (in_quote) 227267843Sdelphij s++; 228267843Sdelphij } 229267843Sdelphij argv[i++] = NULL; 230267843Sdelphij 231267843Sdelphij /* Setup the redirection. We can't use the usual fork/exec and redirect 232267843Sdelphij since we may be running on non-POSIX Windows host. */ 233267843Sdelphij 234267843Sdelphij fflush (stdout); 235267843Sdelphij fflush (stderr); 236267843Sdelphij 237267843Sdelphij /* Open temporary output file. */ 238267843Sdelphij redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666); 239267843Sdelphij if (redir_handle == -1) 240267843Sdelphij fatal (_("can't open temporary file `%s': %s"), redir, 241267843Sdelphij strerror (errno)); 242267843Sdelphij 243267843Sdelphij /* Duplicate the stdout file handle so it can be restored later. */ 244267843Sdelphij stdout_save = dup (STDOUT_FILENO); 245267843Sdelphij if (stdout_save == -1) 246267843Sdelphij fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno)); 247267843Sdelphij 248267843Sdelphij /* Redirect stdout to our output file. */ 249267843Sdelphij dup2 (redir_handle, STDOUT_FILENO); 250267843Sdelphij 251267843Sdelphij pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base, 252267843Sdelphij &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH); 253267843Sdelphij 254267843Sdelphij /* Restore stdout to its previous setting. */ 255267843Sdelphij dup2 (stdout_save, STDOUT_FILENO); 256267843Sdelphij 257267843Sdelphij /* Close reponse file. */ 258267843Sdelphij close (redir_handle); 259267843Sdelphij 260267843Sdelphij if (pid == -1) 261267843Sdelphij { 262267843Sdelphij fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno)); 263267843Sdelphij return 1; 264267843Sdelphij } 265267843Sdelphij 266267843Sdelphij retcode = 0; 267267843Sdelphij pid = pwait (pid, &wait_status, 0); 268267843Sdelphij 269267843Sdelphij if (pid == -1) 270267843Sdelphij { 271267843Sdelphij fatal (_("wait: %s"), strerror (errno)); 272267843Sdelphij retcode = 1; 273267843Sdelphij } 274267843Sdelphij else if (WIFSIGNALED (wait_status)) 275267843Sdelphij { 276267843Sdelphij fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status)); 277267843Sdelphij retcode = 1; 278267843Sdelphij } 279267843Sdelphij else if (WIFEXITED (wait_status)) 280267843Sdelphij { 281267843Sdelphij if (WEXITSTATUS (wait_status) != 0) 282267843Sdelphij { 283267843Sdelphij fatal (_("%s exited with status %d"), cmd, 284267843Sdelphij WEXITSTATUS (wait_status)); 285267843Sdelphij retcode = 1; 286267843Sdelphij } 287267843Sdelphij } 288267843Sdelphij else 289267843Sdelphij retcode = 1; 290267843Sdelphij 291267843Sdelphij return retcode; 292267843Sdelphij} 293267843Sdelphij 294267843Sdelphijstatic FILE * 295267843Sdelphijopen_input_stream (cmd) 296267843Sdelphij char *cmd; 297267843Sdelphij{ 298267843Sdelphij if (istream_type == ISTREAM_FILE) 299267843Sdelphij { 300267843Sdelphij char *fileprefix; 301267843Sdelphij 302267843Sdelphij fileprefix = choose_temp_base (); 303267843Sdelphij cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5); 304267843Sdelphij sprintf (cpp_temp_file, "%s.irc", fileprefix); 305267843Sdelphij free (fileprefix); 306267843Sdelphij 307267843Sdelphij if (run_cmd (cmd, cpp_temp_file)) 308267843Sdelphij fatal (_("can't execute `%s': %s"), cmd, strerror (errno)); 309267843Sdelphij 310267843Sdelphij cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);; 311267843Sdelphij if (cpp_pipe == NULL) 312267843Sdelphij fatal (_("can't open temporary file `%s': %s"), 313267843Sdelphij cpp_temp_file, strerror (errno)); 314267843Sdelphij 315267843Sdelphij if (verbose) 316267843Sdelphij fprintf (stderr, 317267843Sdelphij _("Using temporary file `%s' to read preprocessor output\n"), 318267843Sdelphij cpp_temp_file); 319267843Sdelphij } 320267843Sdelphij else 321267843Sdelphij { 322267843Sdelphij cpp_pipe = popen (cmd, FOPEN_RT); 323267843Sdelphij if (cpp_pipe == NULL) 324267843Sdelphij fatal (_("can't popen `%s': %s"), cmd, strerror (errno)); 325267843Sdelphij if (verbose) 326267843Sdelphij fprintf (stderr, _("Using popen to read preprocessor output\n")); 327267843Sdelphij } 328267843Sdelphij 329267843Sdelphij xatexit (close_input_stream); 330267843Sdelphij return cpp_pipe; 331267843Sdelphij} 332267843Sdelphij 333267843Sdelphij/* look for the preprocessor program */ 334267843Sdelphij 335267843Sdelphijstatic FILE * 336267843Sdelphijlook_for_default (cmd, prefix, end_prefix, preprocargs, filename) 337267843Sdelphij char *cmd; 338267843Sdelphij const char *prefix; 339267843Sdelphij int end_prefix; 340267843Sdelphij const char *preprocargs; 341267843Sdelphij const char *filename; 342267843Sdelphij{ 343267843Sdelphij char *space; 344267843Sdelphij int found; 345267843Sdelphij struct stat s; 346267843Sdelphij 347267843Sdelphij strcpy (cmd, prefix); 348267843Sdelphij 349267843Sdelphij sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR); 350267843Sdelphij space = strchr (cmd + end_prefix, ' '); 351267843Sdelphij if (space) 352267843Sdelphij *space = 0; 353267843Sdelphij 354267843Sdelphij if ( 355267843Sdelphij#if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32) 356267843Sdelphij strchr (cmd, '\\') || 357267843Sdelphij#endif 358267843Sdelphij strchr (cmd, '/')) 359267843Sdelphij { 360267843Sdelphij found = (stat (cmd, &s) == 0 361267843Sdelphij#ifdef HAVE_EXECUTABLE_SUFFIX 362267843Sdelphij || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0 363267843Sdelphij#endif 364267843Sdelphij ); 365267843Sdelphij 366267843Sdelphij if (! found) 367267843Sdelphij { 368267843Sdelphij if (verbose) 369267843Sdelphij fprintf (stderr, _("Tried `%s'\n"), cmd); 370267843Sdelphij return NULL; 371267843Sdelphij } 372267843Sdelphij } 373267843Sdelphij 374267843Sdelphij strcpy (cmd, prefix); 375267843Sdelphij 376267843Sdelphij sprintf (cmd + end_prefix, "%s %s %s", 377267843Sdelphij DEFAULT_PREPROCESSOR, preprocargs, filename); 378267843Sdelphij 379267843Sdelphij if (verbose) 380267843Sdelphij fprintf (stderr, _("Using `%s'\n"), cmd); 381267843Sdelphij 382267843Sdelphij cpp_pipe = open_input_stream (cmd); 383267843Sdelphij return cpp_pipe; 384267843Sdelphij} 385267843Sdelphij 386267843Sdelphij/* Read an rc file. */ 387267843Sdelphij 388267843Sdelphijstruct res_directory * 389267843Sdelphijread_rc_file (filename, preprocessor, preprocargs, language, use_temp_file) 390267843Sdelphij const char *filename; 391267843Sdelphij const char *preprocessor; 392267843Sdelphij const char *preprocargs; 393267843Sdelphij int language; 394267843Sdelphij int use_temp_file; 395267843Sdelphij{ 396267843Sdelphij char *cmd; 397267843Sdelphij 398267843Sdelphij istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE; 399267843Sdelphij 400267843Sdelphij if (preprocargs == NULL) 401267843Sdelphij preprocargs = ""; 402267843Sdelphij if (filename == NULL) 403267843Sdelphij filename = "-"; 404267843Sdelphij 405267843Sdelphij if (preprocessor) 406267843Sdelphij { 407267843Sdelphij cmd = xmalloc (strlen (preprocessor) 408267843Sdelphij + strlen (preprocargs) 409267843Sdelphij + strlen (filename) 410267843Sdelphij + 10); 411267843Sdelphij sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename); 412267843Sdelphij 413267843Sdelphij cpp_pipe = open_input_stream (cmd); 414267843Sdelphij } 415267843Sdelphij else 416267843Sdelphij { 417267843Sdelphij char *dash, *slash, *cp; 418267843Sdelphij 419267843Sdelphij preprocessor = DEFAULT_PREPROCESSOR; 420267843Sdelphij 421267843Sdelphij cmd = xmalloc (strlen (program_name) 422267843Sdelphij + strlen (preprocessor) 423267843Sdelphij + strlen (preprocargs) 424267843Sdelphij + strlen (filename) 425267843Sdelphij#ifdef HAVE_EXECUTABLE_SUFFIX 426267843Sdelphij + strlen (EXECUTABLE_SUFFIX) 427267843Sdelphij#endif 428267843Sdelphij + 10); 429267843Sdelphij 430267843Sdelphij 431267843Sdelphij dash = slash = 0; 432267843Sdelphij for (cp = program_name; *cp; cp++) 433267843Sdelphij { 434267843Sdelphij if (*cp == '-') 435267843Sdelphij dash = cp; 436267843Sdelphij if ( 437267843Sdelphij#if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32) 438267843Sdelphij *cp == ':' || *cp == '\\' || 439267843Sdelphij#endif 440267843Sdelphij *cp == '/') 441267843Sdelphij { 442267843Sdelphij slash = cp; 443267843Sdelphij dash = 0; 444267843Sdelphij } 445267843Sdelphij } 446267843Sdelphij 447267843Sdelphij cpp_pipe = 0; 448267843Sdelphij 449267843Sdelphij if (dash) 450267843Sdelphij { 451267843Sdelphij /* First, try looking for a prefixed gcc in the windres 452267843Sdelphij directory, with the same prefix as windres */ 453267843Sdelphij 454267843Sdelphij cpp_pipe = look_for_default (cmd, program_name, dash-program_name+1, 455267843Sdelphij preprocargs, filename); 456267843Sdelphij } 457267843Sdelphij 458267843Sdelphij if (slash && !cpp_pipe) 459267843Sdelphij { 460267843Sdelphij /* Next, try looking for a gcc in the same directory as 461267843Sdelphij that windres */ 462267843Sdelphij 463267843Sdelphij cpp_pipe = look_for_default (cmd, program_name, slash-program_name+1, 464267843Sdelphij preprocargs, filename); 465267843Sdelphij } 466267843Sdelphij 467267843Sdelphij if (!cpp_pipe) 468267843Sdelphij { 469267843Sdelphij /* Sigh, try the default */ 470267843Sdelphij 471267843Sdelphij cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename); 472267843Sdelphij } 473267843Sdelphij 474267843Sdelphij } 475267843Sdelphij 476267843Sdelphij free (cmd); 477267843Sdelphij 478267843Sdelphij rc_filename = xstrdup (filename); 479267843Sdelphij rc_lineno = 1; 480267843Sdelphij if (language != -1) 481267843Sdelphij rcparse_set_language (language); 482267843Sdelphij yyin = cpp_pipe; 483267843Sdelphij yyparse (); 484267843Sdelphij 485267843Sdelphij close_input_stream (); 486267843Sdelphij 487267843Sdelphij if (fontdirs != NULL) 488267843Sdelphij define_fontdirs (); 489267843Sdelphij 490267843Sdelphij free (rc_filename); 491267843Sdelphij rc_filename = NULL; 492267843Sdelphij 493267843Sdelphij return resources; 494267843Sdelphij} 495267843Sdelphij 496267843Sdelphij/* Close the input stream if it is open. */ 497267843Sdelphij 498267843Sdelphijstatic void 499267843Sdelphijclose_input_stream () 500267843Sdelphij{ 501267843Sdelphij if (cpp_pipe != NULL) 502267843Sdelphij pclose (cpp_pipe); 503267843Sdelphij 504267843Sdelphij if (istream_type == ISTREAM_FILE) 505267843Sdelphij { 506267843Sdelphij if (cpp_pipe != NULL) 507267843Sdelphij fclose (cpp_pipe); 508267843Sdelphij 509267843Sdelphij if (cpp_temp_file != NULL) 510267843Sdelphij { 511267843Sdelphij int errno_save = errno; 512267843Sdelphij 513267843Sdelphij unlink (cpp_temp_file); 514267843Sdelphij errno = errno_save; 515267843Sdelphij free (cpp_temp_file); 516267843Sdelphij } 517267843Sdelphij } 518267843Sdelphij else 519267843Sdelphij { 520267843Sdelphij if (cpp_pipe != NULL) 521267843Sdelphij pclose (cpp_pipe); 522267843Sdelphij } 523267843Sdelphij 524267843Sdelphij /* Since this is also run via xatexit, safeguard. */ 525267843Sdelphij cpp_pipe = NULL; 526267843Sdelphij cpp_temp_file = NULL; 527267843Sdelphij} 528267843Sdelphij 529267843Sdelphij/* Report an error while reading an rc file. */ 530267843Sdelphij 531267843Sdelphijvoid 532267843Sdelphijyyerror (msg) 533267843Sdelphij const char *msg; 534267843Sdelphij{ 535267843Sdelphij fatal ("%s:%d: %s", rc_filename, rc_lineno, msg); 536267843Sdelphij} 537267843Sdelphij 538267843Sdelphij/* Issue a warning while reading an rc file. */ 539267843Sdelphij 540267843Sdelphijvoid 541267843Sdelphijrcparse_warning (msg) 542267843Sdelphij const char *msg; 543267843Sdelphij{ 544267843Sdelphij fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg); 545267843Sdelphij} 546267843Sdelphij 547267843Sdelphij/* Die if we get an unexpected end of file. */ 548267843Sdelphij 549267843Sdelphijstatic void 550267843Sdelphijunexpected_eof (msg) 551267843Sdelphij const char *msg; 552267843Sdelphij{ 553267843Sdelphij fatal (_("%s: unexpected EOF"), msg); 554267843Sdelphij} 555267843Sdelphij 556267843Sdelphij/* Read a 16 bit word from a file. The data is assumed to be little 557267843Sdelphij endian. */ 558267843Sdelphij 559267843Sdelphijstatic int 560267843Sdelphijget_word (e, msg) 561267843Sdelphij FILE *e; 562267843Sdelphij const char *msg; 563267843Sdelphij{ 564267843Sdelphij int b1, b2; 565267843Sdelphij 566267843Sdelphij b1 = getc (e); 567267843Sdelphij b2 = getc (e); 568267843Sdelphij if (feof (e)) 569267843Sdelphij unexpected_eof (msg); 570267843Sdelphij return ((b2 & 0xff) << 8) | (b1 & 0xff); 571267843Sdelphij} 572267843Sdelphij 573267843Sdelphij/* Read a 32 bit word from a file. The data is assumed to be little 574267843Sdelphij endian. */ 575267843Sdelphij 576267843Sdelphijstatic unsigned long 577267843Sdelphijget_long (e, msg) 578267843Sdelphij FILE *e; 579267843Sdelphij const char *msg; 580267843Sdelphij{ 581267843Sdelphij int b1, b2, b3, b4; 582267843Sdelphij 583267843Sdelphij b1 = getc (e); 584267843Sdelphij b2 = getc (e); 585267843Sdelphij b3 = getc (e); 586267843Sdelphij b4 = getc (e); 587267843Sdelphij if (feof (e)) 588267843Sdelphij unexpected_eof (msg); 589267843Sdelphij return (((((((b4 & 0xff) << 8) 590267843Sdelphij | (b3 & 0xff)) << 8) 591267843Sdelphij | (b2 & 0xff)) << 8) 592267843Sdelphij | (b1 & 0xff)); 593267843Sdelphij} 594267843Sdelphij 595267843Sdelphij/* Read data from a file. This is a wrapper to do error checking. */ 596267843Sdelphij 597267843Sdelphijstatic void 598267843Sdelphijget_data (e, p, c, msg) 599267843Sdelphij FILE *e; 600267843Sdelphij unsigned char *p; 601267843Sdelphij unsigned long c; 602267843Sdelphij const char *msg; 603267843Sdelphij{ 604267843Sdelphij unsigned long got; 605267843Sdelphij 606267843Sdelphij got = fread (p, 1, c, e); 607267843Sdelphij if (got == c) 608267843Sdelphij return; 609267843Sdelphij 610267843Sdelphij fatal (_("%s: read of %lu returned %lu"), msg, c, got); 611267843Sdelphij} 612267843Sdelphij 613267843Sdelphij/* Define an accelerator resource. */ 614267843Sdelphij 615267843Sdelphijvoid 616267843Sdelphijdefine_accelerator (id, resinfo, data) 617267843Sdelphij struct res_id id; 618267843Sdelphij const struct res_res_info *resinfo; 619267843Sdelphij struct accelerator *data; 620267843Sdelphij{ 621267843Sdelphij struct res_resource *r; 622267843Sdelphij 623267843Sdelphij r = define_standard_resource (&resources, RT_ACCELERATOR, id, 624267843Sdelphij resinfo->language, 0); 625267843Sdelphij r->type = RES_TYPE_ACCELERATOR; 626267843Sdelphij r->u.acc = data; 627267843Sdelphij r->res_info = *resinfo; 628267843Sdelphij} 629267843Sdelphij 630267843Sdelphij/* Define a bitmap resource. Bitmap data is stored in a file. The 631267843Sdelphij first 14 bytes of the file are a standard header, which is not 632267843Sdelphij included in the resource data. */ 633267843Sdelphij 634267843Sdelphij#define BITMAP_SKIP (14) 635267843Sdelphij 636267843Sdelphijvoid 637267843Sdelphijdefine_bitmap (id, resinfo, filename) 638267843Sdelphij struct res_id id; 639267843Sdelphij const struct res_res_info *resinfo; 640267843Sdelphij const char *filename; 641267843Sdelphij{ 642267843Sdelphij FILE *e; 643267843Sdelphij char *real_filename; 644267843Sdelphij struct stat s; 645267843Sdelphij unsigned char *data; 646267843Sdelphij int i; 647267843Sdelphij struct res_resource *r; 648267843Sdelphij 649267843Sdelphij e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename); 650267843Sdelphij 651267843Sdelphij if (stat (real_filename, &s) < 0) 652267843Sdelphij fatal (_("stat failed on bitmap file `%s': %s"), real_filename, 653267843Sdelphij strerror (errno)); 654267843Sdelphij 655267843Sdelphij data = (unsigned char *) res_alloc (s.st_size - BITMAP_SKIP); 656267843Sdelphij 657267843Sdelphij for (i = 0; i < BITMAP_SKIP; i++) 658267843Sdelphij getc (e); 659267843Sdelphij 660267843Sdelphij get_data (e, data, s.st_size - BITMAP_SKIP, real_filename); 661267843Sdelphij 662267843Sdelphij fclose (e); 663267843Sdelphij free (real_filename); 664267843Sdelphij 665267843Sdelphij r = define_standard_resource (&resources, RT_BITMAP, id, 666267843Sdelphij resinfo->language, 0); 667267843Sdelphij 668267843Sdelphij r->type = RES_TYPE_BITMAP; 669267843Sdelphij r->u.data.length = s.st_size - BITMAP_SKIP; 670 r->u.data.data = data; 671 r->res_info = *resinfo; 672} 673 674/* Define a cursor resource. A cursor file may contain a set of 675 bitmaps, each representing the same cursor at various different 676 resolutions. They each get written out with a different ID. The 677 real cursor resource is then a group resource which can be used to 678 select one of the actual cursors. */ 679 680void 681define_cursor (id, resinfo, filename) 682 struct res_id id; 683 const struct res_res_info *resinfo; 684 const char *filename; 685{ 686 FILE *e; 687 char *real_filename; 688 int type, count, i; 689 struct icondir *icondirs; 690 int first_cursor; 691 struct res_resource *r; 692 struct group_cursor *first, **pp; 693 694 e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename); 695 696 /* A cursor file is basically an icon file. The start of the file 697 is a three word structure. The first word is ignored. The 698 second word is the type of data. The third word is the number of 699 entries. */ 700 701 get_word (e, real_filename); 702 type = get_word (e, real_filename); 703 count = get_word (e, real_filename); 704 if (type != 2) 705 fatal (_("cursor file `%s' does not contain cursor data"), real_filename); 706 707 /* Read in the icon directory entries. */ 708 709 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs); 710 711 for (i = 0; i < count; i++) 712 { 713 icondirs[i].width = getc (e); 714 icondirs[i].height = getc (e); 715 icondirs[i].colorcount = getc (e); 716 getc (e); 717 icondirs[i].u.cursor.xhotspot = get_word (e, real_filename); 718 icondirs[i].u.cursor.yhotspot = get_word (e, real_filename); 719 icondirs[i].bytes = get_long (e, real_filename); 720 icondirs[i].offset = get_long (e, real_filename); 721 722 if (feof (e)) 723 unexpected_eof (real_filename); 724 } 725 726 /* Define each cursor as a unique resource. */ 727 728 first_cursor = cursors; 729 730 for (i = 0; i < count; i++) 731 { 732 unsigned char *data; 733 struct res_id name; 734 struct cursor *c; 735 736 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0) 737 fatal (_("%s: fseek to %lu failed: %s"), real_filename, 738 icondirs[i].offset, strerror (errno)); 739 740 data = (unsigned char *) res_alloc (icondirs[i].bytes); 741 742 get_data (e, data, icondirs[i].bytes, real_filename); 743 744 c = (struct cursor *) res_alloc (sizeof *c); 745 c->xhotspot = icondirs[i].u.cursor.xhotspot; 746 c->yhotspot = icondirs[i].u.cursor.yhotspot; 747 c->length = icondirs[i].bytes; 748 c->data = data; 749 750 ++cursors; 751 752 name.named = 0; 753 name.u.id = cursors; 754 755 r = define_standard_resource (&resources, RT_CURSOR, name, 756 resinfo->language, 0); 757 r->type = RES_TYPE_CURSOR; 758 r->u.cursor = c; 759 r->res_info = *resinfo; 760 } 761 762 fclose (e); 763 free (real_filename); 764 765 /* Define a cursor group resource. */ 766 767 first = NULL; 768 pp = &first; 769 for (i = 0; i < count; i++) 770 { 771 struct group_cursor *cg; 772 773 cg = (struct group_cursor *) res_alloc (sizeof *cg); 774 cg->next = NULL; 775 cg->width = icondirs[i].width; 776 cg->height = 2 * icondirs[i].height; 777 778 /* FIXME: What should these be set to? */ 779 cg->planes = 1; 780 cg->bits = 1; 781 782 cg->bytes = icondirs[i].bytes + 4; 783 cg->index = first_cursor + i + 1; 784 785 *pp = cg; 786 pp = &(*pp)->next; 787 } 788 789 free (icondirs); 790 791 r = define_standard_resource (&resources, RT_GROUP_CURSOR, id, 792 resinfo->language, 0); 793 r->type = RES_TYPE_GROUP_CURSOR; 794 r->u.group_cursor = first; 795 r->res_info = *resinfo; 796} 797 798/* Define a dialog resource. */ 799 800void 801define_dialog (id, resinfo, dialog) 802 struct res_id id; 803 const struct res_res_info *resinfo; 804 const struct dialog *dialog; 805{ 806 struct dialog *copy; 807 struct res_resource *r; 808 809 copy = (struct dialog *) res_alloc (sizeof *copy); 810 *copy = *dialog; 811 812 r = define_standard_resource (&resources, RT_DIALOG, id, 813 resinfo->language, 0); 814 r->type = RES_TYPE_DIALOG; 815 r->u.dialog = copy; 816 r->res_info = *resinfo; 817} 818 819/* Define a dialog control. This does not define a resource, but 820 merely allocates and fills in a structure. */ 821 822struct dialog_control * 823define_control (text, id, x, y, width, height, class, style, exstyle) 824 const char *text; 825 unsigned long id; 826 unsigned long x; 827 unsigned long y; 828 unsigned long width; 829 unsigned long height; 830 unsigned long class; 831 unsigned long style; 832 unsigned long exstyle; 833{ 834 struct dialog_control *n; 835 836 n = (struct dialog_control *) res_alloc (sizeof *n); 837 n->next = NULL; 838 n->id = id; 839 n->style = style; 840 n->exstyle = exstyle; 841 n->x = x; 842 n->y = y; 843 n->width = width; 844 n->height = height; 845 n->class.named = 0; 846 n->class.u.id = class; 847 if (text != NULL) 848 res_string_to_id (&n->text, text); 849 else 850 { 851 n->text.named = 0; 852 n->text.u.id = 0; 853 } 854 n->data = NULL; 855 n->help = 0; 856 857 return n; 858} 859 860/* Define a font resource. */ 861 862void 863define_font (id, resinfo, filename) 864 struct res_id id; 865 const struct res_res_info *resinfo; 866 const char *filename; 867{ 868 FILE *e; 869 char *real_filename; 870 struct stat s; 871 unsigned char *data; 872 struct res_resource *r; 873 long offset; 874 long fontdatalength; 875 unsigned char *fontdata; 876 struct fontdir *fd; 877 const char *device, *face; 878 struct fontdir **pp; 879 880 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename); 881 882 if (stat (real_filename, &s) < 0) 883 fatal (_("stat failed on bitmap file `%s': %s"), real_filename, 884 strerror (errno)); 885 886 data = (unsigned char *) res_alloc (s.st_size); 887 888 get_data (e, data, s.st_size, real_filename); 889 890 fclose (e); 891 free (real_filename); 892 893 r = define_standard_resource (&resources, RT_FONT, id, 894 resinfo->language, 0); 895 896 r->type = RES_TYPE_FONT; 897 r->u.data.length = s.st_size; 898 r->u.data.data = data; 899 r->res_info = *resinfo; 900 901 /* For each font resource, we must add an entry in the FONTDIR 902 resource. The FONTDIR resource includes some strings in the font 903 file. To find them, we have to do some magic on the data we have 904 read. */ 905 906 offset = ((((((data[47] << 8) 907 | data[46]) << 8) 908 | data[45]) << 8) 909 | data[44]); 910 if (offset > 0 && offset < s.st_size) 911 device = (char *) data + offset; 912 else 913 device = ""; 914 915 offset = ((((((data[51] << 8) 916 | data[50]) << 8) 917 | data[49]) << 8) 918 | data[48]); 919 if (offset > 0 && offset < s.st_size) 920 face = (char *) data + offset; 921 else 922 face = ""; 923 924 ++fonts; 925 926 fontdatalength = 58 + strlen (device) + strlen (face); 927 fontdata = (unsigned char *) res_alloc (fontdatalength); 928 memcpy (fontdata, data, 56); 929 strcpy ((char *) fontdata + 56, device); 930 strcpy ((char *) fontdata + 57 + strlen (device), face); 931 932 fd = (struct fontdir *) res_alloc (sizeof *fd); 933 fd->next = NULL; 934 fd->index = fonts; 935 fd->length = fontdatalength; 936 fd->data = fontdata; 937 938 for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next) 939 ; 940 *pp = fd; 941 942 /* For the single fontdirs resource, we always use the resource 943 information of the last font. I don't know what else to do. */ 944 fontdirs_resinfo = *resinfo; 945} 946 947/* Define the fontdirs resource. This is called after the entire rc 948 file has been parsed, if any font resources were seen. */ 949 950static void 951define_fontdirs () 952{ 953 struct res_resource *r; 954 struct res_id id; 955 956 id.named = 0; 957 id.u.id = 1; 958 959 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0); 960 961 r->type = RES_TYPE_FONTDIR; 962 r->u.fontdir = fontdirs; 963 r->res_info = fontdirs_resinfo; 964} 965 966/* Define an icon resource. An icon file may contain a set of 967 bitmaps, each representing the same icon at various different 968 resolutions. They each get written out with a different ID. The 969 real icon resource is then a group resource which can be used to 970 select one of the actual icon bitmaps. */ 971 972void 973define_icon (id, resinfo, filename) 974 struct res_id id; 975 const struct res_res_info *resinfo; 976 const char *filename; 977{ 978 FILE *e; 979 char *real_filename; 980 int type, count, i; 981 struct icondir *icondirs; 982 int first_icon; 983 struct res_resource *r; 984 struct group_icon *first, **pp; 985 986 e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename); 987 988 /* The start of an icon file is a three word structure. The first 989 word is ignored. The second word is the type of data. The third 990 word is the number of entries. */ 991 992 get_word (e, real_filename); 993 type = get_word (e, real_filename); 994 count = get_word (e, real_filename); 995 if (type != 1) 996 fatal (_("icon file `%s' does not contain icon data"), real_filename); 997 998 /* Read in the icon directory entries. */ 999 1000 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs); 1001 1002 for (i = 0; i < count; i++) 1003 { 1004 icondirs[i].width = getc (e); 1005 icondirs[i].height = getc (e); 1006 icondirs[i].colorcount = getc (e); 1007 getc (e); 1008 icondirs[i].u.icon.planes = get_word (e, real_filename); 1009 icondirs[i].u.icon.bits = get_word (e, real_filename); 1010 icondirs[i].bytes = get_long (e, real_filename); 1011 icondirs[i].offset = get_long (e, real_filename); 1012 1013 if (feof (e)) 1014 unexpected_eof (real_filename); 1015 } 1016 1017 /* Define each icon as a unique resource. */ 1018 1019 first_icon = icons; 1020 1021 for (i = 0; i < count; i++) 1022 { 1023 unsigned char *data; 1024 struct res_id name; 1025 1026 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0) 1027 fatal (_("%s: fseek to %lu failed: %s"), real_filename, 1028 icondirs[i].offset, strerror (errno)); 1029 1030 data = (unsigned char *) res_alloc (icondirs[i].bytes); 1031 1032 get_data (e, data, icondirs[i].bytes, real_filename); 1033 1034 ++icons; 1035 1036 name.named = 0; 1037 name.u.id = icons; 1038 1039 r = define_standard_resource (&resources, RT_ICON, name, 1040 resinfo->language, 0); 1041 r->type = RES_TYPE_ICON; 1042 r->u.data.length = icondirs[i].bytes; 1043 r->u.data.data = data; 1044 r->res_info = *resinfo; 1045 } 1046 1047 fclose (e); 1048 free (real_filename); 1049 1050 /* Define an icon group resource. */ 1051 1052 first = NULL; 1053 pp = &first; 1054 for (i = 0; i < count; i++) 1055 { 1056 struct group_icon *cg; 1057 1058 /* For some reason, at least in some files the planes and bits 1059 are zero. We instead set them from the color. This is 1060 copied from rcl. */ 1061 1062 cg = (struct group_icon *) res_alloc (sizeof *cg); 1063 cg->next = NULL; 1064 cg->width = icondirs[i].width; 1065 cg->height = icondirs[i].height; 1066 cg->colors = icondirs[i].colorcount; 1067 1068 cg->planes = 1; 1069 cg->bits = 0; 1070 while ((1 << cg->bits) < cg->colors) 1071 ++cg->bits; 1072 1073 cg->bytes = icondirs[i].bytes; 1074 cg->index = first_icon + i + 1; 1075 1076 *pp = cg; 1077 pp = &(*pp)->next; 1078 } 1079 1080 free (icondirs); 1081 1082 r = define_standard_resource (&resources, RT_GROUP_ICON, id, 1083 resinfo->language, 0); 1084 r->type = RES_TYPE_GROUP_ICON; 1085 r->u.group_icon = first; 1086 r->res_info = *resinfo; 1087} 1088 1089/* Define a menu resource. */ 1090 1091void 1092define_menu (id, resinfo, menuitems) 1093 struct res_id id; 1094 const struct res_res_info *resinfo; 1095 struct menuitem *menuitems; 1096{ 1097 struct menu *m; 1098 struct res_resource *r; 1099 1100 m = (struct menu *) res_alloc (sizeof *m); 1101 m->items = menuitems; 1102 m->help = 0; 1103 1104 r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0); 1105 r->type = RES_TYPE_MENU; 1106 r->u.menu = m; 1107 r->res_info = *resinfo; 1108} 1109 1110/* Define a menu item. This does not define a resource, but merely 1111 allocates and fills in a structure. */ 1112 1113struct menuitem * 1114define_menuitem (text, menuid, type, state, help, menuitems) 1115 const char *text; 1116 int menuid; 1117 unsigned long type; 1118 unsigned long state; 1119 unsigned long help; 1120 struct menuitem *menuitems; 1121{ 1122 struct menuitem *mi; 1123 1124 mi = (struct menuitem *) res_alloc (sizeof *mi); 1125 mi->next = NULL; 1126 mi->type = type; 1127 mi->state = state; 1128 mi->id = menuid; 1129 if (text == NULL) 1130 mi->text = NULL; 1131 else 1132 unicode_from_ascii ((int *) NULL, &mi->text, text); 1133 mi->help = help; 1134 mi->popup = menuitems; 1135 return mi; 1136} 1137 1138/* Define a messagetable resource. */ 1139 1140void 1141define_messagetable (id, resinfo, filename) 1142 struct res_id id; 1143 const struct res_res_info *resinfo; 1144 const char *filename; 1145{ 1146 FILE *e; 1147 char *real_filename; 1148 struct stat s; 1149 unsigned char *data; 1150 struct res_resource *r; 1151 1152 e = open_file_search (filename, FOPEN_RB, "messagetable file", 1153 &real_filename); 1154 1155 if (stat (real_filename, &s) < 0) 1156 fatal (_("stat failed on bitmap file `%s': %s"), real_filename, 1157 strerror (errno)); 1158 1159 data = (unsigned char *) res_alloc (s.st_size); 1160 1161 get_data (e, data, s.st_size, real_filename); 1162 1163 fclose (e); 1164 free (real_filename); 1165 1166 r = define_standard_resource (&resources, RT_MESSAGETABLE, id, 1167 resinfo->language, 0); 1168 1169 r->type = RES_TYPE_MESSAGETABLE; 1170 r->u.data.length = s.st_size; 1171 r->u.data.data = data; 1172 r->res_info = *resinfo; 1173} 1174 1175/* Define an rcdata resource. */ 1176 1177void 1178define_rcdata (id, resinfo, data) 1179 struct res_id id; 1180 const struct res_res_info *resinfo; 1181 struct rcdata_item *data; 1182{ 1183 struct res_resource *r; 1184 1185 r = define_standard_resource (&resources, RT_RCDATA, id, 1186 resinfo->language, 0); 1187 r->type = RES_TYPE_RCDATA; 1188 r->u.rcdata = data; 1189 r->res_info = *resinfo; 1190} 1191 1192/* Create an rcdata item holding a string. */ 1193 1194struct rcdata_item * 1195define_rcdata_string (string, len) 1196 const char *string; 1197 unsigned long len; 1198{ 1199 struct rcdata_item *ri; 1200 char *s; 1201 1202 ri = (struct rcdata_item *) res_alloc (sizeof *ri); 1203 ri->next = NULL; 1204 ri->type = RCDATA_STRING; 1205 ri->u.string.length = len; 1206 s = (char *) res_alloc (len); 1207 memcpy (s, string, len); 1208 ri->u.string.s = s; 1209 1210 return ri; 1211} 1212 1213/* Create an rcdata item holding a number. */ 1214 1215struct rcdata_item * 1216define_rcdata_number (val, dword) 1217 unsigned long val; 1218 int dword; 1219{ 1220 struct rcdata_item *ri; 1221 1222 ri = (struct rcdata_item *) res_alloc (sizeof *ri); 1223 ri->next = NULL; 1224 ri->type = dword ? RCDATA_DWORD : RCDATA_WORD; 1225 ri->u.word = val; 1226 1227 return ri; 1228} 1229 1230/* Define a stringtable resource. This is called for each string 1231 which appears in a STRINGTABLE statement. */ 1232 1233void 1234define_stringtable (resinfo, stringid, string) 1235 const struct res_res_info *resinfo; 1236 unsigned long stringid; 1237 const char *string; 1238{ 1239 struct res_id id; 1240 struct res_resource *r; 1241 1242 id.named = 0; 1243 id.u.id = (stringid >> 4) + 1; 1244 r = define_standard_resource (&resources, RT_STRING, id, 1245 resinfo->language, 1); 1246 1247 if (r->type == RES_TYPE_UNINITIALIZED) 1248 { 1249 int i; 1250 1251 r->type = RES_TYPE_STRINGTABLE; 1252 r->u.stringtable = ((struct stringtable *) 1253 res_alloc (sizeof (struct stringtable))); 1254 for (i = 0; i < 16; i++) 1255 { 1256 r->u.stringtable->strings[i].length = 0; 1257 r->u.stringtable->strings[i].string = NULL; 1258 } 1259 1260 r->res_info = *resinfo; 1261 } 1262 1263 unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length, 1264 &r->u.stringtable->strings[stringid & 0xf].string, 1265 string); 1266} 1267 1268/* Define a user data resource where the data is in the rc file. */ 1269 1270void 1271define_user_data (id, type, resinfo, data) 1272 struct res_id id; 1273 struct res_id type; 1274 const struct res_res_info *resinfo; 1275 struct rcdata_item *data; 1276{ 1277 struct res_id ids[3]; 1278 struct res_resource *r; 1279 1280 ids[0] = type; 1281 ids[1] = id; 1282 ids[2].named = 0; 1283 ids[2].u.id = resinfo->language; 1284 1285 r = define_resource (&resources, 3, ids, 0); 1286 r->type = RES_TYPE_USERDATA; 1287 r->u.userdata = data; 1288 r->res_info = *resinfo; 1289} 1290 1291/* Define a user data resource where the data is in a file. */ 1292 1293void 1294define_user_file (id, type, resinfo, filename) 1295 struct res_id id; 1296 struct res_id type; 1297 const struct res_res_info *resinfo; 1298 const char *filename; 1299{ 1300 FILE *e; 1301 char *real_filename; 1302 struct stat s; 1303 unsigned char *data; 1304 struct res_id ids[3]; 1305 struct res_resource *r; 1306 1307 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename); 1308 1309 if (stat (real_filename, &s) < 0) 1310 fatal (_("stat failed on bitmap file `%s': %s"), real_filename, 1311 strerror (errno)); 1312 1313 data = (unsigned char *) res_alloc (s.st_size); 1314 1315 get_data (e, data, s.st_size, real_filename); 1316 1317 fclose (e); 1318 free (real_filename); 1319 1320 ids[0] = type; 1321 ids[1] = id; 1322 ids[2].named = 0; 1323 ids[2].u.id = resinfo->language; 1324 1325 r = define_resource (&resources, 3, ids, 0); 1326 r->type = RES_TYPE_USERDATA; 1327 r->u.userdata = ((struct rcdata_item *) 1328 res_alloc (sizeof (struct rcdata_item))); 1329 r->u.userdata->next = NULL; 1330 r->u.userdata->type = RCDATA_BUFFER; 1331 r->u.userdata->u.buffer.length = s.st_size; 1332 r->u.userdata->u.buffer.data = data; 1333 r->res_info = *resinfo; 1334} 1335 1336/* Define a versioninfo resource. */ 1337 1338void 1339define_versioninfo (id, language, fixedverinfo, verinfo) 1340 struct res_id id; 1341 int language; 1342 struct fixed_versioninfo *fixedverinfo; 1343 struct ver_info *verinfo; 1344{ 1345 struct res_resource *r; 1346 1347 r = define_standard_resource (&resources, RT_VERSION, id, language, 0); 1348 r->type = RES_TYPE_VERSIONINFO; 1349 r->u.versioninfo = ((struct versioninfo *) 1350 res_alloc (sizeof (struct versioninfo))); 1351 r->u.versioninfo->fixed = fixedverinfo; 1352 r->u.versioninfo->var = verinfo; 1353 r->res_info.language = language; 1354} 1355 1356/* Add string version info to a list of version information. */ 1357 1358struct ver_info * 1359append_ver_stringfileinfo (verinfo, language, strings) 1360 struct ver_info *verinfo; 1361 const char *language; 1362 struct ver_stringinfo *strings; 1363{ 1364 struct ver_info *vi, **pp; 1365 1366 vi = (struct ver_info *) res_alloc (sizeof *vi); 1367 vi->next = NULL; 1368 vi->type = VERINFO_STRING; 1369 unicode_from_ascii ((int *) NULL, &vi->u.string.language, language); 1370 vi->u.string.strings = strings; 1371 1372 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next) 1373 ; 1374 *pp = vi; 1375 1376 return verinfo; 1377} 1378 1379/* Add variable version info to a list of version information. */ 1380 1381struct ver_info * 1382append_ver_varfileinfo (verinfo, key, var) 1383 struct ver_info *verinfo; 1384 const char *key; 1385 struct ver_varinfo *var; 1386{ 1387 struct ver_info *vi, **pp; 1388 1389 vi = (struct ver_info *) res_alloc (sizeof *vi); 1390 vi->next = NULL; 1391 vi->type = VERINFO_VAR; 1392 unicode_from_ascii ((int *) NULL, &vi->u.var.key, key); 1393 vi->u.var.var = var; 1394 1395 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next) 1396 ; 1397 *pp = vi; 1398 1399 return verinfo; 1400} 1401 1402/* Append version string information to a list. */ 1403 1404struct ver_stringinfo * 1405append_verval (strings, key, value) 1406 struct ver_stringinfo *strings; 1407 const char *key; 1408 const char *value; 1409{ 1410 struct ver_stringinfo *vs, **pp; 1411 1412 vs = (struct ver_stringinfo *) res_alloc (sizeof *vs); 1413 vs->next = NULL; 1414 unicode_from_ascii ((int *) NULL, &vs->key, key); 1415 unicode_from_ascii ((int *) NULL, &vs->value, value); 1416 1417 for (pp = &strings; *pp != NULL; pp = &(*pp)->next) 1418 ; 1419 *pp = vs; 1420 1421 return strings; 1422} 1423 1424/* Append version variable information to a list. */ 1425 1426struct ver_varinfo * 1427append_vertrans (var, language, charset) 1428 struct ver_varinfo *var; 1429 unsigned long language; 1430 unsigned long charset; 1431{ 1432 struct ver_varinfo *vv, **pp; 1433 1434 vv = (struct ver_varinfo *) res_alloc (sizeof *vv); 1435 vv->next = NULL; 1436 vv->language = language; 1437 vv->charset = charset; 1438 1439 for (pp = &var; *pp != NULL; pp = &(*pp)->next) 1440 ; 1441 *pp = vv; 1442 1443 return var; 1444} 1445 1446/* Local functions used to write out an rc file. */ 1447 1448static void indent PARAMS ((FILE *, int)); 1449static void write_rc_directory 1450 PARAMS ((FILE *, const struct res_directory *, const struct res_id *, 1451 const struct res_id *, int *, int)); 1452static void write_rc_subdir 1453 PARAMS ((FILE *, const struct res_entry *, const struct res_id *, 1454 const struct res_id *, int *, int)); 1455static void write_rc_resource 1456 PARAMS ((FILE *, const struct res_id *, const struct res_id *, 1457 const struct res_resource *, int *)); 1458static void write_rc_accelerators 1459 PARAMS ((FILE *, const struct accelerator *)); 1460static void write_rc_cursor PARAMS ((FILE *, const struct cursor *)); 1461static void write_rc_group_cursor 1462 PARAMS ((FILE *, const struct group_cursor *)); 1463static void write_rc_dialog PARAMS ((FILE *, const struct dialog *)); 1464static void write_rc_dialog_control 1465 PARAMS ((FILE *, const struct dialog_control *)); 1466static void write_rc_fontdir PARAMS ((FILE *, const struct fontdir *)); 1467static void write_rc_group_icon PARAMS ((FILE *, const struct group_icon *)); 1468static void write_rc_menu PARAMS ((FILE *, const struct menu *, int)); 1469static void write_rc_menuitems 1470 PARAMS ((FILE *, const struct menuitem *, int, int)); 1471static void write_rc_rcdata PARAMS ((FILE *, const struct rcdata_item *, int)); 1472static void write_rc_stringtable 1473 PARAMS ((FILE *, const struct res_id *, const struct stringtable *)); 1474static void write_rc_versioninfo PARAMS ((FILE *, const struct versioninfo *)); 1475static void write_rc_filedata 1476 PARAMS ((FILE *, unsigned long, const unsigned char *)); 1477 1478/* Indent a given number of spaces. */ 1479 1480static void 1481indent (e, c) 1482 FILE *e; 1483 int c; 1484{ 1485 int i; 1486 1487 for (i = 0; i < c; i++) 1488 putc (' ', e); 1489} 1490 1491/* Dump the resources we have read in the format of an rc file. 1492 1493 Actually, we don't use the format of an rc file, because it's way 1494 too much of a pain--for example, we'd have to write icon resources 1495 into a file and refer to that file. We just generate a readable 1496 format that kind of looks like an rc file, and is useful for 1497 understanding the contents of a resource file. Someday we may want 1498 to generate an rc file which the rc compiler can read; if that day 1499 comes, this code will have to be fixed up. */ 1500 1501void 1502write_rc_file (filename, resources) 1503 const char *filename; 1504 const struct res_directory *resources; 1505{ 1506 FILE *e; 1507 int language; 1508 1509 if (filename == NULL) 1510 e = stdout; 1511 else 1512 { 1513 e = fopen (filename, FOPEN_WT); 1514 if (e == NULL) 1515 fatal (_("can't open `%s' for output: %s"), filename, strerror (errno)); 1516 } 1517 1518 language = -1; 1519 write_rc_directory (e, resources, (const struct res_id *) NULL, 1520 (const struct res_id *) NULL, &language, 1); 1521} 1522 1523/* Write out a directory. E is the file to write to. RD is the 1524 directory. TYPE is a pointer to the level 1 ID which serves as the 1525 resource type. NAME is a pointer to the level 2 ID which serves as 1526 an individual resource name. LANGUAGE is a pointer to the current 1527 language. LEVEL is the level in the tree. */ 1528 1529static void 1530write_rc_directory (e, rd, type, name, language, level) 1531 FILE *e; 1532 const struct res_directory *rd; 1533 const struct res_id *type; 1534 const struct res_id *name; 1535 int *language; 1536 int level; 1537{ 1538 const struct res_entry *re; 1539 1540 /* Print out some COFF information that rc files can't represent. */ 1541 1542 if (rd->time != 0) 1543 fprintf (e, "// Time stamp: %lu\n", rd->time); 1544 if (rd->characteristics != 0) 1545 fprintf (e, "// Characteristics: %lu\n", rd->characteristics); 1546 if (rd->major != 0 || rd->minor != 0) 1547 fprintf (e, "// Version: %d %d\n", rd->major, rd->minor); 1548 1549 for (re = rd->entries; re != NULL; re = re->next) 1550 { 1551 switch (level) 1552 { 1553 case 1: 1554 /* If we're at level 1, the key of this resource is the 1555 type. This normally duplicates the information we have 1556 stored with the resource itself, but we need to remember 1557 the type if this is a user define resource type. */ 1558 type = &re->id; 1559 break; 1560 1561 case 2: 1562 /* If we're at level 2, the key of this resource is the name 1563 we are going to use in the rc printout. */ 1564 name = &re->id; 1565 break; 1566 1567 case 3: 1568 /* If we're at level 3, then this key represents a language. 1569 Use it to update the current language. */ 1570 if (! re->id.named 1571 && re->id.u.id != (unsigned long) (unsigned int) *language 1572 && (re->id.u.id & 0xffff) == re->id.u.id) 1573 { 1574 fprintf (e, "LANGUAGE %lu, %lu\n", 1575 re->id.u.id & 0xff, (re->id.u.id >> 8) & 0xff); 1576 *language = re->id.u.id; 1577 } 1578 break; 1579 1580 default: 1581 break; 1582 } 1583 1584 if (re->subdir) 1585 write_rc_subdir (e, re, type, name, language, level); 1586 else 1587 { 1588 if (level == 3) 1589 { 1590 /* This is the normal case: the three levels are 1591 TYPE/NAME/LANGUAGE. NAME will have been set at level 1592 2, and represents the name to use. We probably just 1593 set LANGUAGE, and it will probably match what the 1594 resource itself records if anything. */ 1595 write_rc_resource (e, type, name, re->u.res, language); 1596 } 1597 else 1598 { 1599 fprintf (e, "// Resource at unexpected level %d\n", level); 1600 write_rc_resource (e, type, (struct res_id *) NULL, re->u.res, 1601 language); 1602 } 1603 } 1604 } 1605} 1606 1607/* Write out a subdirectory entry. E is the file to write to. RE is 1608 the subdirectory entry. TYPE and NAME are pointers to higher level 1609 IDs, or NULL. LANGUAGE is a pointer to the current language. 1610 LEVEL is the level in the tree. */ 1611 1612static void 1613write_rc_subdir (e, re, type, name, language, level) 1614 FILE *e; 1615 const struct res_entry *re; 1616 const struct res_id *type; 1617 const struct res_id *name; 1618 int *language; 1619 int level; 1620{ 1621 fprintf (e, "\n"); 1622 switch (level) 1623 { 1624 case 1: 1625 fprintf (e, "// Type: "); 1626 if (re->id.named) 1627 res_id_print (e, re->id, 1); 1628 else 1629 { 1630 const char *s; 1631 1632 switch (re->id.u.id) 1633 { 1634 case RT_CURSOR: s = "cursor"; break; 1635 case RT_BITMAP: s = "bitmap"; break; 1636 case RT_ICON: s = "icon"; break; 1637 case RT_MENU: s = "menu"; break; 1638 case RT_DIALOG: s = "dialog"; break; 1639 case RT_STRING: s = "stringtable"; break; 1640 case RT_FONTDIR: s = "fontdir"; break; 1641 case RT_FONT: s = "font"; break; 1642 case RT_ACCELERATOR: s = "accelerators"; break; 1643 case RT_RCDATA: s = "rcdata"; break; 1644 case RT_MESSAGETABLE: s = "messagetable"; break; 1645 case RT_GROUP_CURSOR: s = "group cursor"; break; 1646 case RT_GROUP_ICON: s = "group icon"; break; 1647 case RT_VERSION: s = "version"; break; 1648 case RT_DLGINCLUDE: s = "dlginclude"; break; 1649 case RT_PLUGPLAY: s = "plugplay"; break; 1650 case RT_VXD: s = "vxd"; break; 1651 case RT_ANICURSOR: s = "anicursor"; break; 1652 case RT_ANIICON: s = "aniicon"; break; 1653 default: s = NULL; break; 1654 } 1655 1656 if (s != NULL) 1657 fprintf (e, "%s", s); 1658 else 1659 res_id_print (e, re->id, 1); 1660 } 1661 fprintf (e, "\n"); 1662 break; 1663 1664 case 2: 1665 fprintf (e, "// Name: "); 1666 res_id_print (e, re->id, 1); 1667 fprintf (e, "\n"); 1668 break; 1669 1670 case 3: 1671 fprintf (e, "// Language: "); 1672 res_id_print (e, re->id, 1); 1673 fprintf (e, "\n"); 1674 break; 1675 1676 default: 1677 fprintf (e, "// Level %d: ", level); 1678 res_id_print (e, re->id, 1); 1679 fprintf (e, "\n"); 1680 } 1681 1682 write_rc_directory (e, re->u.dir, type, name, language, level + 1); 1683} 1684 1685/* Write out a single resource. E is the file to write to. TYPE is a 1686 pointer to the type of the resource. NAME is a pointer to the name 1687 of the resource; it will be NULL if there is a level mismatch. RES 1688 is the resource data. LANGUAGE is a pointer to the current 1689 language. */ 1690 1691static void 1692write_rc_resource (e, type, name, res, language) 1693 FILE *e; 1694 const struct res_id *type; 1695 const struct res_id *name; 1696 const struct res_resource *res; 1697 int *language; 1698{ 1699 const char *s; 1700 int rt; 1701 int menuex = 0; 1702 1703 fprintf (e, "\n"); 1704 1705 switch (res->type) 1706 { 1707 default: 1708 abort (); 1709 1710 case RES_TYPE_ACCELERATOR: 1711 s = "ACCELERATOR"; 1712 rt = RT_ACCELERATOR; 1713 break; 1714 1715 case RES_TYPE_BITMAP: 1716 s = "BITMAP"; 1717 rt = RT_BITMAP; 1718 break; 1719 1720 case RES_TYPE_CURSOR: 1721 s = "CURSOR"; 1722 rt = RT_CURSOR; 1723 break; 1724 1725 case RES_TYPE_GROUP_CURSOR: 1726 s = "GROUP_CURSOR"; 1727 rt = RT_GROUP_CURSOR; 1728 break; 1729 1730 case RES_TYPE_DIALOG: 1731 if (extended_dialog (res->u.dialog)) 1732 s = "DIALOGEX"; 1733 else 1734 s = "DIALOG"; 1735 rt = RT_DIALOG; 1736 break; 1737 1738 case RES_TYPE_FONT: 1739 s = "FONT"; 1740 rt = RT_FONT; 1741 break; 1742 1743 case RES_TYPE_FONTDIR: 1744 s = "FONTDIR"; 1745 rt = RT_FONTDIR; 1746 break; 1747 1748 case RES_TYPE_ICON: 1749 s = "ICON"; 1750 rt = RT_ICON; 1751 break; 1752 1753 case RES_TYPE_GROUP_ICON: 1754 s = "GROUP_ICON"; 1755 rt = RT_GROUP_ICON; 1756 break; 1757 1758 case RES_TYPE_MENU: 1759 if (extended_menu (res->u.menu)) 1760 { 1761 s = "MENUEX"; 1762 menuex = 1; 1763 } 1764 else 1765 { 1766 s = "MENU"; 1767 menuex = 0; 1768 } 1769 rt = RT_MENU; 1770 break; 1771 1772 case RES_TYPE_MESSAGETABLE: 1773 s = "MESSAGETABLE"; 1774 rt = RT_MESSAGETABLE; 1775 break; 1776 1777 case RES_TYPE_RCDATA: 1778 s = "RCDATA"; 1779 rt = RT_RCDATA; 1780 break; 1781 1782 case RES_TYPE_STRINGTABLE: 1783 s = "STRINGTABLE"; 1784 rt = RT_STRING; 1785 break; 1786 1787 case RES_TYPE_USERDATA: 1788 s = NULL; 1789 rt = 0; 1790 break; 1791 1792 case RES_TYPE_VERSIONINFO: 1793 s = "VERSIONINFO"; 1794 rt = RT_VERSION; 1795 break; 1796 } 1797 1798 if (rt != 0 1799 && type != NULL 1800 && (type->named || type->u.id != (unsigned long) rt)) 1801 { 1802 fprintf (e, "// Unexpected resource type mismatch: "); 1803 res_id_print (e, *type, 1); 1804 fprintf (e, " != %d", rt); 1805 } 1806 1807 if (res->coff_info.codepage != 0) 1808 fprintf (e, "// Code page: %lu\n", res->coff_info.codepage); 1809 if (res->coff_info.reserved != 0) 1810 fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved); 1811 1812 if (name != NULL) 1813 res_id_print (e, *name, 0); 1814 else 1815 fprintf (e, "??Unknown-Name??"); 1816 1817 fprintf (e, " "); 1818 if (s != NULL) 1819 fprintf (e, "%s", s); 1820 else if (type != NULL) 1821 res_id_print (e, *type, 0); 1822 else 1823 fprintf (e, "??Unknown-Type??"); 1824 1825 if (res->res_info.memflags != 0) 1826 { 1827 if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0) 1828 fprintf (e, " MOVEABLE"); 1829 if ((res->res_info.memflags & MEMFLAG_PURE) != 0) 1830 fprintf (e, " PURE"); 1831 if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0) 1832 fprintf (e, " PRELOAD"); 1833 if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0) 1834 fprintf (e, " DISCARDABLE"); 1835 } 1836 1837 if (res->type == RES_TYPE_DIALOG) 1838 { 1839 fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y, 1840 res->u.dialog->width, res->u.dialog->height); 1841 if (res->u.dialog->ex != NULL 1842 && res->u.dialog->ex->help != 0) 1843 fprintf (e, ", %lu", res->u.dialog->ex->help); 1844 } 1845 1846 fprintf (e, "\n"); 1847 1848 if ((res->res_info.language != 0 && res->res_info.language != *language) 1849 || res->res_info.characteristics != 0 1850 || res->res_info.version != 0) 1851 { 1852 int modifiers; 1853 1854 switch (res->type) 1855 { 1856 case RES_TYPE_ACCELERATOR: 1857 case RES_TYPE_DIALOG: 1858 case RES_TYPE_MENU: 1859 case RES_TYPE_RCDATA: 1860 case RES_TYPE_STRINGTABLE: 1861 modifiers = 1; 1862 break; 1863 1864 default: 1865 modifiers = 0; 1866 break; 1867 } 1868 1869 if (res->res_info.language != 0 && res->res_info.language != *language) 1870 fprintf (e, "%sLANGUAGE %d, %d\n", 1871 modifiers ? "// " : "", 1872 res->res_info.language & 0xff, 1873 (res->res_info.language >> 8) & 0xff); 1874 if (res->res_info.characteristics != 0) 1875 fprintf (e, "%sCHARACTERISTICS %lu\n", 1876 modifiers ? "// " : "", 1877 res->res_info.characteristics); 1878 if (res->res_info.version != 0) 1879 fprintf (e, "%sVERSION %lu\n", 1880 modifiers ? "// " : "", 1881 res->res_info.version); 1882 } 1883 1884 switch (res->type) 1885 { 1886 default: 1887 abort (); 1888 1889 case RES_TYPE_ACCELERATOR: 1890 write_rc_accelerators (e, res->u.acc); 1891 break; 1892 1893 case RES_TYPE_CURSOR: 1894 write_rc_cursor (e, res->u.cursor); 1895 break; 1896 1897 case RES_TYPE_GROUP_CURSOR: 1898 write_rc_group_cursor (e, res->u.group_cursor); 1899 break; 1900 1901 case RES_TYPE_DIALOG: 1902 write_rc_dialog (e, res->u.dialog); 1903 break; 1904 1905 case RES_TYPE_FONTDIR: 1906 write_rc_fontdir (e, res->u.fontdir); 1907 break; 1908 1909 case RES_TYPE_GROUP_ICON: 1910 write_rc_group_icon (e, res->u.group_icon); 1911 break; 1912 1913 case RES_TYPE_MENU: 1914 write_rc_menu (e, res->u.menu, menuex); 1915 break; 1916 1917 case RES_TYPE_RCDATA: 1918 write_rc_rcdata (e, res->u.rcdata, 0); 1919 break; 1920 1921 case RES_TYPE_STRINGTABLE: 1922 write_rc_stringtable (e, name, res->u.stringtable); 1923 break; 1924 1925 case RES_TYPE_USERDATA: 1926 write_rc_rcdata (e, res->u.userdata, 0); 1927 break; 1928 1929 case RES_TYPE_VERSIONINFO: 1930 write_rc_versioninfo (e, res->u.versioninfo); 1931 break; 1932 1933 case RES_TYPE_BITMAP: 1934 case RES_TYPE_FONT: 1935 case RES_TYPE_ICON: 1936 case RES_TYPE_MESSAGETABLE: 1937 write_rc_filedata (e, res->u.data.length, res->u.data.data); 1938 break; 1939 } 1940} 1941 1942/* Write out accelerator information. */ 1943 1944static void 1945write_rc_accelerators (e, accelerators) 1946 FILE *e; 1947 const struct accelerator *accelerators; 1948{ 1949 const struct accelerator *acc; 1950 1951 fprintf (e, "BEGIN\n"); 1952 for (acc = accelerators; acc != NULL; acc = acc->next) 1953 { 1954 int printable; 1955 1956 fprintf (e, " "); 1957 1958 if ((acc->key & 0x7f) == acc->key 1959 && isprint ((unsigned char) acc->key) 1960 && (acc->flags & ACC_VIRTKEY) == 0) 1961 { 1962 fprintf (e, "\"%c\"", acc->key); 1963 printable = 1; 1964 } 1965 else 1966 { 1967 fprintf (e, "%d", acc->key); 1968 printable = 0; 1969 } 1970 1971 fprintf (e, ", %d", acc->id); 1972 1973 if (! printable) 1974 { 1975 if ((acc->flags & ACC_VIRTKEY) != 0) 1976 fprintf (e, ", VIRTKEY"); 1977 else 1978 fprintf (e, ", ASCII"); 1979 } 1980 1981 if ((acc->flags & ACC_SHIFT) != 0) 1982 fprintf (e, ", SHIFT"); 1983 if ((acc->flags & ACC_CONTROL) != 0) 1984 fprintf (e, ", CONTROL"); 1985 if ((acc->flags & ACC_ALT) != 0) 1986 fprintf (e, ", ALT"); 1987 1988 fprintf (e, "\n"); 1989 } 1990 1991 fprintf (e, "END\n"); 1992} 1993 1994/* Write out cursor information. This would normally be in a separate 1995 file, which the rc file would include. */ 1996 1997static void 1998write_rc_cursor (e, cursor) 1999 FILE *e; 2000 const struct cursor *cursor; 2001{ 2002 fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot, 2003 cursor->yhotspot); 2004 write_rc_filedata (e, cursor->length, cursor->data); 2005} 2006 2007/* Write out group cursor data. This would normally be built from the 2008 cursor data. */ 2009 2010static void 2011write_rc_group_cursor (e, group_cursor) 2012 FILE *e; 2013 const struct group_cursor *group_cursor; 2014{ 2015 const struct group_cursor *gc; 2016 2017 for (gc = group_cursor; gc != NULL; gc = gc->next) 2018 { 2019 fprintf (e, "// width: %d; height %d; planes %d; bits %d\n", 2020 gc->width, gc->height, gc->planes, gc->bits); 2021 fprintf (e, "// data bytes: %lu; index: %d\n", 2022 gc->bytes, gc->index); 2023 } 2024} 2025 2026/* Write dialog data. */ 2027 2028static void 2029write_rc_dialog (e, dialog) 2030 FILE *e; 2031 const struct dialog *dialog; 2032{ 2033 const struct dialog_control *control; 2034 2035 if (dialog->style != 0) 2036 fprintf (e, "STYLE 0x%lx\n", dialog->style); 2037 if (dialog->exstyle != 0) 2038 fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle); 2039 if ((dialog->class.named && dialog->class.u.n.length > 0) 2040 || dialog->class.u.id != 0) 2041 { 2042 fprintf (e, "CLASS "); 2043 res_id_print (e, dialog->class, 0); 2044 fprintf (e, "\n"); 2045 } 2046 if (dialog->caption != NULL) 2047 { 2048 fprintf (e, "CAPTION \""); 2049 unicode_print (e, dialog->caption, -1); 2050 fprintf (e, "\"\n"); 2051 } 2052 if ((dialog->menu.named && dialog->menu.u.n.length > 0) 2053 || dialog->menu.u.id != 0) 2054 { 2055 fprintf (e, "MENU "); 2056 res_id_print (e, dialog->menu, 0); 2057 fprintf (e, "\n"); 2058 } 2059 if (dialog->font != NULL) 2060 { 2061 fprintf (e, "FONT %d, \"", dialog->pointsize); 2062 unicode_print (e, dialog->font, -1); 2063 fprintf (e, "\""); 2064 if (dialog->ex != NULL 2065 && (dialog->ex->weight != 0 || dialog->ex->italic != 0)) 2066 fprintf (e, ", %d, %d", dialog->ex->weight, dialog->ex->italic); 2067 fprintf (e, "\n"); 2068 } 2069 2070 fprintf (e, "BEGIN\n"); 2071 2072 for (control = dialog->controls; control != NULL; control = control->next) 2073 write_rc_dialog_control (e, control); 2074 2075 fprintf (e, "END\n"); 2076} 2077 2078/* For each predefined control keyword, this table provides the class 2079 and the style. */ 2080 2081struct control_info 2082{ 2083 const char *name; 2084 unsigned short class; 2085 unsigned long style; 2086}; 2087 2088static const struct control_info control_info[] = 2089{ 2090 { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE }, 2091 { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX }, 2092 { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON }, 2093 { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX }, 2094 { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 }, 2095 { "CTEXT", CTL_STATIC, SS_CENTER }, 2096 { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON }, 2097 { "EDITTEXT", CTL_EDIT, (unsigned long) -1 }, 2098 { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX }, 2099 { "ICON", CTL_STATIC, SS_ICON }, 2100 { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 }, 2101 { "LTEXT", CTL_STATIC, SS_LEFT }, 2102 { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX }, 2103 { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON }, 2104 { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON }, 2105 { "RTEXT", CTL_STATIC, SS_RIGHT }, 2106 { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 }, 2107 { "STATE3", CTL_BUTTON, BS_3STATE }, 2108 /* It's important that USERBUTTON come after all the other button 2109 types, so that it won't be matched too early. */ 2110 { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 }, 2111 { NULL, 0, 0 } 2112}; 2113 2114/* Write a dialog control. */ 2115 2116static void 2117write_rc_dialog_control (e, control) 2118 FILE *e; 2119 const struct dialog_control *control; 2120{ 2121 const struct control_info *ci; 2122 2123 fprintf (e, " "); 2124 2125 if (control->class.named) 2126 ci = NULL; 2127 else 2128 { 2129 for (ci = control_info; ci->name != NULL; ++ci) 2130 if (ci->class == control->class.u.id 2131 && (ci->style == (unsigned long) -1 2132 || ci->style == (control->style & 0xff))) 2133 break; 2134 } 2135 if (ci == NULL) 2136 fprintf (e, "CONTROL"); 2137 else if (ci->name != NULL) 2138 fprintf (e, "%s", ci->name); 2139 else 2140 fprintf (e, "CONTROL"); 2141 2142 if (control->text.named || control->text.u.id != 0) 2143 { 2144 fprintf (e, " "); 2145 res_id_print (e, control->text, 1); 2146 fprintf (e, ","); 2147 } 2148 2149 fprintf (e, " %d, ", control->id); 2150 2151 if (ci == NULL) 2152 { 2153 if (control->class.named) 2154 fprintf (e, "\""); 2155 res_id_print (e, control->class, 0); 2156 if (control->class.named) 2157 fprintf (e, "\""); 2158 fprintf (e, ", 0x%lx, ", control->style); 2159 } 2160 2161 fprintf (e, "%d, %d", control->x, control->y); 2162 2163 if (control->style != SS_ICON 2164 || control->exstyle != 0 2165 || control->width != 0 2166 || control->height != 0 2167 || control->help != 0) 2168 { 2169 fprintf (e, ", %d, %d", control->width, control->height); 2170 2171 /* FIXME: We don't need to print the style if it is the default. 2172 More importantly, in certain cases we actually need to turn 2173 off parts of the forced style, by using NOT. */ 2174 fprintf (e, ", 0x%lx", control->style); 2175 2176 if (control->exstyle != 0 || control->help != 0) 2177 fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help); 2178 } 2179 2180 fprintf (e, "\n"); 2181 2182 if (control->data != NULL) 2183 write_rc_rcdata (e, control->data, 2); 2184} 2185 2186/* Write out font directory data. This would normally be built from 2187 the font data. */ 2188 2189static void 2190write_rc_fontdir (e, fontdir) 2191 FILE *e; 2192 const struct fontdir *fontdir; 2193{ 2194 const struct fontdir *fc; 2195 2196 for (fc = fontdir; fc != NULL; fc = fc->next) 2197 { 2198 fprintf (e, "// Font index: %d\n", fc->index); 2199 write_rc_filedata (e, fc->length, fc->data); 2200 } 2201} 2202 2203/* Write out group icon data. This would normally be built from the 2204 icon data. */ 2205 2206static void 2207write_rc_group_icon (e, group_icon) 2208 FILE *e; 2209 const struct group_icon *group_icon; 2210{ 2211 const struct group_icon *gi; 2212 2213 for (gi = group_icon; gi != NULL; gi = gi->next) 2214 { 2215 fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n", 2216 gi->width, gi->height, gi->colors, gi->planes, gi->bits); 2217 fprintf (e, "// data bytes: %lu; index: %d\n", 2218 gi->bytes, gi->index); 2219 } 2220} 2221 2222/* Write out a menu resource. */ 2223 2224static void 2225write_rc_menu (e, menu, menuex) 2226 FILE *e; 2227 const struct menu *menu; 2228 int menuex; 2229{ 2230 if (menu->help != 0) 2231 fprintf (e, "// Help ID: %lu\n", menu->help); 2232 write_rc_menuitems (e, menu->items, menuex, 0); 2233} 2234 2235/* Write out menuitems. */ 2236 2237static void 2238write_rc_menuitems (e, menuitems, menuex, ind) 2239 FILE *e; 2240 const struct menuitem *menuitems; 2241 int menuex; 2242 int ind; 2243{ 2244 const struct menuitem *mi; 2245 2246 indent (e, ind); 2247 fprintf (e, "BEGIN\n"); 2248 2249 for (mi = menuitems; mi != NULL; mi = mi->next) 2250 { 2251 indent (e, ind + 2); 2252 2253 if (mi->popup == NULL) 2254 fprintf (e, "MENUITEM"); 2255 else 2256 fprintf (e, "POPUP"); 2257 2258 if (! menuex 2259 && mi->popup == NULL 2260 && mi->text == NULL 2261 && mi->type == 0 2262 && mi->id == 0) 2263 { 2264 fprintf (e, " SEPARATOR\n"); 2265 continue; 2266 } 2267 2268 if (mi->text == NULL) 2269 fprintf (e, " \"\""); 2270 else 2271 { 2272 fprintf (e, " \""); 2273 unicode_print (e, mi->text, -1); 2274 fprintf (e, "\""); 2275 } 2276 2277 if (! menuex) 2278 { 2279 if (mi->popup == NULL) 2280 fprintf (e, ", %d", mi->id); 2281 2282 if ((mi->type & MENUITEM_CHECKED) != 0) 2283 fprintf (e, ", CHECKED"); 2284 if ((mi->type & MENUITEM_GRAYED) != 0) 2285 fprintf (e, ", GRAYED"); 2286 if ((mi->type & MENUITEM_HELP) != 0) 2287 fprintf (e, ", HELP"); 2288 if ((mi->type & MENUITEM_INACTIVE) != 0) 2289 fprintf (e, ", INACTIVE"); 2290 if ((mi->type & MENUITEM_MENUBARBREAK) != 0) 2291 fprintf (e, ", MENUBARBREAK"); 2292 if ((mi->type & MENUITEM_MENUBREAK) != 0) 2293 fprintf (e, ", MENUBREAK"); 2294 } 2295 else 2296 { 2297 if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0) 2298 { 2299 fprintf (e, ", %d", mi->id); 2300 if (mi->type != 0 || mi->state != 0 || mi->help != 0) 2301 { 2302 fprintf (e, ", %lu", mi->type); 2303 if (mi->state != 0 || mi->help != 0) 2304 { 2305 fprintf (e, ", %lu", mi->state); 2306 if (mi->help != 0) 2307 fprintf (e, ", %lu", mi->help); 2308 } 2309 } 2310 } 2311 } 2312 2313 fprintf (e, "\n"); 2314 2315 if (mi->popup != NULL) 2316 write_rc_menuitems (e, mi->popup, menuex, ind + 2); 2317 } 2318 2319 indent (e, ind); 2320 fprintf (e, "END\n"); 2321} 2322 2323/* Write out an rcdata resource. This is also used for other types of 2324 resources that need to print arbitrary data. */ 2325 2326static void 2327write_rc_rcdata (e, rcdata, ind) 2328 FILE *e; 2329 const struct rcdata_item *rcdata; 2330 int ind; 2331{ 2332 const struct rcdata_item *ri; 2333 2334 indent (e, ind); 2335 fprintf (e, "BEGIN\n"); 2336 2337 for (ri = rcdata; ri != NULL; ri = ri->next) 2338 { 2339 if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0) 2340 continue; 2341 2342 indent (e, ind + 2); 2343 2344 switch (ri->type) 2345 { 2346 default: 2347 abort (); 2348 2349 case RCDATA_WORD: 2350 fprintf (e, "%d", ri->u.word); 2351 break; 2352 2353 case RCDATA_DWORD: 2354 fprintf (e, "%luL", ri->u.dword); 2355 break; 2356 2357 case RCDATA_STRING: 2358 { 2359 const char *s; 2360 unsigned long i; 2361 2362 fprintf (e, "\""); 2363 s = ri->u.string.s; 2364 for (i = 0; i < ri->u.string.length; i++) 2365 { 2366 if (isprint ((unsigned char) *s)) 2367 putc (*s, e); 2368 else 2369 fprintf (e, "\\%03o", *s); 2370 } 2371 fprintf (e, "\""); 2372 break; 2373 } 2374 2375 case RCDATA_WSTRING: 2376 fprintf (e, "L\""); 2377 unicode_print (e, ri->u.wstring.w, ri->u.wstring.length); 2378 fprintf (e, "\""); 2379 break; 2380 2381 case RCDATA_BUFFER: 2382 { 2383 unsigned long i; 2384 int first; 2385 2386 /* Assume little endian data. */ 2387 2388 first = 1; 2389 for (i = 0; i + 3 < ri->u.buffer.length; i += 4) 2390 { 2391 unsigned long l; 2392 int j; 2393 2394 if (! first) 2395 indent (e, ind + 2); 2396 l = ((((((ri->u.buffer.data[i + 3] << 8) 2397 | ri->u.buffer.data[i + 2]) << 8) 2398 | ri->u.buffer.data[i + 1]) << 8) 2399 | ri->u.buffer.data[i]); 2400 fprintf (e, "%luL", l); 2401 if (i + 4 < ri->u.buffer.length || ri->next != NULL) 2402 fprintf (e, ","); 2403 for (j = 0; j < 4; ++j) 2404 if (! isprint (ri->u.buffer.data[i + j]) 2405 && ri->u.buffer.data[i + j] != 0) 2406 break; 2407 if (j >= 4) 2408 { 2409 fprintf (e, "\t// "); 2410 for (j = 0; j < 4; ++j) 2411 { 2412 if (! isprint (ri->u.buffer.data[i + j])) 2413 fprintf (e, "\\%03o", ri->u.buffer.data[i + j]); 2414 else 2415 { 2416 if (ri->u.buffer.data[i + j] == '\\') 2417 fprintf (e, "\\"); 2418 fprintf (e, "%c", ri->u.buffer.data[i + j]); 2419 } 2420 } 2421 } 2422 fprintf (e, "\n"); 2423 first = 0; 2424 } 2425 2426 if (i + 1 < ri->u.buffer.length) 2427 { 2428 int s; 2429 int j; 2430 2431 if (! first) 2432 indent (e, ind + 2); 2433 s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i]; 2434 fprintf (e, "%d", s); 2435 if (i + 2 < ri->u.buffer.length || ri->next != NULL) 2436 fprintf (e, ","); 2437 for (j = 0; j < 2; ++j) 2438 if (! isprint (ri->u.buffer.data[i + j]) 2439 && ri->u.buffer.data[i + j] != 0) 2440 break; 2441 if (j >= 2) 2442 { 2443 fprintf (e, "\t// "); 2444 for (j = 0; j < 2; ++j) 2445 { 2446 if (! isprint (ri->u.buffer.data[i + j])) 2447 fprintf (e, "\\%03o", ri->u.buffer.data[i + j]); 2448 else 2449 { 2450 if (ri->u.buffer.data[i + j] == '\\') 2451 fprintf (e, "\\"); 2452 fprintf (e, "%c", ri->u.buffer.data[i + j]); 2453 } 2454 } 2455 } 2456 fprintf (e, "\n"); 2457 i += 2; 2458 first = 0; 2459 } 2460 2461 if (i < ri->u.buffer.length) 2462 { 2463 if (! first) 2464 indent (e, ind + 2); 2465 if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i] 2466 && isprint (ri->u.buffer.data[i])) 2467 fprintf (e, "\"%c\"", ri->u.buffer.data[i]); 2468 else 2469 fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]); 2470 if (ri->next != NULL) 2471 fprintf (e, ","); 2472 fprintf (e, "\n"); 2473 first = 0; 2474 } 2475 2476 break; 2477 } 2478 } 2479 2480 if (ri->type != RCDATA_BUFFER) 2481 { 2482 if (ri->next != NULL) 2483 fprintf (e, ","); 2484 fprintf (e, "\n"); 2485 } 2486 } 2487 2488 indent (e, ind); 2489 fprintf (e, "END\n"); 2490} 2491 2492/* Write out a stringtable resource. */ 2493 2494static void 2495write_rc_stringtable (e, name, stringtable) 2496 FILE *e; 2497 const struct res_id *name; 2498 const struct stringtable *stringtable; 2499{ 2500 unsigned long offset; 2501 int i; 2502 2503 if (name != NULL && ! name->named) 2504 offset = (name->u.id - 1) << 4; 2505 else 2506 { 2507 fprintf (e, "// %s string table name\n", 2508 name == NULL ? "Missing" : "Invalid"); 2509 offset = 0; 2510 } 2511 2512 fprintf (e, "BEGIN\n"); 2513 2514 for (i = 0; i < 16; i++) 2515 { 2516 if (stringtable->strings[i].length != 0) 2517 { 2518 fprintf (e, " %lu, \"", offset + i); 2519 unicode_print (e, stringtable->strings[i].string, 2520 stringtable->strings[i].length); 2521 fprintf (e, "\"\n"); 2522 } 2523 } 2524 2525 fprintf (e, "END\n"); 2526} 2527 2528/* Write out a versioninfo resource. */ 2529 2530static void 2531write_rc_versioninfo (e, versioninfo) 2532 FILE *e; 2533 const struct versioninfo *versioninfo; 2534{ 2535 const struct fixed_versioninfo *f; 2536 const struct ver_info *vi; 2537 2538 f = versioninfo->fixed; 2539 if (f->file_version_ms != 0 || f->file_version_ls != 0) 2540 fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n", 2541 (f->file_version_ms >> 16) & 0xffff, 2542 f->file_version_ms & 0xffff, 2543 (f->file_version_ls >> 16) & 0xffff, 2544 f->file_version_ls & 0xffff); 2545 if (f->product_version_ms != 0 || f->product_version_ls != 0) 2546 fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n", 2547 (f->product_version_ms >> 16) & 0xffff, 2548 f->product_version_ms & 0xffff, 2549 (f->product_version_ls >> 16) & 0xffff, 2550 f->product_version_ls & 0xffff); 2551 if (f->file_flags_mask != 0) 2552 fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask); 2553 if (f->file_flags != 0) 2554 fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags); 2555 if (f->file_os != 0) 2556 fprintf (e, " FILEOS 0x%lx\n", f->file_os); 2557 if (f->file_type != 0) 2558 fprintf (e, " FILETYPE 0x%lx\n", f->file_type); 2559 if (f->file_subtype != 0) 2560 fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype); 2561 if (f->file_date_ms != 0 || f->file_date_ls != 0) 2562 fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls); 2563 2564 fprintf (e, "BEGIN\n"); 2565 2566 for (vi = versioninfo->var; vi != NULL; vi = vi->next) 2567 { 2568 switch (vi->type) 2569 { 2570 case VERINFO_STRING: 2571 { 2572 const struct ver_stringinfo *vs; 2573 2574 fprintf (e, " BLOCK \"StringFileInfo\"\n"); 2575 fprintf (e, " BEGIN\n"); 2576 fprintf (e, " BLOCK \""); 2577 unicode_print (e, vi->u.string.language, -1); 2578 fprintf (e, "\"\n"); 2579 fprintf (e, " BEGIN\n"); 2580 2581 for (vs = vi->u.string.strings; vs != NULL; vs = vs->next) 2582 { 2583 fprintf (e, " VALUE \""); 2584 unicode_print (e, vs->key, -1); 2585 fprintf (e, "\", \""); 2586 unicode_print (e, vs->value, -1); 2587 fprintf (e, "\"\n"); 2588 } 2589 2590 fprintf (e, " END\n"); 2591 fprintf (e, " END\n"); 2592 break; 2593 } 2594 2595 case VERINFO_VAR: 2596 { 2597 const struct ver_varinfo *vv; 2598 2599 fprintf (e, " BLOCK \"VarFileInfo\"\n"); 2600 fprintf (e, " BEGIN\n"); 2601 fprintf (e, " VALUE \""); 2602 unicode_print (e, vi->u.var.key, -1); 2603 fprintf (e, "\""); 2604 2605 for (vv = vi->u.var.var; vv != NULL; vv = vv->next) 2606 fprintf (e, ", 0x%x, %d", (unsigned int) vv->language, 2607 vv->charset); 2608 2609 fprintf (e, "\n END\n"); 2610 2611 break; 2612 } 2613 } 2614 } 2615 2616 fprintf (e, "END\n"); 2617} 2618 2619/* Write out data which would normally be read from a file. */ 2620 2621static void 2622write_rc_filedata (e, length, data) 2623 FILE *e; 2624 unsigned long length; 2625 const unsigned char *data; 2626{ 2627 unsigned long i; 2628 2629 for (i = 0; i + 15 < length; i += 16) 2630 { 2631 fprintf (e, "// %4lx: ", i); 2632 fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ", 2633 data[i + 0], data[i + 1], data[i + 2], data[i + 3], 2634 data[i + 4], data[i + 5], data[i + 6], data[i + 7]); 2635 fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n", 2636 data[i + 8], data[i + 9], data[i + 10], data[i + 11], 2637 data[i + 12], data[i + 13], data[i + 14], data[i + 15]); 2638 } 2639 2640 if (i < length) 2641 { 2642 fprintf (e, "// %4lx:", i); 2643 while (i < length) 2644 { 2645 fprintf (e, " %02x", data[i]); 2646 ++i; 2647 } 2648 fprintf (e, "\n"); 2649 } 2650} 2651