utils.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /*
  2. * utils.c
  3. * Miscellaneous utilities for string manipulation
  4. *
  5. * Copyright (c) 2013 Federico Mena Quintero
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. #include <config.h>
  23. #endif
  24. #include <stdarg.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <time.h>
  28. #include <sys/time.h>
  29. #include <inttypes.h>
  30. #include <ctype.h>
  31. #include "utils.h"
  32. #ifndef HAVE_STPCPY
  33. /**
  34. * Copy characters from one string into another
  35. *
  36. * @note: The strings should not overlap, as the behavior is undefined.
  37. *
  38. * @s1: The source string.
  39. * @s2: The destination string.
  40. *
  41. * @return a pointer to the terminating `\0' character of @s1,
  42. * or NULL if @s1 or @s2 is NULL.
  43. */
  44. char *stpcpy(char *s1, const char *s2)
  45. {
  46. if (s1 == NULL || s2 == NULL)
  47. return NULL;
  48. strcpy(s1, s2);
  49. return s1 + strlen(s2);
  50. }
  51. #endif
  52. /**
  53. * Concatenate strings into a newly allocated string
  54. *
  55. * @note: Specify NULL for the last string in the varargs list
  56. *
  57. * @str: The first string in the list
  58. * @...: Subsequent strings. Use NULL for the last item.
  59. *
  60. * @return a newly allocated string, or NULL if @str is NULL. This will also
  61. * return NULL and set errno to ENOMEM if memory is exhausted.
  62. */
  63. char *string_concat(const char *str, ...)
  64. {
  65. size_t len;
  66. va_list args;
  67. char *s;
  68. char *result;
  69. char *dest;
  70. if (!str)
  71. return NULL;
  72. /* Compute final length */
  73. len = strlen(str) + 1; /* plus 1 for the null terminator */
  74. va_start(args, str);
  75. s = va_arg(args, char *);
  76. while (s) {
  77. len += strlen(s);
  78. s = va_arg(args, char*);
  79. }
  80. va_end(args);
  81. /* Concat each string */
  82. result = malloc(len);
  83. if (!result)
  84. return NULL; /* errno remains set */
  85. dest = result;
  86. dest = stpcpy(dest, str);
  87. va_start(args, str);
  88. s = va_arg(args, char *);
  89. while (s) {
  90. dest = stpcpy(dest, s);
  91. s = va_arg(args, char *);
  92. }
  93. va_end(args);
  94. return result;
  95. }
  96. char *string_build_path(const char *elem, ...)
  97. {
  98. if (!elem)
  99. return NULL;
  100. va_list args;
  101. int len = strlen(elem)+1;
  102. va_start(args, elem);
  103. char *arg = va_arg(args, char*);
  104. while (arg) {
  105. len += strlen(arg)+1;
  106. arg = va_arg(args, char*);
  107. }
  108. va_end(args);
  109. char* out = (char*)malloc(len);
  110. strcpy(out, elem);
  111. va_start(args, elem);
  112. arg = va_arg(args, char*);
  113. while (arg) {
  114. strcat(out, "/");
  115. strcat(out, arg);
  116. arg = va_arg(args, char*);
  117. }
  118. va_end(args);
  119. return out;
  120. }
  121. char *string_format_size(uint64_t size)
  122. {
  123. char buf[80];
  124. double sz;
  125. if (size >= 1000000000000LL) {
  126. sz = ((double)size / 1000000000000.0f);
  127. sprintf(buf, "%0.1f TB", sz);
  128. } else if (size >= 1000000000LL) {
  129. sz = ((double)size / 1000000000.0f);
  130. sprintf(buf, "%0.1f GB", sz);
  131. } else if (size >= 1000000LL) {
  132. sz = ((double)size / 1000000.0f);
  133. sprintf(buf, "%0.1f MB", sz);
  134. } else if (size >= 1000LL) {
  135. sz = ((double)size / 1000.0f);
  136. sprintf(buf, "%0.1f KB", sz);
  137. } else {
  138. sprintf(buf, "%d Bytes", (int)size);
  139. }
  140. return strdup(buf);
  141. }
  142. char *string_toupper(char* str)
  143. {
  144. char *res = strdup(str);
  145. unsigned int i;
  146. for (i = 0; i < strlen(res); i++) {
  147. res[i] = toupper(res[i]);
  148. }
  149. return res;
  150. }
  151. static int get_rand(int min, int max)
  152. {
  153. int retval = (rand() % (max - min)) + min;
  154. return retval;
  155. }
  156. char *generate_uuid()
  157. {
  158. const char *chars = "ABCDEF0123456789";
  159. int i = 0;
  160. char *uuid = (char *) malloc(sizeof(char) * 37);
  161. srand(time(NULL));
  162. for (i = 0; i < 36; i++) {
  163. if (i == 8 || i == 13 || i == 18 || i == 23) {
  164. uuid[i] = '-';
  165. continue;
  166. } else {
  167. uuid[i] = chars[get_rand(0, 16)];
  168. }
  169. }
  170. /* make it a real string */
  171. uuid[36] = '\0';
  172. return uuid;
  173. }
  174. void buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
  175. {
  176. FILE *f;
  177. uint64_t size;
  178. *length = 0;
  179. f = fopen(filename, "rb");
  180. if (!f) {
  181. return;
  182. }
  183. fseek(f, 0, SEEK_END);
  184. size = ftell(f);
  185. rewind(f);
  186. if (size == 0) {
  187. fclose(f);
  188. return;
  189. }
  190. *buffer = (char*)malloc(sizeof(char)*(size+1));
  191. if (fread(*buffer, sizeof(char), size, f) != size) {
  192. fclose(f);
  193. return;
  194. }
  195. fclose(f);
  196. *length = size;
  197. }
  198. void buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
  199. {
  200. FILE *f;
  201. f = fopen(filename, "wb");
  202. if (f) {
  203. fwrite(buffer, sizeof(char), length, f);
  204. fclose(f);
  205. }
  206. }
  207. int plist_read_from_filename(plist_t *plist, const char *filename)
  208. {
  209. char *buffer = NULL;
  210. uint64_t length;
  211. if (!filename)
  212. return 0;
  213. buffer_read_from_filename(filename, &buffer, &length);
  214. if (!buffer) {
  215. return 0;
  216. }
  217. if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) {
  218. plist_from_bin(buffer, length, plist);
  219. } else {
  220. plist_from_xml(buffer, length, plist);
  221. }
  222. free(buffer);
  223. return 1;
  224. }
  225. int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format)
  226. {
  227. char *buffer = NULL;
  228. uint32_t length;
  229. if (!plist || !filename)
  230. return 0;
  231. if (format == PLIST_FORMAT_XML)
  232. plist_to_xml(plist, &buffer, &length);
  233. else if (format == PLIST_FORMAT_BINARY)
  234. plist_to_bin(plist, &buffer, &length);
  235. else
  236. return 0;
  237. buffer_write_to_filename(filename, buffer, length);
  238. free(buffer);
  239. return 1;
  240. }
  241. static const char base64_str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  242. static const char base64_pad = '=';
  243. static char *base64encode(const unsigned char *buf, size_t size)
  244. {
  245. if (!buf || !(size > 0)) return NULL;
  246. int outlen = (size / 3) * 4;
  247. char *outbuf = (char*)malloc(outlen+5); // 4 spare bytes + 1 for '\0'
  248. size_t n = 0;
  249. size_t m = 0;
  250. unsigned char input[3];
  251. unsigned int output[4];
  252. while (n < size) {
  253. input[0] = buf[n];
  254. input[1] = (n+1 < size) ? buf[n+1] : 0;
  255. input[2] = (n+2 < size) ? buf[n+2] : 0;
  256. output[0] = input[0] >> 2;
  257. output[1] = ((input[0] & 3) << 4) + (input[1] >> 4);
  258. output[2] = ((input[1] & 15) << 2) + (input[2] >> 6);
  259. output[3] = input[2] & 63;
  260. outbuf[m++] = base64_str[(int)output[0]];
  261. outbuf[m++] = base64_str[(int)output[1]];
  262. outbuf[m++] = (n+1 < size) ? base64_str[(int)output[2]] : base64_pad;
  263. outbuf[m++] = (n+2 < size) ? base64_str[(int)output[3]] : base64_pad;
  264. n+=3;
  265. }
  266. outbuf[m] = 0; // 0-termination!
  267. return outbuf;
  268. }
  269. static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream);
  270. static void plist_array_print_to_stream(plist_t node, int* indent_level, FILE* stream)
  271. {
  272. /* iterate over items */
  273. int i, count;
  274. plist_t subnode = NULL;
  275. count = plist_array_get_size(node);
  276. for (i = 0; i < count; i++) {
  277. subnode = plist_array_get_item(node, i);
  278. fprintf(stream, "%*s", *indent_level, "");
  279. fprintf(stream, "%d: ", i);
  280. plist_node_print_to_stream(subnode, indent_level, stream);
  281. }
  282. }
  283. static void plist_dict_print_to_stream(plist_t node, int* indent_level, FILE* stream)
  284. {
  285. /* iterate over key/value pairs */
  286. plist_dict_iter it = NULL;
  287. char* key = NULL;
  288. plist_t subnode = NULL;
  289. plist_dict_new_iter(node, &it);
  290. plist_dict_next_item(node, it, &key, &subnode);
  291. while (subnode)
  292. {
  293. fprintf(stream, "%*s", *indent_level, "");
  294. fprintf(stream, "%s", key);
  295. if (plist_get_node_type(subnode) == PLIST_ARRAY)
  296. fprintf(stream, "[%d]: ", plist_array_get_size(subnode));
  297. else
  298. fprintf(stream, ": ");
  299. free(key);
  300. key = NULL;
  301. plist_node_print_to_stream(subnode, indent_level, stream);
  302. plist_dict_next_item(node, it, &key, &subnode);
  303. }
  304. free(it);
  305. }
  306. static void plist_node_print_to_stream(plist_t node, int* indent_level, FILE* stream)
  307. {
  308. char *s = NULL;
  309. char *data = NULL;
  310. double d;
  311. uint8_t b;
  312. uint64_t u = 0;
  313. struct timeval tv = { 0, 0 };
  314. plist_type t;
  315. if (!node)
  316. return;
  317. t = plist_get_node_type(node);
  318. switch (t) {
  319. case PLIST_BOOLEAN:
  320. plist_get_bool_val(node, &b);
  321. fprintf(stream, "%s\n", (b ? "true" : "false"));
  322. break;
  323. case PLIST_UINT:
  324. plist_get_uint_val(node, &u);
  325. fprintf(stream, "%"PRIu64"\n", u);
  326. break;
  327. case PLIST_REAL:
  328. plist_get_real_val(node, &d);
  329. fprintf(stream, "%f\n", d);
  330. break;
  331. case PLIST_STRING:
  332. plist_get_string_val(node, &s);
  333. fprintf(stream, "%s\n", s);
  334. free(s);
  335. break;
  336. case PLIST_KEY:
  337. plist_get_key_val(node, &s);
  338. fprintf(stream, "%s: ", s);
  339. free(s);
  340. break;
  341. case PLIST_DATA:
  342. plist_get_data_val(node, &data, &u);
  343. if (u > 0) {
  344. s = base64encode((unsigned char*)data, u);
  345. free(data);
  346. if (s) {
  347. fprintf(stream, "%s\n", s);
  348. free(s);
  349. } else {
  350. fprintf(stream, "\n");
  351. }
  352. } else {
  353. fprintf(stream, "\n");
  354. }
  355. break;
  356. case PLIST_DATE:
  357. plist_get_date_val(node, (int32_t*)&tv.tv_sec, (int32_t*)&tv.tv_usec);
  358. {
  359. time_t ti = (time_t)tv.tv_sec;
  360. struct tm *btime = localtime(&ti);
  361. if (btime) {
  362. s = (char*)malloc(24);
  363. memset(s, 0, 24);
  364. if (strftime(s, 24, "%Y-%m-%dT%H:%M:%SZ", btime) <= 0) {
  365. free (s);
  366. s = NULL;
  367. }
  368. }
  369. }
  370. if (s) {
  371. fprintf(stream, "%s\n", s);
  372. free(s);
  373. } else {
  374. fprintf(stream, "\n");
  375. }
  376. break;
  377. case PLIST_ARRAY:
  378. fprintf(stream, "\n");
  379. (*indent_level)++;
  380. plist_array_print_to_stream(node, indent_level, stream);
  381. (*indent_level)--;
  382. break;
  383. case PLIST_DICT:
  384. fprintf(stream, "\n");
  385. (*indent_level)++;
  386. plist_dict_print_to_stream(node, indent_level, stream);
  387. (*indent_level)--;
  388. break;
  389. default:
  390. break;
  391. }
  392. }
  393. void plist_print_to_stream(plist_t plist, FILE* stream)
  394. {
  395. int indent = 0;
  396. if (!plist || !stream)
  397. return;
  398. switch (plist_get_node_type(plist)) {
  399. case PLIST_DICT:
  400. plist_dict_print_to_stream(plist, &indent, stream);
  401. break;
  402. case PLIST_ARRAY:
  403. plist_array_print_to_stream(plist, &indent, stream);
  404. break;
  405. default:
  406. plist_node_print_to_stream(plist, &indent, stream);
  407. }
  408. }