GRASS GIS 8 Programmer's Manual  8.3.1(2023)-exported
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  char buffer[maxsize];
271  int i;
272  char *end = buffer + maxsize;
273  char *p = NULL;
274 
275  if (maxsize < 1 || num_strings < 1)
276  return NULL;
277 
278  memset(buffer, 0, sizeof(buffer));
279 
280  for (i = 0; i < num_strings; i++) {
281  if (i == 0)
282  p = (char *)G__memccpy(buffer, src_strings[i], '\0', maxsize);
283  else {
284  if (p)
285  p = (char *)G__memccpy(p - 1, sep, '\0', end - p);
286  if (p)
287  p = (char *)G__memccpy(p - 1, src_strings[i], '\0', end - p);
288  }
289  }
290 
291  return G_store(buffer);
292 }
293 
294 /*!
295  \brief Removes all leading and trailing white space from string.
296 
297  \param[in,out] buf buffer to be worked on
298  */
299 void G_strip(char *buf)
300 {
301  char *a, *b;
302 
303  /* remove leading white space */
304  for (a = b = buf; *a == ' ' || *a == '\t'; a++)
305  ;
306  if (a != b)
307  while ((*b++ = *a++))
308  ;
309  /* remove trailing white space */
310  for (a = buf; *a; a++)
311  ;
312  if (a != buf) {
313  for (a--; *a == ' ' || *a == '\t'; a--)
314  ;
315  a++;
316  *a = 0;
317  }
318 }
319 
320 /*!
321  \brief Chop leading and trailing white spaces.
322 
323  \verbatim space, \f, \n, \r, \t, \v \endverbatim
324 
325  Modified copy of G_squeeze() by RB in March 2000.
326 
327  \param line buffer to be worked on
328 
329  \return pointer to string
330  */
331 char *G_chop(char *line)
332 {
333  char *f = line, *t = line;
334 
335  while (isspace(*f)) /* go to first non white-space char */
336  f++;
337 
338  if (!*f) { /* no more chars in string */
339  *t = '\0';
340  return (line);
341  }
342 
343  for (t = f; *t; t++) /* go from first non white-space char to end */
344  ;
345  while (isspace(*--t))
346  ;
347  *++t = '\0'; /* remove trailing white-spaces */
348 
349  if (f != line) {
350  t = line;
351  while (*f) /* leading white spaces, shift */
352  *t++ = *f++;
353  *t = '\0';
354  }
355 
356  return (line);
357 }
358 
359 /*!
360  \brief Convert string to upper case
361 
362  \param[in,out] str pointer to string
363  */
364 void G_str_to_upper(char *str)
365 {
366  int i = 0;
367 
368  if (!str)
369  return;
370 
371  while (str[i]) {
372  str[i] = toupper(str[i]);
373  i++;
374  }
375 }
376 
377 /*!
378  \brief Convert string to lower case
379 
380  \param[in,out] str pointer to string
381  */
382 void G_str_to_lower(char *str)
383 {
384  int i = 0;
385 
386  if (!str)
387  return;
388 
389  while (str[i]) {
390  str[i] = tolower(str[i]);
391  i++;
392  }
393 }
394 
395 /*!
396  \brief Make string SQL compliant
397 
398  \param[in,out] str pointer to string
399 
400  \return number of changed characters
401  */
402 int G_str_to_sql(char *str)
403 {
404  int count;
405  char *c;
406 
407  count = 0;
408 
409  if (!str || !*str)
410  return 0;
411 
412  c = str;
413  while (*c) {
414  *c = toascii(*c);
415 
416  if (!(*c >= 'A' && *c <= 'Z') && !(*c >= 'a' && *c <= 'z') &&
417  !(*c >= '0' && *c <= '9')) {
418  *c = '_';
419  count++;
420  }
421  c++;
422  }
423 
424  c = str;
425  if (!(*c >= 'A' && *c <= 'Z') && !(*c >= 'a' && *c <= 'z')) {
426  *c = 'x';
427  count++;
428  }
429 
430  return count;
431 }
432 
433 /*!
434  \brief Remove superfluous white space.
435 
436  Leading and trailing white space is removed from the string
437  <b>line</b> and internal white space which is more than one character
438  is reduced to a single space character. White space here means
439  spaces, tabs, linefeeds, newlines, and formfeeds.
440 
441  \param[in,out] line
442 
443  \return Pointer to <b>line</b>
444  */
445 void G_squeeze(char *line)
446 {
447  char *f = line, *t = line;
448  int l;
449 
450  /* skip over space at the beginning of the line. */
451  while (isspace(*f))
452  f++;
453 
454  while (*f)
455  if (!isspace(*f))
456  *t++ = *f++;
457  else if (*++f)
458  if (!isspace(*f))
459  *t++ = ' ';
460  *t = '\0';
461  l = strlen(line) - 1;
462  if (*(line + l) == '\n')
463  *(line + l) = '\0';
464 }
465 
466 /*!
467  \brief Finds the first occurrence of the sub-string in the
468  null-terminated string ignoring case (upper or lower)
469 
470  \param str string where to find sub-string
471  \param substr sub-string
472 
473  \return a pointer to the first occurrence of sub-string
474  \return NULL if no occurrences are found
475  */
476 char *G_strcasestr(const char *str, const char *substr)
477 {
478  const char *p;
479  const char *q;
480  int length;
481 
482  p = substr;
483  q = str;
484  length = strlen(substr);
485 
486  do {
487  /* match 1st substr char */
488  while (*q != '\0' && toupper(*q) != toupper(*p)) {
489  q++;
490  }
491  } while (*q != '\0' && G_strncasecmp(p, q, length) != 0 && q++);
492 
493  if (*q == '\0') {
494  /* ran off end of str */
495  return NULL;
496  }
497 
498  return (char *)q;
499 }
500 
501 /*!
502  \brief Copy string until character found
503 
504  The bytes from string src are copied to string dst. If the character c (as
505  converted to an unsigned char) occurs in the string src, the copy stops and
506  a pointer to the byte after the copy of c in the string dst is returned.
507  Otherwise, n bytes are copied, and a NULL pointer is returned.
508 
509  The source and destination strings should not overlap, as the behavior
510  is undefined.
511 
512  \param dst destination
513  \param src source
514  \param c stop character
515  \param n max number of bytes to copy
516 
517  \return a pointer to the next character in dest after c
518  \return NULL if c was not found in the first n characters of src
519  */
520 static void *G__memccpy(void *dst, const void *src, int c, size_t n)
521 {
522  const char *s = src;
523  char *ret;
524 
525  for (ret = dst; n; ++ret, ++s, --n) {
526  *ret = *s;
527  if ((unsigned char)*ret == (unsigned char)c)
528  return ret + 1;
529  }
530 
531  return NULL;
532 }
533 
534 static int _strncasecmp(const char *x, const char *y, int n)
535 {
536  int xx, yy, i;
537 
538  if (!x)
539  return y ? -1 : 0;
540  if (!y)
541  return x ? 1 : 0;
542 
543  i = 1;
544  while (*x && *y) {
545  xx = *x++;
546  yy = *y++;
547  if (xx >= 'A' && xx <= 'Z')
548  xx = xx + 'a' - 'A';
549  if (yy >= 'A' && yy <= 'Z')
550  yy = yy + 'a' - 'A';
551  if (xx < yy)
552  return -1;
553  if (xx > yy)
554  return 1;
555 
556  if (n > -1 && i >= n)
557  return 0;
558 
559  i++;
560  }
561 
562  if (*x)
563  return 1;
564  if (*y)
565  return -1;
566  return 0;
567 }
double b
double l
double t
int count
#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:402
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:476
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:364
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:382
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:445
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:299
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:331
#define x