#include "flexdef.h"
#include "tables.h"
#define BYTES2TFLAG(n)\
(((n) == sizeof(flex_int8_t))\
? YYTD_DATA8\
:(((n)== sizeof(flex_int16_t))\
? YYTD_DATA16\
: YYTD_DATA32))
#define TFLAGS_CLRDATA(flg) ((flg) & ~(YYTD_DATA8 | YYTD_DATA16 | YYTD_DATA32))
int yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v);
int yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v);
int yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v);
int yytbl_writen (struct yytbl_writer *wr, void *v, flex_int32_t len);
static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i);
static flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i,
int j, int k);
int yytbl_writer_init (struct yytbl_writer *wr, FILE * out)
{
wr->out = out;
wr->total_written = 0;
return 0;
}
int yytbl_hdr_init (struct yytbl_hdr *th, const char *version_str,
const char *name)
{
memset (th, 0, sizeof (struct yytbl_hdr));
th->th_magic = YYTBL_MAGIC;
th->th_hsize = 14 + strlen (version_str) + 1 + strlen (name) + 1;
th->th_hsize += yypad64 (th->th_hsize);
th->th_ssize = 0; th->th_flags = 0;
th->th_version = copy_string (version_str);
th->th_name = copy_string (name);
return 0;
}
int yytbl_data_init (struct yytbl_data *td, enum yytbl_id id)
{
memset (td, 0, sizeof (struct yytbl_data));
td->td_id = id;
td->td_flags = YYTD_DATA32;
return 0;
}
int yytbl_data_destroy (struct yytbl_data *td)
{
if (td->td_data)
free (td->td_data);
td->td_data = 0;
free (td);
return 0;
}
static int yytbl_write_pad64 (struct yytbl_writer *wr)
{
int pad, bwritten = 0;
pad = yypad64 (wr->total_written);
while (pad-- > 0)
if (yytbl_write8 (wr, 0) < 0)
return -1;
else
bwritten++;
return bwritten;
}
int yytbl_hdr_fwrite (struct yytbl_writer *wr, const struct yytbl_hdr *th)
{
int sz, rv;
int bwritten = 0;
if (yytbl_write32 (wr, th->th_magic) < 0
|| yytbl_write32 (wr, th->th_hsize) < 0)
flex_die (_("th_magic|th_hsize write32 failed"));
bwritten += 8;
if (fgetpos (wr->out, &(wr->th_ssize_pos)) != 0)
flex_die (_("fgetpos failed"));
if (yytbl_write32 (wr, th->th_ssize) < 0
|| yytbl_write16 (wr, th->th_flags) < 0)
flex_die (_("th_ssize|th_flags write failed"));
bwritten += 6;
sz = strlen (th->th_version) + 1;
if ((rv = yytbl_writen (wr, th->th_version, sz)) != sz)
flex_die (_("th_version writen failed"));
bwritten += rv;
sz = strlen (th->th_name) + 1;
if ((rv = yytbl_writen (wr, th->th_name, sz)) != sz)
flex_die (_("th_name writen failed"));
bwritten += rv;
if ((rv = yytbl_write_pad64 (wr)) < 0)
flex_die (_("pad64 failed"));
bwritten += rv;
if (bwritten != (int) th->th_hsize)
flex_die (_("pad64 failed"));
return bwritten;
}
int yytbl_data_fwrite (struct yytbl_writer *wr, struct yytbl_data *td)
{
int rv;
flex_int32_t bwritten = 0;
flex_int32_t i, total_len;
fpos_t pos;
if ((rv = yytbl_write16 (wr, td->td_id)) < 0)
return -1;
bwritten += rv;
if ((rv = yytbl_write16 (wr, td->td_flags)) < 0)
return -1;
bwritten += rv;
if ((rv = yytbl_write32 (wr, td->td_hilen)) < 0)
return -1;
bwritten += rv;
if ((rv = yytbl_write32 (wr, td->td_lolen)) < 0)
return -1;
bwritten += rv;
total_len = yytbl_calc_total_len (td);
for (i = 0; i < total_len; i++) {
switch (YYTDFLAGS2BYTES (td->td_flags)) {
case sizeof (flex_int8_t):
rv = yytbl_write8 (wr, yytbl_data_geti (td, i));
break;
case sizeof (flex_int16_t):
rv = yytbl_write16 (wr, yytbl_data_geti (td, i));
break;
case sizeof (flex_int32_t):
rv = yytbl_write32 (wr, yytbl_data_geti (td, i));
break;
default:
flex_die (_("invalid td_flags detected"));
}
if (rv < 0) {
flex_die (_("error while writing tables"));
return -1;
}
bwritten += rv;
}
if (bwritten != (int) (12 + total_len * YYTDFLAGS2BYTES (td->td_flags))) {
flex_die (_("insanity detected"));
return -1;
}
if ((rv = yytbl_write_pad64 (wr)) < 0) {
flex_die (_("pad64 failed"));
return -1;
}
bwritten += rv;
if (fgetpos (wr->out, &pos) != 0
|| fsetpos (wr->out, &(wr->th_ssize_pos)) != 0
|| yytbl_write32 (wr, wr->total_written) < 0
|| fsetpos (wr->out, &pos)) {
flex_die (_("get|set|fwrite32 failed"));
return -1;
}
else
wr->total_written -= sizeof (flex_int32_t);
return bwritten;
}
int yytbl_writen (struct yytbl_writer *wr, void *v, flex_int32_t len)
{
int rv;
rv = fwrite (v, 1, len, wr->out);
if (rv != len)
return -1;
wr->total_written += len;
return len;
}
int yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v)
{
flex_uint32_t vnet;
size_t bytes, rv;
vnet = htonl (v);
bytes = sizeof (flex_uint32_t);
rv = fwrite (&vnet, bytes, 1, wr->out);
if (rv != 1)
return -1;
wr->total_written += bytes;
return bytes;
}
int yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v)
{
flex_uint16_t vnet;
size_t bytes, rv;
vnet = htons (v);
bytes = sizeof (flex_uint16_t);
rv = fwrite (&vnet, bytes, 1, wr->out);
if (rv != 1)
return -1;
wr->total_written += bytes;
return bytes;
}
int yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v)
{
size_t bytes, rv;
bytes = sizeof (flex_uint8_t);
rv = fwrite (&v, bytes, 1, wr->out);
if (rv != 1)
return -1;
wr->total_written += bytes;
return bytes;
}
static flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i,
int j, int k)
{
flex_int32_t lo;
k %= 2;
lo = tbl->td_lolen;
switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
case sizeof (flex_int8_t):
return ((flex_int8_t *) (tbl->td_data))[(i * lo + j) * (k + 1) +
k];
case sizeof (flex_int16_t):
return ((flex_int16_t *) (tbl->td_data))[(i * lo + j) * (k +
1) +
k];
case sizeof (flex_int32_t):
return ((flex_int32_t *) (tbl->td_data))[(i * lo + j) * (k +
1) +
k];
default:
flex_die (_("invalid td_flags detected"));
break;
}
return 0;
}
static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i)
{
switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
case sizeof (flex_int8_t):
return ((flex_int8_t *) (tbl->td_data))[i];
case sizeof (flex_int16_t):
return ((flex_int16_t *) (tbl->td_data))[i];
case sizeof (flex_int32_t):
return ((flex_int32_t *) (tbl->td_data))[i];
default:
flex_die (_("invalid td_flags detected"));
break;
}
return 0;
}
static void yytbl_data_seti (const struct yytbl_data *tbl, int i,
flex_int32_t newval)
{
switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
case sizeof (flex_int8_t):
((flex_int8_t *) (tbl->td_data))[i] = (flex_int8_t) newval;
break;
case sizeof (flex_int16_t):
((flex_int16_t *) (tbl->td_data))[i] = (flex_int16_t) newval;
break;
case sizeof (flex_int32_t):
((flex_int32_t *) (tbl->td_data))[i] = (flex_int32_t) newval;
break;
default:
flex_die (_("invalid td_flags detected"));
break;
}
}
static size_t min_int_size (struct yytbl_data *tbl)
{
flex_uint32_t i, total_len;
flex_int32_t max = 0;
total_len = yytbl_calc_total_len (tbl);
for (i = 0; i < total_len; i++) {
flex_int32_t n;
n = abs (yytbl_data_geti (tbl, i));
if (n > max)
max = n;
}
if (max <= INT8_MAX)
return sizeof (flex_int8_t);
else if (max <= INT16_MAX)
return sizeof (flex_int16_t);
else
return sizeof (flex_int32_t);
}
void yytbl_data_compress (struct yytbl_data *tbl)
{
flex_int32_t i, newsz, total_len;
struct yytbl_data newtbl;
yytbl_data_init (&newtbl, tbl->td_id);
newtbl.td_hilen = tbl->td_hilen;
newtbl.td_lolen = tbl->td_lolen;
newtbl.td_flags = tbl->td_flags;
newsz = min_int_size (tbl);
if (newsz == (int) YYTDFLAGS2BYTES (tbl->td_flags))
return;
if (newsz > (int) YYTDFLAGS2BYTES (tbl->td_flags)) {
flex_die (_("detected negative compression"));
return;
}
total_len = yytbl_calc_total_len (tbl);
newtbl.td_data = calloc (total_len, newsz);
newtbl.td_flags =
TFLAGS_CLRDATA (newtbl.td_flags) | BYTES2TFLAG (newsz);
for (i = 0; i < total_len; i++) {
flex_int32_t g;
g = yytbl_data_geti (tbl, i);
yytbl_data_seti (&newtbl, i, g);
}
free (tbl->td_data);
*tbl = newtbl;
}