|
|
1.1 root 1: #include <X/mit-copyright.h>
2:
3: /* Copyright 1985, Massachusetts Institute of Technology */
4:
5: #ifndef lint
6: static char *rcsid_keycomp_c = "$Header: keycomp.c,v 10.4 86/02/01 15:45:26 tony Rel $";
7: #endif
8:
9: #include <stdio.h>
10: #include <X/X.h>
11: #include "Xkeymap.h"
12:
13: #define isnum(c) (((c) >= '0') && ((c) <= '9'))
14: #define isoctal(c) (((c) >= '0') && ((c) <= '7'))
15: #define whitespace(c) (((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\0'))
16:
17: #define bool int
18: #define TRUE 1
19: #define FALSE 0
20:
21: #define MAXLENGTH 80
22:
23: typedef struct _EscMapEntry {
24: char from, to;} EscMapEntry;
25:
26: typedef enum _ParseError {
27: e_NoError,
28: e_NoKeycode,
29: e_KeycodeTooBig,
30: e_Not1Or16Items,
31: e_NotNumber,
32: e_NumberTooBig,
33: e_SingleQuoteNotClosed,
34: e_StringTooLong,
35: e_DoubleQuoteNotClosed,
36: e_TooManyCharsBetweenQuotes,
37: e_Unrecognized
38: } ParseError;
39:
40: #define CT_ESC_ENTRIES 5
41: static EscMapEntry EscMap [CT_ESC_ENTRIES] = {
42: {'n', '\n'},
43: {'t', '\t'},
44: {'b', '\b'},
45: {'r', '\r'},
46: {'f', '\f'}} ;
47:
48: static KeyMapElt keymap [256];
49:
50: static int column_map[16] =
51: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
52:
53: /* the following variables are global to facilitate error-handling */
54: static int line_no = 0, item_no = 0;
55:
56: /* the following variables are global to simplify initialization */
57: char string_array [16][BUFSIZ];
58: char *strings[16];
59:
60: main ()
61: {
62: char s[BUFSIZ];
63: int i, j;
64: char magic = X_KEYMAP_MAGIC;
65: /* seek past end of keymap (to beginning of extension) */
66: if (isatty(fileno(stdout))
67: || (fseek (stdout, sizeof (keymap)+1, 0) == -1)) {
68: /* "+1" above is because magic number is first byte in file */
69: fprintf (stderr, "Couldn't fseek output file\n");
70: exit (-1);
71: }
72: for (i=0;i<256;i++)
73: for (j=0;j<16;j++)
74: keymap[i][j] = UNBOUND;
75: for (i=0;i<16;i++)
76: strings[i] = string_array[i];
77: while (gets(s)) {
78: ProcessLine(s);
79: line_no++;
80: }
81: fseek (stdout, 0, 0);
82: if (!fwrite (&magic, 1, 1, stdout)
83: || !fwrite (keymap, sizeof(keymap), 1, stdout)) {
84: fprintf (stderr, "Error writing beginning of output file\n");
85: exit (-1);
86: }
87: exit(0);
88: }
89:
90: ProcessLine (line)
91: char *line;
92: {
93: int lengths [MAXLENGTH];
94: int i=0, items, keycode;
95: char c;
96: if (line[0] == '#' || line[0] == '\0')
97: /* ignore comment lines (starting with '#') and blank lines */
98: return;
99: if (!isnum(line[0]))
100: Error(e_NoKeycode); /* line must start with key code */
101: i++;
102: while (isnum(line[i]))
103: i++;
104: c = line[i];
105: line[i] = '\0';
106: sscanf (line, (line[0] == '0') ? "%o" : "%d", &keycode);
107: if (keycode > 255)
108: Error(e_KeycodeTooBig);
109: line[i] = c;
110: items = ScanForItems (&line[i], strings, lengths);
111: if (items == 1) {
112: unsigned char value;
113: int j;
114: if (lengths[0] == 0)
115: value = UNBOUND;
116: else if (lengths[0] > 1 || !SingleCharBound (strings[0][0])) {
117: value = EXTENSION_BOUND;
118: AddToExtension (keycode, DontCareMetaBits, strings[0], lengths[0]);
119: }
120: else
121: value = strings[0][0];
122: for (j=0;j<16;j++)
123: keymap[keycode][j] = value;
124: }
125: else if (items == 16) {
126: int j;
127: for (j=0;j<16;j++) {
128: unsigned char value;
129: if (lengths[j] == 0)
130: value = UNBOUND;
131: else if (lengths[j] > 1 || !SingleCharBound (strings[j][0])) {
132: value = EXTENSION_BOUND;
133: AddToExtension (keycode, column_map[j], strings[j], lengths[j]);
134: }
135: else
136: value = strings[j][0];
137: keymap [keycode] [column_map[j]] = value;
138: }
139: }
140: else Error(e_Not1Or16Items);
141: }
142:
143: AddToExtension (keycode, metabits, string, length)
144: unsigned int keycode, metabits;
145: char *string;
146: int length;
147: {
148: ExtensionHeader header;
149: header.keycode = keycode;
150: header.metabits = metabits;
151: header.length = length;
152: if (!fwrite (&header, ExtensionHeaderSize, 1, stdout) ||
153: !fwrite (string, length, 1, stdout)) {
154: fprintf (stderr, "Error writing extension to output file\n");
155: exit (-3);
156: }
157: }
158:
159: int ScanForItems (line, items, lengths)
160: char *line;
161: char *items[16];
162: int lengths[16];
163: {
164: int i = 0;
165: item_no = 0;
166: while (1) {
167:
168: /* skip over leading white space */
169: while (whitespace(line[i])) {
170: if (line[i] == '\0')
171: return (item_no);
172: i++;
173: }
174:
175: if (isnum(line[i])) {
176: char *begin_num = &line[i];
177: char c;
178:
179: /* find end of number string */
180: while (c = line[++i], isnum (c))
181: /* this CANNOT be written isnum(line[++i]) because of side
182: * effect in expression passed to macro */
183: ;
184:
185: /* temporarily put null character at end of number string */
186: c = line[i];
187: line[i] = '\0';
188: lengths [item_no] = TranslateNumber (begin_num, items[item_no]);
189: line[i] = c;
190: }
191:
192: else switch (line[i]) {
193: case '#':
194: return(item_no); /* rest of line is comment -- ignore it */
195:
196: case 'U': /* "U" means "unbound" */
197: lengths [item_no] = 0;
198: i++; /* increment past the "U" character */
199: break;
200:
201: case '\'':
202: case '"': /* something between quotes */ {
203: char c;
204: char *begin_quote = &line[i++];
205: bool backslash = FALSE;
206: while (1)
207: switch (c = line[i++]) {
208: case '\0':
209: Error ((*begin_quote == '\'')
210: ? e_SingleQuoteNotClosed
211: : e_DoubleQuoteNotClosed);
212: break;
213: case '\\':
214: backslash = !backslash;
215: break;
216: default:
217: if (c == *begin_quote && !backslash)
218: goto out1;
219: backslash = FALSE;
220: break;
221: }
222: out1:
223: c = line [i];
224: line[i] = '\0';
225: lengths[item_no] = TranslateQuote (begin_quote, items[item_no]);
226: if ((lengths[item_no] > 1) && (*begin_quote == '\''))
227: Error (e_TooManyCharsBetweenQuotes);
228: line[i] = c;
229: break;
230: }
231:
232: default:
233: Error(e_Unrecognized);
234: break;
235:
236: }
237:
238: if (line[i] == ',')
239: i++; /* ignore terminating comma */
240: if (!whitespace (line[i]))
241: Error(e_Unrecognized);
242: item_no++;
243: if (item_no == 16)
244: return (item_no); /* ignore anything on line after 16th char */
245: }
246:
247: }
248:
249: int TranslateNumber (from, to)
250: char *from, *to;
251: {
252: int value;
253: sscanf (from, (from[0] == '0') ? "%o" : "%d", &value);
254: if (value > 255)
255: Error(e_NumberTooBig);
256: to[0] = value;
257: return (1); /* length */
258: }
259:
260:
261: int TranslateQuote (from, to)
262: char *from, *to;
263: {
264: int from_length = strlen (from);
265: int i, to_length = 0;
266: for (i=1;i<from_length-1;i++) {
267: if (to_length >= MAXLENGTH)
268: Error(e_StringTooLong);
269: if (from[i] == '\\') {
270: if (isoctal (from[i+1])) {
271: /* backslash followed by octal digits */
272: int digits = 1; /* how many successive digits (max 3) */
273: int value;
274: if (isoctal (from[i+2]))
275: digits += (1 + isoctal (from[i+3]));
276: sscanf (from+i+1, "%3o", &value);
277: if (value > 255)
278: Error(e_NumberTooBig);
279: to[to_length++] = value;
280: i += digits;
281: }
282: else {
283: /* backslash followed by non-number */
284: int j;
285: for (j=0;j<CT_ESC_ENTRIES;j++)
286: if (EscMap[j].from == from[i+1]) {
287: to[to_length++] = EscMap[j].to;
288: goto out;
289: }
290: to[to_length++] = from[i+1];
291: out:
292: i++;
293: }
294: }
295: else
296: /* not a backslash, just an ordinary character */
297: to[to_length++] = from[i];
298: }
299: return (to_length);
300: }
301:
302: Error (type)
303: ParseError type;
304: {
305: char *s;
306: switch (type) {
307: case e_NoKeycode:
308: s = "Line doesn't begin with keycode"; break;
309: case e_KeycodeTooBig:
310: s = "Keycode is too big"; break;
311: case e_Not1Or16Items:
312: s = "Line doesn't have 1 or 16 entries"; break;
313: case e_NotNumber:
314: s = "Non-number found after backslash in char constant"; break;
315: case e_NumberTooBig:
316: s = "Number after backslash is too big for a char constant"; break;
317: case e_SingleQuoteNotClosed:
318: s = "Closing single quote not found"; break;
319: case e_StringTooLong:
320: s = "String is too long"; break;
321: case e_DoubleQuoteNotClosed:
322: s = "Closing double quote not found"; break;
323: case e_TooManyCharsBetweenQuotes:
324: s = "Too many characters for single character constant"; break;
325: case e_Unrecognized:
326: s = "Not a U, number, single- or double-quoted string"; break;
327: default:
328: s = "Unknown error"; break;
329: }
330: fprintf (stderr, "Parse error at item %d on line %d:\n\t %s\n",
331: item_no+1, line_no+1, s);
332: exit (type);
333: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.