GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
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, const char *new_str)
190 {
191  char *R;
192  const char *N, *B;
193  char *replace;
194  int count, len;
195 
196  /* Make sure old_str and new_str are not NULL */
197  if (old_str == NULL || new_str == NULL)
198  return G_store(buffer);
199  /* Make sure buffer is not NULL */
200  if (buffer == NULL)
201  return NULL;
202 
203  /* Make sure old_str occurs */
204  B = strstr(buffer, old_str);
205  if (B == NULL)
206  /* return NULL; */
207  return G_store(buffer);
208 
209  if (strlen(new_str) > strlen(old_str)) {
210  /* Count occurrences of old_str */
211  count = 0;
212  len = strlen(old_str);
213  B = buffer;
214  while (B != NULL && *B != '\0') {
215  B = strstr(B, old_str);
216  if (B != NULL) {
217  B += len;
218  count++;
219  }
220  }
221 
222  len = count * (strlen(new_str) - strlen(old_str))
223  + strlen(buffer);
224 
225  }
226  else
227  len = strlen(buffer);
228 
229  /* Allocate new replacement */
230  replace = G_malloc(len + 1);
231  if (replace == NULL)
232  return NULL;
233 
234  /* Replace old_str with new_str */
235  B = buffer;
236  R = replace;
237  len = strlen(old_str);
238  while (*B != '\0') {
239  if (*B == old_str[0] && strncmp(B, old_str, len) == 0) {
240  N = new_str;
241  while (*N != '\0')
242  *R++ = *N++;
243  B += len;
244  }
245  else {
246  *R++ = *B++;
247  }
248  }
249  *R = '\0';
250 
251  return replace;
252 }
253 
254 /*!
255  \brief String concatenation
256 
257  Concatenates the strings in src_strings, which consists of num_strings number
258  of strings, with the separator sep. The size of the concatenated string is
259  limited by maxsize.
260 
261  \param src_strings array of strings to concatenate
262  \param num_strings count of strings in src_strings
263  \param sep separator string
264  \param maxsize maximum number of characters of returned string
265 
266  \return the concatenated string (allocated)
267  */
268 char *G_str_concat(const char **src_strings, int num_strings,
269  const char *sep, int maxsize)
270 {
271  char buffer[maxsize];
272  int i;
273  char *end = buffer + maxsize;
274  char *p = NULL;
275 
276  if (maxsize < 1 || num_strings < 1)
277  return NULL;
278 
279  memset(buffer, 0, sizeof(buffer));
280 
281  for (i = 0; i < num_strings; i++) {
282  if (i == 0)
283  p = (char *)G__memccpy(buffer, src_strings[i], '\0', maxsize);
284  else {
285  if (p)
286  p = (char *)G__memccpy(p - 1, sep, '\0', end - p);
287  if (p)
288  p = (char *)G__memccpy(p - 1, src_strings[i], '\0', end - p);
289  }
290  }
291 
292  return G_store(buffer);
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  if (a != b)
307  while ((*b++ = *a++)) ;
308  /* remove trailing white space */
309  for (a = buf; *a; a++) ;
310  if (a != buf) {
311  for (a--; *a == ' ' || *a == '\t'; a--) ;
312  a++;
313  *a = 0;
314  }
315 }
316 
317 /*!
318  \brief Chop leading and trailing white spaces.
319 
320  \verbatim space, \f, \n, \r, \t, \v \endverbatim
321 
322  Modified copy of G_squeeze() by RB in March 2000.
323 
324  \param line buffer to be worked on
325 
326  \return pointer to string
327 */
328 char *G_chop(char *line)
329 {
330  char *f = line, *t = line;
331 
332  while (isspace(*f)) /* go to first non white-space char */
333  f++;
334 
335  if (!*f) { /* no more chars in string */
336  *t = '\0';
337  return (line);
338  }
339 
340  for (t = f; *t; t++) /* go from first non white-space char to end */
341  ;
342  while (isspace(*--t)) ;
343  *++t = '\0'; /* remove trailing white-spaces */
344 
345  if (f != line) {
346  t = line;
347  while (*f) /* leading white spaces, shift */
348  *t++ = *f++;
349  *t = '\0';
350  }
351 
352  return (line);
353 }
354 
355 /*!
356  \brief Convert string to upper case
357 
358  \param[in,out] str pointer to string
359 */
360 void G_str_to_upper(char *str)
361 {
362  int i = 0;
363 
364  if (!str)
365  return;
366 
367  while (str[i]) {
368  str[i] = toupper(str[i]);
369  i++;
370  }
371 }
372 
373 /*!
374  \brief Convert string to lower case
375 
376  \param[in,out] str pointer to string
377 */
378 void G_str_to_lower(char *str)
379 {
380  int i = 0;
381 
382  if (!str)
383  return;
384 
385  while (str[i]) {
386  str[i] = tolower(str[i]);
387  i++;
388  }
389 }
390 
391 /*!
392  \brief Make string SQL compliant
393 
394  \param[in,out] str pointer to string
395 
396  \return number of changed characters
397 */
398 int G_str_to_sql(char *str)
399 {
400  int count;
401  char *c;
402 
403  count = 0;
404 
405  if (!str || !*str)
406  return 0;
407 
408  c = str;
409  while (*c) {
410  *c = toascii(*c);
411 
412  if (!(*c >= 'A' && *c <= 'Z') && !(*c >= 'a' && *c <= 'z') &&
413  !(*c >= '0' && *c <= '9')) {
414  *c = '_';
415  count++;
416  }
417  c++;
418  }
419 
420  c = str;
421  if (!(*c >= 'A' && *c <= 'Z') && !(*c >= 'a' && *c <= 'z')) {
422  *c = 'x';
423  count++;
424  }
425 
426  return count;
427 }
428 
429 /*!
430  \brief Remove superfluous white space.
431 
432  Leading and trailing white space is removed from the string
433  <b>line</b> and internal white space which is more than one character
434  is reduced to a single space character. White space here means
435  spaces, tabs, linefeeds, newlines, and formfeeds.
436 
437  \param[in,out] line
438 
439  \return Pointer to <b>line</b>
440 */
441 void G_squeeze(char *line)
442 {
443  char *f = line, *t = line;
444  int l;
445 
446  /* skip over space at the beginning of the line. */
447  while (isspace(*f))
448  f++;
449 
450  while (*f)
451  if (!isspace(*f))
452  *t++ = *f++;
453  else if (*++f)
454  if (!isspace(*f))
455  *t++ = ' ';
456  *t = '\0';
457  l = strlen(line) - 1;
458  if (*(line + l) == '\n')
459  *(line + l) = '\0';
460 }
461 
462 /*!
463  \brief Finds the first occurrence of the sub-string in the
464  null-terminated string ignoring case (upper or lower)
465 
466  \param str string where to find sub-string
467  \param substr sub-string
468 
469  \return a pointer to the first occurrence of sub-string
470  \return NULL if no occurrences are found
471 */
472 char *G_strcasestr(const char *str, const char *substr)
473 {
474  const char *p;
475  const char *q;
476  int length;
477 
478  p = substr;
479  q = str;
480  length = strlen(substr);
481 
482  do {
483  /* match 1st substr char */
484  while (*q != '\0' && toupper(*q) != toupper(*p)) {
485  q++;
486  }
487  } while (*q != '\0' && G_strncasecmp(p, q, length) != 0 && q++);
488 
489  if (*q == '\0') {
490  /* ran off end of str */
491  return NULL;
492  }
493 
494  return (char *) q;
495 }
496 
497 /*!
498  \brief Copy string until character found
499 
500  The bytes from string src are copied to string dst. If the character c (as
501  converted to an unsigned char) occurs in the string src, the copy stops and
502  a pointer to the byte after the copy of c in the string dst is returned.
503  Otherwise, n bytes are copied, and a NULL pointer is returned.
504 
505  The source and destination strings should not overlap, as the behavior
506  is undefined.
507 
508  \param dst destination
509  \param src source
510  \param c stop character
511  \param n max number of bytes to copy
512 
513  \return a pointer to the next character in dest after c
514  \return NULL if c was not found in the first n characters of src
515  */
516 static void *G__memccpy(void *dst, const void *src, int c, size_t n)
517 {
518  const char *s = src;
519  char *ret;
520 
521  for (ret = dst; n; ++ret, ++s, --n) {
522  *ret = *s;
523  if ((unsigned char)*ret == (unsigned char)c)
524  return ret + 1;
525  }
526 
527  return NULL;
528 }
529 
530 static int _strncasecmp(const char *x, const char *y, int n)
531 {
532  int xx, yy, i;
533 
534  if (!x)
535  return y ? -1 : 0;
536  if (!y)
537  return x ? 1 : 0;
538 
539  i = 1;
540  while (*x && *y) {
541  xx = *x++;
542  yy = *y++;
543  if (xx >= 'A' && xx <= 'Z')
544  xx = xx + 'a' - 'A';
545  if (yy >= 'A' && yy <= 'Z')
546  yy = yy + 'a' - 'A';
547  if (xx < yy)
548  return -1;
549  if (xx > yy)
550  return 1;
551 
552  if (n > -1 && i >= n)
553  return 0;
554 
555  i++;
556  }
557 
558  if (*x)
559  return 1;
560  if (*y)
561  return -1;
562  return 0;
563 }
#define G_malloc(n)
Definition: defs/gis.h:112
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition: strings.c:47
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:472
#define NULL
Definition: strings.c:26
void G_strip(char *buf)
Removes all leading and trailing white space from string.
Definition: strings.c:300
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_strchg(char *bug, char character, char new)
Replace all occurrences of character in string bug with new.
Definition: strings.c:160
int count
char * G_store(const char *s)
Copy string to allocated memory.
Definition: strings.c:87
char * dst
Definition: lz4.h:599
#define N
Definition: e_intersect.c:917
char * G_store_lower(const char *s)
Copy string to allocated memory and convert copied string to lower case.
Definition: strings.c:141
char * G_chop(char *line)
Chop leading and trailing white spaces.
Definition: strings.c:328
#define x
void G_str_to_lower(char *str)
Convert string to lower case.
Definition: strings.c:378
double l
Definition: r_raster.c:39
double t
Definition: r_raster.c:39
double b
Definition: r_raster.c:39
void G_squeeze(char *line)
Remove superfluous white space.
Definition: strings.c:441
char * G_store_upper(const char *s)
Copy string to allocated memory and convert copied string to upper case.
Definition: strings.c:117
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_str_to_upper(char *str)
Convert string to upper case.
Definition: strings.c:360
char * G_str_concat(const char **src_strings, int num_strings, const char *sep, int maxsize)
String concatenation.
Definition: strings.c:268
int G_str_to_sql(char *str)
Make string SQL compliant.
Definition: strings.c:398