add "Ripe Seeds, Praying Hands" remix
[kents-nes-stuff.git] / tools / huffpuff / charmap.c
blobf672ff472b791a98cabd5f94779d4ab83039f804
1 /*
2 * $Id: charmap.c,v 1.1 2004/06/30 07:55:35 kenth Exp $
3 * $Log: charmap.c,v $
4 * Revision 1.1 2004/06/30 07:55:35 kenth
5 * Initial revision
7 */
9 /**
10 * (C) 2004 Kent Hansen
12 * The XORcyst is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * The XORcyst is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with The XORcyst; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 /** This file contains functions for parsing a custom character map.
28 * Such a map is used by the assembler to process .char directives.
29 * The map is a text file containing a series of lines of the following form:
31 * key=value
32 * OR: keylo-keyhi=value (specifies a range of keys starting at value)
34 * where key is a character or C escape sequence, and value is an integer.
35 * # is considered the start of a comment; the rest of the line is ignored.
37 * Examples:
38 * # map lowercase letters starting at 0xC0, so that a=0xC0, b=0xC1, ...
39 * a-z=0xC0
40 * # map some punctuation
41 * !=0x60
42 * ?=0x63
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <stdarg.h>
48 #include <string.h>
49 #include "charmap.h"
51 /*---------------------------------------------------------------------------*/
53 /**
54 * Issues a character map error.
55 * @param filename File where error occured
56 * @param line Line of file
57 * @param fmt printf-style format string
59 static void maperr(const char *filename, int line, char *fmt, ...)
61 va_list ap;
62 va_start(ap, fmt);
64 /* Print error message */
65 fprintf(stderr, "error: %s:%d: ", filename, line);
66 vfprintf(stderr, fmt, ap);
67 fprintf(stderr, "\n");
69 va_end(ap);
72 #define IS_SPACE(c) ( ((c) == '\t') || ((c) == ' ') )
74 /**
75 * Eats whitespace.
76 * @param s String with whitespace (possibly)
77 * @param i Start index in string, will be incremented beyond whitespace
79 static void eat_ws(char *s, int *i)
81 while (IS_SPACE(s[*i])) (*i)++;
84 /**
85 * Parses a key.
86 * @param s Pointer to buffer containing key
87 * @param i Pointer to index of first character of key in s
88 * @param d Where to store the parsed key
90 static int get_key(char *s, int *i, char *d)
92 char key;
93 /* Read first character */
94 key = s[(*i)++];
95 /* Make sure we've not hit end of string */
96 if ((key == '\0') || (key == '\n')) { return 0; }
97 /* Check if escape character */
98 if (key == '\\') {
99 key = s[(*i)++];
100 /* Make sure we've not hit end of string */
101 if ((key == '\0') || (key == '\n')) { return 0; }
102 /* Convert to C escape char if applicable */
103 switch (key) {
104 case '0': key = '\0'; break;
105 case 'a': key = '\a'; break;
106 case 'b': key = '\b'; break;
107 case 't': key = '\t'; break;
108 case 'f': key = '\f'; break;
109 case 'n': key = '\n'; break;
110 case 'r': key = '\r'; break;
113 /* Copy to output */
114 *d = key;
115 /* Success */
116 return 1;
120 * Parses a value.
121 * @param s Pointer to first character of value
123 static unsigned char get_value(char *s)
125 if (s[0] == '$') {
126 return strtol(&s[1], NULL, 16);
127 } else if (s[0] == '%') {
128 return strtol(&s[1], NULL, 2);
130 return strtol(s, NULL, 0);
134 * Parses a character map from file.
135 * @param filename Name of the character map file
136 * @param map 256-byte buffer where parsed map shall be stored
137 * @return 0 if fail, 1 if OK
139 int charmap_parse(const char *filename, unsigned char *map)
141 int lineno;
142 FILE *fp;
143 char line[1024];
144 /* Attempt to open the file */
145 fp = fopen(filename, "rt");
146 if (fp == NULL) {
147 return 0;
149 /* Reset line counter */
150 lineno = 0;
151 /* Read mappings */
152 while (fgets(line, 1023, fp) != NULL) {
153 unsigned char key;
154 unsigned char hkey;
155 unsigned char value;
156 int i;
157 /* Increase line number */
158 lineno++;
159 /* Comment? */
160 if (line[0] == '#')
161 continue;
162 /* Reset line index */
163 i = 0;
164 /* Read key */
165 if (get_key(line, &i, &key) == 0) {
166 maperr(filename, lineno, "key expected");
167 continue;
169 /* Check if this is a range definition */
170 if (line[i] == '-') {
171 /* Eat - */
172 i++;
173 /* Read high key */
174 if (get_key(line, &i, &hkey) == 0) {
175 maperr(filename, lineno, "high limit key expected");
176 continue;
178 /* Make sure hkey larger or equal to key */
179 if (hkey < key) {
180 maperr(filename, lineno, "invalid range");
181 continue;
184 else {
185 hkey = key;
187 /* Eat whitespace */
188 eat_ws(line, &i);
189 /* Verify = */
190 if (line[i] != '=') {
191 maperr(filename, lineno, "`=' expected");
192 continue;
194 /* Eat = */
195 i++;
196 /* Eat whitespace */
197 eat_ws(line, &i);
198 /* Make sure we've not hit end of string */
199 if ((line[i] == '\0') || (line[i] == '\n')) {
200 maperr(filename, lineno, "value expected");
201 return 0;
203 /* Read value */
204 value = get_value(&line[i]);
205 /* Store mapping(s) */
206 for (; key <= hkey; key++) {
207 map[key] = value++;
210 /* Close the file */
211 fclose(fp);
212 /* Success */
213 return 1;