xs_po.h 1.9 KB

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