cfg.c 4.3 KB

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