GRASS GIS 8 Programmer's Manual 8.2.0(2022)-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
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, 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 */
268char *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*/
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 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*/
328char *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*/
360void 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*/
378void 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*/
398int 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*/
441void 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*/
472char *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 */
516static 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
530static 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}
double b
double l
double t
int count
char * dst
Definition: lz4.h:599
#define NULL
Definition: strings.c:26
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:398
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:360
void G_str_to_lower(char *str)
Convert string to lower case.
Definition: strings.c:378
char * G_chop(char *line)
Chop leading and trailing white spaces.
Definition: strings.c:328
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:472
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:441
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:268
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