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 <stdlib.h>
28#include <stdio.h>
29#include <ctype.h>
30#include <X11/Xos.h>
31#include <X11/Xlib.h>
32#include <X11/XKBlib.h>
33
34#include "tokens.h"
35#define	DEBUG_VAR	scanDebug
36#include "utils.h"
37#include "parseutils.h"
38
39#ifdef DEBUG
40unsigned int scanDebug;
41#endif
42
43static FILE *yyin;
44
45static char scanFileBuf[1024] = {0};
46char *scanFile = scanFileBuf;
47int lineNum = 0;
48
49int scanInt;
50
51char scanBuf[1024];
52static int scanStrLine = 0;
53
54#define	BUFSIZE	4096
55static char readBuf[BUFSIZE];
56static int readBufPos = 0;
57static int readBufLen = 0;
58
59#ifdef DEBUG
60extern int debugFlags;
61
62static char *
63tokText(int tok)
64{
65    static char buf[32];
66
67    switch (tok)
68    {
69    case END_OF_FILE:
70        snprintf(buf, sizeof(buf), "END_OF_FILE");
71        break;
72    case ERROR_TOK:
73        snprintf(buf, sizeof(buf), "ERROR");
74        break;
75
76    case XKB_KEYMAP:
77        snprintf(buf, sizeof(buf), "XKB_KEYMAP");
78        break;
79    case XKB_KEYCODES:
80        snprintf(buf, sizeof(buf), "XKB_KEYCODES");
81        break;
82    case XKB_TYPES:
83        snprintf(buf, sizeof(buf), "XKB_TYPES");
84        break;
85    case XKB_SYMBOLS:
86        snprintf(buf, sizeof(buf), "XKB_SYMBOLS");
87        break;
88    case XKB_COMPATMAP:
89        snprintf(buf, sizeof(buf), "XKB_COMPATMAP");
90        break;
91    case XKB_GEOMETRY:
92        snprintf(buf, sizeof(buf), "XKB_GEOMETRY");
93        break;
94    case XKB_SEMANTICS:
95        snprintf(buf, sizeof(buf), "XKB_SEMANTICS");
96        break;
97    case XKB_LAYOUT:
98        snprintf(buf, sizeof(buf), "XKB_LAYOUT");
99        break;
100
101    case INCLUDE:
102        snprintf(buf, sizeof(buf), "INCLUDE");
103        break;
104    case OVERRIDE:
105        snprintf(buf, sizeof(buf), "OVERRIDE");
106        break;
107    case AUGMENT:
108        snprintf(buf, sizeof(buf), "AUGMENT");
109        break;
110    case REPLACE:
111        snprintf(buf, sizeof(buf), "REPLACE");
112        break;
113    case ALTERNATE:
114        snprintf(buf, sizeof(buf), "ALTERNATE");
115        break;
116
117    case VIRTUAL_MODS:
118        snprintf(buf, sizeof(buf), "VIRTUAL_MODS");
119        break;
120    case TYPE:
121        snprintf(buf, sizeof(buf), "TYPE");
122        break;
123    case INTERPRET:
124        snprintf(buf, sizeof(buf), "INTERPRET");
125        break;
126    case ACTION_TOK:
127        snprintf(buf, sizeof(buf), "ACTION");
128        break;
129    case KEY:
130        snprintf(buf, sizeof(buf), "KEY");
131        break;
132    case ALIAS:
133        snprintf(buf, sizeof(buf), "ALIAS");
134        break;
135    case GROUP:
136        snprintf(buf, sizeof(buf), "GROUP");
137        break;
138    case MODIFIER_MAP:
139        snprintf(buf, sizeof(buf), "MODIFIER_MAP");
140        break;
141    case INDICATOR:
142        snprintf(buf, sizeof(buf), "INDICATOR");
143        break;
144    case SHAPE:
145        snprintf(buf, sizeof(buf), "SHAPE");
146        break;
147    case KEYS:
148        snprintf(buf, sizeof(buf), "KEYS");
149        break;
150    case ROW:
151        snprintf(buf, sizeof(buf), "ROW");
152        break;
153    case SECTION:
154        snprintf(buf, sizeof(buf), "SECTION");
155        break;
156    case OVERLAY:
157        snprintf(buf, sizeof(buf), "OVERLAY");
158        break;
159    case TEXT:
160        snprintf(buf, sizeof(buf), "TEXT");
161        break;
162    case OUTLINE:
163        snprintf(buf, sizeof(buf), "OUTLINE");
164        break;
165    case SOLID:
166        snprintf(buf, sizeof(buf), "SOLID");
167        break;
168    case LOGO:
169        snprintf(buf, sizeof(buf), "LOGO");
170        break;
171    case VIRTUAL:
172        snprintf(buf, sizeof(buf), "VIRTUAL");
173        break;
174
175    case EQUALS:
176        snprintf(buf, sizeof(buf), "EQUALS");
177        break;
178    case PLUS:
179        snprintf(buf, sizeof(buf), "PLUS");
180        break;
181    case MINUS:
182        snprintf(buf, sizeof(buf), "MINUS");
183        break;
184    case DIVIDE:
185        snprintf(buf, sizeof(buf), "DIVIDE");
186        break;
187    case TIMES:
188        snprintf(buf, sizeof(buf), "TIMES");
189        break;
190    case OBRACE:
191        snprintf(buf, sizeof(buf), "OBRACE");
192        break;
193    case CBRACE:
194        snprintf(buf, sizeof(buf), "CBRACE");
195        break;
196    case OPAREN:
197        snprintf(buf, sizeof(buf), "OPAREN");
198        break;
199    case CPAREN:
200        snprintf(buf, sizeof(buf), "CPAREN");
201        break;
202    case OBRACKET:
203        snprintf(buf, sizeof(buf), "OBRACKET");
204        break;
205    case CBRACKET:
206        snprintf(buf, sizeof(buf), "CBRACKET");
207        break;
208    case DOT:
209        snprintf(buf, sizeof(buf), "DOT");
210        break;
211    case COMMA:
212        snprintf(buf, sizeof(buf), "COMMA");
213        break;
214    case SEMI:
215        snprintf(buf, sizeof(buf), "SEMI");
216        break;
217    case EXCLAM:
218        snprintf(buf, sizeof(buf), "EXCLAM");
219        break;
220    case INVERT:
221        snprintf(buf, sizeof(buf), "INVERT");
222        break;
223
224    case STRING:
225        snprintf(buf, sizeof(buf), "STRING (%s)", scanBuf);
226        break;
227    case INTEGER:
228        snprintf(buf, sizeof(buf), "INTEGER (0x%x)", scanInt);
229        break;
230    case FLOAT:
231        snprintf(buf, sizeof(buf), "FLOAT (%d.%d)",
232                scanInt / XkbGeomPtsPerMM, scanInt % XkbGeomPtsPerMM);
233        break;
234    case IDENT:
235        snprintf(buf, sizeof(buf), "IDENT (%s)", scanBuf);
236        break;
237    case KEYNAME:
238        snprintf(buf, sizeof(buf), "KEYNAME (%s)", scanBuf);
239        break;
240
241    case PARTIAL:
242        snprintf(buf, sizeof(buf), "PARTIAL");
243        break;
244    case DEFAULT:
245        snprintf(buf, sizeof(buf), "DEFAULT");
246        break;
247    case HIDDEN:
248        snprintf(buf, sizeof(buf), "HIDDEN");
249        break;
250
251    case ALPHANUMERIC_KEYS:
252        snprintf(buf, sizeof(buf), "ALPHANUMERIC_KEYS");
253        break;
254    case MODIFIER_KEYS:
255        snprintf(buf, sizeof(buf), "MODIFIER_KEYS");
256        break;
257    case KEYPAD_KEYS:
258        snprintf(buf, sizeof(buf), "KEYPAD_KEYS");
259        break;
260    case FUNCTION_KEYS:
261        snprintf(buf, sizeof(buf), "FUNCTION_KEYS");
262        break;
263    case ALTERNATE_GROUP:
264        snprintf(buf, sizeof(buf), "ALTERNATE_GROUP");
265        break;
266
267    default:
268        snprintf(buf, sizeof(buf), "UNKNOWN");
269        break;
270    }
271    return buf;
272}
273#endif
274
275void
276scan_set_file(FILE *file)
277{
278    readBufLen = 0;
279    readBufPos = 0;
280    yyin = file;
281}
282
283static int
284scanchar(void)
285{
286    if (readBufPos >= readBufLen) {
287        readBufLen = fread(readBuf, 1, BUFSIZE, yyin);
288        readBufPos = 0;
289        if (!readBufLen)
290            return EOF;
291        if (feof(yyin))
292            readBuf[readBufLen] = EOF;
293    }
294
295    return readBuf[readBufPos++];
296}
297
298static void
299unscanchar(int c)
300{
301    if (readBuf[--readBufPos] != c) {
302        fprintf(stderr, "UNGETCHAR FAILED! Put back %c, was expecting %c at "
303                        "position %d, buf is '%s'\n", c, readBuf[readBufPos],
304                        readBufPos, readBuf);
305        _exit(94);
306    }
307}
308
309int
310setScanState(char *file, int line)
311{
312    if (file != NULL)
313        strncpy(scanFile, file, 1024);
314    if (line >= 0)
315        lineNum = line;
316    return 1;
317}
318
319static int
320yyGetString(void)
321{
322    int ch, i;
323
324    i = 0;
325    while (((ch = scanchar()) != EOF) && (ch != '"'))
326    {
327        if (ch == '\\')
328        {
329            if ((ch = scanchar()) != EOF)
330            {
331                if (ch == 'n')
332                    ch = '\n';
333                else if (ch == 't')
334                    ch = '\t';
335                else if (ch == 'v')
336                    ch = '\v';
337                else if (ch == 'b')
338                    ch = '\b';
339                else if (ch == 'r')
340                    ch = '\r';
341                else if (ch == 'f')
342                    ch = '\f';
343                else if (ch == 'e')
344                    ch = '\033';
345                else if (ch == '0')
346                {
347                    int tmp, stop;
348                    ch = stop = 0;
349                    if (((tmp = scanchar()) != EOF) && (isdigit(tmp))
350                        && (tmp != '8') && (tmp != '9'))
351                    {
352                        ch = (ch * 8) + (tmp - '0');
353                    }
354                    else
355                    {
356                        stop = 1;
357                        unscanchar(tmp);
358                    }
359                    if (!stop)
360                    {
361                        if (((tmp = scanchar()) != EOF)
362                            && (isdigit(tmp)) && (tmp != '8') && (tmp != '9'))
363                        {
364                            ch = (ch * 8) + (tmp - '0');
365                        }
366                        else
367                        {
368                            stop = 1;
369                            unscanchar(tmp);
370                        }
371                    }
372                    if (!stop)
373                    {
374                        if (((tmp = scanchar()) != EOF)
375                            && (isdigit(tmp)) && (tmp != '8') && (tmp != '9'))
376                        {
377                            ch = (ch * 8) + (tmp - '0');
378                        }
379                        else
380                        {
381                            stop = 1;
382                            unscanchar(tmp);
383                        }
384                    }
385                }
386            }
387            else
388                return ERROR_TOK;
389        }
390        if (i < sizeof(scanBuf) - 1)
391            scanBuf[i++] = ch;
392    }
393    scanBuf[i] = '\0';
394    if (ch == '"')
395    {
396        scanStrLine = lineNum;
397        return STRING;
398    }
399    return ERROR_TOK;
400}
401
402static int
403yyGetKeyName(void)
404{
405    int ch, i;
406
407    i = 0;
408    while (((ch = scanchar()) != EOF) && (ch != '>'))
409    {
410        if (ch == '\\')
411        {
412            if ((ch = scanchar()) != EOF)
413            {
414                if (ch == 'n')
415                    ch = '\n';
416                else if (ch == 't')
417                    ch = '\t';
418                else if (ch == 'v')
419                    ch = '\v';
420                else if (ch == 'b')
421                    ch = '\b';
422                else if (ch == 'r')
423                    ch = '\r';
424                else if (ch == 'f')
425                    ch = '\f';
426                else if (ch == 'e')
427                    ch = '\033';
428                else if (ch == '0')
429                {
430                    int tmp, stop;
431                    ch = stop = 0;
432                    if (((tmp = scanchar()) != EOF) && (isdigit(tmp))
433                        && (tmp != '8') && (tmp != '9'))
434                    {
435                        ch = (ch * 8) + (tmp - '0');
436                    }
437                    else
438                    {
439                        stop = 1;
440                        unscanchar(tmp);
441                    }
442                    if ((!stop) && ((tmp = scanchar()) != EOF)
443                        && (isdigit(tmp)) && (tmp != '8') && (tmp != '9'))
444                    {
445                        ch = (ch * 8) + (tmp - '0');
446                    }
447                    else
448                    {
449                        stop = 1;
450                        unscanchar(tmp);
451                    }
452                    if ((!stop) && ((tmp = scanchar()) != EOF)
453                        && (isdigit(tmp)) && (tmp != '8') && (tmp != '9'))
454                    {
455                        ch = (ch * 8) + (tmp - '0');
456                    }
457                    else
458                    {
459                        stop = 1;
460                        unscanchar(tmp);
461                    }
462                }
463            }
464            else
465                return ERROR_TOK;
466        }
467        if (i < sizeof(scanBuf) - 1)
468            scanBuf[i++] = ch;
469    }
470    scanBuf[i] = '\0';
471    if ((ch == '>') && (i < 5))
472    {
473        scanStrLine = lineNum;
474        return KEYNAME;
475    }
476    return ERROR_TOK;
477}
478
479static struct _Keyword
480{
481    const char *keyword;
482    int token;
483} keywords[] =
484{
485    {
486    "xkb_keymap", XKB_KEYMAP},
487    {
488    "xkb_keycodes", XKB_KEYCODES},
489    {
490    "xkb_types", XKB_TYPES},
491    {
492    "xkb_symbols", XKB_SYMBOLS},
493    {
494    "xkb_compat", XKB_COMPATMAP},
495    {
496    "xkb_compat_map", XKB_COMPATMAP},
497    {
498    "xkb_compatibility", XKB_COMPATMAP},
499    {
500    "xkb_compatibility_map", XKB_COMPATMAP},
501    {
502    "xkb_geometry", XKB_GEOMETRY},
503    {
504    "xkb_semantics", XKB_SEMANTICS},
505    {
506    "xkb_layout", XKB_LAYOUT},
507    {
508    "include", INCLUDE},
509    {
510    "override", OVERRIDE},
511    {
512    "augment", AUGMENT},
513    {
514    "replace", REPLACE},
515    {
516    "alternate", ALTERNATE},
517    {
518    "partial", PARTIAL},
519    {
520    "default", DEFAULT},
521    {
522    "hidden", HIDDEN},
523    {
524    "virtual_modifiers", VIRTUAL_MODS},
525    {
526    "type", TYPE},
527    {
528    "interpret", INTERPRET},
529    {
530    "action", ACTION_TOK},
531    {
532    "key", KEY},
533    {
534    "alias", ALIAS},
535    {
536    "group", GROUP},
537    {
538    "modmap", MODIFIER_MAP},
539    {
540    "mod_map", MODIFIER_MAP},
541    {
542    "modifier_map", MODIFIER_MAP},
543    {
544    "indicator", INDICATOR},
545    {
546    "shape", SHAPE},
547    {
548    "row", ROW},
549    {
550    "keys", KEYS},
551    {
552    "section", SECTION},
553    {
554    "overlay", OVERLAY},
555    {
556    "text", TEXT},
557    {
558    "outline", OUTLINE},
559    {
560    "solid", SOLID},
561    {
562    "logo", LOGO},
563    {
564    "virtual", VIRTUAL},
565    {
566    "alphanumeric_keys", ALPHANUMERIC_KEYS},
567    {
568    "modifier_keys", MODIFIER_KEYS},
569    {
570    "keypad_keys", KEYPAD_KEYS},
571    {
572    "function_keys", FUNCTION_KEYS},
573    {
574    "alternate_group", ALTERNATE_GROUP}
575};
576static int numKeywords = sizeof(keywords) / sizeof(struct _Keyword);
577
578static int
579yyGetIdent(int first)
580{
581    int ch, j, found;
582    int rtrn = IDENT;
583
584    scanBuf[0] = first;
585    j = 1;
586    while (((ch = scanchar()) != EOF) && (isalnum(ch) || (ch == '_')))
587    {
588        if (j < sizeof(scanBuf) - 1)
589            scanBuf[j++] = ch;
590    }
591    scanBuf[j++] = '\0';
592    found = 0;
593
594    for (int i = 0; (!found) && (i < numKeywords); i++)
595    {
596        if (uStrCaseCmp(scanBuf, keywords[i].keyword) == 0)
597        {
598            rtrn = keywords[i].token;
599            found = 1;
600        }
601    }
602    if (!found)
603    {
604        scanStrLine = lineNum;
605        rtrn = IDENT;
606    }
607
608    if ((ch != EOF) && (!isspace(ch)))
609        unscanchar(ch);
610    else if (ch == '\n')
611        lineNum++;
612
613    return rtrn;
614}
615
616static int
617yyGetNumber(int ch)
618{
619    const int nMaxBuffSize = 1024;
620    int isFloat = 0;
621    char buf[nMaxBuffSize];
622    int nInBuf = 0;
623
624    buf[0] = ch;
625    nInBuf = 1;
626    while (((ch = scanchar()) != EOF)
627           && (isxdigit(ch) || ((nInBuf == 1) && (ch == 'x')))
628           && nInBuf < (nMaxBuffSize - 1))
629    {
630        buf[nInBuf++] = ch;
631    }
632    if ((ch == '.') && (nInBuf < (nMaxBuffSize - 1)))
633    {
634        isFloat = 1;
635        buf[nInBuf++] = ch;
636        while (((ch = scanchar()) != EOF) && (isxdigit(ch))
637               && nInBuf < (nMaxBuffSize - 1))
638        {
639            buf[nInBuf++] = ch;
640        }
641    }
642    buf[nInBuf++] = '\0';
643    if ((ch != EOF) && (!isspace(ch)))
644        unscanchar(ch);
645
646    if (isFloat)
647    {
648        float tmp;
649        if (sscanf(buf, "%g", &tmp) == 1)
650        {
651            scanInt = tmp * XkbGeomPtsPerMM;
652            return FLOAT;
653        }
654    }
655    else if (sscanf(buf, "%i", &scanInt) == 1)
656        return INTEGER;
657    fprintf(stderr, "Malformed number %s\n", buf);
658    return ERROR_TOK;
659}
660
661int
662yylex(void)
663{
664    int ch;
665    int rtrn;
666
667    do
668    {
669        ch = scanchar();
670        if (ch == '\n')
671        {
672            lineNum++;
673        }
674        else if (ch == '#')
675        {                       /* handle shell style '#' comments */
676            do
677            {
678                ch = scanchar();
679            }
680            while ((ch != '\n') && (ch != EOF));
681            lineNum++;
682        }
683        else if (ch == '/')
684        {                       /* handle C++ style double-/ comments */
685            int newch = scanchar();
686            if (newch == '/')
687            {
688                do
689                {
690                    ch = scanchar();
691                }
692                while ((ch != '\n') && (ch != EOF));
693                lineNum++;
694            }
695            else if (newch != EOF)
696            {
697                unscanchar(newch);
698            }
699        }
700    }
701    while ((ch != EOF) && (isspace(ch)));
702    if (ch == '=')
703        rtrn = EQUALS;
704    else if (ch == '+')
705        rtrn = PLUS;
706    else if (ch == '-')
707        rtrn = MINUS;
708    else if (ch == '/')
709        rtrn = DIVIDE;
710    else if (ch == '*')
711        rtrn = TIMES;
712    else if (ch == '{')
713        rtrn = OBRACE;
714    else if (ch == '}')
715        rtrn = CBRACE;
716    else if (ch == '(')
717        rtrn = OPAREN;
718    else if (ch == ')')
719        rtrn = CPAREN;
720    else if (ch == '[')
721        rtrn = OBRACKET;
722    else if (ch == ']')
723        rtrn = CBRACKET;
724    else if (ch == '.')
725        rtrn = DOT;
726    else if (ch == ',')
727        rtrn = COMMA;
728    else if (ch == ';')
729        rtrn = SEMI;
730    else if (ch == '!')
731        rtrn = EXCLAM;
732    else if (ch == '~')
733        rtrn = INVERT;
734    else if (ch == '"')
735        rtrn = yyGetString();
736    else if (ch == '<')
737        rtrn = yyGetKeyName();
738    else if (isalpha(ch) || (ch == '_'))
739        rtrn = yyGetIdent(ch);
740    else if (isdigit(ch))
741        rtrn = yyGetNumber(ch);
742    else if (ch == EOF)
743        rtrn = END_OF_FILE;
744    else
745    {
746#ifdef DEBUG
747        if (debugFlags)
748            fprintf(stderr,
749                    "Unexpected character %c (%d) in input stream\n", ch, ch);
750#endif
751        rtrn = ERROR_TOK;
752    }
753#ifdef DEBUG
754    if (debugFlags & 0x2)
755        fprintf(stderr, "scan: %s\n", tokText(rtrn));
756#endif
757    return rtrn;
758}
759