PIPS
string_buffer.c
Go to the documentation of this file.
1 /*
2 
3  $Id: string_buffer.c 1357 2016-03-02 08:18:50Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of NewGen.
8 
9  NewGen is free software: you can redistribute it and/or modify it under the
10  terms of the GNU General Public License as published by the Free Software
11  Foundation, either version 3 of the License, or any later version.
12 
13  NewGen is distributed in the hope that it will be useful, but WITHOUT ANY
14  WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16  License for more details.
17 
18  You should have received a copy of the GNU General Public License along with
19  NewGen. If not, see <http://www.gnu.org/licenses/>.
20 
21 */
22 /*
23  Implement an a la java StringBuffer, a string-like object with
24  efficient modification methods.
25 
26  The idea here is to speed-up concatenation of strings by keeping a
27  stack of strings and delaying the final build-up of the global string up
28  to an explicit call to the string_buffer_to_string() method.
29 
30  In this way, if we have s strings of c characters, the concatenation
31  complexity is in O(sc) with string_buffer_append() instead of O(s^2 c)
32  with concatenate().
33 
34  Fabien Coelho
35 */
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 
40 #include <stdlib.h>
41 #include "genC.h"
42 
43 /* internally defined structure.
44  * the string_buffer pointer type is defined in "newgen_string_buffer.h"
45  */
47 {
49  bool dup; // whether to duplicate all strings appended to the buffer.
50  // we could keep track of the current buffer size on the fly:
51  // size_t size;
52 };
53 
54 /* allocate a new string buffer
55  * @param dup tell whether to string duplicate appended strings
56  * if so, the strings will be freed later.
57  */
59 {
60  string_buffer n =
61  (string_buffer) malloc(sizeof(struct __string_buffer_head));
62  message_assert("string_buffer is allocated", n!=NULL);
63  n->ins = stack_make(0, 0, 0);
64  n->dup = dup;
65  return n;
66 }
67 
68 /* remove stack contents
69  */
71 {
72  while (!stack_empty_p(sb->ins)) {
73  string s = (string) stack_pop(sb->ins);
74  if (sb->dup) free(s);
75  }
76 }
77 
78 /* @brief free string buffer structure, also free string contents
79  * according to the dup field
80  * @arg psb the string_buffer to free
81  */
83 {
84  if ((*psb)->dup)
85  STACK_MAP_X(s, string, free(s), (*psb)->ins, 0);
86  stack_free(&((*psb)->ins));
87  free(*psb);
88  *psb = NULL;
89 }
90 
91 /* free string buffer structure and force string freeing
92  * @arg psb the string_buffer to free
93  */
95 {
96  message_assert("not null pointer", (*psb) != NULL);
97  (*psb)->dup = true;
98  string_buffer_free (psb);
99 }
100 
101 /* return the size of the string in string_buffer sb
102  */
104 {
105  size_t size = 0;
106  STACK_MAP_X(s, string, size+=strlen(s), sb->ins, 0);
107  return size;
108 }
109 
110 /* return whether string_buffer sb is empty.
111  */
113 {
114  return string_buffer_size(sb)==0;
115 }
116 
117 /* convert to a malloced string, maybe in rev-ersed order of the appends
118  */
119 static string
121 {
122  string buf = (string) malloc(string_buffer_size(sb)+1);
123  message_assert("allocated", buf!=NULL);
124 
125  int current = 0;
126  buf[current] = '\0';
127 
128  STACK_MAP_X(s, string,
129  {
130  int len = strlen(s);
131  (void) memcpy(&buf[current], s, len);
132  current += len;
133  buf[current] = '\0';
134  },
135  sb->ins, rev);
136 
137  return buf;
138 }
139 /* return malloc'ed string from string buffer sb
140  */
142 {
143  return string_buffer_to_string_internal(sb, false);
144 }
145 
146 /* return malloc'ed string from string buffer sb going from bottom to top
147  */
149 {
150  return string_buffer_to_string_internal(sb, true);
151 }
152 
153 /* put string buffer into file.
154  */
156 {
157  STACK_MAP_X(s, string, fputs(s, out), sb->ins, 0);
158 }
159 
160 #define BUFFER_SIZE 512
161 
162 /* put string buffer as a C-string definition of the string buffer,
163  * including external double-quotes. It adds escapes for special characters.
164  */
166  string_buffer sb, const string_buffer src, int indent)
167 {
168  message_assert("distinct string buffers", sb!=src);
169  // internal working buffer...
170  char buffer[BUFFER_SIZE];
171  int i = 0, j;
172  // start string
173  buffer[i++] = '"';
174  bool in_string = true;
175  STACK_MAP_X(s, string,
176  for (char * c = s; *c; c++)
177  {
178  if (i>BUFFER_SIZE-10-indent)
179  {
180  buffer[i++] = '\0';
182  i = 0;
183  }
184  if (!in_string)
185  {
186  buffer[i++] = '\n';
187  for (j=0; j<indent; j++)
188  buffer[i++] = ' ';
189  buffer[i++] = '"';
190  in_string = true;
191  }
192  switch (*c)
193  {
194  case '\n': // New line
195  buffer[i++] = '\\';
196  buffer[i++] = 'n';
197  // the string is closed on newlines anyway
198  buffer[i++] = '"';
199  in_string = false;
200  break;
201  case '\a': // Audible bell
202  buffer[i++] = '\\';
203  buffer[i++] = 'a';
204  break;
205  case '\b': // Backspace
206  buffer[i++] = '\\';
207  buffer[i++] = 'b';
208  break;
209  case '\f': // Form feed
210  buffer[i++] = '\\';
211  buffer[i++] = 'f';
212  break;
213  case '\r': // carriage Return
214  buffer[i++] = '\\';
215  buffer[i++] = 'r';
216  break;
217  case '\t': // horizontal tab
218  buffer[i++] = '\\';
219  buffer[i++] = 't';
220  break;
221  case '\v': // Vertical tab
222  buffer[i++] = '\\';
223  buffer[i++] = 'v';
224  break;
225  case '\0': // null character
226  buffer[i++] = '\\';
227  buffer[i++] = '0';
228  break;
229  case '\\': // backslash
230  buffer[i++] = '\\';
231  buffer[i++] = '\\';
232  break;
233  case '"': // double quote
234  buffer[i++] = '\\';
235  buffer[i++] = '"';
236  break;
237  default:
238  buffer[i++] = *c;
239  }
240  },
241  src->ins, 0);
242  // end string if needed
243  if (in_string)
244  buffer[i++] = '"';
245  buffer[i++] = '\0';
247 }
248 
249 /* append, without handling duplication
250  */
251 static void string_buffer_append_internal(string_buffer sb, const string s)
252 {
253  if (*s)
254  stack_push(s, sb->ins);
255 }
256 
257 /* append string s (if non empty) to string buffer sb, the duplication
258  * is done if needed according to the dup field.
259  */
260 void string_buffer_append(string_buffer sb, const string s)
261 {
262  if (*s)
264 }
265 
266 /* @brief append the string buffer sb2 to string buffer sb.
267  * @return void
268  * @param sb, the string buffer where to append the second string buffer
269  * @param sb2, the string buffer to append to the fisrt string buffer
270  */
272 {
273  STACK_MAP_X(s, string, string_buffer_append(sb, s), sb2->ins, 0);
274 }
275 
276 /* @brief append a list of string to a string buffer. Note that each element
277  * of the list is duplicated or not according to the dup field.
278  * @return void
279  * @param sb, the string buffer where to append the whole list
280  * @param l, the list of string to append to the string buffer
281  */
283 {
284  FOREACH (string, s, l)
286 }
287 
288 #include <stdarg.h>
289 
290 /* append a NULL terminated list of string to sb.
291  * @param sb string buffer to be appended to
292  * @param first... appended strings
293  */
294 void string_buffer_cat(string_buffer sb, const string first, ...)
295 {
296  va_list args;
297  va_start(args, first);
298  string next = first;
299  while (next)
300  {
301  string_buffer_append(sb, next);
302  next = va_arg(args, string);
303  }
304  va_end(args);
305 }
306 
307 /* formatted alist version
308  */
311  const string format,
312  va_list *args)
313 {
314  va_list acpy;
315  va_copy(acpy, *args);
316  string str;
317  int err = vasprintf(&str, format, acpy);
318  message_assert("vasprintf ok", err >= 0);
319  string_buffer_append(sb, str);
320  if (sb->dup) free(str);
321  va_end(acpy);
322 }
323 
324 /* append a formatted string to sb
325  * @param sb string buffer to be appended to
326  * @param format printf format string
327  * @param ... values
328  */
331  const string format,
332  ...)
333 {
334  va_list args;
335  va_start(args, format);
336  string_buffer_printf_alist(sb, format, &args);
337  va_end(args);
338 }
339 
340 /* append a string with XML escapes
341  */
344  const string stuff,
345  bool also_nl)
346 {
347  // count needed chars, with a margin
348  int len = 1; // final '\0'
349  char * s = stuff;
350  while (*s) {
351  // only five mandatory ("'&<>), \n added...
352  if (strchr("\"'&<>\n", *s))
353  len += 5;
354  len ++, s ++;
355  }
356 
357  // allocate
358  char * escaped = (char*) malloc(sizeof(char)*len);
359 
360  // copy stuff & insert escapes
361  s = stuff;
362  char * e = escaped;
363  while (*s) {
364  switch (*s) {
365  // mandatory
366  case '"':
367  *e++='&'; *e++='q'; *e++='u'; *e++='o'; *e++='t'; *e++=';'; break;
368  case '\'':
369  *e++='&'; *e++='a'; *e++='p'; *e++='o'; *e++='s'; *e++=';'; break;
370  case '&':
371  *e++='&'; *e++='a'; *e++='m'; *e++='p'; *e++=';'; break;
372  case '<':
373  *e++='&'; *e++='l'; *e++='t'; *e++=';'; break;
374  case '>':
375  *e++='&'; *e++='g'; *e++='t'; *e++=';'; break;
376  // others...
377  case '\n':
378  if (also_nl) {
379  *e++='&'; *e++='#'; *e++='1'; *e++='0'; *e++=';'; break;
380  }
381  // else fall through
382  default:
383  *e++ = *s;
384  }
385  s++;
386  }
387  *e = '\0';
388 
390 }
static FILE * out
Definition: alias_check.c:128
void * malloc(YYSIZE_T)
void free(void *)
#define FOREACH(_fe_CASTER, _fe_item, _fe_list)
Apply/map an instruction block on all the elements of a list.
Definition: newgen_list.h:179
#define src(name, suf)
HPFC by Fabien Coelho, May 1993 and later...
Definition: compile.c:41
#define message_assert(msg, ex)
Definition: newgen_assert.h:47
#define STACK_MAP_X(_item, _itemtype, _code, _stack, _downwards)
not needed
Definition: newgen_stack.h:104
bool stack_empty_p(const stack)
void stack_push(void *, stack)
stack use
Definition: stack.c:373
void stack_free(stack *)
type, bucket_size, policy
Definition: stack.c:292
stack stack_make(int, int, int)
allocation
Definition: stack.c:246
void * stack_pop(stack)
POPs one item from stack s.
Definition: stack.c:399
struct __string_buffer_head * string_buffer
minimal a la java StringBuffer...
char * string
STRING.
Definition: newgen_types.h:39
char * strdup()
static char buf[BSZ]
Definition: split_file.c:157
static size_t current
Definition: string.c:115
static string buffer
Definition: string.c:113
void string_buffer_append_list(string_buffer sb, const list l)
append a list of string to a string buffer.
void string_buffer_free_all(string_buffer *psb)
free string buffer structure and force string freeing
Definition: string_buffer.c:94
void string_buffer_free(string_buffer *psb)
free string buffer structure, also free string contents according to the dup field
Definition: string_buffer.c:82
bool string_buffer_empty_p(const string_buffer sb)
return whether string_buffer sb is empty.
void string_buffer_append_sb(string_buffer sb, const string_buffer sb2)
append the string buffer sb2 to string buffer sb.
void string_buffer_printf_alist(string_buffer sb, const string format, va_list *args)
formatted alist version
static void string_buffer_append_internal(string_buffer sb, const string s)
append, without handling duplication
size_t string_buffer_size(const string_buffer sb)
return the size of the string in string_buffer sb
void string_buffer_printf(string_buffer sb, const string format,...)
append a formatted string to sb
void string_buffer_append_c_string_buffer(string_buffer sb, const string_buffer src, int indent)
put string buffer as a C-string definition of the string buffer, including external double-quotes.
#define BUFFER_SIZE
void string_buffer_reset(string_buffer sb)
remove stack contents
Definition: string_buffer.c:70
string string_buffer_to_string(const string_buffer sb)
return malloc'ed string from string buffer sb
void string_buffer_cat(string_buffer sb, const string first,...)
append a NULL terminated list of string to sb.
string_buffer string_buffer_make(bool dup)
allocate a new string buffer
Definition: string_buffer.c:58
static string string_buffer_to_string_internal(const string_buffer sb, bool rev)
convert to a malloced string, maybe in rev-ersed order of the appends
string string_buffer_to_string_reverse(const string_buffer sb)
return malloc'ed string from string buffer sb going from bottom to top
void string_buffer_to_file(const string_buffer sb, FILE *out)
put string buffer into file.
void string_buffer_append(string_buffer sb, const string s)
append string s (if non empty) to string buffer sb, the duplication is done if needed according to th...
void string_buffer_append_xml_text(string_buffer sb, const string stuff, bool also_nl)
append a string with XML escapes
the stack head
Definition: stack.c:62
internally defined structure.
Definition: string_buffer.c:47
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
Definition: statement.c:4047
int vasprintf(char **resultp, const char *format, va_list args)
Formatted output to strings.
Definition: vasprintf.c:33