Esempio n. 1
0
static int
compile_append_text(lwan_tpl_t *tpl, strbuf_t *buf)
{
    int length = strbuf_get_length(buf);
    if (!length)
        return 0;

    lwan_tpl_chunk_t *chunk = malloc(sizeof(*chunk));
    if (!chunk)
        return -ENOMEM;

    if (length == 1) {
        chunk->action = TPL_ACTION_APPEND_CHAR;
        chunk->data = (void *)((uintptr_t)strbuf_get_buffer(buf)[0]);
    } else {
        chunk->action = TPL_ACTION_APPEND;
        chunk->data = strdup(strbuf_get_buffer(buf));
    }

    chunk->next = tpl->chunks;
    tpl->chunks = chunk;
    tpl->minimum_size += strbuf_get_length(buf);
    strbuf_reset(buf);

    return 0;
}
Esempio n. 2
0
static int
compile_append_var(lwan_tpl_t *tpl, strbuf_t *buf)
{
    lwan_tpl_chunk_t *chunk = malloc(sizeof(*chunk));
    if (!chunk)
        return -ENOMEM;

    char *variable = strbuf_get_buffer(buf);
    int length = strbuf_get_length(buf) - 1;

    switch (*variable) {
    case '>': {
        char template_file[PATH_MAX];
        snprintf(template_file, sizeof(template_file), "%s.tpl", variable + 1);

        lwan_tpl_t *included = lwan_tpl_compile(template_file);
        if (!included)
            return -ENOENT;
        chunk->action = TPL_ACTION_APPLY_TPL;
        chunk->data = included;
        break;
    }
    case '#':
        chunk->action = TPL_ACTION_LIST_START_ITER;
        chunk->data = strdup(variable + 1);
        break;
    case '/':
        if (variable[length] == '?') {
            chunk->action = TPL_ACTION_END_IF_VARIABLE_NOT_EMPTY;
            variable[length] = '\0';
        } else {
            chunk->action = TPL_ACTION_LIST_END_ITER;
        }
        chunk->data = strdup(variable + 1);
        break;
    default:
        if (variable[length] == '?') {
            chunk->action = TPL_ACTION_IF_VARIABLE_NOT_EMPTY;
            variable[length] = '\0';
        } else {
            chunk->action = TPL_ACTION_VARIABLE;
        }
        chunk->data = strdup(variable);
    }

    chunk->next = tpl->chunks;
    tpl->chunks = chunk;
    tpl->minimum_size += strbuf_get_length(buf);
    strbuf_reset(buf);

    return 0;
}
Esempio n. 3
0
static int
dijkstra_result(ladders_rec_t *rec, Vertex *vv)
{
    register Vertex *t, *p, *q; /* registers for reversing links */

    t = NULL, p = vv;

    if (!p->backlink) {
        strbuf_append_printf(rec->response->buffer,
                             "Sorry, %s is unreachable.", p->name);
        return 0;
    }

    do { /* pop an item from |p| to |t| */
        q = p->backlink;
        p->backlink = t;
        t = p;
        p = q;
    } while (t != p); /* the loop stops with |t==p==uu| */

    do {
        strbuf_append_printf(&rec->path, "\"%s\",", t->name);
        t = t->backlink;
    } while (t);
    rec->path.value.buffer[strbuf_get_length(&rec->path)-1] = '\0';

    t = p;

    do { /* pop an item from |t| to |p| */
        q = t->backlink;
        t->backlink = p;
        p = t;
        t = q;
    } while (p != vv);

    return 1;
}
Esempio n. 4
0
lwan_tpl_chunk_t *
lwan_tpl_apply_until(lwan_tpl_chunk_t *chunks, strbuf_t *buf,
    char *(*var_get)(const char *name, void *data), void *var_get_data,
    bool (*until)(lwan_tpl_chunk_t *chunk, void *data), void *until_data)
{
    lwan_tpl_chunk_t *chunk = chunks;

    for (; chunk; chunk = chunk->next) {
        if (until(chunk, until_data))
            break;

        switch (chunk->action) {
        case TPL_ACTION_APPEND:
            strbuf_append_str(buf, chunk->data, 0);
            break;
        case TPL_ACTION_APPEND_CHAR:
            strbuf_append_char(buf, (char)(uintptr_t)chunk->data);
            break;
        case TPL_ACTION_VARIABLE:
            {
                char *tmp = var_get((const char*)chunk->data, var_get_data);
                strbuf_append_str(buf, tmp, 0);
                free(tmp);
            }
            break;
        case TPL_ACTION_LIST_START_ITER:
            strbuf_append_str(buf, "[begin_iter:", 0);
            strbuf_append_str(buf, chunk->data, 0);
            strbuf_append_str(buf, "]", 0);
            break;
        case TPL_ACTION_LIST_END_ITER:
            strbuf_append_str(buf, "[end_iter:", 0);
            strbuf_append_str(buf, chunk->data, 0);
            strbuf_append_str(buf, "]", 0);
            break;
        case TPL_ACTION_IF_VARIABLE_NOT_EMPTY:
            {
                const char *var_name = (const char*)chunk->data;
                char *tmp = var_get(var_name, var_get_data);
                if (tmp && *tmp) {
                    chunk = lwan_tpl_apply_until(chunk->next, buf, var_get, var_get_data, 
                                        until_not_empty, chunk->data);
                } else {
                    for (chunk = chunk->next; chunk; chunk = chunk->next) {
                        if (chunk->action == TPL_ACTION_END_IF_VARIABLE_NOT_EMPTY && !strcmp(chunk->data, var_name))
                            break;
                    }
                }
                free(tmp);
            }
            break;
        case TPL_ACTION_END_IF_VARIABLE_NOT_EMPTY:
            /* Shouldn't happen */
            break;
        case TPL_ACTION_APPLY_TPL:
            {
                strbuf_t *tmp = lwan_tpl_apply(chunk->data, var_get, var_get_data);
                strbuf_append_str(buf, strbuf_get_buffer(tmp), strbuf_get_length(tmp));
                strbuf_free(tmp);
            }
        }
    }

    return chunk;
}
Esempio n. 5
0
lwan_tpl_t *
lwan_tpl_compile(const char *filename)
{
    lwan_tpl_t *tpl;
    strbuf_t *buf;
    FILE *file;
    int state = STATE_DEFAULT;
    char error_msg[512];
    
    tpl = calloc(1, sizeof(*tpl));
    if (!tpl)
        return NULL;

    buf = strbuf_new();
    if (!buf) {
        free(tpl);
        return NULL;
    }
    
    file = fopen(filename, "r");
    if (!file) {
        strbuf_free(buf);
        free(tpl);
        return NULL;
    }

    int line = 1;
    int column = 1;
    char ch;
    while ((ch = fgetc(file)) != EOF) {
        if (ch == '\n') {
            if (state == STATE_DEFAULT)
                strbuf_append_char(buf, '\n');

            line++;
            column = 1;
            continue;
        }
        ++column;

        switch (state) {
        case STATE_DEFAULT:
            if (ch == '{') {
                state = STATE_FIRST_BRACE;
                continue;
            }

            strbuf_append_char(buf, ch);
            break;
        case STATE_FIRST_BRACE:
            if (ch == '{') {
                switch (compile_append_text(tpl, buf)) {
                case -ENOMEM:
                    PARSE_ERROR("Out of memory while appending text.");
                }

                state = STATE_SECOND_BRACE;
                continue;
            }

            strbuf_append_char(buf, '{');
            strbuf_append_char(buf, ch);
            state = STATE_DEFAULT;
            break;
        case STATE_SECOND_BRACE:
            if (ch == '{')
                PARSE_ERROR("Unexpected open brace.");

            if (ch == '}') {
                state = STATE_FIRST_CLOSING_BRACE;
                continue;
            }

            strbuf_append_char(buf, ch);
            break;
        case STATE_FIRST_CLOSING_BRACE:
            if (ch == '}') {
                state = STATE_SECOND_CLOSING_BRACE;
                continue;
            }
            PARSE_ERROR("Closing brace expected.");
        case STATE_SECOND_CLOSING_BRACE:
            if (ch == '}')
                PARSE_ERROR("Unexpected close brace.");

            if (strbuf_get_length(buf) == 0)
                PARSE_ERROR("Expecting variable name.");

            switch (compile_append_var(tpl, buf)) {
            case -ENOMEM:
                PARSE_ERROR("Out of memory while appending variable.");
            case -ENOENT:
                PARSE_ERROR("Cannot find included template: ``%s''.", strbuf_get_buffer(buf) + 1);
            }

            if (ch == '{') {
                state = STATE_FIRST_BRACE;
                continue;
            }

            strbuf_append_char(buf, ch);
            state = STATE_DEFAULT;
        }
    }

    switch (state) {
    case STATE_DEFAULT:
        switch (compile_append_text(tpl, buf)) {
        case -ENOMEM:
            PARSE_ERROR("Out of memory while appending text.");
        }
        break;
    case STATE_FIRST_BRACE:
    case STATE_SECOND_BRACE:
        PARSE_ERROR("Expecting close brace.");
    case STATE_FIRST_CLOSING_BRACE:
        PARSE_ERROR("Expecting second close brace.");
    case STATE_SECOND_CLOSING_BRACE:
        if (strbuf_get_length(buf) == 0)
            PARSE_ERROR("Expecting variable name.");

        switch (compile_append_var(tpl, buf)) {
        case -ENOMEM:
            PARSE_ERROR("Out of memory while appending variable.");
        case -ENOENT:
            PARSE_ERROR("Cannot find included template: ``%s''.", strbuf_get_buffer(buf));
        }
    }

    lwan_tpl_chunk_t *last = malloc(sizeof(*last));
    if (!last)
        goto error;
    last->action = TPL_ACTION_LAST;
    last->data = NULL;
    last->next = tpl->chunks;
    tpl->chunks = last;

    lwan_tpl_chunk_t *prev = NULL;
    while (tpl->chunks) {
        lwan_tpl_chunk_t *next = tpl->chunks->next;
        tpl->chunks->next = prev;
        prev = tpl->chunks;
        tpl->chunks = next;
    }
    tpl->chunks = prev;

    strbuf_free(buf);
    return tpl;

error:
    lwan_tpl_free(tpl);
    strbuf_free(buf);
    fclose(file);
    
    printf("Line %d, column %d: %s\n", line, column, error_msg);
    return NULL;
}
Esempio n. 6
0
static void *parse_key_value(struct parser *parser)
{
    struct config_line line = { .type = CONFIG_LINE_TYPE_LINE };
    struct lexeme *lexeme;
    size_t key_size;

    while (lexeme_buffer_consume(&parser->buffer, &lexeme)) {
        strbuf_append_str(&parser->strbuf, lexeme->value.value, lexeme->value.len);

        if (parser->buffer.population >= 1)
            strbuf_append_char(&parser->strbuf, '_');
    }
    key_size = strbuf_get_length(&parser->strbuf);
    strbuf_append_char(&parser->strbuf, '\0');

    while (lex_next(&parser->lexer, &lexeme)) {
        switch (lexeme->type) {
        case LEXEME_VARIABLE: {
            const char *value;

            value = secure_getenv_len(lexeme->value.value, lexeme->value.len);
            if (!value) {
                lwan_status_error("Variable '$%.*s' not defined in environment",
                    (int)lexeme->value.len, lexeme->value.value);
                return NULL;
            }

            strbuf_append_str(&parser->strbuf, value, 0);
            break;
        }

        case LEXEME_EQUAL:
            strbuf_append_char(&parser->strbuf, '=');
            break;

        case LEXEME_STRING:
            strbuf_append_str(&parser->strbuf, lexeme->value.value, lexeme->value.len);
            break;

        case LEXEME_CLOSE_BRACKET:
            backup(&parser->lexer);
            /* fallthrough */

        case LEXEME_LINEFEED:
            line.key = strbuf_get_buffer(&parser->strbuf);
            line.value = line.key + key_size + 1;
            if (!config_buffer_emit(&parser->items, &line))
                return NULL;

            return parse_config;

        default:
            lwan_status_error("Unexpected token while parsing key-value: %s",
                lexeme_type_str[lexeme->type]);
            return NULL;
        }
    }

    lwan_status_error("EOF while parsing key-value");
    return NULL;
}