Home | History | Annotate | Line # | Download | only in src
      1 /*	$NetBSD: tables.c,v 1.3 2017/01/02 17:45:27 christos Exp $	*/
      2 
      3 /*  tables.c - tables serialization code
      4  *
      5  *  Copyright (c) 1990 The Regents of the University of California.
      6  *  All rights reserved.
      7  *
      8  *  This code is derived from software contributed to Berkeley by
      9  *  Vern Paxson.
     10  *
     11  *  The United States Government has rights in this work pursuant
     12  *  to contract no. DE-AC03-76SF00098 between the United States
     13  *  Department of Energy and the University of California.
     14  *
     15  *  This file is part of flex.
     16  *
     17  *  Redistribution and use in source and binary forms, with or without
     18  *  modification, are permitted provided that the following conditions
     19  *  are met:
     20  *
     21  *  1. Redistributions of source code must retain the above copyright
     22  *     notice, this list of conditions and the following disclaimer.
     23  *  2. Redistributions in binary form must reproduce the above copyright
     24  *     notice, this list of conditions and the following disclaimer in the
     25  *     documentation and/or other materials provided with the distribution.
     26  *
     27  *  Neither the name of the University nor the names of its contributors
     28  *  may be used to endorse or promote products derived from this software
     29  *  without specific prior written permission.
     30  *
     31  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     32  *  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     33  *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     34  *  PURPOSE.
     35  */
     36 #include "flexdef.h"
     37 __RCSID("$NetBSD: tables.c,v 1.3 2017/01/02 17:45:27 christos Exp $");
     38 
     39 
     41 #include "tables.h"
     42 
     43 /** Convert size_t to t_flag.
     44  *  @param n in {1,2,4}
     45  *  @return YYTD_DATA*.
     46  */
     47 #define BYTES2TFLAG(n)\
     48     (((n) == sizeof(flex_int8_t))\
     49         ? YYTD_DATA8\
     50         :(((n)== sizeof(flex_int16_t))\
     51             ? YYTD_DATA16\
     52             : YYTD_DATA32))
     53 
     54 /** Clear YYTD_DATA* bit flags
     55  * @return the flag with the YYTD_DATA* bits cleared
     56  */
     57 #define TFLAGS_CLRDATA(flg) ((flg) & ~(YYTD_DATA8 | YYTD_DATA16 | YYTD_DATA32))
     58 
     59 int     yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v);
     60 int     yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v);
     61 int     yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v);
     62 int     yytbl_writen (struct yytbl_writer *wr, void *v, int len);
     63 static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i);
     64 /* XXX Not used
     65 static flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i,
     66 				  int j, int k);
     67  */
     68 
     69 
     70 /** Initialize the table writer.
     71  *  @param wr an uninitialized writer
     72  *  @param out the output file
     73  *  @return 0 on success
     74  */
     75 int yytbl_writer_init (struct yytbl_writer *wr, FILE * out)
     76 {
     77 	wr->out = out;
     78 	wr->total_written = 0;
     79 	return 0;
     80 }
     81 
     82 /** Initialize a table header.
     83  *  @param th  The uninitialized structure
     84  *  @param version_str the  version string
     85  *  @param name the name of this table set
     86  */
     87 int yytbl_hdr_init (struct yytbl_hdr *th, const char *version_str,
     88 		    const char *name)
     89 {
     90 	memset (th, 0, sizeof (struct yytbl_hdr));
     91 
     92 	th->th_magic = YYTBL_MAGIC;
     93 	th->th_hsize = (flex_uint32_t) (14 + strlen (version_str) + 1 + strlen (name) + 1);
     94 	th->th_hsize += yypad64 (th->th_hsize);
     95 	th->th_ssize = 0;	// Not known at this point.
     96 	th->th_flags = 0;
     97 	th->th_version = xstrdup(version_str);
     98 	th->th_name = xstrdup(name);
     99 	return 0;
    100 }
    101 
    102 /** Allocate and initialize a table data structure.
    103  *  @param td a pointer to an uninitialized table
    104  *  @param id  the table identifier
    105  *  @return 0 on success
    106  */
    107 int yytbl_data_init (struct yytbl_data *td, enum yytbl_id id)
    108 {
    109 
    110 	memset (td, 0, sizeof (struct yytbl_data));
    111 	td->td_id = id;
    112 	td->td_flags = YYTD_DATA32;
    113 	return 0;
    114 }
    115 
    116 /** Clean up table and data array.
    117  *  @param td will be destroyed
    118  *  @return 0 on success
    119  */
    120 int yytbl_data_destroy (struct yytbl_data *td)
    121 {
    122 	free(td->td_data);
    123 	td->td_data = 0;
    124 	free (td);
    125 	return 0;
    126 }
    127 
    128 /** Write enough padding to bring the file pointer to a 64-bit boundary. */
    129 static int yytbl_write_pad64 (struct yytbl_writer *wr)
    130 {
    131 	int     pad, bwritten = 0;
    132 
    133 	pad = yypad64 (wr->total_written);
    134 	while (pad-- > 0)
    135 		if (yytbl_write8 (wr, 0) < 0)
    136 			return -1;
    137 		else
    138 			bwritten++;
    139 	return bwritten;
    140 }
    141 
    142 /** write the header.
    143  *  @param wr the output stream
    144  *  @param th table header to be written
    145  *  @return -1 on error, or bytes written on success.
    146  */
    147 int yytbl_hdr_fwrite (struct yytbl_writer *wr, const struct yytbl_hdr *th)
    148 {
    149 	int  sz, rv;
    150 	int     bwritten = 0;
    151 
    152 	if (yytbl_write32 (wr, th->th_magic) < 0
    153 	    || yytbl_write32 (wr, th->th_hsize) < 0)
    154 		flex_die (_("th_magic|th_hsize write32 failed"));
    155 	bwritten += 8;
    156 
    157 	if (fgetpos (wr->out, &(wr->th_ssize_pos)) != 0)
    158 		flex_die (_("fgetpos failed"));
    159 
    160 	if (yytbl_write32 (wr, th->th_ssize) < 0
    161 	    || yytbl_write16 (wr, th->th_flags) < 0)
    162 		flex_die (_("th_ssize|th_flags write failed"));
    163 	bwritten += 6;
    164 
    165 	sz = (int) strlen (th->th_version) + 1;
    166 	if ((rv = yytbl_writen (wr, th->th_version, sz)) != sz)
    167 		flex_die (_("th_version writen failed"));
    168 	bwritten += rv;
    169 
    170 	sz = (int) strlen (th->th_name) + 1;
    171 	if ((rv = yytbl_writen (wr, th->th_name, sz)) != sz)
    172 		flex_die (_("th_name writen failed"));
    173 	bwritten += rv;
    174 
    175 	/* add padding */
    176 	if ((rv = yytbl_write_pad64 (wr)) < 0)
    177 		flex_die (_("pad64 failed"));
    178 	bwritten += rv;
    179 
    180 	/* Sanity check */
    181 	if (bwritten != (int) th->th_hsize)
    182 		flex_die (_("pad64 failed"));
    183 
    184 	return bwritten;
    185 }
    186 
    187 
    188 /** Write this table.
    189  *  @param wr the file writer
    190  *  @param td table data to be written
    191  *  @return -1 on error, or bytes written on success.
    192  */
    193 int yytbl_data_fwrite (struct yytbl_writer *wr, struct yytbl_data *td)
    194 {
    195 	int  rv;
    196 	flex_int32_t bwritten = 0;
    197 	flex_int32_t i, total_len;
    198 	fpos_t  pos;
    199 
    200 	if ((rv = yytbl_write16 (wr, td->td_id)) < 0)
    201 		return -1;
    202 	bwritten += rv;
    203 
    204 	if ((rv = yytbl_write16 (wr, td->td_flags)) < 0)
    205 		return -1;
    206 	bwritten += rv;
    207 
    208 	if ((rv = yytbl_write32 (wr, td->td_hilen)) < 0)
    209 		return -1;
    210 	bwritten += rv;
    211 
    212 	if ((rv = yytbl_write32 (wr, td->td_lolen)) < 0)
    213 		return -1;
    214 	bwritten += rv;
    215 
    216 	total_len = yytbl_calc_total_len (td);
    217 	for (i = 0; i < total_len; i++) {
    218 		switch (YYTDFLAGS2BYTES (td->td_flags)) {
    219 		case sizeof (flex_int8_t):
    220 			rv = yytbl_write8 (wr, (flex_uint8_t) yytbl_data_geti (td, i));
    221 			break;
    222 		case sizeof (flex_int16_t):
    223 			rv = yytbl_write16 (wr, (flex_uint16_t) yytbl_data_geti (td, i));
    224 			break;
    225 		case sizeof (flex_int32_t):
    226 			rv = yytbl_write32 (wr, (flex_uint32_t) yytbl_data_geti (td, i));
    227 			break;
    228 		default:
    229 			flex_die (_("invalid td_flags detected"));
    230 		}
    231 		if (rv < 0) {
    232 			flex_die (_("error while writing tables"));
    233 			return -1;
    234 		}
    235 		bwritten += rv;
    236 	}
    237 
    238 	/* Sanity check */
    239 	if (bwritten != (12 + total_len * (int) YYTDFLAGS2BYTES (td->td_flags))) {
    240 		flex_die (_("insanity detected"));
    241 		return -1;
    242 	}
    243 
    244 	/* add padding */
    245 	if ((rv = yytbl_write_pad64 (wr)) < 0) {
    246 		flex_die (_("pad64 failed"));
    247 		return -1;
    248 	}
    249 	bwritten += rv;
    250 
    251 	/* Now go back and update the th_hsize member */
    252 	if (fgetpos (wr->out, &pos) != 0
    253 	    || fsetpos (wr->out, &(wr->th_ssize_pos)) != 0
    254 	    || yytbl_write32 (wr, (flex_uint32_t) wr->total_written) < 0
    255 	    || fsetpos (wr->out, &pos)) {
    256 		flex_die (_("get|set|fwrite32 failed"));
    257 		return -1;
    258 	}
    259 	else
    260 		/* Don't count the int we just wrote. */
    261 		wr->total_written -= (int) sizeof (flex_int32_t);
    262 	return bwritten;
    263 }
    264 
    265 /** Write n bytes.
    266  *  @param  wr   the table writer
    267  *  @param  v    data to be written
    268  *  @param  len  number of bytes
    269  *  @return  -1 on error. number of bytes written on success.
    270  */
    271 int yytbl_writen (struct yytbl_writer *wr, void *v, int len)
    272 {
    273 	int  rv;
    274 
    275 	rv = (int) fwrite (v, 1, (size_t) len, wr->out);
    276 	if (rv != len)
    277 		return -1;
    278 	wr->total_written += len;
    279 	return len;
    280 }
    281 
    282 /** Write four bytes in network byte order
    283  *  @param  wr  the table writer
    284  *  @param  v    a dword in host byte order
    285  *  @return  -1 on error. number of bytes written on success.
    286  */
    287 int yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v)
    288 {
    289 	flex_uint32_t vnet;
    290 	int  bytes, rv;
    291 
    292 	vnet = htonl (v);
    293 	bytes = (int) sizeof (flex_uint32_t);
    294 	rv = (int) fwrite (&vnet, (size_t) bytes, 1, wr->out);
    295 	if (rv != 1)
    296 		return -1;
    297 	wr->total_written += bytes;
    298 	return bytes;
    299 }
    300 
    301 /** Write two bytes in network byte order.
    302  *  @param  wr  the table writer
    303  *  @param  v    a word in host byte order
    304  *  @return  -1 on error. number of bytes written on success.
    305  */
    306 int yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v)
    307 {
    308 	flex_uint16_t vnet;
    309 	int  bytes, rv;
    310 
    311 	vnet = htons (v);
    312 	bytes = (int) sizeof (flex_uint16_t);
    313 	rv = (int) fwrite (&vnet, (size_t) bytes, 1, wr->out);
    314 	if (rv != 1)
    315 		return -1;
    316 	wr->total_written += bytes;
    317 	return bytes;
    318 }
    319 
    320 /** Write a byte.
    321  *  @param  wr  the table writer
    322  *  @param  v    the value to be written
    323  *  @return  -1 on error. number of bytes written on success.
    324  */
    325 int yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v)
    326 {
    327 	int  bytes, rv;
    328 
    329 	bytes = (int) sizeof (flex_uint8_t);
    330 	rv = (int) fwrite (&v, (size_t) bytes, 1, wr->out);
    331 	if (rv != 1)
    332 		return -1;
    333 	wr->total_written += bytes;
    334 	return bytes;
    335 }
    336 
    337 
    338 /* XXX Not Used */
    339 #if 0
    340 /** Extract data element [i][j] from array data tables.
    341  * @param tbl data table
    342  * @param i index into higher dimension array. i should be zero for one-dimensional arrays.
    343  * @param j index into lower dimension array.
    344  * @param k index into struct, must be 0 or 1. Only valid for YYTD_ID_TRANSITION table
    345  * @return data[i][j + k]
    346  */
    347 static flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i,
    348 				  int j, int k)
    349 {
    350 	flex_int32_t lo;
    351 
    352 	k %= 2;
    353 	lo = tbl->td_lolen;
    354 
    355 	switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
    356 	case sizeof (flex_int8_t):
    357 		return ((flex_int8_t *) (tbl->td_data))[(i * lo + j) * (k + 1) +
    358 						   k];
    359 	case sizeof (flex_int16_t):
    360 		return ((flex_int16_t *) (tbl->td_data))[(i * lo + j) * (k +
    361 								    1) +
    362 						    k];
    363 	case sizeof (flex_int32_t):
    364 		return ((flex_int32_t *) (tbl->td_data))[(i * lo + j) * (k +
    365 								    1) +
    366 						    k];
    367 	default:
    368 		flex_die (_("invalid td_flags detected"));
    369 		break;
    370 	}
    371 
    372 	return 0;
    373 }
    374 #endif /* Not used */
    375 
    376 /** Extract data element [i] from array data tables treated as a single flat array of integers.
    377  * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
    378  * of structs.
    379  * @param tbl data table
    380  * @param i index into array.
    381  * @return data[i]
    382  */
    383 static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i)
    384 {
    385 
    386 	switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
    387 	case sizeof (flex_int8_t):
    388 		return ((flex_int8_t *) (tbl->td_data))[i];
    389 	case sizeof (flex_int16_t):
    390 		return ((flex_int16_t *) (tbl->td_data))[i];
    391 	case sizeof (flex_int32_t):
    392 		return ((flex_int32_t *) (tbl->td_data))[i];
    393 	default:
    394 		flex_die (_("invalid td_flags detected"));
    395 		break;
    396 	}
    397 	return 0;
    398 }
    399 
    400 /** Set data element [i] in array data tables treated as a single flat array of integers.
    401  * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
    402  * of structs.
    403  * @param tbl data table
    404  * @param i index into array.
    405  * @param newval new value for data[i]
    406  */
    407 static void yytbl_data_seti (const struct yytbl_data *tbl, int i,
    408 			     flex_int32_t newval)
    409 {
    410 
    411 	switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
    412 	case sizeof (flex_int8_t):
    413 		((flex_int8_t *) (tbl->td_data))[i] = (flex_int8_t) newval;
    414 		break;
    415 	case sizeof (flex_int16_t):
    416 		((flex_int16_t *) (tbl->td_data))[i] = (flex_int16_t) newval;
    417 		break;
    418 	case sizeof (flex_int32_t):
    419 		((flex_int32_t *) (tbl->td_data))[i] = (flex_int32_t) newval;
    420 		break;
    421 	default:
    422 		flex_die (_("invalid td_flags detected"));
    423 		break;
    424 	}
    425 }
    426 
    427 /** Calculate the number of bytes  needed to hold the largest
    428  *  absolute value in this data array.
    429  *  @param tbl  the data table
    430  *  @return sizeof(n) where n in {flex_int8_t, flex_int16_t, flex_int32_t}
    431  */
    432 static size_t min_int_size (struct yytbl_data *tbl)
    433 {
    434 	flex_int32_t i, total_len;
    435 	flex_int32_t max = 0;
    436 
    437 	total_len = yytbl_calc_total_len (tbl);
    438 
    439 	for (i = 0; i < total_len; i++) {
    440 		flex_int32_t n;
    441 
    442 		n = abs (yytbl_data_geti (tbl, i));
    443 
    444 		if (max < n)
    445 			max = n;
    446 	}
    447 
    448 	if (max <= INT8_MAX)
    449 		return sizeof (flex_int8_t);
    450 	else if (max <= INT16_MAX)
    451 		return sizeof (flex_int16_t);
    452 	else
    453 		return sizeof (flex_int32_t);
    454 }
    455 
    456 /** Transform data to smallest possible of (int32, int16, int8).
    457  * For example, we may have generated an int32 array due to user options
    458  * (e.g., %option align), but if the maximum value in that array
    459  * is 80 (for example), then we can serialize it with only 1 byte per int.
    460  * This is NOT the same as compressed DFA tables. We're just trying
    461  * to save storage space here.
    462  *
    463  * @param tbl the table to be compressed
    464  */
    465 void yytbl_data_compress (struct yytbl_data *tbl)
    466 {
    467 	flex_int32_t i, total_len;
    468 	size_t newsz;
    469 	struct yytbl_data newtbl;
    470 
    471 	yytbl_data_init (&newtbl, tbl->td_id);
    472 	newtbl.td_hilen = tbl->td_hilen;
    473 	newtbl.td_lolen = tbl->td_lolen;
    474 	newtbl.td_flags = tbl->td_flags;
    475 
    476 	newsz = min_int_size (tbl);
    477 
    478 
    479 	if (newsz == YYTDFLAGS2BYTES (tbl->td_flags))
    480 		/* No change in this table needed. */
    481 		return;
    482 
    483 	if (newsz > YYTDFLAGS2BYTES (tbl->td_flags)) {
    484 		flex_die (_("detected negative compression"));
    485 		return;
    486 	}
    487 
    488 	total_len = yytbl_calc_total_len (tbl);
    489 	newtbl.td_data = calloc ((size_t) total_len, newsz);
    490 	newtbl.td_flags = (flex_uint16_t)
    491 		(TFLAGS_CLRDATA (newtbl.td_flags) | BYTES2TFLAG (newsz));
    492 
    493 	for (i = 0; i < total_len; i++) {
    494 		flex_int32_t g;
    495 
    496 		g = yytbl_data_geti (tbl, i);
    497 		yytbl_data_seti (&newtbl, i, g);
    498 	}
    499 
    500 
    501 	/* Now copy over the old table */
    502 	free (tbl->td_data);
    503 	*tbl = newtbl;
    504 }
    505 
    506 /* vim:set noexpandtab cindent tabstop=8 softtabstop=0 shiftwidth=8 textwidth=0: */
    507