|
1 /* |
|
2 * Hedgewars, a free turn based strategy game |
|
3 * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com> |
|
4 * |
|
5 * This program is free software; you can redistribute it and/or |
|
6 * modify it under the terms of the GNU General Public License |
|
7 * as published by the Free Software Foundation; either version 2 |
|
8 * of the License, or (at your option) any later version. |
|
9 * |
|
10 * This program is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 * GNU General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License |
|
16 * along with this program; if not, write to the Free Software |
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 */ |
|
19 |
|
20 #include "util.h" |
|
21 #include "logging.h" |
|
22 |
|
23 #include <stddef.h> |
|
24 #include <stdarg.h> |
|
25 #include <stdlib.h> |
|
26 #include <string.h> |
|
27 #include <stdio.h> |
|
28 #include <ctype.h> |
|
29 #include <limits.h> |
|
30 |
|
31 char *flib_asprintf(const char *fmt, ...) { |
|
32 va_list argp; |
|
33 va_start(argp, fmt); |
|
34 char *result = flib_vasprintf(fmt, argp); |
|
35 va_end(argp); |
|
36 return result; |
|
37 } |
|
38 |
|
39 char *flib_vasprintf(const char *fmt, va_list args) { |
|
40 char *result = NULL; |
|
41 if(!log_badargs_if(fmt==NULL)) { |
|
42 int requiredSize = vsnprintf(NULL, 0, fmt, args)+1; // Figure out how much memory we need, |
|
43 if(!log_e_if(requiredSize<0, "Error formatting string with template \"%s\"", fmt)) { |
|
44 char *tmpbuf = flib_malloc(requiredSize); // allocate it |
|
45 if(tmpbuf && vsnprintf(tmpbuf, requiredSize, fmt, args)>=0) { // and then do the actual formatting. |
|
46 result = tmpbuf; |
|
47 tmpbuf = NULL; |
|
48 } |
|
49 free(tmpbuf); |
|
50 } |
|
51 } |
|
52 return result; |
|
53 } |
|
54 |
|
55 char *flib_join(char **parts, int partCount, const char *delimiter) { |
|
56 char *result = NULL; |
|
57 if(!log_badargs_if2(parts==NULL, delimiter==NULL)) { |
|
58 size_t totalSize = 1; |
|
59 size_t delimLen = strlen(delimiter); |
|
60 for(int i=0; i<partCount; i++) { |
|
61 totalSize += strlen(parts[i]) + delimLen; |
|
62 } |
|
63 result = flib_malloc(totalSize); |
|
64 |
|
65 if(result) { |
|
66 size_t outpos = 0; |
|
67 for(int i=0; i<partCount; i++) { |
|
68 if(i>0) { |
|
69 strcpy(result+outpos, delimiter); |
|
70 outpos += delimLen; |
|
71 } |
|
72 strcpy(result+outpos, parts[i]); |
|
73 outpos += strlen(parts[i]); |
|
74 } |
|
75 } |
|
76 } |
|
77 return result; |
|
78 } |
|
79 |
|
80 char *flib_strdupnull(const char *str) { |
|
81 return str==NULL ? NULL : flib_asprintf("%s", str); |
|
82 } |
|
83 |
|
84 void *flib_bufdupnull(const void *buf, size_t size) { |
|
85 void *result = NULL; |
|
86 if(!log_badargs_if(buf==NULL && size>0)) { |
|
87 result = flib_malloc(size); |
|
88 if(result) { |
|
89 memcpy(result, buf, size); |
|
90 } |
|
91 } |
|
92 return result; |
|
93 } |
|
94 |
|
95 void *flib_malloc(size_t size) { |
|
96 void *result = malloc(size); |
|
97 if(!result && size>0) { |
|
98 flib_log_e("Out of memory trying to malloc %zu bytes.", size); |
|
99 } |
|
100 return result; |
|
101 } |
|
102 |
|
103 void *flib_calloc(size_t count, size_t elementsize) { |
|
104 void *result = calloc(count, elementsize); |
|
105 if(!result && count>0 && elementsize>0) { |
|
106 flib_log_e("Out of memory trying to calloc %zu objects of %zu bytes each.", count, elementsize); |
|
107 } |
|
108 return result; |
|
109 } |
|
110 |
|
111 void *flib_realloc(void *ptr, size_t size) { |
|
112 void *result = realloc(ptr, size); |
|
113 if(!result && size>0) { |
|
114 flib_log_e("Out of memory trying to realloc %zu bytes.", size); |
|
115 } |
|
116 return result; |
|
117 } |
|
118 |
|
119 static bool isAsciiAlnum(char c) { |
|
120 return (c>='0' && c<='9') || (c>='a' && c <='z') || (c>='A' && c <='Z'); |
|
121 } |
|
122 |
|
123 char *flib_urlencode(const char *inbuf) { |
|
124 return flib_urlencode_pred(inbuf, isAsciiAlnum); |
|
125 } |
|
126 |
|
127 static size_t countCharsToEscape(const char *inbuf, bool (*needsEscaping)(char c)) { |
|
128 size_t result = 0; |
|
129 for(const char *c=inbuf; *c; c++) { |
|
130 if(needsEscaping(*c)) { |
|
131 result++; |
|
132 } |
|
133 } |
|
134 return result; |
|
135 } |
|
136 |
|
137 char *flib_urlencode_pred(const char *inbuf, bool (*needsEscaping)(char c)) { |
|
138 char *result = NULL; |
|
139 if(inbuf && !log_badargs_if(needsEscaping == NULL)) { |
|
140 size_t insize = strlen(inbuf); |
|
141 if(!log_e_if(insize > SIZE_MAX/4, "String too long: %zu bytes.", insize)) { |
|
142 size_t escapeCount = countCharsToEscape(inbuf, needsEscaping); |
|
143 result = flib_malloc(insize + escapeCount*2 + 1); |
|
144 } |
|
145 if(result) { |
|
146 char *out = result; |
|
147 for(const char *in = inbuf; *in; in++) { |
|
148 if(!needsEscaping(*in)) { |
|
149 *out = *in; |
|
150 out++; |
|
151 } else { |
|
152 snprintf(out, 4, "%%%02x", (unsigned)(*(uint8_t*)in)); |
|
153 out += 3; |
|
154 } |
|
155 } |
|
156 *out = 0; |
|
157 } |
|
158 } |
|
159 return result; |
|
160 } |
|
161 |
|
162 char *flib_urldecode(const char *inbuf) { |
|
163 if(!inbuf) { |
|
164 return NULL; |
|
165 } |
|
166 char *outbuf = flib_malloc(strlen(inbuf)+1); |
|
167 if(!outbuf) { |
|
168 return NULL; |
|
169 } |
|
170 |
|
171 size_t inpos = 0, outpos = 0; |
|
172 while(inbuf[inpos]) { |
|
173 if(inbuf[inpos] == '%' && isxdigit(inbuf[inpos+1]) && isxdigit(inbuf[inpos+2])) { |
|
174 char temp[3] = {inbuf[inpos+1],inbuf[inpos+2],0}; |
|
175 outbuf[outpos++] = strtol(temp, NULL, 16); |
|
176 inpos += 3; |
|
177 } else { |
|
178 outbuf[outpos++] = inbuf[inpos++]; |
|
179 } |
|
180 } |
|
181 outbuf[outpos] = 0; |
|
182 char *shrunk = realloc(outbuf, outpos+1); |
|
183 return shrunk ? shrunk : outbuf; |
|
184 } |
|
185 |
|
186 bool flib_contains_dir_separator(const char *str) { |
|
187 if(!log_badargs_if(!str)) { |
|
188 for(;*str;str++) { |
|
189 if(*str=='\\' || *str=='/') { |
|
190 return true; |
|
191 } |
|
192 } |
|
193 } |
|
194 return false; |
|
195 } |
|
196 |
|
197 bool flib_strempty(const char *str) { |
|
198 return !str || !*str; |
|
199 } |
|
200 |
|
201 int flib_gets(char *str, size_t strlen) { |
|
202 if(fgets(str, strlen, stdin)) { |
|
203 for(char *s=str; *s; s++) { |
|
204 if(*s=='\r' || *s=='\n') { |
|
205 *s = 0; |
|
206 break; |
|
207 } |
|
208 } |
|
209 return 0; |
|
210 } |
|
211 return -1; |
|
212 } |