├── .gitignore ├── README.md └── src ├── base64.c ├── base64.h ├── html.c ├── html.h ├── main.c ├── md5.c ├── md5.h ├── repeat.c ├── repeat.h ├── replace.c ├── replace.h ├── slashes.c ├── slashes.h ├── strcase.c ├── strcase.h ├── string.h ├── strpos.c ├── strpos.h ├── substr.c ├── substr.h ├── trim.c ├── trim.h ├── url.c └── url.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.xcodeproj 2 | build/ 3 | Build/ 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/catorv/string-c/67f802120bc955c240bc865ea11a920aeed45586/README.md -------------------------------------------------------------------------------- /src/base64.c: -------------------------------------------------------------------------------- 1 | // 2 | // base64.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 11/5/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include "base64.h" 10 | 11 | string_t copy_base64encode(const string_t str) 12 | { 13 | size_t len = strlen(str); 14 | size_t nlen = sizeof(char) * ((len + 2) / 3 * 4); 15 | 16 | const string_t result = (string_t)malloc(nlen + sizeof(char)); 17 | 18 | static string_t table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 19 | 20 | int32_t i; 21 | for (i=0; i < len; i += 3) { 22 | int32_t value = 0; 23 | int32_t j; 24 | for (j = i; j < (i + 3); j++) { 25 | value <<= 8; 26 | 27 | if (j < len) { 28 | value |= (0xFF & str[j]); 29 | } 30 | } 31 | 32 | int32_t index = (i / 3) * 4; 33 | result[index + 0] = table[(value >> 18) & 0x3F]; 34 | result[index + 1] = table[(value >> 12) & 0x3F]; 35 | result[index + 2] = (i + 1) < len ? table[(value >> 6) & 0x3F] : '='; 36 | result[index + 3] = (i + 2) < len ? table[(value >> 0) & 0x3F] : '='; 37 | } 38 | 39 | result[nlen] = '\0'; 40 | 41 | return result; 42 | } 43 | 44 | string_t base64decode(string_t *str) 45 | { 46 | static uint8_t table[256]; 47 | static bool table_inited = false; 48 | if (!table_inited) { 49 | int i; 50 | for (i = 0; i < 256; ++i) { 51 | table[i] = (uint8_t)0x80; 52 | } 53 | for (i = 'A'; i <= 'Z'; ++i) { 54 | table[i] = 0 + (i - 'A'); 55 | } 56 | for (i = 'a'; i <= 'z'; ++i) { 57 | table[i] = 26 + (i - 'a'); 58 | } 59 | for (i = '0'; i <= '9'; ++i) { 60 | table[i] = 52 + (i - '0'); 61 | } 62 | table[(uint8_t)'+'] = 62; 63 | table[(uint8_t)'/'] = 63; 64 | table[(uint8_t)'='] = 0; 65 | table_inited = true; 66 | } 67 | 68 | const string_t input = *str; 69 | size_t len = strlen(input); 70 | 71 | 72 | int k = 0; 73 | int m, n; 74 | for (m = 0; m < len; m += 4) { 75 | uint8_t c[4]; 76 | for (n = 0; n < 4; ++n) { 77 | c[n] = table[(uint8_t)input[n + m]]; 78 | if ((c[n] & 0x80) != 0) { 79 | c[n] = 0; 80 | } 81 | } 82 | 83 | input[k++] = (c[0] << 2) | (c[1] >> 4); 84 | input[k++] = (c[1] << 4) | (c[2] >> 2); 85 | input[k++] = (c[2] << 6) | c[3]; 86 | } 87 | input[k] = '\0'; 88 | 89 | return *str; 90 | } 91 | -------------------------------------------------------------------------------- /src/base64.h: -------------------------------------------------------------------------------- 1 | // 2 | // base64.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 11/5/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_base64_h 10 | #define string_c_base64_h 11 | 12 | #include "string.h" 13 | 14 | /** 15 | * 对字符串进行BASE64编码 16 | * 17 | * @param str 要进行编码的字符串 18 | * @return 返回编码后的字符串 19 | */ 20 | string_t copy_base64encode(const string_t str); 21 | 22 | /** 23 | * 对字符串进行BASE64解码 24 | * 25 | * @param str 要进行解码的字符串 26 | * @return 返回解码后的字符串 27 | */ 28 | string_t base64decode(string_t *str); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/html.c: -------------------------------------------------------------------------------- 1 | // 2 | // html.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/30/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include "html.h" 10 | 11 | 12 | string_t striptags(string_t *str) 13 | { 14 | string_t s = *str; 15 | string_t p = s; 16 | 17 | bool ouside = true; 18 | 19 | while (*p != '\0') { 20 | if (ouside && *p == '<') { 21 | ouside = false; 22 | } else if (!ouside && *p == '>') { 23 | ouside = true; 24 | p++; 25 | continue; 26 | } 27 | 28 | if (ouside && s != p) { 29 | *s = *p; 30 | s++; 31 | p++; 32 | } else { 33 | p++; 34 | } 35 | } 36 | 37 | *s = '\0'; 38 | 39 | return *str; 40 | } 41 | 42 | string_t copy_htmlencode(const string_t str, bool skip_quotes) 43 | { 44 | const size_t len = strlen(str); 45 | const string_t se = str + len; 46 | register string_t s = str; 47 | register string_t p; 48 | 49 | string_t result = (string_t)malloc(sizeof(char) * (len * 6 + 1)); 50 | 51 | s = str; 52 | p = result; 53 | while (s < se) { 54 | switch (*s) { 55 | case '&': 56 | memcpy(p, "&", 5); 57 | p += 5; 58 | break; 59 | 60 | case '"': 61 | case '\'': 62 | if (skip_quotes) { 63 | *p++ = *s; 64 | } else { 65 | memcpy(p, *s == '"' ? """ : "'", 6); 66 | p += 6; 67 | } 68 | break; 69 | 70 | case '<': 71 | case '>': 72 | memcpy(p, *s == '<' ? "<" : ">", 4); 73 | p += 4; 74 | break; 75 | 76 | default: 77 | *p++ = *s; 78 | break; 79 | } 80 | s++; 81 | } 82 | 83 | *p = '\0'; 84 | 85 | return result; 86 | } 87 | 88 | typedef struct htmlentity_t { 89 | string_t entity; 90 | size_t length; 91 | unsigned char c1; 92 | unsigned char c2; 93 | } htmlentity_t; 94 | 95 | string_t htmldecode(string_t *str) 96 | { 97 | string_t s = *str; 98 | string_t p = s; 99 | 100 | htmlentity_t htmlentities[] = { 101 | {"&", 5, 0, '&'}, 102 | {""", 6, 0, '"'}, 103 | {"'", 6, 0, '\''}, 104 | {"<", 4, 0, '<'}, 105 | {">", 4, 0, '>'} 106 | }; 107 | int htmlentity_count = sizeof(htmlentities) / sizeof(htmlentity_t); 108 | 109 | int i; 110 | htmlentity_t entity; 111 | 112 | while (*s != '\0') { 113 | if (*s == '&') { 114 | for (i = 0; i < htmlentity_count; i++) { 115 | entity = htmlentities[i]; 116 | if (strncasecmp(s, entity.entity, entity.length) == 0) { 117 | if (entity.c1 != 0) { 118 | *p++ = entity.c1; 119 | } 120 | *p++ = entity.c2; 121 | s += entity.length; 122 | break; 123 | } 124 | } 125 | if (i < htmlentity_count) { 126 | continue; 127 | } 128 | } 129 | *p++ = *s++; 130 | } 131 | 132 | *p = '\0'; 133 | 134 | return *str; 135 | } -------------------------------------------------------------------------------- /src/html.h: -------------------------------------------------------------------------------- 1 | // 2 | // html.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/30/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_html_h 10 | #define string_c_html_h 11 | 12 | #include "string.h" 13 | 14 | /** 15 | * 从字符串中去除 HTML 标记 16 | * 17 | * @param str 输入字符串 18 | * @return 返回处理后的字符串 19 | */ 20 | string_t striptags(string_t *str); 21 | 22 | /** 23 | * HTML特殊字符编码 24 | * 25 | * @param str 输入字符串 26 | * @param skip_quotes 是否跳过单引号和双引号 27 | * @return 返回编码后的字符串 28 | */ 29 | string_t copy_htmlencode(const string_t str, bool skip_quotes); 30 | 31 | /** 32 | * HTML特殊字符解码 33 | * 34 | * @param str 输入字符串(也是输出字符串) 35 | * @return 返回解码后的字符串 36 | */ 37 | string_t htmldecode(string_t *str); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/22/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "string.h" 14 | 15 | void __(string_t label) 16 | { 17 | printf("\n__%s_________________________________________________\n", label); 18 | } 19 | 20 | int main(int argc, const char * argv[]) 21 | { 22 | const string_t s1 = "Created by Cator VeeVee on 10/22/13 (cator)"; 23 | const string_t s2 = "cator"; 24 | const string_t s3 = "Cator"; 25 | const string_t s4 = "Wei"; 26 | 27 | string_t str; 28 | 29 | printf("s1 = '%s' \n", s1); 30 | printf("s2 = '%s' \n", s2); 31 | printf("s3 = '%s' \n", s3); 32 | printf("s4 = '%s' \n", s4); 33 | 34 | 35 | __("strpos"); { 36 | printf("strpos(s1, s2): %ld \n", strpos(s1, s2)); 37 | printf("stripos(s1, s2): %ld \n", stripos(s1, s2)); 38 | printf("strrpos(s1, s3): %ld \n", strrpos(s1, s3)); 39 | printf("strripos(s1, s3): %ld \n", strripos(s1, s3)); 40 | 41 | printf("strpos(s1, s4): %ld \n", strpos(s1, s4)); 42 | printf("stripos(s1, s4): %ld \n", stripos(s1, s4)); 43 | printf("strrpos(s1, s4): %ld \n", strrpos(s1, s4)); 44 | printf("strripos(s1, s4): %ld \n", strripos(s1, s4)); 45 | } 46 | 47 | 48 | __("copy_substr"); { 49 | str = copy_substr(s1, 11, 5); 50 | printf("copy_substr(s1, 11, 5): '%s'\n", str); 51 | free(str); 52 | 53 | str = copy_substr(s1, -6, 5); 54 | printf("copy_substr(s1, -6, 5): '%s'\n", str); 55 | free(str); 56 | 57 | str = copy_substr(s1, -6, -1); 58 | printf("copy_substr(s1, -6, -1): '%s'\n", str); 59 | free(str); 60 | 61 | str = copy_substr(s1, 34, 10000); 62 | printf("copy_substr(s1, 34, 10000): '%s'\n", str); 63 | free(str); 64 | 65 | str = copy_substr(s1, 34, 0); 66 | printf("copy_substr(s1, 34, 0): '%s'\n", str); 67 | free(str); 68 | } 69 | 70 | 71 | __("substr_count"); { 72 | printf("substr_count(s1, \"Vee\"): %ld\n", substr_count(s1, "Vee")); 73 | printf("substr_count(s1, \"Cator\"): %ld\n", substr_count(s1, "Cator")); 74 | } 75 | 76 | 77 | __("strcase"); { 78 | str = copy_str(s1); 79 | 80 | printf("strtolowwer(s1): '%s'\n", strtolower(&str)); 81 | printf("strtoupper(s1): '%s'\n", strtoupper(&str)); 82 | printf("lcfirst(s1): '%s'\n", lcfirst(&str)); 83 | strtolower(&str); 84 | printf("ucfirst(s1): '%s'\n", ucfirst(&str)); 85 | strtolower(&str); 86 | printf("ucwords(s1): '%s'\n", ucwords(&str)); 87 | 88 | free(str); 89 | } 90 | 91 | 92 | __("trim"); { 93 | str = copy_str(" \t\v cator \r\n "); 94 | printf("ltrim(\" \\t\\v cator \\r\\n \"): '%s'\n", ltrim(&str)); 95 | free(str); 96 | 97 | str = copy_str(" \t\v cator \r\n "); 98 | printf("rtrim(\" \\t\\v cator \\r\\n \"): '%s'\n", rtrim(&str)); 99 | free(str); 100 | 101 | str = copy_str(" \t\v cator \r\n "); 102 | printf("trim(\" \\t\\v cator \\r\\n \"): '%s'\n", trim(&str)); 103 | free(str); 104 | } 105 | 106 | 107 | __("repeat"); { 108 | str = copy_repeat("-=", 10); 109 | printf("copy_repeat(\"-=\", 10): '%s'\n", str); 110 | free(str); 111 | 112 | str = copy_strpad(s2, 20, "-=", STR_PAD_LEFT); 113 | printf("copy_strpad(s2, 20, \"-=\", STR_PAD_LEFT): '%s'\n", str); 114 | free(str); 115 | 116 | str = copy_strpad(s2, 20, "-=", STR_PAD_RIGHT); 117 | printf("copy_strpad(s2, 20, \"-=\", STR_PAD_RIGHT): '%s'\n", str); 118 | free(str); 119 | 120 | str = copy_strpad(s2, 20, "-=", STR_PAD_BOTH); 121 | printf("copy_strpad(s2, 20, \"-=\", STR_PAD_BOTH): '%s'\n", str); 122 | free(str); 123 | } 124 | 125 | 126 | __("replace"); { 127 | str = copy_str(s1); 128 | printf("strtr(&str, \"ctr\", \"CTR\"): '%s'\n", strtr(&str, "ctr", "CTR")); 129 | free(str); 130 | 131 | str = copy_replace("cator", "*name*", s1); 132 | printf("copy_replace(\"cator\", \"*name*\", s1): '%s'\n", str); 133 | free(str); 134 | 135 | str = copy_ireplace("cator", "*name*", s1); 136 | printf("copy_ireplace(\"cator\", \"*name*\", s1): '%s'\n", str); 137 | free(str); 138 | } 139 | 140 | __("html"); { 141 | string_t html = "

Test 'paragraph'.

Other text"; 142 | printf("html: ‘%s’\n", html); 143 | 144 | str = copy_str(html); 145 | printf("striptags(html): '%s'\n", striptags(&str)); 146 | free(str); 147 | 148 | str = copy_htmlencode(html, false); 149 | printf("copy_htmlencode(html, false): '%s'\n", str); 150 | free(str); 151 | 152 | str = copy_htmlencode(html, true); 153 | printf("copy_htmlencode(html, true): '%s'\n", str); 154 | free(str); 155 | 156 | str = copy_htmlencode(html, false); 157 | printf("htmldecode(encoded_html): '%s'\n", htmldecode(&str)); 158 | free(str); 159 | } 160 | 161 | __("url"); { 162 | string_t url = "http://myname:mypw@catorv.com/index.html?name=cator&age=100#vee~"; 163 | printf("url: '%s'\n", url); 164 | 165 | str = copy_urlencode(url); 166 | printf("copy_urlencode(url): '%s'\n", str); 167 | printf("urldecode(copy_urlencode(url)): '%s'\n", urldecode(&str)); 168 | free(str); 169 | 170 | urlcompoments_t *components = copy_urlcompoments(url); 171 | if (components) { 172 | printf("copy_urlcompoments - scheme: '%s'\n", components->scheme); 173 | printf("copy_urlcompoments - user: '%s'\n", components->user); 174 | printf("copy_urlcompoments - password: '%s'\n", components->password); 175 | printf("copy_urlcompoments - host: '%s'\n", components->host); 176 | printf("copy_urlcompoments - port: %d\n", components->port); 177 | printf("copy_urlcompoments - path: '%s'\n", components->path); 178 | printf("copy_urlcompoments - query: '%s'\n", components->query); 179 | printf("copy_urlcompoments - fragment: '%s'\n", components->fragment); 180 | free_urlcomponents(components); 181 | } 182 | } 183 | 184 | __("base64"); { 185 | str = copy_base64encode(s1); 186 | printf("copy_base64encode(s1): '%s'\n", str); 187 | printf("base64decode(encoded_str): '%s'\n", base64decode(&str)); 188 | free(str); 189 | } 190 | 191 | __("md5"); { 192 | md5context_t md5; 193 | unsigned char decrypt[16]; 194 | size_t len = strlen(s2); 195 | int i; 196 | 197 | md5init(&md5); 198 | md5update(&md5, s2, len); 199 | md5final(decrypt, &md5); 200 | 201 | printf("copy_md5(s2): '"); 202 | for(i = 0; i < 16; i++) { 203 | printf("%02x", decrypt[i]); 204 | } 205 | printf("'\n"); 206 | 207 | // or 208 | 209 | str = copy_md5(s3); 210 | printf("copy_md5(s3): '%s'\n", str); 211 | free(str); 212 | } 213 | 214 | __("slashes"); { 215 | str = copy_addslashes("ab'cd\"dd\\..."); 216 | printf("copy_addslashes: '%s'\n", str); 217 | printf("stripslashes: '%s'\n", stripslashes(&str)); 218 | free(str); 219 | } 220 | 221 | return 0; 222 | } 223 | 224 | -------------------------------------------------------------------------------- /src/md5.c: -------------------------------------------------------------------------------- 1 | // 2 | // md5.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 11/6/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include "md5.h" 10 | 11 | #define S11 7 12 | #define S12 12 13 | #define S13 17 14 | #define S14 22 15 | #define S21 5 16 | #define S22 9 17 | #define S23 14 18 | #define S24 20 19 | #define S31 4 20 | #define S32 11 21 | #define S33 16 22 | #define S34 23 23 | #define S41 6 24 | #define S42 10 25 | #define S43 15 26 | #define S44 21 27 | 28 | static unsigned char PADDING[64] = { 29 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 32 | }; 33 | 34 | /* F, G, H and I are basic MD5 functions. */ 35 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 36 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) 37 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 38 | #define I(x, y, z) ((y) ^ ((x) | (~z))) 39 | 40 | /* ROTATE_LEFT rotates x left n bits. */ 41 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 42 | 43 | /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. 44 | Rotation is separate from addition to prevent recomputation. */ 45 | #define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } 46 | #define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } 47 | #define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } 48 | #define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); } 49 | 50 | /* Encodes input (uint32_t) into output (unsigned char). Assumes len is 51 | a multiple of 4. */ 52 | static void _encode(unsigned char *output, uint32_t *input, size_t len) 53 | { 54 | size_t i, j; 55 | 56 | for(i = 0, j = 0; j < len; i++, j += 4) { 57 | output[j] = (unsigned char)(input[i] & 0xff); 58 | output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); 59 | output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); 60 | output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); 61 | } 62 | } 63 | 64 | /* Decodes input (unsigned char) into output (uint32_t). Assumes len is 65 | a multiple of 4. */ 66 | static void _decode(uint32_t *output, unsigned char *input, size_t len) 67 | { 68 | size_t i, j; 69 | 70 | for (i = 0, j = 0; j < len; i++, j += 4) { 71 | output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) | 72 | (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24); 73 | } 74 | } 75 | 76 | /* MD5 basic transformation. Transforms state based on block. */ 77 | static void md5transform(uint32_t state[4], unsigned char block[64]) 78 | { 79 | uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; 80 | 81 | _decode(x, block, 64); 82 | 83 | /* Round 1 */ 84 | FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ 85 | FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ 86 | FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ 87 | FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ 88 | FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ 89 | FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ 90 | FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ 91 | FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ 92 | FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ 93 | FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ 94 | FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ 95 | FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ 96 | FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ 97 | FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ 98 | FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ 99 | FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ 100 | 101 | /* Round 2 */ 102 | GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ 103 | GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ 104 | GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ 105 | GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ 106 | GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ 107 | GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ 108 | GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ 109 | GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ 110 | GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ 111 | GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ 112 | GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ 113 | GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ 114 | GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ 115 | GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ 116 | GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ 117 | GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ 118 | 119 | /* Round 3 */ 120 | HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ 121 | HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ 122 | HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ 123 | HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ 124 | HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ 125 | HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ 126 | HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ 127 | HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ 128 | HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ 129 | HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ 130 | HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ 131 | HH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ 132 | HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ 133 | HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ 134 | HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ 135 | HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ 136 | 137 | /* Round 4 */ 138 | II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ 139 | II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ 140 | II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ 141 | II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ 142 | II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ 143 | II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ 144 | II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ 145 | II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ 146 | II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ 147 | II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ 148 | II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ 149 | II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ 150 | II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ 151 | II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ 152 | II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ 153 | II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ 154 | 155 | state[0] += a; 156 | state[1] += b; 157 | state[2] += c; 158 | state[3] += d; 159 | 160 | /* Zeroize sensitive information. */ 161 | memset((unsigned char *)x, 0, sizeof(x)); 162 | } 163 | 164 | 165 | 166 | /* MD5 initialization. Begins an MD5 operation, writing a new context. */ 167 | void md5init(md5context_t *context) 168 | { 169 | /* 将当前的有效信息的长度设成0,这个很简单,还没有有效信息,长度当然是0了 */ 170 | context->count[0] = context->count[1] = 0; 171 | 172 | /* Load magic initialization constants. */ 173 | context->state[0] = 0x67452301; 174 | context->state[1] = 0xefcdab89; 175 | context->state[2] = 0x98badcfe; 176 | context->state[3] = 0x10325476; 177 | } 178 | 179 | /* MD5 block update operation. Continues an MD5 message-digest 180 | operation, processing another message block, and updating the 181 | context. */ 182 | void md5update(md5context_t *context, string_t input, size_t length) 183 | { 184 | unsigned int i, index, partLen; 185 | 186 | /* Compute number of bytes mod 64 */ 187 | index = (unsigned int)((context->count[0] >> 3) & 0x3F); 188 | 189 | /* Update number of bits *//*更新已有信息的bits长度*/ 190 | if ((context->count[0] += ((uint32_t)length << 3)) < ((uint32_t)length << 3)) { 191 | context->count[1]++; 192 | } 193 | context->count[1] += ((uint32_t)length >> 29); 194 | 195 | /*计算已有的字节数长度还差多少字节可以 凑成64的整倍数*/ 196 | partLen = 64 - index; 197 | 198 | /* Transform as many times as possible. */ 199 | if (length >= partLen) { 200 | /* 用当前输入的内容把context->buffer的内容补足512bits */ 201 | memcpy((unsigned char *)&context->buffer[index], 202 | (unsigned char *)input, 203 | partLen); 204 | /* 用基本函数对填充满的512bits(已经保存到context->buffer中) 205 | 做一次转换,转换结果保存到context->state中 */ 206 | md5transform(context->state, context->buffer); 207 | 208 | /* 209 | 对当前输入的剩余字节做转换(如果剩余的字节<在输入的input缓冲区中>大于512bits的话 ), 210 | 转换结果保存到context->state中 211 | */ 212 | for(i = partLen; i + 63 < length; i += 64 ) { 213 | md5transform(context->state, (unsigned char *)&input[i]); 214 | } 215 | 216 | index = 0; 217 | } else { 218 | i = 0; 219 | } 220 | 221 | /* Buffer remaining input */ 222 | memcpy((unsigned char *)&context->buffer[index], 223 | (unsigned char *)&input[i], 224 | length - i); 225 | } 226 | 227 | /* MD5 finalization. Ends an MD5 message-digest operation, writing the 228 | the message digest and zeroizing the context. */ 229 | void md5final(unsigned char digest[16], md5context_t *context) 230 | { 231 | unsigned char bits[8]; 232 | unsigned int index, padLen; 233 | 234 | /* Save number of bits */ 235 | /*将要被转换的信息(所有的)的bits长度拷贝到bits中*/ 236 | _encode(bits, context->count, 8); 237 | 238 | /* Pad out to 56 mod 64. */ 239 | /* 计算所有的bits长度的字节数的模64, 64bytes=512bits*/ 240 | index = (unsigned int)((context->count[0] >> 3) & 0x3f); 241 | /*计算需要填充的字节数,padLen的取值范围在1-64之间*/ 242 | padLen = (index < 56) ? (56 - index) : (120 - index); 243 | /*这一次函数调用绝对不会再导致MD5Transform的被调用,因为这一次不会填满512bits*/ 244 | md5update(context, (string_t)PADDING, padLen); 245 | 246 | /* Append length (before padding) */ 247 | md5update(context, (string_t)bits, 8); 248 | 249 | /* Store state in digest */ 250 | _encode(digest, context->state, 16); 251 | 252 | /* Zeroize sensitive information. */ 253 | memset((unsigned char *)context, 0, sizeof(*context)); 254 | } 255 | 256 | string_t copy_md5(const string_t input) 257 | { 258 | static md5context_t md5; 259 | bool inited = false; 260 | 261 | if (!inited) { 262 | md5init(&md5); 263 | inited = true; 264 | } 265 | 266 | unsigned char decrypt[16]; 267 | const size_t len = strlen(input); 268 | const string_t result = (string_t)malloc(sizeof(char) * (32 + 1)); 269 | 270 | md5update(&md5, input, len); 271 | md5final(decrypt, &md5); 272 | 273 | int i; 274 | for(i = 0; i < 16; i++) { 275 | sprintf(result + i * 2, "%02x", decrypt[i]); 276 | } 277 | 278 | return result; 279 | } -------------------------------------------------------------------------------- /src/md5.h: -------------------------------------------------------------------------------- 1 | // 2 | // md5.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 11/6/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_md5_h 10 | #define string_c_md5_h 11 | 12 | #include "string.h" 13 | 14 | /* MD5 context */ 15 | typedef struct { 16 | uint32_t state[4]; 17 | uint32_t count[2]; 18 | unsigned char buffer[64]; 19 | } md5context_t; 20 | 21 | void md5init(md5context_t *context); 22 | void md5update(md5context_t *context, string_t input, size_t length); 23 | void md5final(unsigned char digest[16], md5context_t *context); 24 | 25 | /** 26 | * 生成MD5字符串 27 | * 28 | * @param input 输入字符串 29 | * @return 返回32字节的十六进制MD5字符串 30 | */ 31 | string_t copy_md5(const string_t input); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/repeat.c: -------------------------------------------------------------------------------- 1 | // 2 | // repeat.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/25/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include "repeat.h" 10 | 11 | string_t copy_repeat(string_t input, size_t multiplier) 12 | { 13 | string_t result; 14 | string_t p; 15 | size_t i; 16 | 17 | size_t len = strlen(input); 18 | 19 | result = (string_t)malloc(sizeof(char) * (len * multiplier + 1)); 20 | 21 | p = result; 22 | for (i = 0; i < multiplier; i++) { 23 | memcpy(p, input, len); 24 | p += len; 25 | } 26 | *p = '\0'; 27 | 28 | return result; 29 | } 30 | 31 | string_t copy_strpad(string_t input, size_t pad_length, string_t pad_string, unsigned pad_type) 32 | { 33 | size_t input_len = strlen(input); 34 | size_t pad_str_len = strlen(pad_string); 35 | size_t left = 0; 36 | size_t right; 37 | size_t i; 38 | 39 | if (pad_length <= input_len) { 40 | return copy_str(input); 41 | } 42 | 43 | string_t result = (string_t)malloc(sizeof(char) * (pad_length + 1)); 44 | 45 | if (pad_type & STR_PAD_RIGHT) { 46 | left = pad_length - input_len; 47 | if (pad_type & STR_PAD_LEFT) { 48 | left /= 2; 49 | } 50 | } 51 | 52 | memcpy(result + left, input, input_len); 53 | 54 | right = left + input_len; 55 | for (i = 0; i < pad_length; i++) { 56 | if (i < left || i >= right) { 57 | *(result + i) = *(pad_string + (i % pad_str_len)); 58 | } else { 59 | i += input_len - 1; 60 | } 61 | } 62 | 63 | *(result + pad_length) = '\0'; 64 | 65 | return result; 66 | } -------------------------------------------------------------------------------- /src/repeat.h: -------------------------------------------------------------------------------- 1 | // 2 | // repeat.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/25/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_repeat_h 10 | #define string_c_repeat_h 11 | 12 | #include "string.h" 13 | 14 | #define STR_PAD_LEFT 0x01 15 | #define STR_PAD_RIGHT 0x02 16 | #define STR_PAD_BOTH 0x03 17 | 18 | /** 19 | * 重复一个字符串 20 | * 21 | * @param input 待操作的字符串 22 | * @param multiplier `input`被重复的次数 23 | * @return 返回`input`重复`multiplier`次后的结果 24 | */ 25 | string_t copy_repeat(string_t input, size_t multiplier); 26 | 27 | /** 28 | * 使用另一个字符串填充字符串为指定长度 29 | * 30 | * @param input 输入字符串 31 | * @param pad_length 如果`pad_length`的值是负数,小于或者等于输入字符串的长度,不会发生任何填充 32 | * @param pad_string 如果填充字符的长度不能被`pad_string`整除,那么`pad_string`可能会被缩短 33 | * @param pad_type 填充对齐的方式,可能值为 STR_PAD_RIGHT,STR_PAD_LEFT 或 STR_PAD_BOTH 34 | * @return 返回填充后的字符串 35 | */ 36 | string_t copy_strpad(string_t input, size_t pad_length, string_t pad_string, unsigned pad_type); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/replace.c: -------------------------------------------------------------------------------- 1 | // 2 | // replace.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/28/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include "repeat.h" 10 | 11 | string_t strtr(string_t *str, const string_t from, const string_t to) 12 | { 13 | string_t s = *str; 14 | 15 | while (*s != '\0') { 16 | string_t p = strchr(from, *s); 17 | if (p != NULL) { 18 | *s = *(to + (p - from)); 19 | } 20 | s++; 21 | } 22 | 23 | return *str; 24 | } 25 | 26 | string_t copy_strreplace(const string_t search, const string_t replace, const string_t subject, const bool ignorecase) 27 | { 28 | size_t len_subject = strlen(subject); 29 | size_t len_search = strlen(search); 30 | size_t len_replace = strlen(replace); 31 | 32 | size_t count = substr_count(subject, search); 33 | 34 | size_t len = len_subject - len_search * count + len_replace + count; 35 | 36 | string_t result = (string_t)malloc(sizeof(char) * (len + 1)); 37 | 38 | size_t i = 0; 39 | size_t c = 0; 40 | 41 | int (* cmp)(const char *, const char *, size_t) = ignorecase ? strncasecmp : strncmp; 42 | while (i <= len_subject) { 43 | if (cmp(subject + i, search, len_search) == 0) { 44 | memcpy(result + c, replace, len_replace); 45 | c += len_replace; 46 | i += len_search; 47 | } else { 48 | *(result + c) = *(subject + i); 49 | c++; 50 | i++; 51 | } 52 | } 53 | 54 | return result; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/replace.h: -------------------------------------------------------------------------------- 1 | // 2 | // replace.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/28/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_replace_h 10 | #define string_c_replace_h 11 | 12 | #include "string.h" 13 | 14 | /** 15 | * 转换指定字符 16 | * 17 | * @param str 待转换的字符串 18 | * @param from 字符串中与将要被转换的目的字符`to`相对应的源字符 19 | * @param to 字符串中与将要被转换的字符`from`相对应的目的字符 20 | * @return 返回转换后的字符串 21 | */ 22 | string_t strtr(string_t *str, const string_t from, const string_t to); 23 | 24 | /** 25 | * 子字符串替换 26 | * 27 | * @param search 查找的目标值 28 | * @param replace `search`的替换值 29 | * @param subject 执行替换的数组或者字符串 30 | * @param ignorecase 是否忽略大小写 31 | * @return 该函数返回替换后的数组或者字符串 32 | */ 33 | string_t copy_strreplace(const string_t search, const string_t replace, const string_t subject, const bool ignorecase); 34 | 35 | /** 36 | * 子字符串替换 37 | * 38 | * @param search 查找的目标值 39 | * @param replace `search`的替换值 40 | * @param subject 执行替换的数组或者字符串 41 | * @return 该函数返回替换后的数组或者字符串 42 | */ 43 | #define copy_replace(search, replace, subject) copy_strreplace(search, replace, subject, false) 44 | 45 | /** 46 | * 子字符串替换(忽略大小写) 47 | * 48 | * @param search 查找的目标值 49 | * @param replace `search`的替换值 50 | * @param subject 执行替换的数组或者字符串 51 | * @return 该函数返回替换后的数组或者字符串 52 | */ 53 | #define copy_ireplace(search, replace, subject) copy_strreplace(search, replace, subject, true) 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/slashes.c: -------------------------------------------------------------------------------- 1 | // 2 | // slashes.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 11/8/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include "slashes.h" 10 | 11 | string_t copy_addslashes(const string_t str) 12 | { 13 | size_t len = strlen(str); 14 | string_t result = (string_t)malloc(sizeof(char) * (len * 2 + 1)); 15 | register string_t s = str; 16 | register string_t p = result; 17 | 18 | while (*s != '\0') { 19 | if (*s == '\'' || *s == '"' || *s == '\\') { 20 | *p++ = '\\'; 21 | } 22 | *p++ = *s++; 23 | } 24 | 25 | result[p - result] = '\0'; 26 | 27 | return result; 28 | } 29 | 30 | string_t stripslashes(string_t *str) 31 | { 32 | register string_t s = *str; 33 | register string_t p = s; 34 | size_t len = strlen(s); 35 | const string_t se = s + len; 36 | 37 | while (s < se) { 38 | if (s[0] == '\\' && s[1] != '\0') { 39 | s++; 40 | } else { 41 | *p++ = *s++; 42 | } 43 | } 44 | 45 | *p = '\0'; 46 | 47 | return *str; 48 | } -------------------------------------------------------------------------------- /src/slashes.h: -------------------------------------------------------------------------------- 1 | // 2 | // slashes.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 11/8/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_slashes_h 10 | #define string_c_slashes_h 11 | 12 | #include "string.h" 13 | 14 | /** 15 | * 返回字符串,该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线。 16 | * 这些字符是单引号(')、双引号(")、反斜线(\) 17 | * 18 | * @param str 要转义的字符串 19 | * @return 返回转义后的字符串 20 | */ 21 | string_t copy_addslashes(const string_t str); 22 | 23 | /** 24 | * 去除字符串的转义反斜线 25 | * 26 | * @param str 输入字符串 27 | * @return 返回一个去除转义反斜线后的字符串 28 | */ 29 | string_t stripslashes(string_t *str); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/strcase.c: -------------------------------------------------------------------------------- 1 | // 2 | // strcase.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/23/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include "strcase.h" 10 | 11 | string_t strcase(string_t *str, size_t length, bool to_lower) 12 | { 13 | string_t p = *str; 14 | if (p != NULL) { 15 | int (*tocase)(int _c) = to_lower ? tolower : toupper; 16 | 17 | size_t len = strlen(p); 18 | if (length > 0 && length < len) { 19 | len = length; 20 | } 21 | 22 | string_t end = p + len; 23 | 24 | while (p < end) { 25 | *p = tocase(*p); 26 | p++; 27 | } 28 | } 29 | 30 | return *str; 31 | } 32 | 33 | 34 | string_t ucwords(string_t *str) 35 | { 36 | if (str != NULL) { 37 | size_t len = strlen(*str); 38 | 39 | string_t p = *str; 40 | string_t end = p + len; 41 | 42 | while (p < end) { 43 | while (!isalpha(*p) && p < end) { 44 | p++; 45 | } 46 | if (p < end) { 47 | if (p == *str || isspace(*(p - 1))) { 48 | *p = toupper(*p); 49 | } 50 | while (isalpha(*p) && p < end) { 51 | p++; 52 | } 53 | } 54 | } 55 | } 56 | return *str; 57 | } 58 | -------------------------------------------------------------------------------- /src/strcase.h: -------------------------------------------------------------------------------- 1 | // 2 | // strcase.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/23/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_strcase_h 10 | #define string_c_strcase_h 11 | 12 | #include "string.h" 13 | 14 | /** 15 | * 转换字符串大小写 16 | * 17 | * @param str 待转换的字符串 18 | * @param length 转换字符串长度,如果小于等于0或大于`str`的长度,则转换整个字符串 19 | * @param to_lower 为true则转换成大写字母,否则转换成小写字母 20 | * @return 返回转换后的字符串 21 | */ 22 | string_t strcase(string_t *str, size_t length, bool to_lower); 23 | 24 | /** 25 | * 将字符串转化为小写 26 | * 27 | * @param str (string_t *) 输入字符串,str本身的值会被改变,所以这里不允许传入字符串常量。 28 | * @return 返回转换后的字符串 29 | */ 30 | #define strtolower(str) strcase(str, 0, true) 31 | 32 | /** 33 | * 将字符串转化为大写 34 | * 35 | * @param str (string_t *) 输入字符串,str本身的值会被改变,所以str必须是保存在heap上的。 36 | * @return 返回转换后的字符串 37 | */ 38 | #define strtoupper(str) strcase(str, 0, false) 39 | 40 | /** 41 | * 使一个字符串的第一个字符小写 42 | * 43 | * @param str (string_t *) 输入字符串,str本身的值会被改变,所以str必须是保存在heap上的。 44 | * @return 返回转换后的字符串 45 | */ 46 | #define lcfirst(str) strcase(str, 1, true) 47 | 48 | /** 49 | * 将字符串的首字母转换为大写 50 | * 51 | * @param str (string_t *) 输入字符串,str本身的值会被改变,所以str必须是保存在heap上的。 52 | * @return 返回转换后的字符串 53 | */ 54 | #define ucfirst(str) strcase(str, 1, false) 55 | 56 | /** 57 | * 将字符串中每个单词的首字母转换为大写 58 | * 59 | * @param str 输入字符串,str本身的值会被改变,所以str必须是保存在heap上的。 60 | * @return 返回转换后的字符串 61 | */ 62 | string_t ucwords(string_t *str); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/string.h: -------------------------------------------------------------------------------- 1 | // 2 | // string.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/22/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_string_h 10 | #define string_c_string_h 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | typedef char * string_t; 19 | 20 | #include "strpos.h" 21 | #include "substr.h" 22 | #include "strcase.h" 23 | #include "trim.h" 24 | #include "repeat.h" 25 | #include "replace.h" 26 | #include "html.h" 27 | #include "url.h" 28 | #include "base64.h" 29 | #include "md5.h" 30 | #include "slashes.h" 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/strpos.c: -------------------------------------------------------------------------------- 1 | // 2 | // strpos.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/22/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include "strpos.h" 10 | 11 | long _strpos(const string_t haystack,const string_t needle, bool ignorecase, bool from_right) 12 | { 13 | size_t hlen = strlen(haystack); 14 | size_t nlen = strlen(needle); 15 | 16 | if (nlen > hlen) { 17 | return -1; 18 | } 19 | 20 | int (* cmp)(const char *, const char *, size_t) = ignorecase ? strncasecmp : strncmp; 21 | size_t len = hlen - nlen; 22 | register long i = from_right ? len : 0; 23 | 24 | while (i >= 0 && i <= len) { 25 | if (cmp(haystack + i, needle, nlen) == 0) { 26 | return i; 27 | } 28 | if (from_right) { 29 | i--; 30 | } else { 31 | i++; 32 | } 33 | } 34 | 35 | return -1; 36 | } -------------------------------------------------------------------------------- /src/strpos.h: -------------------------------------------------------------------------------- 1 | // 2 | // strpos.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/22/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_strpos_h 10 | #define string_c_strpos_h 11 | 12 | #include "string.h" 13 | 14 | long _strpos(const string_t haystack,const string_t needle, bool ignorecase, bool from_right); 15 | 16 | /** 17 | * 在字符串`haystack`中查找子字符串`needle`的索引位置 18 | * 19 | * @param haystack (const string_t) 被搜索的字符串 20 | * @param needle (const string_t) 查找的子字符串 21 | * @return 返回字符串`needle`所在的索引位置,如果未找到,返回-1. 22 | */ 23 | #define strpos(haystack, needle) _strpos(haystack, needle, false, false) 24 | 25 | /** 26 | * 在字符串`haystack`中查找子字符串`needle`的索引位置,不区分大小写字母 27 | * 28 | * @param haystack (const string_t) 被搜索的字符串 29 | * @param needle (const string_t) 查找的子字符串 30 | * @return 返回字符串`needle`所在的索引位置,如果未找到,返回-1. 31 | */ 32 | #define stripos(haystack, needle) _strpos(haystack, needle, true, false) 33 | 34 | /** 35 | * 在字符串`haystack`中查找子字符串`needle`的索引位置,从字符串右侧开始搜索 36 | * 37 | * @param haystack (const string_t) 被搜索的字符串 38 | * @param needle (const string_t) 查找的子字符串 39 | * @return 返回字符串`needle`所在的索引位置,如果未找到,返回-1. 40 | */ 41 | #define strrpos(haystack, needle) _strpos(haystack, needle, false, true) 42 | 43 | /** 44 | * 在字符串`haystack`中查找子字符串`needle`的索引位置,从字符串右侧开始搜索, 45 | * 且不区分大小写字母 46 | * 47 | * @param haystack (const string_t) 被搜索的字符串 48 | * @param needle (const string_t) 查找的子字符串 49 | * @return 返回字符串`needle`所在的索引位置,如果未找到,返回-1. 50 | */ 51 | #define strripos(haystack, needle) _strpos(haystack, needle, true, true) 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/substr.c: -------------------------------------------------------------------------------- 1 | // 2 | // substr.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/23/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include "substr.h" 10 | 11 | string_t copy_substr(const string_t str, long start, long length) 12 | { 13 | if (str == NULL) { 14 | return NULL; 15 | } 16 | 17 | size_t len = strlen(str); 18 | 19 | if (len == 0) { 20 | return NULL; 21 | } 22 | 23 | if (start < 0) { 24 | start += len; 25 | } 26 | 27 | if (start < 0) { 28 | start = 0; 29 | } else if (start >= len) { 30 | return NULL; 31 | } 32 | 33 | if (length < 0) { 34 | length = len + length - start; 35 | if (length < 0) { 36 | return NULL; 37 | } 38 | } 39 | 40 | if (start + length > len) { 41 | length = len - start; 42 | } 43 | 44 | string_t result = (string_t)calloc(sizeof(char), length + 1); 45 | 46 | memcpy(result, str + start, length); 47 | 48 | return result; 49 | } 50 | 51 | size_t substr_count(const string_t haystack, const string_t needle) 52 | { 53 | size_t count = 0; 54 | 55 | long pos; 56 | string_t p = haystack; 57 | 58 | while ((pos = strpos(p, needle)) >= 0) { 59 | count++; 60 | p += pos + 1; 61 | } 62 | 63 | return count; 64 | } 65 | -------------------------------------------------------------------------------- /src/substr.h: -------------------------------------------------------------------------------- 1 | // 2 | // substr.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/23/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_substr_h 10 | #define string_c_substr_h 11 | 12 | #include "string.h" 13 | 14 | /** 15 | * 返回字符串 str 由 start 和 length 参数指定的子字符串。 16 | * 17 | * @param str 输入字符串。如果 str 为 NULL 或空串,则将返回 NULL。 18 | * @param start 如果 start 是非负数,返回的字符串将从 str 的 start 位置开始,\ 19 | * 从 0 开始计算。\ 20 | * 如果 start 是负数,返回的字符串将从 str 结尾处向前数\ 21 | * 第 start 个字符开始。\ 22 | * 如果 str 的长度小于或等于 start,将返回 NULL。 23 | * @param length 如果提供了正数的 length,返回的字符串将从 start 处开始最多包括 \ 24 | * length 个字符(取决于 str 的长度)。\ 25 | * 如果提供了负数的 length,那么 str 末尾处的许多字符将会被漏掉\ 26 | * (若 start 是负数则从字符串尾部算起)。如果 start 不在这段文本中,\ 27 | * 那么将返回 NULL。\ 28 | * 如果提供了值为 0,将返回空字符串("\0")。 29 | * @return 返回提取的子字符串, 或者在失败时返回 NULL。 30 | */ 31 | string_t copy_substr(const string_t str, long start, long length); 32 | 33 | /** 34 | * 复制字符串 35 | * 36 | * @param str (const string_t) 输入字符串。如果 str 为 NULL 或空串,则将返回 NULL。 37 | * @return 返回复制字符串的首地址,或者在失败时返回 NULL。 38 | */ 39 | #define copy_str(str) strdup(str) 40 | 41 | /** 42 | * 计算字串出现的次数。注意 needle 区分大小写。 43 | * 44 | * @param haystack 在此字符串中进行搜索 45 | * @param needle 要搜索的字符串 46 | * @return 返回子字符串needle 在字符串 haystack 中出现的次数 47 | */ 48 | size_t substr_count(const string_t haystack, const string_t needle); 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/trim.c: -------------------------------------------------------------------------------- 1 | // 2 | // trim.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/24/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include "trim.h" 10 | 11 | string_t strtrim(string_t *str, unsigned flags, string_t chars) 12 | { 13 | string_t s = *str; 14 | size_t len = strlen(s); 15 | 16 | if (flags & STR_TRIM_FLAGS_LEFT) { 17 | size_t pos = strspn(s, chars); 18 | if (pos < len) { 19 | len -= pos; 20 | memmove(s, s + pos, len + 1); 21 | } 22 | } 23 | 24 | if (flags & STR_TRIM_FLAGS_RIGHT) { 25 | string_t p = s + len - 1; 26 | while (p != s && strchr(chars, *p) != NULL) { 27 | p--; 28 | } 29 | *(p + 1) = '\0'; 30 | } 31 | 32 | return s; 33 | } -------------------------------------------------------------------------------- /src/trim.h: -------------------------------------------------------------------------------- 1 | // 2 | // trim.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 10/24/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_trim_h 10 | #define string_c_trim_h 11 | 12 | #include "string.h" 13 | 14 | #define STR_TRIM_CHARS " \r\n\t\v" 15 | #define STR_TRIM_FLAGS_LEFT 0x01 16 | #define STR_TRIM_FLAGS_RIGHT 0x02 17 | 18 | 19 | string_t strtrim(string_t *str, unsigned flags, string_t chars); 20 | 21 | /** 22 | * 删除字符串开头的空白字符 23 | * 24 | * @param str (string_t *) 输入字符串,str本身的值会被改变,所以str必须是保存在heap上的。 25 | * @return 返回一个删除了 str 最左边的空白字符的字符串。 26 | */ 27 | #define ltrim(str) strtrim(str, STR_TRIM_FLAGS_LEFT, STR_TRIM_CHARS) 28 | 29 | /** 30 | * 删除字符串末端的空白字符 31 | * 32 | * @param str (string_t *) 输入字符串,str本身的值会被改变,所以str必须是保存在heap上的。 33 | * @return 返回一个删除了 str 最右边的空白字符的字符串。 34 | */ 35 | #define rtrim(str) strtrim(str, STR_TRIM_FLAGS_RIGHT, STR_TRIM_CHARS) 36 | 37 | /** 38 | * 删除字符串首尾处的空白字符 39 | * 40 | * @param str (string_t *) 输入字符串,str本身的值会被改变,所以str必须是保存在heap上的。 41 | * @return 返回一个删除了 str 首尾处的空白字符的字符串。 42 | */ 43 | #define trim(str) strtrim(str, STR_TRIM_FLAGS_LEFT | STR_TRIM_FLAGS_RIGHT, STR_TRIM_CHARS) 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/url.c: -------------------------------------------------------------------------------- 1 | // 2 | // url.c 3 | // string-c 4 | // 5 | // Created by Cator Vee on 11/1/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #include "url.h" 10 | 11 | string_t copy_urlencode(const string_t str) 12 | { 13 | register char c; 14 | register size_t i = 0; 15 | size_t len = strlen(str); 16 | string_t result = (string_t)malloc(sizeof(char) * (len * 3 + 1)); 17 | register string_t p = result; 18 | 19 | while ((c = *(str + i++)) != '\0') { 20 | if (c == ' ') { 21 | *p++ = '+'; 22 | } else if (!isalnum(c) && strchr("_-.", c) == NULL) { 23 | sprintf(p, "%%%02X", (unsigned char)c); 24 | p += 3; 25 | } else { 26 | *p++ = c; 27 | } 28 | } 29 | 30 | *p = '\0'; 31 | 32 | return result; 33 | } 34 | 35 | static char hexdec(char c) 36 | { 37 | if (c>='0' && c<='9') return c - '0'; 38 | if (c>='a' && c<='z') return c - 'a' + 10; 39 | if (c>='A' && c<='Z') return c - 'A' + 10; 40 | 41 | return 0; 42 | } 43 | 44 | string_t urldecode(string_t *str) 45 | { 46 | register string_t s = *str; 47 | register string_t p = s; 48 | string_t se = *str + strlen(*str) - 1; 49 | 50 | while (s <= se) { 51 | if (*s == '+') { 52 | *p = ' '; 53 | } else if (*s == '%' && (se - s) >= 2 && isxdigit((int) *(s + 1)) 54 | && isxdigit((int) *(s + 2))) { 55 | *p = hexdec(*(s + 1)) * 16 + hexdec(*(s + 2)); 56 | s += 2; 57 | } else { 58 | *p = *s; 59 | } 60 | s++; 61 | p++; 62 | } 63 | 64 | *p = '\0'; 65 | 66 | return *str; 67 | } 68 | 69 | /* 参考PHP parse_url() 源代码 */ 70 | urlcompoments_t *copy_urlcompoments(string_t str) 71 | { 72 | char port_buf[6]; 73 | urlcompoments_t *result = calloc(1, sizeof(urlcompoments_t)); 74 | char const *s, *e, *p, *pp, *ue; 75 | size_t len = strlen(str); 76 | 77 | s = str; 78 | ue = s + len; 79 | 80 | /* parse scheme */ 81 | if ((e = memchr(s, ':', len)) && (e - s)) { 82 | /* validate scheme */ 83 | p = s; 84 | while (p < e) { 85 | /* scheme = 1*[ lowalpha | digit | "+" | "-" | "." ] */ 86 | if (!isalpha(*p) && !isdigit(*p) && *p != '+' && *p != '.' && *p != '-') { 87 | if (e + 1 < ue) { 88 | goto parse_port; 89 | } else { 90 | goto just_path; 91 | } 92 | } 93 | p++; 94 | } 95 | 96 | if (*(e + 1) == '\0') { /* only scheme is available */ 97 | result->scheme = strndup(s, (e - s)); 98 | goto end; 99 | } 100 | 101 | /* 102 | * certain schemas like mailto: and zlib: may not have any / after them 103 | * this check ensures we support those. 104 | */ 105 | if (*(e+1) != '/') { 106 | /* check if the data we get is a port this allows us to 107 | * correctly parse things like a.com:80 108 | */ 109 | p = e + 1; 110 | while (isdigit(*p)) { 111 | p++; 112 | } 113 | 114 | if ((*p == '\0' || *p == '/') && (p - e) < 7) { 115 | goto parse_port; 116 | } 117 | 118 | result->scheme = strndup(s, (e-s)); 119 | 120 | len -= ++e - s; 121 | s = e; 122 | goto just_path; 123 | } else { 124 | result->scheme = strndup(s, (e-s)); 125 | 126 | if (*(e+2) == '/') { 127 | s = e + 3; 128 | if (!strncasecmp("file", result->scheme, sizeof("file"))) { 129 | if (*(e + 3) == '/') { 130 | /* support windows drive letters as in: 131 | file:///c:/somedir/file.txt 132 | */ 133 | if (*(e + 5) == ':') { 134 | s = e + 4; 135 | } 136 | goto nohost; 137 | } 138 | } 139 | } else { 140 | if (!strncasecmp("file", result->scheme, sizeof("file"))) { 141 | s = e + 1; 142 | goto nohost; 143 | } else { 144 | len -= ++e - s; 145 | s = e; 146 | goto just_path; 147 | } 148 | } 149 | } 150 | } else if (e) { /* no scheme; starts with colon: look for port */ 151 | parse_port: 152 | p = e + 1; 153 | pp = p; 154 | 155 | while (pp-p < 6 && isdigit(*pp)) { 156 | pp++; 157 | } 158 | 159 | if (pp - p > 0 && pp - p < 6 && (*pp == '/' || *pp == '\0')) { 160 | long port; 161 | memcpy(port_buf, p, (pp - p)); 162 | port_buf[pp - p] = '\0'; 163 | port = strtol(port_buf, NULL, 10); 164 | if (port > 0 && port <= 65535) { 165 | result->port = (unsigned short) port; 166 | } else { 167 | free(result->scheme); 168 | free(result); 169 | return NULL; 170 | } 171 | } else if (p == pp && *pp == '\0') { 172 | free(result->scheme); 173 | free(result); 174 | return NULL; 175 | } else { 176 | goto just_path; 177 | } 178 | } else { 179 | just_path: 180 | ue = s + len; 181 | goto nohost; 182 | } 183 | 184 | e = ue; 185 | 186 | if (!(p = memchr(s, '/', (ue - s)))) { 187 | char *query, *fragment; 188 | 189 | query = memchr(s, '?', (ue - s)); 190 | fragment = memchr(s, '#', (ue - s)); 191 | 192 | if (query && fragment) { 193 | if (query > fragment) { 194 | p = e = fragment; 195 | } else { 196 | p = e = query; 197 | } 198 | } else if (query) { 199 | p = e = query; 200 | } else if (fragment) { 201 | p = e = fragment; 202 | } 203 | } else { 204 | e = p; 205 | } 206 | 207 | /* check for login and password */ 208 | if ((p = strrchr(s, '@'))) { 209 | if ((pp = memchr(s, ':', (p-s)))) { 210 | if ((pp-s) > 0) { 211 | result->user = strndup(s, (pp-s)); 212 | } 213 | 214 | pp++; 215 | if (p-pp > 0) { 216 | result->password = strndup(pp, (p-pp)); 217 | } 218 | } else { 219 | result->user = strndup(s, (p-s)); 220 | } 221 | 222 | s = p + 1; 223 | } 224 | 225 | /* check for port */ 226 | if (*s == '[' && *(e-1) == ']') { 227 | /* Short circuit portscan, 228 | we're dealing with an 229 | IPv6 embedded address */ 230 | p = s; 231 | } else { 232 | /* memrchr is a GNU specific extension 233 | Emulate for wide compatability */ 234 | for(p = e; *p != ':' && p >= s; p--); 235 | } 236 | 237 | if (p >= s && *p == ':') { 238 | if (!result->port) { 239 | p++; 240 | if (e-p > 5) { /* port cannot be longer then 5 characters */ 241 | free(result->scheme); 242 | free(result->user); 243 | free(result->password); 244 | free(result); 245 | return NULL; 246 | } else if (e - p > 0) { 247 | long port; 248 | memcpy(port_buf, p, (e - p)); 249 | port_buf[e - p] = '\0'; 250 | port = strtol(port_buf, NULL, 10); 251 | if (port > 0 && port <= 65535) { 252 | result->port = (unsigned short)port; 253 | } else { 254 | free(result->scheme); 255 | free(result->user); 256 | free(result->password); 257 | free(result); 258 | return NULL; 259 | } 260 | } 261 | p--; 262 | } 263 | } else { 264 | p = e; 265 | } 266 | 267 | /* check if we have a valid host, if we don't reject the string as url */ 268 | if ((p-s) < 1) { 269 | free(result->scheme); 270 | free(result->user); 271 | free(result->password); 272 | free(result); 273 | return NULL; 274 | } 275 | 276 | result->host = strndup(s, (p-s)); 277 | 278 | if (e == ue) { 279 | goto end; 280 | } 281 | 282 | s = e; 283 | 284 | nohost: 285 | 286 | if ((p = memchr(s, '?', (ue - s)))) { 287 | pp = strchr(s, '#'); 288 | 289 | if (pp && pp < p) { 290 | if (pp - s) { 291 | result->path = strndup(s, (pp-s)); 292 | } 293 | p = pp; 294 | goto label_parse; 295 | } 296 | 297 | if (p - s) { 298 | result->path = strndup(s, (p-s)); 299 | } 300 | 301 | if (pp) { 302 | if (pp - ++p) { 303 | result->query = strndup(p, (pp-p)); 304 | } 305 | p = pp; 306 | goto label_parse; 307 | } else if (++p - ue) { 308 | result->query = strndup(p, (ue-p)); 309 | } 310 | } else if ((p = memchr(s, '#', (ue - s)))) { 311 | if (p - s) { 312 | result->path = strndup(s, (p-s)); 313 | } 314 | 315 | label_parse: 316 | p++; 317 | 318 | if (ue - p) { 319 | result->fragment = strndup(p, (ue-p)); 320 | } 321 | } else { 322 | result->path = strndup(s, (ue-s)); 323 | } 324 | end: 325 | if (result->port == 0 && result->scheme) { 326 | len = strlen(result->scheme); 327 | if (len == 4 && strncasecmp(result->scheme, "http", 4) == 0) { 328 | result->port = 80; 329 | } else if (len == 5 && strncasecmp(result->scheme, "https", 5) == 0) { 330 | result->port = 443; 331 | } else if (len == 3 && strncasecmp(result->scheme, "ftp", 3) == 0) { 332 | result->port = 21; 333 | } 334 | } 335 | return result; 336 | } 337 | 338 | void free_urlcomponents(urlcompoments_t *components) 339 | { 340 | if (components) { 341 | if (components->scheme) { 342 | free(components->scheme); 343 | } 344 | if (components->user) { 345 | free(components->user); 346 | } 347 | if (components->password) { 348 | free(components->password); 349 | } 350 | if (components->host) { 351 | free(components->host); 352 | } 353 | if (components->path) { 354 | free(components->path); 355 | } 356 | if (components->query) { 357 | free(components->query); 358 | } 359 | if (components->fragment) { 360 | free(components->fragment); 361 | } 362 | free(components); 363 | } 364 | } -------------------------------------------------------------------------------- /src/url.h: -------------------------------------------------------------------------------- 1 | // 2 | // url.h 3 | // string-c 4 | // 5 | // Created by Cator Vee on 11/1/13. 6 | // Copyright (c) 2013 Cator Vee. All rights reserved. 7 | // 8 | 9 | #ifndef string_c_url_h 10 | #define string_c_url_h 11 | 12 | #include "string.h" 13 | 14 | typedef struct urlcomponents_t { 15 | string_t scheme; // 协议名称 16 | string_t user; // 用户名 17 | string_t password; // 密码 18 | string_t host; // 主机名或域名 19 | unsigned short port; // 端口号 20 | string_t path; // 路径 21 | string_t query; // 在问号 ? 之后的部分 22 | string_t fragment; // 在散列符号 # 之后的部分 23 | } urlcompoments_t; 24 | 25 | /** 26 | * 此函数便于将字符串编码并将其用于 URL 的请求部分,同时它还便于将变量传递给下一页。 27 | * 28 | * @param str 要编码的字符串 29 | * @return 返回字符串,此字符串中除了 -_. 之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+)。 30 | */ 31 | string_t copy_urlencode(const string_t str); 32 | 33 | /** 34 | * 解码给出的已编码字符串中的任何 %##。 加号('+')被解码成一个空格字符。 35 | * 36 | * @param str 要解码的字符串 37 | * @return 返回解码后的字符串 38 | */ 39 | string_t urldecode(string_t *str); 40 | 41 | /** 42 | * 解析URL字符串并返回URL的各个部分。 43 | * 44 | * @param str 要解析的URL 45 | * @return 如果解析失败,返回NULL,否则返回一个`urlcompoments_t`指针 46 | */ 47 | urlcompoments_t *copy_urlcompoments(string_t str); 48 | 49 | /** 50 | * 释放`urlcompoments_t`变量占用的内存 51 | * 52 | * @param components 要释放的`urlcompoments_t`变量 53 | */ 54 | void free_urlcomponents(urlcompoments_t *components); 55 | 56 | #endif 57 | --------------------------------------------------------------------------------