|
|
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.