1 /*
2  * load-schematic.c
3  *
4  *
5  * Authors:
6  *  Richard Hult <rhult@hem.passagen.se>
7  *  Ricardo Markiewicz <rmarkie@fi.uba.ar>
8  *  Andres de Barbara <adebarbara@fi.uba.ar>
9  *  Marc Lorber <lorber.marc@wanadoo.fr>
10  *  Bernhard Schuster <bernhard@ahoi.io>
11  *  Guido Trentalancia <guido@trentalancia.com>
12  *
13  * Web page: https://ahoi.io/project/oregano
14  *
15  * Copyright (C) 1999-2001  Richard Hult
16  * Copyright (C) 2003,2006  Ricardo Markiewicz
17  * Copyright (C) 2009-2012  Marc Lorber
18  * Copyright (C) 2013-2014  Bernhard Schuster
19  * Copyright (C) 2017       Guido Trentalancia
20  *
21  * This program is free software; you can redistribute it and/or
22  * modify it under the terms of the GNU General Public License as
23  * published by the Free Software Foundation; either version 2 of the
24  * License, or (at your option) any later version.
25  *
26  * This program is distributed in the hope that it will be useful,
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29  * General Public License for more details.
30  *
31  * You should have received a copy of the GNU General Public
32  * License along with this program; if not, write to the
33  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
34  * Boston, MA 02110-1301, USA.
35  */
36 
37 #include <string.h>
38 #include <glib/gi18n.h>
39 
40 #include "xml-compat.h"
41 #include "oregano.h"
42 #include "xml-helper.h"
43 #include "load-common.h"
44 #include "load-schematic.h"
45 #include "coords.h"
46 #include "part-label.h"
47 #include "schematic.h"
48 #include "sim-settings.h"
49 #include "textbox.h"
50 #include "errors.h"
51 #include "engines/netlist-helper.h"
52 
53 #include "debug.h"
54 
55 typedef enum {
56 	PARSE_START,
57 	PARSE_SCHEMATIC,
58 	PARSE_TITLE,
59 	PARSE_AUTHOR,
60 	PARSE_VERSION,
61 	PARSE_COMMENTS,
62 
63 	PARSE_SIMULATION_SETTINGS,
64 	PARSE_TRANSIENT_SETTINGS,
65 	PARSE_TRANSIENT_ENABLED,
66 	PARSE_TRANSIENT_START,
67 	PARSE_TRANSIENT_STOP,
68 	PARSE_TRANSIENT_STEP,
69 	PARSE_TRANSIENT_STEP_ENABLE,
70 	PARSE_TRANSIENT_INIT_COND,
71 	PARSE_TRANSIENT_ANALYZE_ALL,
72 
73 	PARSE_AC_SETTINGS,
74 	PARSE_AC_ENABLED,
75 	PARSE_AC_VOUT,
76 	PARSE_AC_TYPE,
77 	PARSE_AC_NPOINTS,
78 	PARSE_AC_START,
79 	PARSE_AC_STOP,
80 
81 	PARSE_DC_SETTINGS,
82 	PARSE_DC_ENABLED,
83 	PARSE_DC_VSRC,
84 	PARSE_DC_VOUT,
85 	PARSE_DC_START,
86 	PARSE_DC_STOP,
87 	PARSE_DC_STEP,
88 
89 	PARSE_FOURIER_SETTINGS,
90 	PARSE_FOURIER_ENABLED,
91 	PARSE_FOURIER_FREQ,
92 	PARSE_FOURIER_VOUT,
93 
94 	PARSE_NOISE_SETTINGS,
95 	PARSE_NOISE_ENABLED,
96 	PARSE_NOISE_VSRC,
97 	PARSE_NOISE_VOUT,
98 	PARSE_NOISE_TYPE,
99 	PARSE_NOISE_NPOINTS,
100 	PARSE_NOISE_START,
101 	PARSE_NOISE_STOP,
102 
103 	PARSE_OPTION_LIST,
104 	PARSE_OPTION,
105 	PARSE_OPTION_NAME,
106 	PARSE_OPTION_VALUE,
107 
108 	PARSE_ZOOM,
109 
110 	PARSE_PARTS,
111 	PARSE_PART,
112 	PARSE_PART_NAME,
113 	PARSE_PART_LIBNAME,
114 	PARSE_PART_REFDES,
115 	PARSE_PART_POSITION,
116 	PARSE_PART_ROTATION,
117 	PARSE_PART_FLIP,
118 	PARSE_PART_SYMNAME,
119 	PARSE_PART_TEMPLATE,
120 	PARSE_PART_MODEL,
121 	PARSE_PART_LABELS,
122 	PARSE_PART_LABEL,
123 	PARSE_PART_LABEL_NAME,
124 	PARSE_PART_LABEL_TEXT,
125 	PARSE_PART_LABEL_POS,
126 	PARSE_PART_PROPERTIES,
127 	PARSE_PART_PROPERTY,
128 	PARSE_PART_PROPERTY_NAME,
129 	PARSE_PART_PROPERTY_VALUE,
130 	PARSE_WIRES,
131 	PARSE_WIRE,
132 	PARSE_WIRE_POINTS,
133 	//	PARSE_WIRE_LABEL,
134 	PARSE_TEXTBOXES,
135 	PARSE_TEXTBOX,
136 	PARSE_TEXTBOX_TEXT,
137 	PARSE_TEXTBOX_POSITION,
138 	PARSE_FINISH,
139 	PARSE_UNKNOWN,
140 	PARSE_ERROR
141 } State;
142 
143 typedef struct
144 {
145 	State state;
146 	State prev_state;
147 	int unknown_depth;
148 	GString *content;
149 	Schematic *schematic;
150 	SimSettings *sim_settings;
151 
152 	char *author;
153 	char *title;
154 	char *oregano_version;
155 	char *comments;
156 
157 	char *textbox_text;
158 
159 	// Temporary place holder for a wire
160 	Coords wire_start;
161 	Coords wire_end;
162 
163 	// Temporary place holder for a part
164 	LibraryPart *part;
165 	PartLabel *label;
166 	Property *property;
167 	Coords pos;
168 	int rotation;
169 	IDFlip flip;
170 
171 	// Temporary place holder for an option
172 	SimOption *option;
173 } ParseState;
174 
175 static xmlEntityPtr get_entity (void *user_data, const xmlChar *name);
176 static void start_document (ParseState *state);
177 static void end_document (ParseState *state);
178 static void start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs);
179 static void end_element (ParseState *state, const xmlChar *name);
180 
181 static void my_characters (ParseState *state, const xmlChar *chars, int len);
182 static void my_warning (void *user_data, const char *msg, ...);
183 static void my_error (void *user_data, const char *msg, ...);
184 static void my_fatal_error (void *user_data, const char *msg, ...);
185 
186 static void create_wire (ParseState *state);
187 static void create_part (ParseState *state);
188 
189 static xmlSAXHandler oreganoSAXParser = {
190     0,                                    // internalSubset
191     0,                                    // isStandalone
192     0,                                    // hasInternalSubset
193     0,                                    // hasExternalSubset
194     0,                                    // resolveEntity
195     (getEntitySAXFunc)get_entity,         // getEntity
196     0,                                    // entityDecl
197     0,                                    // notationDecl
198     0,                                    // attributeDecl
199     0,                                    // elementDecl
200     0,                                    // unparsedEntityDecl
201     0,                                    // setDocumentLocator
202     (startDocumentSAXFunc)start_document, // startDocument
203     (endDocumentSAXFunc)end_document,     // endDocument
204     (startElementSAXFunc)start_element,   // startElement
205     (endElementSAXFunc)end_element,       // endElement
206     0,                                    // reference
207     (charactersSAXFunc)my_characters,     // characters
208     0,                                    // ignorableWhitespace
209     0,                                    // processingInstruction
210     0,                                    //(commentSAXFunc)0,	 comment
211     (warningSAXFunc)my_warning,           // warning
212     (errorSAXFunc)my_error,               // error
213     (fatalErrorSAXFunc)my_fatal_error,    // fatalError
214 };
215 
create_textbox(ParseState * state)216 static void create_textbox (ParseState *state)
217 {
218 	Textbox *textbox;
219 
220 	textbox = textbox_new (NULL);
221 	textbox_set_text (textbox, state->textbox_text);
222 	item_data_set_pos (ITEM_DATA (textbox), &state->pos);
223 	schematic_add_item (state->schematic, ITEM_DATA (textbox));
224 }
225 
create_wire(ParseState * state)226 static void create_wire (ParseState *state)
227 {
228 	Coords start_pos, length;
229 	Wire *wire;
230 
231 	start_pos.x = state->wire_start.x;
232 	start_pos.y = state->wire_start.y;
233 	length.x = state->wire_end.x - start_pos.x;
234 	length.y = state->wire_end.y - start_pos.y;
235 
236 	wire = wire_new ();
237 	wire_set_length (wire, &length);
238 
239 	item_data_set_pos (ITEM_DATA (wire), &state->wire_start);
240 	schematic_add_item (state->schematic, ITEM_DATA (wire));
241 }
242 
create_part(ParseState * state)243 static void create_part (ParseState *state)
244 {
245 	Part *part;
246 	LibraryPart *library_part = state->part;
247 
248 	part = part_new_from_library_part (library_part);
249 	if (!part) {
250 		g_warning ("Failed to create Part from LibraryPart");
251 		return;
252 	}
253 
254 	item_data_set_pos (ITEM_DATA (part), &state->pos);
255 	item_data_rotate (ITEM_DATA (part), state->rotation, NULL);
256 	if (state->flip & ID_FLIP_HORIZ)
257 		item_data_flip (ITEM_DATA (part), ID_FLIP_HORIZ, NULL);
258 	if (state->flip & ID_FLIP_VERT)
259 		item_data_flip (ITEM_DATA (part), ID_FLIP_VERT, NULL);
260 
261 	schematic_add_item (state->schematic, ITEM_DATA (part));
262 }
263 
schematic_parse_xml_file(Schematic * sm,const char * filename,GError ** error)264 int schematic_parse_xml_file (Schematic *sm, const char *filename, GError **error)
265 {
266 	ParseState state;
267 	int retval = 0;
268 
269 	state.schematic = sm;
270 	state.sim_settings = schematic_get_sim_settings (sm);
271 	state.author = NULL;
272 	state.title = NULL;
273 	state.oregano_version = NULL;
274 	state.comments = NULL;
275 
276 	if (!oreganoXmlSAXParseFile (&oreganoSAXParser, &state, filename)) {
277 		g_warning ("Document not well formed!");
278 		if (error != NULL) {
279 			g_set_error (error, OREGANO_ERROR, OREGANO_SCHEMATIC_BAD_FILE_FORMAT,
280 			             _ ("Bad file format."));
281 		}
282 		retval = -1;
283 	}
284 
285 	if (state.state == PARSE_ERROR) {
286 		if (error != NULL) {
287 			g_set_error (error, OREGANO_ERROR, OREGANO_SCHEMATIC_BAD_FILE_FORMAT,
288 			             _ ("Unknown parser error."));
289 		}
290 		retval = -2;
291 	}
292 
293 	schematic_set_filename(sm, filename);
294 	schematic_set_author (sm, state.author);
295 	schematic_set_title (sm, state.title);
296 	schematic_set_version(sm, state.oregano_version);
297 	schematic_set_comments (sm, state.comments);
298 
299 	g_free(state.author);
300 	g_free(state.title);
301 	g_free(state.oregano_version);
302 	g_free(state.comments);
303 
304 	update_schematic(sm);
305 
306 	return retval;
307 }
308 
start_document(ParseState * state)309 static void start_document (ParseState *state)
310 {
311 	state->state = PARSE_START;
312 	state->unknown_depth = 0;
313 	state->prev_state = PARSE_UNKNOWN;
314 
315 	state->content = g_string_sized_new (128);
316 	state->part = NULL;
317 }
318 
end_document(ParseState * state)319 static void end_document (ParseState *state)
320 {
321 
322 	if (state->unknown_depth != 0)
323 		g_warning ("unknown_depth != 0 (%d)", state->unknown_depth);
324 }
325 
start_element(ParseState * state,const xmlChar * name,const xmlChar ** attrs)326 static void start_element (ParseState *state, const xmlChar *name, const xmlChar **attrs)
327 {
328 	switch (state->state) {
329 	case PARSE_START:
330 		if (xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:schematic")) {
331 			g_warning ("Expecting 'ogo:schematic'.  Got '%s'", name);
332 			state->state = PARSE_ERROR;
333 		} else
334 			state->state = PARSE_SCHEMATIC;
335 		break;
336 
337 	case PARSE_SCHEMATIC:
338 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:author")) {
339 			state->state = PARSE_AUTHOR;
340 			g_string_truncate (state->content, 0);
341 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:title")) {
342 			state->state = PARSE_TITLE;
343 			g_string_truncate (state->content, 0);
344 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:version")) {
345 			state->state = PARSE_VERSION;
346 			g_string_truncate (state->content, 0);
347 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:comments")) {
348 			state->state = PARSE_COMMENTS;
349 			g_string_truncate (state->content, 0);
350 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:zoom")) {
351 			state->state = PARSE_ZOOM;
352 			g_string_truncate (state->content, 0);
353 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:simulation-settings")) {
354 			state->state = PARSE_SIMULATION_SETTINGS;
355 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:parts")) {
356 			state->state = PARSE_PARTS;
357 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:wires")) {
358 			state->state = PARSE_WIRES;
359 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:textboxes")) {
360 			state->state = PARSE_TEXTBOXES;
361 		} else {
362 			state->prev_state = state->state;
363 			state->state = PARSE_UNKNOWN;
364 			state->unknown_depth++;
365 		}
366 		break;
367 
368 	case PARSE_SIMULATION_SETTINGS:
369 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:transient")) {
370 			state->state = PARSE_TRANSIENT_SETTINGS;
371 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:ac")) {
372 			state->state = PARSE_AC_SETTINGS;
373 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:dc-sweep")) {
374 			state->state = PARSE_DC_SETTINGS;
375 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:fourier")) {
376 			state->state = PARSE_FOURIER_SETTINGS;
377 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:noise")) {
378 			state->state = PARSE_NOISE_SETTINGS;
379 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:options")) {
380 			state->state = PARSE_OPTION_LIST;
381 		} else {
382 			state->prev_state = state->state;
383 			state->state = PARSE_UNKNOWN;
384 			state->unknown_depth++;
385 		}
386 		break;
387 
388 	case PARSE_TRANSIENT_SETTINGS:
389 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:enabled")) {
390 			state->state = PARSE_TRANSIENT_ENABLED;
391 			g_string_truncate (state->content, 0);
392 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:start")) {
393 			state->state = PARSE_TRANSIENT_START;
394 			g_string_truncate (state->content, 0);
395 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:stop")) {
396 			state->state = PARSE_TRANSIENT_STOP;
397 			g_string_truncate (state->content, 0);
398 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:step")) {
399 			state->state = PARSE_TRANSIENT_STEP;
400 			g_string_truncate (state->content, 0);
401 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:step-enabled")) {
402 			state->state = PARSE_TRANSIENT_STEP_ENABLE;
403 			g_string_truncate (state->content, 0);
404 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:init-conditions")) {
405 			state->state = PARSE_TRANSIENT_INIT_COND;
406 			g_string_truncate (state->content, 0);
407 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:analyze-all")) {
408 			state->state = PARSE_TRANSIENT_ANALYZE_ALL;
409 			g_string_truncate (state->content, 0);
410 		} else {
411 			state->prev_state = state->state;
412 			state->state = PARSE_UNKNOWN;
413 			state->unknown_depth++;
414 		}
415 		break;
416 
417 	case PARSE_AC_SETTINGS:
418 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:enabled")) {
419 			state->state = PARSE_AC_ENABLED;
420 			g_string_truncate (state->content, 0);
421 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vout1")) {
422 			state->state = PARSE_AC_VOUT;
423 			g_string_truncate (state->content, 0);
424 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:type")) {
425 			state->state = PARSE_AC_TYPE;
426 			g_string_truncate (state->content, 0);
427 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:npoints")) {
428 			state->state = PARSE_AC_NPOINTS;
429 			g_string_truncate (state->content, 0);
430 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:start")) {
431 			state->state = PARSE_AC_START;
432 			g_string_truncate (state->content, 0);
433 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:stop")) {
434 			state->state = PARSE_AC_STOP;
435 			g_string_truncate (state->content, 0);
436 		} else {
437 			state->prev_state = state->state;
438 			state->state = PARSE_UNKNOWN;
439 			state->unknown_depth++;
440 		}
441 		break;
442 
443 	case PARSE_DC_SETTINGS:
444 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:enabled")) {
445 			state->state = PARSE_DC_ENABLED;
446 			g_string_truncate (state->content, 0);
447 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vsrc1")) {
448 			state->state = PARSE_DC_VSRC;
449 			g_string_truncate (state->content, 0);
450 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vout1")) {
451 			state->state = PARSE_DC_VOUT;
452 			g_string_truncate (state->content, 0);
453 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:start1")) {
454 			state->state = PARSE_DC_START;
455 			g_string_truncate (state->content, 0);
456 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:stop1")) {
457 			state->state = PARSE_DC_STOP;
458 			g_string_truncate (state->content, 0);
459 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:step1")) {
460 			state->state = PARSE_DC_STEP;
461 			g_string_truncate (state->content, 0);
462 		} else {
463 			state->prev_state = state->state;
464 			state->state = PARSE_UNKNOWN;
465 			state->unknown_depth++;
466 		}
467 		break;
468 
469 	case PARSE_FOURIER_SETTINGS:
470 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:enabled")) {
471 			state->state = PARSE_FOURIER_ENABLED;
472 			g_string_truncate (state->content, 0);
473 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:freq")) {
474 			state->state = PARSE_FOURIER_FREQ;
475 			g_string_truncate (state->content, 0);
476 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vout")) {
477 			state->state = PARSE_FOURIER_VOUT;
478 			g_string_truncate (state->content, 0);
479 		} else {
480 			state->prev_state = state->state;
481 			state->state = PARSE_UNKNOWN;
482 			state->unknown_depth++;
483 		}
484 		break;
485 
486 	case PARSE_NOISE_SETTINGS:
487 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:enabled")) {
488 			state->state = PARSE_NOISE_ENABLED;
489 			g_string_truncate (state->content, 0);
490 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vsrc1")) {
491 			state->state = PARSE_NOISE_VSRC;
492 			g_string_truncate (state->content, 0);
493 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:vout1")) {
494 			state->state = PARSE_NOISE_VOUT;
495 			g_string_truncate (state->content, 0);
496 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:type")) {
497 			state->state = PARSE_NOISE_TYPE;
498 			g_string_truncate (state->content, 0);
499 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:npoints")) {
500 			state->state = PARSE_NOISE_NPOINTS;
501 			g_string_truncate (state->content, 0);
502 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:start")) {
503 			state->state = PARSE_NOISE_START;
504 			g_string_truncate (state->content, 0);
505 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:stop")) {
506 			state->state = PARSE_NOISE_STOP;
507 			g_string_truncate (state->content, 0);
508 		} else {
509 			state->prev_state = state->state;
510 			state->state = PARSE_UNKNOWN;
511 			state->unknown_depth++;
512 		}
513 		break;
514 
515 	case PARSE_OPTION_LIST:
516 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:option")) {
517 			state->state = PARSE_OPTION;
518 			state->option = g_new0 (SimOption, 1);
519 			g_string_truncate (state->content, 0);
520 		} else {
521 			state->prev_state = state->state;
522 			state->state = PARSE_UNKNOWN;
523 			state->unknown_depth++;
524 		}
525 		break;
526 	case PARSE_OPTION:
527 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:name")) {
528 			state->state = PARSE_OPTION_NAME;
529 			g_string_truncate (state->content, 0);
530 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:value")) {
531 			state->state = PARSE_OPTION_VALUE;
532 			g_string_truncate (state->content, 0);
533 		} else {
534 			state->prev_state = state->state;
535 			state->state = PARSE_UNKNOWN;
536 			state->unknown_depth++;
537 		}
538 
539 		break;
540 	case PARSE_PARTS:
541 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:part")) {
542 			state->state = PARSE_PART;
543 			state->part = g_new0 (LibraryPart, 1);
544 			state->rotation = 0;
545 			state->flip = ID_FLIP_NONE;
546 			state->label = NULL;
547 			state->property = NULL;
548 		} else {
549 			state->prev_state = state->state;
550 			state->state = PARSE_UNKNOWN;
551 			state->unknown_depth++;
552 		}
553 		break;
554 	case PARSE_PART:
555 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:name")) {
556 			state->state = PARSE_PART_NAME;
557 			g_string_truncate (state->content, 0);
558 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:library")) {
559 			state->state = PARSE_PART_LIBNAME;
560 			g_string_truncate (state->content, 0);
561 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:refdes")) {
562 			state->state = PARSE_PART_REFDES;
563 			g_string_truncate (state->content, 0);
564 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:position")) {
565 			state->state = PARSE_PART_POSITION;
566 			g_string_truncate (state->content, 0);
567 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:rotation")) {
568 			state->state = PARSE_PART_ROTATION;
569 			g_string_truncate (state->content, 0);
570 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:flip")) {
571 			state->state = PARSE_PART_FLIP;
572 			g_string_truncate (state->content, 0);
573 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:template")) {
574 			state->state = PARSE_PART_TEMPLATE;
575 			g_string_truncate (state->content, 0);
576 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:model")) {
577 			state->state = PARSE_PART_MODEL;
578 			g_string_truncate (state->content, 0);
579 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:symbol")) {
580 			state->state = PARSE_PART_SYMNAME;
581 			g_string_truncate (state->content, 0);
582 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:labels")) {
583 			state->state = PARSE_PART_LABELS;
584 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:properties")) {
585 			state->state = PARSE_PART_PROPERTIES;
586 		} else {
587 			state->prev_state = state->state;
588 			state->state = PARSE_UNKNOWN;
589 			state->unknown_depth++;
590 		}
591 		break;
592 	case PARSE_PART_LABELS:
593 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:label")) {
594 			state->state = PARSE_PART_LABEL;
595 			state->label = g_new0 (PartLabel, 1);
596 		} else {
597 			state->prev_state = state->state;
598 			state->state = PARSE_UNKNOWN;
599 			state->unknown_depth++;
600 		}
601 		break;
602 	case PARSE_PART_LABEL:
603 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:name")) {
604 			state->state = PARSE_PART_LABEL_NAME;
605 			g_string_truncate (state->content, 0);
606 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:text")) {
607 			state->state = PARSE_PART_LABEL_TEXT;
608 			g_string_truncate (state->content, 0);
609 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:position")) {
610 			state->state = PARSE_PART_LABEL_POS;
611 			g_string_truncate (state->content, 0);
612 		} else {
613 			state->prev_state = state->state;
614 			state->state = PARSE_UNKNOWN;
615 			state->unknown_depth++;
616 		}
617 		break;
618 
619 	case PARSE_PART_PROPERTIES:
620 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:property")) {
621 			state->state = PARSE_PART_PROPERTY;
622 			state->property = g_new0 (Property, 1);
623 		} else {
624 			state->prev_state = state->state;
625 			state->state = PARSE_UNKNOWN;
626 			state->unknown_depth++;
627 		}
628 		break;
629 	case PARSE_PART_PROPERTY:
630 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:name")) {
631 			state->state = PARSE_PART_PROPERTY_NAME;
632 			g_string_truncate (state->content, 0);
633 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:value")) {
634 			state->state = PARSE_PART_PROPERTY_VALUE;
635 			g_string_truncate (state->content, 0);
636 		} else {
637 			state->prev_state = state->state;
638 			state->state = PARSE_UNKNOWN;
639 			state->unknown_depth++;
640 		}
641 		break;
642 
643 	case PARSE_WIRES:
644 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:wire")) {
645 			state->state = PARSE_WIRE;
646 		} else {
647 			state->prev_state = state->state;
648 			state->state = PARSE_UNKNOWN;
649 			state->unknown_depth++;
650 		}
651 		break;
652 	case PARSE_WIRE:
653 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:points")) {
654 			state->state = PARSE_WIRE_POINTS;
655 			g_string_truncate (state->content, 0);
656 		} else {
657 			state->prev_state = state->state;
658 			state->state = PARSE_UNKNOWN;
659 			state->unknown_depth++;
660 		}
661 		break;
662 
663 	case PARSE_TEXTBOXES:
664 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:textbox")) {
665 			state->state = PARSE_TEXTBOX;
666 		} else {
667 			state->prev_state = state->state;
668 			state->state = PARSE_UNKNOWN;
669 			state->unknown_depth++;
670 		}
671 		break;
672 	case PARSE_TEXTBOX:
673 		if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:position")) {
674 			state->state = PARSE_TEXTBOX_POSITION;
675 			g_string_truncate (state->content, 0);
676 		} else if (!xmlStrcmp (BAD_CAST name, BAD_CAST "ogo:text")) {
677 			state->state = PARSE_TEXTBOX_TEXT;
678 			g_string_truncate (state->content, 0);
679 		} else {
680 			state->prev_state = state->state;
681 			state->state = PARSE_UNKNOWN;
682 			state->unknown_depth++;
683 		}
684 		break;
685 
686 	case PARSE_TRANSIENT_ENABLED:
687 	case PARSE_TRANSIENT_START:
688 	case PARSE_TRANSIENT_STOP:
689 	case PARSE_TRANSIENT_STEP:
690 	case PARSE_TRANSIENT_STEP_ENABLE:
691 
692 	case PARSE_AC_ENABLED:
693 	case PARSE_AC_VOUT:
694 	case PARSE_AC_TYPE:
695 	case PARSE_AC_NPOINTS:
696 	case PARSE_AC_START:
697 	case PARSE_AC_STOP:
698 
699 	case PARSE_DC_ENABLED:
700 	case PARSE_DC_VSRC:
701 	case PARSE_DC_VOUT:
702 	case PARSE_DC_START:
703 	case PARSE_DC_STOP:
704 	case PARSE_DC_STEP:
705 
706 	case PARSE_FOURIER_ENABLED:
707 	case PARSE_FOURIER_FREQ:
708 	case PARSE_FOURIER_VOUT:
709 
710 	case PARSE_NOISE_ENABLED:
711 	case PARSE_NOISE_VSRC:
712 	case PARSE_NOISE_VOUT:
713 	case PARSE_NOISE_TYPE:
714 	case PARSE_NOISE_NPOINTS:
715 	case PARSE_NOISE_START:
716 	case PARSE_NOISE_STOP:
717 
718 	case PARSE_WIRE_POINTS:
719 	case PARSE_OPTION_NAME:
720 	case PARSE_OPTION_VALUE:
721 	case PARSE_PART_NAME:
722 	case PARSE_PART_LIBNAME:
723 	case PARSE_PART_TEMPLATE:
724 	case PARSE_PART_MODEL:
725 	case PARSE_PART_REFDES:
726 	case PARSE_PART_POSITION:
727 	case PARSE_PART_ROTATION:
728 	case PARSE_PART_FLIP:
729 	case PARSE_PART_SYMNAME:
730 	case PARSE_PART_LABEL_NAME:
731 	case PARSE_PART_LABEL_TEXT:
732 	case PARSE_PART_LABEL_POS:
733 	case PARSE_PART_PROPERTY_NAME:
734 	case PARSE_PART_PROPERTY_VALUE:
735 	case PARSE_TEXTBOX_POSITION:
736 	case PARSE_TEXTBOX_TEXT:
737 	case PARSE_ZOOM:
738 	case PARSE_TITLE:
739 	case PARSE_AUTHOR:
740 	case PARSE_VERSION:
741 	case PARSE_COMMENTS:
742 	case PARSE_TRANSIENT_INIT_COND:
743 	case PARSE_TRANSIENT_ANALYZE_ALL:
744 		// there should be no tags inside these types of tags
745 		g_message ("*** '%s' tag found", name);
746 		state->prev_state = state->state;
747 		state->state = PARSE_UNKNOWN;
748 		state->unknown_depth++;
749 		break;
750 
751 	case PARSE_ERROR:
752 		break;
753 	case PARSE_UNKNOWN:
754 		state->unknown_depth++;
755 		break;
756 	case PARSE_FINISH:
757 		// should not start new elements in this state
758 		g_assert_not_reached ();
759 		break;
760 	}
761 	// g_message("Start element %s (state %s)", name, states[state->state]);
762 }
763 
end_element(ParseState * state,const xmlChar * name)764 static void end_element (ParseState *state, const xmlChar *name)
765 {
766 	GList *libs;
767 	Schematic *schematic = state->schematic;
768 
769 	switch (state->state) {
770 	case PARSE_UNKNOWN:
771 		state->unknown_depth--;
772 		if (state->unknown_depth == 0)
773 			state->state = state->prev_state;
774 		break;
775 	case PARSE_AUTHOR:
776 		state->author = g_strdup (state->content->str);
777 		state->state = PARSE_SCHEMATIC;
778 		break;
779 	case PARSE_TITLE:
780 		state->title = g_strdup (state->content->str);
781 		state->state = PARSE_SCHEMATIC;
782 		break;
783 	case PARSE_VERSION:
784 		state->oregano_version = g_strdup (state->content->str);
785 		state->state = PARSE_SCHEMATIC;
786 		break;
787 	case PARSE_COMMENTS:
788 		state->comments = g_strdup (state->content->str);
789 		state->state = PARSE_SCHEMATIC;
790 		break;
791 	case PARSE_ZOOM: {
792 		double zoom;
793 
794 		zoom = g_strtod (state->content->str, NULL);
795 		schematic_set_zoom (state->schematic, zoom);
796 		state->state = PARSE_SCHEMATIC;
797 
798 		break;
799 	}
800 
801 	case PARSE_SIMULATION_SETTINGS:
802 		state->state = PARSE_SCHEMATIC;
803 		break;
804 
805 	case PARSE_TRANSIENT_SETTINGS:
806 		state->state = PARSE_SIMULATION_SETTINGS;
807 		break;
808 	case PARSE_TRANSIENT_ENABLED:
809 		sim_settings_set_trans (state->sim_settings,
810 		                        !g_ascii_strcasecmp (state->content->str, "true"));
811 		state->state = PARSE_TRANSIENT_SETTINGS;
812 		break;
813 	case PARSE_TRANSIENT_START:
814 		sim_settings_set_trans_start (state->sim_settings, state->content->str);
815 		state->state = PARSE_TRANSIENT_SETTINGS;
816 		break;
817 	case PARSE_TRANSIENT_STOP:
818 		sim_settings_set_trans_stop (state->sim_settings, state->content->str);
819 		state->state = PARSE_TRANSIENT_SETTINGS;
820 		break;
821 	case PARSE_TRANSIENT_STEP:
822 		sim_settings_set_trans_step (state->sim_settings, state->content->str);
823 		state->state = PARSE_TRANSIENT_SETTINGS;
824 		break;
825 	case PARSE_TRANSIENT_STEP_ENABLE:
826 		sim_settings_set_trans_step_enable (state->sim_settings,
827 		                                    !g_ascii_strcasecmp (state->content->str, "true"));
828 		state->state = PARSE_TRANSIENT_SETTINGS;
829 		break;
830 	case PARSE_TRANSIENT_INIT_COND:
831 		sim_settings_set_trans_init_cond (state->sim_settings,
832 		                                  !g_ascii_strcasecmp (state->content->str, "true"));
833 		state->state = PARSE_TRANSIENT_SETTINGS;
834 		break;
835 	case PARSE_TRANSIENT_ANALYZE_ALL:
836 		sim_settings_set_trans_analyze_all(state->sim_settings,
837 		                                !g_ascii_strcasecmp (state->content->str, "true"));
838 		state->state = PARSE_TRANSIENT_SETTINGS;
839 		break;
840 
841 	case PARSE_AC_SETTINGS:
842 		state->state = PARSE_SIMULATION_SETTINGS;
843 		break;
844 	case PARSE_AC_ENABLED:
845 		sim_settings_set_ac (state->sim_settings,
846 		                     !g_ascii_strcasecmp (state->content->str, "true"));
847 		state->state = PARSE_AC_SETTINGS;
848 		break;
849 	case PARSE_AC_VOUT:
850 		sim_settings_set_ac_vout (state->sim_settings, state->content->str);
851 		state->state = PARSE_AC_SETTINGS;
852 		break;
853 	case PARSE_AC_TYPE:
854 		sim_settings_set_ac_type (state->sim_settings, state->content->str);
855 		state->state = PARSE_AC_SETTINGS;
856 		break;
857 	case PARSE_AC_NPOINTS:
858 		sim_settings_set_ac_npoints (state->sim_settings, state->content->str);
859 		state->state = PARSE_AC_SETTINGS;
860 		break;
861 	case PARSE_AC_START:
862 		sim_settings_set_ac_start (state->sim_settings, state->content->str);
863 		state->state = PARSE_AC_SETTINGS;
864 		break;
865 	case PARSE_AC_STOP:
866 		sim_settings_set_ac_stop (state->sim_settings, state->content->str);
867 		state->state = PARSE_AC_SETTINGS;
868 		break;
869 
870 	case PARSE_DC_SETTINGS:
871 		state->state = PARSE_SIMULATION_SETTINGS;
872 		break;
873 	case PARSE_DC_ENABLED:
874 		sim_settings_set_dc (state->sim_settings,
875 		                     !g_ascii_strcasecmp (state->content->str, "true"));
876 		state->state = PARSE_DC_SETTINGS;
877 		break;
878 	case PARSE_DC_VSRC:
879 		sim_settings_set_dc_vsrc (state->sim_settings, state->content->str);
880 		state->state = PARSE_DC_SETTINGS;
881 		break;
882 	case PARSE_DC_VOUT:
883 		sim_settings_set_dc_vout (state->sim_settings, state->content->str);
884 		state->state = PARSE_DC_SETTINGS;
885 		break;
886 	case PARSE_DC_START:
887 		sim_settings_set_dc_start (state->sim_settings, state->content->str);
888 		state->state = PARSE_DC_SETTINGS;
889 		break;
890 	case PARSE_DC_STOP:
891 		sim_settings_set_dc_stop (state->sim_settings, state->content->str);
892 		state->state = PARSE_DC_SETTINGS;
893 		break;
894 	case PARSE_DC_STEP:
895 		sim_settings_set_dc_step (state->sim_settings, state->content->str);
896 		state->state = PARSE_DC_SETTINGS;
897 		break;
898 
899 	case PARSE_FOURIER_SETTINGS:
900 		state->state = PARSE_SIMULATION_SETTINGS;
901 		break;
902 	case PARSE_FOURIER_ENABLED:
903 		sim_settings_set_fourier (state->sim_settings,
904 		                          !g_ascii_strcasecmp (state->content->str, "true"));
905 		state->state = PARSE_FOURIER_SETTINGS;
906 		break;
907 	case PARSE_FOURIER_FREQ:
908 		sim_settings_set_fourier_frequency (state->sim_settings, state->content->str);
909 		state->state = PARSE_FOURIER_SETTINGS;
910 		break;
911 	case PARSE_FOURIER_VOUT:
912 		sim_settings_set_fourier_vout (state->sim_settings, state->content->str);
913 		state->state = PARSE_FOURIER_SETTINGS;
914 		break;
915 
916 	case PARSE_NOISE_SETTINGS:
917 		state->state = PARSE_SIMULATION_SETTINGS;
918 		break;
919 	case PARSE_NOISE_ENABLED:
920 		sim_settings_set_noise (state->sim_settings,
921 		                     !g_ascii_strcasecmp (state->content->str, "true"));
922 		state->state = PARSE_NOISE_SETTINGS;
923 		break;
924 	case PARSE_NOISE_VSRC:
925 		sim_settings_set_noise_vsrc (state->sim_settings, state->content->str);
926 		state->state = PARSE_NOISE_SETTINGS;
927 		break;
928 	case PARSE_NOISE_VOUT:
929 		sim_settings_set_noise_vout (state->sim_settings, state->content->str);
930 		state->state = PARSE_NOISE_SETTINGS;
931 		break;
932 	case PARSE_NOISE_TYPE:
933 		sim_settings_set_noise_type (state->sim_settings, state->content->str);
934 		state->state = PARSE_NOISE_SETTINGS;
935 		break;
936 	case PARSE_NOISE_NPOINTS:
937 		sim_settings_set_noise_npoints (state->sim_settings, state->content->str);
938 		state->state = PARSE_NOISE_SETTINGS;
939 		break;
940 	case PARSE_NOISE_START:
941 		sim_settings_set_noise_start (state->sim_settings, state->content->str);
942 		state->state = PARSE_NOISE_SETTINGS;
943 		break;
944 	case PARSE_NOISE_STOP:
945 		sim_settings_set_noise_stop (state->sim_settings, state->content->str);
946 		state->state = PARSE_NOISE_SETTINGS;
947 		break;
948 
949 	case PARSE_OPTION_LIST:
950 		state->state = PARSE_SIMULATION_SETTINGS;
951 		break;
952 	case PARSE_OPTION:
953 		state->state = PARSE_OPTION_LIST;
954 		sim_settings_add_option (state->sim_settings, state->option);
955 		state->option = g_new0 (SimOption, 1);
956 		break;
957 	case PARSE_OPTION_NAME:
958 		state->option->name = g_strdup (state->content->str);
959 		state->state = PARSE_OPTION;
960 		break;
961 
962 	case PARSE_OPTION_VALUE:
963 		state->option->value = g_strdup (state->content->str);
964 		state->state = PARSE_OPTION;
965 		break;
966 
967 	case PARSE_PARTS:
968 		state->state = PARSE_SCHEMATIC;
969 		break;
970 	case PARSE_PART:
971 		create_part (state);
972 		state->state = PARSE_PARTS;
973 		break;
974 	case PARSE_PART_NAME:
975 		state->part->name = g_strdup (state->content->str);
976 		state->state = PARSE_PART;
977 		break;
978 	case PARSE_PART_LIBNAME:
979 		state->state = PARSE_PART;
980 		state->part->library = NULL;
981 		libs = oregano.libraries;
982 		while (libs) {
983 			Library *lib = (Library *)libs->data;
984 			if (g_ascii_strcasecmp (state->content->str, lib->name) == 0) {
985 				state->part->library = lib;
986 				break;
987 			}
988 			libs = libs->next;
989 		}
990 		break;
991 	case PARSE_PART_POSITION:
992 		sscanf (state->content->str, "(%lf %lf)", &state->pos.x, &state->pos.y);
993 		// Try to fix invalid positions
994 		if (state->pos.x < 0)
995 			state->pos.x = -state->pos.x;
996 		if (state->pos.y < 0)
997 			state->pos.y = -state->pos.y;
998 		// Determine the maximum parts' coordinates to be used during sheet creation
999 		if (state->pos.x > schematic_get_width(schematic))
1000 			schematic_set_width(schematic, (guint) state->pos.x);
1001 		if (state->pos.y > schematic_get_height(schematic))
1002 			schematic_set_height(schematic, (guint) state->pos.y);
1003 		state->state = PARSE_PART;
1004 		break;
1005 	case PARSE_PART_ROTATION:
1006 		sscanf (state->content->str, "%d", &state->rotation);
1007 		state->state = PARSE_PART;
1008 		break;
1009 	case PARSE_PART_FLIP:
1010 		if (g_ascii_strcasecmp (state->content->str, "horizontal") == 0)
1011 			state->flip = state->flip | ID_FLIP_HORIZ;
1012 		else if (g_ascii_strcasecmp (state->content->str, "vertical") == 0)
1013 			state->flip = state->flip | ID_FLIP_VERT;
1014 		state->state = PARSE_PART;
1015 		break;
1016 	case PARSE_PART_REFDES:
1017 		state->part->refdes = g_strdup (state->content->str);
1018 		state->state = PARSE_PART;
1019 		break;
1020 	case PARSE_PART_TEMPLATE:
1021 		state->part->template = g_strdup (state->content->str);
1022 		state->state = PARSE_PART;
1023 		break;
1024 	case PARSE_PART_MODEL:
1025 		state->part->model = g_strdup (state->content->str);
1026 		state->state = PARSE_PART;
1027 		break;
1028 	case PARSE_PART_SYMNAME:
1029 		state->part->symbol_name = g_strdup (state->content->str);
1030 		state->state = PARSE_PART;
1031 		break;
1032 	case PARSE_PART_LABELS:
1033 		state->state = PARSE_PART;
1034 		break;
1035 	case PARSE_PART_LABEL:
1036 		state->state = PARSE_PART_LABELS;
1037 		state->part->labels = g_slist_prepend (state->part->labels, state->label);
1038 		break;
1039 	case PARSE_PART_LABEL_NAME:
1040 		state->label->name = g_strdup (state->content->str);
1041 		state->state = PARSE_PART_LABEL;
1042 		break;
1043 	case PARSE_PART_LABEL_TEXT:
1044 		state->label->text = g_strdup (state->content->str);
1045 		state->state = PARSE_PART_LABEL;
1046 		break;
1047 	case PARSE_PART_LABEL_POS:
1048 		sscanf (state->content->str, "(%lf %lf)", &state->label->pos.x, &state->label->pos.y);
1049 		state->state = PARSE_PART_LABEL;
1050 		break;
1051 	case PARSE_PART_PROPERTIES:
1052 		state->state = PARSE_PART;
1053 		break;
1054 	case PARSE_PART_PROPERTY:
1055 		state->state = PARSE_PART_PROPERTIES;
1056 		state->part->properties = g_slist_prepend (state->part->properties, state->property);
1057 		break;
1058 	case PARSE_PART_PROPERTY_NAME:
1059 		state->property->name = g_strdup (state->content->str);
1060 		state->state = PARSE_PART_PROPERTY;
1061 		break;
1062 	case PARSE_PART_PROPERTY_VALUE:
1063 		state->property->value = g_strdup (state->content->str);
1064 		state->state = PARSE_PART_PROPERTY;
1065 		break;
1066 
1067 	case PARSE_WIRES:
1068 		state->state = PARSE_SCHEMATIC;
1069 		break;
1070 	case PARSE_WIRE:
1071 		state->state = PARSE_WIRES;
1072 		break;
1073 	case PARSE_WIRE_POINTS:
1074 		sscanf (state->content->str, "(%lf %lf)(%lf %lf)", &state->wire_start.x,
1075 		        &state->wire_start.y, &state->wire_end.x, &state->wire_end.y);
1076 		create_wire (state);
1077 		state->state = PARSE_WIRE;
1078 		break;
1079 
1080 	case PARSE_TEXTBOXES:
1081 		state->state = PARSE_SCHEMATIC;
1082 		break;
1083 	case PARSE_TEXTBOX:
1084 		create_textbox (state);
1085 		state->state = PARSE_TEXTBOXES;
1086 		break;
1087 	case PARSE_TEXTBOX_POSITION:
1088 		sscanf (state->content->str, "(%lf %lf)", &state->pos.x, &state->pos.y);
1089 		state->state = PARSE_TEXTBOX;
1090 		break;
1091 	case PARSE_TEXTBOX_TEXT:
1092 		state->textbox_text = g_strdup (state->content->str);
1093 		state->state = PARSE_TEXTBOX;
1094 		break;
1095 	case PARSE_SCHEMATIC:
1096 		// The end of the file.
1097 		state->state = PARSE_FINISH;
1098 		break;
1099 	case PARSE_ERROR:
1100 		break;
1101 	case PARSE_START:
1102 	case PARSE_FINISH:
1103 		// There should not be a closing tag in this state.
1104 		g_assert_not_reached ();
1105 		break;
1106 	}
1107 }
1108 
my_characters(ParseState * state,const xmlChar * chars,int len)1109 static void my_characters (ParseState *state, const xmlChar *chars, int len)
1110 {
1111 	int i;
1112 
1113 	if (state->state == PARSE_FINISH || state->state == PARSE_START ||
1114 	    state->state == PARSE_PARTS || state->state == PARSE_PART)
1115 		return;
1116 
1117 	for (i = 0; i < len; i++)
1118 		g_string_append_c (state->content, chars[i]);
1119 }
1120 
get_entity(void * user_data,const xmlChar * name)1121 static xmlEntityPtr get_entity (void *user_data, const xmlChar *name)
1122 {
1123 	return xmlGetPredefinedEntity (name);
1124 }
1125 
my_warning(void * user_data,const char * msg,...)1126 static void my_warning (void *user_data, const char *msg, ...)
1127 {
1128 	va_list args;
1129 
1130 	va_start (args, msg);
1131 	g_logv ("XML", G_LOG_LEVEL_WARNING, msg, args);
1132 	va_end (args);
1133 }
1134 
1135 // FIXME this should not be critical but forward to the oregano log buffer
my_error(void * user_data,const char * msg,...)1136 static void my_error (void *user_data, const char *msg, ...)
1137 {
1138 	va_list args;
1139 
1140 	va_start (args, msg);
1141 	g_logv ("XML", G_LOG_LEVEL_CRITICAL, msg, args);
1142 	va_end (args);
1143 }
1144 
my_fatal_error(void * user_data,const char * msg,...)1145 static void my_fatal_error (void *user_data, const char *msg, ...)
1146 {
1147 	va_list args;
1148 
1149 	va_start (args, msg);
1150 	g_logv ("XML", G_LOG_LEVEL_ERROR, msg, args);
1151 	va_end (args);
1152 }
1153