Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / SCDoc / SCDoc.cpp
blobe0ccc553fab1cc77f69065b6073eb6425ecf4fee
1 /************************************************************************
3 * Copyright 2012 Jonatan Liljedahl <lijon@kymatica.com>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 ************************************************************************/
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include "SCDoc.h"
26 DocNode * scdoc_parse_run(int partial);
27 void scdocrestart (FILE *input_file);
28 int scdoclex_destroy(void);
30 char * scdoc_current_file = NULL;
32 const char * NODE_TEXT = "TEXT";
33 const char * NODE_NL = "NL";
35 static int doc_node_dump_level_done[32] = {0,};
37 // merge a+b and free b
38 char *strmerge(char *a, char *b) {
39 if(a==NULL) return b;
40 if(b==NULL) return a;
41 char *s = (char *)realloc(a,strlen(a)+strlen(b)+1);
42 strcat(s,b);
43 free(b);
44 return s;
47 static char *striptrailingws(char *s) {
48 char *s2 = strchr(s,0);
49 while(--s2 > s && isspace(*s2)) {
50 *s2 = 0;
52 return s;
55 DocNode * doc_node_create(const char *id) {
56 DocNode *n = (DocNode *)malloc(sizeof(DocNode));
57 n->id = id;
58 n->text = NULL;
59 n->n_childs = 0;
60 n->children = NULL;
61 return n;
64 // takes ownership of child
65 DocNode * doc_node_add_child(DocNode *n, DocNode *child) {
66 if(child) {
67 n->children = (DocNode **)realloc(n->children, (n->n_childs+1) * sizeof(DocNode*));
68 n->children[n->n_childs] = child;
69 n->n_childs++;
71 return n;
74 // takes ownership of text
75 /*DocNode * doc_node_add_text(DocNode *n, char *text) {
76 if(n->text) {
77 char *str = strmergefree(n->text,text);
78 n->text = str;
79 printf("NODE: Adding text '%s'\n",text);
80 } else {
81 n->text = text;
83 return n;
84 }*/
86 // moves the childs from src doc_node to n
87 void doc_node_move_children(DocNode *n, DocNode *src) {
88 if(src) {
89 free(n->children);
90 n->children = src->children;
91 n->n_childs = src->n_childs;
92 // src->children = NULL;
93 // src->n_childs = 0;
94 free(src->text);
95 free(src);
99 DocNode * doc_node_make(const char *id, char *text, DocNode *child) {
100 DocNode *n = doc_node_create(id);
101 n->text = text;
102 doc_node_add_child(n, child);
103 return n;
106 DocNode * doc_node_make_take_children(const char *id, char *text, DocNode *src) {
107 DocNode *n = doc_node_make(id, text, NULL);
108 doc_node_move_children(n, src);
109 return n;
112 void doc_node_free_tree(DocNode *n) {
113 int i;
114 if(!n) return;
115 free(n->text);
116 for(i=0;i<n->n_childs;i++) {
117 doc_node_free_tree(n->children[i]);
119 free(n->children);
120 free(n);
123 void doc_node_fixup_tree(DocNode *n) {
124 int i;
125 if(n->id != NODE_TEXT && n->text) {
126 n->text = striptrailingws(n->text);
128 if(n->n_childs) {
129 DocNode *last = n->children[n->n_childs-1];
130 if(last->id==NODE_NL) {
131 free(last); // NL has no text or children
132 n->n_childs--;
134 last = NULL;
135 for(i = 0; i < n->n_childs; i++) {
136 DocNode *child = n->children[i];
137 if((child->id==NODE_TEXT || child->id==NODE_NL) && last && last->id==NODE_TEXT) {
138 if(child->id==NODE_NL) {
139 last->text = (char*)realloc(last->text,strlen(last->text)+2);
140 strcat(last->text," ");
141 } else {
142 last->text = strmerge(last->text,child->text);
144 free(child); // we took childs text and it has no children
145 n->children[i] = NULL;
146 } else {
147 doc_node_fixup_tree(child);
148 last = child;
151 int j = 0;
152 for(i = 0; i < n->n_childs; i++) {
153 if(n->children[i]) {
154 n->children[j++] = n->children[i];
157 n->n_childs = j;
161 static void _doc_node_dump(DocNode *n, int level, int last) {
162 int i;
163 for(i=0;i<level;i++) {
164 if(doc_node_dump_level_done[i])
165 printf(" ");
166 else
167 printf("| ");
169 if(last) {
170 printf("`-- ");
171 doc_node_dump_level_done[level] = 1;
172 } else {
173 printf("|-- ");
175 printf("%s",n->id);
176 if(n->text) printf(" \"%s\"",n->text);
177 printf("\n");
178 for(i = 0; i < n->n_childs; i++) {
179 _doc_node_dump(n->children[i], level+1, i==n->n_childs-1);
181 doc_node_dump_level_done[level] = 0;
184 void doc_node_dump(DocNode *n) {
185 _doc_node_dump(n,0,1);
188 extern void error(const char *fmt, ...);
190 DocNode * scdoc_parse_file(char *fn, int mode) {
191 FILE *fp;
192 DocNode *n;
194 fp = fopen(fn,"r");
195 if(!fp) {
196 error("scdoc_parse_file: could not open '%s'\n",fn);
197 return NULL;
199 scdoc_current_file = fn;
200 scdocrestart(fp);
201 n = scdoc_parse_run(mode);
202 if(n) {
203 doc_node_fixup_tree(n);
205 fclose(fp);
206 scdoclex_destroy();
207 scdoc_current_file = NULL;
208 return n;