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