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 successful, otherwise returns NULL
52 *
53 * @note This modify source string directly.
54 */
55char *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 successful, otherwise returns NULL
87 *
88 * @note This modify source string directly.
89 */
90char *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 successful, otherwise returns NULL
113 *
114 * @note This modify source string directly.
115 */
116char *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, otherwise 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 */
149char *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, otherwise returns NULL
174 *
175 * @note
176 * The mode argument has two separated characters. 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 */
236char *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 if (newstr == NULL)
255 return NULL;
256
257 for (srcp = (char *) srcstr, newp = newstr; *srcp; srcp++) {
258 for (tokenp = (char *) tokstr; *tokenp; tokenp++) {
259 if (*srcp == *tokenp) {
260 char *wordp;
261 for (wordp = (char *) word; *wordp; wordp++) {
262 *newp++ = *wordp;
263 }
264 break;
265 }
266 }
267 if (!*tokenp)
268 *newp++ = *srcp;
269 }
270 *newp = '\0';
271 } else if (method == 's') { /* String replace */
272 if (strlen(word) > strlen(tokstr)) {
273 maxstrlen = ((strlen(srcstr) / strlen(tokstr)) * strlen(word))
274 + (strlen(srcstr) % strlen(tokstr));
275 } else {
276 maxstrlen = strlen(srcstr);
277 }
278 newstr = (char *) malloc(maxstrlen + 1);
279 if (newstr == NULL)
280 return NULL;
281
282 tokstrlen = strlen(tokstr);
283
284 for (srcp = srcstr, newp = newstr; *srcp; srcp++) {
285 if (!strncmp(srcp, tokstr, tokstrlen)) {
286 char *wordp;
287 for (wordp = (char *) word; *wordp; wordp++)
288 *newp++ = *wordp;
289 srcp += tokstrlen - 1;
290 } else
291 *newp++ = *srcp;
292 }
293 *newp = '\0';
294 } else {
295 DEBUG("Unknown mode \"%s\".", mode);
296 return NULL;
297 }
298
299 /* decide whether newing the memory or replacing into exist one */
300 if (memuse == 'n')
301 retp = newstr;
302 else if (memuse == 'r') {
303 strcpy(srcstr, newstr);
304 free(newstr);
305 retp = srcstr;
306 } else {
307 DEBUG("Unknown mode \"%s\".", mode);
308 free(newstr);
309 return NULL;
310 }
311
312 return retp;
313}
314
315/**
316 * Copy src string to dst. The dst string array will be always terminated by
317 * NULL character. Also allows overlap between src and dst.
318 *
319 * @param dst a pointer of the string to be copied
320 * @param size the size of dst character arrary
321 * @param src a pointer of source string
322 *
323 * @return always returns a pointer of dst
324 */
325char *qstrcpy(char *dst, size_t size, const char *src) {
326 if (dst == NULL || size == 0 || src == NULL)
327 return dst;
328
329 size_t nbytes = strlen(src);
330 return qstrncpy(dst, size, src, nbytes);
331}
332
333/**
334 * Copy src string to dst no more than n bytes. The dst string array will be
335 * always terminated by NULL character. Also allows overlap between src and dst.
336 *
337 * @param dst a pointer of the string to be copied
338 * @param size the size of dst character arrary
339 * @param src a pointer of source string
340 * @param nbytes number of bytes to copy
341 *
342 * @return always returns a pointer of dst
343 */
344char *qstrncpy(char *dst, size_t size, const char *src, size_t nbytes) {
345 if (dst == NULL || size == 0 || src == NULL)
346 return dst;
347
348 if (nbytes >= size)
349 nbytes = size - 1;
350 memmove((void *) dst, (void *) src, nbytes);
351 dst[nbytes] = '\0';
352
353 return dst;
354}
355
356/**
357 * Duplicate a formatted string.
358 *
359 * @param format string format
360 *
361 * @return a pointer of malloced string if successful, otherwise returns NULL
362 */
363char *qstrdupf(const char *format, ...) {
364 char *str;
365 DYNAMIC_VSPRINTF(str, format);
366 if (str == NULL)
367 return NULL;
368
369 char *dup = strdup(str);
370 free(str);
371
372 return dup;
373}
374
375/**
376 * Duplicate a substing set
377 *
378 * @param str a pointer of original string
379 * @param start substring which is started with this
380 * @param end substring which is ended with this
381 *
382 * @return a pointer of malloced string if successful, otherwise returns NULL
383 */
384char *qstrdup_between(const char *str, const char *start, const char *end) {
385 char *s;
386 if ((s = strstr(str, start)) == NULL)
387 return NULL;
388 s += strlen(start);
389
390 char *e;
391 if ((e = strstr(s, end)) == NULL)
392 return NULL;
393
394 int len = e - s;
395
396 char *buf = (char *) malloc(sizeof(char) * (len + 1));
397 if (buf == NULL)
398 return NULL;
399
400 strncpy(buf, s, len);
401 buf[len] = '\0';
402 return buf;
403}
404
405/**
406 * Duplicate a copy of memory data.
407 *
408 * @param data source data
409 * @param size data size
410 *
411 * @return a pointer of malloced data which's content is identical to source data.
412 */
413void *qmemdup(const void *data, size_t size) {
414 if (data == NULL || size == 0) {
415 return NULL;
416 }
417
418 void *newdata = malloc(size);
419 if (newdata == NULL) {
420 return NULL;
421 }
422
423 memcpy(newdata, data, size);
424 return newdata;
425}
426
427/**
428 * Append formatted string to the end of the source str
429 *
430 * @param str a pointer of original string
431 * @param format string format to append
432 *
433 * @return a pointer of str if successful, otherwise returns NULL
434 */
435char *qstrcatf(char *str, const char *format, ...) {
436 char *buf;
437 DYNAMIC_VSPRINTF(buf, format);
438 if (buf == NULL)
439 return NULL;
440
441 char *ret = strcat(str, buf);
442 free(buf);
443 return ret;
444}
445
446/**
447 * Get one line from the string offset.
448 *
449 * @param buf buffer pointer
450 * @param size buffer size
451 * @param offset a offset pointer which point source string
452 *
453 * @return a pointer of buffer if successful, otherwise(EOF) returns NULL
454 *
455 * @note
456 * CR and LF will not be stored.
457 *
458 * @code
459 * char *text="Hello\nWorld";
460 *
461 * char *offset = text;
462 * char buf[1024];
463 * while(qstrgets(buf, sizeof(buf), &offset) == NULL) {
464 * printf("%s\n", buf);
465 * }
466 * @endcode
467 */
468char *qstrgets(char *buf, size_t size, char **offset) {
469 if (offset == NULL || *offset == NULL || **offset == '\0')
470 return NULL;
471
472 size_t i;
473 char *from = *offset;
474 char *to = buf;
475 for (i = 0; *from != '\0' && i < (size - 1); i++, from++) {
476 if (*from == '\r')
477 continue;
478 if (*from == '\n') {
479 from++;
480 break;
481 }
482 *to = *from;
483 to++;
484 }
485 *to = '\0';
486 *offset = from;
487
488 return buf;
489}
490
491/**
492 * Reverse the order of characters in the string
493 *
494 * @param str a pointer of source string
495 *
496 * @return always returns a pointer of str
497 *
498 * @note This modify str directly.
499 */
500char *qstrrev(char *str) {
501 if (str == NULL)
502 return str;
503
504 char *p1, *p2;
505 for (p1 = str, p2 = str + (strlen(str) - 1); p2 > p1; p1++, p2--) {
506 char t = *p1;
507 *p1 = *p2;
508 *p2 = t;
509 }
510
511 return str;
512}
513
514/**
515 * Convert character to bigger character.
516 *
517 * @param str a pointer of source string
518 *
519 * @return always returns a pointer of str
520 *
521 * @note This modify str directly.
522 */
523char *qstrupper(char *str) {
524 char *cp;
525
526 if (!str)
527 return NULL;
528 for (cp = str; *cp; cp++)
529 if (*cp >= 'a' && *cp <= 'z')
530 *cp -= 32;
531 return str;
532}
533
534/**
535 * Convert character to lower character.
536 *
537 * @param str a pointer of source string
538 *
539 * @return always returns a pointer of str
540 *
541 * @note This modify str directly.
542 */
543char *qstrlower(char *str) {
544 char *cp;
545
546 if (!str)
547 return NULL;
548 for (cp = str; *cp; cp++)
549 if (*cp >= 'A' && *cp <= 'Z')
550 *cp += 32;
551 return str;
552}
553
554/**
555 * Split string into tokens
556 *
557 * @param str source string
558 * @param delimiters string that specifies a set of delimiters that may
559 * surround the token being extracted
560 * @param retstop stop delimiter character will be stored. it can be NULL
561 * if you don't want to know.
562 * @param offset integer pointer used for store last position.
563 * (must be reset to 0)
564 *
565 * @return a pointer to the first byte of a token if successful, otherwise
566 * returns NULL.
567 *
568 * @code
569 * char *str = strdup("Hello,world|Thank,you");
570 * char *token;
571 * int offset = 0;
572 * while((token = qstrtok(str, "|,", NULL, &offset)) != NULL) {
573 * printf("%s\n", token);
574 * }
575 * @endcode
576 *
577 * @note
578 * This may modify str argument.
579 * The major difference between qstrtok() and standard strtok() is that
580 * qstrtok() can returns empty string tokens. If the str is "a:b::d", qstrtok()
581 * returns "a", "b", "", "d". But strtok() returns "a","b","d".
582 */
583char *qstrtok(char *str, const char *delimiters, char *retstop, int *offset) {
584 char *tokensp, *tokenep;
585
586 tokensp = tokenep = (char *) (str + *offset);
587 int numdel = strlen(delimiters);
588 for (; *tokenep; tokenep++) {
589 int j;
590 for (j = 0; j < numdel; j++) {
591 if (*tokenep == delimiters[j]) {
592 if (retstop != NULL)
593 *retstop = delimiters[j];
594 *tokenep = '\0';
595 tokenep++;
596 *offset = tokenep - str;
597 return tokensp;
598 }
599 }
600 }
601
602 if (retstop != NULL)
603 *retstop = '\0';
604 if (tokensp != tokenep) {
605 *offset = tokenep - str;
606 return tokensp;
607 }
608 return NULL;
609}
610
611/**
612 * String Tokenizer
613 *
614 * @param str source string
615 * @param delimiters string that specifies a set of delimiters that may
616 * surround the token being extracted
617 *
618 * @return qlist container pointer otherwise returns NULL.
619 *
620 * @code
621 * qlist_t *tokens = qstr_tokenizer("a:b:c", ":");
622 * char *str;
623 * while((str = tokens->popfirst(tokens, NULL)) != NULL) {
624 * printf("%s\n", str);
625 * }
626 * tokens->free(tokens);
627 * @endcode
628 */
629qlist_t *qstrtokenizer(const char *str, const char *delimiters) {
630 qlist_t *list = qlist(0);
631 if (list == NULL)
632 return NULL;
633
634 int i;
635 char *dupstr = strdup(str);
636 char *token;
637 int offset = 0;
638 for (i = 1, token = qstrtok(dupstr, delimiters, NULL, &offset);
639 token != NULL;
640 token = qstrtok(dupstr, delimiters, NULL, &offset), i++) {
641 list->addlast(list, token, strlen(token) + 1);
642 }
643 free(dupstr);
644
645 return list;
646}
647
648/**
649 * Generate unique id
650 *
651 * @param seed additional seed string. this can be NULL
652 *
653 * @return a pointer of malloced string
654 *
655 * @note
656 * The length of returned string is 32+1 bytes long including terminating NULL
657 * character. It's a good idea to call srand() once before calling this because
658 * it uses rand().
659 */
660char *qstrunique(const char *seed) {
661 long usec;
662#ifdef _WIN32
663 FILETIME ft;
664 GetSystemTimeAsFileTime(&ft);
665 usec = ft.dwLowDateTime % 1000000;
666#else
667 struct timeval tv;
668 gettimeofday(&tv, NULL);
669 usec = tv.tv_usec;
670#endif
671
672 char uniquestr[128];
673 snprintf(uniquestr, sizeof(uniquestr), "%u%d%lu%ld%s", getpid(), rand(),
674 (unsigned long)time(NULL), usec, (seed != NULL) ? seed : "");
675
676 unsigned char md5hash[16];
677 qhashmd5(uniquestr, strlen(uniquestr), md5hash);
678 char *md5ascii = qhex_encode(md5hash, 16);
679
680 return md5ascii;
681}
682
683/**
684 * Convert integer to comma string.
685 *
686 * @param number integer
687 *
688 * @return a pointer of malloced string which contains comma separated number
689 * if successful, otherwise returns NULL
690 */
691char *qstr_comma_number(int number) {
692 char *str, *strp;
693
694 str = strp = (char *) malloc(sizeof(char) * (14 + 1));
695 if (str == NULL)
696 return NULL;
697
698 char buf[10 + 1], *bufp;
699 snprintf(buf, sizeof(buf), "%d", abs(number));
700
701 if (number < 0)
702 *strp++ = '-';
703 for (bufp = buf; *bufp != '\0'; strp++, bufp++) {
704 *strp = *bufp;
705 if ((strlen(bufp)) % 3 == 1 && *(bufp + 1) != '\0')
706 *(++strp) = ',';
707 }
708 *strp = '\0';
709
710 return str;
711}
712
713/**
714 * Test for an alpha-numeric string
715 *
716 * @param testfunc test function for individual character
717 * @param str a pointer of string
718 *
719 * @return true for ok, otherwise returns false
720 *
721 * @code
722 * if(qstrtest(isalnum, "hello1234") == true) {
723 * printf("It is alpha-numeric string.");
724 * }
725 *
726 * if(qstrtest(isdigit, "0123456789") == true) {
727 * printf("It is alpha-numeric string.");
728 * }
729 * @endcode
730 *
731 * @note
732 * Basically you can use below test functios without creating your own version.
733 * Make sure <ctype.h> header should be included before using any of these
734 * functions.
735 * isalnum - checks for an alphanumeric character.
736 * isalpha - checks for an alphabetic character.
737 * isascii - checks whether c is a 7-bit unsigned char value that fits into
738 * the ASCII character set.
739 * isblank - checks for a blank character; that is, a space or a tab.
740 * iscntrl - checks for a control character.
741 * isdigit - checks for a digit (0 through 9).
742 * isgraph - checks for any printable character except space.
743 * islower - checks for a lower-case character.
744 * isprint - checks for any printable character including space.
745 * ispunct - checks for any printable character which is not a space or an
746 * alphanumeric character.
747 * isspace - checks for white-space characters.
748 * isupper - checks for an uppercase letter.
749 * isxdigit - checks for a hexadecimal digits.
750 * Please refer "man isalnum" for more details about these functions.
751 */
752bool qstrtest(int (*testfunc)(int), const char *str) {
753 for (; *str; str++) {
754 if (testfunc(*str) == 0)
755 return false;
756 }
757 return true;
758}
759
760/**
761 * Test for an email-address formatted string
762 *
763 * @param email email-address formatted string
764 *
765 * @return true if successful, otherwise returns false
766 */
767bool qstr_is_email(const char *email) {
768 int i, alpa, dot, gol;
769
770 if (email == NULL)
771 return false;
772
773 for (i = alpa = dot = gol = 0; email[i] != '\0'; i++) {
774 switch (email[i]) {
775 case '@': {
776 if (alpa == 0)
777 return false;
778 if (gol > 0)
779 return false;
780 gol++;
781 break;
782 }
783 case '.': {
784 if ((i > 0) && (email[i - 1] == '@'))
785 return false;
786 if ((gol > 0) && (email[i - 1] == '.'))
787 return false;
788 dot++;
789 break;
790 }
791 default: {
792 alpa++;
793 if ((email[i] >= '0') && (email[i] <= '9'))
794 break;
795 else if ((email[i] >= 'A') && (email[i] <= 'Z'))
796 break;
797 else if ((email[i] >= 'a') && (email[i] <= 'z'))
798 break;
799 else if ((email[i] == '-') || (email[i] == '_'))
800 break;
801 else
802 return false;
803 }
804 }
805 }
806
807 if ((alpa <= 3) || (gol == 0) || (dot == 0))
808 return false;
809 return true;
810}
811
812/**
813 * Test for an IPv4 address string
814 *
815 * @param url IPv4 address string
816 *
817 * @return true if successful, otherwise returns false
818 *
819 * @code
820 * if(qstr_is_ip4addr("1.2.3.4") == true) {
821 * printf("It is IPv4 address string.");
822 * }
823 * @endcode
824 */
825bool qstr_is_ip4addr(const char *str) {
826 char *dupstr = strdup(str);
827
828 char *s1, *s2;
829 int periodcnt;
830 for (s1 = dupstr, periodcnt = 0; (s2 = strchr(s1, '.')) != NULL;
831 s1 = s2 + 1, periodcnt++) {
832 *s2 = '\0';
833
834 int n;
835 if (qstrtest(isdigit, s1) == false || (n = atoi(s1)) <= 0 || n >= 256) {
836 free(dupstr);
837 return false;
838 }
839 }
840
841 free(dupstr);
842 if (periodcnt != 3)
843 return false;
844 return true;
845}
846
847#ifdef __linux__
848#include <iconv.h>
849#endif
850
851/**
852 * Convert character encoding
853 *
854 * @param str additional seed string. this can be NULL
855 * @param fromcode encoding type of str
856 * @param tocode encoding to convert
857 * @param mag magnification between fromcode and tocode
858 *
859 * @return a pointer of malloced converted string if successful,
860 * otherwise returns NULL
861 *
862 * @code
863 * qCharEncode("KOREAN_EUCKR_STRING", "EUC-KR", "UTF-8", 1.5);
864 * @endcode
865 */
866char *qstr_conv_encoding(const char *str, const char *fromcode,
867 const char *tocode, float mag) {
868#ifdef __linux__
869 if (str == NULL)
870 return NULL;
871
872 char *fromstr = (char *) str;
873 size_t fromsize = strlen(fromstr) + 1;
874
875 size_t tosize = sizeof(char) * ((mag * (fromsize - 1)) + 1);
876 char *tostr = (char *) malloc(tosize);
877 if (tostr == NULL)
878 return NULL;
879
880 char *tostr1 = tostr;
881
882 iconv_t it = iconv_open(tocode, fromcode);
883 if (it < 0) {
884 DEBUG("iconv_open() failed.");
885 return NULL;
886 }
887
888 int ret = iconv(it, &fromstr, &fromsize, &tostr, &tosize);
889 iconv_close(it);
890
891 if (ret < 0) {
892 DEBUG("iconv() failed.");
893 free(tostr1);
894 return NULL;
895 }
896
897 return tostr1;
898#else
899 return NULL;
900#endif
901}
char * qhex_encode(const void *bin, size_t size)
Encode data to Hexadecimal digit format.
Definition qencode.c:393
bool qhashmd5(const void *data, size_t nbytes, void *retbuf)
Calculate 128-bit(16-bytes) MD5 hash.
Definition qhash.c:67
static bool head(qhttpclient_t *client, const char *uri, int *rescode, qlisttbl_t *reqheaders, qlisttbl_t *resheaders)
qhttpclient->head(): Sends a HEAD request.
qlist_t * qlist(int options)
Create new qlist_t linked-list container.
Definition qlist.c:124
char * qstrrev(char *str)
Reverse the order of characters in the string.
Definition qstring.c:500
char * qstrtok(char *str, const char *delimiters, char *retstop, int *offset)
Split string into tokens.
Definition qstring.c:583
char * qstrcpy(char *dst, size_t size, const char *src)
Copy src string to dst.
Definition qstring.c:325
char * qstrunique(const char *seed)
Generate unique id.
Definition qstring.c:660
qlist_t * qstrtokenizer(const char *str, const char *delimiters)
String Tokenizer.
Definition qstring.c:629
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:344
char * qstrtrim(char *str)
Remove white spaces(including CR, LF) from head and tail of the string.
Definition qstring.c:55
bool qstrtest(int(*testfunc)(int), const char *str)
Test for an alpha-numeric string.
Definition qstring.c:752
char * qstrtrim_head(char *str)
Remove heading white spaces of the string.
Definition qstring.c:90
char * qstrcatf(char *str, const char *format,...)
Append formatted string to the end of the source str.
Definition qstring.c:435
char * qstrunchar(char *str, char head, char tail)
Remove character from head and tail of the string.
Definition qstring.c:149
char * qstrdup_between(const char *str, const char *start, const char *end)
Duplicate a substing set.
Definition qstring.c:384
bool qstr_is_ip4addr(const char *str)
Test for an IPv4 address string.
Definition qstring.c:825
char * qstrdupf(const char *format,...)
Duplicate a formatted string.
Definition qstring.c:363
void * qmemdup(const void *data, size_t size)
Duplicate a copy of memory data.
Definition qstring.c:413
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:468
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 * qstrupper(char *str)
Convert character to bigger character.
Definition qstring.c:523
char * qstrlower(char *str)
Convert character to lower character.
Definition qstring.c:543
char * qstr_comma_number(int number)
Convert integer to comma string.
Definition qstring.c:691
char * qstr_conv_encoding(const char *str, const char *fromcode, const char *tocode, float mag)
Convert character encoding.
Definition qstring.c:866
bool qstr_is_email(const char *email)
Test for an email-address formatted string.
Definition qstring.c:767