9 date 2007.07.22.13.33.26; author khansen; state Exp;
14 date 2004.12.18.16.59.50; author kenth; state Exp;
19 date 2004.06.30.07.55.53; author kenth; state Exp;
30 @convert tabs to whitespaces
34 * $Id: script.c,v 1.2 2004/12/18 16:59:50 kenth Exp $
36 * Revision 1.2 2004/12/18 16:59:50 kenth
37 * fixed command parser bug
39 * Revision 1.1 2004/06/30 07:55:53 kenth
45 * (C) 2004 Kent Hansen
47 * The XORcyst is free software; you can redistribute it and/or modify
48 * it under the terms of the GNU General Public License as published by
49 * the Free Software Foundation; either version 2 of the License, or
50 * (at your option) any later version.
52 * The XORcyst is distributed in the hope that it will be useful,
53 * but WITHOUT ANY WARRANTY; without even the implied warranty of
54 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55 * GNU General Public License for more details.
57 * You should have received a copy of the GNU General Public License
58 * along with The XORcyst; if not, write to the Free Software
59 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
63 * This file contains functions to parse, manage, process and query XORcyst
64 * linker scripts and their commands.
65 * Such a script is just a text file with a series of commands of the following
67 * command_name{arg_name=value, arg_name=value, ...}
76 #define SAFE_FREE(a) if (a) { free(a); a = NULL; }
78 /*---------------------------------------------------------------------------*/
80 /** Describes a mapping from string to command type */
81 struct tag_string_to_command_type_mapping {
86 typedef struct tag_string_to_command_type_mapping string_to_command_type_mapping;
89 * Attempts to map a string to a script command type.
90 * @@param s String representation of command
91 * @@return The corresponding command
93 static command_type string_to_command_type(char *s) {
95 /* Table of mappings */
96 static string_to_command_type_mapping map[] = {
97 { "ram", RAM_COMMAND },
98 { "output", OUTPUT_COMMAND },
99 { "copy", COPY_COMMAND },
100 { "bank", BANK_COMMAND },
101 { "link", LINK_COMMAND },
102 { "options", OPTIONS_COMMAND },
103 { "pad", PAD_COMMAND},
106 /* Try all the mappings */
107 for (i=0; map[i].string != NULL; i++) {
108 if (strcmp(s, map[i].string) == 0) {
113 /* Not in map table */
117 /** Describes the arguments that a command should acknowledge */
118 struct tag_valid_command_args
124 typedef struct tag_valid_command_args valid_command_args;
127 * Tests if the given command argument name is valid.
129 static int is_valid_command_arg(command_type type, const char *candidate_arg)
134 /* Lists of valid args for each command */
135 static char *ram_args[] = { "end", "start", NULL };
136 static char *output_args[] = { "file", NULL };
137 static char *copy_args[] = { "file", NULL };
138 static char *bank_args[] = { "size", "origin", NULL };
139 static char *link_args[] = { "file", "origin", NULL };
140 static char *pad_args[] = { "size", "origin", "offset", NULL };
141 /* Table of valid args */
142 static valid_command_args ok_args[] = {
143 { RAM_COMMAND, ram_args },
144 { OUTPUT_COMMAND, output_args },
145 { COPY_COMMAND, copy_args },
146 { BANK_COMMAND, bank_args },
147 { LINK_COMMAND, link_args },
148 { PAD_COMMAND, pad_args }
150 /* Find arg array for command */
151 for (i=0; ok_args[i].type != -1; i++) {
152 if (ok_args[i].type == type) {
153 /* Now go through array of valid args for command */
154 args = ok_args[i].args;
155 for (j=0; args[j] != NULL; j++) {
156 if (strcmp(args[j], candidate_arg) == 0) {
157 /* Found it. Valid. */
161 /* Didn't find it. Invalid. */
165 /* Not valid argument */
169 /*---------------------------------------------------------------------------*/
171 #define IS_SPACE(c) ( ((c) == '\t') || ((c) == ' ') )
175 * @@param s String with whitespace (possibly)
176 * @@param i Start index in string, will be incremented beyond whitespace
178 static void eat_ws(char *s, int *i)
180 while (IS_SPACE(s[*i])) (*i)++;
184 * Tests if a character is in a set of delimiters.
186 static int is_delim(unsigned char c, char *delim)
189 /* Compare to all delimiters */
190 for (i=0; i<strlen(delim)+1; i++) {
191 if (delim[i] == c) return 1;
193 /* Not a delimiter */
199 * @@param s String containing token
200 * @@param i Start index in string, will be incremented beyond token
201 * @@param delim Set of delimiters which may mark end of token
202 * @@param dest Where to store the grabbed token
204 static void get_token(char *s, int *i, char *delim, char *dest)
210 /* Get next character */
212 /* Test if token delimiter */
213 if (is_delim(c, delim)) {
219 /* check if escape character */
223 /* Get next character */
225 /* Convert to C escape char if applicable */
227 case '0': c = '\0'; break;
228 case 'a': c = '\a'; break;
229 case 'b': c = '\b'; break;
230 case 't': c = '\t'; break;
231 case 'f': c = '\f'; break;
232 case 'n': c = '\n'; break;
233 case 'r': c = '\r'; break;
244 /*---------------------------------------------------------------------------*/
247 * Displays an error message generated during script parsing.
248 * @@param filename Name of file where error was found
249 * @@param line Line of file
250 * @@param fmt printf-style format string
252 static void err(char *filename, int line, char *fmt, ...)
257 /* Print error message w/ location info */
258 fprintf(stderr, "error: %s:%d: ", filename, line);
259 vfprintf(stderr, fmt, ap);
260 fprintf(stderr, "\n");
265 /*---------------------------------------------------------------------------*/
268 * Adds an argument to script command.
269 * @@param cmd Command
270 * @@param arg Argument to add
272 static void add_arg(script_command *cmd, command_arg *arg)
275 if (cmd->first_arg == NULL) {
277 cmd->first_arg = arg;
280 /* Add to end of list */
281 for (a = cmd->first_arg; a->next != NULL; a = a->next) ;
288 * Adds a command to script.
290 * @@param cmd Command to add
292 static void add_command(script *sc, script_command *cmd)
295 if (sc->first_command == NULL) {
297 sc->first_command = cmd;
300 /* Add to end of list */
301 for (c = sc->first_command; c->next != NULL; c = c->next) ;
308 * Finalizes a script command.
309 * @@param cmd Command
311 static void finalize_command(script_command *cmd)
315 /* Finalize all arguments */
316 for(a = cmd->first_arg; a != NULL; a = t) {
326 * Gets the processor function for a script command type from a map.
327 * @@param type The command type
328 * @@param map A mapping from command types to processor functions
330 static script_commandproc command_type_to_proc(command_type type, script_commandprocmap *map)
332 for (; map->proc != NULL; map += 1) {
333 if (map->type == type) {
340 /*---------------------------------------------------------------------------*/
343 * Parses a script from a file to a script struct.
344 * @@param filename File to parse
345 * @@param sc Destination script
346 * @@return 0 if fail, 1 if OK
348 int script_parse(char *filename, script *sc)
359 static int lineno = 0;
361 sc->first_command = NULL;
362 /* Attempt to open script */
363 fp = fopen(filename, "rt");
365 fprintf(stderr, "error: could not open `%s' for reading\n", filename);
369 while (fgets(line, 1023, fp) != NULL) {
370 /* Increase line number */
372 /* Skip white space */
375 /* Skip line if comment or end */
376 if ( (line[i] == '#') || (line[i] == '\0') || (line[i] == '\n') ) continue;
377 /* Get command name */
378 get_token(line, &i, " \t{", cmdname);
379 /* Check that it's a valid command */
380 if (strlen(cmdname) == 0) {
381 err(filename, lineno, "command expected");
385 /* Convert from string to command type */
386 type = string_to_command_type(cmdname);
387 if (type == BAD_COMMAND) {
388 err(filename, lineno, "unknown command `%s'", cmdname);
392 /* Allocate space for command */
393 cmd = (script_command *)malloc( sizeof(script_command) );
397 /* No arguments (yet) */
398 cmd->first_arg = NULL;
399 /* Store line number */
401 /* Add command to script */
402 add_command(sc, cmd);
406 /* Skip white space */
408 /* Next token should be '{' */
409 if (line[i] != '{') {
410 err(filename, lineno, "{ expected");
414 /* Get argument(s) */
415 while (line[i] != '}') {
416 if (line[i] == '\0') {
420 if (cmd->first_arg != NULL) {
421 /* Skip white space */
423 /* Next token should be , */
424 if (line[i] != ',') {
425 err(filename, lineno, ", expected");
430 /* Skip white space */
432 /* Get argument name */
433 get_token(line, &i, " \t=", argname);
434 if (strlen(argname) == 0) {
435 err(filename, lineno, "argument name expected");
438 /* Skip white space */
440 /* Next token should be '=' */
441 if (line[i] != '=') {
442 err(filename, lineno, "= expected");
446 /* Skip white space */
449 get_token(line, &i, " \t},", argvalue);
450 if (strlen(argvalue) == 0) {
451 err(filename, lineno, "value expected for argument `%s'", argname);
454 // Check if the argument name is valid for this command */
455 if (is_valid_command_arg(cmd->type, argname) ) {
456 /* Create argument struct */
457 arg = (command_arg *)malloc( sizeof(command_arg) );
459 arg->key = (char *)malloc( strlen(argname)+1 );
460 arg->value = (char *)malloc( strlen(argvalue)+1 );
462 strcpy(arg->key, argname);
463 strcpy(arg->value, argvalue);
464 /* Store argument in list */
469 /* Not valid argument name */
470 err(filename, lineno, "invalid argument `%s'", argname);
473 /* Skip white space */
484 * Finalizes a script.
487 void script_finalize(script *sc)
491 if (sc == NULL) { return; }
492 for(c = sc->first_command; c != NULL; c = t) {
499 * Gets the length (that is, number of commands) of a script.
501 * @@return Number of commands in script
503 int script_length(script *sc)
507 if (sc == NULL) { return 0; }
508 for (i=0, c=sc->first_command; c != NULL; i++, c = c->next) ;
513 * Gets a command from a script.
515 * @@param index Command index
517 script_command *script_get_command(script *sc, int index)
521 if (sc == NULL) { return NULL; }
522 for (i=0, c=sc->first_command; (c != NULL) && (i != index); i++, c = c->next) ;
527 * Processes commands in script.
529 * @@param map Map from command to processor function
531 void script_walk(script *sc, script_commandprocmap *map, void *arg)
534 script_commandproc p;
535 if (sc == NULL) { return; }
536 /* Walk all the commands */
537 for (c=sc->first_command; c != NULL; c = c->next) {
538 /* Process this command if it has a processor function */
539 p = command_type_to_proc(c->type, map);
547 * Gets value of argument for script command.
549 * @@param key Key (argument name)
551 char *script_get_command_arg(script_command *c, char *key)
554 if (c == NULL) { return NULL; }
555 /* Go through all args */
556 for (a = c->first_arg; a != NULL; a = a->next) {
557 if (strcmp(key, a->key) == 0) {
558 /* Found it, return its value */
567 * Gets the string representation of a command type.
568 * @@param type Command type
570 char *script_command_type_to_string(command_type type)
573 case RAM_COMMAND: return "ram";
574 case OUTPUT_COMMAND: return "output";
575 case COPY_COMMAND: return "copy";
576 case BANK_COMMAND: return "bank";
577 case LINK_COMMAND: return "link";
578 case OPTIONS_COMMAND: return "options";
579 case PAD_COMMAND: return "pad";
581 /* Invalid command */
584 return "Invalid command!";
588 * Counts the number of commands of the given type in a script.
590 * @@param type Command type
592 int script_count_command_type(script *sc, command_type type)
596 if (sc == NULL) { return 0; }
597 for (count=0, c=sc->first_command; c != NULL; c = c->next) {
598 if (c->type == type) {
609 @fixed command parser bug
614 * $Id: script.c,v 1.1 2004/06/30 07:55:53 kenth Exp kenth $
623 /* Table of mappings */
624 static string_to_command_type_mapping map[] = {
625 { "ram", RAM_COMMAND },
626 { "output", OUTPUT_COMMAND },
627 { "copy", COPY_COMMAND },
628 { "bank", BANK_COMMAND },
629 { "link", LINK_COMMAND },
630 { "options", OPTIONS_COMMAND },
631 { "pad", PAD_COMMAND},
634 /* Try all the mappings */
635 for (i=0; map[i].string != NULL; i++) {
636 if (strcmp(s, map[i].string) == 0) {
641 /* Not in map table */
652 /* Lists of valid args for each command */
653 static char *ram_args[] = { "end", "start", NULL };
654 static char *output_args[] = { "file", NULL };
655 static char *copy_args[] = { "file", NULL };
656 static char *bank_args[] = { "size", "origin", NULL };
657 static char *link_args[] = { "file", "origin", NULL };
658 static char *pad_args[] = { "size", "origin", "offset", NULL };
659 /* Table of valid args */
660 static valid_command_args ok_args[] = {
661 { RAM_COMMAND, ram_args },
662 { OUTPUT_COMMAND, output_args },
663 { COPY_COMMAND, copy_args },
664 { BANK_COMMAND, bank_args },
665 { LINK_COMMAND, link_args },
666 { PAD_COMMAND, pad_args }
668 /* Find arg array for command */
669 for (i=0; ok_args[i].type != -1; i++) {
670 if (ok_args[i].type == type) {
671 /* Now go through array of valid args for command */
672 args = ok_args[i].args;
673 for (j=0; args[j] != NULL; j++) {
674 if (strcmp(args[j], candidate_arg) == 0) {
675 /* Found it. Valid. */
679 /* Didn't find it. Invalid. */
683 /* Not valid argument */
687 while (IS_SPACE(s[*i])) (*i)++;
691 /* Compare to all delimiters */
692 for (i=0; i<strlen(delim)+1; i++) {
693 if (delim[i] == c) return 1;
695 /* Not a delimiter */
703 /* Get next character */
705 /* Test if token delimiter */
706 if (is_delim(c, delim)) {
712 /* check if escape character */
716 /* Get next character */
718 /* Convert to C escape char if applicable */
720 case '0': c = '\0'; break;
721 case 'a': c = '\a'; break;
722 case 'b': c = '\b'; break;
723 case 't': c = '\t'; break;
724 case 'f': c = '\f'; break;
725 case 'n': c = '\n'; break;
726 case 'r': c = '\r'; break;
741 /* Print error message w/ location info */
742 fprintf(stderr, "error: %s:%d: ", filename, line);
743 vfprintf(stderr, fmt, ap);
744 fprintf(stderr, "\n");
751 if (cmd->first_arg == NULL) {
753 cmd->first_arg = arg;
756 /* Add to end of list */
757 for (a = cmd->first_arg; a->next != NULL; a = a->next) ;
764 if (sc->first_command == NULL) {
766 sc->first_command = cmd;
769 /* Add to end of list */
770 for (c = sc->first_command; c->next != NULL; c = c->next) ;
778 /* Finalize all arguments */
779 for(a = cmd->first_arg; a != NULL; a = t) {
788 for (; map->proc != NULL; map += 1) {
789 if (map->type == type) {
805 static int lineno = 0;
807 sc->first_command = NULL;
808 /* Attempt to open script */
809 fp = fopen(filename, "rt");
811 fprintf(stderr, "error: could not open `%s' for reading\n", filename);
815 while (fgets(line, 1023, fp) != NULL) {
816 /* Increase line number */
818 /* Skip white space */
821 /* Skip line if comment or end */
822 if ( (line[i] == '#') || (line[i] == '\0') || (line[i] == '\n') ) continue;
823 /* Get command name */
824 get_token(line, &i, " \t{", cmdname);
825 /* Check that it's a valid command */
826 if (strlen(cmdname) == 0) {
827 err(filename, lineno, "command expected");
831 /* Convert from string to command type */
832 type = string_to_command_type(cmdname);
833 if (type == BAD_COMMAND) {
834 err(filename, lineno, "unknown command `%s'", cmdname);
838 /* Allocate space for command */
839 cmd = (script_command *)malloc( sizeof(script_command) );
843 /* No arguments (yet) */
844 cmd->first_arg = NULL;
845 /* Store line number */
847 /* Add command to script */
848 add_command(sc, cmd);
852 /* Skip white space */
854 /* Next token should be '{' */
855 if (line[i] != '{') {
856 err(filename, lineno, "{ expected");
860 /* Get argument(s) */
861 while (line[i] != '}') {
862 if (line[i] == '\0') {
866 if (cmd->first_arg != NULL) {
867 /* Skip white space */
869 /* Next token should be , */
870 if (line[i] != ',') {
871 err(filename, lineno, ", expected");
876 /* Skip white space */
878 /* Get argument name */
879 get_token(line, &i, " \t=", argname);
880 if (strlen(argname) == 0) {
881 err(filename, lineno, "argument name expected");
884 /* Skip white space */
886 /* Next token should be '=' */
887 if (line[i] != '=') {
888 err(filename, lineno, "= expected");
892 /* Skip white space */
895 get_token(line, &i, " \t},", argvalue);
896 if (strlen(argvalue) == 0) {
897 err(filename, lineno, "value expected for argument `%s'", argname);
900 // Check if the argument name is valid for this command */
901 if (is_valid_command_arg(cmd->type, argname) ) {
902 /* Create argument struct */
903 arg = (command_arg *)malloc( sizeof(command_arg) );
905 arg->key = (char *)malloc( strlen(argname)+1 );
906 arg->value = (char *)malloc( strlen(argvalue)+1 );
908 strcpy(arg->key, argname);
909 strcpy(arg->value, argvalue);
910 /* Store argument in list */
915 /* Not valid argument name */
916 err(filename, lineno, "invalid argument `%s'", argname);
919 /* Skip white space */
931 if (sc == NULL) { return; }
932 for(c = sc->first_command; c != NULL; c = t) {
940 if (sc == NULL) { return 0; }
941 for (i=0, c=sc->first_command; c != NULL; i++, c = c->next) ;
947 if (sc == NULL) { return NULL; }
948 for (i=0, c=sc->first_command; (c != NULL) && (i != index); i++, c = c->next) ;
953 script_commandproc p;
954 if (sc == NULL) { return; }
955 /* Walk all the commands */
956 for (c=sc->first_command; c != NULL; c = c->next) {
957 /* Process this command if it has a processor function */
958 p = command_type_to_proc(c->type, map);
966 if (c == NULL) { return NULL; }
967 /* Go through all args */
968 for (a = c->first_arg; a != NULL; a = a->next) {
969 if (strcmp(key, a->key) == 0) {
970 /* Found it, return its value */
979 case RAM_COMMAND: return "ram";
980 case OUTPUT_COMMAND: return "output";
981 case COPY_COMMAND: return "copy";
982 case BANK_COMMAND: return "bank";
983 case LINK_COMMAND: return "link";
984 case OPTIONS_COMMAND: return "options";
985 case PAD_COMMAND: return "pad";
987 /* Invalid command */
990 return "Invalid command!";
995 if (sc == NULL) { return 0; }
996 for (count=0, c=sc->first_command; c != NULL; c = c->next) {
997 if (c->type == type) {