Add bzrignore file
[jelmer/ptabtools.git] / ptb2xml.c
1 /*
2         (c) 2004-2005: Jelmer Vernooij <jelmer@samba.org>
3
4         This program is free software; you can redistribute it and/or modify
5         it under the terms of the GNU General Public License as published by
6         the Free Software Foundation; either version 2 of the License, or
7         (at your option) any later version.
8
9         This program is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12         GNU General Public License for more details.
13
14         You should have received a copy of the GNU General Public License
15         along with this program; if not, write to the Free Software
16         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <stdio.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <popt.h>
23 #include <time.h>
24 #include <libxml/xmlmemory.h>
25 #include <libxml/parser.h>
26
27 #define DTD_URL "http://jelmer.vernstok.nl/oss/ptabtools/svn/trunk/ptbxml.dtd"
28
29 #ifdef HAVE_CONFIG_H
30 #  include "config.h"
31 #endif
32
33 #ifdef HAVE_STDINT_H
34 #  include <stdint.h>
35 #endif
36
37 #include "ptb.h"
38
39 #ifdef HAVE_XSLT
40 #  include <libxslt/xslt.h>
41 #  include <libxslt/transform.h>
42 #endif
43
44 #define SMART_ADD_PROP_INT(parent, name, contents) { \
45         char tmpc[100]; \
46         snprintf(tmpc, 100, "%d", contents); \
47         xmlSetProp(parent, name, tmpc); \
48 }
49
50
51 #define SMART_ADD_CHILD_STRING(parent, name, contents) xmlNewTextChild(parent, NULL, name, contents)
52 #define SMART_ADD_CHILD_INT(parent, name, contents) { \
53         char tmpc[100]; \
54         xmlNodePtr tmp = xmlNewNode(NULL, name); \
55         snprintf(tmpc, 100, "%d", contents); \
56         xmlNodeSetContent(tmp, tmpc); \
57         xmlAddChild(parent, tmp); \
58 }
59
60 #define SMART_ADD_CHILD_XINT(parent, name, contents) { \
61         char tmpc[100]; \
62         xmlNodePtr tmp = xmlNewNode(NULL, name); \
63         snprintf(tmpc, 100, "%x", contents); \
64         xmlNodeSetContent(tmp, tmpc); \
65         xmlAddChild(parent, tmp); \
66 }
67
68 xmlNodePtr xml_write_font(const char *name, struct ptb_font *font)
69 {
70         xmlNodePtr xfont = xmlNewNode(NULL, "font");
71         xmlSetProp(xfont, "function", name);
72         SMART_ADD_PROP_INT(xfont, "size", font->size);
73         SMART_ADD_PROP_INT(xfont, "thickness", font->thickness);
74         SMART_ADD_PROP_INT(xfont, "underlined", font->underlined);
75         SMART_ADD_PROP_INT(xfont, "italic", font->italic);
76         xmlSetProp(xfont, "family", font->family);
77         return xfont;
78 }
79
80 xmlNodePtr xml_write_directions(struct ptb_direction *directions)
81 {
82         xmlNodePtr xdirections = xmlNewNode(NULL, "directions");
83         struct ptb_direction *direction = directions;
84
85         while(direction) {
86                 xmlNodePtr xdirection = xmlNewNode(NULL, "direction");
87                 xmlAddChild(xdirections, xdirection);
88
89                 direction = direction->next;
90         }
91         return xdirections;
92 }
93
94 xmlNodePtr xml_write_rhythmslashes(struct ptb_rhythmslash *rhythmslashs)
95 {
96         xmlNodePtr xrhythmslashs = xmlNewNode(NULL, "rhythmslashs");
97         struct ptb_rhythmslash *rhythmslash = rhythmslashs;
98
99         while(rhythmslash) {
100                 xmlNodePtr xrhythmslash = xmlNewNode(NULL, "rhythmslash");
101                 xmlAddChild(xrhythmslashs, xrhythmslash);
102                 SMART_ADD_CHILD_INT(xrhythmslash, "properties", rhythmslash->properties);
103                 SMART_ADD_PROP_INT(xrhythmslash, "offset", rhythmslash->offset);
104                 SMART_ADD_CHILD_INT(xrhythmslash, "dotted", rhythmslash->dotted);
105                 SMART_ADD_CHILD_INT(xrhythmslash, "length", rhythmslash->length);
106                 
107                 rhythmslash = rhythmslash->next;
108         }
109         
110         return xrhythmslashs;
111 }
112
113 xmlNodePtr xml_write_chordtexts(struct ptb_chordtext *chordtexts)
114 {
115         xmlNodePtr xchordtexts = xmlNewNode(NULL, "chordtexts");
116         struct ptb_chordtext *chordtext = chordtexts;
117
118         while(chordtext) {
119                 xmlNodePtr xchordtext = xmlNewNode(NULL, "chordtext");
120                 xmlAddChild(xchordtexts, xchordtext);
121
122                 SMART_ADD_CHILD_STRING(xchordtext, "note1", ptb_get_tone(chordtext->name[0]));
123                 SMART_ADD_CHILD_STRING(xchordtext, "note2", ptb_get_tone(chordtext->name[1]));
124                 SMART_ADD_PROP_INT(xchordtext, "offset", chordtext->offset);
125                 SMART_ADD_CHILD_INT(xchordtext, "additions", chordtext->additions);
126                 SMART_ADD_CHILD_INT(xchordtext, "alterations", chordtext->alterations);
127                 SMART_ADD_CHILD_INT(xchordtext, "properties", chordtext->properties);
128                 SMART_ADD_CHILD_INT(xchordtext, "VII", chordtext->VII);
129
130                 chordtext = chordtext->next;
131         }
132         return xchordtexts;
133 }
134
135 xmlNodePtr xml_write_musicbars(struct ptb_musicbar *musicbars)
136 {
137         xmlNodePtr xmusicbars = xmlNewNode(NULL, "musicbars");
138         struct ptb_musicbar *musicbar = musicbars;
139
140         while(musicbar) {
141                 xmlNodePtr xmusicbar = SMART_ADD_CHILD_STRING(xmusicbars, "musicbar", musicbar->description);
142
143                 if(musicbar->letter != 0x7f) {
144                         char tmp[100];
145                         snprintf(tmp, 100, "%c", musicbar->letter);
146                         xmlSetProp(xmusicbar, "letter", tmp);
147                 }
148
149                 musicbar = musicbar->next;
150         }
151         return xmusicbars;
152 }
153
154 xmlNodePtr xml_write_linedatas(struct ptb_linedata *linedatas)
155 {
156         xmlNodePtr xlinedatas = xmlNewNode(NULL, "linedatas");
157         struct ptb_linedata *linedata = linedatas;
158
159         while(linedata) {
160                 xmlNodePtr xlinedata = xmlNewNode(NULL, "linedata");
161                 xmlAddChild(xlinedatas, xlinedata);
162
163                 SMART_ADD_CHILD_INT(xlinedata, "string", linedata->detailed.string);
164                 SMART_ADD_CHILD_INT(xlinedata, "fret", linedata->detailed.fret);
165                 SMART_ADD_CHILD_INT(xlinedata, "properties", linedata->properties);
166                 SMART_ADD_CHILD_INT(xlinedata, "transcribe", linedata->transcribe);
167                 SMART_ADD_CHILD_INT(xlinedata, "conn_to_next", linedata->conn_to_next);
168
169                 linedata = linedata->next;
170         }
171         return xlinedatas;
172 }
173
174 xmlNodePtr xml_write_positions(struct ptb_position *positions)
175 {
176         xmlNodePtr xpositions = xmlNewNode(NULL, "positions");
177         struct ptb_position *position = positions;
178
179         while(position) {
180                 xmlNodePtr xposition = xmlNewNode(NULL, "position");
181                 xmlAddChild(xpositions, xposition);
182
183                 SMART_ADD_PROP_INT(xposition, "offset", position->offset);
184                 SMART_ADD_CHILD_INT(xposition, "dots", position->dots);
185                 SMART_ADD_CHILD_INT(xposition, "length", position->length);
186                 SMART_ADD_CHILD_INT(xposition, "properties", position->properties);
187                 SMART_ADD_CHILD_INT(xposition, "fermenta", position->fermenta);
188
189                 xmlAddChild(xposition, xml_write_linedatas(position->linedatas));
190
191                 position = position->next;
192         }
193         return xpositions;
194 }
195
196 xmlNodePtr xml_write_staffs(struct ptb_staff *staffs)
197 {
198         xmlNodePtr xstaffs = xmlNewNode(NULL, "staffs");
199         struct ptb_staff *staff = staffs;
200
201         while(staff) {
202                 int i;
203                 xmlNodePtr xstaff = xmlNewNode(NULL, "staff");
204                 xmlAddChild(xstaffs, xstaff);
205
206                 SMART_ADD_CHILD_INT(xstaff, "highest_note", staff->highest_note);
207                 SMART_ADD_CHILD_INT(xstaff, "lowest_note", staff->lowest_note);
208                 SMART_ADD_CHILD_INT(xstaff, "properties", staff->properties);
209
210                 for(i = 0; i < 2; i++) 
211                         xmlAddChild(xstaff, xml_write_positions(staff->positions[i]));
212                 
213                 staff = staff->next;
214         }
215         return xstaffs;
216 }
217
218 xmlNodePtr xml_write_sections(struct ptb_section *sections) 
219 {
220         xmlNodePtr sctns = xmlNewNode(NULL, "sections");
221         struct ptb_section *section = sections;
222
223         while(section) {
224                 xmlNodePtr meter_type;
225                 xmlNodePtr xsection = xmlNewNode(NULL, "section");
226
227                 xmlAddChild(sctns, xsection);
228
229                 if(section->letter != 0x7f) {
230                 char tmp[100];
231                 snprintf(tmp, 100, "%c", section->letter);
232                 xmlSetProp(xsection, "letter", tmp);
233                 }
234
235                 switch(section->end_mark) {
236                 case END_MARK_TYPE_NORMAL:
237                         SMART_ADD_CHILD_STRING(xsection, "end-mark", "normal");
238                         break;
239                 case END_MARK_TYPE_REPEAT:
240                         SMART_ADD_CHILD_STRING(xsection, "end-mark", "repeat");
241                         break;
242                 }
243
244                 meter_type = xmlNewNode(NULL, "meter-type");
245                 xmlAddChild(xsection, meter_type);
246
247                 if(section->meter_type & METER_TYPE_BEAM_2) SMART_ADD_CHILD_STRING(meter_type, "beam_2", "");
248                 if(section->meter_type & METER_TYPE_BEAM_3) SMART_ADD_CHILD_STRING(meter_type, "beam_3", "");
249                 if(section->meter_type & METER_TYPE_BEAM_4) SMART_ADD_CHILD_STRING(meter_type, "beam_4", "");
250                 if(section->meter_type & METER_TYPE_BEAM_5) SMART_ADD_CHILD_STRING(meter_type, "beam_5", "");
251                 if(section->meter_type & METER_TYPE_BEAM_6) SMART_ADD_CHILD_STRING(meter_type, "beam_6", "");
252                 if(section->meter_type & METER_TYPE_COMMON) SMART_ADD_CHILD_STRING(meter_type, "common", "");
253                 if(section->meter_type & METER_TYPE_CUT) SMART_ADD_CHILD_STRING(meter_type, "cut", "");
254                 if(section->meter_type & METER_TYPE_SHOW) SMART_ADD_CHILD_STRING(meter_type, "show", "");
255
256                 SMART_ADD_CHILD_INT(xsection, "beat", section->detailed.beat);
257                 SMART_ADD_CHILD_INT(xsection, "beat-value", section->detailed.beat_value);
258                 SMART_ADD_CHILD_INT(xsection, "metronome-pulses-per-measure", section->metronome_pulses_per_measure);
259                 SMART_ADD_CHILD_INT(xsection, "properties", section->properties);
260                 SMART_ADD_CHILD_INT(xsection, "key-extra", section->key_extra);
261                 SMART_ADD_CHILD_INT(xsection, "position-width", section->position_width);
262                 SMART_ADD_CHILD_STRING(xsection, "description", section->description);
263
264                 xmlAddChild(xsection, xml_write_chordtexts(section->chordtexts));
265                 xmlAddChild(xsection, xml_write_rhythmslashes(section->rhythmslashes));
266                 xmlAddChild(xsection, xml_write_directions(section->directions));
267                 xmlAddChild(xsection, xml_write_staffs(section->staffs));
268
269                 xmlAddChild(xsection, xml_write_musicbars(section->musicbars));
270
271                 section = section->next;
272         }
273
274         return sctns;
275 }
276
277 xmlNodePtr xml_write_guitars(struct ptb_guitar *guitars, int instr) 
278 {
279         xmlNodePtr gtrs = xmlNewNode(NULL, "guitars");
280         struct ptb_guitar *gtr = guitars;
281
282         while(gtr) {
283                 char tmp[100];
284                 int i;
285                 xmlNodePtr xgtr = xmlNewNode(NULL, "guitar");
286                 xmlNodePtr strings;
287                 xmlAddChild(gtrs, xgtr);
288
289                 snprintf(tmp, 100, "gtr-%d-%d", instr, gtr->index);
290                 xmlSetProp(xgtr, "id", tmp);
291
292                 strings = xmlNewNode(NULL, "tuning");
293                 xmlAddChild(xgtr, strings);
294
295                 for(i = 0; i < gtr->nr_strings; i++) {
296                         const char *notenames[] = { "c", "cis", "d", "dis", "e", "f", "fis", "g", "gis", "a", "ais", "b" };
297                         xmlNodePtr string = xmlNewNode(NULL, "stringtuning");
298                         SMART_ADD_PROP_INT(string, "octave", gtr->strings[i]/12);
299                         xmlSetProp(string, "note", notenames[gtr->strings[i]%12]);
300                         xmlAddChild(strings, string);
301                 }
302
303                 SMART_ADD_CHILD_STRING(xgtr, "title", gtr->title);
304                 SMART_ADD_CHILD_STRING(xgtr, "type", gtr->type);
305                 SMART_ADD_CHILD_INT(xgtr, "reverb", gtr->reverb);
306                 SMART_ADD_CHILD_INT(xgtr, "chorus", gtr->chorus);
307                 SMART_ADD_CHILD_INT(xgtr, "tremolo", gtr->tremolo);
308                 SMART_ADD_CHILD_INT(xgtr, "pan", gtr->pan);
309                 SMART_ADD_CHILD_INT(xgtr, "capo", gtr->capo);
310                 SMART_ADD_CHILD_INT(xgtr, "initial_volume", gtr->initial_volume);
311                 SMART_ADD_CHILD_INT(xgtr, "midi_instrument", gtr->midi_instrument);
312                 SMART_ADD_CHILD_INT(xgtr, "half_up", gtr->half_up);
313                 SMART_ADD_CHILD_INT(xgtr, "simulate", gtr->simulate);
314
315                 gtr = gtr->next;
316         }
317         
318         return gtrs;
319 }
320
321 xmlNodePtr xml_write_guitarins(struct ptb_guitarin *guitarins)
322 {
323         struct ptb_guitarin *guitarin = guitarins;
324         xmlNodePtr xguitarins = xmlNewNode(NULL, "guitarins");
325         
326         while(guitarin) {
327                 xmlNodePtr xguitarin = xmlNewNode(NULL, "guitarin");
328                 xmlAddChild(xguitarins, xguitarin);
329
330                 SMART_ADD_PROP_INT(xguitarin, "offset", guitarin->offset);
331                 SMART_ADD_PROP_INT(xguitarin, "section", guitarin->section);
332                 SMART_ADD_PROP_INT(xguitarin, "staff", guitarin->staff);
333                 SMART_ADD_CHILD_INT(xguitarin, "rhythm_slash", guitarin->rhythm_slash);
334                 SMART_ADD_CHILD_INT(xguitarin, "staff_in", guitarin->staff_in);
335
336                 guitarin = guitarin->next;
337         }
338
339         return xguitarins;
340 }
341
342 xmlNodePtr xml_write_tempomarkers(struct ptb_tempomarker *tempomarkers)
343 {
344         struct ptb_tempomarker *tempomarker = tempomarkers;
345         xmlNodePtr xtempomarkers = xmlNewNode(NULL, "tempomarkers");
346         
347         while(tempomarker) {
348                 xmlNodePtr xtempomarker = SMART_ADD_CHILD_STRING(xtempomarkers, "tempomarker", tempomarker->description);
349                 
350                 SMART_ADD_CHILD_INT(xtempomarker, "type", tempomarker->type);
351                 SMART_ADD_PROP_INT(xtempomarker, "section", tempomarker->section);
352                 SMART_ADD_PROP_INT(xtempomarker, "offset", tempomarker->offset);
353                 SMART_ADD_CHILD_INT(xtempomarker, "bpm", tempomarker->bpm);
354
355                 tempomarker = tempomarker->next;
356         }
357
358         return xtempomarkers;
359 }
360
361 xmlNodePtr xml_write_dynamics(struct ptb_dynamic *dynamics)
362 {
363         struct ptb_dynamic *dynamic = dynamics;
364         xmlNodePtr xdynamics = xmlNewNode(NULL, "dynamics");
365         
366         while(dynamic) {
367                 xmlNodePtr xdynamic = xmlNewNode(NULL, "dynamic");
368                 xmlAddChild(xdynamics, xdynamic);
369                 
370                 SMART_ADD_PROP_INT(xdynamic, "offset", dynamic->offset);
371
372                 dynamic = dynamic->next;
373         }
374
375         return xdynamics;
376 }
377
378 xmlNodePtr xml_write_chorddiagrams(struct ptb_chorddiagram *chorddiagrams)
379 {
380         struct ptb_chorddiagram *chorddiagram = chorddiagrams;
381         xmlNodePtr xchorddiagrams = xmlNewNode(NULL, "chorddiagrams");
382         
383         while(chorddiagram) {
384                 int i;
385                 xmlNodePtr xchorddiagram = xmlNewNode(NULL, "chorddiagram");
386                 xmlNodePtr strings = xmlNewNode(NULL, "strings");
387                 xmlAddChild(xchorddiagrams, xchorddiagram);
388                 xmlAddChild(xchorddiagram, strings);
389                 
390                 SMART_ADD_CHILD_STRING(xchorddiagram, "note1", ptb_get_tone(chorddiagram->name[0]));
391                 SMART_ADD_CHILD_STRING(xchorddiagram, "note2", ptb_get_tone(chorddiagram->name[1]));
392                 SMART_ADD_CHILD_INT(xchorddiagram, "frets", chorddiagram->frets);
393                 SMART_ADD_CHILD_INT(xchorddiagram, "type", chorddiagram->type);
394
395                 for(i = 0; i < chorddiagram->nr_strings; i++) {
396                         SMART_ADD_CHILD_INT(strings, "string", chorddiagram->tones[i]);
397                 }
398                 
399                 chorddiagram = chorddiagram->next;
400         }
401
402         return xchorddiagrams;
403 }
404
405 xmlNodePtr xml_write_sectionsymbols(struct ptb_sectionsymbol *sectionsymbols)
406 {
407         struct ptb_sectionsymbol *sectionsymbol = sectionsymbols;
408         xmlNodePtr xsectionsymbols = xmlNewNode(NULL, "sectionsymbols");
409         
410         while(sectionsymbol) {
411                 xmlNodePtr xsectionsymbol = xmlNewNode(NULL, "sectionsymbol");
412                 xmlAddChild(xsectionsymbols, xsectionsymbol);
413                 
414                 SMART_ADD_CHILD_INT(xsectionsymbol, "repeat-ending", sectionsymbol->repeat_ending);
415
416                 sectionsymbol = sectionsymbol->next;
417         }
418
419         return xsectionsymbols;
420 }
421
422 xmlNodePtr xml_write_floatingtexts(struct ptb_floatingtext *floatingtexts)
423 {
424         struct ptb_floatingtext *floatingtext = floatingtexts;
425         xmlNodePtr xfloatingtexts = xmlNewNode(NULL, "floatingtexts");
426         
427         while(floatingtext) {
428                 xmlNodePtr xfloatingtext = SMART_ADD_CHILD_STRING(xfloatingtexts, "floatingtext", floatingtext->text);
429                 
430                 SMART_ADD_PROP_INT(xfloatingtext, "offset", floatingtext->offset);
431
432                 switch(floatingtext->alignment) {
433                 case ALIGN_LEFT:
434                         SMART_ADD_CHILD_STRING(xfloatingtext, "alignment", "left");
435                         break;
436                 case ALIGN_RIGHT:
437                         SMART_ADD_CHILD_STRING(xfloatingtext, "alignment", "right");
438                         break;
439                 case ALIGN_CENTER:
440                         SMART_ADD_CHILD_STRING(xfloatingtext, "alignment", "center");
441                         break;
442                 }
443
444                 xmlAddChild(xfloatingtext, xml_write_font("font", &floatingtext->font));
445
446                 floatingtext = floatingtext->next;
447         }
448
449         return xfloatingtexts;
450 }
451
452 xmlNodePtr xml_write_instrument(struct ptbf *bf, int i)
453 {
454         char tmp[100];
455         xmlNodePtr instrument = xmlNewNode(NULL, "instrument");
456         snprintf(tmp, 100, "instr-%d", i);
457         xmlSetProp(instrument, "id", tmp);
458
459         xmlAddChild(instrument, xml_write_guitars(bf->instrument[i].guitars, i));
460         xmlAddChild(instrument, xml_write_sections(bf->instrument[i].sections));
461         xmlAddChild(instrument, xml_write_guitarins(bf->instrument[i].guitarins));
462         xmlAddChild(instrument, xml_write_chorddiagrams(bf->instrument[i].chorddiagrams));
463         xmlAddChild(instrument, xml_write_tempomarkers(bf->instrument[i].tempomarkers));
464         xmlAddChild(instrument, xml_write_dynamics(bf->instrument[i].dynamics));
465         xmlAddChild(instrument, xml_write_floatingtexts(bf->instrument[i].floatingtexts));
466         xmlAddChild(instrument, xml_write_sectionsymbols(bf->instrument[i].sectionsymbols));
467         return instrument;
468 }
469
470 xmlNodePtr xml_write_song_header(struct ptb_hdr *hdr)
471 {
472         xmlNodePtr song = xmlNewNode(NULL, "song");
473
474         SMART_ADD_CHILD_STRING(song, "title", hdr->class_info.song.title); 
475         SMART_ADD_CHILD_STRING(song, "artist", hdr->class_info.song.artist); 
476         SMART_ADD_CHILD_STRING(song, "words-by", hdr->class_info.song.words_by); 
477         SMART_ADD_CHILD_STRING(song, "music-by", hdr->class_info.song.music_by); 
478         SMART_ADD_CHILD_STRING(song, "arranged-by", hdr->class_info.song.arranged_by); 
479         SMART_ADD_CHILD_STRING(song, "guitar-transcribed-by", hdr->class_info.song.guitar_transcribed_by); 
480         SMART_ADD_CHILD_STRING(song, "bass-transcribed-by", hdr->class_info.song.bass_transcribed_by); 
481         SMART_ADD_CHILD_STRING(song, "lyrics", hdr->class_info.song.lyrics);
482         SMART_ADD_CHILD_STRING(song, "copyright", hdr->class_info.song.copyright);
483
484         /* FIXME: Sub stuff */
485
486         return song;
487 }
488
489 xmlNodePtr xml_write_lesson_header(struct ptb_hdr *hdr)
490 {
491         xmlNodePtr lesson = xmlNewNode(NULL, "lesson");
492
493         SMART_ADD_CHILD_STRING(lesson, "title", hdr->class_info.lesson.title); 
494         SMART_ADD_CHILD_STRING(lesson, "artist", hdr->class_info.lesson.artist); 
495         SMART_ADD_CHILD_STRING(lesson, "author", hdr->class_info.lesson.author);
496         SMART_ADD_CHILD_STRING(lesson, "copyright", hdr->class_info.lesson.copyright);
497
498         switch(hdr->class_info.lesson.level) {
499         case LEVEL_BEGINNER: xmlSetProp(lesson, "level", "beginner"); break;
500         case LEVEL_INTERMEDIATE: xmlSetProp(lesson, "level", "intermediate"); break;
501         case LEVEL_ADVANCED: xmlSetProp(lesson, "level", "advanced"); break;
502         }
503
504         /* FIXME: Style */
505
506         return lesson;
507 }
508
509 xmlNodePtr xml_write_header(struct ptb_hdr *hdr) 
510 {
511         xmlNodePtr header = xmlNewNode(NULL, "header");
512         switch(hdr->classification) {
513         case CLASSIFICATION_SONG:
514                 xmlSetProp(header, "classification", "song");
515                 xmlAddChild(header, xml_write_song_header(hdr));
516                 break;
517         case CLASSIFICATION_LESSON:
518                 xmlSetProp(header, "classification", "lesson");
519                 xmlAddChild(header, xml_write_lesson_header(hdr));
520                 break;
521         }
522         return header;
523 }
524
525 int main(int argc, const char **argv) 
526 {
527         struct ptbf *ret;
528         int debugging = 0;
529         xmlNodePtr root_node;
530         xmlDocPtr doc;
531         xmlNodePtr comment;
532         xmlNodePtr fonts;
533         xmlDtdPtr dtd;
534         int c, i, musicxml = 0;
535         int version = 0;
536         const char *input = NULL;
537         char *output = NULL;
538         poptContext pc;
539         int quiet = 0;
540         int format_output = 1;
541         struct poptOption options[] = {
542                 POPT_AUTOHELP
543                 {"debug", 'd', POPT_ARG_NONE, &debugging, 0, "Turn on debugging output" },
544                 {"outputfile", 'o', POPT_ARG_STRING, &output, 0, "Write to specified file", "FILE" },
545                 {"musicxml", 'm', POPT_ARG_NONE, &musicxml, 'm', "Output MusicXML" },
546                 {"no-format", 'f', POPT_ARG_NONE, &format_output, 0, "Don't format output" },
547                 {"quiet", 'q', POPT_ARG_NONE, &quiet, 1, "Be quiet (no output to stderr)" },
548                 {"version", 'v', POPT_ARG_NONE, &version, 'v', "Show version information" },
549                 POPT_TABLEEND
550         };
551
552         pc = poptGetContext(argv[0], argc, argv, options, 0);
553         poptSetOtherOptionHelp(pc, "file.ptb");
554         while((c = poptGetNextOpt(pc)) >= 0) {
555                 switch(c) {
556                 case 'v':
557                         printf("ptb2xml Version "PACKAGE_VERSION"\n");
558                         printf("(C) 2004-2005 Jelmer Vernooij <jelmer@samba.org>\n");
559                         exit(0);
560                         break;
561                 }
562         }
563                         
564         ptb_set_debug(debugging);
565         
566         if(!poptPeekArg(pc)) {
567                 poptPrintUsage(pc, stderr, 0);
568                 return -1;
569         }
570         
571         input = poptGetArg(pc);
572         if (!quiet) fprintf(stderr, "Parsing %s...\n", input);
573         ret = ptb_read_file(input);
574         
575         if(!ret) {
576                 perror("Read error: ");
577                 return -1;
578         } 
579
580         if(!output) {
581                 int baselength = strlen(input);
582                 if (!strcmp(input + strlen(input) - 4, ".ptb")) {
583                         baselength -= 4;
584                 }
585                 output = malloc(baselength + 6);
586                 strncpy(output, input, baselength);
587                 strcpy(output + baselength, ".xml");
588         }
589
590         if (!quiet) fprintf(stderr, "Building DOM tree...\n");
591
592         doc = xmlNewDoc(BAD_CAST "1.0");
593         root_node = xmlNewNode(NULL, BAD_CAST "powertab");
594         dtd = xmlCreateIntSubset(doc, "powertab", NULL, DTD_URL);
595         xmlDocSetRootElement(doc, root_node);
596
597         comment = xmlNewComment("\nGenerated by ptb2xml, part of ptabtools. \n"
598                                                         "(C) 2004-2005 by Jelmer Vernooij <jelmer@samba.org>\n"
599                                                         "See http://jelmer.vernstok.nl/oss/ptabtools/ for details\n");
600         xmlAddChild(root_node, comment);
601
602         xmlAddChild(root_node, xml_write_header(&ret->hdr));
603
604         for(i = 0; i < 2; i++) {
605                 xmlAddChild(root_node, xml_write_instrument(ret, i));
606         }
607
608         fonts = xmlNewNode( NULL, "fonts"); xmlAddChild(root_node, fonts);
609
610         xmlAddChild(fonts, xml_write_font("default_font", &ret->default_font));
611         xmlAddChild(fonts, xml_write_font("chord_name_font", &ret->chord_name_font));
612         xmlAddChild(fonts, xml_write_font("tablature_font", &ret->tablature_font));
613
614         if (musicxml)
615         {
616                 if (!quiet) fprintf(stderr, "Converting to MusicXML...\n");
617 #ifdef HAVE_XSLT
618                 xsltStylesheetPtr stylesheet = xsltParseStylesheetFile(MUSICXMLSTYLESHEET);
619                 doc = xsltApplyStylesheet(stylesheet, doc, NULL);
620                 xsltFreeStylesheet(stylesheet);
621 #else
622                 fprintf(stderr, "Conversion to MusicXML not possible in this version: libxslt not compiled in\n");
623                 return -1;
624 #endif
625         }
626
627         if (!quiet) fprintf(stderr, "Writing output to %s...\n", output);
628
629         if (xmlSaveFormatFile(output, doc, format_output) < 0) {
630                 return -1;
631         }
632
633         xmlFreeDoc(doc);
634
635         xmlCleanupParser();
636
637         return 0;
638 }