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