1228072Sbapt/* flex - tool to generate fast lexical analyzers */
2228072Sbapt
3228072Sbapt/*  Copyright (c) 1990 The Regents of the University of California. */
4228072Sbapt/*  All rights reserved. */
5228072Sbapt
6228072Sbapt/*  This code is derived from software contributed to Berkeley by */
7228072Sbapt/*  Vern Paxson. */
8228072Sbapt
9228072Sbapt/*  The United States Government has rights in this work pursuant */
10228072Sbapt/*  to contract no. DE-AC03-76SF00098 between the United States */
11228072Sbapt/*  Department of Energy and the University of California. */
12228072Sbapt
13228072Sbapt/*  This file is part of flex. */
14228072Sbapt
15228072Sbapt/*  Redistribution and use in source and binary forms, with or without */
16228072Sbapt/*  modification, are permitted provided that the following conditions */
17228072Sbapt/*  are met: */
18228072Sbapt
19228072Sbapt/*  1. Redistributions of source code must retain the above copyright */
20228072Sbapt/*     notice, this list of conditions and the following disclaimer. */
21228072Sbapt/*  2. Redistributions in binary form must reproduce the above copyright */
22228072Sbapt/*     notice, this list of conditions and the following disclaimer in the */
23228072Sbapt/*     documentation and/or other materials provided with the distribution. */
24228072Sbapt
25228072Sbapt/*  Neither the name of the University nor the names of its contributors */
26228072Sbapt/*  may be used to endorse or promote products derived from this software */
27228072Sbapt/*  without specific prior written permission. */
28228072Sbapt
29228072Sbapt/*  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */
30228072Sbapt/*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
31228072Sbapt/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
32228072Sbapt/*  PURPOSE. */
33228072Sbapt
34228072Sbapt#include "flexdef.h"
35228072Sbapt
36228072Sbapt/* Take note: The buffer object is sometimes used as a String buffer (one
37228072Sbapt * continuous string), and sometimes used as a list of strings, usually line by
38228072Sbapt * line.
39228072Sbapt *
40228072Sbapt * The type is specified in buf_init by the elt_size. If the elt_size is
41228072Sbapt * sizeof(char), then the buffer should be treated as string buffer. If the
42228072Sbapt * elt_size is sizeof(char*), then the buffer should be treated as a list of
43228072Sbapt * strings.
44228072Sbapt *
45228072Sbapt * Certain functions are only appropriate for one type or the other.
46228072Sbapt */
47228072Sbapt
48228072Sbapt/* global buffers. */
49228072Sbaptstruct Buf userdef_buf;		/**< for user #definitions triggered by cmd-line. */
50228072Sbaptstruct Buf defs_buf;		/**< for #define's autogenerated. List of strings. */
51228072Sbaptstruct Buf yydmap_buf;		/**< string buffer to hold yydmap elements */
52228072Sbaptstruct Buf m4defs_buf;          /**< m4 definitions. List of strings. */
53228072Sbaptstruct Buf top_buf;             /**< contains %top code. String buffer. */
54228072Sbapt
55228072Sbaptstruct Buf *buf_print_strings(struct Buf * buf, FILE* out)
56228072Sbapt{
57228072Sbapt    int i;
58228072Sbapt
59228072Sbapt    if(!buf || !out)
60228072Sbapt        return buf;
61228072Sbapt
62228072Sbapt    for (i=0; i < buf->nelts; i++){
63228072Sbapt        const char * s = ((char**)buf->elts)[i];
64228072Sbapt        if(s)
65228072Sbapt            fprintf(out, "%s", s);
66228072Sbapt    }
67228072Sbapt    return buf;
68228072Sbapt}
69228072Sbapt
70228072Sbapt/* Append a "%s" formatted string to a string buffer */
71228072Sbaptstruct Buf *buf_prints (struct Buf *buf, const char *fmt, const char *s)
72228072Sbapt{
73228072Sbapt	char   *t;
74228072Sbapt        size_t tsz;
75228072Sbapt
76228072Sbapt	t = flex_alloc (tsz = strlen (fmt) + strlen (s) + 1);
77250125Sjkim	if (!t)
78250125Sjkim	    flexfatal (_("Allocation of buffer to print string failed"));
79228072Sbapt	snprintf (t, tsz, fmt, s);
80228072Sbapt	buf = buf_strappend (buf, t);
81228072Sbapt	flex_free (t);
82228072Sbapt	return buf;
83228072Sbapt}
84228072Sbapt
85228072Sbapt/** Append a line directive to the string buffer.
86228072Sbapt * @param buf A string buffer.
87228072Sbapt * @param filename file name
88228072Sbapt * @param lineno line number
89228072Sbapt * @return buf
90228072Sbapt */
91228072Sbaptstruct Buf *buf_linedir (struct Buf *buf, const char* filename, int lineno)
92228072Sbapt{
93250875Sjkim    char *dst, *t;
94250875Sjkim    const char *src;
95250125Sjkim
96250125Sjkim    t = flex_alloc (strlen ("#line \"\"\n")          +   /* constant parts */
97250125Sjkim                    2 * strlen (filename)            +   /* filename with possibly all backslashes escaped */
98250876Sjkim                    NUMCHARLINES                     +   /* line number */
99250125Sjkim                    1);                                  /* NUL */
100250125Sjkim    if (!t)
101250125Sjkim      flexfatal (_("Allocation of buffer for line directive failed"));
102250125Sjkim    for (dst = t + sprintf (t, "#line %d \"", lineno), src = filename; *src; *dst++ = *src++)
103250125Sjkim      if (*src == '\\')   /* escape backslashes */
104250125Sjkim        *dst++ = '\\';
105250125Sjkim    *dst++ = '"';
106250125Sjkim    *dst++ = '\n';
107250125Sjkim    *dst   = '\0';
108228072Sbapt    buf = buf_strappend (buf, t);
109228072Sbapt    flex_free (t);
110228072Sbapt    return buf;
111228072Sbapt}
112228072Sbapt
113228072Sbapt
114228072Sbapt/** Append the contents of @a src to @a dest.
115228072Sbapt * @param @a dest the destination buffer
116228072Sbapt * @param @a dest the source buffer
117228072Sbapt * @return @a dest
118228072Sbapt */
119228072Sbaptstruct Buf *buf_concat(struct Buf* dest, const struct Buf* src)
120228072Sbapt{
121228072Sbapt    buf_append(dest, src->elts, src->nelts);
122228072Sbapt    return dest;
123228072Sbapt}
124228072Sbapt
125228072Sbapt
126228072Sbapt/* Appends n characters in str to buf. */
127228072Sbaptstruct Buf *buf_strnappend (buf, str, n)
128228072Sbapt     struct Buf *buf;
129228072Sbapt     const char *str;
130228072Sbapt     int n;
131228072Sbapt{
132228072Sbapt	buf_append (buf, str, n + 1);
133228072Sbapt
134228072Sbapt	/* "undo" the '\0' character that buf_append() already copied. */
135228072Sbapt	buf->nelts--;
136228072Sbapt
137228072Sbapt	return buf;
138228072Sbapt}
139228072Sbapt
140228072Sbapt/* Appends characters in str to buf. */
141228072Sbaptstruct Buf *buf_strappend (buf, str)
142228072Sbapt     struct Buf *buf;
143228072Sbapt     const char *str;
144228072Sbapt{
145228072Sbapt	return buf_strnappend (buf, str, strlen (str));
146228072Sbapt}
147228072Sbapt
148228072Sbapt/* appends "#define str def\n" */
149228072Sbaptstruct Buf *buf_strdefine (buf, str, def)
150228072Sbapt     struct Buf *buf;
151228072Sbapt     const char *str;
152228072Sbapt     const char *def;
153228072Sbapt{
154228072Sbapt	buf_strappend (buf, "#define ");
155228072Sbapt	buf_strappend (buf, " ");
156228072Sbapt	buf_strappend (buf, str);
157228072Sbapt	buf_strappend (buf, " ");
158228072Sbapt	buf_strappend (buf, def);
159228072Sbapt	buf_strappend (buf, "\n");
160228072Sbapt	return buf;
161228072Sbapt}
162228072Sbapt
163228072Sbapt/** Pushes "m4_define( [[def]], [[val]])m4_dnl" to end of buffer.
164228072Sbapt * @param buf A buffer as a list of strings.
165228072Sbapt * @param def The m4 symbol to define.
166228072Sbapt * @param val The definition; may be NULL.
167228072Sbapt * @return buf
168228072Sbapt */
169228072Sbaptstruct Buf *buf_m4_define (struct Buf *buf, const char* def, const char* val)
170228072Sbapt{
171228072Sbapt    const char * fmt = "m4_define( [[%s]], [[%s]])m4_dnl\n";
172228072Sbapt    char * str;
173228072Sbapt    size_t strsz;
174228072Sbapt
175228072Sbapt    val = val?val:"";
176228072Sbapt    str = (char*)flex_alloc(strsz = strlen(fmt) + strlen(def) + strlen(val) + 2);
177250125Sjkim    if (!str)
178250125Sjkim        flexfatal (_("Allocation of buffer for m4 def failed"));
179228072Sbapt
180228072Sbapt    snprintf(str, strsz, fmt, def, val);
181228072Sbapt    buf_append(buf, &str, 1);
182228072Sbapt    return buf;
183228072Sbapt}
184228072Sbapt
185228072Sbapt/** Pushes "m4_undefine([[def]])m4_dnl" to end of buffer.
186228072Sbapt * @param buf A buffer as a list of strings.
187228072Sbapt * @param def The m4 symbol to undefine.
188228072Sbapt * @return buf
189228072Sbapt */
190228072Sbaptstruct Buf *buf_m4_undefine (struct Buf *buf, const char* def)
191228072Sbapt{
192228072Sbapt    const char * fmt = "m4_undefine( [[%s]])m4_dnl\n";
193228072Sbapt    char * str;
194228072Sbapt    size_t strsz;
195228072Sbapt
196228072Sbapt    str = (char*)flex_alloc(strsz = strlen(fmt) + strlen(def) + 2);
197250125Sjkim    if (!str)
198250125Sjkim        flexfatal (_("Allocation of buffer for m4 undef failed"));
199228072Sbapt
200228072Sbapt    snprintf(str, strsz, fmt, def);
201228072Sbapt    buf_append(buf, &str, 1);
202228072Sbapt    return buf;
203228072Sbapt}
204228072Sbapt
205228072Sbapt/* create buf with 0 elements, each of size elem_size. */
206228072Sbaptvoid buf_init (buf, elem_size)
207228072Sbapt     struct Buf *buf;
208228072Sbapt     size_t elem_size;
209228072Sbapt{
210228072Sbapt	buf->elts = (void *) 0;
211228072Sbapt	buf->nelts = 0;
212228072Sbapt	buf->elt_size = elem_size;
213228072Sbapt	buf->nmax = 0;
214228072Sbapt}
215228072Sbapt
216228072Sbapt/* frees memory */
217228072Sbaptvoid buf_destroy (buf)
218228072Sbapt     struct Buf *buf;
219228072Sbapt{
220228072Sbapt	if (buf && buf->elts)
221228072Sbapt		flex_free (buf->elts);
222228072Sbapt	buf->elts = (void *) 0;
223228072Sbapt}
224228072Sbapt
225228072Sbapt
226228072Sbapt/* appends ptr[] to buf, grow if necessary.
227228072Sbapt * n_elem is number of elements in ptr[], NOT bytes.
228228072Sbapt * returns buf.
229228072Sbapt * We grow by mod(512) boundaries.
230228072Sbapt */
231228072Sbapt
232228072Sbaptstruct Buf *buf_append (buf, ptr, n_elem)
233228072Sbapt     struct Buf *buf;
234228072Sbapt     const void *ptr;
235228072Sbapt     int n_elem;
236228072Sbapt{
237228072Sbapt	int     n_alloc = 0;
238228072Sbapt
239228072Sbapt	if (!ptr || n_elem == 0)
240228072Sbapt		return buf;
241228072Sbapt
242228072Sbapt	/* May need to alloc more. */
243228072Sbapt	if (n_elem + buf->nelts > buf->nmax) {
244228072Sbapt
245228072Sbapt		/* exact amount needed... */
246228072Sbapt		n_alloc = (n_elem + buf->nelts) * buf->elt_size;
247228072Sbapt
248228072Sbapt		/* ...plus some extra */
249228072Sbapt		if (((n_alloc * buf->elt_size) % 512) != 0
250228072Sbapt		    && buf->elt_size < 512)
251228072Sbapt			n_alloc +=
252228072Sbapt				(512 -
253228072Sbapt				 ((n_alloc * buf->elt_size) % 512)) /
254228072Sbapt				buf->elt_size;
255228072Sbapt
256228072Sbapt		if (!buf->elts)
257228072Sbapt			buf->elts =
258228072Sbapt				allocate_array (n_alloc, buf->elt_size);
259228072Sbapt		else
260228072Sbapt			buf->elts =
261228072Sbapt				reallocate_array (buf->elts, n_alloc,
262228072Sbapt						  buf->elt_size);
263228072Sbapt
264228072Sbapt		buf->nmax = n_alloc;
265228072Sbapt	}
266228072Sbapt
267228072Sbapt	memcpy ((char *) buf->elts + buf->nelts * buf->elt_size, ptr,
268228072Sbapt		n_elem * buf->elt_size);
269228072Sbapt	buf->nelts += n_elem;
270228072Sbapt
271228072Sbapt	return buf;
272228072Sbapt}
273228072Sbapt
274228072Sbapt/* vim:set tabstop=8 softtabstop=4 shiftwidth=4: */
275