1*8880fbfeStedu /* $OpenBSD: buf.c,v 1.7 2015/11/20 18:54:49 tedu Exp $ */
2a58c1ecbStedu
3a58c1ecbStedu /* flex - tool to generate fast lexical analyzers */
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. */
351017a5bdStedu
361017a5bdStedu
37a58c1ecbStedu #include "flexdef.h"
38a58c1ecbStedu
39a58c1ecbStedu /* Take note: The buffer object is sometimes used as a String buffer (one
40a58c1ecbStedu * continuous string), and sometimes used as a list of strings, usually line by
41a58c1ecbStedu * line.
42a58c1ecbStedu *
43a58c1ecbStedu * The type is specified in buf_init by the elt_size. If the elt_size is
44a58c1ecbStedu * sizeof(char), then the buffer should be treated as string buffer. If the
45a58c1ecbStedu * elt_size is sizeof(char*), then the buffer should be treated as a list of
46a58c1ecbStedu * strings.
47a58c1ecbStedu *
48a58c1ecbStedu * Certain functions are only appropriate for one type or the other.
49a58c1ecbStedu */
50a58c1ecbStedu
51a58c1ecbStedu /* global buffers. */
52a58c1ecbStedu struct Buf userdef_buf; /**< for user #definitions triggered by cmd-line. */
53a58c1ecbStedu struct Buf defs_buf; /**< for #define's autogenerated. List of strings. */
54a58c1ecbStedu struct Buf yydmap_buf; /**< string buffer to hold yydmap elements */
55a58c1ecbStedu struct Buf m4defs_buf; /**< m4 definitions. List of strings. */
56a58c1ecbStedu struct Buf top_buf; /**< contains %top code. String buffer. */
57a58c1ecbStedu
581017a5bdStedu struct Buf *
buf_print_strings(struct Buf * buf,FILE * out)591017a5bdStedu buf_print_strings(struct Buf * buf, FILE * out)
60a58c1ecbStedu {
61a58c1ecbStedu int i;
62a58c1ecbStedu
63a58c1ecbStedu if (!buf || !out)
64a58c1ecbStedu return buf;
65a58c1ecbStedu
66a58c1ecbStedu for (i = 0; i < buf->nelts; i++) {
67a58c1ecbStedu const char *s = ((char **) buf->elts)[i];
68a58c1ecbStedu if (s)
69a58c1ecbStedu fprintf(out, "%s", s);
70a58c1ecbStedu }
71a58c1ecbStedu return buf;
72a58c1ecbStedu }
73a58c1ecbStedu
74a58c1ecbStedu /* Append a "%s" formatted string to a string buffer */
751017a5bdStedu struct Buf *
buf_prints(struct Buf * buf,const char * fmt,const char * s)761017a5bdStedu buf_prints(struct Buf * buf, const char *fmt, const char *s)
77a58c1ecbStedu {
78a58c1ecbStedu char *t;
79a58c1ecbStedu size_t tsz;
80a58c1ecbStedu
8187c89001Stedu tsz = strlen(fmt) + strlen(s) + 1;
8287c89001Stedu t = malloc(tsz);
83a58c1ecbStedu if (!t)
84a58c1ecbStedu flexfatal(_("Allocation of buffer to print string failed"));
85a58c1ecbStedu snprintf(t, tsz, fmt, s);
86a58c1ecbStedu buf = buf_strappend(buf, t);
874c01f208Stedu free(t);
88a58c1ecbStedu return buf;
89a58c1ecbStedu }
90a58c1ecbStedu
91a58c1ecbStedu /** Append a line directive to the string buffer.
92a58c1ecbStedu * @param buf A string buffer.
93a58c1ecbStedu * @param filename file name
94a58c1ecbStedu * @param lineno line number
95a58c1ecbStedu * @return buf
96a58c1ecbStedu */
971017a5bdStedu struct Buf *
buf_linedir(struct Buf * buf,const char * filename,int lineno)981017a5bdStedu buf_linedir(struct Buf * buf, const char *filename, int lineno)
99a58c1ecbStedu {
100a58c1ecbStedu const char *src;
101a58c1ecbStedu char *dst, *t;
102a58c1ecbStedu size_t tsz;
103a58c1ecbStedu
10487c89001Stedu tsz = strlen("#line \"\"\n") + /* constant parts */
10587c89001Stedu 2 * strlen(filename) + /* filename with possibly all backslashes escaped */
106a58c1ecbStedu (int) (1 + log10(abs(lineno))) + /* line number */
10787c89001Stedu 1; /* NUL */
10887c89001Stedu t = malloc(tsz);
109a58c1ecbStedu if (!t)
110a58c1ecbStedu flexfatal(_("Allocation of buffer for line directive failed"));
11187c89001Stedu dst = t + snprintf(t, tsz, "#line %d \"", lineno);
11287c89001Stedu for (src = filename; *src; *dst++ = *src++)
113a58c1ecbStedu if (*src == '\\') /* escape backslashes */
114a58c1ecbStedu *dst++ = '\\';
115a58c1ecbStedu *dst++ = '"';
116a58c1ecbStedu *dst++ = '\n';
117a58c1ecbStedu *dst = '\0';
118a58c1ecbStedu buf = buf_strappend(buf, t);
1194c01f208Stedu free(t);
120a58c1ecbStedu return buf;
121a58c1ecbStedu }
122a58c1ecbStedu
123a58c1ecbStedu
124a58c1ecbStedu /** Append the contents of @a src to @a dest.
125a58c1ecbStedu * @param @a dest the destination buffer
126a58c1ecbStedu * @param @a dest the source buffer
127a58c1ecbStedu * @return @a dest
128a58c1ecbStedu */
1291017a5bdStedu struct Buf *
buf_concat(struct Buf * dest,const struct Buf * src)1301017a5bdStedu buf_concat(struct Buf * dest, const struct Buf * src)
131a58c1ecbStedu {
132a58c1ecbStedu buf_append(dest, src->elts, src->nelts);
133a58c1ecbStedu return dest;
134a58c1ecbStedu }
135a58c1ecbStedu
136a58c1ecbStedu
137a58c1ecbStedu /* Appends n characters in str to buf. */
1381017a5bdStedu struct Buf *
buf_strnappend(struct Buf * buf,const char * str,int n)139*8880fbfeStedu buf_strnappend(struct Buf *buf, const char *str, int n)
140a58c1ecbStedu {
141a58c1ecbStedu buf_append(buf, str, n + 1);
142a58c1ecbStedu
143a58c1ecbStedu /* "undo" the '\0' character that buf_append() already copied. */
144a58c1ecbStedu buf->nelts--;
145a58c1ecbStedu
146a58c1ecbStedu return buf;
147a58c1ecbStedu }
148a58c1ecbStedu
149a58c1ecbStedu /* Appends characters in str to buf. */
1501017a5bdStedu struct Buf *
buf_strappend(struct Buf * buf,const char * str)151*8880fbfeStedu buf_strappend(struct Buf *buf, const char *str)
152a58c1ecbStedu {
153a58c1ecbStedu return buf_strnappend(buf, str, strlen(str));
154a58c1ecbStedu }
155a58c1ecbStedu
156a58c1ecbStedu /* appends "#define str def\n" */
1571017a5bdStedu struct Buf *
buf_strdefine(struct Buf * buf,const char * str,const char * def)158*8880fbfeStedu buf_strdefine(struct Buf *buf, const char *str, const char *def)
159a58c1ecbStedu {
160a58c1ecbStedu buf_strappend(buf, "#define ");
161a58c1ecbStedu buf_strappend(buf, " ");
162a58c1ecbStedu buf_strappend(buf, str);
163a58c1ecbStedu buf_strappend(buf, " ");
164a58c1ecbStedu buf_strappend(buf, def);
165a58c1ecbStedu buf_strappend(buf, "\n");
166a58c1ecbStedu return buf;
167a58c1ecbStedu }
168a58c1ecbStedu
169a58c1ecbStedu /** Pushes "m4_define( [[def]], [[val]])m4_dnl" to end of buffer.
170a58c1ecbStedu * @param buf A buffer as a list of strings.
171a58c1ecbStedu * @param def The m4 symbol to define.
172a58c1ecbStedu * @param val The definition; may be NULL.
173a58c1ecbStedu * @return buf
174a58c1ecbStedu */
1751017a5bdStedu struct Buf *
buf_m4_define(struct Buf * buf,const char * def,const char * val)1761017a5bdStedu buf_m4_define(struct Buf * buf, const char *def, const char *val)
177a58c1ecbStedu {
178a58c1ecbStedu const char *fmt = "m4_define( [[%s]], [[%s]])m4_dnl\n";
179a58c1ecbStedu char *str;
180a58c1ecbStedu size_t strsz;
181a58c1ecbStedu
182a58c1ecbStedu val = val ? val : "";
18387c89001Stedu strsz = strlen(fmt) + strlen(def) + strlen(val) + 2;
18487c89001Stedu str = malloc(strsz);
185a58c1ecbStedu if (!str)
186a58c1ecbStedu flexfatal(_("Allocation of buffer for m4 def failed"));
187a58c1ecbStedu
188a58c1ecbStedu snprintf(str, strsz, fmt, def, val);
189a58c1ecbStedu buf_append(buf, &str, 1);
190a58c1ecbStedu return buf;
191a58c1ecbStedu }
192a58c1ecbStedu
193a58c1ecbStedu /** Pushes "m4_undefine([[def]])m4_dnl" to end of buffer.
194a58c1ecbStedu * @param buf A buffer as a list of strings.
195a58c1ecbStedu * @param def The m4 symbol to undefine.
196a58c1ecbStedu * @return buf
197a58c1ecbStedu */
1981017a5bdStedu struct Buf *
buf_m4_undefine(struct Buf * buf,const char * def)1991017a5bdStedu buf_m4_undefine(struct Buf * buf, const char *def)
200a58c1ecbStedu {
201a58c1ecbStedu const char *fmt = "m4_undefine( [[%s]])m4_dnl\n";
202a58c1ecbStedu char *str;
203a58c1ecbStedu size_t strsz;
204a58c1ecbStedu
20587c89001Stedu strsz = strlen(fmt) + strlen(def) + 2;
20687c89001Stedu str = malloc(strsz);
207a58c1ecbStedu if (!str)
208a58c1ecbStedu flexfatal(_("Allocation of buffer for m4 undef failed"));
209a58c1ecbStedu
210a58c1ecbStedu snprintf(str, strsz, fmt, def);
211a58c1ecbStedu buf_append(buf, &str, 1);
212a58c1ecbStedu return buf;
213a58c1ecbStedu }
214a58c1ecbStedu
215a58c1ecbStedu /* create buf with 0 elements, each of size elem_size. */
2161017a5bdStedu void
buf_init(struct Buf * buf,size_t elem_size)217*8880fbfeStedu buf_init(struct Buf *buf, size_t elem_size)
218a58c1ecbStedu {
21909a27527Stedu buf->elts = NULL;
220a58c1ecbStedu buf->nelts = 0;
221a58c1ecbStedu buf->elt_size = elem_size;
222a58c1ecbStedu buf->nmax = 0;
223a58c1ecbStedu }
224a58c1ecbStedu
225a58c1ecbStedu /* frees memory */
2261017a5bdStedu void
buf_destroy(struct Buf * buf)227*8880fbfeStedu buf_destroy(struct Buf *buf)
228a58c1ecbStedu {
2294c01f208Stedu free(buf->elts);
23009a27527Stedu buf->elts = NULL;
231a58c1ecbStedu }
232a58c1ecbStedu
233a58c1ecbStedu
234a58c1ecbStedu /* appends ptr[] to buf, grow if necessary.
235a58c1ecbStedu * n_elem is number of elements in ptr[], NOT bytes.
236a58c1ecbStedu * returns buf.
237a58c1ecbStedu * We grow by mod(512) boundaries.
238a58c1ecbStedu */
239a58c1ecbStedu
2401017a5bdStedu struct Buf *
buf_append(struct Buf * buf,const void * ptr,int n_elem)241*8880fbfeStedu buf_append(struct Buf *buf, const void *ptr, int n_elem)
242a58c1ecbStedu {
243a58c1ecbStedu int n_alloc = 0;
244a58c1ecbStedu
245a58c1ecbStedu if (!ptr || n_elem == 0)
246a58c1ecbStedu return buf;
247a58c1ecbStedu
248a58c1ecbStedu /* May need to alloc more. */
249a58c1ecbStedu if (n_elem + buf->nelts > buf->nmax) {
250a58c1ecbStedu
251a58c1ecbStedu /* exact amount needed... */
252a58c1ecbStedu n_alloc = (n_elem + buf->nelts) * buf->elt_size;
253a58c1ecbStedu
254a58c1ecbStedu /* ...plus some extra */
255a58c1ecbStedu if (((n_alloc * buf->elt_size) % 512) != 0
256a58c1ecbStedu && buf->elt_size < 512)
257a58c1ecbStedu n_alloc +=
258a58c1ecbStedu (512 -
259a58c1ecbStedu ((n_alloc * buf->elt_size) % 512)) /
260a58c1ecbStedu buf->elt_size;
261a58c1ecbStedu
262a58c1ecbStedu if (!buf->elts)
263a58c1ecbStedu buf->elts =
264a58c1ecbStedu allocate_array(n_alloc, buf->elt_size);
265a58c1ecbStedu else
266a58c1ecbStedu buf->elts =
267a58c1ecbStedu reallocate_array(buf->elts, n_alloc,
268a58c1ecbStedu buf->elt_size);
269a58c1ecbStedu
270a58c1ecbStedu buf->nmax = n_alloc;
271a58c1ecbStedu }
272a58c1ecbStedu memcpy((char *) buf->elts + buf->nelts * buf->elt_size, ptr,
273a58c1ecbStedu n_elem * buf->elt_size);
274a58c1ecbStedu buf->nelts += n_elem;
275a58c1ecbStedu
276a58c1ecbStedu return buf;
277a58c1ecbStedu }
278