strings.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. /*!
  2. \file lib/gis/strings.c
  3. \brief GIS Library - string/chring movement functions
  4. \todo merge interesting functions from ../datetime/scan.c here
  5. (C) 1999-2008, 2011 by the GRASS Development Team
  6. This program is free software under the GNU General Public License
  7. (>=v2). Read the file COPYING that comes with GRASS for details.
  8. \author Dave Gerdes (USACERL)
  9. \author Michael Shapiro (USACERL)
  10. \author Amit Parghi (USACERL)
  11. \author Bernhard Reiter (Intevation GmbH, Germany) and many others
  12. */
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <ctype.h>
  16. #include <sys/types.h>
  17. #include <grass/gis.h>
  18. #ifndef NULL
  19. #define NULL 0
  20. #endif
  21. static void *G__memccpy(void *, const void *, int, size_t);
  22. static int _strncasecmp(const char *, const char *, int);
  23. /*!
  24. \brief String compare ignoring case (upper or lower)
  25. Returning a value that has the same sign as the difference between
  26. the first differing pair of characters.
  27. Note: strcasecmp() is affected by the locale (LC_CTYPE), while
  28. G_strcasecmp() isn't.
  29. \param x first string to compare
  30. \param y second string to compare
  31. \return 0 the two strings are equal
  32. \return -1, 1
  33. */
  34. int G_strcasecmp(const char *x, const char *y)
  35. {
  36. return _strncasecmp(x, y, -1);
  37. }
  38. /*!
  39. \brief String compare ignoring case (upper or lower) - limited
  40. number of characters
  41. Returning a value that has the same sign as the difference between
  42. the first differing pair of characters.
  43. Note: strcasecmp() is affected by the locale (LC_CTYPE), while
  44. G_strcasecmp() isn't.
  45. \param x first string to compare
  46. \param y second string to compare
  47. \param n number or characters to compare
  48. \return 0 the two strings are equal
  49. \return -1, 1
  50. */
  51. int G_strncasecmp(const char *x, const char *y, int n)
  52. {
  53. return _strncasecmp(x, y, n);
  54. }
  55. /*!
  56. \brief Copy string to allocated memory.
  57. This routine allocates enough memory to hold the string <b>s</b>,
  58. copies <em>s</em> to the allocated memory, and returns a pointer
  59. to the allocated memory.
  60. If <em>s</em> is NULL then empty string is returned.
  61. \param s string
  62. \return pointer to newly allocated string
  63. */
  64. char *G_store(const char *s)
  65. {
  66. char *buf;
  67. if (s == NULL) {
  68. buf = G_malloc(sizeof(char));
  69. buf[0] = '\0';
  70. }
  71. else {
  72. buf = G_malloc(strlen(s) + 1);
  73. strcpy(buf, s);
  74. }
  75. return buf;
  76. }
  77. /*!
  78. \brief Copy string to allocated memory and convert copied string
  79. to upper case
  80. This routine allocates enough memory to hold the string <b>s</b>,
  81. copies <em>s</em> to the allocated memory, and returns a pointer
  82. to the allocated memory.
  83. If <em>s</em> is NULL then empty string is returned.
  84. \param s string
  85. \return pointer to newly allocated upper case string
  86. */
  87. char *G_store_upper(const char *s)
  88. {
  89. char *u_s;
  90. u_s = G_store(s);
  91. G_str_to_upper(u_s);
  92. return u_s;
  93. }
  94. /*!
  95. \brief Copy string to allocated memory and convert copied string
  96. to lower case
  97. This routine allocates enough memory to hold the string <b>s</b>,
  98. copies <em>s</em> to the allocated memory, and returns a pointer
  99. to the allocated memory.
  100. If <em>s</em> is NULL then empty string is returned.
  101. \param s string
  102. \return pointer to newly allocated lower case string
  103. */
  104. char *G_store_lower(const char *s)
  105. {
  106. char *l_s;
  107. l_s = G_store(s);
  108. G_str_to_lower(l_s);
  109. return l_s;
  110. }
  111. /*!
  112. \brief Replace all occurrences of character in string bug with new
  113. \param[in,out] bug base string
  114. \param character character to replace
  115. \param new new character
  116. \return bug string
  117. */
  118. char *G_strchg(char *bug, char character, char new)
  119. {
  120. char *help = bug;
  121. while (*help) {
  122. if (*help == character)
  123. *help = new;
  124. help++;
  125. }
  126. return bug;
  127. }
  128. /*!
  129. \brief Replace all occurrences of old_str in buffer with new_str
  130. Code example:
  131. \code
  132. char *name;
  133. name = G_str_replace ( inbuf, ".exe", "" );
  134. ...
  135. G_free (name);
  136. \endcode
  137. \param buffer input string buffer
  138. \param old_str string to be replaced
  139. \param new_str new string
  140. \return the newly allocated string, input buffer is unchanged
  141. */
  142. char *G_str_replace(const char *buffer, const char *old_str, const char *new_str)
  143. {
  144. char *R;
  145. const char *N, *B;
  146. char *replace;
  147. int count, len;
  148. /* Make sure old_str and new_str are not NULL */
  149. if (old_str == NULL || new_str == NULL)
  150. return G_store(buffer);
  151. /* Make sure buffer is not NULL */
  152. if (buffer == NULL)
  153. return NULL;
  154. /* Make sure old_str occurs */
  155. B = strstr(buffer, old_str);
  156. if (B == NULL)
  157. /* return NULL; */
  158. return G_store(buffer);
  159. if (strlen(new_str) > strlen(old_str)) {
  160. /* Count occurrences of old_str */
  161. count = 0;
  162. len = strlen(old_str);
  163. B = buffer;
  164. while (B != NULL && *B != '\0') {
  165. B = strstr(B, old_str);
  166. if (B != NULL) {
  167. B += len;
  168. count++;
  169. }
  170. }
  171. len = count * (strlen(new_str) - strlen(old_str))
  172. + strlen(buffer);
  173. }
  174. else
  175. len = strlen(buffer);
  176. /* Allocate new replacement */
  177. replace = G_malloc(len + 1);
  178. if (replace == NULL)
  179. return NULL;
  180. /* Replace old_str with new_str */
  181. B = buffer;
  182. R = replace;
  183. len = strlen(old_str);
  184. while (*B != '\0') {
  185. if (*B == old_str[0] && strncmp(B, old_str, len) == 0) {
  186. N = new_str;
  187. while (*N != '\0')
  188. *R++ = *N++;
  189. B += len;
  190. }
  191. else {
  192. *R++ = *B++;
  193. }
  194. }
  195. *R = '\0';
  196. return replace;
  197. }
  198. /*!
  199. \brief String concatenation
  200. Concatenates the strings in src_strings, which consists of num_strings number
  201. of strings, with the separator sep. The size of the concatenated string is
  202. limited by maxsize.
  203. \param src_strings array of strings to concatenate
  204. \param num_strings count of strings in src_strings
  205. \param sep separator string
  206. \param maxsize maximum number of characters of returned string
  207. \return the concatenated string (allocated)
  208. */
  209. char *G_str_concat(const char **src_strings, int num_strings,
  210. const char *sep, int maxsize)
  211. {
  212. char buffer[maxsize];
  213. int i;
  214. char *end = buffer + maxsize;
  215. char *p = NULL;
  216. if (maxsize < 1 || num_strings < 1)
  217. return NULL;
  218. memset(buffer, 0, sizeof(buffer));
  219. for (i = 0; i < num_strings; i++) {
  220. if (i == 0)
  221. p = (char *)G__memccpy(buffer, src_strings[i], '\0', maxsize);
  222. else {
  223. if (p)
  224. p = (char *)G__memccpy(p - 1, sep, '\0', end - p);
  225. if (p)
  226. p = (char *)G__memccpy(p - 1, src_strings[i], '\0', end - p);
  227. }
  228. }
  229. return G_store(buffer);
  230. }
  231. /*!
  232. \brief Removes all leading and trailing white space from string.
  233. \param[in,out] buf buffer to be worked on
  234. */
  235. void G_strip(char *buf)
  236. {
  237. char *a, *b;
  238. /* remove leading white space */
  239. for (a = b = buf; *a == ' ' || *a == '\t'; a++) ;
  240. if (a != b)
  241. while ((*b++ = *a++)) ;
  242. /* remove trailing white space */
  243. for (a = buf; *a; a++) ;
  244. if (a != buf) {
  245. for (a--; *a == ' ' || *a == '\t'; a--) ;
  246. a++;
  247. *a = 0;
  248. }
  249. }
  250. /*!
  251. \brief Chop leading and trailing white spaces.
  252. \verbatim space, \f, \n, \r, \t, \v \endverbatim
  253. Modified copy of G_squeeze() by RB in March 2000.
  254. \param line buffer to be worked on
  255. \return pointer to string
  256. */
  257. char *G_chop(char *line)
  258. {
  259. char *f = line, *t = line;
  260. while (isspace(*f)) /* go to first non white-space char */
  261. f++;
  262. if (!*f) { /* no more chars in string */
  263. *t = '\0';
  264. return (line);
  265. }
  266. for (t = f; *t; t++) /* go from first non white-space char to end */
  267. ;
  268. while (isspace(*--t)) ;
  269. *++t = '\0'; /* remove trailing white-spaces */
  270. if (f != line) {
  271. t = line;
  272. while (*f) /* leading white spaces, shift */
  273. *t++ = *f++;
  274. *t = '\0';
  275. }
  276. return (line);
  277. }
  278. /*!
  279. \brief Convert string to upper case
  280. \param[in,out] str pointer to string
  281. */
  282. void G_str_to_upper(char *str)
  283. {
  284. int i = 0;
  285. if (!str)
  286. return;
  287. while (str[i]) {
  288. str[i] = toupper(str[i]);
  289. i++;
  290. }
  291. }
  292. /*!
  293. \brief Convert string to lower case
  294. \param[in,out] str pointer to string
  295. */
  296. void G_str_to_lower(char *str)
  297. {
  298. int i = 0;
  299. if (!str)
  300. return;
  301. while (str[i]) {
  302. str[i] = tolower(str[i]);
  303. i++;
  304. }
  305. }
  306. /*!
  307. \brief Make string SQL compliant
  308. \param[in,out] str pointer to string
  309. \return number of changed characters
  310. */
  311. int G_str_to_sql(char *str)
  312. {
  313. int count;
  314. char *c;
  315. count = 0;
  316. if (!str || !*str)
  317. return 0;
  318. c = str;
  319. while (*c) {
  320. *c = toascii(*c);
  321. if (!(*c >= 'A' && *c <= 'Z') && !(*c >= 'a' && *c <= 'z') &&
  322. !(*c >= '0' && *c <= '9')) {
  323. *c = '_';
  324. count++;
  325. }
  326. c++;
  327. }
  328. c = str;
  329. if (!(*c >= 'A' && *c <= 'Z') && !(*c >= 'a' && *c <= 'z')) {
  330. *c = 'x';
  331. count++;
  332. }
  333. return count;
  334. }
  335. /*!
  336. \brief Remove superfluous white space.
  337. Leading and trailing white space is removed from the string
  338. <b>line</b> and internal white space which is more than one character
  339. is reduced to a single space character. White space here means
  340. spaces, tabs, linefeeds, newlines, and formfeeds.
  341. \param[in,out] line
  342. \return Pointer to <b>line</b>
  343. */
  344. void G_squeeze(char *line)
  345. {
  346. char *f = line, *t = line;
  347. int l;
  348. /* skip over space at the beginning of the line. */
  349. while (isspace(*f))
  350. f++;
  351. while (*f)
  352. if (!isspace(*f))
  353. *t++ = *f++;
  354. else if (*++f)
  355. if (!isspace(*f))
  356. *t++ = ' ';
  357. *t = '\0';
  358. l = strlen(line) - 1;
  359. if (*(line + l) == '\n')
  360. *(line + l) = '\0';
  361. }
  362. /*!
  363. \brief Finds the first occurrence of the sub-string in the
  364. null-terminated string ignoring case (upper or lower)
  365. \param str string where to find sub-string
  366. \param substr sub-string
  367. \return a pointer to the first occurrence of sub-string
  368. \return NULL if no occurrences are found
  369. */
  370. char *G_strcasestr(const char *str, const char *substr)
  371. {
  372. const char *p;
  373. const char *q;
  374. int length;
  375. p = substr;
  376. q = str;
  377. length = strlen(substr);
  378. do {
  379. /* match 1st substr char */
  380. while (*q != '\0' && toupper(*q) != toupper(*p)) {
  381. q++;
  382. }
  383. } while (*q != '\0' && G_strncasecmp(p, q, length) != 0 && q++);
  384. if (*q == '\0') {
  385. /* ran off end of str */
  386. return NULL;
  387. }
  388. return (char *) q;
  389. }
  390. /*!
  391. \brief Copy string until character found
  392. The bytes from string src are copied to string dst. If the character c (as
  393. converted to an unsigned char) occurs in the string src, the copy stops and
  394. a pointer to the byte after the copy of c in the string dst is returned.
  395. Otherwise, n bytes are copied, and a NULL pointer is returned.
  396. The source and destination strings should not overlap, as the behavior
  397. is undefined.
  398. \param dst destination
  399. \param src source
  400. \param c stop character
  401. \param n max number of bytes to copy
  402. \return a pointer to the next character in dest after c
  403. \return NULL if c was not found in the first n characters of src
  404. */
  405. static void *G__memccpy(void *dst, const void *src, int c, size_t n)
  406. {
  407. const char *s = src;
  408. char *ret;
  409. for (ret = dst; n; ++ret, ++s, --n) {
  410. *ret = *s;
  411. if ((unsigned char)*ret == (unsigned char)c)
  412. return ret + 1;
  413. }
  414. return NULL;
  415. }
  416. static int _strncasecmp(const char *x, const char *y, int n)
  417. {
  418. int xx, yy, i;
  419. if (!x)
  420. return y ? -1 : 0;
  421. if (!y)
  422. return x ? 1 : 0;
  423. i = 1;
  424. while (*x && *y) {
  425. xx = *x++;
  426. yy = *y++;
  427. if (xx >= 'A' && xx <= 'Z')
  428. xx = xx + 'a' - 'A';
  429. if (yy >= 'A' && yy <= 'Z')
  430. yy = yy + 'a' - 'A';
  431. if (xx < yy)
  432. return -1;
  433. if (xx > yy)
  434. return 1;
  435. if (n > -1 && i >= n)
  436. return 0;
  437. i++;
  438. }
  439. if (*x)
  440. return 1;
  441. if (*y)
  442. return -1;
  443. return 0;
  444. }