GRASS 8 Programmer's Manual 8.6.0dev(2026)-1a88e4eae9
Loading...
Searching...
No Matches
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 SPDX-FileCopyrightText: 1999-2008, 2011 GRASS Development Team
9 SPDX-License-Identifier: GPL-2.0-or-later
10
11 \author Dave Gerdes (USACERL)
12 \author Michael Shapiro (USACERL)
13 \author Amit Parghi (USACERL)
14 \author Bernhard Reiter (Intevation GmbH, Germany) and many others
15 */
16
17#include <string.h>
18#include <stdlib.h>
19#include <ctype.h>
20#include <limits.h>
21#include <sys/types.h>
22#include <grass/gis.h>
23
24#ifndef NULL
25#define NULL 0
26#endif
27
28static void *G__memccpy(void *, const void *, int, size_t);
29static int _strncasecmp(const char *, const char *, int);
30
31/*!
32 \brief String compare ignoring case (upper or lower)
33
34 Returning a value that has the same sign as the difference between
35 the first differing pair of characters.
36
37 Note: strcasecmp() is affected by the locale (LC_CTYPE), while
38 G_strcasecmp() isn't.
39
40 \param x first string to compare
41 \param y second string to compare
42
43 \return 0 the two strings are equal
44 \return -1, 1
45 */
46int G_strcasecmp(const char *x, const char *y)
47{
48 return _strncasecmp(x, y, -1);
49}
50
51/*!
52 \brief String compare ignoring case (upper or lower) - limited
53 number of characters
54
55 Returning a value that has the same sign as the difference between
56 the first differing pair of characters.
57
58 Note: strcasecmp() is affected by the locale (LC_CTYPE), while
59 G_strcasecmp() isn't.
60
61 \param x first string to compare
62 \param y second string to compare
63 \param n number or characters to compare
64
65 \return 0 the two strings are equal
66 \return -1, 1
67 */
68int G_strncasecmp(const char *x, const char *y, int n)
69{
70 return _strncasecmp(x, y, n);
71}
72
73/*!
74 \brief Copy string to allocated memory.
75
76 This routine allocates enough memory to hold the string <b>s</b>,
77 copies <em>s</em> to the allocated memory, and returns a pointer
78 to the allocated memory.
79
80 If <em>s</em> is NULL then empty string is returned.
81
82 \param s string
83
84 \return pointer to newly allocated string
85 */
86char *G_store(const char *s)
87{
88 char *buf;
89
90 if (s == NULL) {
91 buf = G_malloc(sizeof(char));
92 buf[0] = '\0';
93 }
94 else {
95 buf = G_malloc(strlen(s) + 1);
96 strcpy(buf, s);
97 }
98
99 return buf;
100}
101
102/*!
103 \brief Copy string to allocated memory and convert copied string
104 to upper case
105
106 This routine allocates enough memory to hold the string <b>s</b>,
107 copies <em>s</em> to the allocated memory, and returns a pointer
108 to the allocated memory.
109
110 If <em>s</em> is NULL then empty string is returned.
111
112 \param s string
113
114 \return pointer to newly allocated upper case string
115 */
116char *G_store_upper(const char *s)
117{
118 char *u_s;
119
120 u_s = G_store(s);
121 G_str_to_upper(u_s);
122
123 return u_s;
124}
125
126/*!
127 \brief Copy string to allocated memory and convert copied string
128 to lower case
129
130 This routine allocates enough memory to hold the string <b>s</b>,
131 copies <em>s</em> to the allocated memory, and returns a pointer
132 to the allocated memory.
133
134 If <em>s</em> is NULL then empty string is returned.
135
136 \param s string
137
138 \return pointer to newly allocated lower case string
139 */
140char *G_store_lower(const char *s)
141{
142 char *l_s;
143
144 l_s = G_store(s);
146
147 return l_s;
148}
149
150/*!
151 \brief Replace all occurrences of character in string bug with new
152
153 \param[in,out] bug base string
154 \param character character to replace
155 \param new new character
156
157 \return bug string
158 */
159char *G_strchg(char *bug, char character, char new)
160{
161 char *help = bug;
162
163 while (*help) {
164 if (*help == character)
165 *help = new;
166 help++;
167 }
168 return bug;
169}
170
171/*!
172 \brief Replace all occurrences of old_str in buffer with new_str
173
174 Code example:
175 \code
176 char *name;
177 name = G_str_replace ( inbuf, ".exe", "" );
178 ...
179 G_free (name);
180 \endcode
181
182 \param buffer input string buffer
183 \param old_str string to be replaced
184 \param new_str new string
185
186 \return the newly allocated string, input buffer is unchanged
187 */
188char *G_str_replace(const char *buffer, const char *old_str,
189 const char *new_str)
190{
191 char *R;
192 const char *N, *B;
193 char *replace;
194 size_t 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)) + strlen(buffer);
223 }
224 else
225 len = strlen(buffer);
226
227 /* Allocate new replacement */
228 replace = G_malloc(len + 1);
229 if (replace == NULL)
230 return NULL;
231
232 /* Replace old_str with new_str */
233 B = buffer;
234 R = replace;
235 len = strlen(old_str);
236 while (*B != '\0') {
237 if (*B == old_str[0] && strncmp(B, old_str, len) == 0) {
238 N = new_str;
239 while (*N != '\0')
240 *R++ = *N++;
241 B += len;
242 }
243 else {
244 *R++ = *B++;
245 }
246 }
247 *R = '\0';
248
249 return replace;
250}
251
252/*!
253 \brief String concatenation
254
255 Concatenates the strings in src_strings, which consists of num_strings number
256 of strings, with the separator sep. The size of the concatenated string is
257 limited by maxsize.
258
259 \param src_strings array of strings to concatenate
260 \param num_strings count of strings in src_strings
261 \param sep separator string
262 \param maxsize maximum number of characters of returned string
263
264 \return the concatenated string (allocated)
265 */
266char *G_str_concat(const char **src_strings, int num_strings, const char *sep,
267 int maxsize)
268{
269 if (maxsize < 1 || num_strings < 1)
270 return NULL;
271
272 char *concat_str = NULL;
273 char *p = NULL;
274 char *buffer = G_malloc(maxsize * sizeof(char));
275 char *end = buffer + maxsize;
276
277 memset(buffer, 0, maxsize);
278 for (int i = 0; i < num_strings; i++) {
279 if (i == 0)
280 p = (char *)G__memccpy(buffer, src_strings[i], '\0', maxsize);
281 else {
282 if (p)
283 p = (char *)G__memccpy(p - 1, sep, '\0', end - p);
284 if (p)
285 p = (char *)G__memccpy(p - 1, src_strings[i], '\0', end - p);
286 }
287 }
288 concat_str = G_store(buffer);
289 G_free(buffer);
290
291 return concat_str;
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 */
299void 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 */
331char *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 */
364void 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 */
382void 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 */
402int 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 */
445void G_squeeze(char *line)
446{
447 char *f = line, *t = line;
448
449 /* skip over space at the beginning of the line. */
450 while (isspace(*f))
451 f++;
452
453 while (*f)
454 if (!isspace(*f))
455 *t++ = *f++;
456 else if (*++f)
457 if (!isspace(*f))
458 *t++ = ' ';
459 *t = '\0';
460 size_t length = strlen(line);
461 if (length > 0 && line[length - 1] == '\n')
462 line[length - 1] = '\0';
463}
464
465/*!
466 \brief Finds the first occurrence of the sub-string in the
467 null-terminated string ignoring case (upper or lower)
468
469 \param str string where to find sub-string
470 \param substr sub-string
471
472 \return a pointer to the first occurrence of sub-string
473 \return NULL if no occurrences are found
474 */
475char *G_strcasestr(const char *str, const char *substr)
476{
477 const char *p;
478 const char *q;
479 int length;
480
481 p = substr;
482 q = str;
483 size_t substr_length = strlen(substr);
485 return NULL;
486 length = (int)substr_length;
487
488 do {
489 /* match 1st substr char */
490 while (*q != '\0' && toupper(*q) != toupper(*p)) {
491 q++;
492 }
493 } while (*q != '\0' && G_strncasecmp(p, q, length) != 0 && q++);
494
495 if (*q == '\0') {
496 /* ran off end of str */
497 return NULL;
498 }
499
500 return (char *)q;
501}
502
503/*!
504 \brief Copy string until character found
505
506 The bytes from string src are copied to string dst. If the character c (as
507 converted to an unsigned char) occurs in the string src, the copy stops and
508 a pointer to the byte after the copy of c in the string dst is returned.
509 Otherwise, n bytes are copied, and a NULL pointer is returned.
510
511 The source and destination strings should not overlap, as the behavior
512 is undefined.
513
514 \param dst destination
515 \param src source
516 \param c stop character
517 \param n max number of bytes to copy
518
519 \return a pointer to the next character in dest after c
520 \return NULL if c was not found in the first n characters of src
521 */
522static void *G__memccpy(void *dst, const void *src, int c, size_t n)
523{
524 const char *s = src;
525 char *ret;
526
527 for (ret = dst; n; ++ret, ++s, --n) {
528 *ret = *s;
529 if ((unsigned char)*ret == (unsigned char)c)
530 return ret + 1;
531 }
532
533 return NULL;
534}
535
536static int _strncasecmp(const char *x, const char *y, int n)
537{
538 int xx, yy, i;
539
540 if (!x)
541 return y ? -1 : 0;
542 if (!y)
543 return x ? 1 : 0;
544
545 i = 1;
546 while (*x && *y) {
547 xx = *x++;
548 yy = *y++;
549 if (xx >= 'A' && xx <= 'Z')
550 xx = xx + 'a' - 'A';
551 if (yy >= 'A' && yy <= 'Z')
552 yy = yy + 'a' - 'A';
553 if (xx < yy)
554 return -1;
555 if (xx > yy)
556 return 1;
557
558 if (n > -1 && i >= n)
559 return 0;
560
561 i++;
562 }
563
564 if (*x)
565 return 1;
566 if (*y)
567 return -1;
568 return 0;
569}
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:145
#define G_malloc(n)
Definition defs/gis.h:136
#define N
int count
#define strcpy
Definition parson.c:66
double b
Definition r_raster.c:37
double t
Definition r_raster.c:37
#define NULL
Definition strings.c:25
char * G_store_lower(const char *s)
Copy string to allocated memory and convert copied string to lower case.
Definition strings.c:140
int G_str_to_sql(char *str)
Make string SQL compliant.
Definition strings.c:402
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:68
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:188
void G_str_to_upper(char *str)
Convert string to upper case.
Definition strings.c:364
void G_str_to_lower(char *str)
Convert string to lower case.
Definition strings.c:382
char * G_chop(char *line)
Chop leading and trailing white spaces.
Definition strings.c:331
char * G_strchg(char *bug, char character, char new)
Replace all occurrences of character in string bug with new.
Definition strings.c:159
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:475
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition strings.c:46
void G_squeeze(char *line)
Remove superfluous white space.
Definition strings.c:445
char * G_store(const char *s)
Copy string to allocated memory.
Definition strings.c:86
void G_strip(char *buf)
Removes all leading and trailing white space from string.
Definition strings.c:299
char * G_str_concat(const char **src_strings, int num_strings, const char *sep, int maxsize)
String concatenation.
Definition strings.c:266
char * G_store_upper(const char *s)
Copy string to allocated memory and convert copied string to upper case.
Definition strings.c:116
#define x