%{ #include #include #include #include typedef unsigned long long uint64; typedef unsigned int uint32; typedef unsigned char uint8; #include "rsys/custom.h" typedef struct { uint32 length; uint8 bytes[0]; } byte_sequence_t; static int yyparse (void); static long yylex (void); static void output (uint32 tag, const byte_sequence_t *bp); static byte_sequence_t *bptr_from_file_contents (const char *filename); static byte_sequence_t *bptr_from_uint32 (uint32 i); static byte_sequence_t *bptr_from_bptr_and_uint32 (const byte_sequence_t *bp, uint32 i); static byte_sequence_t *bptr_from_bptr_and_string (const byte_sequence_t *bp, const char *str); static byte_sequence_t *bptr_from_string (const char *str); %} %start configuration %union { uint32 number; char *cptr; byte_sequence_t *bptr; }; %token STRING /* ptr points to null-terminated string */ %token HEXINT /* number */ %token INTEGER /* number */ %token CHAR4INT %token VARNAME %type STRING %type HEXINT INTEGER CHAR4INT VARNAME number %type filename numberlist bptr stringlist %% configuration: /* empty */ | assignments ; assignment: VARNAME '=' bptr ';' { output ($1, $3); }; assignments: assignment | assignments assignment ; filename: STRING { $$ = bptr_from_file_contents ($1); free ($1); }; bptr: filename | '{' numberlist '}' { $$ = $2; } | '{' numberlist ',' '}' { $$ = $2; } | number { $$ = bptr_from_uint32 ($1); } | '{' stringlist '}' { $$ = bptr_from_bptr_and_string ($2, ""); } | '{' stringlist ',' '}' { $$ = bptr_from_bptr_and_string ($2, ""); } ; number: HEXINT | INTEGER | '-' INTEGER { $$ = - $2; } | CHAR4INT ; numberlist: numberlist ',' number { $$ = bptr_from_bptr_and_uint32 ($1, $3); } | number { $$ = bptr_from_uint32 ($1); } ; stringlist: stringlist ',' STRING { $$ = bptr_from_bptr_and_string ($1, $3); free ($3); } | STRING { $$ = bptr_from_string ($1); free ($1); } ; %% #include #include FILE *exec_fp; struct namevaluestr { char *name; } reserved[] = { { CUSTOM_CREATORS }, { CUSTOM_LICENSE }, { CUSTOM_FIRST_SN }, { CUSTOM_CHECKSUM }, { CUSTOM_LAST_SN }, { CUSTOM_SPLASH }, { CUSTOM_ABOUT_BOX }, { CUSTOM_COPYRIGHT_INFO }, { CUSTOM_THANK_YOU_INFO }, { CUSTOM_REGISTRATION_INSTRUCTIONS }, { CUSTOM_MAGIC_VOLUMES }, { CUSTOM_MUST_REGISTER }, { CUSTOM_MAC_CDROM }, { CUSTOM_DEMO_IDENTIFIER }, { CUSTOM_DISABLE_COMMAND_KEYS }, { CUSTOM_RESTART_STRING }, { CUSTOM_MENU_ABOUT_STRING }, { CUSTOM_VERSION_STRING }, { CUSTOM_SUFFIX_MAPS }, { CUSTOM_DEFAULT_APP }, { CUSTOM_DEMO_DAYS }, }; static int reserved_cmp (const void *p1, const void *p2) { int retval; retval = strcmp (*(const char **) p1, *(const char **) p2); return retval; } typedef enum { false, true, } boolean_t; #if !defined (NELEM) #define NELEM(x) (sizeof (x) / sizeof (x)[0]) #endif #define RELOAD (-2) static long binfind(char *tofind, struct namevaluestr table[], short nentries) { short low, mid, high; int cmpret; static char already_sorted = false; if (!already_sorted) { qsort (reserved, NELEM (reserved), sizeof reserved[0], reserved_cmp); already_sorted = true; } for (low = -1, high = nentries; high - low > 1;) { mid = (high + low) / 2; cmpret = strcmp(tofind, table[mid].name); if (cmpret < 0) high = mid; else if (cmpret == 0) { yylval.number = *(uint32 *)table[mid].name; /*-->*/ return VARNAME; } else /* cmpret > 0 */ low = mid; } return 0; } static long linecount = 1; #define GET_REMAINING_DEFINE(func, test) \ static int \ get_remaining_ ## func (char **tokenp, int c) \ { \ int retval; \ char *buf, *old_buf, *p; \ int bufsize, old_bufsize; \ int chars_left; \ \ bufsize = 32; \ old_bufsize = 0; \ old_buf = NULL; /* to get rid of compiler warnings */ \ do \ { \ buf = alloca (bufsize); \ memcpy (buf, old_buf, old_bufsize); \ chars_left = bufsize - old_bufsize; \ p = buf + old_bufsize; \ while (c != EOF && chars_left > 0 && (test)) \ { \ *p++ = c; \ --chars_left; \ c = getchar (); \ } \ old_buf = buf; \ old_bufsize = bufsize; \ bufsize *= 2; \ } \ while (!chars_left); \ *p = 0; \ *tokenp = strdup (buf); \ retval = c; \ return retval; \ } GET_REMAINING_DEFINE(token, (isalnum (c) || c == '_')) GET_REMAINING_DEFINE(string, ((c == '\\' ? ((c = getchar ()),1) : 0) || \ c != '"')) #define warning_unexpected(fmt, args...) fprintf (stderr, fmt "\n" , ## args) static void cleanup_linefeeds (char *p) { char *orig_p; orig_p = p; while (*p) { if (*p == '\n') { if (p > orig_p && p[-1] == '\r') memmove (p, p+1, strlen (p)); else { *p = '\r'; orig_p = p+1; } } ++p; } } static long yylex (void) { static short c = RELOAD; long retval; int i; if (c == RELOAD) c = getchar(); while (true) { switch (c) { case '"': c = getchar (); /* consume leading " */ c = get_remaining_string (&yylval.cptr, c); cleanup_linefeeds (yylval.cptr); c = getchar (); /* consume trailing " */ return STRING; break; case '0': if ((c = getchar()) == 'x') { yylval.number = 0; while (isalnum (c = getchar ())) { if (yylval.number & 0xF0000000) warning_unexpected ("hex constant too long parsing " "configuration file (line %ld)", linecount); if (c >= '0' && c <= '9') yylval.number = (yylval.number << 4) + c - '0'; else if (c >= 'a' && c <= 'f') yylval.number = (yylval.number << 4) + c - 'a' + 10; else if (c >= 'A' && c <= 'F') yylval.number = (yylval.number << 4) + c - 'A' + 10; else warning_unexpected ("bad character in hex constant " "parsing configuration file " "(line %ld)", linecount); } return HEXINT; break; } /* We just ate a 0 that should be part of a decimal integer (we don't support octal). It is a leading zero, so we can forget about it and fall through */ ungetc(c, stdin); c = '0'; /* FALL THROUGH */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': yylval.number = c - '0'; while (isdigit(c = getchar ())) { yylval.number = yylval.number * 10 + c - '0'; if (yylval.number < 0) warning_unexpected ("integer overflow parsing configuration " "file (line %ld)", linecount); } return INTEGER; break; case ' ': case '\r': case '\n': case '\t': case '\f': do if (c == '\n') linecount++; while (isspace(c = getchar ())); break; case '/': if ((c = getchar ()) == '/') { while ((c = getchar ()) != '\n') ; linecount++; c = getchar (); } else warning_unexpected ("single '/' parsing configuration file " "(line %ld)", linecount); break; case '\'': yylval.number = 0; for (i = 0 ; i < 4 ; i++) { c = getchar (); yylval.number = (unsigned long)yylval.number * 256 + c; } if ((c = getchar ()) != '\'') warning_unexpected ("missing \' parsing configuration file (line " "%ld)", linecount); c = getchar (); return CHAR4INT; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': { char *token; c = get_remaining_token (&token, c); retval = binfind(token, reserved, NELEM (reserved)); if (!retval) warning_unexpected ("unknown reserved word (\"%s\") parsing " "configuration file (line %ld)", token, linecount); free (token); return retval; } break; case '{': case '}': case '(': case ')': case '=': case ':': case ',': case ';': case '-': case '.': retval = c; c = getchar (); return retval; break; case EOF: c = RELOAD; /* for the next time around */ linecount = 1; return EOF; break; default: warning_unexpected ("unknown character parsing configuration file " "(line %ld)", linecount); } } } void yyerror(char *str) { warning_unexpected ("configuration file parse error (line %ld): %s", linecount, str); } static void output (uint32 tag, const byte_sequence_t *bp) { if (fwrite (&tag, sizeof tag, 1, exec_fp) != 1 || fwrite (&bp->length, sizeof bp->length, 1, exec_fp) != 1 || fwrite (bp->bytes, bp->length, 1, exec_fp) != 1) warning_unexpected ("Trouble writing\n"); free ((byte_sequence_t *) bp); } static byte_sequence_t * bptr_from_file_contents (const char *filename) { byte_sequence_t *retval; FILE *fp; retval = 0; fp = fopen (filename, "r"); if (!fp) warning_unexpected ("Couldn't open \"%s\"\n", filename); else { struct stat sbuf; if (fstat (fileno (fp), &sbuf) != 0) warning_unexpected ("Couldn't fstat \"%s\"\n", filename); else { retval = malloc (sizeof *retval + sbuf.st_size); if (retval) { int n; retval->length = sbuf.st_size; n = fread (retval->bytes, retval->length, 1, fp); if (n != 1) warning_unexpected ("Trouble reading\n"); } } fclose (fp); } return retval; } static byte_sequence_t * bptr_from_uint32 (uint32 i) { byte_sequence_t *retval; retval = malloc (sizeof *retval + sizeof i); if (retval) { retval->length = sizeof i; memcpy (retval->bytes, &i, sizeof i); } return retval; } static byte_sequence_t * bptr_from_bptr_and_uint32 (const byte_sequence_t *bp, uint32 i) { byte_sequence_t *retval; retval = malloc (sizeof *retval + bp->length + sizeof i); if (retval) { retval->length = bp->length + sizeof i; memcpy (retval->bytes, bp->bytes, bp->length); memcpy (retval->bytes + bp->length, &i, sizeof i); } free ((byte_sequence_t *) bp); return retval; } static byte_sequence_t * bptr_from_bptr_and_string (const byte_sequence_t *bp, const char *str) { byte_sequence_t *retval; int len; len = strlen (str) + 1; retval = malloc (sizeof *retval + bp->length + len); if (retval) { retval->length = bp->length + len; memcpy (retval->bytes, bp->bytes, bp->length); memcpy (retval->bytes + bp->length, str, len); } free ((byte_sequence_t *) bp); return retval; } static byte_sequence_t * bptr_from_string (const char *str) { byte_sequence_t *retval; int len; len = strlen (str) + 1; retval = malloc (sizeof *retval + len); if (retval) { retval->length = len; memcpy (retval->bytes, str, len); } return retval; } static boolean_t position_after_magic (FILE *fp, uint64 magic) { uint64 test; long offset; boolean_t found; boolean_t retval; for (offset = 0, found = false; (!found && fseek (fp, offset, SEEK_SET) == 0 && fread (&test, sizeof test, 1, fp) == 1); ++offset) { if (test == magic) found = true; } if (!found) retval = false; else { test = 0; retval = (fseek (fp, offset-1, SEEK_SET) == 0 && fwrite (&test, sizeof test, 1, fp) == 1); } return retval; } int main (int argc, const char *argv[]) { int retval; if (argc != 3) { fprintf (stderr, "Usage: customize executor.exe config_file\n"); exit (1); } exec_fp = fopen (argv[1], "r+b"); if (!exec_fp) { fprintf (stderr, "Couldn't open \"%s\" for writing\n", argv[1]); exit (1); } if (!position_after_magic (exec_fp, CUSTOM_MAGIC)) { fprintf (stderr, "Couldn't find magic\n"); exit (1); } if (freopen (argv[2], "r", stdin) == NULL) { fprintf (stderr, "Couldn't open \"%s\" for reading\n", argv[2]); exit (1); } retval = yyparse (); fclose (exec_fp); return retval; }