qLibc
qstring.c
Go to the documentation of this file.
1 /******************************************************************************
2  * qLibc
3  *
4  * Copyright (c) 2010-2015 Seungyoung Kim.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *****************************************************************************/
28 
29 /**
30  * @file qstring.c String APIs.
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stdbool.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <ctype.h>
39 #include <unistd.h>
40 #include <sys/time.h>
41 #include "qinternal.h"
42 #include "utilities/qencode.h"
43 #include "utilities/qhash.h"
44 #include "utilities/qstring.h"
45 
46 /**
47  * Remove white spaces(including CR, LF) from head and tail of the string.
48  *
49  * @param str source string
50  *
51  * @return a pointer of source string if rsuccessful, otherewise returns NULL
52  *
53  * @note This modify source string directly.
54  */
55 char *qstrtrim(char *str) {
56  if (str == NULL)
57  return NULL;
58 
59  char *ss, *se;
60  for (ss = str; *ss == ' ' || *ss == '\t' || *ss == '\r' || *ss == '\n';
61  ss++)
62  ;
63  for (se = ss; *se != '\0'; se++)
64  ;
65  for (se--;
66  se >= ss
67  && (*se == ' ' || *se == '\t' || *se == '\r' || *se == '\n');
68  se--)
69  ;
70  se++;
71  *se = '\0';
72 
73  if (ss > str) {
74  size_t len = (se - ss) + 1;
75  memmove(str, ss, len);
76  }
77 
78  return str;
79 }
80 
81 /**
82  * Remove heading white spaces of the string.
83  *
84  * @param str source string
85  *
86  * @return a pointer of source string if rsuccessful, otherewise returns NULL
87  *
88  * @note This modify source string directly.
89  */
90 char *qstrtrim_head(char *str) {
91  if (str == NULL)
92  return NULL;
93 
94  char *ss;
95  for (ss = str; *ss == ' ' || *ss == '\t' || *ss == '\r' || *ss == '\n';
96  ss++)
97  ;
98 
99  if (ss > str) {
100  size_t len = strlen(ss) + 1;
101  memmove(str, ss, len);
102  }
103 
104  return str;
105 }
106 
107 /**
108  * Remove tailing white spaces(including CR, LF) of the string.
109  *
110  * @param str source string
111  *
112  * @return a pointer of source string if rsuccessful, otherewise returns NULL
113  *
114  * @note This modify source string directly.
115  */
116 char *qstrtrim_tail(char *str) {
117  if (str == NULL)
118  return NULL;
119 
120  char *se;
121  for (se = str + strlen(str) - 1;
122  se >= str
123  && (*se == ' ' || *se == '\t' || *se == '\r' || *se == '\n');
124  se--)
125  ;
126  se++;
127  *se = '\0';
128 
129  return str;
130 }
131 
132 /**
133  * Remove character from head and tail of the string.
134  *
135  * @param str source string
136  * @param head heading character
137  * @param tail tailing character
138  *
139  * @return a pointer of source string if successful, otherewise returns NULL
140  *
141  * @note This modify source string directly.
142  *
143  * @code
144  * char *str = strdup(" \"hello world\" ");
145  * qstrtrim(str); // to remove white spaces
146  * qstrunchar(str, '"', '"'); // to unquote
147  * @endcode
148  */
149 char *qstrunchar(char *str, char head, char tail) {
150  if (str == NULL)
151  return NULL;
152 
153  int len = strlen(str);
154  if (len >= 2 && str[0] == head && str[len - 1] == tail) {
155  memmove(str, str + 1, len - 2);
156  str[len - 2] = '\0';
157  } else {
158  return NULL;
159  }
160 
161  return str;
162 }
163 
164 /**
165  * Replace string or tokens as word from source string with given mode.
166  *
167  * @param mode replacing mode
168  * @param srcstr source string
169  * @param tokstr token or string
170  * @param word target word to be replaced
171  *
172  * @return a pointer of malloced or source string depending on the mode if
173  * successful, otherewise returns NULL
174  *
175  * @note
176  * The mode argument has two separated character. First character
177  * is used to decide replacing method and can be 't' or 's'.
178  * The character 't' and 's' stand on [t]oken and [s]tring.
179  *
180  * When 't' is given each character of the token string(third argument)
181  * will be compared with source string individually. If matched one
182  * is found. the character will be replaced with given work.
183  *
184  * If 's' is given instead of 't'. Token string will be analyzed
185  * only one chunk word. So the replacement will be occured when
186  * the case of whole word matched.
187  *
188  * Second character is used to decide returning memory type and
189  * can be 'n' or 'r' which are stand on [n]ew and [r]eplace.
190  *
191  * When 'n' is given the result will be placed into new array so
192  * you should free the return string after using. Instead of this,
193  * you can also use 'r' character to modify source string directly.
194  * In this case, given source string should have enough space. Be
195  * sure that untouchable value can not be used for source string.
196  *
197  * So there are four associatable modes such like below.
198  *
199  * Mode "tn" : [t]oken replacing & putting the result into [n]ew array.
200  * Mode "tr" : [t]oken replacing & [r]eplace source string directly.
201  * Mode "sn" : [s]tring replacing & putting the result into [n]ew array.
202  * Mode "sr" : [s]tring replacing & [r]eplace source string directly.
203  *
204  * @code
205  * char srcstr[256], *retstr;
206  * char mode[4][2+1] = {"tn", "tr", "sn", "sr"};
207  *
208  * for(i = 0; i < 4; i++) {
209  * strcpy(srcstr, "Welcome to The qDecoder Project.");
210  *
211  * printf("before %s : srcstr = %s\n", mode[i], srcstr);
212  * retstr = qstrreplace(mode[i], srcstr, "The", "_");
213  * printf("after %s : srcstr = %s\n", mode[i], srcstr);
214  * printf(" retstr = %s\n\n", retstr);
215  * if(mode[i][1] == 'n') free(retstr);
216  * }
217  *
218  * --[Result]--
219  * before tn : srcstr = Welcome to The qDecoder Project.
220  * after tn : srcstr = Welcome to The qDecoder Project.
221  * retstr = W_lcom_ _o ___ qD_cod_r Proj_c_.
222  *
223  * before tr : srcstr = Welcome to The qDecoder Project.
224  * after tr : srcstr = W_lcom_ _o ___ qD_cod_r Proj_c_.
225  * retstr = W_lcom_ _o ___ qD_cod_r Proj_c_.
226  *
227  * before sn : srcstr = Welcome to The qDecoder Project.
228  * after sn : srcstr = Welcome to The qDecoder Project.
229  * retstr = Welcome to _ qDecoder Project.
230  *
231  * before sr : srcstr = Welcome to The qDecoder Project.
232  * after sr : srcstr = Welcome to _ qDecoder Project.
233  * retstr = Welcome to _ qDecoder Project.
234  * @endcode
235  */
236 char *qstrreplace(const char *mode, char *srcstr, const char *tokstr,
237  const char *word) {
238  if (mode == NULL || strlen(mode) != 2|| srcstr == NULL || tokstr == NULL
239  || word == NULL) {
240  DEBUG("Unknown mode \"%s\".", mode);
241  return NULL;
242  }
243 
244  char *newstr, *newp, *srcp, *tokenp, *retp;
245  newstr = newp = srcp = tokenp = retp = NULL;
246 
247  char method = mode[0], memuse = mode[1];
248  int maxstrlen, tokstrlen;
249 
250  /* Put replaced string into malloced 'newstr' */
251  if (method == 't') { /* Token replace */
252  maxstrlen = strlen(srcstr) * ((strlen(word) > 0) ? strlen(word) : 1);
253  newstr = (char *) malloc(maxstrlen + 1);
254 
255  for (srcp = (char *) srcstr, newp = newstr; *srcp; srcp++) {
256  for (tokenp = (char *) tokstr; *tokenp; tokenp++) {
257  if (*srcp == *tokenp) {
258  char *wordp;
259  for (wordp = (char *) word; *wordp; wordp++) {
260  *newp++ = *wordp;
261  }
262  break;
263  }
264  }
265  if (!*tokenp)
266  *newp++ = *srcp;
267  }
268  *newp = '\0';
269  } else if (method == 's') { /* String replace */
270  if (strlen(word) > strlen(tokstr)) {
271  maxstrlen = ((strlen(srcstr) / strlen(tokstr)) * strlen(word))
272  + (strlen(srcstr) % strlen(tokstr));
273  } else {
274  maxstrlen = strlen(srcstr);
275  }
276  newstr = (char *) malloc(maxstrlen + 1);
277  tokstrlen = strlen(tokstr);
278 
279  for (srcp = srcstr, newp = newstr; *srcp; srcp++) {
280  if (!strncmp(srcp, tokstr, tokstrlen)) {
281  char *wordp;
282  for (wordp = (char *) word; *wordp; wordp++)
283  *newp++ = *wordp;
284  srcp += tokstrlen - 1;
285  } else
286  *newp++ = *srcp;
287  }
288  *newp = '\0';
289  } else {
290  DEBUG("Unknown mode \"%s\".", mode);
291  return NULL;
292  }
293 
294  /* decide whether newing the memory or replacing into exist one */
295  if (memuse == 'n')
296  retp = newstr;
297  else if (memuse == 'r') {
298  strcpy(srcstr, newstr);
299  free(newstr);
300  retp = srcstr;
301  } else {
302  DEBUG("Unknown mode \"%s\".", mode);
303  free(newstr);
304  return NULL;
305  }
306 
307  return retp;
308 }
309 
310 /**
311  * Copy src string to dst. The dst string array will be always terminated by
312  * NULL character. Also allows overlap between src and dst.
313  *
314  * @param dst a pointer of the string to be copied
315  * @param size the size of dst character arrary
316  * @param src a pointer of source string
317  *
318  * @return always returns a pointer of dst
319  */
320 char *qstrcpy(char *dst, size_t size, const char *src) {
321  if (dst == NULL || size == 0 || src == NULL)
322  return dst;
323 
324  size_t nbytes = strlen(src);
325  return qstrncpy(dst, size, src, nbytes);
326 }
327 
328 /**
329  * Copy src string to dst no more than n bytes. The dst string array will be
330  * always terminated by NULL character. Also allows overlap between src and dst.
331  *
332  * @param dst a pointer of the string to be copied
333  * @param size the size of dst character arrary
334  * @param src a pointer of source string
335  * @param nbytes number of bytes to copy
336  *
337  * @return always returns a pointer of dst
338  */
339 char *qstrncpy(char *dst, size_t size, const char *src, size_t nbytes) {
340  if (dst == NULL || size == 0 || src == NULL)
341  return dst;
342 
343  if (nbytes >= size)
344  nbytes = size - 1;
345  memmove((void *) dst, (void *) src, nbytes);
346  dst[nbytes] = '\0';
347 
348  return dst;
349 }
350 
351 /**
352  * Duplicate a formatted string.
353  *
354  * @param format string format
355  *
356  * @return a pointer of malloced string if successful, otherwise returns NULL
357  */
358 char *qstrdupf(const char *format, ...) {
359  char *str;
360  DYNAMIC_VSPRINTF(str, format);
361  if (str == NULL)
362  return NULL;
363 
364  char *dup = strdup(str);
365  free(str);
366 
367  return dup;
368 }
369 
370 /**
371  * Duplicate a substing set
372  *
373  * @param str a pointer of original string
374  * @param start substring which is started with this
375  * @param end substring which is ended with this
376  *
377  * @return a pointer of malloced string if successful, otherwise returns NULL
378  */
379 char *qstrdup_between(const char *str, const char *start, const char *end) {
380  char *s;
381  if ((s = strstr(str, start)) == NULL)
382  return NULL;
383  s += strlen(start);
384 
385  char *e;
386  if ((e = strstr(s, end)) == NULL)
387  return NULL;
388 
389  int len = e - s;
390 
391  char *buf = (char *) malloc(sizeof(char) * (len + 1));
392  strncpy(buf, s, len);
393  buf[len] = '\0';
394 
395  return buf;
396 }
397 
398 /**
399  * Duplicate a copy of memory data.
400  *
401  * @param data source data
402  * @param size data size
403  *
404  * @return a pointer of malloced data which's content is identical to source data.
405  */
406 void *qmemdup(const void *data, size_t size) {
407  if (data == NULL || size == 0) {
408  return NULL;
409  }
410 
411  void *newdata = malloc(size);
412  if (newdata == NULL) {
413  return NULL;
414  }
415 
416  memcpy(newdata, data, size);
417  return newdata;
418 }
419 
420 /**
421  * Append formatted string to the end of the source str
422  *
423  * @param str a pointer of original string
424  * @param format string format to append
425  *
426  * @return a pointer of str if successful, otherwise returns NULL
427  */
428 char *qstrcatf(char *str, const char *format, ...) {
429  char *buf;
430  DYNAMIC_VSPRINTF(buf, format);
431  if (buf == NULL)
432  return NULL;
433 
434  char *ret = strcat(str, buf);
435  free(buf);
436  return ret;
437 }
438 
439 /**
440  * Get one line from the string offset.
441  *
442  * @param buf buffer pointer
443  * @param size buffer size
444  * @param offset a offset pointer which point source string
445  *
446  * @return a pointer of buffer if successful, otherwise(EOF) returns NULL
447  *
448  * @note
449  * CR and LF will not be stored.
450  *
451  * @code
452  * char *text="Hello\nWorld";
453  *
454  * char *offset = text;
455  * char buf[1024];
456  * while(qstrgets(buf, sizeof(buf), &offset) == NULL) {
457  * printf("%s\n", buf);
458  * }
459  * @endcode
460  */
461 char *qstrgets(char *buf, size_t size, char **offset) {
462  if (offset == NULL || *offset == NULL || **offset == '\0')
463  return NULL;
464 
465  size_t i;
466  char *from = *offset;
467  char *to = buf;
468  for (i = 0; *from != '\0' && i < (size - 1); i++, from++) {
469  if (*from == '\r')
470  continue;
471  if (*from == '\n') {
472  from++;
473  break;
474  }
475  *to = *from;
476  to++;
477  }
478  *to = '\0';
479  *offset = from;
480 
481  return buf;
482 }
483 
484 /**
485  * Reverse the order of characters in the string
486  *
487  * @param str a pointer of source string
488  *
489  * @return always returns a pointer of str
490  *
491  * @note This modify str directly.
492  */
493 char *qstrrev(char *str) {
494  if (str == NULL)
495  return str;
496 
497  char *p1, *p2;
498  for (p1 = str, p2 = str + (strlen(str) - 1); p2 > p1; p1++, p2--) {
499  char t = *p1;
500  *p1 = *p2;
501  *p2 = t;
502  }
503 
504  return str;
505 }
506 
507 /**
508  * Convert character to bigger character.
509  *
510  * @param str a pointer of source string
511  *
512  * @return always returns a pointer of str
513  *
514  * @note This modify str directly.
515  */
516 char *qstrupper(char *str) {
517  char *cp;
518 
519  if (!str)
520  return NULL;
521  for (cp = str; *cp; cp++)
522  if (*cp >= 'a' && *cp <= 'z')
523  *cp -= 32;
524  return str;
525 }
526 
527 /**
528  * Convert character to lower character.
529  *
530  * @param str a pointer of source string
531  *
532  * @return always returns a pointer of str
533  *
534  * @note This modify str directly.
535  */
536 char *qstrlower(char *str) {
537  char *cp;
538 
539  if (!str)
540  return NULL;
541  for (cp = str; *cp; cp++)
542  if (*cp >= 'A' && *cp <= 'Z')
543  *cp += 32;
544  return str;
545 }
546 
547 /**
548  * Split string into tokens
549  *
550  * @param str source string
551  * @param delimiters string that specifies a set of delimiters that may
552  * surround the token being extracted
553  * @param retstop stop delimiter character will be stored. it can be NULL
554  * if you don't want to know.
555  * @param offset integer pointer used for store last position.
556  * (must be reset to 0)
557  *
558  * @return a pointer to the first byte of a token if successful, otherwise
559  * returns NULL.
560  *
561  * @code
562  * char *str = strdup("Hello,world|Thank,you");
563  * char *token;
564  * int offset = 0;
565  * while((token = qstrtok(str, "|,", NULL, &offset)) != NULL) {
566  * printf("%s\n", token);
567  * }
568  * @endcode
569  *
570  * @note
571  * This may modify str argument.
572  * The major difference between qstrtok() and standard strtok() is that
573  * qstrtok() can returns empty string tokens. If the str is "a:b::d", qstrtok()
574  * returns "a", "b", "", "d". But strtok() returns "a","b","d".
575  */
576 char *qstrtok(char *str, const char *delimiters, char *retstop, int *offset) {
577  char *tokensp, *tokenep;
578 
579  tokensp = tokenep = (char *) (str + *offset);
580  int numdel = strlen(delimiters);
581  for (; *tokenep; tokenep++) {
582  int j;
583  for (j = 0; j < numdel; j++) {
584  if (*tokenep == delimiters[j]) {
585  if (retstop != NULL)
586  *retstop = delimiters[j];
587  *tokenep = '\0';
588  tokenep++;
589  *offset = tokenep - str;
590  return tokensp;
591  }
592  }
593  }
594 
595  if (retstop != NULL)
596  *retstop = '\0';
597  if (tokensp != tokenep) {
598  *offset = tokenep - str;
599  return tokensp;
600  }
601  return NULL;
602 }
603 
604 /**
605  * String Tokenizer
606  *
607  * @param str source string
608  * @param delimiters string that specifies a set of delimiters that may
609  * surround the token being extracted
610  *
611  * @return qlist container pointer otherwise returns NULL.
612  *
613  * @code
614  * qlist_t *tokens = qstr_tokenizer("a:b:c", ":");
615  * char *str;
616  * while((str = tokens->popfirst(tokens, NULL)) != NULL) {
617  * printf("%s\n", str);
618  * }
619  * tokens->free(tokens);
620  * @endcode
621  */
622 qlist_t *qstrtokenizer(const char *str, const char *delimiters) {
623  qlist_t *list = qlist(0);
624  if (list == NULL)
625  return NULL;
626 
627  int i;
628  char *dupstr = strdup(str);
629  char *token;
630  int offset = 0;
631  for (i = 1, token = qstrtok(dupstr, delimiters, NULL, &offset);
632  token != NULL;
633  token = qstrtok(dupstr, delimiters, NULL, &offset), i++) {
634  list->addlast(list, token, strlen(token) + 1);
635  }
636  free(dupstr);
637 
638  return list;
639 }
640 
641 /**
642  * Generate unique id
643  *
644  * @param seed additional seed string. this can be NULL
645  *
646  * @return a pointer of malloced string
647  *
648  * @note
649  * The length of returned string is 32+1 bytes long including terminating NULL
650  * character. It's a good idea to call srand() once before calling this because
651  * it uses rand().
652  */
653 char *qstrunique(const char *seed) {
654  long usec;
655 #ifdef _WIN32
656  FILETIME ft;
657  GetSystemTimeAsFileTime(&ft);
658  usec = ft.dwLowDateTime % 1000000;
659 #else
660  struct timeval tv;
661  gettimeofday(&tv, NULL);
662  usec = tv.tv_usec;
663 #endif
664 
665  char uniquestr[128];
666  snprintf(uniquestr, sizeof(uniquestr), "%u%d%lu%ld%s", getpid(), rand(),
667  (unsigned long)time(NULL), usec, (seed != NULL) ? seed : "");
668 
669  unsigned char md5hash[16];
670  qhashmd5(uniquestr, strlen(uniquestr), md5hash);
671  char *md5ascii = qhex_encode(md5hash, 16);
672 
673  return md5ascii;
674 }
675 
676 /**
677  * Convert integer to comma string.
678  *
679  * @param number integer
680  *
681  * @return a pointer of malloced string which contains comma separated number
682  * if successful, otherwise returns NULL
683  */
684 char *qstr_comma_number(int number) {
685  char *str, *strp;
686 
687  str = strp = (char *) malloc(sizeof(char) * (14 + 1));
688  if (str == NULL)
689  return NULL;
690 
691  char buf[10 + 1], *bufp;
692  snprintf(buf, sizeof(buf), "%d", abs(number));
693 
694  if (number < 0)
695  *strp++ = '-';
696  for (bufp = buf; *bufp != '\0'; strp++, bufp++) {
697  *strp = *bufp;
698  if ((strlen(bufp)) % 3 == 1 && *(bufp + 1) != '\0')
699  *(++strp) = ',';
700  }
701  *strp = '\0';
702 
703  return str;
704 }
705 
706 /**
707  * Test for an alpha-numeric string
708  *
709  * @param testfunc test function for individual character
710  * @param str a pointer of string
711  *
712  * @return true for ok, otherwise returns false
713  *
714  * @code
715  * if(qstrtest(isalnum, "hello1234") == true) {
716  * printf("It is alpha-numeric string.");
717  * }
718  *
719  * if(qstrtest(isdigit, "0123456789") == true) {
720  * printf("It is alpha-numeric string.");
721  * }
722  * @endcode
723  *
724  * @note
725  * Basically you can use below test functios without creating your own version.
726  * Make sure <ctype.h> header should be included before using any of these
727  * functions.
728  * isalnum - checks for an alphanumeric character.
729  * isalpha - checks for an alphabetic character.
730  * isascii - checks whether c is a 7-bit unsigned char value that fits into
731  * the ASCII character set.
732  * isblank - checks for a blank character; that is, a space or a tab.
733  * iscntrl - checks for a control character.
734  * isdigit - checks for a digit (0 through 9).
735  * isgraph - checks for any printable character except space.
736  * islower - checks for a lower-case character.
737  * isprint - checks for any printable character including space.
738  * ispunct - checks for any printable character which is not a space or an
739  * alphanumeric character.
740  * isspace - checks for white-space characters.
741  * isupper - checks for an uppercase letter.
742  * isxdigit - checks for a hexadecimal digits.
743  * Please refer "man isalnum" for more details about these functions.
744  */
745 bool qstrtest(int (*testfunc)(int), const char *str) {
746  for (; *str; str++) {
747  if (testfunc(*str) == 0)
748  return false;
749  }
750  return true;
751 }
752 
753 /**
754  * Test for an email-address formatted string
755  *
756  * @param email email-address formatted string
757  *
758  * @return true if successful, otherwise returns false
759  */
760 bool qstr_is_email(const char *email) {
761  int i, alpa, dot, gol;
762 
763  if (email == NULL)
764  return false;
765 
766  for (i = alpa = dot = gol = 0; email[i] != '\0'; i++) {
767  switch (email[i]) {
768  case '@': {
769  if (alpa == 0)
770  return false;
771  if (gol > 0)
772  return false;
773  gol++;
774  break;
775  }
776  case '.': {
777  if ((i > 0) && (email[i - 1] == '@'))
778  return false;
779  if ((gol > 0) && (email[i - 1] == '.'))
780  return false;
781  dot++;
782  break;
783  }
784  default: {
785  alpa++;
786  if ((email[i] >= '0') && (email[i] <= '9'))
787  break;
788  else if ((email[i] >= 'A') && (email[i] <= 'Z'))
789  break;
790  else if ((email[i] >= 'a') && (email[i] <= 'z'))
791  break;
792  else if ((email[i] == '-') || (email[i] == '_'))
793  break;
794  else
795  return false;
796  }
797  }
798  }
799 
800  if ((alpa <= 3) || (gol == 0) || (dot == 0))
801  return false;
802  return true;
803 }
804 
805 /**
806  * Test for an IPv4 address string
807  *
808  * @param url IPv4 address string
809  *
810  * @return true if successful, otherwise returns false
811  *
812  * @code
813  * if(qstr_is_ip4addr("1.2.3.4") == true) {
814  * printf("It is IPv4 address string.");
815  * }
816  * @endcode
817  */
818 bool qstr_is_ip4addr(const char *str) {
819  char *dupstr = strdup(str);
820 
821  char *s1, *s2;
822  int periodcnt;
823  for (s1 = dupstr, periodcnt = 0; (s2 = strchr(s1, '.')) != NULL;
824  s1 = s2 + 1, periodcnt++) {
825  *s2 = '\0';
826 
827  int n;
828  if (qstrtest(isdigit, s1) == false || (n = atoi(s1)) <= 0 || n >= 256) {
829  free(dupstr);
830  return false;
831  }
832  }
833 
834  free(dupstr);
835  if (periodcnt != 3)
836  return false;
837  return true;
838 }
839 
840 #ifdef __linux__
841 #include <iconv.h>
842 #endif
843 
844 /**
845  * Convert character encoding
846  *
847  * @param str additional seed string. this can be NULL
848  * @param fromcode encoding type of str
849  * @param tocode encoding to convert
850  * @param mag magnification between fromcode and tocode
851  *
852  * @return a pointer of malloced converted string if successful,
853  * otherwise returns NULL
854  *
855  * @code
856  * qCharEncode("KOREAN_EUCKR_STRING", "EUC-KR", "UTF-8", 1.5);
857  * @endcode
858  */
859 char *qstr_conv_encoding(const char *str, const char *fromcode,
860  const char *tocode, float mag) {
861 #ifdef __linux__
862  if (str == NULL)
863  return NULL;
864 
865  char *fromstr = (char *) str;
866  size_t fromsize = strlen(fromstr) + 1;
867 
868  size_t tosize = sizeof(char) * ((mag * (fromsize - 1)) + 1);
869  char *tostr = (char *) malloc(tosize);
870  if (tostr == NULL)
871  return NULL;
872  char *tostr1 = tostr;
873 
874  iconv_t it = iconv_open(tocode, fromcode);
875  if (it < 0) {
876  DEBUG("iconv_open() failed.");
877  return NULL;
878  }
879 
880  int ret = iconv(it, &fromstr, &fromsize, &tostr, &tosize);
881  iconv_close(it);
882 
883  if (ret < 0) {
884  DEBUG("iconv() failed.");
885  free(tostr1);
886  return NULL;
887  }
888 
889  return tostr1;
890 #else
891  return NULL;
892 #endif
893 }
char * qstrdup_between(const char *str, const char *start, const char *end)
Duplicate a substing set.
Definition: qstring.c:379
char * qhex_encode(const void *bin, size_t size)
Encode data to Hexadecimal digit format.
Definition: qencode.c:393
char * qstrcatf(char *str, const char *format,...)
Append formatted string to the end of the source str.
Definition: qstring.c:428
char * qstrupper(char *str)
Convert character to bigger character.
Definition: qstring.c:516
char * qstrtrim_tail(char *str)
Remove tailing white spaces(including CR, LF) of the string.
Definition: qstring.c:116
char * qstrgets(char *buf, size_t size, char **offset)
Get one line from the string offset.
Definition: qstring.c:461
bool qstr_is_ip4addr(const char *str)
Test for an IPv4 address string.
Definition: qstring.c:818
qlist_t * qlist(int options)
Create new qlist_t linked-list container.
Definition: qlist.c:124
char * qstrtrim_head(char *str)
Remove heading white spaces of the string.
Definition: qstring.c:90
char * qstrdupf(const char *format,...)
Duplicate a formatted string.
Definition: qstring.c:358
bool qhashmd5(const void *data, size_t nbytes, void *retbuf)
Calculate 128-bit(16-bytes) MD5 hash.
Definition: qhash.c:67
char * qstr_conv_encoding(const char *str, const char *fromcode, const char *tocode, float mag)
Convert character encoding.
Definition: qstring.c:859
char * qstrncpy(char *dst, size_t size, const char *src, size_t nbytes)
Copy src string to dst no more than n bytes.
Definition: qstring.c:339
qlist_t * qstrtokenizer(const char *str, const char *delimiters)
String Tokenizer.
Definition: qstring.c:622
char * qstrtrim(char *str)
Remove white spaces(including CR, LF) from head and tail of the string.
Definition: qstring.c:55
char * qstrunchar(char *str, char head, char tail)
Remove character from head and tail of the string.
Definition: qstring.c:149
char * qstrcpy(char *dst, size_t size, const char *src)
Copy src string to dst.
Definition: qstring.c:320
char * qstrtok(char *str, const char *delimiters, char *retstop, int *offset)
Split string into tokens.
Definition: qstring.c:576
void * qmemdup(const void *data, size_t size)
Duplicate a copy of memory data.
Definition: qstring.c:406
bool qstrtest(int(*testfunc)(int), const char *str)
Test for an alpha-numeric string.
Definition: qstring.c:745
char * qstrrev(char *str)
Reverse the order of characters in the string.
Definition: qstring.c:493
bool qstr_is_email(const char *email)
Test for an email-address formatted string.
Definition: qstring.c:760
char * qstrreplace(const char *mode, char *srcstr, const char *tokstr, const char *word)
Replace string or tokens as word from source string with given mode.
Definition: qstring.c:236
char * qstr_comma_number(int number)
Convert integer to comma string.
Definition: qstring.c:684
char * qstrlower(char *str)
Convert character to lower character.
Definition: qstring.c:536
char * qstrunique(const char *seed)
Generate unique id.
Definition: qstring.c:653
static bool head(qhttpclient_t *client, const char *uri, int *rescode, qlisttbl_t *reqheaders, qlisttbl_t *resheaders)
qhttpclient->head(): Sends a HEAD request.
Definition: qhttpclient.c:553