PIPS
string.c
Go to the documentation of this file.
1 /*
2 
3  $Id: string.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  convenient functions to deal with strings.
24  moved from pips by FC, 16/09/1998.
25 
26  CONCATENATE concatenates a variable list of strings in a static string
27  (which is returned).
28 
29  STRNDUP copie les N premiers caracteres de la chaine S dans une zone
30  allouee dynamiquement, puis retourne un pointeur sur cette zone. si la
31  longueur de S est superieure ou egale a N, aucun caratere null n'est
32  ajoute au resultat. sinon, la chaine resultat est padde avec des
33  caracteres null.
34 
35  STRNDUP0 copie les N premiers caracteres de la chaine S dans une zone
36  allouee dynamiquement, puis retourne un pointeur sur cette zone.
37  l'allocation est systematiquement faite avec N+1 caracteres de telle
38  sorte qu'un caractere null soit ajoute a la chaine resultat, meme si la
39  longueur de la chaine S est superieure ou egale a N. dans le cas
40  contraire, la chaine resultat est padde avec des caracteres null.
41 
42 */
43 #ifdef HAVE_CONFIG_H
44  #include "config.h"
45 #endif
46 
47 #include <assert.h>
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <ctype.h>
51 #include <memory.h>
52 
53 #include <stdarg.h>
54 #include "genC.h"
55 
56 /* Like strdup() but copy at most n characters.
57  The return string *is not* null terminated. if the original string is a
58  least n-byte long. */
59 string gen_strndup(
60  string s, /* la chaine a copier */
61  size_t n /* le nombre de caracteres a copier */)
62 {
63  size_t i;
64 
65  string r = (string) malloc(n);
66  message_assert("allocated", r);
67 
68  /* recopie */
69  for (i = 0; i < n && s[i] != '\0'; i += 1 )
70  r[i] = s[i];
71 
72  /* padding */
73  while (i < n) {
74  r[i] = '\0';
75  i += 1;
76  }
77 
78  return r;
79 }
80 
81 /* Like strdup() but copy at most n characters.
82  The return string is null terminated. */
83 string gen_strndup0(
84  string s, /* la chaine a copier */
85  size_t n /* le nombre de caracteres a copier */)
86 {
87  register string r;
88  register size_t i;
89 
90  r = (string) malloc(n+1);
91  message_assert("allocated", r);
92 
93  /* recopie */
94  for (i = 0; i < n && s[i] != '\0'; i += 1 )
95  r[i] = s[i];
96 
97  /* padding */
98  while (i < n+1) {
99  r[i] = '\0';
100  i += 1;
101  }
102 
103  return r;
104 }
105 
106 /* CONCATENATE() *********** Last argument must be NULL *********/
107 
108 #define BUFFER_SIZE_INCREMENT 128
109 #ifndef MAX
110 #define MAX(x,y) (((x)>(y))?(x):(y))
111 #endif
112 
113 static string buffer = (string) NULL;
114 static size_t buffer_size = 0;
115 static size_t current = 0;
116 
117 /* I2A (Integer TO Ascii) yields a string for a given Integer.
118 
119  Moved in this global place from build.c since it used in many place in
120  PIPS.*/
121 char * i2a(int i) {
122  static char buf[ 20 ] ;
123  sprintf( &buf[0], "%d", i ) ;
124  return buf;
125 }
126 
127 void init_the_buffer(void)
128 {
129  /* initial allocation
130  */
131  if (buffer_size==0)
132  {
133  message_assert("NULL buffer", buffer==NULL);
136  message_assert("enough memory", buffer);
137  }
138  current = 0;
139  buffer[0] = '\0';
140 }
141 
142 /* If the string is undefined, just skip it. Well, I hope it will not hide
143  some bugs by masking some deliberate string_undefined put to trigger a
144  wrong assertion is some higher parts of the code... */
145 string append_to_the_buffer(const char* s /* what to append to the buffer */)
146 {
147  if (s != string_undefined)
148  {
149  size_t len = strlen(s);
150 
151  /* reallocates if needed
152  */
153  if (current+len >= buffer_size)
154  {
155  buffer_size = MAX(current+len+1,
157  buffer = realloc(buffer, buffer_size);
158  message_assert("enough memory", buffer);
159  }
160 
161  (void) memcpy(&buffer[current], s, len);
162  current += len;
163  buffer[current] = '\0' ;
164  }
165 
166  return buffer;
167 }
168 
169 string get_the_buffer(void)
170 {
171  return buffer;
172 }
173 
174 /* Return the concatenation of the given strings.
175  *
176  * CAUTION! concatenation is based on a static dynamically allocated buffer
177  * which is shared from one call to another.
178  *
179  * Note that if a string is string_undefined, it is just skiped.
180  *
181  * FC.
182  */
183 string concatenate(const char* next, ...)
184 {
185  int count = 0;
186  va_list args;
187  char * initial_buffer = buffer;
188 
189  if (next && next!=initial_buffer)
190  init_the_buffer();
191  /* else first argument is the buffer itself... */
192 
193  /* now gets the strings and concatenates them
194  */
195  va_start(args, next);
196  while (next)
197  {
198  count++;
199  if (next!=initial_buffer) /* skipping first argument if is buffer */
200  (void) append_to_the_buffer(next);
201  next = va_arg(args, string);
202  message_assert("reuse concatenate result only as the first argument",
203  !next || next!=initial_buffer);
204  /* should stop after some count? */
205  }
206  va_end(args);
207 
208  /* returns the static '\0' terminated buffer.
209  */
210  return buffer;
211 }
212 
213 string strupper(string s1, const char* s2)
214 {
215  char *r = s1;
216 
217  while (*s2) {
218  *s1 = (islower((int)*s2)) ? toupper(*s2) : *s2;
219  s1++;
220  s2++;
221  }
222 
223  *s1 = '\0';
224 
225  return r;
226 }
227 
228 string strlower(string s1, const char* s2)
229 {
230  char *r = s1;
231 
232  while (*s2) {
233  *s1 = (isupper((int)*s2)) ? tolower(*s2) : *s2;
234  s1++;
235  s2++;
236  }
237 
238  *s1 = '\0';
239 
240  return r;
241 }
242 
243 string bool_to_string(bool b)
244 {
245  return b? "true": "false";
246 }
247 
248 /* @return the english suffix for i.
249  */
250 string nth_suffix(int i)
251 {
252  string suffix = string_undefined;
253 
254  message_assert("Formal parameter i is greater or equal to 1", i >= 1);
255 
256  switch(i) {
257  case 1: suffix = "st";
258  break;
259  case 2: suffix = "nd";
260  break;
261  case 3: suffix = "rd";
262  break;
263  default: suffix = "th";
264  break;
265  }
266  return suffix;
267 }
268 
269 
270 /* Find if a string s end with a suffix.
271 
272  If yes, return a pointer to the suffix in s, if not, return NULL. */
273 string find_suffix(const string s, const string suffix)
274 {
275  size_t l = strlen(s);
276  size_t l_suffix = strlen(suffix);
277 
278  if (l < l_suffix)
279  /* No way if the suffix is longer than the string! */
280  return NULL;
281 
282  string suffix_position = s + l - l_suffix;
283  if (memcmp(suffix_position, suffix, l_suffix) == 0)
284  /* Get it! */
285  return suffix_position;
286 
287  /* Not found: */
288  return NULL;
289 }
290 
291 ///@return a string whithout the last "\n" char
292 ///@param s, the string to process
293 ///@param flg, if true do a copy of the string
294 string chop_newline (string s, bool flg)
295 {
296  if ((s == string_undefined) || (s == NULL)) return s;
297  string r = s;
298  if (flg == true) r = strdup(s);
299  int l = strlen(s);
300  if (l > 0) {
301  if (*(r + l - 1) == '\n') *(r + l - 1) = '\0';
302  }
303  return r;
304 }
305 
306 
307 ///@return a copy of the string whithout the last "\n" char
308 ///@param s, the string to process
309 string remove_newline_of_string (string s)
310 {
311  return chop_newline(s, true) ;
312 }
313 
314 /* @return array of string
315  * @param s string considered
316  * @pram d delimiter
317  */
318 list strsplit(const char *s, const char *d)
319 {
320  string buffer=strdup(s);
321  list split = NIL;
322  for(string tmp = strtok(buffer,d); tmp;tmp=strtok(NULL,d))
323  split=CONS(STRING,strdup(tmp),split);
324  free(buffer);
325  return gen_nreverse(split);
326 }
327 
328 /**
329  * Callback for sorting string with qsort
330  * @return see man strcmp
331  */
332 int gen_qsort_string_cmp(const void * s1, const void *s2) {
333  return strcmp(*(char **)s1, *(char **)s2);
334 }
335 
336 /**
337  * @brief Prepend the prefix to the string. Free the destination string
338  * if needed
339  * @param dst, the string to be modified
340  * @param prefix, the prefix to be prepended
341  */
342 void str_prepend (string* dst, string prefix) {
343  if ((prefix == NULL) || prefix == string_undefined || strlen (prefix) == 0)
344  return;
345  string old = * dst;
346  *dst = strdup (concatenate (prefix, *dst,NULL));
347  free (old);
348 }
349 
350 /**
351  * @brief Append the suffix to the string. Free the destination string
352  * if needed
353  * @param dst, the string to be modified
354  * @param suffix, the suffix to be appended
355  */
356 void str_append (string* dst, string suffix) {
357  if ((suffix == NULL) || suffix == string_undefined || strlen (suffix) == 0)
358  return;
359  string old = * dst;
360  *dst = strdup (concatenate (*dst, suffix, NULL));
361  free (old);
362 }
static int count
Definition: SDG.c:519
#define STRING(x)
Definition: genC.h:87
void * malloc(YYSIZE_T)
void free(void *)
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
#define message_assert(msg, ex)
Definition: newgen_assert.h:47
#define string_undefined
Definition: newgen_types.h:40
char * string
STRING.
Definition: newgen_types.h:39
static const char * prefix
char * strdup()
s1
Definition: set.c:247
static char buf[BSZ]
Definition: split_file.c:157
string remove_newline_of_string(string s)
Definition: string.c:309
string bool_to_string(bool b)
Definition: string.c:243
string get_the_buffer(void)
Definition: string.c:169
string append_to_the_buffer(const char *s)
If the string is undefined, just skip it.
Definition: string.c:145
static size_t current
Definition: string.c:115
string chop_newline(string s, bool flg)
Definition: string.c:294
string gen_strndup(string s, size_t n)
Like strdup() but copy at most n characters.
Definition: string.c:59
string gen_strndup0(string s, size_t n)
Like strdup() but copy at most n characters.
Definition: string.c:83
string find_suffix(const string s, const string suffix)
Find if a string s end with a suffix.
Definition: string.c:273
string strupper(string s1, const char *s2)
Definition: string.c:213
string strlower(string s1, const char *s2)
Definition: string.c:228
static size_t buffer_size
Definition: string.c:114
#define BUFFER_SIZE_INCREMENT
CONCATENATE() *********** Last argument must be NULL.
Definition: string.c:108
list strsplit(const char *s, const char *d)
Definition: string.c:318
string concatenate(const char *next,...)
Return the concatenation of the given strings.
Definition: string.c:183
#define MAX(x, y)
Definition: string.c:110
string nth_suffix(int i)
Definition: string.c:250
static string buffer
Definition: string.c:113
void str_append(string *dst, string suffix)
Append the suffix to the string.
Definition: string.c:356
char * i2a(int i)
I2A (Integer TO Ascii) yields a string for a given Integer.
Definition: string.c:121
void init_the_buffer(void)
Definition: string.c:127
void str_prepend(string *dst, string prefix)
Prepend the prefix to the string.
Definition: string.c:342
int gen_qsort_string_cmp(const void *s1, const void *s2)
Callback for sorting string with qsort.
Definition: string.c:332
The structure used to build lists in NewGen.
Definition: newgen_list.h:41