16f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin/*
26f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * Copyright © 2012 Ran Benita <ran234@gmail.com>
36f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin *
46f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * Permission is hereby granted, free of charge, to any person obtaining a
56f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * copy of this software and associated documentation files (the "Software"),
66f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * to deal in the Software without restriction, including without limitation
76f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * the rights to use, copy, modify, merge, publish, distribute, sublicense,
86f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * and/or sell copies of the Software, and to permit persons to whom the
96f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * Software is furnished to do so, subject to the following conditions:
106f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin *
116f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * The above copyright notice and this permission notice (including the next
126f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * paragraph) shall be included in all copies or substantial portions of the
136f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * Software.
146f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin *
156f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
166f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
176f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
186f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
196f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
206f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
216f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin * DEALINGS IN THE SOFTWARE.
226f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin */
236f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
246f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#ifndef XKBCOMP_SCANNER_UTILS_H
256f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#define XKBCOMP_SCANNER_UTILS_H
266f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
276f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin/* Point to some substring in the file; used to avoid copying. */
286f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstruct sval {
296f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    const char *start;
306f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    unsigned int len;
316f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin};
326f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempintypedef darray(struct sval) darray_sval;
336f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
346f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline bool
356f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinsvaleq(struct sval s1, struct sval s2)
366f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
376f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return s1.len == s2.len && memcmp(s1.start, s2.start, s1.len) == 0;
386f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
396f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
406f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline bool
416f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinsvaleq_prefix(struct sval s1, struct sval s2)
426f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
436f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return s1.len <= s2.len && memcmp(s1.start, s2.start, s1.len) == 0;
446f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
456f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
466f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstruct scanner {
476f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    const char *s;
486f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    size_t pos;
496f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    size_t len;
506f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    char buf[1024];
516f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    size_t buf_pos;
526f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    unsigned line, column;
536f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    /* The line/column of the start of the current token. */
546f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    unsigned token_line, token_column;
556f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    const char *file_name;
566f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    struct xkb_context *ctx;
576f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    void *priv;
586f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin};
596f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
606f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#define scanner_log(scanner, level, fmt, ...) \
616f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    xkb_log((scanner)->ctx, (level), 0, \
626f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin            "%s:%u:%u: " fmt "\n", \
636f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin             (scanner)->file_name, \
646f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin             (scanner)->token_line, (scanner)->token_column, ##__VA_ARGS__)
656f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
666f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#define scanner_err(scanner, fmt, ...) \
676f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    scanner_log(scanner, XKB_LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__)
686f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
696f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#define scanner_warn(scanner, fmt, ...) \
706f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    scanner_log(scanner, XKB_LOG_LEVEL_WARNING, fmt, ##__VA_ARGS__)
716f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
726f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline void
736f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinscanner_init(struct scanner *s, struct xkb_context *ctx,
746f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin             const char *string, size_t len, const char *file_name,
756f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin             void *priv)
766f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
776f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->s = string;
786f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->len = len;
796f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->pos = 0;
806f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->line = s->column = 1;
816f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->token_line = s->token_column = 1;
826f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->file_name = file_name;
836f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->ctx = ctx;
846f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->priv = priv;
856f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
866f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
876f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline char
886f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinpeek(struct scanner *s)
896f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
906f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    if (unlikely(s->pos >= s->len))
916f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        return '\0';
926f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return s->s[s->pos];
936f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
946f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
956f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline bool
966f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempineof(struct scanner *s)
976f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
986f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return s->pos >= s->len;
996f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
1006f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
1016f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline bool
1026f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempineol(struct scanner *s)
1036f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
1046f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return peek(s) == '\n';
1056f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
1066f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
1076f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline void
1086f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinskip_to_eol(struct scanner *s)
1096f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
1106f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    const char *nl = memchr(s->s + s->pos, '\n', s->len - s->pos);
1116f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    const size_t new_pos = nl ? (size_t) (nl - s->s) : s->len;
1126f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->column += new_pos - s->pos;
1136f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->pos = new_pos;
1146f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
1156f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
1166f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline char
1176f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinnext(struct scanner *s)
1186f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
1196f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    if (unlikely(eof(s)))
1206f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        return '\0';
1216f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    if (unlikely(eol(s))) {
1226f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        s->line++;
1236f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        s->column = 1;
1246f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    }
1256f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    else {
1266f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        s->column++;
1276f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    }
1286f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return s->s[s->pos++];
1296f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
1306f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
1316f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline bool
1326f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinchr(struct scanner *s, char ch)
1336f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
1346f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    if (likely(peek(s) != ch))
1356f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        return false;
1366f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->pos++; s->column++;
1376f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return true;
1386f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
1396f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
1406f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline bool
1416f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstr(struct scanner *s, const char *string, size_t len)
1426f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
1436f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    if (s->len - s->pos < len)
1446f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        return false;
1456f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    if (memcmp(s->s + s->pos, string, len) != 0)
1466f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        return false;
1476f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->pos += len; s->column += len;
1486f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return true;
1496f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
1506f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
1516f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#define lit(s, literal) str(s, literal, sizeof(literal) - 1)
1526f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
1536f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline bool
1546f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinbuf_append(struct scanner *s, char ch)
1556f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
1566f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    if (s->buf_pos + 1 >= sizeof(s->buf))
1576f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        return false;
1586f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->buf[s->buf_pos++] = ch;
1596f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return true;
1606f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
1616f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
1626f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline bool
1636f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinbuf_appends(struct scanner *s, const char *str)
1646f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
1656f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    int ret;
1666f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    ret = snprintf(s->buf + s->buf_pos, sizeof(s->buf) - s->buf_pos, "%s", str);
1676f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    if (ret < 0 || (size_t) ret >= sizeof(s->buf) - s->buf_pos)
1686f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        return false;
1696f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    s->buf_pos += ret;
1706f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return true;
1716f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
1726f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
1736f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline bool
1746f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinoct(struct scanner *s, uint8_t *out)
1756f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
1766f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    int i;
1776f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    for (i = 0, *out = 0; peek(s) >= '0' && peek(s) <= '7' && i < 3; i++)
1786f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        *out = *out * 8 + next(s) - '0';
1796f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return i > 0;
1806f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
1816f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
1826f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinstatic inline bool
1836f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempinhex(struct scanner *s, uint8_t *out)
1846f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin{
1856f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    int i;
1866f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    for (i = 0, *out = 0; is_xdigit(peek(s)) && i < 2; i++) {
1876f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        const char c = next(s);
1886f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        const char offset = (c >= '0' && c <= '9' ? '0' :
1896f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin                             c >= 'a' && c <= 'f' ? 'a' - 10 : 'A' - 10);
1906f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin        *out = *out * 16 + c - offset;
1916f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    }
1926f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin    return i > 0;
1936f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin}
1946f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin
1956f36ec3ef7a87f9eaa37fc78868dbac2cb958b0Dennis Kempin#endif
196