Fix CA path setting really
[libisds.git] / src / utils.c
blob5606a6f4edd93ac3a916938d7cd20b730a4b5278
1 #define _XOPEN_SOURCE 500 /* For strdup(3) */
2 #define _POSIX_C_SOURCE 200112L /* For setenv() */
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <iconv.h>
7 #include <langinfo.h>
8 #include <time.h>
9 #include "utils.h"
10 #include "cencode.h"
11 #include "cdecode.h"
13 char *tz_orig; /* Copy of original TZ variable */
15 /* Concatenate two strings into newly allocated buffer.
16 * You must free() them, when you don't need it anymore.
17 * Any of the arguments can be NULL meaning empty string.
18 * In case of error returns NULL.
19 * Empty string is always returned as allocated empty string. */
20 _hidden char *astrcat(const char *first, const char *second) {
21 size_t first_len, second_len;
22 char *buf;
24 first_len = (first) ? strlen(first) : 0;
25 second_len = (second) ? strlen(second) : 0;
26 buf = malloc(1 + first_len + second_len);
27 if (buf) {
28 buf[0] = '\0';
29 if (first) strcpy(buf, first);
30 if (second) strcpy(buf + first_len, second);
32 return buf;
36 /* Concatenate three strings into newly allocated buffer.
37 * You must free() them, when you don't need it anymore.
38 * Any of the arguments can be NULL meaning empty string.
39 * In case of error returns NULL.
40 * Empty string is always returned as allocated empty string. */
41 _hidden char *astrcat3(const char *first, const char *second,
42 const char *third) {
43 size_t first_len, second_len, third_len;
44 char *buf, *next;
46 first_len = (first) ? strlen(first) : 0;
47 second_len = (second) ? strlen(second) : 0;
48 third_len = (third) ? strlen(third) : 0;
49 buf = malloc(1 + first_len + second_len + third_len);
50 if (buf) {
51 buf[0] = '\0';
52 next = buf;
53 if (first) {
54 strcpy(next, first);
55 next += first_len;
57 if (second) {
58 strcpy(next, second);
59 next += second_len;
61 if (third) {
62 strcpy(next, third);
65 return buf;
69 /* Print formated string into automtically reallocated @uffer.
70 * @buffer automatically reallocated buffer. Must be &NULL or preallocated
71 * memory.
72 * @format format string as for printf(3)
73 * @ap list of variadic arguments, after call will be in udefined state
74 * @Returns number of bytes printed. In case of errror, -1 and NULL @buffer*/
75 _hidden int isds_vasprintf(char **buffer, const char *format, va_list ap) {
76 va_list aq;
77 int length, new_length;
78 char *new_buffer;
80 if (!buffer || !format) {
81 if (buffer) {
82 free(*buffer);
83 *buffer = NULL;
85 return -1;
88 va_copy(aq, ap);
89 length = vsnprintf(NULL, 0, format, aq) + 1;
90 va_end(aq);
91 if (length <= 0) {
92 free(*buffer);
93 *buffer = NULL;
94 return -1;
97 new_buffer = realloc(*buffer, length);
98 if (!new_buffer) {
99 free(*buffer);
100 *buffer = NULL;
101 return -1;
103 *buffer = new_buffer;
105 new_length = vsnprintf(*buffer, length, format, ap);
106 if (new_length >= length) {
107 free(*buffer);
108 *buffer = NULL;
109 return -1;
112 return new_length;
116 /* Print formated string into automtically reallocated @uffer.
117 * @buffer automatically reallocated buffer. Must be &NULL or preallocated
118 * memory.
119 * @format format string as for printf(3)
120 * @... variadic arguments
121 * @Returns number of bytes printed. In case of errror, -1 and NULL @buffer*/
122 _hidden int isds_asprintf(char **buffer, const char *format, ...) {
123 int ret;
124 va_list ap;
125 va_start(ap, format);
126 ret = isds_vasprintf(buffer, format, ap);
127 va_end(ap);
128 return ret;
132 /* Converts UTF8 string into locale encoded string.
133 * @utf string int UTF-8 terminated by zero byte
134 * @return allocated string encoded in locale specific encoding. You must free
135 * it. In case of error or NULL @utf returns NULL. */
136 _hidden char *utf82locale(const char *utf) {
137 iconv_t state;
138 size_t utf_length;
139 char *buffer = NULL, *new_buffer;
140 size_t buffer_length = 0, buffer_used = 0;
141 char *inbuf, *outbuf;
142 size_t inleft, outleft;
144 if (!utf) return NULL;
146 /* nl_langinfo() is not thread-safe */
147 state = iconv_open(nl_langinfo(CODESET), "UTF-8");
148 if (state == (iconv_t) -1) return NULL;
150 /* Get the initial ouput buffer length */
151 utf_length = strlen(utf);
152 buffer_length = utf_length + 1;
154 inbuf = (char *) utf;
155 inleft = utf_length + 1;
157 while (inleft > 0) {
158 /* Extend buffer */
159 new_buffer = realloc(buffer, buffer_length);
160 if (!new_buffer) {
161 free(buffer);
162 buffer = NULL;
163 goto leave;
165 buffer = new_buffer;
167 /* FIXME */
168 outbuf = buffer + buffer_used;
169 outleft = buffer_length - buffer_used;
171 /* Convert chunk of data */
172 if ((size_t) -1 == iconv(state, &inbuf, &inleft, &outbuf, &outleft)) {
173 free(buffer);
174 buffer = NULL;
175 goto leave;
178 /* Update positions */
179 buffer_length += 1024;
180 buffer_used = outbuf - buffer;
183 leave:
184 iconv_close(state);
185 return buffer;
189 /* Encode given data into MIME Base64 encoded zero terminated string.
190 * @plain are input data (binary stream)
191 * @length is length of @plain data in bytes
192 * @return allocated string of base64 encoded plain data or NULL in case of
193 * error. You must free it. */
194 _hidden char *b64encode(const void *plain, const size_t length) {
196 base64_encodestate state;
197 size_t code_length;
198 char *buffer, *new_buffer;
200 if (!plain) return NULL;
202 base64_init_encodestate(&state);
204 /* TODO: This function assumes sizeof(char) == 1 byte.
205 * To fix it, one must fix underlying functions too. */
206 if (sizeof(char) != 1) PANIC("sizeof(char) != 1 byte");
208 /* Allocate buffer
209 * (4 is padding, 1 is final new line, and 1 is string terminator) */
210 buffer = malloc(length * 2 + 4 + 1 + 1);
211 if (!buffer) return NULL;
213 /* Encode plain data */
214 code_length = base64_encode_block(plain, length, buffer, &state);
215 code_length += base64_encode_blockend(buffer + code_length, &state);
217 /* Terminate string */
218 buffer[code_length++] = '\0';
220 /* Shrink the buffer */
221 new_buffer = realloc(buffer, code_length);
222 if (new_buffer) buffer = new_buffer;
224 return buffer;
228 /* Decode given data from MIME Base64 encoded zero terminated string to binary
229 * stream.
230 * @encoded are input data (Base64 zero terminated string)
231 * @plain are automatically realocated output data (binary stream). You must
232 * free it. Will be freed in case of error.
233 * @return length of @plain data in bytes or (size_t) -1 in case of decoding
234 * failure. */
235 _hidden size_t b64decode(const char *encoded, void **plain) {
237 base64_decodestate state;
238 size_t encoded_length;
239 int plain_length;
240 char *buffer;
242 if (!encoded || !plain) {
243 if (plain && *plain) zfree(*plain);
244 return ((size_t) -1);
247 encoded_length = strlen(encoded);
248 base64_init_decodestate(&state);
250 /* TODO: This function assumes sizeof(char) == 1 byte.
251 * To fix it, one must fix underlying functions too. */
252 if (sizeof(char) != 1) PANIC("sizeof(char) != 1 byte");
254 /* Allocate buffer */
255 buffer = realloc(*plain, encoded_length);
256 if (!buffer) {
257 zfree(*plain);
258 return ((size_t) -1);
260 *plain = buffer;
262 /* Decode encoded data */
263 plain_length = base64_decode_block(encoded, encoded_length,
264 *plain, &state);
265 if (plain_length < 0) {
266 zfree(*plain);
267 return((size_t) -1);
270 /* Shrink the buffer */
271 buffer = realloc(*plain, plain_length);
272 if (!buffer) *plain = buffer;
274 return plain_length;
278 /* Switches time zone to UTC.
279 * XXX: This is not reentrant and not thread-safe */
280 _hidden void switch_tz_to_utc(void) {
281 char *tz;
283 tz = getenv("TZ");
284 if (tz) {
285 tz_orig = strdup(tz);
286 if (!tz_orig)
287 PANIC("Can not back original time zone up");
288 } else {
289 tz_orig = NULL;
292 if (setenv("TZ", "", 1))
293 PANIC("Can not change time zone to UTC temporarily");
295 tzset();
299 /* Switches time zone to original value.
300 * XXX: This is not reentrant and not thread-safe */
301 _hidden void switch_tz_to_native(void) {
302 if (tz_orig) {
303 if (setenv("TZ", tz_orig, 1))
304 PANIC("Can not restore time zone by setting TZ variable");
305 free(tz_orig);
306 tz_orig = NULL;
307 } else {
308 if(unsetenv("TZ"))
309 PANIC("Can not restore time zone by unsetting TZ variable");
311 tzset();