allow extrn symbols to be defined by the unit itself (part II)
[xorcyst.git] / charmap.c
blobb386abb879d13ab25a6cff42d4e97df8e3e7638a
1 /*
2 * $Id: charmap.c,v 1.3 2007/11/11 22:35:22 khansen Exp $
3 * $Log: charmap.c,v $
4 * Revision 1.3 2007/11/11 22:35:22 khansen
5 * compile on mac
7 * Revision 1.2 2007/07/22 13:33:26 khansen
8 * convert tabs to whitespaces
10 * Revision 1.1 2004/06/30 07:55:35 kenth
11 * Initial revision
15 /**
16 * (C) 2004 Kent Hansen
18 * The XORcyst is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * The XORcyst is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with The XORcyst; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 /** This file contains functions for parsing a custom character map.
34 * Such a map is used by the assembler to process .char directives.
35 * The map is a text file containing a series of lines of the following form:
37 * key=value
38 * OR: keylo-keyhi=value (specifies a range of keys starting at value)
40 * where key is a character or C escape sequence, and value is an integer.
41 * # is considered the start of a comment; the rest of the line is ignored.
43 * Examples:
44 * # map lowercase letters starting at 0xC0, so that a=0xC0, b=0xC1, ...
45 * a-z=0xC0
46 * # map some punctuation
47 * !=0x60
48 * ?=0x63
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <stdarg.h>
54 #include <string.h>
55 #include "charmap.h"
57 /*---------------------------------------------------------------------------*/
59 /**
60 * Issues a character map error.
61 * @param filename File where error occured
62 * @param line Line of file
63 * @param fmt printf-style format string
65 static void maperr(const char *filename, int line, const char *fmt, ...)
67 va_list ap;
68 va_start(ap, fmt);
70 /* Print error message */
71 fprintf(stderr, "%s:%d: error: ", filename, line);
72 vfprintf(stderr, fmt, ap);
73 fprintf(stderr, "\n");
75 va_end(ap);
78 #define IS_SPACE(c) ( ((c) == '\t') || ((c) == ' ') )
80 /**
81 * Eats whitespace.
82 * @param s String with whitespace (possibly)
83 * @param i Start index in string, will be incremented beyond whitespace
85 static void eat_ws(const char *s, int *i)
87 while (IS_SPACE(s[*i])) (*i)++;
90 /**
91 * Parses a key.
92 * @param s Pointer to buffer containing key
93 * @param i Pointer to index of first character of key in s
94 * @param d Where to store the parsed key
96 static int get_key(const char *s, int *i, unsigned char *d)
98 char key;
99 /* Read first character */
100 key = s[(*i)++];
101 /* Make sure we've not hit end of string */
102 if ((key == '\0') || (key == '\n')) { return 0; }
103 /* Check if escape character */
104 if (key == '\\') {
105 key = s[(*i)++];
106 /* Make sure we've not hit end of string */
107 if ((key == '\0') || (key == '\n')) { return 0; }
108 /* Convert to C escape char if applicable */
109 switch (key) {
110 case '0': key = '\0'; break;
111 case 'a': key = '\a'; break;
112 case 'b': key = '\b'; break;
113 case 't': key = '\t'; break;
114 case 'f': key = '\f'; break;
115 case 'n': key = '\n'; break;
116 case 'r': key = '\r'; break;
119 /* Copy to output */
120 *d = key;
121 /* Success */
122 return 1;
126 * Parses a value.
127 * @param s Pointer to first character of value
129 static unsigned char get_value(const char *s)
131 if (s[0] == '$') {
132 return strtol(&s[1], NULL, 16);
134 else if (s[0] == '%') {
135 return strtol(&s[1], NULL, 2);
137 return strtol(s, NULL, 0);
141 * Parses a character map from file.
142 * @param filename Name of the character map file
143 * @param map 256-byte buffer where parsed map shall be stored
144 * @return 0 if fail, 1 if OK
146 int charmap_parse(const char *filename, unsigned char *map)
148 int lineno;
149 FILE *fp;
150 unsigned char key;
151 unsigned char hkey;
152 unsigned char value;
153 int i;
154 char line[1024];
155 /* Attempt to open the file */
156 fp = fopen(filename, "rt");
157 if (fp == NULL) {
158 return 0;
160 /* Reset line counter */
161 lineno = 0;
162 /* Read mappings */
163 while (fgets(line, 1023, fp) != NULL) {
164 /* Increase line number */
165 lineno++;
166 /* Reset line index */
167 i = 0;
168 /* Read key */
169 if (get_key(line, &i, &key) == 0) {
170 maperr(filename, lineno, "key expected");
171 continue;
173 /* Check if this is a range definition */
174 if (line[i] == '-') {
175 /* Eat - */
176 i++;
177 /* Read high key */
178 if (get_key(line, &i, &hkey) == 0) {
179 maperr(filename, lineno, "high limit key expected");
180 continue;
182 /* Make sure hkey larger or equal to key */
183 if (hkey < key) {
184 maperr(filename, lineno, "invalid range");
185 continue;
188 else {
189 hkey = key;
191 /* Eat whitespace */
192 eat_ws(line, &i);
193 /* Verify = */
194 if (line[i] != '=') {
195 maperr(filename, lineno, "`=' expected");
196 continue;
198 /* Eat = */
199 i++;
200 /* Eat whitespace */
201 eat_ws(line, &i);
202 /* Make sure we've not hit end of string */
203 if ((line[i] == '\0') || (line[i] == '\n')) {
204 maperr(filename, lineno, "value expected");
205 return 0;
207 /* Read value */
208 value = get_value(&line[i]);
209 /* Store mapping(s) */
210 for (; key <= hkey; key++) {
211 map[key] = value++;
214 /* Close the file */
215 fclose(fp);
216 /* Success */
217 return 1;