GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-112dd97adf
strings.c
Go to the documentation of this file.
1 /*!
2  \file lib/gis/strings.c
3 
4  \brief GIS Library - string/chring movement functions
5 
6  \todo merge interesting functions from ../datetime/scan.c here
7 
8  (C) 1999-2008, 2011 by the GRASS Development Team
9 
10  This program is free software under the GNU General Public License
11  (>=v2). Read the file COPYING that comes with GRASS for details.
12 
13  \author Dave Gerdes (USACERL)
14  \author Michael Shapiro (USACERL)
15  \author Amit Parghi (USACERL)
16  \author Bernhard Reiter (Intevation GmbH, Germany) and many others
17  */
18 
19 #include <string.h>
20 #include <stdlib.h>
21 #include <ctype.h>
22 #include <sys/types.h>
23 #include <grass/gis.h>
24 
25 #ifndef NULL
26 #define NULL 0
27 #endif
28 
29 static void *G__memccpy(void *, const void *, int, size_t);
30 static int _strncasecmp(const char *, const char *, int);
31 
32 /*!
33  \brief String compare ignoring case (upper or lower)
34 
35  Returning a value that has the same sign as the difference between
36  the first differing pair of characters.
37 
38  Note: strcasecmp() is affected by the locale (LC_CTYPE), while
39  G_strcasecmp() isn't.
40 
41  \param x first string to compare
42  \param y second string to compare
43 
44  \return 0 the two strings are equal
45  \return -1, 1
46  */
47 int G_strcasecmp(const char *x, const char *y)
48 {
49  return _strncasecmp(x, y, -1);
50 }
51 
52 /*!
53  \brief String compare ignoring case (upper or lower) - limited
54  number of characters
55 
56  Returning a value that has the same sign as the difference between
57  the first differing pair of characters.
58 
59  Note: strcasecmp() is affected by the locale (LC_CTYPE), while
60  G_strcasecmp() isn't.
61 
62  \param x first string to compare
63  \param y second string to compare
64  \param n number or characters to compare
65 
66  \return 0 the two strings are equal
67  \return -1, 1
68  */
69 int G_strncasecmp(const char *x, const char *y, int n)
70 {
71  return _strncasecmp(x, y, n);
72 }
73 
74 /*!
75  \brief Copy string to allocated memory.
76 
77  This routine allocates enough memory to hold the string <b>s</b>,
78  copies <em>s</em> to the allocated memory, and returns a pointer
79  to the allocated memory.
80 
81  If <em>s</em> is NULL then empty string is returned.
82 
83  \param s string
84 
85  \return pointer to newly allocated string
86  */
87 char *G_store(const char *s)
88 {
89  char *buf;
90 
91  if (s == NULL) {
92  buf = G_malloc(sizeof(char));
93  buf[0] = '\0';
94  }
95  else {
96  buf = G_malloc(strlen(s) + 1);
97  strcpy(buf, s);
98  }
99 
100  return buf;
101 }
102 
103 /*!
104  \brief Copy string to allocated memory and convert copied string
105  to upper case
106 
107  This routine allocates enough memory to hold the string <b>s</b>,
108  copies <em>s</em> to the allocated memory, and returns a pointer
109  to the allocated memory.
110 
111  If <em>s</em> is NULL then empty string is returned.
112 
113  \param s string
114 
115  \return pointer to newly allocated upper case string
116  */
117 char *G_store_upper(const char *s)
118 {
119  char *u_s;
120 
121  u_s = G_store(s);
122  G_str_to_upper(u_s);
123 
124  return u_s;
125 }
126 
127 /*!
128  \brief Copy string to allocated memory and convert copied string
129  to lower case
130 
131  This routine allocates enough memory to hold the string <b>s</b>,
132  copies <em>s</em> to the allocated memory, and returns a pointer
133  to the allocated memory.
134 
135  If <em>s</em> is NULL then empty string is returned.
136 
137  \param s string
138 
139  \return pointer to newly allocated lower case string
140  */
141 char *G_store_lower(const char *s)
142 {
143  char *l_s;
144 
145  l_s = G_store(s);
146  G_str_to_lower(l_s);
147 
148  return l_s;
149 }
150 
151 /*!
152  \brief Replace all occurrences of character in string bug with new
153 
154  \param[in,out] bug base string
155  \param character character to replace
156  \param new new character
157 
158  \return bug string
159  */
160 char *G_strchg(char *bug, char character, char new)
161 {
162  char *help = bug;
163 
164  while (*help) {
165  if (*help == character)
166  *help = new;
167  help++;
168  }
169  return bug;
170 }
171 
172 /*!
173  \brief Replace all occurrences of old_str in buffer with new_str
174 
175  Code example:
176  \code
177  char *name;
178  name = G_str_replace ( inbuf, ".exe", "" );
179  ...
180  G_free (name);
181  \endcode
182 
183  \param buffer input string buffer
184  \param old_str string to be replaced
185  \param new_str new string
186 
187  \return the newly allocated string, input buffer is unchanged
188  */
189 char *G_str_replace(const char *buffer, const char *old_str,
190  const char *new_str)
191 {
192  char *R;
193  const char *N, *B;
194  char *replace;
195  int count, len;
196 
197  /* Make sure old_str and new_str are not NULL */
198  if (old_str == NULL || new_str == NULL)
199  return G_store(buffer);
200  /* Make sure buffer is not NULL */
201  if (buffer == NULL)
202  return NULL;
203 
204  /* Make sure old_str occurs */
205  B = strstr(buffer, old_str);
206  if (B == NULL)
207  /* return NULL; */
208  return G_store(buffer);
209 
210  if (strlen(new_str) > strlen(old_str)) {
211  /* Count occurrences of old_str */
212  count = 0;
213  len = strlen(old_str);
214  B = buffer;
215  while (B != NULL && *B != '\0') {
216  B = strstr(B, old_str);
217  if (B != NULL) {
218  B += len;
219  count++;
220  }
221  }
222 
223  len = count * (strlen(new_str) - strlen(old_str)) + strlen(buffer);
224  }
225  else
226  len = strlen(buffer);
227 
228  /* Allocate new replacement */
229  replace = G_malloc(len + 1);
230  if (replace == NULL)
231  return NULL;
232 
233  /* Replace old_str with new_str */
234  B = buffer;
235  R = replace;
236  len = strlen(old_str);
237  while (*B != '\0') {
238  if (*B == old_str[0] && strncmp(B, old_str, len) == 0) {
239  N = new_str;
240  while (*N != '\0')
241  *R++ = *N++;
242  B += len;
243  }
244  else {
245  *R++ = *B++;
246  }
247  }
248  *R = '\0';
249 
250  return replace;
251 }
252 
253 /*!
254  \brief String concatenation
255 
256  Concatenates the strings in src_strings, which consists of num_strings number
257  of strings, with the separator sep. The size of the concatenated string is
258  limited by maxsize.
259 
260  \param src_strings array of strings to concatenate
261  \param num_strings count of strings in src_strings
262  \param sep separator string
263  \param maxsize maximum number of characters of returned string
264 
265  \return the concatenated string (allocated)
266  */
267 char *G_str_concat(const char **src_strings, int num_strings, const char *sep,
268  int maxsize)
269 {
270  if (maxsize < 1 || num_strings < 1)
271  return NULL;
272 
273  char *concat_str = NULL;
274  char *p = NULL;
275  char *buffer = G_malloc(maxsize * sizeof(char));
276  char *end = buffer + maxsize;
277 
278  memset(buffer, 0, maxsize);
279  for (int i = 0; i < num_strings; i++) {
280  if (i == 0)
281  p = (char *)G__memccpy(buffer, src_strings[i], '\0', maxsize);
282  else {
283  if (p)
284  p = (char *)G__memccpy(p - 1, sep, '\0', end - p);
285  if (p)
286  p = (char *)G__memccpy(p - 1, src_strings[i], '\0', end - p);
287  }
288  }
289  concat_str = G_store(buffer);
290  G_free(buffer);
291 
292  return concat_str;
293 }
294 
295 /*!
296  \brief Removes all leading and trailing white space from string.
297 
298  \param[in,out] buf buffer to be worked on
299  */
300 void G_strip(char *buf)
301 {
302  char *a, *b;
303 
304  /* remove leading white space */
305  for (a = b = buf; *a == ' ' || *a == '\t'; a++)
306  ;
307  if (a != b)
308  while ((*b++ = *a++))
309  ;
310  /* remove trailing white space */
311  for (a = buf; *a; a++)
312  ;
313  if (a != buf) {
314  for (a--; *a == ' ' || *a == '\t'; a--)
315  ;
316  a++;
317  *a = 0;
318  }
319 }
320 
321 /*!
322  \brief Chop leading and trailing white spaces.
323 
324  \verbatim space, \f, \n, \r, \t, \v \endverbatim
325 
326  Modified copy of G_squeeze() by RB in March 2000.
327 
328  \param line buffer to be worked on
329 
330  \return pointer to string
331  */
332 char *G_chop(char *line)
333 {
334  char *f = line, *t = line;
335 
336  while (isspace(*f)) /* go to first non white-space char */
337  f++;
338 
339  if (!*f) { /* no more chars in string */
340  *t = '\0';
341  return (line);
342  }
343 
344  for (t = f; *t; t++) /* go from first non white-space char to end */
345  ;
346  while (isspace(*--t))
347  ;
348  *++t = '\0'; /* remove trailing white-spaces */
349 
350  if (f != line) {
351  t = line;
352  while (*f) /* leading white spaces, shift */
353  *t++ = *f++;
354  *t = '\0';
355  }
356 
357  return (line);
358 }
359 
360 /*!
361  \brief Convert string to upper case
362 
363  \param[in,out] str pointer to string
364  */
365 void G_str_to_upper(char *str)
366 {
367  int i = 0;
368 
369  if (!str)
370  return;
371 
372  while (str[i]) {
373  str[i] = toupper(str[i]);
374  i++;
375  }
376 }
377 
378 /*!
379  \brief Convert string to lower case
380 
381  \param[in,out] str pointer to string
382  */
383 void G_str_to_lower(char *str)
384 {
385  int i = 0;
386 
387  if (!str)
388  return;
389 
390  while (str[i]) {
391  str[i] = tolower(str[i]);
392  i++;
393  }
394 }
395 
396 /*!
397  \brief Make string SQL compliant
398 
399  \param[in,out] str pointer to string
400 
401  \return number of changed characters
402  */
403 int G_str_to_sql(char *str)
404 {
405  int count;
406  char *c;
407 
408  count = 0;
409 
410  if (!str || !*str)
411  return 0;
412 
413  c = str;
414  while (*c) {
415  *c = toascii(*c);
416 
417  if (!(*c >= 'A' && *c <= 'Z') && !(*c >= 'a' && *c <= 'z') &&
418  !(*c >= '0' && *c <= '9')) {
419  *c = '_';
420  count++;
421  }
422  c++;
423  }
424 
425  c = str;
426  if (!(*c >= 'A' && *c <= 'Z') && !(*c >= 'a' && *c <= 'z')) {
427  *c = 'x';
428  count++;
429  }
430 
431  return count;
432 }
433 
434 /*!
435  \brief Remove superfluous white space.
436 
437  Leading and trailing white space is removed from the string
438  <b>line</b> and internal white space which is more than one character
439  is reduced to a single space character. White space here means
440  spaces, tabs, linefeeds, newlines, and formfeeds.
441 
442  \param[in,out] line
443 
444  \return Pointer to <b>line</b>
445  */
446 void G_squeeze(char *line)
447 {
448  char *f = line, *t = line;
449  int l;
450 
451  /* skip over space at the beginning of the line. */
452  while (isspace(*f))
453  f++;
454 
455  while (*f)
456  if (!isspace(*f))
457  *t++ = *f++;
458  else if (*++f)
459  if (!isspace(*f))
460  *t++ = ' ';
461  *t = '\0';
462  l = strlen(line) - 1;
463  if (*(line + l) == '\n')
464  *(line + l) = '\0';
465 }
466 
467 /*!
468  \brief Finds the first occurrence of the sub-string in the
469  null-terminated string ignoring case (upper or lower)
470 
471  \param str string where to find sub-string
472  \param substr sub-string
473 
474  \return a pointer to the first occurrence of sub-string
475  \return NULL if no occurrences are found
476  */
477 char *G_strcasestr(const char *str, const char *substr)
478 {
479  const char *p;
480  const char *q;
481  int length;
482 
483  p = substr;
484  q = str;
485  length = strlen(substr);
486 
487  do {
488  /* match 1st substr char */
489  while (*q != '\0' && toupper(*q) != toupper(*p)) {
490  q++;
491  }
492  } while (*q != '\0' && G_strncasecmp(p, q, length) != 0 && q++);
493 
494  if (*q == '\0') {
495  /* ran off end of str */
496  return NULL;
497  }
498 
499  return (char *)q;
500 }
501 
502 /*!
503  \brief Copy string until character found
504 
505  The bytes from string src are copied to string dst. If the character c (as
506  converted to an unsigned char) occurs in the string src, the copy stops and
507  a pointer to the byte after the copy of c in the string dst is returned.
508  Otherwise, n bytes are copied, and a NULL pointer is returned.
509 
510  The source and destination strings should not overlap, as the behavior
511  is undefined.
512 
513  \param dst destination
514  \param src source
515  \param c stop character
516  \param n max number of bytes to copy
517 
518  \return a pointer to the next character in dest after c
519  \return NULL if c was not found in the first n characters of src
520  */
521 static void *G__memccpy(void *dst, const void *src, int c, size_t n)
522 {
523  const char *s = src;
524  char *ret;
525 
526  for (ret = dst; n; ++ret, ++s, --n) {
527  *ret = *s;
528  if ((unsigned char)*ret == (unsigned char)c)
529  return ret + 1;
530  }
531 
532  return NULL;
533 }
534 
535 static int _strncasecmp(const char *x, const char *y, int n)
536 {
537  int xx, yy, i;
538 
539  if (!x)
540  return y ? -1 : 0;
541  if (!y)
542  return x ? 1 : 0;
543 
544  i = 1;
545  while (*x && *y) {
546  xx = *x++;
547  yy = *y++;
548  if (xx >= 'A' && xx <= 'Z')
549  xx = xx + 'a' - 'A';
550  if (yy >= 'A' && yy <= 'Z')
551  yy = yy + 'a' - 'A';
552  if (xx < yy)
553  return -1;
554  if (xx > yy)
555  return 1;
556 
557  if (n > -1 && i >= n)
558  return 0;
559 
560  i++;
561  }
562 
563  if (*x)
564  return 1;
565  if (*y)
566  return -1;
567  return 0;
568 }
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_malloc(n)
Definition: defs/gis.h:94
#define N
Definition: e_intersect.c:926
int count
#define strcpy
Definition: parson.c:62
double b
Definition: r_raster.c:39
double l
Definition: r_raster.c:39
double t
Definition: r_raster.c:39
#define NULL
Definition: strings.c:26
char * G_store(const char *s)
Copy string to allocated memory.
Definition: strings.c:87
int G_str_to_sql(char *str)
Make string SQL compliant.
Definition: strings.c:403
char * G_strcasestr(const char *str, const char *substr)
Finds the first occurrence of the sub-string in the null-terminated string ignoring case (upper or lo...
Definition: strings.c:477
int G_strncasecmp(const char *x, const char *y, int n)
String compare ignoring case (upper or lower) - limited number of characters.
Definition: strings.c:69
char * G_store_upper(const char *s)
Copy string to allocated memory and convert copied string to upper case.
Definition: strings.c:117
void G_str_to_upper(char *str)
Convert string to upper case.
Definition: strings.c:365
char * G_str_concat(const char **src_strings, int num_strings, const char *sep, int maxsize)
String concatenation.
Definition: strings.c:267
void G_str_to_lower(char *str)
Convert string to lower case.
Definition: strings.c:383
char * G_store_lower(const char *s)
Copy string to allocated memory and convert copied string to lower case.
Definition: strings.c:141
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition: strings.c:47
void G_squeeze(char *line)
Remove superfluous white space.
Definition: strings.c:446
char * G_str_replace(const char *buffer, const char *old_str, const char *new_str)
Replace all occurrences of old_str in buffer with new_str.
Definition: strings.c:189
void G_strip(char *buf)
Removes all leading and trailing white space from string.
Definition: strings.c:300
char * G_strchg(char *bug, char character, char new)
Replace all occurrences of character in string bug with new.
Definition: strings.c:160
char * G_chop(char *line)
Chop leading and trailing white spaces.
Definition: strings.c:332
#define x