knhx.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #include <ctype.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "knhx.h"
  6. typedef struct {
  7. int error, n, max;
  8. knhx1_t *node;
  9. } knaux_t;
  10. static inline char *add_node(const char *s, knaux_t *aux, int x)
  11. {
  12. char *p, *nbeg, *nend = 0;
  13. knhx1_t *r;
  14. if (aux->n == aux->max) {
  15. aux->max = aux->max? aux->max<<1 : 8;
  16. aux->node = (knhx1_t*)realloc(aux->node, sizeof(knhx1_t) * aux->max);
  17. }
  18. r = aux->node + (aux->n++);
  19. r->n = x; r->parent = -1;
  20. for (p = (char*)s, nbeg = p, r->d = -1.0; *p && *p != ',' && *p != ')'; ++p) {
  21. if (*p == '[') {
  22. if (nend == 0) nend = p;
  23. do ++p; while (*p && *p != ']');
  24. if (*p == 0) {
  25. aux->error |= KNERR_BRACKET;
  26. break;
  27. }
  28. } else if (*p == ':') {
  29. if (nend == 0) nend = p;
  30. r->d = strtod(p + 1, &p);
  31. --p;
  32. } else if (!isgraph(*p)) if (nend == 0) nend = p;
  33. }
  34. if (nend == 0) nend = p;
  35. if (nend != nbeg) {
  36. r->name = (char*)calloc(nend - nbeg + 1, 1);
  37. strncpy(r->name, nbeg, nend - nbeg);
  38. } else r->name = strdup("");
  39. return p;
  40. }
  41. knhx1_t *kn_parse(const char *nhx, int *_n, int *_error)
  42. {
  43. char *p;
  44. int *stack, top, max;
  45. knaux_t *aux;
  46. knhx1_t *ret;
  47. #define __push_back(y) do { \
  48. if (top == max) { \
  49. max = max? max<<1 : 16; \
  50. stack = (int*)realloc(stack, sizeof(int) * max); \
  51. } \
  52. stack[top++] = (y); \
  53. } while (0) \
  54. stack = 0; top = max = 0;
  55. p = (char*)nhx;
  56. aux = (knaux_t*)calloc(1, sizeof(knaux_t));
  57. while (*p) {
  58. while (*p && !isgraph(*p)) ++p;
  59. if (*p == 0) break;
  60. if (*p == ',') ++p;
  61. else if (*p == '(') {
  62. __push_back(-1);
  63. ++p;
  64. } else if (*p == ')') {
  65. int x = aux->n, m, i;
  66. for (i = top - 1; i >= 0; --i)
  67. if (stack[i] < 0) break;
  68. m = top - 1 - i;
  69. p = add_node(p + 1, aux, m);
  70. aux->node[x].child = (int*)calloc(m, sizeof(int));
  71. for (i = top - 1, m = m - 1; m >= 0; --m, --i) {
  72. aux->node[x].child[m] = stack[i];
  73. aux->node[stack[i]].parent = x;
  74. }
  75. top = i;
  76. __push_back(x);
  77. } else {
  78. __push_back(aux->n);
  79. p = add_node(p, aux, 0);
  80. }
  81. }
  82. *_n = aux->n;
  83. *_error = aux->error;
  84. ret = aux->node;
  85. free(aux); free(stack);
  86. return ret;
  87. }
  88. #ifndef kroundup32
  89. #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
  90. #endif
  91. static inline int kputsn(const char *p, int l, kstring_t *s)
  92. {
  93. if (s->l + l + 1 >= s->m) {
  94. s->m = s->l + l + 2;
  95. kroundup32(s->m);
  96. s->s = (char*)realloc(s->s, s->m);
  97. }
  98. memcpy(s->s + s->l, p, l);
  99. s->l += l; s->s[s->l] = 0;
  100. return l;
  101. }
  102. static inline int kputc(int c, kstring_t *s)
  103. {
  104. if (s->l + 1 >= s->m) {
  105. s->m = s->l + 2;
  106. kroundup32(s->m);
  107. s->s = (char*)realloc(s->s, s->m);
  108. }
  109. s->s[s->l++] = c; s->s[s->l] = 0;
  110. return c;
  111. }
  112. static void format_node_recur(const knhx1_t *node, const knhx1_t *p, kstring_t *s, char *numbuf)
  113. {
  114. if (p->n) {
  115. int i;
  116. kputc('(', s);
  117. for (i = 0; i < p->n; ++i) {
  118. if (i) kputc(',', s);
  119. format_node_recur(node, &node[p->child[i]], s, numbuf);
  120. }
  121. kputc(')', s);
  122. if (p->name) kputsn(p->name, strlen(p->name), s);
  123. if (p->d >= 0) {
  124. sprintf(numbuf, ":%g", p->d);
  125. kputsn(numbuf, strlen(numbuf), s);
  126. }
  127. } else kputsn(p->name, strlen(p->name), s);
  128. }
  129. void kn_format(const knhx1_t *node, int root, kstring_t *s) // TODO: get rid of recursion
  130. {
  131. char numbuf[128];
  132. format_node_recur(node, &node[root], s, numbuf);
  133. }
  134. #ifdef KNHX_MAIN
  135. int main(int argc, char *argv[])
  136. {
  137. char *s = "((a[abc],d1)x:0.5,((b[&&NHX:S=MOUSE],h2)[&&NHX:S=HUMAN:B=99][blabla][&&NHX:K=foo],c))";
  138. knhx1_t *node;
  139. int i, j, n, error;
  140. kstring_t str;
  141. node = kn_parse(s, &n, &error);
  142. for (i = 0; i < n; ++i) {
  143. knhx1_t *p = node + i;
  144. printf("[%d] %s\t%d\t%d\t%g", i, p->name, p->parent, p->n, p->d);
  145. for (j = 0; j < p->n; ++j)
  146. printf("\t%d", p->child[j]);
  147. putchar('\n');
  148. }
  149. str.l = str.m = 0; str.s = 0;
  150. kn_format(node, n-1, &str);
  151. puts(str.s);
  152. free(str.s);
  153. return 0;
  154. }
  155. #endif