CUBRID Engine  latest
variable_string.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * variable_string.c : Flexible strings that allow unlimited appending,
21  * prepending, etc.
22  */
23 
24 #ident "$Id$"
25 
26 #include "config.h"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32 
33 #include "porting.h"
34 #include "variable_string.h"
35 #include "error_code.h"
36 #include "error_manager.h"
37 
38 #define FUDGE 16
39 #define PREFIX_CUSHION 8
40 #define VS_INC 32
41 
42 static const char *EMPTY_STRING = "";
43 
44 static int vs_cannot_hold (varstring * vstr, int n);
45 static int vs_grow (varstring * vstr, int n);
46 static int vs_do_sprintf (varstring * vstr, const char *fmt, va_list args);
47 static int vs_itoa (varstring * vstr, int n);
48 
49 /*
50  * vs_cannot_hold() - Check vstr can hold or not
51  * return: true if cannot hold, false if can hold
52  * vstr(in/out): the varstring to be grown
53  * n(in): the size
54  */
55 static int
56 vs_cannot_hold (varstring * vstr, int n)
57 {
58  return ((vstr->base == NULL) || (vstr->limit - vstr->end) < n);
59 }
60 
61 /*
62  * vs_grow() - Enlarge the buffer area of the given varstring by the
63  * given amount.
64  * return: -1 if failure, 0 if success
65  * vstr(in/out): the varstring to be grown
66  * n(in): the size to grow it by.
67  */
68 static int
69 vs_grow (varstring * vstr, int n)
70 {
71  if (vstr == NULL)
72  {
73  return ER_FAILED;
74  }
75 
76  if (vstr->base)
77  {
78  int size = CAST_STRLEN (vstr->limit - vstr->base);
79  int length = CAST_STRLEN (vstr->end - vstr->start);
80  int offset = CAST_STRLEN (vstr->start - vstr->base);
81  char *new_buf = (char *) malloc (sizeof (char) * (size + n));
82  if (new_buf == NULL)
83  {
84  return ER_FAILED;
85  }
86 
87  /*
88  * Don't use strcpy here; vs_grow() can be invoked in the middle
89  * of string processing while the string isn't properly
90  * null-terminated.
91  */
92  memcpy (new_buf, vstr->base, size);
93  free (vstr->base);
94 
95  vstr->base = new_buf;
96  vstr->limit = new_buf + size + n;
97  vstr->start = new_buf + offset;
98  vstr->end = vstr->start + length;
99  }
100  else
101  {
102  char *new_buf = (char *) malloc (sizeof (char) * n);
103 
104  if (new_buf == NULL)
105  {
106  return ER_FAILED;
107  }
108 
109  vstr->base = new_buf;
110  vstr->limit = new_buf + n;
111  vstr->start = new_buf + (n > PREFIX_CUSHION ? PREFIX_CUSHION : 0);
112  vstr->end = vstr->start;
113  *vstr->start = '\0';
114  }
115 
116  return NO_ERROR;
117 }
118 
119 /*
120  * vs_do_sprintf() - Format the arguments into vstr according to fmt
121  * return: -1 if failure, 0 if success
122  * vstr(in/out): pointer to a varstring.
123  * fmt(in) : printf-style format string.
124  * args(in): stdarg-style package of arguments to be formatted.
125  *
126  * Note: Only understands %s and %d right now.
127  */
128 static int
129 vs_do_sprintf (varstring * vstr, const char *fmt, va_list args)
130 {
131  int c;
132  char *p, *limit;
133 
134  if (vstr->base == NULL && vs_grow (vstr, VS_INC))
135  {
136  return ER_FAILED;
137  }
138 
139  while (1)
140  {
141  restart:
142  for (p = vstr->end, limit = vstr->limit; p < limit;)
143  {
144  switch (c = *fmt++)
145  {
146  case '%':
147  switch (c = *fmt++)
148  {
149  case '%':
150  *p++ = '%';
151  continue;
152 
153  case 's':
154  vstr->end = p;
155  if (vs_strcat (vstr, va_arg (args, char *)))
156  {
157  return 1;
158  }
159  goto restart;
160 
161  case 'd':
162  vstr->end = p;
163  if (vs_itoa (vstr, va_arg (args, int)))
164  {
165  return 1;
166  }
167  goto restart;
168 
169  default:
170  break;
171  }
172  /* Fall through */
173 
174  case '\0':
175  *p = '\0';
176  vstr->end = p;
177  return NO_ERROR;
178 
179  default:
180  *p++ = (char) c;
181  continue;
182  }
183  }
184 
185  vstr->end = p;
186  if (vs_grow (vstr, VS_INC))
187  {
188  return ER_FAILED;
189  }
190  }
191 
192  return NO_ERROR;
193 }
194 
195 /*
196  * vs_itoa() - Append the text representation of the given integer
197  * return: -1 if failure, 0 if success
198  * vstr(in/out)
199  * n(in)
200  *
201  * Note:
202  */
203 static int
204 vs_itoa (varstring * vstr, int n)
205 {
206  char buf[32];
207  sprintf (buf, "%d", n);
208  return vs_strcat (vstr, buf);
209 }
210 
211 /*
212  * vs_new() - Allocate (if necessary) and initialize a varstring.
213  * return: pointer to the vstr if success, NULL if failure
214  * vstr(in): pointer of varstring to be initialized, possibly NULL.
215  */
216 varstring *
218 {
219  if (vstr == NULL)
220  {
221  vstr = (varstring *) malloc (sizeof (varstring));
222  if (vstr == NULL)
223  {
225  return NULL;
226  }
227 
228  vstr->heap_allocated = 1;
229  }
230  else
231  {
232  vstr->heap_allocated = 0;
233  }
234 
235  vstr->base = NULL;
236  vstr->limit = NULL;
237  vstr->start = NULL;
238  vstr->end = NULL;
239 
240  return vstr;
241 }
242 
243 /*
244  * vs_free() - free varstring if it was heap allocated.
245  * return: none
246  * vstr(in/out)
247  */
248 void
250 {
251  if (vstr == NULL)
252  {
253  return;
254  }
255 
256  if (vstr->base)
257  {
258  free (vstr->base);
259  vstr->base = NULL;
260  }
261 
262  if (vstr->heap_allocated)
263  {
264  free (vstr);
265  }
266 }
267 
268 /*
269  * vs_clear() - Reset the buffer pointers in varstring.
270  * return: none
271  * vstr(in/out)
272  */
273 void
275 {
276  if (vstr == NULL || vstr->base == NULL)
277  {
278  return;
279  }
280 
281  vstr->start = vstr->base + (vstr->limit - vstr->base < PREFIX_CUSHION ? 0 : PREFIX_CUSHION);
282 
283  vstr->end = vstr->start;
284  *vstr->start = '\0';
285 }
286 
287 
288 /*
289  * vs_append() - synonym for vs_strcat().
290  * return: -1 if failure, 0 if success.
291  * vstr(in/out)
292  * suffix(in)
293  */
294 int
295 vs_append (varstring * vstr, const char *suffix)
296 {
297  return vs_strcat (vstr, suffix);
298 }
299 
300 /*
301  * vs_prepend() - Prefix a string onto the varstring.
302  * return: -1 if failure, 0 if success
303  * vstr(in/out)
304  * prefix(in)
305  *
306  * Note:
307  */
308 int
309 vs_prepend (varstring * vstr, const char *prefix)
310 {
311  int n, available;
312 
313  if (vstr == NULL)
314  {
315  return ER_FAILED;
316  }
317 
318  if (prefix == NULL)
319  {
320  return NO_ERROR;
321  }
322 
323  n = (int) strlen (prefix);
324  if (n == 0)
325  {
326  return NO_ERROR;
327  }
328 
329  if (vstr->base == NULL && vs_grow (vstr, n + FUDGE))
330  {
331  return ER_FAILED;
332  }
333 
334  available = CAST_STRLEN (vstr->start - vstr->base);
335  if (available < n)
336  {
337  /*
338  * Make room at the front of the string for the prefix. If there
339  * is enough slop at the end, shift the current string toward the
340  * end without growing the string; if not, grow it and then do
341  * the shift.
342  */
343  char *new_start;
344  int length;
345 
346  if (vs_cannot_hold (vstr, PREFIX_CUSHION + (n - available)) && vs_grow (vstr, n + PREFIX_CUSHION + FUDGE))
347  {
348  return ER_FAILED;
349  }
350 
351  length = CAST_STRLEN (vstr->end - vstr->start);
352  new_start = vstr->base + n + PREFIX_CUSHION;
353 
354  memmove (new_start, vstr->start, length);
355 
356  vstr->end = new_start + length;
357  vstr->start = new_start;
358  *vstr->end = '\0';
359  }
360 
361  vstr->start -= n;
362  memcpy (vstr->start, prefix, n);
363 
364  return NO_ERROR;
365 }
366 
367 /*
368  * vs_sprintf() - Perform a sprintf-style formatting into vstr
369  * return: -1 if failure, 0 if success.
370  * vstr(in/out)
371  * fmt(in)
372  *
373  * Note: only the %s and %d codes are supported.
374  */
375 int
376 vs_sprintf (varstring * vstr, const char *fmt, ...)
377 {
378  int status;
379  va_list args;
380 
381  if (vstr == NULL || fmt == NULL)
382  {
383  return ER_FAILED;
384  }
385 
386  va_start (args, fmt);
387  status = vs_do_sprintf (vstr, fmt, args);
388  va_end (args);
389 
390  return status;
391 }
392 
393 /*
394  * vs_strcat() - Concatenate string onto the buffer in varstring
395  * return: -1 if failure, 0 if success.
396  * vstr(in/out)
397  * str(in)
398  */
399 int
400 vs_strcat (varstring * vstr, const char *str)
401 {
402  int n;
403 
404  if (vstr == NULL)
405  {
406  return ER_FAILED;
407  }
408 
409  if (str == NULL || (n = (int) strlen (str)) == 0)
410  {
411  return NO_ERROR;
412  }
413 
414  if (vs_cannot_hold (vstr, n) && vs_grow (vstr, n + FUDGE))
415  {
416  return ER_FAILED;
417  }
418 
419  memcpy (vstr->end, str, n);
420  vstr->end += n;
421 
422  return NO_ERROR;
423 
424 }
425 
426 /*
427  * vs_strcatn() - Concatenate str onto the buffer in varstring for
428  * a given length
429  * return: -1 if failure, 0 if success.
430  * vstr(in/out)
431  * str(in)
432  * length(in)
433  */
434 int
435 vs_strcatn (varstring * vstr, const char *str, int length)
436 {
437  if (vstr == NULL)
438  {
439  return ER_FAILED;
440  }
441 
442  if (str == NULL || length == 0)
443  {
444  return NO_ERROR;
445  }
446 
447  if (vs_cannot_hold (vstr, length) && vs_grow (vstr, length + FUDGE))
448  {
449  return ER_FAILED;
450  }
451 
452  memcpy (vstr->end, str, length);
453  vstr->end += length;
454 
455  return NO_ERROR;
456 }
457 
458 /*
459  * vs_strcpy() - Initialize varstring with the contents of string.
460  * return: -1 if failure, 0 if success.
461  * vstr(in/out)
462  * str(in)
463  */
464 int
465 vs_strcpy (varstring * vstr, const char *str)
466 {
467  vs_clear (vstr);
468  return vs_strcat (vstr, str);
469 }
470 
471 /*
472  * vs_putc() - Put a single character in varstring
473  * return: -1 if failure, 0 if success.
474  * vstr(in/out)
475  * ch(in)
476  */
477 int
478 vs_putc (varstring * vstr, int ch)
479 {
480  if (vstr == NULL)
481  {
482  return ER_FAILED;
483  }
484 
485  if (vs_cannot_hold (vstr, 1) && vs_grow (vstr, FUDGE))
486  {
487  return ER_FAILED;
488  }
489 
490  *vstr->end++ = (char) ch;
491 
492  return NO_ERROR;
493 
494 }
495 
496 /*
497  * vs_str() - Return the prepared character string within varstring.
498  * return: the start pointer of varstring
499  * vstr(in/out)
500  */
501 char *
503 {
504  if (vstr == NULL || vstr->base == NULL)
505  {
506  return (char *) EMPTY_STRING;
507  }
508  else
509  {
510  /*
511  * Make sure it's null-terminated by emitting a null character
512  * and then backing up the end pointer.
513  */
514  if (vs_cannot_hold (vstr, 1) && vs_grow (vstr, FUDGE))
515  {
516  return NULL;
517  }
518 
519  *vstr->end = '\0';
520  return vstr->start;
521  }
522 }
523 
524 /*
525  * vs_strlen() - Return the length of the string managed by varstring.
526  * return: length of the varstring
527  * vstr(in)
528  */
529 int
530 vs_strlen (const varstring * vstr)
531 {
532  if (vstr == NULL || vstr->base == NULL)
533  {
534  return 0;
535  }
536 
537  return CAST_STRLEN (vstr->end - vstr->start);
538 }
#define NO_ERROR
Definition: error_code.h:46
static int vs_grow(varstring *vstr, int n)
int vs_append(varstring *vstr, const char *suffix)
varstring * vs_new(varstring *vstr)
#define PREFIX_CUSHION
#define ER_FAILED
Definition: error_code.h:47
int vs_prepend(varstring *vstr, const char *prefix)
#define CAST_STRLEN
Definition: porting.h:470
int vs_strcpy(varstring *vstr, const char *str)
int vs_sprintf(varstring *vstr, const char *fmt,...)
#define FUDGE
char * vs_str(varstring *vstr)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
static int vs_itoa(varstring *vstr, int n)
void vs_free(varstring *vstr)
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
static int vs_do_sprintf(varstring *vstr, const char *fmt, va_list args)
char * limit
int heap_allocated
#define NULL
Definition: freelistheap.h:34
int vs_strcatn(varstring *vstr, const char *str, int length)
int vs_putc(varstring *vstr, int ch)
void vs_clear(varstring *vstr)
#define ARG_FILE_LINE
Definition: error_manager.h:44
int vs_strcat(varstring *vstr, const char *str)
#define strlen(s1)
Definition: intl_support.c:43
int vs_strlen(const varstring *vstr)
static const char * EMPTY_STRING
char * start
#define VS_INC
static int vs_cannot_hold(varstring *vstr, int n)
const char ** p
Definition: dynamic_load.c:945