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