%{
/*
**  OSSP l2 - Flexible Logging
**  Copyright (c) 2001-2003 Cable & Wireless Deutschland GmbH
**  Copyright (c) 2001-2003 The OSSP Project (http://www.ossp.org/)
**  Copyright (c) 2001-2003 Ralf S. Engelschall <rse@engelschall.com>
**
**  This file is part of OSSP l2, a flexible logging library which
**  can be found at http://www.ossp.org/pkg/lib/l2/.
**
**  Permission to use, copy, modify, and distribute this software for
**  any purpose with or without fee is hereby granted, provided that
**  the above copyright notice and this permission notice appear in all
**  copies.
**
**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
**  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
**  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
**  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
**  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
**  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
**  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
**  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
**  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
**  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
**  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
**  SUCH DAMAGE.
**
**  l2_spec_scan.l: GNU Flex (Lex-style) scanner specification
**
**  ATTENTION: This requires GNU Flex 2.5.10 or newer!
*/

#include "l2.h"             /* for l2_xxx() */
#include "l2_spec.h"        /* for l2_spec_ctx_t */
#include "l2_spec_parse.h"  /* for T_XXXX */

/* how to find our own context */
#define CTX ((l2_spec_ctx_t *)yyget_extra(yyscanner))

/* provide own input handling */
#define YY_NO_UNPUT 1
#undef  YY_INPUT
#define YY_INPUT(buf,result,max_size) (result = yyinput(CTX, buf, max_size))
static int yyinput(l2_spec_ctx_t *ctx, char *buf, int max_size);

/* location tracking */
#define YY_USER_INIT \
    yylloc->first = 0; \
    yylloc->last  = 0;
#define YY_USER_ACTION \
    yylloc->first = yylloc->last; \
    yylloc->last += yyleng;
#define YY_USER_ACTION_ROLLBACK \
    yylloc->last = yylloc->first
%}

/* scanner options */
%pointer
%option stack
%option reentrant
%option bison-bridge
%option bison-locations
%option never-interactive
%option noyywrap

/* scanner states */
%x SS_PARAM
%x SS_PARAM_Q

%%

    /* local variables */
    char  caParam[2048];
    char *cpParam = NULL;

    /* parameter value */
<SS_PARAM>\" {
    if (cpParam == NULL)
        cpParam = caParam;
    BEGIN(SS_PARAM_Q);
}
<SS_PARAM>\\. {
    if (cpParam == NULL)
        cpParam = caParam;
    *cpParam++ = yytext[1];
}
<SS_PARAM>[^ \t\r\n\\,)"]+ {
    char *cp = yytext;
    if (cpParam == NULL)
        cpParam = caParam;
    while (*cp != '\0')
        *cpParam++ = *cp++;
}
<SS_PARAM>(.|\n) {
    if (cpParam == NULL)
        cpParam = caParam;
    *cpParam = '\0';
    yylval->cpValue = strdup(caParam);
    cpParam = NULL;
    yyless(0);
    YY_USER_ACTION_ROLLBACK;
    return T_PARAM;
}
<SS_PARAM_Q>\" {
    BEGIN(SS_PARAM);
}
<SS_PARAM_Q>\n {
    l2_spec_error(CTX, L2_ERR_SYN, yylloc, "Unterminated string");
    return 0;
}
<SS_PARAM_Q>\\[0-7]{1,3} {
    unsigned int result;
    (void)sscanf(yytext+1, "%o", &result);
    if (result > 0xff) {
        l2_spec_error(CTX, L2_ERR_SYN, yylloc, "Escape sequence out of bound");
        return 0;
    }
    else
        *cpParam++ = result;
}
<SS_PARAM_Q>\\x[0-9a-fA-F]{2} {
    unsigned int result;
    (void)sscanf(yytext+1, "%x", &result);
    if (result > 0xff) {
        l2_spec_error(CTX, L2_ERR_SYN, yylloc, "Escape sequence out of bound");
        return 0;
    }
    else
        *cpParam++ = result;
}
<SS_PARAM_Q>\\n { *cpParam++ = '\n'; }
<SS_PARAM_Q>\\r { *cpParam++ = '\r'; }
<SS_PARAM_Q>\\t { *cpParam++ = '\t'; }
<SS_PARAM_Q>\\b { *cpParam++ = '\b'; }
<SS_PARAM_Q>\\f { *cpParam++ = '\f'; }
<SS_PARAM_Q>\\(.|\n) {
    *cpParam++ = yytext[1];
}
<SS_PARAM_Q>[^\\\"]+ {
    char *cp = yytext;
    while (*cp != '\0')
        *cpParam++ = *cp++;
}
<SS_PARAM_Q>(.|\n) {
    *cpParam++ = yytext[0];
}

    /* whitespaces */
[ \t\n]+ {
    /* NOOP */
}

   /* operators */
"->" {
    return T_OP_ARROW;
}

   /* identifiers */
[a-zA-Z][a-zA-Z0-9_-]* {
    yylval->cpValue = strdup(yytext);
    return T_ID;
}

   /* anything else is returned as is... */
.|\n {
    return yytext[0];
}

%%

/* external scanner state transitions */
void l2_spec_scan_push(l2_spec_ctx_t *ctx, const char *state);
void l2_spec_scan_push(l2_spec_ctx_t *ctx, const char *state)
{
    if (strcmp(state, "SS_PARAM") == 0)
        yy_push_state(SS_PARAM, ctx->yyscan);
}
void l2_spec_scan_pop(l2_spec_ctx_t *ctx);
void l2_spec_scan_pop(l2_spec_ctx_t *ctx)
{
    yy_pop_state(ctx->yyscan);
}

/* buffer-based input routine */
static int yyinput(l2_spec_ctx_t *ctx, char *buf, int max_size)
{
    int n;

    n = (ctx->inputbuf + ctx->inputlen - ctx->inputptr);
    if (n > max_size)
        n = max_size;
    if (n <= 0)
        return YY_NULL;
    memcpy(buf, ctx->inputptr, n);
    ctx->inputptr += n;
    return n;
}

