gluon-web: clean up parser

This commit is contained in:
Matthias Schiffer 2018-02-22 21:09:35 +01:00
parent 5a20f9794c
commit 3203970969
No known key found for this signature in database
GPG Key ID: 16EF3F64CB201D9C
6 changed files with 262 additions and 294 deletions

View File

@ -19,6 +19,53 @@
#include "template_lmo.h" #include "template_lmo.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <fnmatch.h>
#include <dirent.h>
#include <ctype.h>
#include <limits.h>
struct lmo_entry {
uint32_t key_id;
uint32_t val_id;
uint32_t offset;
uint32_t length;
} __attribute__((packed));
typedef struct lmo_entry lmo_entry_t;
struct lmo_archive {
int fd;
int length;
uint32_t size;
lmo_entry_t *index;
char *mmap;
char *end;
struct lmo_archive *next;
};
typedef struct lmo_archive lmo_archive_t;
struct lmo_catalog {
char lang[6];
struct lmo_archive *archives;
struct lmo_catalog *next;
};
typedef struct lmo_catalog lmo_catalog_t;
/* /*
* Hash function from http://www.azillionmonkeys.com/qed/hash.html * Hash function from http://www.azillionmonkeys.com/qed/hash.html
* Copyright (C) 2004-2008 by Paul Hsieh * Copyright (C) 2004-2008 by Paul Hsieh

View File

@ -20,52 +20,7 @@
#ifndef _TEMPLATE_LMO_H_ #ifndef _TEMPLATE_LMO_H_
#define _TEMPLATE_LMO_H_ #define _TEMPLATE_LMO_H_
#include <stdlib.h> #include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <fnmatch.h>
#include <dirent.h>
#include <ctype.h>
#include <limits.h>
struct lmo_entry {
uint32_t key_id;
uint32_t val_id;
uint32_t offset;
uint32_t length;
} __attribute__((packed));
typedef struct lmo_entry lmo_entry_t;
struct lmo_archive {
int fd;
int length;
uint32_t size;
lmo_entry_t *index;
char *mmap;
char *end;
struct lmo_archive *next;
};
typedef struct lmo_archive lmo_archive_t;
struct lmo_catalog {
char lang[6];
struct lmo_archive *archives;
struct lmo_catalog *next;
};
typedef struct lmo_catalog lmo_catalog_t;
int lmo_load_catalog(const char *lang, const char *dir); int lmo_load_catalog(const char *lang, const char *dir);

View File

@ -21,6 +21,14 @@
#include "template_utils.h" #include "template_utils.h"
#include "template_lmo.h" #include "template_lmo.h"
#include <lualib.h>
#include <lauxlib.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#define TEMPLATE_LUALIB_META "gluon.web.template.parser" #define TEMPLATE_LUALIB_META "gluon.web.template.parser"

View File

@ -21,20 +21,79 @@
#include "template_utils.h" #include "template_utils.h"
#include "template_lmo.h" #include "template_lmo.h"
#include <lualib.h>
#include <lauxlib.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* code types */
#define T_TYPE_INIT 0
#define T_TYPE_TEXT 1
#define T_TYPE_COMMENT 2
#define T_TYPE_EXPR 3
#define T_TYPE_INCLUDE 4
#define T_TYPE_I18N 5
#define T_TYPE_I18N_RAW 6
#define T_TYPE_CODE 7
#define T_TYPE_EOF 8
struct template_chunk {
const char *s;
const char *e;
int type;
int line;
};
/* parser state */
struct template_parser {
int fd;
size_t size;
char *data;
char *off;
char *lua_chunk;
int line;
int in_expr;
bool strip_before;
bool strip_after;
struct template_chunk prv_chunk;
struct template_chunk cur_chunk;
const char *file;
};
/* leading and trailing code for different types */ /* leading and trailing code for different types */
static const char *const gen_code[9][2] = { static const char *const gen_code[][2] = {
{NULL, NULL}, [T_TYPE_INIT] = {NULL, NULL},
{"write(\"", "\")"}, [T_TYPE_TEXT] = {"write(\"", "\")"},
{NULL, NULL}, [T_TYPE_COMMENT] = {NULL, NULL},
{"write(tostring(", " or \"\"))"}, [T_TYPE_EXPR] = {"write(tostring(", " or \"\"))"},
{"include(\"", "\")"}, [T_TYPE_INCLUDE] = {"include(\"", "\")"},
{"write(\"", "\")"}, [T_TYPE_I18N] = {"write(\"", "\")"},
{"write(\"", "\")"}, [T_TYPE_I18N_RAW] = {"write(\"", "\")"},
{NULL, " "}, [T_TYPE_CODE] = {NULL, " "},
{} [T_TYPE_EOF] = {NULL, NULL},
}; };
static struct template_parser * template_init(struct template_parser *parser)
{
parser->off = parser->data;
parser->cur_chunk.type = T_TYPE_INIT;
parser->cur_chunk.s = parser->data;
parser->cur_chunk.e = parser->data;
return parser;
}
struct template_parser * template_open(const char *file) struct template_parser * template_open(const char *file)
{ {
struct stat s; struct stat s;
@ -56,44 +115,29 @@ struct template_parser * template_open(const char *file)
parser->data = mmap(NULL, parser->size, PROT_READ, MAP_PRIVATE, parser->data = mmap(NULL, parser->size, PROT_READ, MAP_PRIVATE,
parser->fd, 0); parser->fd, 0);
if (parser->data != MAP_FAILED) if (parser->data == MAP_FAILED)
{ goto err;
parser->off = parser->data;
parser->cur_chunk.type = T_TYPE_INIT;
parser->cur_chunk.s = parser->data;
parser->cur_chunk.e = parser->data;
return parser; return template_init(parser);
}
err: err:
template_close(parser); template_close(parser);
return NULL; return NULL;
} }
struct template_parser * template_string(const char *str, uint32_t len) struct template_parser * template_string(const char *str, size_t len)
{ {
struct template_parser *parser; struct template_parser *parser;
if (!str) {
errno = EINVAL;
return NULL;
}
if (!(parser = calloc(1, sizeof(*parser)))) if (!(parser = calloc(1, sizeof(*parser))))
goto err; goto err;
parser->fd = -1; parser->fd = -1;
parser->size = len; parser->size = len;
parser->data = (char*)str; parser->data = (char *)str;
parser->off = parser->data; return template_init(parser);
parser->cur_chunk.type = T_TYPE_INIT;
parser->cur_chunk.s = parser->data;
parser->cur_chunk.e = parser->data;
return parser;
err: err:
template_close(parser); template_close(parser);
@ -105,8 +149,7 @@ void template_close(struct template_parser *parser)
if (!parser) if (!parser)
return; return;
if (parser->gc != NULL) free(parser->lua_chunk);
free(parser->gc);
/* if file is not set, we were parsing a string */ /* if file is not set, we were parsing a string */
if (parser->file) { if (parser->file) {
@ -124,18 +167,14 @@ static void template_text(struct template_parser *parser, const char *e)
{ {
const char *s = parser->off; const char *s = parser->off;
if (s < (parser->data + parser->size)) if (s < (parser->data + parser->size)) {
{ if (parser->strip_after) {
if (parser->strip_after) while ((s < e) && isspace(s[0]))
{
while ((s <= e) && isspace(*s))
s++; s++;
} }
parser->cur_chunk.type = T_TYPE_TEXT; parser->cur_chunk.type = T_TYPE_TEXT;
} } else {
else
{
parser->cur_chunk.type = T_TYPE_EOF; parser->cur_chunk.type = T_TYPE_EOF;
} }
@ -148,57 +187,53 @@ static void template_code(struct template_parser *parser, const char *e)
{ {
const char *s = parser->off; const char *s = parser->off;
parser->strip_before = 0; parser->strip_before = false;
parser->strip_after = 0; parser->strip_after = false;
if (*s == '-') if (s < e && s[0] == '-') {
{ parser->strip_before = true;
parser->strip_before = 1; s++;
for (s++; (s <= e) && (*s == ' ' || *s == '\t'); s++);
} }
if (*(e-1) == '-') if (s < e && e[-1] == '-') {
{ parser->strip_after = true;
parser->strip_after = 1; e--;
for (e--; (e >= s) && (*e == ' ' || *e == '\t'); e--);
} }
switch (*s) switch (*s) {
{ /* comment */
/* comment */ case '#':
case '#': s++;
s++; parser->cur_chunk.type = T_TYPE_COMMENT;
parser->cur_chunk.type = T_TYPE_COMMENT; break;
break;
/* include */ /* include */
case '+': case '+':
s++; s++;
parser->cur_chunk.type = T_TYPE_INCLUDE; parser->cur_chunk.type = T_TYPE_INCLUDE;
break; break;
/* translate */ /* translate */
case ':': case ':':
s++; s++;
parser->cur_chunk.type = T_TYPE_I18N; parser->cur_chunk.type = T_TYPE_I18N;
break; break;
/* translate raw */ /* translate raw */
case '_': case '_':
s++; s++;
parser->cur_chunk.type = T_TYPE_I18N_RAW; parser->cur_chunk.type = T_TYPE_I18N_RAW;
break; break;
/* expr */ /* expr */
case '=': case '=':
s++; s++;
parser->cur_chunk.type = T_TYPE_EXPR; parser->cur_chunk.type = T_TYPE_EXPR;
break; break;
/* code */ /* code */
default: default:
parser->cur_chunk.type = T_TYPE_CODE; parser->cur_chunk.type = T_TYPE_CODE;
break;
} }
parser->cur_chunk.line = parser->line; parser->cur_chunk.line = parser->line;
@ -206,142 +241,117 @@ static void template_code(struct template_parser *parser, const char *e)
parser->cur_chunk.e = e; parser->cur_chunk.e = e;
} }
static const char * static struct template_buffer * template_format_chunk(struct template_parser *parser)
template_format_chunk(struct template_parser *parser, size_t *sz)
{ {
const char *s, *p; const char *p;
const char *head, *tail; const char *head, *tail;
struct template_chunk *c = &parser->prv_chunk; struct template_chunk *c = &parser->prv_chunk;
struct template_buffer *buf;
*sz = 0; if (parser->strip_before && c->type == T_TYPE_TEXT) {
s = parser->gc = NULL; while ((c->e > c->s) && isspace(c->e[-1]))
if (parser->strip_before && c->type == T_TYPE_TEXT)
{
while ((c->e > c->s) && isspace(*(c->e - 1)))
c->e--; c->e--;
} }
/* empty chunk */ /* empty chunk */
if (c->s == c->e) if (c->type == T_TYPE_EOF)
{ return NULL;
if (c->type == T_TYPE_EOF)
{
*sz = 0;
s = NULL;
}
else
{
*sz = 1;
s = " ";
}
}
/* format chunk */ struct template_buffer *buf = buf_init(c->e - c->s);
else if ((buf = buf_init(c->e - c->s)) != NULL) if (!buf)
{ return NULL;
if (c->e > c->s) {
if ((head = gen_code[c->type][0]) != NULL) if ((head = gen_code[c->type][0]) != NULL)
buf_append(buf, head, strlen(head)); buf_append(buf, head, strlen(head));
switch (c->type) switch (c->type) {
{ case T_TYPE_TEXT:
case T_TYPE_TEXT: luastr_escape(buf, c->s, c->e - c->s, false);
luastr_escape(buf, c->s, c->e - c->s, 0); break;
break;
case T_TYPE_EXPR: case T_TYPE_EXPR:
buf_append(buf, c->s, c->e - c->s); buf_append(buf, c->s, c->e - c->s);
for (p = c->s; p < c->e; p++) for (p = c->s; p < c->e; p++)
parser->line += (*p == '\n'); parser->line += (*p == '\n');
break; break;
case T_TYPE_INCLUDE: case T_TYPE_INCLUDE:
luastr_escape(buf, c->s, c->e - c->s, 0); luastr_escape(buf, c->s, c->e - c->s, false);
break; break;
case T_TYPE_I18N: case T_TYPE_I18N:
luastr_translate(buf, c->s, c->e - c->s, 1); luastr_translate(buf, c->s, c->e - c->s, true);
break; break;
case T_TYPE_I18N_RAW: case T_TYPE_I18N_RAW:
luastr_translate(buf, c->s, c->e - c->s, 0); luastr_translate(buf, c->s, c->e - c->s, false);
break; break;
case T_TYPE_CODE: case T_TYPE_CODE:
buf_append(buf, c->s, c->e - c->s); buf_append(buf, c->s, c->e - c->s);
for (p = c->s; p < c->e; p++) for (p = c->s; p < c->e; p++)
parser->line += (*p == '\n'); parser->line += (*p == '\n');
break; break;
} }
if ((tail = gen_code[c->type][1]) != NULL) if ((tail = gen_code[c->type][1]) != NULL)
buf_append(buf, tail, strlen(tail)); buf_append(buf, tail, strlen(tail));
*sz = buf_length(buf);
s = parser->gc = buf_destroy(buf);
if (!*sz)
{
*sz = 1;
s = " ";
}
} }
return s; return buf;
} }
const char *template_reader(lua_State *L __attribute__((unused)), void *ud, size_t *sz) const char * template_reader(lua_State *L __attribute__((unused)), void *ud, size_t *sz)
{ {
struct template_parser *parser = ud; struct template_parser *parser = ud;
int rem = parser->size - (parser->off - parser->data);
char *tag;
parser->prv_chunk = parser->cur_chunk; /* free previous chunk */
free(parser->lua_chunk);
parser->lua_chunk = NULL;
/* free previous string */ while (true) {
if (parser->gc) int rem = parser->size - (parser->off - parser->data);
{ char *tag;
free(parser->gc);
parser->gc = NULL;
}
/* before tag */ parser->prv_chunk = parser->cur_chunk;
if (!parser->in_expr)
{ /* before tag */
if ((tag = memmem(parser->off, rem, "<%", 2)) != NULL) if (!parser->in_expr) {
{ if ((tag = memmem(parser->off, rem, "<%", 2)) != NULL) {
template_text(parser, tag); template_text(parser, tag);
parser->off = tag + 2; parser->off = tag + 2;
parser->in_expr = 1; parser->in_expr = 1;
} else {
template_text(parser, parser->data + parser->size);
parser->off = parser->data + parser->size;
}
} }
else
{ /* inside tag */
template_text(parser, parser->data + parser->size); else {
parser->off = parser->data + parser->size; if ((tag = memmem(parser->off, rem, "%>", 2)) != NULL) {
template_code(parser, tag);
parser->off = tag + 2;
parser->in_expr = 0;
} else {
/* unexpected EOF */
template_code(parser, parser->data + parser->size);
*sz = 1;
return "\033";
}
}
struct template_buffer *buf = template_format_chunk(parser);
if (!buf)
return NULL;
*sz = buf_length(buf);
if (*sz) {
parser->lua_chunk = buf_destroy(buf);
return parser->lua_chunk;
} }
} }
/* inside tag */
else
{
if ((tag = memmem(parser->off, rem, "%>", 2)) != NULL)
{
template_code(parser, tag);
parser->off = tag + 2;
parser->in_expr = 0;
}
else
{
/* unexpected EOF */
template_code(parser, parser->data + parser->size);
*sz = 1;
return "\033";
}
}
return template_format_chunk(parser, sz);
} }
int template_error(lua_State *L, struct template_parser *parser) int template_error(lua_State *L, struct template_parser *parser)
@ -353,33 +363,30 @@ int template_error(lua_State *L, struct template_parser *parser)
int line = 0; int line = 0;
int chunkline = 0; int chunkline = 0;
if ((ptr = memmem(err, strlen(err), "]:", 2)) != NULL) if ((ptr = memmem(err, strlen(err), "]:", 2)) != NULL) {
{
chunkline = atoi(ptr + 2) - parser->prv_chunk.line; chunkline = atoi(ptr + 2) - parser->prv_chunk.line;
while (*ptr) while (*ptr) {
{ if (*ptr++ == ' ') {
if (*ptr++ == ' ')
{
err = ptr; err = ptr;
break; break;
} }
} }
} }
if (memmem(err, strlen(err), "'char(27)'", 10) != NULL) if (memmem(err, strlen(err), "'char(27)'", 10) != NULL) {
{
off = parser->data + parser->size; off = parser->data + parser->size;
err = "'%>' expected before end of file"; err = "'%>' expected before end of file";
chunkline = 0; chunkline = 0;
} }
for (ptr = parser->data; ptr < off; ptr++) for (ptr = parser->data; ptr < off; ptr++) {
if (*ptr == '\n') if (*ptr == '\n')
line++; line++;
}
snprintf(msg, sizeof(msg), "Syntax error in %s:%d: %s", snprintf(msg, sizeof(msg), "Syntax error in %s:%d: %s",
parser->file ? parser->file : "[string]", line + chunkline, err ? err : "(unknown error)"); parser->file ?: "[string]", line + chunkline, err ?: "(unknown error)");
lua_pushnil(L); lua_pushnil(L);
lua_pushinteger(L, line + chunkline); lua_pushinteger(L, line + chunkline);

View File

@ -20,59 +20,14 @@
#ifndef _TEMPLATE_PARSER_H_ #ifndef _TEMPLATE_PARSER_H_
#define _TEMPLATE_PARSER_H_ #define _TEMPLATE_PARSER_H_
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <lua.h> #include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
/* code types */ struct template_parser;
#define T_TYPE_INIT 0
#define T_TYPE_TEXT 1
#define T_TYPE_COMMENT 2
#define T_TYPE_EXPR 3
#define T_TYPE_INCLUDE 4
#define T_TYPE_I18N 5
#define T_TYPE_I18N_RAW 6
#define T_TYPE_CODE 7
#define T_TYPE_EOF 8
struct template_chunk {
const char *s;
const char *e;
int type;
int line;
};
/* parser state */
struct template_parser {
int fd;
uint32_t size;
char *data;
char *off;
char *gc;
int line;
int in_expr;
int strip_before;
int strip_after;
struct template_chunk prv_chunk;
struct template_chunk cur_chunk;
const char *file;
};
struct template_parser * template_open(const char *file); struct template_parser * template_open(const char *file);
struct template_parser * template_string(const char *str, uint32_t len); struct template_parser * template_string(const char *str, size_t len);
void template_close(struct template_parser *parser); void template_close(struct template_parser *parser);
const char *template_reader(lua_State *L, void *ud, size_t *sz); const char *template_reader(lua_State *L, void *ud, size_t *sz);

View File

@ -27,19 +27,15 @@
/* initialize a buffer object */ /* initialize a buffer object */
struct template_buffer * buf_init(size_t size) struct template_buffer * buf_init(size_t size)
{ {
if (size < 1024)
size = 1024;
struct template_buffer *buf = malloc(sizeof(*buf)); struct template_buffer *buf = malloc(sizeof(*buf));
if (buf != NULL) { if (buf != NULL) {
buf->size = size; buf->size = size;
buf->data = malloc(buf->size); buf->data = malloc(buf->size);
buf->dptr = buf->data;
if (buf->data != NULL) { if (buf->data != NULL || size == 0)
buf->dptr = buf->data;
return buf; return buf;
}
free(buf); free(buf);
} }