GRASS GIS 8 Programmer's Manual 8.4.1(2025)-45ca3179ab
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 (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
29static void *G__memccpy(void *, const void *, int, size_t);
30static 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 */
47int 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 */
69int 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 */
87char *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 */
117char *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 */
141char *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 */
160char *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 */
189char *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 */
267char *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 */
300void 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 */
332char *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 */
365void 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 */
383void 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 */
403int 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 */
446void 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 */
477char *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 */
521static 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
535static 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 *buf)
Free allocated memory.
Definition alloc.c:150
#define NULL
Definition ccmath.h:32
double b
double l
double t
int count
#define strcpy
Definition parson.c:62
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_str_to_sql(char *str)
Make string SQL compliant.
Definition strings.c:403
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_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:365
void G_str_to_lower(char *str)
Convert string to lower case.
Definition strings.c:383
char * G_chop(char *line)
Chop leading and trailing white spaces.
Definition strings.c:332
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_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_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_store(const char *s)
Copy string to allocated memory.
Definition strings.c:87
void G_strip(char *buf)
Removes all leading and trailing white space from string.
Definition strings.c:300
char * G_str_concat(const char **src_strings, int num_strings, const char *sep, int maxsize)
String concatenation.
Definition strings.c:267
char * G_store_upper(const char *s)
Copy string to allocated memory and convert copied string to upper case.
Definition strings.c:117
#define x