xs_po.h (1926B)
1 /* copyright (c) 2025 grunfink et al. / MIT license */ 2 3 #ifndef _XS_PO_H 4 5 #define _XS_PO_H 6 7 xs_dict *xs_po_to_dict(const char *fn); 8 9 #ifdef XS_IMPLEMENTATION 10 11 xs_dict *xs_po_to_dict(const char *fn) 12 /* converts a PO file to a dict */ 13 { 14 xs_dict *d = NULL; 15 FILE *f; 16 17 if ((f = fopen(fn, "r")) != NULL) { 18 d = xs_dict_new(); 19 20 xs *k = NULL; 21 xs *v = NULL; 22 enum { IN_NONE, IN_K, IN_V } mode = IN_NONE; 23 24 while (!feof(f)) { 25 xs *l = xs_strip_i(xs_readline(f)); 26 27 /* discard empty lines and comments */ 28 if (*l == '\0' || *l == '#') 29 continue; 30 31 if (xs_startswith(l, "msgid ")) { 32 if (mode == IN_V) { 33 /* flush */ 34 if (xs_is_string(k) && xs_is_string(v) && *v) 35 d = xs_dict_set(d, k, v); 36 37 k = xs_free(k); 38 v = xs_free(v); 39 } 40 41 l = xs_replace_i(l, "msgid ", ""); 42 mode = IN_K; 43 44 k = xs_str_new(NULL); 45 } 46 else 47 if (xs_startswith(l, "msgstr ")) { 48 if (mode != IN_K) 49 break; 50 51 l = xs_replace_i(l, "msgstr ", ""); 52 mode = IN_V; 53 54 v = xs_str_new(NULL); 55 } 56 57 l = xs_replace_i(l, "\\n", "\n"); 58 l = xs_strip_chars_i(l, "\""); 59 60 switch (mode) { 61 case IN_K: 62 k = xs_str_cat(k, l); 63 break; 64 65 case IN_V: 66 v = xs_str_cat(v, l); 67 break; 68 69 case IN_NONE: 70 break; 71 } 72 } 73 74 /* final flush */ 75 if (xs_is_string(k) && xs_is_string(v) && *v) 76 d = xs_dict_set(d, k, v); 77 78 fclose(f); 79 } 80 81 return d; 82 } 83 84 #endif /* XS_IMPLEMENTATION */ 85 86 #endif /* XS_PO_H */