PageRenderTime 59ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/libcgi-1.0/src/string.c

#
C | 643 lines | 273 code | 95 blank | 275 comment | 85 complexity | eabe62fff1c3a334c85f67fc11021a89 MD5 | raw file
  1. /*
  2. LibCGI - A library to make CGI programs using C
  3. Copyright (C) 2001/2002 Rafael Steil
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. You can contact the author by e-mail: rafael@insanecorp.com
  16. */
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20. #include <stdarg.h>
  21. #include <ctype.h>
  22. #include "cgi.h"
  23. #include "error.h"
  24. /*********************************************************
  25. * STRING GROUP
  26. *********************************************************/
  27. /**
  28. * @defgroup libcgi_string Strings
  29. * General string manipulation and utilities functions
  30. * @{
  31. */
  32. /**
  33. * Same to addslashes(), except that this one only do the action while 'n' is great than 0.
  34. * @param s String to parse
  35. * @param n Number of characters to work with.
  36. * @see addslashes()
  37. * \code
  38. * char *name = "My test string is called \"foobar\"";
  39. * puts(name); // will display My test string is called "foobar"
  40. *
  41. * name = addnslashes(name, 31);
  42. * puts(name); // will display My test string is called \"foobar"
  43. * \endcode
  44. */
  45. char *addnslashes(char *s, int n)
  46. {
  47. char *tmp;
  48. int len, j = 0;
  49. if (s == NULL)
  50. return NULL;
  51. len = strlen(s);
  52. tmp = (char *)malloc(len+1);
  53. if (!tmp)
  54. return NULL;
  55. while (*s) {
  56. if ((n-- > 0) && ((*s == '\"') || (*s == '\'') || (*s == '\\'))) {
  57. len++;
  58. tmp = (char *)realloc(tmp, len);
  59. if (tmp == NULL)
  60. return NULL;
  61. tmp[j++] = '\\';
  62. tmp[j++] = *s++;
  63. }
  64. else
  65. tmp[j++] = *s++;
  66. }
  67. tmp[j] = '\0';
  68. return tmp;
  69. }
  70. /**
  71. * Add slashes to a string when necessary.
  72. * Adds a '\' in every quote ( " ), apostrophe ( ' ) or backslash ( \ )
  73. * It's useful when working with databases, for example, because
  74. * someone can try insert this caracters to try hack the application...
  75. * @param *s String to parse
  76. * @return The new string, with slashes
  77. * @see stripslashes, addnslashes
  78. *
  79. * \code
  80. * char *name = "My test string is called \"foobar\"";
  81. * puts(name); // will display My test string is called "foobar"
  82. *
  83. * name = addslashes(name);
  84. * puts(name); // will display My test string is called \"foobar\"
  85. * \endcode
  86. */
  87. char *addslashes(char *s)
  88. {
  89. return addnslashes(s, strlen(s));
  90. }
  91. /**
  92. * Strip no more than 'n' slashes from a string.
  93. * Strip the backslash character ( \ ) from a string, stopping after 'n' char
  94. * @param s String to parse
  95. * @param n Maximum number of chars to parse
  96. * @return The new string, without slashes
  97. * @see addslashes, stripslashes
  98. *
  99. * \code
  100. * char *name = "My another string is called \\\"blablabla\\\"";
  101. * puts(name); // will display My another string is called \"blablabla\"
  102. * name = stripslashes(name, 33);
  103. * puts(name); // will display My another string is called "blablabla\"
  104. * \endcode
  105. */
  106. char *stripnslashes(char *s, int n)
  107. {
  108. int j = 0;
  109. char *tmp;
  110. if (s == NULL)
  111. return NULL;
  112. tmp = (char *)malloc(strlen(s)+1);
  113. if (tmp == NULL)
  114. return NULL;
  115. while (*s) {
  116. if ((n-- > 0) && (*s == '\\'))
  117. s++;
  118. tmp[j++] = *s++;
  119. }
  120. tmp[j] = '\0';
  121. return tmp;
  122. }
  123. /**
  124. * Strip slashes from a string.
  125. * Strip the backslash character ( \ ) from a string
  126. * @param s String to parse
  127. * @return The new string, without slashes
  128. * @see addslashes, stripnslashes
  129. *
  130. * \code
  131. * char *name = "My another string is called \\\"blablabla\\\"";
  132. * puts(name); // will display My another string is called \"blablabla\"
  133. * name = stripslashes(name);
  134. * puts(name); // will display My another string is called "blablabla"
  135. * \endcode
  136. */
  137. char *stripslashes(char *str)
  138. {
  139. return stripnslashes(str, strlen(str));
  140. }
  141. /**
  142. * Strip left white spaces from a string.
  143. * @param str String to parse
  144. * @return The new string, without left spaces
  145. * @author Original code was contribuition by Erik Jansson
  146. * @see rtrim, trim
  147. *
  148. * \code
  149. * char *s = " String with spaces ";
  150. * printf("_%s_\n", s);
  151. * s = ltrim(s);
  152. * printf("_%s_\n", s);
  153. * \endcode
  154. */
  155. void ltrim(char *str)
  156. {
  157. char *s = str;
  158. while (isspace(*s))
  159. s++;
  160. while ((*str++ = *s++));
  161. }
  162. /**
  163. * Strip right white spaces from a string.
  164. * @param str String to parse
  165. * @return The new string, without left spaces
  166. * @author Original code was contribuition by Erik Jansson
  167. * @see ltrim, trim
  168. *
  169. * \code
  170. * char *s = " String with spaces ";
  171. * printf("_%s_\n", s);
  172. * s = rtrim(s);
  173. * printf("_%s_\n", s);
  174. * \endcode
  175. */
  176. void rtrim(char *str)
  177. {
  178. char *s = str;
  179. register int i;
  180. for (i = strlen(s)-1; isspace(*(s+i)); i--)
  181. *(s+i) = '\0';
  182. while ((*str++ = *s++));
  183. }
  184. /**
  185. * Strip both left and right white spaces from a string.
  186. * @param str String to parse
  187. * @return The new string, without left spaces
  188. * @author Original code was contribuition by Erik Jansson
  189. * @see ltrim, trim
  190. *
  191. * \code
  192. * char *s = " String with spaces ";
  193. * printf("_%s_\n", s);
  194. * s = trim(s);
  195. * printf("_%s_\n", s);
  196. * \endcode
  197. */
  198. void trim(char *str)
  199. {
  200. ltrim(str);
  201. rtrim(str);
  202. }
  203. /**
  204. * Copy part of a string.
  205. * Copy count characters from src, starting from start
  206. * @param src String to copy from
  207. * @param start Initial offset
  208. * @param count Number of chars to copy
  209. * @return The new string
  210. *
  211. * \code
  212. * char *part, *str = "Test one, test two";
  213. * part = substr(str, 1, 5);
  214. * puts(part); // -> est o
  215. * \endcode
  216. **/
  217. char *substr(char *src, const int start, const int count)
  218. {
  219. char *tmp;
  220. tmp = (char *)malloc(count+1);
  221. if (tmp == NULL) {
  222. libcgi_error(E_MEMORY, "%s, line %s", __FILE__, __LINE__);
  223. return NULL;
  224. }
  225. strncpy(tmp, src+start, count);
  226. tmp[count] = '\0';
  227. return tmp;
  228. }
  229. /**
  230. * Create an array from a string separated by some special char.
  231. * Divides the src string in pieces, each delimited by token
  232. * and storing the total of pieces in total
  233. * @param src String to parse
  234. * @param token Character delimiter to search.
  235. * @param total An integer variable passed as reference, which stores the total of
  236. * itens of the array
  237. * @return The array, where each item is one separeted by token
  238. *
  239. * \code
  240. *
  241. * char **pieces;
  242. * char *name = "This,is,a,string,of,test";
  243. * int total, i;
  244. * pieces = explode(name, ",", &total);
  245. * for (i = 0; i < total; i++)
  246. * printf("Piece %d: %s\n", i, *(pieces+i));
  247. * \endcode
  248. **/
  249. char **explode(char *src, const char *token, int *total)
  250. {
  251. char **str;
  252. register int i, j, count, item, start;
  253. int len;
  254. if (!src || !token) {
  255. *total = 0;
  256. return NULL;
  257. }
  258. count = item = start = 0;
  259. j = 1;
  260. len = strlen(src);
  261. // Scans the string to verify how many pieces we heave
  262. for (i = 0; i < len; i++) {
  263. if (src[i] == *token)
  264. count++;
  265. }
  266. // We don't have any piece to explode. Returning...
  267. if (count == 0) {
  268. *total = 0;
  269. return NULL;
  270. }
  271. // Allocate memory for the structure ( count lines )
  272. str = (char **)malloc(count * sizeof(char *));
  273. if (str == NULL)
  274. libcgi_error(E_MEMORY, "%s, line %s", __FILE__, __LINE__);
  275. // Now we'll going to get each piece and store it in the structure
  276. for (i = 0; i < len; i++) {
  277. if (src[i] != *token)
  278. j++;
  279. else {
  280. // Found one. Now we need to allocate memory to store data
  281. str[item] = (char *)malloc(j-start);
  282. if (str[item] == NULL) {
  283. libcgi_error(E_MEMORY, "%s, line %s", __FILE__, __LINE__);
  284. return NULL;
  285. }
  286. *(str+item) = substr(src, start, j-1);
  287. str[item][j-start-1] = '\0';
  288. item++;
  289. start = j++;
  290. }
  291. }
  292. // The last one
  293. *(str+count) = (char *)malloc(j);
  294. if (str[count] == NULL)
  295. libcgi_error(E_MEMORY, "%s, line %s", __FILE__, __LINE__);
  296. str[count] = substr(src, start, j);
  297. str[count][j-start] = '\0';
  298. *total = ++count;
  299. return str;
  300. }
  301. /**
  302. * Replace characteres in a string, but not more than 'n'.
  303. * Replace all occourences of *delim on *src with characteres pointed by *with,
  304. * stopping after 'n' char.
  305. * @param *src String to parse
  306. * @param *delim Character to search that will be replaced
  307. * @param with String to replace with
  308. * @param n Maximum number of chars to parse
  309. * @return The new string
  310. * @see str_replace
  311. *
  312. * \code
  313. * char *linux = "Linux C";
  314. * linux = str_nreplace(linux, "C", "Cool", strlen(linux));
  315. * puts(linux);
  316. * // -- OR --
  317. * char *name = "rAfAel steil";
  318. * name = str_nreplace(name, "A", "a", 3);
  319. * puts(name);
  320. * \endcode
  321. **/
  322. char *str_nreplace(char *src, const char *delim, const char *with, int n)
  323. {
  324. unsigned int w_len, i, n_len, counter;
  325. char *buf;
  326. // w_len -> width length
  327. w_len = strlen(with);
  328. n_len = strlen(src);
  329. counter = 0;
  330. buf = (char *)malloc(n_len+1);
  331. if (buf == NULL)
  332. libcgi_error(E_MEMORY, "%s, line %s", __FILE__, __LINE__);
  333. while (*src) {
  334. if ((n-- > 0) && (*src == *delim)) {
  335. // If length of *with is greater than 1, then we need
  336. // to realocate memory before copying
  337. if (w_len > 1) {
  338. n_len += w_len;
  339. buf = (char *)realloc(buf, n_len);
  340. if (buf == NULL)
  341. libcgi_error(E_MEMORY, "%s, line %s", __FILE__, __LINE__);
  342. // replace the character delimited by *delim with
  343. // the characters pointed by *with
  344. for (i = 0; i < w_len; i++)
  345. buf[counter++] = with[i];
  346. }
  347. // otherwise, only do a simple character subtitution
  348. buf[counter++] = *with;
  349. }
  350. else
  351. buf[counter++] = *src;
  352. src++;
  353. }
  354. buf[counter] = '\0';
  355. return buf;
  356. }
  357. /**
  358. * Replace characteres in a string.
  359. * Replace all occourences of *delim on *src with characteres pointed by *with.
  360. * The problem with the folowing code is that the function only searches for the
  361. * first caracter of *delim, ingoring the rest. Other problem is speed relacioned:
  362. * note that the function ever compare the length of *with to do the correct action.
  363. * @param src String to parse
  364. * @param delim Character to search that will be replaced
  365. * @param with String to replace with
  366. * @return The new string
  367. * @see str_nreplace
  368. *
  369. * \code
  370. * char *linux = "Linux C";
  371. * linux = str_replace(linux, "C", "Cool");
  372. * puts(linux);
  373. * // -- OR --
  374. * char *name = "rAfAel steil";
  375. * name = str_replace(name, "A", "a");
  376. * puts(name);
  377. * \endcode
  378. **/
  379. char *str_replace(char *str, const char *delim, const char *with)
  380. {
  381. return str_nreplace(str, delim, with, strlen(str));
  382. }
  383. // Just for compatibility with older versions of LibCGI
  384. char *replace(char *str, const char *delim, const char *with)
  385. {
  386. return str_nreplace(str, delim, with, strlen(str));
  387. }
  388. /**
  389. * Returns the position of a character in a string, but parses no more that 'n' chars
  390. * @param s String where the search will be done
  391. * @param ch Character to search
  392. * @param count Maximum number of chars to parse before exiting the function
  393. * @see strpos()
  394. */
  395. int strnpos(char *s, char *ch, unsigned int count)
  396. {
  397. register unsigned int pos = 0, i;
  398. for (i = 0; i <= count && *s; i++) {
  399. if (*s++ == *ch)
  400. return pos;
  401. pos++;
  402. }
  403. return -1;
  404. }
  405. /**
  406. * Returns the position of a character in a string.
  407. * @param s String where the search will be done
  408. * @param ch Character to search
  409. * @param count Maximum number of ch to search
  410. * @see strnpos()
  411. **/
  412. int strpos(char *s, char *ch)
  413. {
  414. return strnpos(s, ch, strlen(s));
  415. }
  416. /**
  417. * Delete characters from a string.
  418. * Delete count characters of s, starting in start
  419. * @param s String to search
  420. * @param start Initial offset to begin search
  421. * @param count Number of characteres to delete
  422. * @return The new string
  423. * @see strndel()
  424. *
  425. * \code
  426. * *txt = "Some text to test anything";
  427. * puts(txt);
  428. * txt = strdel(txt, 2, 8);
  429. * puts(txt);
  430. * \endcode
  431. **/
  432. char *strdel(char *s, int start, int count)
  433. {
  434. register int i, len, contador = 0;
  435. register char *tmp;
  436. len = strlen(s);
  437. if ((count+start) > len)
  438. return NULL;
  439. tmp = (char *)malloc(len - count + 1);
  440. if (tmp == NULL)
  441. libcgi_error(E_MEMORY, "%s, line %s", __FILE__, __LINE__);
  442. for (i = 0; i < len; i++) {
  443. if ((i >= start) && (i < (start+count)))
  444. s++;
  445. else
  446. tmp[contador++] = *s++;
  447. }
  448. tmp[contador] = '\0';
  449. return tmp;
  450. }
  451. /**
  452. * Reads an entire line.
  453. * Reads a line from the file specified by the file pointer passed
  454. * as parameter. This function is intead to replace the non-portable
  455. * GNU getline() function.
  456. *
  457. * @param s File pointer to the file to read from.
  458. * @return String containing the line read or NULL if no more line are available
  459. * @author Robert Csok
  460. **/
  461. char *recvline(FILE *s)
  462. {
  463. int i = 0, ch;
  464. char *buf = 0;
  465. size_t siz = 0;
  466. for (; (ch = fgetc(s)) != EOF; i++) {
  467. if (i == siz)
  468. buf = realloc(buf, siz += BUFSIZ);
  469. buf[i] = ch;
  470. if (buf[i] == '\n') {
  471. buf[i] = '\0';
  472. if (i > 0 && buf[i-1] == '\r')
  473. buf[i-1] = '\0';
  474. return buf;
  475. }
  476. }
  477. if (i > 0) {
  478. if (i == siz) buf = realloc(buf, siz + 1);
  479. buf[i] = '\0';
  480. return buf;
  481. }
  482. return NULL;
  483. }
  484. /**
  485. * Makes a string.
  486. * Works like printf(), with the difference
  487. * that it returns a string that is the
  488. * concatenation of the values passed as parameter.
  489. *
  490. * @param *s Inicial String and optionally formatation parameters ( just %s is allowed )
  491. * @return The new String
  492. * \code
  493. * char *sql = make_string("INSERT INTO myTable VALUES ('%s', '%s', '%s')", varValue1, varValue2, varValue3);
  494. * \endcode
  495. * \todo String limits/error checking
  496. **/
  497. char *make_string(char *s, ...)
  498. {
  499. va_list ptr, bkp;
  500. unsigned int len;
  501. char *str_return, *a, *str;
  502. str = s;
  503. va_start(ptr, s);
  504. va_copy(bkp, ptr);
  505. len = strlen(s);
  506. while (*str) {
  507. if (*str == '%') {
  508. str++;
  509. switch (*str) {
  510. case 's':
  511. a = (char *)va_arg(ptr, char *);
  512. if (a)
  513. len += strlen(a);
  514. break;
  515. }
  516. }
  517. str++;
  518. }
  519. str_return = (char *)malloc((len + 1) * sizeof(char));
  520. if (!str_return)
  521. libcgi_error(E_MEMORY, "%s, line %s", __FILE__, __LINE__);
  522. vsprintf(str_return, s, bkp);
  523. va_end(ptr);
  524. va_end(bkp);
  525. str_return[len] = '\0';
  526. return str_return;
  527. }
  528. char *strcat_ex(const char *str1, const char *str2)
  529. {
  530. char *new_str;
  531. unsigned int len;
  532. if (!str1 || !str2)
  533. return NULL;
  534. len = strlen(str1) + strlen(str2);
  535. new_str = (char *)malloc((len + 1) * sizeof(char*));
  536. if (!new_str)
  537. libcgi_error(E_MEMORY, "%s, line %s", __FILE__, __LINE__);
  538. sprintf(new_str, "%s%s", str1, str2);
  539. new_str[len] = '\0';
  540. return new_str;
  541. }
  542. /**
  543. * @}
  544. */