lfs_cfg.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * Simple config parser
  3. *
  4. * Copyright (c) 2017 Christopher Haster
  5. * Distributed under the MIT license
  6. */
  7. #include "emubd/lfs_cfg.h"
  8. #include <stdlib.h>
  9. #include <errno.h>
  10. #include <string.h>
  11. #include <stdio.h>
  12. static int lfs_cfg_buffer(lfs_cfg_t *cfg, char c) {
  13. // Amortize double
  14. if (cfg->blen == cfg->bsize) {
  15. size_t nsize = cfg->bsize * 2;
  16. char *nbuf = malloc(nsize);
  17. if (!nbuf) {
  18. return -ENOMEM;
  19. }
  20. memcpy(nbuf, cfg->buf, cfg->bsize);
  21. free(cfg->buf);
  22. cfg->buf = nbuf;
  23. cfg->bsize = nsize;
  24. }
  25. cfg->buf[cfg->blen] = c;
  26. cfg->blen += 1;
  27. return 0;
  28. }
  29. static int lfs_cfg_attr(lfs_cfg_t *cfg, unsigned key, unsigned val) {
  30. // Amortize double
  31. if (cfg->len == cfg->size) {
  32. size_t nsize = cfg->size * 2;
  33. struct lfs_cfg_attr *nattrs = malloc(nsize*sizeof(struct lfs_cfg_attr));
  34. if (!nattrs) {
  35. return -ENOMEM;
  36. }
  37. memcpy(nattrs, cfg->attrs, cfg->size*sizeof(struct lfs_cfg_attr));
  38. free(cfg->attrs);
  39. cfg->attrs = nattrs;
  40. cfg->size = nsize;
  41. }
  42. // Keep attrs sorted for binary search
  43. unsigned i = 0;
  44. while (i < cfg->len &&
  45. strcmp(&cfg->buf[key],
  46. &cfg->buf[cfg->attrs[i].key]) > 0) {
  47. i += 1;
  48. }
  49. memmove(&cfg->attrs[i+1], &cfg->attrs[i],
  50. (cfg->size - i)*sizeof(struct lfs_cfg_attr));
  51. cfg->attrs[i].key = key;
  52. cfg->attrs[i].val = val;
  53. cfg->len += 1;
  54. return 0;
  55. }
  56. static bool lfs_cfg_match(FILE *f, const char *matches) {
  57. char c = getc(f);
  58. ungetc(c, f);
  59. for (int i = 0; matches[i]; i++) {
  60. if (c == matches[i]) {
  61. return true;
  62. }
  63. }
  64. return false;
  65. }
  66. int lfs_cfg_create(lfs_cfg_t *cfg, const char *filename) {
  67. // start with some initial space
  68. cfg->len = 0;
  69. cfg->size = 4;
  70. cfg->attrs = malloc(cfg->size*sizeof(struct lfs_cfg_attr));
  71. cfg->blen = 0;
  72. cfg->bsize = 16;
  73. cfg->buf = malloc(cfg->size);
  74. FILE *f = fopen(filename, "r");
  75. if (!f) {
  76. return -errno;
  77. }
  78. while (!feof(f)) {
  79. int err;
  80. while (lfs_cfg_match(f, " \t\v\f")) {
  81. fgetc(f);
  82. }
  83. if (!lfs_cfg_match(f, "#\r\n")) {
  84. unsigned key = cfg->blen;
  85. while (!lfs_cfg_match(f, " \t\v\f:#") && !feof(f)) {
  86. if ((err = lfs_cfg_buffer(cfg, fgetc(f)))) {
  87. return err;
  88. }
  89. }
  90. if ((err = lfs_cfg_buffer(cfg, 0))) {
  91. return err;
  92. }
  93. while (lfs_cfg_match(f, " \t\v\f")) {
  94. fgetc(f);
  95. }
  96. if (lfs_cfg_match(f, ":")) {
  97. fgetc(f);
  98. while (lfs_cfg_match(f, " \t\v\f")) {
  99. fgetc(f);
  100. }
  101. unsigned val = cfg->blen;
  102. while (!lfs_cfg_match(f, " \t\v\f#\r\n") && !feof(f)) {
  103. if ((err = lfs_cfg_buffer(cfg, fgetc(f)))) {
  104. return err;
  105. }
  106. }
  107. if ((err = lfs_cfg_buffer(cfg, 0))) {
  108. return err;
  109. }
  110. if ((err = lfs_cfg_attr(cfg, key, val))) {
  111. return err;
  112. }
  113. } else {
  114. cfg->blen = key;
  115. }
  116. }
  117. while (!lfs_cfg_match(f, "\r\n") && !feof(f)) {
  118. fgetc(f);
  119. }
  120. fgetc(f);
  121. }
  122. return 0;
  123. }
  124. void lfs_cfg_destroy(lfs_cfg_t *cfg) {
  125. free(cfg->attrs);
  126. }
  127. bool lfs_cfg_has(lfs_cfg_t *cfg, const char *key) {
  128. return lfs_cfg_get(cfg, key, 0);
  129. }
  130. const char *lfs_cfg_get(lfs_cfg_t *cfg, const char *key, const char *def) {
  131. // binary search for attribute
  132. int lo = 0;
  133. int hi = cfg->len-1;
  134. while (lo <= hi) {
  135. int i = (hi + lo) / 2;
  136. int cmp = strcmp(key, &cfg->buf[cfg->attrs[i].key]);
  137. if (cmp == 0) {
  138. return &cfg->buf[cfg->attrs[i].val];
  139. } else if (cmp < 0) {
  140. hi = i-1;
  141. } else {
  142. lo = i+1;
  143. }
  144. }
  145. return def;
  146. }
  147. ssize_t lfs_cfg_geti(lfs_cfg_t *cfg, const char *key, ssize_t def) {
  148. const char *val = lfs_cfg_get(cfg, key, 0);
  149. if (!val) {
  150. return def;
  151. }
  152. char *end;
  153. ssize_t res = strtoll(val, &end, 0);
  154. return (end == val) ? def : res;
  155. }
  156. size_t lfs_cfg_getu(lfs_cfg_t *cfg, const char *key, size_t def) {
  157. const char *val = lfs_cfg_get(cfg, key, 0);
  158. if (!val) {
  159. return def;
  160. }
  161. char *end;
  162. size_t res = strtoull(val, &end, 0);
  163. return (end == val) ? def : res;
  164. }