GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/lex/tables.c Lines: 4 151 2.6 %
Date: 2017-11-07 Branches: 0 94 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: tables.c,v 1.4 2017/08/17 19:27:09 tedu 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
37
38
#include "flexdef.h"
39
#include "tables.h"
40
41
/** Convert size_t to t_flag.
42
 *  @param n in {1,2,4}
43
 *  @return YYTD_DATA*.
44
 */
45
#define BYTES2TFLAG(n)\
46
    (((n) == sizeof(flex_int8_t))\
47
        ? YYTD_DATA8\
48
        :(((n)== sizeof(flex_int16_t))\
49
            ? YYTD_DATA16\
50
            : YYTD_DATA32))
51
52
/** Clear YYTD_DATA* bit flags
53
 * @return the flag with the YYTD_DATA* bits cleared
54
 */
55
#define TFLAGS_CLRDATA(flg) ((flg) & ~(YYTD_DATA8 | YYTD_DATA16 | YYTD_DATA32))
56
57
int     yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v);
58
int     yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v);
59
int     yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v);
60
int     yytbl_writen (struct yytbl_writer *wr, void *v, flex_int32_t len);
61
static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i);
62
63
/** Initialize the table writer.
64
 *  @param wr an uninitialized writer
65
 *  @param the output file
66
 *  @return 0 on success
67
 */
68
int yytbl_writer_init (struct yytbl_writer *wr, FILE * out)
69
{
70
	wr->out = out;
71
	wr->total_written = 0;
72
	return 0;
73
}
74
75
/** Initialize a table header.
76
 *  @param th  The uninitialized structure
77
 *  @param version_str the  version string
78
 *  @param name the name of this table set
79
 */
80
int yytbl_hdr_init (struct yytbl_hdr *th, const char *version_str,
81
		    const char *name)
82
{
83
	memset (th, 0, sizeof (struct yytbl_hdr));
84
85
	th->th_magic = YYTBL_MAGIC;
86
	th->th_hsize = 14 + strlen (version_str) + 1 + strlen (name) + 1;
87
	th->th_hsize += yypad64 (th->th_hsize);
88
	th->th_ssize = 0;	// Not known at this point.
89
	th->th_flags = 0;
90
	th->th_version = copy_string (version_str);
91
	th->th_name = copy_string (name);
92
	return 0;
93
}
94
95
/** Allocate and initialize a table data structure.
96
 *  @param tbl a pointer to an uninitialized table
97
 *  @param id  the table identifier
98
 *  @return 0 on success
99
 */
100
int yytbl_data_init (struct yytbl_data *td, enum yytbl_id id)
101
{
102
103
126
	memset (td, 0, sizeof (struct yytbl_data));
104
63
	td->td_id = id;
105
63
	td->td_flags = YYTD_DATA32;
106
63
	return 0;
107
}
108
109
/** Clean up table and data array.
110
 *  @param td will be destroyed
111
 *  @return 0 on success
112
 */
113
int yytbl_data_destroy (struct yytbl_data *td)
114
{
115
	free(td->td_data);
116
	td->td_data = 0;
117
	free (td);
118
	return 0;
119
}
120
121
/** Write enough padding to bring the file pointer to a 64-bit boundary. */
122
static int yytbl_write_pad64 (struct yytbl_writer *wr)
123
{
124
	int     pad, bwritten = 0;
125
126
	pad = yypad64 (wr->total_written);
127
	while (pad-- > 0)
128
		if (yytbl_write8 (wr, 0) < 0)
129
			return -1;
130
		else
131
			bwritten++;
132
	return bwritten;
133
}
134
135
/** write the header.
136
 *  @param out the output stream
137
 *  @param th table header to be written
138
 *  @return -1 on error, or bytes written on success.
139
 */
140
int yytbl_hdr_fwrite (struct yytbl_writer *wr, const struct yytbl_hdr *th)
141
{
142
	int  sz, rv;
143
	int     bwritten = 0;
144
145
	if (yytbl_write32 (wr, th->th_magic) < 0
146
	    || yytbl_write32 (wr, th->th_hsize) < 0)
147
		flex_die (_("th_magic|th_hsize write32 failed"));
148
	bwritten += 8;
149
150
	if (fgetpos (wr->out, &(wr->th_ssize_pos)) != 0)
151
		flex_die (_("fgetpos failed"));
152
153
	if (yytbl_write32 (wr, th->th_ssize) < 0
154
	    || yytbl_write16 (wr, th->th_flags) < 0)
155
		flex_die (_("th_ssize|th_flags write failed"));
156
	bwritten += 6;
157
158
	sz = strlen (th->th_version) + 1;
159
	if ((rv = yytbl_writen (wr, th->th_version, sz)) != sz)
160
		flex_die (_("th_version writen failed"));
161
	bwritten += rv;
162
163
	sz = strlen (th->th_name) + 1;
164
	if ((rv = yytbl_writen (wr, th->th_name, sz)) != sz)
165
		flex_die (_("th_name writen failed"));
166
	bwritten += rv;
167
168
	/* add padding */
169
	if ((rv = yytbl_write_pad64 (wr)) < 0)
170
		flex_die (_("pad64 failed"));
171
	bwritten += rv;
172
173
	/* Sanity check */
174
	if (bwritten != (int) th->th_hsize)
175
		flex_die (_("pad64 failed"));
176
177
	return bwritten;
178
}
179
180
181
/** Write this table.
182
 *  @param out the file writer
183
 *  @param td table data to be written
184
 *  @return -1 on error, or bytes written on success.
185
 */
186
int yytbl_data_fwrite (struct yytbl_writer *wr, struct yytbl_data *td)
187
{
188
	int  rv;
189
	flex_int32_t bwritten = 0;
190
	flex_int32_t i, total_len;
191
	fpos_t  pos;
192
193
	if ((rv = yytbl_write16 (wr, td->td_id)) < 0)
194
		return -1;
195
	bwritten += rv;
196
197
	if ((rv = yytbl_write16 (wr, td->td_flags)) < 0)
198
		return -1;
199
	bwritten += rv;
200
201
	if ((rv = yytbl_write32 (wr, td->td_hilen)) < 0)
202
		return -1;
203
	bwritten += rv;
204
205
	if ((rv = yytbl_write32 (wr, td->td_lolen)) < 0)
206
		return -1;
207
	bwritten += rv;
208
209
	total_len = yytbl_calc_total_len (td);
210
	for (i = 0; i < total_len; i++) {
211
		switch (YYTDFLAGS2BYTES (td->td_flags)) {
212
		case sizeof (flex_int8_t):
213
			rv = yytbl_write8 (wr, yytbl_data_geti (td, i));
214
			break;
215
		case sizeof (flex_int16_t):
216
			rv = yytbl_write16 (wr, yytbl_data_geti (td, i));
217
			break;
218
		case sizeof (flex_int32_t):
219
			rv = yytbl_write32 (wr, yytbl_data_geti (td, i));
220
			break;
221
		default:
222
			flex_die (_("invalid td_flags detected"));
223
		}
224
		if (rv < 0) {
225
			flex_die (_("error while writing tables"));
226
			return -1;
227
		}
228
		bwritten += rv;
229
	}
230
231
	/* Sanity check */
232
	if (bwritten != (int) (12 + total_len * YYTDFLAGS2BYTES (td->td_flags))) {
233
		flex_die (_("insanity detected"));
234
		return -1;
235
	}
236
237
	/* add padding */
238
	if ((rv = yytbl_write_pad64 (wr)) < 0) {
239
		flex_die (_("pad64 failed"));
240
		return -1;
241
	}
242
	bwritten += rv;
243
244
	/* Now go back and update the th_hsize member */
245
	if (fgetpos (wr->out, &pos) != 0
246
	    || fsetpos (wr->out, &(wr->th_ssize_pos)) != 0
247
	    || yytbl_write32 (wr, wr->total_written) < 0
248
	    || fsetpos (wr->out, &pos)) {
249
		flex_die (_("get|set|fwrite32 failed"));
250
		return -1;
251
	}
252
	else
253
		/* Don't count the int we just wrote. */
254
		wr->total_written -= sizeof (flex_int32_t);
255
	return bwritten;
256
}
257
258
/** Write n bytes.
259
 *  @param  wr   the table writer
260
 *  @param  v    data to be written
261
 *  @param  len  number of bytes
262
 *  @return  -1 on error. number of bytes written on success.
263
 */
264
int yytbl_writen (struct yytbl_writer *wr, void *v, flex_int32_t len)
265
{
266
	int  rv;
267
268
	rv = fwrite (v, 1, len, wr->out);
269
	if (rv != len)
270
		return -1;
271
	wr->total_written += len;
272
	return len;
273
}
274
275
/** Write four bytes in network byte order
276
 *  @param  wr  the table writer
277
 *  @param  v    a dword in host byte order
278
 *  @return  -1 on error. number of bytes written on success.
279
 */
280
int yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v)
281
{
282
	flex_uint32_t vnet;
283
	size_t  bytes, rv;
284
285
	vnet = htonl (v);
286
	bytes = sizeof (flex_uint32_t);
287
	rv = fwrite (&vnet, bytes, 1, wr->out);
288
	if (rv != 1)
289
		return -1;
290
	wr->total_written += bytes;
291
	return bytes;
292
}
293
294
/** Write two bytes in network byte order.
295
 *  @param  wr  the table writer
296
 *  @param  v    a word in host byte order
297
 *  @return  -1 on error. number of bytes written on success.
298
 */
299
int yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v)
300
{
301
	flex_uint16_t vnet;
302
	size_t  bytes, rv;
303
304
	vnet = htons (v);
305
	bytes = sizeof (flex_uint16_t);
306
	rv = fwrite (&vnet, bytes, 1, wr->out);
307
	if (rv != 1)
308
		return -1;
309
	wr->total_written += bytes;
310
	return bytes;
311
}
312
313
/** Write a byte.
314
 *  @param  wr  the table writer
315
 *  @param  v    the value to be written
316
 *  @return  -1 on error. number of bytes written on success.
317
 */
318
int yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v)
319
{
320
	size_t  bytes, rv;
321
322
	bytes = sizeof (flex_uint8_t);
323
	rv = fwrite (&v, bytes, 1, wr->out);
324
	if (rv != 1)
325
		return -1;
326
	wr->total_written += bytes;
327
	return bytes;
328
}
329
330
/** Extract data element [i] from array data tables treated as a single flat array of integers.
331
 * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
332
 * of structs.
333
 * @param tbl data table
334
 * @param i index into array.
335
 * @return data[i]
336
 */
337
static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i)
338
{
339
340
	switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
341
	case sizeof (flex_int8_t):
342
		return ((flex_int8_t *) (tbl->td_data))[i];
343
	case sizeof (flex_int16_t):
344
		return ((flex_int16_t *) (tbl->td_data))[i];
345
	case sizeof (flex_int32_t):
346
		return ((flex_int32_t *) (tbl->td_data))[i];
347
	default:
348
		flex_die (_("invalid td_flags detected"));
349
		break;
350
	}
351
	return 0;
352
}
353
354
/** Set data element [i] in array data tables treated as a single flat array of integers.
355
 * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
356
 * of structs.
357
 * @param tbl data table
358
 * @param i index into array.
359
 * @param newval new value for data[i]
360
 */
361
static void yytbl_data_seti (const struct yytbl_data *tbl, int i,
362
			     flex_int32_t newval)
363
{
364
365
	switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
366
	case sizeof (flex_int8_t):
367
		((flex_int8_t *) (tbl->td_data))[i] = (flex_int8_t) newval;
368
		break;
369
	case sizeof (flex_int16_t):
370
		((flex_int16_t *) (tbl->td_data))[i] = (flex_int16_t) newval;
371
		break;
372
	case sizeof (flex_int32_t):
373
		((flex_int32_t *) (tbl->td_data))[i] = (flex_int32_t) newval;
374
		break;
375
	default:
376
		flex_die (_("invalid td_flags detected"));
377
		break;
378
	}
379
}
380
381
/** Calculate the number of bytes  needed to hold the largest
382
 *  absolute value in this data array.
383
 *  @param tbl  the data table
384
 *  @return sizeof(n) where n in {flex_int8_t, flex_int16_t, flex_int32_t}
385
 */
386
static size_t min_int_size (struct yytbl_data *tbl)
387
{
388
	flex_uint32_t i, total_len;
389
	flex_int32_t max = 0;
390
391
	total_len = yytbl_calc_total_len (tbl);
392
393
	for (i = 0; i < total_len; i++) {
394
		flex_int32_t n;
395
396
		n = abs (yytbl_data_geti (tbl, i));
397
398
		if (n > max)
399
			max = n;
400
	}
401
402
	if (max <= INT8_MAX)
403
		return sizeof (flex_int8_t);
404
	else if (max <= INT16_MAX)
405
		return sizeof (flex_int16_t);
406
	else
407
		return sizeof (flex_int32_t);
408
}
409
410
/** Transform data to smallest possible of (int32, int16, int8).
411
 * For example, we may have generated an int32 array due to user options
412
 * (e.g., %option align), but if the maximum value in that array
413
 * is 80 (for example), then we can serialize it with only 1 byte per int.
414
 * This is NOT the same as compressed DFA tables. We're just trying
415
 * to save storage space here.
416
 *
417
 * @param tbl the table to be compressed
418
 */
419
void yytbl_data_compress (struct yytbl_data *tbl)
420
{
421
	flex_int32_t i, newsz, total_len;
422
	struct yytbl_data newtbl;
423
424
	yytbl_data_init (&newtbl, tbl->td_id);
425
	newtbl.td_hilen = tbl->td_hilen;
426
	newtbl.td_lolen = tbl->td_lolen;
427
	newtbl.td_flags = tbl->td_flags;
428
429
	newsz = min_int_size (tbl);
430
431
432
	if (newsz == (int) YYTDFLAGS2BYTES (tbl->td_flags))
433
		/* No change in this table needed. */
434
		return;
435
436
	if (newsz > (int) YYTDFLAGS2BYTES (tbl->td_flags)) {
437
		flex_die (_("detected negative compression"));
438
		return;
439
	}
440
441
	total_len = yytbl_calc_total_len (tbl);
442
	newtbl.td_data = calloc (total_len, newsz);
443
	newtbl.td_flags =
444
		TFLAGS_CLRDATA (newtbl.td_flags) | BYTES2TFLAG (newsz);
445
446
	for (i = 0; i < total_len; i++) {
447
		flex_int32_t g;
448
449
		g = yytbl_data_geti (tbl, i);
450
		yytbl_data_seti (&newtbl, i, g);
451
	}
452
453
454
	/* Now copy over the old table */
455
	free (tbl->td_data);
456
	*tbl = newtbl;
457
}