1/************************************************************
2 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25 ********************************************************/
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <ctype.h>
30#include <X11/Xos.h>
31#include <X11/X.h>
32#include <X11/extensions/XKB.h>
33
34#include "tokens.h"
35#include "xkbevd.h"
36
37FILE    *yyin = NULL;
38
39static char scanFileBuf[1024];
40char    *scanFile = scanFileBuf;
41int      lineNum = 0;
42
43int      scanInt;
44char    *scanIntStr;
45int      scanIntClass;
46
47char    *scanStr = NULL;
48int      scanStrLine = 0;
49
50#define BUFSIZE 512
51static int      nInBuf = 0;
52static char     buf[BUFSIZE];
53
54#ifdef DEBUG
55
56extern unsigned debugFlags;
57
58static char *
59tokText(int tok)
60{
61    static char buf[32];
62
63    switch (tok) {
64    case END_OF_FILE:
65        snprintf(buf, sizeof(buf), "END_OF_FILE");
66        break;
67    case ERROR:
68        snprintf(buf, sizeof(buf), "ERROR");
69        break;
70
71    case BELL:
72        snprintf(buf, sizeof(buf), "BELL");
73        break;
74    case ACCESSX:
75        snprintf(buf, sizeof(buf), "ACCESSX");
76        break;
77    case MESSAGE:
78        snprintf(buf, sizeof(buf), "MESSAGE");
79        break;
80
81    case NONE:
82        snprintf(buf, sizeof(buf), "NONE");
83        break;
84    case IGNORE:
85        snprintf(buf, sizeof(buf), "IGNORE");
86        break;
87    case ECHO:
88        snprintf(buf, sizeof(buf), "ECHO");
89        break;
90    case PRINT_EV:
91        snprintf(buf, sizeof(buf), "PRINT_EV");
92        break;
93    case SHELL:
94        snprintf(buf, sizeof(buf), "SHELL");
95        break;
96    case SOUND:
97        snprintf(buf, sizeof(buf), "SOUND");
98        break;
99
100    case EQUALS:
101        snprintf(buf, sizeof(buf), "EQUALS");
102        break;
103    case PLUS:
104        snprintf(buf, sizeof(buf), "PLUS");
105        break;
106    case MINUS:
107        snprintf(buf, sizeof(buf), "MINUS");
108        break;
109    case DIVIDE:
110        snprintf(buf, sizeof(buf), "DIVIDE");
111        break;
112    case TIMES:
113        snprintf(buf, sizeof(buf), "TIMES");
114        break;
115    case OBRACE:
116        snprintf(buf, sizeof(buf), "OBRACE");
117        break;
118    case CBRACE:
119        snprintf(buf, sizeof(buf), "CBRACE");
120        break;
121    case OPAREN:
122        snprintf(buf, sizeof(buf), "OPAREN");
123        break;
124    case CPAREN:
125        snprintf(buf, sizeof(buf), "CPAREN");
126        break;
127    case OBRACKET:
128        snprintf(buf, sizeof(buf), "OBRACKET");
129        break;
130    case CBRACKET:
131        snprintf(buf, sizeof(buf), "CBRACKET");
132        break;
133    case DOT:
134        snprintf(buf, sizeof(buf), "DOT");
135        break;
136    case COMMA:
137        snprintf(buf, sizeof(buf), "COMMA");
138        break;
139    case SEMI:
140        snprintf(buf, sizeof(buf), "SEMI");
141        break;
142    case EXCLAM:
143        snprintf(buf, sizeof(buf), "EXCLAM");
144        break;
145    case INVERT:
146        snprintf(buf, sizeof(buf), "INVERT");
147        break;
148
149    case STRING:
150        snprintf(buf, sizeof(buf), "STRING (%s)", scanStr);
151        break;
152    case INTEGER:
153        snprintf(buf, sizeof(buf), "INTEGER (0x%x)", scanInt);
154        break;
155    case FLOAT:
156        snprintf(buf, sizeof(buf), "FLOAT (%d.%d)",
157                 scanInt / XkbGeomPtsPerMM, scanInt % XkbGeomPtsPerMM);
158        break;
159    case IDENT:
160        snprintf(buf, sizeof(buf), "IDENT (%s)", scanStr);
161        break;
162    case KEYNAME:
163        snprintf(buf, sizeof(buf), "KEYNAME (%s)", scanStr);
164        break;
165    default:
166        snprintf(buf, sizeof(buf), "UNKNOWN");
167        break;
168    }
169    return buf;
170}
171#endif
172
173int
174setScanState(const char *file, int line)
175{
176    if (file != NULL)
177        strncpy(scanFile, file, 1024);
178    if (line >= 0)
179        lineNum = line;
180    return 1;
181}
182
183static int
184yyGetString(void)
185{
186    int ch;
187
188    nInBuf = 0;
189    while (((ch = getc(yyin)) != EOF) && (ch != '"')) {
190        if (ch == '\\') {
191            if ((ch = getc(yyin)) != EOF) {
192                if (ch == 'n')
193                    ch = '\n';
194                else if (ch == 't')
195                    ch = '\t';
196                else if (ch == 'v')
197                    ch = '\v';
198                else if (ch == 'b')
199                    ch = '\b';
200                else if (ch == 'r')
201                    ch = '\r';
202                else if (ch == 'f')
203                    ch = '\f';
204                else if (ch == 'e')
205                    ch = '\033';
206                else if (ch == '0') {
207                    int tmp, stop;
208
209                    ch = stop = 0;
210                    if (((tmp = getc(yyin)) != EOF) && (isdigit(tmp)) &&
211                        (tmp != '8') && (tmp != '9')) {
212                        ch = (ch * 8) + (tmp - '0');
213                    }
214                    else {
215                        stop = 1;
216                        ungetc(tmp, yyin);
217                    }
218                    if ((!stop) && ((tmp = getc(yyin)) != EOF) && (isdigit(tmp))
219                        && (tmp != '8') && (tmp != '9')) {
220                        ch = (ch * 8) + (tmp - '0');
221                    }
222                    else {
223                        stop = 1;
224                        ungetc(tmp, yyin);
225                    }
226                    if ((!stop) && ((tmp = getc(yyin)) != EOF) && (isdigit(tmp))
227                        && (tmp != '8') && (tmp != '9')) {
228                        ch = (ch * 8) + (tmp - '0');
229                    }
230                    else {
231                        stop = 1;
232                        ungetc(tmp, yyin);
233                    }
234                }
235            }
236            else
237                return ERROR;
238        }
239
240        if (nInBuf < BUFSIZE - 1)
241            buf[nInBuf++] = ch;
242    }
243    if (ch == '"') {
244        buf[nInBuf++] = '\0';
245        if (scanStr)
246            free(scanStr);
247        scanStr = uStringDup(buf);
248        scanStrLine = lineNum;
249        return STRING;
250    }
251    return ERROR;
252}
253
254static int
255yyGetKeyName(void)
256{
257    int ch;
258
259    nInBuf = 0;
260    while (((ch = getc(yyin)) != EOF) && (ch != '>')) {
261        if (ch == '\\') {
262            if ((ch = getc(yyin)) != EOF) {
263                if (ch == 'n')
264                    ch = '\n';
265                else if (ch == 't')
266                    ch = '\t';
267                else if (ch == 'v')
268                    ch = '\v';
269                else if (ch == 'b')
270                    ch = '\b';
271                else if (ch == 'r')
272                    ch = '\r';
273                else if (ch == 'f')
274                    ch = '\f';
275                else if (ch == 'e')
276                    ch = '\033';
277                else if (ch == '0') {
278                    int tmp, stop;
279
280                    ch = stop = 0;
281                    if (((tmp = getc(yyin)) != EOF) && (isdigit(tmp)) &&
282                        (tmp != '8') && (tmp != '9')) {
283                        ch = (ch * 8) + (tmp - '0');
284                    }
285                    else {
286                        stop = 1;
287                        ungetc(tmp, yyin);
288                    }
289                    if ((!stop) && ((tmp = getc(yyin)) != EOF) && (isdigit(tmp))
290                        && (tmp != '8') && (tmp != '9')) {
291                        ch = (ch * 8) + (tmp - '0');
292                    }
293                    else {
294                        stop = 1;
295                        ungetc(tmp, yyin);
296                    }
297                    if ((!stop) && ((tmp = getc(yyin)) != EOF) && (isdigit(tmp))
298                        && (tmp != '8') && (tmp != '9')) {
299                        ch = (ch * 8) + (tmp - '0');
300                    }
301                    else {
302                        stop = 1;
303                        ungetc(tmp, yyin);
304                    }
305                }
306            }
307            else
308                return ERROR;
309        }
310
311        if (nInBuf < BUFSIZE - 1)
312            buf[nInBuf++] = ch;
313    }
314    if ((ch == '>') && (nInBuf < 5)) {
315        buf[nInBuf++] = '\0';
316        if (scanStr)
317            free(scanStr);
318        scanStr = uStringDup(buf);
319        scanStrLine = lineNum;
320        return KEYNAME;
321    }
322    return ERROR;
323}
324
325static struct _Keyword {
326    const char  *keyword;
327    int         token;
328} keywords[] = {
329    { "bell",           BELL },
330    { "accessx",        ACCESSX },
331    { "message",        MESSAGE },
332    { "none",           NONE },
333    { "ignore",         IGNORE },
334    { "echo",           ECHO },
335    { "printevent",     PRINT_EV },
336    { "shell",          SHELL },
337    { "sound",          SOUND }
338};
339static int numKeywords = sizeof(keywords) / sizeof(struct _Keyword);
340
341static int
342yyGetIdent(int first)
343{
344    int ch, found;
345    int rtrn = -1;
346
347    buf[0] = first;
348    nInBuf = 1;
349    while (((ch = getc(yyin)) != EOF) && (isalnum(ch) || (ch == '_'))) {
350        if (nInBuf < BUFSIZE - 1)
351            buf[nInBuf++] = ch;
352    }
353    buf[nInBuf++] = '\0';
354    found = 0;
355
356    for (int i = 0; (!found) && (i < numKeywords); i++) {
357        if (uStrCaseCmp(buf, keywords[i].keyword) == 0) {
358            rtrn = keywords[i].token;
359            found = 1;
360        }
361    }
362    if (!found) {
363        if (scanStr)
364            free(scanStr);
365        scanStr = uStringDup(buf);
366        scanStrLine = lineNum;
367        rtrn = IDENT;
368    }
369
370    if ((ch != EOF) && (!isspace(ch)))
371        ungetc(ch, yyin);
372    else if (ch == '\n')
373        lineNum++;
374
375    return rtrn;
376}
377
378static int
379yyGetNumber(int ch)
380{
381    int isFloat = 0;
382
383    buf[0] = ch;
384    nInBuf = 1;
385    while (((ch = getc(yyin)) != EOF) &&
386           (isxdigit(ch) || ((nInBuf == 1) && (ch == 'x')))) {
387        buf[nInBuf++] = ch;
388    }
389    if (ch == '.') {
390        isFloat = 1;
391        buf[nInBuf++] = ch;
392        while (((ch = getc(yyin)) != EOF) && (isxdigit(ch))) {
393            buf[nInBuf++] = ch;
394        }
395    }
396    buf[nInBuf++] = '\0';
397    if ((ch != EOF) && (!isspace(ch)))
398        ungetc(ch, yyin);
399
400    if (isFloat) {
401        float tmp;
402
403        if (sscanf(buf, "%g", &tmp) == 1) {
404            scanInt = tmp * XkbGeomPtsPerMM;
405            return FLOAT;
406        }
407    }
408    else if (sscanf(buf, "%i", &scanInt) == 1)
409        return INTEGER;
410    fprintf(stderr, "Malformed number %s\n", buf);
411    return ERROR;
412}
413
414int
415yylex(void)
416{
417    int ch;
418    int rtrn;
419
420    do {
421        ch = getc(yyin);
422        if (ch == '\n') {
423            lineNum++;
424        }
425        else if (ch == '/') {   /* handle C++ style double-/ comments */
426            int newch = getc(yyin);
427
428            if (newch == '/') {
429                do {
430                    ch = getc(yyin);
431                } while ((ch != '\n') && (ch != EOF));
432                lineNum++;
433            }
434            else if (newch != EOF) {
435                ungetc(newch, yyin);
436            }
437        }
438    } while ((ch != EOF) && (isspace(ch)));
439    if (ch == '=')
440        rtrn = EQUALS;
441    else if (ch == '+')
442        rtrn = PLUS;
443    else if (ch == '-')
444        rtrn = MINUS;
445    else if (ch == '/')
446        rtrn = DIVIDE;
447    else if (ch == '*')
448        rtrn = TIMES;
449    else if (ch == '{')
450        rtrn = OBRACE;
451    else if (ch == '}')
452        rtrn = CBRACE;
453    else if (ch == '(')
454        rtrn = OPAREN;
455    else if (ch == ')')
456        rtrn = CPAREN;
457    else if (ch == '[')
458        rtrn = OBRACKET;
459    else if (ch == ']')
460        rtrn = CBRACKET;
461    else if (ch == '.')
462        rtrn = DOT;
463    else if (ch == ',')
464        rtrn = COMMA;
465    else if (ch == ';')
466        rtrn = SEMI;
467    else if (ch == '!')
468        rtrn = EXCLAM;
469    else if (ch == '~')
470        rtrn = INVERT;
471    else if (ch == '"')
472        rtrn = yyGetString();
473    else if (ch == '<')
474        rtrn = yyGetKeyName();
475    else if (ch == EOF)
476        rtrn = END_OF_FILE;
477    else if (isalpha(ch) || (ch == '_'))
478        rtrn = yyGetIdent(ch);
479    else if (isdigit(ch))
480        rtrn = yyGetNumber(ch);
481    else {
482        fprintf(stderr, "Unexpected character %c (%d) in input stream\n",
483                ch, ch);
484        rtrn = ERROR;
485    }
486#ifdef DEBUG
487    if (debugFlags & 0x2)
488        fprintf(stderr, "scan: %s\n", tokText(rtrn));
489#endif
490    return rtrn;
491}
492