diff options
Diffstat (limited to 'src/util/strings.c')
-rw-r--r-- | src/util/strings.c | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/src/util/strings.c b/src/util/strings.c new file mode 100644 index 000000000..18f6582e8 --- /dev/null +++ b/src/util/strings.c | |||
@@ -0,0 +1,396 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2005, 2006 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file util/strings.c | ||
23 | * @brief string functions | ||
24 | * @author Nils Durner | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | |||
28 | #include "platform.h" | ||
29 | #if HAVE_ICONV_H | ||
30 | #include <iconv.h> | ||
31 | #endif | ||
32 | #include "gnunet_common.h" | ||
33 | #include "gnunet_strings_lib.h" | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Fill a buffer of the given size with | ||
38 | * count 0-terminated strings (given as varargs). | ||
39 | * If "buffer" is NULL, only compute the amount of | ||
40 | * space required (sum of "strlen(arg)+1"). | ||
41 | * | ||
42 | * Unlike using "snprintf" with "%s", this function | ||
43 | * will add 0-terminators after each string. The | ||
44 | * "GNUNET_string_buffer_tokenize" function can be | ||
45 | * used to parse the buffer back into individual | ||
46 | * strings. | ||
47 | * | ||
48 | * @return number of bytes written to the buffer | ||
49 | * (or number of bytes that would have been written) | ||
50 | */ | ||
51 | unsigned int | ||
52 | GNUNET_STRINGS_buffer_fill (char *buffer, | ||
53 | unsigned int size, unsigned int count, ...) | ||
54 | { | ||
55 | unsigned int needed; | ||
56 | unsigned int slen; | ||
57 | const char *s; | ||
58 | va_list ap; | ||
59 | |||
60 | needed = 0; | ||
61 | va_start (ap, count); | ||
62 | while (count > 0) | ||
63 | { | ||
64 | s = va_arg (ap, const char *); | ||
65 | slen = strlen (s) + 1; | ||
66 | if (buffer != NULL) | ||
67 | { | ||
68 | GNUNET_assert (needed + slen <= size); | ||
69 | memcpy (&buffer[needed], s, slen); | ||
70 | } | ||
71 | needed += slen; | ||
72 | count--; | ||
73 | } | ||
74 | va_end (ap); | ||
75 | return needed; | ||
76 | } | ||
77 | |||
78 | |||
79 | /** | ||
80 | * Given a buffer of a given size, find "count" | ||
81 | * 0-terminated strings in the buffer and assign | ||
82 | * the count (varargs) of type "const char**" to the | ||
83 | * locations of the respective strings in the | ||
84 | * buffer. | ||
85 | * | ||
86 | * @param buffer the buffer to parse | ||
87 | * @param size size of the buffer | ||
88 | * @param count number of strings to locate | ||
89 | * @return offset of the character after the last 0-termination | ||
90 | * in the buffer, or 0 on error. | ||
91 | */ | ||
92 | unsigned int | ||
93 | GNUNET_STRINGS_buffer_tokenize (const char *buffer, | ||
94 | unsigned int size, unsigned int count, ...) | ||
95 | { | ||
96 | unsigned int start; | ||
97 | unsigned int needed; | ||
98 | const char **r; | ||
99 | va_list ap; | ||
100 | |||
101 | needed = 0; | ||
102 | va_start (ap, count); | ||
103 | while (count > 0) | ||
104 | { | ||
105 | r = va_arg (ap, const char **); | ||
106 | start = needed; | ||
107 | while ((needed < size) && (buffer[needed] != '\0')) | ||
108 | needed++; | ||
109 | if (needed == size) | ||
110 | { | ||
111 | va_end (ap); | ||
112 | return 0; /* error */ | ||
113 | } | ||
114 | *r = &buffer[start]; | ||
115 | needed++; /* skip 0-termination */ | ||
116 | count--; | ||
117 | } | ||
118 | va_end (ap); | ||
119 | return needed; | ||
120 | } | ||
121 | |||
122 | |||
123 | /** | ||
124 | * Convert a given filesize into a fancy human-readable format. | ||
125 | */ | ||
126 | char * | ||
127 | GNUNET_STRINGS_byte_size_fancy (unsigned long long size) | ||
128 | { | ||
129 | const char *unit = _( /* size unit */ "b"); | ||
130 | char *ret; | ||
131 | |||
132 | if (size > 5 * 1024) | ||
133 | { | ||
134 | size = size / 1024; | ||
135 | unit = _( /* size unit */ "KiB"); | ||
136 | if (size > 5 * 1024) | ||
137 | { | ||
138 | size = size / 1024; | ||
139 | unit = _( /* size unit */ "MiB"); | ||
140 | if (size > 5 * 1024) | ||
141 | { | ||
142 | size = size / 1024; | ||
143 | unit = _( /* size unit */ "GiB"); | ||
144 | if (size > 5 * 1024) | ||
145 | { | ||
146 | size = size / 1024; | ||
147 | unit = _( /* size unit */ "TiB"); | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | ret = GNUNET_malloc (32); | ||
153 | GNUNET_snprintf (ret, 32, "%llu%s", size, unit); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | |||
158 | /** | ||
159 | * Convert the len characters long character sequence | ||
160 | * given in input that is in the given charset | ||
161 | * to UTF-8. | ||
162 | * @return the converted string (0-terminated), | ||
163 | * if conversion fails, a copy of the orignal | ||
164 | * string is returned. | ||
165 | */ | ||
166 | char * | ||
167 | GNUNET_STRINGS_to_utf8 (const char *input, size_t len, const char *charset) | ||
168 | { | ||
169 | char *ret; | ||
170 | #if ENABLE_NLS && HAVE_ICONV | ||
171 | size_t tmpSize; | ||
172 | size_t finSize; | ||
173 | char *tmp; | ||
174 | char *itmp; | ||
175 | iconv_t cd; | ||
176 | |||
177 | cd = iconv_open ("UTF-8", charset); | ||
178 | if (cd == (iconv_t) - 1) | ||
179 | { | ||
180 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "iconv_open"); | ||
181 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
182 | _("Character set requested was `%s'\n"), charset); | ||
183 | ret = GNUNET_malloc (len + 1); | ||
184 | memcpy (ret, input, len); | ||
185 | ret[len] = '\0'; | ||
186 | return ret; | ||
187 | } | ||
188 | tmpSize = 3 * len + 4; | ||
189 | tmp = GNUNET_malloc (tmpSize); | ||
190 | itmp = tmp; | ||
191 | finSize = tmpSize; | ||
192 | if (iconv (cd, (char **) &input, &len, &itmp, &finSize) == (size_t) - 1) | ||
193 | { | ||
194 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "iconv"); | ||
195 | iconv_close (cd); | ||
196 | GNUNET_free (tmp); | ||
197 | ret = GNUNET_malloc (len + 1); | ||
198 | memcpy (ret, input, len); | ||
199 | ret[len] = '\0'; | ||
200 | return ret; | ||
201 | } | ||
202 | ret = GNUNET_malloc (tmpSize - finSize + 1); | ||
203 | memcpy (ret, tmp, tmpSize - finSize); | ||
204 | ret[tmpSize - finSize] = '\0'; | ||
205 | GNUNET_free (tmp); | ||
206 | if (0 != iconv_close (cd)) | ||
207 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "iconv_close"); | ||
208 | return ret; | ||
209 | #else | ||
210 | ret = GNUNET_malloc (len + 1); | ||
211 | memcpy (ret, input, len); | ||
212 | ret[len] = '\0'; | ||
213 | return ret; | ||
214 | #endif | ||
215 | } | ||
216 | |||
217 | |||
218 | /** | ||
219 | * Complete filename (a la shell) from abbrevition. | ||
220 | * @param fil the name of the file, may contain ~/ or | ||
221 | * be relative to the current directory | ||
222 | * @returns the full file name, | ||
223 | * NULL is returned on error | ||
224 | */ | ||
225 | char * | ||
226 | GNUNET_STRINGS_filename_expand (const char *fil) | ||
227 | { | ||
228 | char *buffer; | ||
229 | #ifndef MINGW | ||
230 | size_t len; | ||
231 | size_t n; | ||
232 | char *fm; | ||
233 | const char *fil_ptr; | ||
234 | #else | ||
235 | char *fn; | ||
236 | long lRet; | ||
237 | #endif | ||
238 | |||
239 | if (fil == NULL) | ||
240 | return NULL; | ||
241 | |||
242 | #ifndef MINGW | ||
243 | if (fil[0] == DIR_SEPARATOR) | ||
244 | /* absolute path, just copy */ | ||
245 | return GNUNET_strdup (fil); | ||
246 | if (fil[0] == '~') | ||
247 | { | ||
248 | fm = getenv ("HOME"); | ||
249 | if (fm == NULL) | ||
250 | { | ||
251 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
252 | _ | ||
253 | ("Failed to expand `$HOME': environment variable `HOME' not set")); | ||
254 | return NULL; | ||
255 | } | ||
256 | fm = GNUNET_strdup (fm); | ||
257 | /* do not copy '~' */ | ||
258 | fil_ptr = fil + 1; | ||
259 | |||
260 | /* skip over dir seperator to be consistent */ | ||
261 | if (fil_ptr[0] == DIR_SEPARATOR) | ||
262 | fil_ptr++; | ||
263 | } | ||
264 | else | ||
265 | { | ||
266 | /* relative path */ | ||
267 | fil_ptr = fil; | ||
268 | len = 512; | ||
269 | fm = NULL; | ||
270 | while (1) | ||
271 | { | ||
272 | buffer = GNUNET_malloc (len); | ||
273 | if (getcwd (buffer, len) != NULL) | ||
274 | { | ||
275 | fm = buffer; | ||
276 | break; | ||
277 | } | ||
278 | if ((errno == ERANGE) && (len < 1024 * 1024 * 4)) | ||
279 | { | ||
280 | len *= 2; | ||
281 | GNUNET_free (buffer); | ||
282 | continue; | ||
283 | } | ||
284 | GNUNET_free (buffer); | ||
285 | break; | ||
286 | } | ||
287 | if (fm == NULL) | ||
288 | { | ||
289 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "getcwd"); | ||
290 | buffer = getenv ("PWD"); /* alternative */ | ||
291 | if (buffer != NULL) | ||
292 | fm = GNUNET_strdup (buffer); | ||
293 | } | ||
294 | if (fm == NULL) | ||
295 | fm = GNUNET_strdup ("./"); /* give up */ | ||
296 | } | ||
297 | n = strlen (fm) + 1 + strlen (fil_ptr) + 1; | ||
298 | buffer = GNUNET_malloc (n); | ||
299 | GNUNET_snprintf (buffer, n, "%s%s%s", | ||
300 | fm, | ||
301 | (fm[strlen (fm) - 1] == | ||
302 | DIR_SEPARATOR) ? "" : DIR_SEPARATOR_STR, fil_ptr); | ||
303 | GNUNET_free (fm); | ||
304 | return buffer; | ||
305 | #else | ||
306 | fn = GNUNET_malloc (MAX_PATH + 1); | ||
307 | |||
308 | if ((lRet = plibc_conv_to_win_path (fil, fn)) != ERROR_SUCCESS) | ||
309 | { | ||
310 | SetErrnoFromWinError (lRet); | ||
311 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
312 | "plibc_conv_to_win_path"); | ||
313 | return NULL; | ||
314 | } | ||
315 | /* is the path relative? */ | ||
316 | if ((strncmp (fn + 1, ":\\", 2) != 0) && (strncmp (fn, "\\\\", 2) != 0)) | ||
317 | { | ||
318 | char szCurDir[MAX_PATH + 1]; | ||
319 | lRet = GetCurrentDirectory (MAX_PATH + 1, szCurDir); | ||
320 | if (lRet + strlen (fn) + 1 > (MAX_PATH + 1)) | ||
321 | { | ||
322 | SetErrnoFromWinError (ERROR_BUFFER_OVERFLOW); | ||
323 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
324 | "GetCurrentDirectory"); | ||
325 | return NULL; | ||
326 | } | ||
327 | buffer = GNUNET_malloc (MAX_PATH + 1); | ||
328 | GNUNET_snprintf (buffer, MAX_PATH + 1, "%s\\%s", szCurDir, fn); | ||
329 | GNUNET_free (fn); | ||
330 | fn = buffer; | ||
331 | } | ||
332 | |||
333 | return fn; | ||
334 | #endif | ||
335 | } | ||
336 | |||
337 | |||
338 | /** | ||
339 | * Give relative time in human-readable fancy format. | ||
340 | * @param delta time in milli seconds | ||
341 | */ | ||
342 | char * | ||
343 | GNUNET_STRINGS_relative_time_to_string (struct GNUNET_TIME_Relative del) | ||
344 | { | ||
345 | const char *unit = _( /* time unit */ "ms"); | ||
346 | char *ret; | ||
347 | uint64_t delta = del.value; | ||
348 | |||
349 | if (delta > 5 * 1000) | ||
350 | { | ||
351 | delta = delta / 1000; | ||
352 | unit = _( /* time unit */ "s"); | ||
353 | if (delta > 5 * 60) | ||
354 | { | ||
355 | delta = delta / 60; | ||
356 | unit = _( /* time unit */ "m"); | ||
357 | if (delta > 5 * 60) | ||
358 | { | ||
359 | delta = delta / 60; | ||
360 | unit = _( /* time unit */ "h"); | ||
361 | if (delta > 5 * 24) | ||
362 | { | ||
363 | delta = delta / 24; | ||
364 | unit = _( /* time unit */ " days"); | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | } | ||
369 | GNUNET_asprintf (&ret, "%llu%s", delta, unit); | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | |||
374 | /** | ||
375 | * "man ctime_r", except for GNUnet time; also, unlike ctime, the | ||
376 | * return value does not include the newline character. | ||
377 | */ | ||
378 | char * | ||
379 | GNUNET_STRINGS_absolute_time_to_string (struct GNUNET_TIME_Absolute t) | ||
380 | { | ||
381 | time_t tt; | ||
382 | char *ret; | ||
383 | |||
384 | tt = t.value / 1000; | ||
385 | #ifdef ctime_r | ||
386 | ret = ctime_r (&tt, GNUNET_malloc (32)); | ||
387 | #else | ||
388 | ret = GNUNET_strdup (ctime (&tt)); | ||
389 | #endif | ||
390 | ret[strlen (ret) - 1] = '\0'; | ||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | |||
395 | |||
396 | /* end of strings.c */ | ||