mirror of
https://github.com/ctm/executor.git
synced 2025-01-09 09:29:33 +00:00
563 lines
12 KiB
Plaintext
563 lines
12 KiB
Plaintext
%{
|
|
#include <stdlib.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
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 <cptr> STRING
|
|
%type <number> HEXINT INTEGER CHAR4INT VARNAME number
|
|
%type <bptr> 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 <stdio.h>
|
|
#include <ctype.h>
|
|
|
|
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;
|
|
}
|