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: }