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 ************************************************************************/
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
) {
41 char *s
= (char *)realloc(a
,strlen(a
)+strlen(b
)+1);
47 static char *striptrailingws(char *s
) {
48 char *s2
= strchr(s
,0);
49 while(--s2
> s
&& isspace(*s2
)) {
55 DocNode
* doc_node_create(const char *id
) {
56 DocNode
*n
= (DocNode
*)malloc(sizeof(DocNode
));
64 // takes ownership of child
65 DocNode
* doc_node_add_child(DocNode
*n
, DocNode
*child
) {
67 n
->children
= (DocNode
**)realloc(n
->children
, (n
->n_childs
+1) * sizeof(DocNode
*));
68 n
->children
[n
->n_childs
] = child
;
74 // takes ownership of text
75 /*DocNode * doc_node_add_text(DocNode *n, char *text) {
77 char *str = strmergefree(n->text,text);
79 printf("NODE: Adding text '%s'\n",text);
86 // moves the childs from src doc_node to n
87 void doc_node_move_children(DocNode
*n
, DocNode
*src
) {
90 n
->children
= src
->children
;
91 n
->n_childs
= src
->n_childs
;
92 // src->children = NULL;
99 DocNode
* doc_node_make(const char *id
, char *text
, DocNode
*child
) {
100 DocNode
*n
= doc_node_create(id
);
102 doc_node_add_child(n
, child
);
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
);
112 void doc_node_free_tree(DocNode
*n
) {
116 for(i
=0;i
<n
->n_childs
;i
++) {
117 doc_node_free_tree(n
->children
[i
]);
123 void doc_node_fixup_tree(DocNode
*n
) {
125 if(n
->id
!= NODE_TEXT
&& n
->text
) {
126 n
->text
= striptrailingws(n
->text
);
129 DocNode
*last
= n
->children
[n
->n_childs
-1];
130 if(last
->id
==NODE_NL
) {
131 free(last
); // NL has no text or children
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
," ");
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
;
147 doc_node_fixup_tree(child
);
152 for(i
= 0; i
< n
->n_childs
; i
++) {
154 n
->children
[j
++] = n
->children
[i
];
161 static void _doc_node_dump(DocNode
*n
, int level
, int last
) {
163 for(i
=0;i
<level
;i
++) {
164 if(doc_node_dump_level_done
[i
])
171 doc_node_dump_level_done
[level
] = 1;
176 if(n
->text
) printf(" \"%s\"",n
->text
);
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
) {
196 error("scdoc_parse_file: could not open '%s'\n",fn
);
199 scdoc_current_file
= fn
;
201 n
= scdoc_parse_run(mode
);
203 doc_node_fixup_tree(n
);
207 scdoc_current_file
= NULL
;