]> git.donarmstrong.com Git - lilypond.git/blob - scripts/convert-ly.py
patch::: 1.3.136.jcn2
[lilypond.git] / scripts / convert-ly.py
1 #!@PYTHON@
2
3 # convert-lilypond.py -- convertor for lilypond versions
4
5 # source file of the GNU LilyPond music typesetter
6
7 # (c) 1998 
8
9 # TODO
10 #   use -f and -t for -s output
11
12 # NEWS
13 # 0.2
14 #  - rewrite in python
15
16 program_name = 'convert-ly'
17 version = '@TOPLEVEL_VERSION@'
18
19 import os
20 import sys
21 import __main__
22 import getopt
23 import  string
24 import re
25 import time
26
27 # Did we ever have \mudela-version?  I doubt it.
28 # lilypond_version_re_str = '\\\\version *\"(.*)\"'
29 lilypond_version_re_str = '\\\\(mudela-)?version *\"(.*)\"'
30 lilypond_version_re = re.compile (lilypond_version_re_str)
31
32 def program_id ():
33         return '%s (GNU LilyPond) %s' %(program_name,  version);
34
35 def identify ():
36         sys.stderr.write (program_id () + '\n')
37
38 def usage ():
39         sys.stdout.write (
40                 r"""Usage: %s [OPTION]... [FILE]... 
41 Try to convert to newer lilypond-versions.  The version number of the
42 input is guessed by default from \version directive
43
44 Options:
45   -h, --help             print this help
46   -e, --edit             in place edit
47   -f, --from=VERSION     start from version
48   -s, --show-rules       print all rules.
49   -t, --to=VERSION       target version
50       --version          print program version
51
52 Report bugs to bugs-gnu-music@gnu.org
53
54 """ % program_name)
55         
56         
57         sys.exit (0)
58
59 def print_version ():
60         
61         sys.stdout.write (r"""%s
62
63 This is free software.  It is covered by the GNU General Public
64 License, and you are welcome to change it and/or distribute copies of
65 it under certain conditions.  invoke as `%s --warranty' for more
66 information.
67
68 """ % (program_id() , program_name))
69         
70 def gulp_file(f):
71         try:
72                 i = open(f)
73                 i.seek (0, 2)
74                 n = i.tell ()
75                 i.seek (0,0)
76         except:
77                 print 'can\'t open file: ' + f + '\n'
78                 return ''
79         s = i.read (n)
80         if len (s) <= 0:
81                 print 'gulped empty file: ' + f + '\n'
82         i.close ()
83         return s
84
85 def str_to_tuple (s):
86         return tuple (map (string.atoi, string.split (s,'.')))
87
88 def tup_to_str (t):
89         return string.join (map (lambda x: '%s' % x, list (t)), '.')
90
91 def version_cmp (t1, t2):
92         for x in [0,1,2]:
93                 if t1[x] - t2[x]:
94                         return t1[x] - t2[x]
95         return 0
96
97 def guess_lilypond_version (filename):
98         s = gulp_file (filename)
99         m = lilypond_version_re.search (s)
100         if m:
101                 return m.group (2)
102         else:
103                 return ''
104
105 class FatalConversionError:
106         pass
107
108 conversions = []
109
110 def show_rules (file):
111         for x in conversions:
112                 file.write  ('%s: %s\n' % (tup_to_str (x[0]), x[2]))
113
114 ############################
115                 
116 if 1:                                   # need new a namespace
117         def conv (str):
118                 if re.search ('\\\\octave', str):
119                         sys.stderr.write ('\nNot smart enough to convert \\octave')
120                         raise FatalConversionError()
121                 
122                 return str
123
124         conversions.append ((
125                 ((0,1,19), conv, 'deprecated \\octave; can\'t convert automatically')))
126
127
128 if 1:                                   # need new a namespace
129         def conv (str):
130                 str = re.sub ('\\\\textstyle([^;]+);',
131                                          '\\\\property Lyrics . textstyle = \\1', str)
132                 str = re.sub ('\\\\key([^;]+);', '\\\\accidentals \\1;', str)
133                         
134                 return str
135
136         conversions.append ((
137                 ((0,1,20), conv, 'deprecated \\textstyle, new \key syntax')))
138
139
140 if 1:
141         def conv (str):
142                 str = re.sub ('\\\\musical_pitch', '\\\\musicalpitch',str)
143                 str = re.sub ('\\\\meter', '\\\\time',str)
144                         
145                 return str
146
147         conversions.append ((
148                 ((0,1,21), conv, '\\musical_pitch -> \\musicalpitch, '+
149                  '\\meter -> \\time')))
150
151 if 1:
152         def conv (str):
153                 return str
154
155         conversions.append ((
156                 ((1,0,0), conv, '0.1.21 -> 1.0.0 ')))
157
158
159 if 1:
160         def conv (str):
161                 str = re.sub ('\\\\accidentals', '\\\\keysignature',str)
162                 str = re.sub ('specialaccidentals *= *1', 'keyoctaviation = 0',str)
163                 str = re.sub ('specialaccidentals *= *0', 'keyoctaviation = 1',str)
164                         
165                 return str
166
167         conversions.append ((
168                 ((1,0,1), conv, '\\accidentals -> \\keysignature, ' +
169                  'specialaccidentals -> keyoctaviation')))
170
171 if 1:
172         def conv(str):
173                 if re.search ('\\\\header', str):
174                         sys.stderr.write ('\nNot smart enough to convert to new \\header format')
175                 return str
176         
177         conversions.append (((1,0,2), conv, '\\header { key = concat + with + operator }'))
178
179 if 1:
180         def conv(str):
181                 str =  re.sub ('\\\\melodic', '\\\\notes',str)
182                 if re.search ('\\\\header', str):
183                         sys.stderr.write ('\nNot smart enough to convert \\multi constructs')
184                         
185                 return str
186         
187         conversions.append (((1,0,3), conv, '\\melodic -> \\notes'))
188
189 if 1:
190         def conv(str):
191                 str =  re.sub ('default_paper *=', '',str)
192                 str =  re.sub ('default_midi *=', '',str)
193                 return str
194         
195         conversions.append (((1,0,4), conv, 'default_{paper,midi}'))
196
197 if 1:
198         def conv(str):
199                 str =  re.sub ('ChoireStaff', 'ChoirStaff',str)
200                 str =  re.sub ('\\output', 'output = ',str)
201                         
202                 return str
203         
204         conversions.append (((1,0,5), conv, 'ChoireStaff -> ChoirStaff'))
205
206 if 1:
207         def conv(str):
208                 if re.search ('[a-zA-Z]+ = *\\translator',str):
209                         sys.stderr.write ('\nNot smart enough to change \\translator syntax')
210                         raise FatalConversionError()
211                 return str
212         
213         conversions.append (((1,0,6), conv, 'foo = \\translator {\\type .. } ->\\translator {\\type ..; foo; }'))
214
215
216 if 1:
217         def conv(str):
218                 str =  re.sub ('\\\\lyric', '\\\\lyrics',str)
219                         
220                 return str
221         
222         conversions.append (((1,0,7), conv, '\\lyric -> \\lyrics'))
223
224 if 1:
225         def conv(str):
226                 str =  re.sub ('\\\\\\[/3+', '\\\\times 2/3 { ',str)
227                 str =  re.sub ('\\[/3+', '\\\\times 2/3 { [',str)
228                 str =  re.sub ('\\\\\\[([0-9/]+)', '\\\\times \\1 {',str)
229                 str =  re.sub ('\\[([0-9/]+)', '\\\\times \\1 { [',str)
230                 str =  re.sub ('\\\\\\]([0-9/]+)', '}', str)
231                 str =  re.sub ('\\\\\\]', '}',str)
232                 str =  re.sub ('\\]([0-9/]+)', '] }', str)
233                 return str
234         
235         conversions.append (((1,0,10), conv, '[2/3 ]1/1 -> \\times 2/3 '))
236
237 if 1:
238         def conv(str):
239                 return str
240         conversions.append (((1,0,12), conv, 'Chord syntax stuff'))
241
242
243 if 1:
244         def conv(str):
245                 
246                 
247                 str =  re.sub ('<([^>~]+)~([^>]*)>','<\\1 \\2> ~', str)
248                         
249                 return str
250         
251         conversions.append (((1,0,13), conv, '<a ~ b> c -> <a b> ~ c'))
252
253 if 1:
254         def conv(str):
255                 str =  re.sub ('<\\[','[<', str)
256                 str =  re.sub ('\\]>','>]', str)
257                         
258                 return str
259         
260         conversions.append (((1,0,14), conv, '<[a b> <a b]>c -> [<a b> <a b>]'))
261
262
263 if 1:
264         def conv(str):
265                 str =  re.sub ('\\\\type','\\\\context', str)
266                 str =  re.sub ('textstyle','textStyle', str)
267                         
268                 return str
269         
270         conversions.append (((1,0,16), conv, '\\type -> \\context, textstyle -> textStyle'))
271
272
273 if 1:
274         def conv(str):
275                 if re.search ('\\\\repeat',str):
276                         sys.stderr.write ('\nNot smart enough to convert \\repeat')
277                         raise FatalConversionError()
278                 return str
279         
280         conversions.append (((1,0,18), conv,
281                 '\\repeat NUM Music Alternative -> \\repeat FOLDSTR Music Alternative'))
282
283 if 1:
284         def conv(str):
285                 str =  re.sub ('SkipBars','skipBars', str)
286                 str =  re.sub ('fontsize','fontSize', str)
287                 str =  re.sub ('midi_instrument','midiInstrument', str)                 
288                         
289                 return str
290
291         conversions.append (((1,0,19), conv,
292                 'fontsize -> fontSize, midi_instrument -> midiInstrument, SkipBars -> skipBars'))
293
294
295 if 1:
296         def conv(str):
297                 str =  re.sub ('tieydirection','tieVerticalDirection', str)
298                 str =  re.sub ('slurydirection','slurVerticalDirection', str)
299                 str =  re.sub ('ydirection','verticalDirection', str)                   
300                         
301                 return str
302
303         conversions.append (((1,0,20), conv,
304                 '{,tie,slur}ydirection -> {v,tieV,slurV}erticalDirection'))
305
306
307 if 1:
308         def conv(str):
309                 str =  re.sub ('hshift','horizontalNoteShift', str)
310                         
311                 return str
312
313         conversions.append (((1,0,21), conv,
314                 'hshift -> horizontalNoteShift'))
315
316
317 if 1:
318         def conv(str):
319                 str =  re.sub ('\\\\grouping[^;]*;','', str)
320                         
321                 return str
322
323         conversions.append (((1,1,52), conv,
324                 'deprecate \\grouping'))
325
326
327 if 1:
328         def conv(str):
329                 str =  re.sub ('\\\\wheel','\\\\coda', str)
330                         
331                 return str
332
333         conversions.append (((1,1,55), conv,
334                 '\\wheel -> \\coda'))
335
336 if 1:
337         def conv(str):
338                 str =  re.sub ('keyoctaviation','keyOctaviation', str)
339                 str =  re.sub ('slurdash','slurDash', str)
340                         
341                 return str
342
343         conversions.append (((1,1,65), conv,
344                 'slurdash -> slurDash, keyoctaviation -> keyOctaviation'))
345
346 if 1:
347         def conv(str):
348                 str =  re.sub ('\\\\repeat *\"?semi\"?','\\\\repeat "volta"', str)
349                         
350                 return str
351
352         conversions.append (((1,1,66), conv,
353                 'semi -> volta'))
354
355
356 if 1:
357         def conv(str):
358                 str =  re.sub ('\"?beamAuto\"? *= *\"?0?\"?','noAutoBeaming = "1"', str)
359                         
360                 return str
361
362         conversions.append (((1,1,67), conv,
363                 'beamAuto -> noAutoBeaming'))
364
365 if 1:
366         def conv(str):
367                 str =  re.sub ('automaticMelismas', 'automaticMelismata', str)
368                         
369                 return str
370
371         conversions.append (((1,2,0), conv,
372                 'automaticMelismas -> automaticMelismata'))
373
374 if 1:
375         def conv(str):
376                 str =  re.sub ('dynamicDir\\b', 'dynamicDirection', str)
377                         
378                 return str
379
380         conversions.append (((1,2,1), conv,
381                 'dynamicDir -> dynamicDirection'))
382
383 if 1:
384         def conv(str):
385                 str =  re.sub ('\\\\cadenza *0 *;', '\\\\cadenzaOff', str)
386                 str =  re.sub ('\\\\cadenza *1 *;', '\\\\cadenzaOn', str)               
387                         
388                 return str
389
390         conversions.append (((1,3,4), conv,
391                 '\\cadenza -> \cadenza{On|Off}'))
392
393 if 1:
394         def conv (str):
395                 str = re.sub ('"?beamAuto([^"=]+)"? *= *"([0-9]+)/([0-9]+)" *;*',
396                               'beamAuto\\1 = #(make-moment \\2 \\3)',
397                               str)
398                 return str
399
400         conversions.append (((1,3,5), conv, 'beamAuto moment properties'))
401
402 if 1:
403         def conv (str):
404                 str = re.sub ('stemStyle',
405                               'flagStyle',
406                               str)
407                 return str
408
409         conversions.append (((1,3,17), conv, 'stemStyle -> flagStyle'))
410
411 if 1:
412         def conv (str):
413                 str = re.sub ('staffLineLeading',
414                               'staffSpace',
415                               str)
416                 return str
417
418         conversions.append (((1,3,18), conv, 'staffLineLeading -> staffSpace'))
419
420 if 1:
421         def conv (str):
422                 str = re.sub ('textEmptyDimension *= *##t',
423                               'textNonEmpty = ##f',
424                               str)
425                 str = re.sub ('textEmptyDimension *= *##f',
426                               'textNonEmpty = ##t',
427                               str)
428                 return str
429
430         conversions.append (((1,3,35), conv, 'textEmptyDimension -> textNonEmpty'))
431
432 if 1:
433         def conv (str):
434                 str = re.sub ("([a-z]+)[ \t]*=[ \t]*\\\\musicalpitch *{([- 0-9]+)} *\n",
435                               "(\\1 . (\\2))\n", str)
436                 str = re.sub ("\\\\musicalpitch *{([0-9 -]+)}",
437                               "\\\\musicalpitch #'(\\1)", str)
438                 if re.search ('\\\\notenames',str):
439                         sys.stderr.write ('\nNot smart enough to convert to new \\notenames format')
440                 return str
441
442         conversions.append (((1,3,38), conv, '\musicalpitch { a b c } -> #\'(a b c)'))
443
444 if 1:
445         def conv (str):
446                 def replace (match):
447                         return '\\key %s;' % string.lower (match.group (1))
448                 
449                 str = re.sub ("\\\\key ([^;]+);",  replace, str)
450                 return str
451         
452         conversions.append (((1,3,39), conv, '\\key A ;  ->\\key a;'))
453
454 if 1:
455         def conv (str):
456                 if re.search ('\\[:',str):
457                         sys.stderr.write ('\nNot smart enough to convert to new tremolo format')
458                 return str
459
460         conversions.append (((1,3,41), conv,
461                 '[:16 c4 d4 ] -> \\repeat "tremolo" 2 { c16 d16 }'))
462
463 if 1:
464         def conv (str):
465                 str = re.sub ('Staff_margin_engraver' , 'Instrument_name_engraver', str)
466                 return str
467
468         conversions.append (((1,3,42), conv,
469                 'Staff_margin_engraver deprecated, use Instrument_name_engraver'))
470
471 if 1:
472         def conv (str):
473                 str = re.sub ('note[hH]eadStyle\\s*=\\s*"?(\\w+)"?' , "noteHeadStyle = #'\\1", str)
474                 return str
475
476         conversions.append (((1,3,49), conv,
477                 'noteHeadStyle value: string -> symbol'))
478
479 if 1:
480         def conv (str):
481                 str = re.sub (r"""\\key *([a-z]+) *;""", r"""\\key \1 \major;""",str);
482                 return str
483         conversions.append (((1,3,59), conv,
484                 '\key X ; -> \key X major; ')) 
485
486 if 1:
487         def conv (str):
488                 str = re.sub (r'latexheaders *= *"\\\\input ',
489                               'latexheaders = "',
490                               str)
491                 return str
492         conversions.append (((1,3,68), conv, 'latexheaders = "\\input global" -> latexheaders = "global"'))
493
494
495
496 ################ TODO: lots of other syntax change should be done here as well
497
498
499
500 if 1:
501         def conv (str):
502                 str = re.sub ('basicCollisionProperties', 'NoteCollision', str)
503                 str = re.sub ('basicVoltaSpannerProperties' , "VoltaBracket", str)
504                 str = re.sub ('basicKeyProperties' , "KeySignature", str)
505
506                 str = re.sub ('basicClefItemProperties' ,"Clef", str)
507
508
509                 str = re.sub ('basicLocalKeyProperties' ,"Accidentals", str)
510                 str = re.sub ('basicMarkProperties' ,"Accidentals", str)                                
511                 str = re.sub ('basic([A-Za-z_]+)Properties', '\\1', str)
512
513                 return str
514         
515         conversions.append (((1,3,92), conv, 'basicXXXProperties -> XXX'))
516
517 if 1:
518         def conv (str):
519                 # Ugh, but meaning of \stemup changed too
520                 # maybe we should do \stemup -> \stemUp\slurUp\tieUp ?
521                 str = re.sub ('\\\\stemup', '\\\\stemUp', str)
522                 str = re.sub ('\\\\stemdown', '\\\\stemDown', str)
523                 str = re.sub ('\\\\stemboth', '\\\\stemBoth', str)
524                 
525                 str = re.sub ('\\\\slurup', '\\\\slurUp', str)
526                 str = re.sub ('\\\\slurboth', '\\\\slurBoth', str)
527                 str = re.sub ('\\\\slurdown', '\\\\slurDown', str)
528                 str = re.sub ('\\\\slurdotted', '\\\\slurDotted', str)
529                 str = re.sub ('\\\\slurnormal', '\\\\slurNoDots', str)          
530                 
531                 str = re.sub ('\\\\shiftoff', '\\\\shiftOff', str)
532                 str = re.sub ('\\\\shifton', '\\\\shiftOn', str)
533                 str = re.sub ('\\\\shiftonn', '\\\\shiftOnn', str)
534                 str = re.sub ('\\\\shiftonnn', '\\\\shiftOnnn', str)
535
536                 str = re.sub ('\\\\onevoice', '\\\\oneVoice', str)
537                 str = re.sub ('\\\\voiceone', '\\\\voiceOne', str)
538                 str = re.sub ('\\\\voicetwo', '\\\\voiceTwo', str)
539                 str = re.sub ('\\\\voicethree', '\\\\voiceThree', str)
540                 str = re.sub ('\\\\voicefour', '\\\\voiceFour', str)
541
542                 # I don't know exactly when these happened...
543                 str = re.sub ('\\\\property *[^ ]*verticalDirection[^=]*= *#?(1|(\\\\up))', '\\\\stemUp\\\\slurUp\\\\tieUp', str)
544                 str = re.sub ('\\\\property *[^ ]*verticalDirection[^=]*= *#?((-1)|(\\\\down))', '\\\\stemDown\\\\slurDown\\\\tieDown', str)
545                 str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)VerticalDirection[^=]*= *#?(1|(\\\\up))', '\\\\\\1Up', str)
546                 str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)VerticalDirection[^=]*= *#?((-1)|(\\\\down))', '\\\\\\1Down', str)
547
548                 return str
549         
550         conversions.append (((1,3,93), conv,
551                 'property definiton case (eg. onevoice -> oneVoice)'))
552
553
554 if 1:
555         def conv (str):
556                 str = re.sub ('ChordNames*', 'ChordNames', str)
557                 if re.search ('\\\\textscript "[^"]* *"[^"]*"', str):
558                         sys.stderr.write ('\nNot smart enough to convert to new \\textscript markup text')
559
560                 str = re.sub ('\\textscript +("[^"]*")', '\\textscript #\\1', str)
561
562                 return str
563         
564         conversions.append (((1,3,97), conv, 'ChordName -> ChordNames'))
565
566
567 ## TODO: add lots of these
568         
569 if 1:
570         def conv (str):
571                 str = re.sub ('\\\\property *"?Voice"? *[.] *"?textStyle"? *= *"([^"]*)"', '\\\\property Voice.TextScript \\\\set #\'font-style = #\'\\1', str)
572                 str = re.sub ('\\\\property *"?Lyrics"? *[.] *"?textStyle"? *= *"([^"]*)"', '\\\\property Lyrics.LyricText \\\\set #\'font-style = #\'\\1', str)
573
574                 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?timeSignatureStyle"? *= *"([^"]*)"', '\\\\property \\1.TimeSignature \\\\override #\'style = #\'\\2', str) 
575
576                 str = re.sub ('"?timeSignatureStyle"? *= *#?""', 'TimeSignature \\\\override #\'style = ##f', str)
577                 
578                 str = re.sub ('"?timeSignatureStyle"? *= *#?"([^"]*)"', 'TimeSignature \\\\override #\'style = #\'\\1', str)
579                 
580                 str = re.sub ('#\'style *= #*"([^"])"', '#\'style = #\'\\1', str)
581                 
582                 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?horizontalNoteShift"? *= *"?#?([0-9]+)"?', '\\\\property \\1.NoteColumn \\\\override #\'horizontal-shift = #\\2', str) 
583
584                 # ugh
585                 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?flagStyle"? *= *""', '\\\\property \\1.Stem \\\\override #\'flag-style = ##f', str)
586                 
587                 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?flagStyle"? *= *"([^"]*)"', '\\\\property \\1.Stem \\\\override #\'flag-style = #\'\\2', str) 
588                 return str
589         
590         conversions.append (((1,3,98), conv, 'CONTEXT.textStyle -> GROB.#font-style '))
591
592 if 1:
593         def conv (str):
594                 str = re.sub ('"?beamAutoEnd_([0-9]*)"? *= *(#\\([^)]*\\))', 'autoBeamSettings \\push #\'(end 1 \\1 * *) = \\2', str)
595                 str = re.sub ('"?beamAutoBegin_([0-9]*)"? *= *(#\\([^)]*\))', 'autoBeamSettings \\push #\'(begin 1 \\1 * *) = \\2', str)
596                 str = re.sub ('"?beamAutoEnd"? *= *(#\\([^)]*\\))', 'autoBeamSettings \\push #\'(end * * * *) = \\1', str)
597                 str = re.sub ('"?beamAutoBegin"? *= *(#\\([^)]*\\))', 'autoBeamSettings \\push #\'(begin * * * *) = \\1', str)
598
599
600                 return str
601         
602         conversions.append (((1,3,102), conv, 'beamAutoEnd -> autoBeamSettings \\push (end * * * *)'))
603
604
605 if 1:
606         def conv (str):
607                 str = re.sub ('\\\\push', '\\\\override', str)
608                 str = re.sub ('\\\\pop', '\\\\revert', str)
609
610                 return str
611         
612         conversions.append (((1,3,111), conv, '\\push -> \\override, \\pop -> \\revert'))
613
614 if 1:
615         def conv (str):
616                 str = re.sub ('LyricVoice', 'LyricsVoice', str)
617                 # old fix
618                 str = re.sub ('Chord[Nn]ames*.Chord[Nn]ames*', 'ChordNames.ChordName', str)
619                 return str
620         
621         conversions.append (((1,3,113), conv, 'LyricVoice -> LyricsVoice'))
622
623 def regularize_id (str):
624         s = ''
625         lastx = ''
626         for x in str:
627                 if x == '_':
628                         lastx = x
629                         continue
630                 elif x in string.digits:
631                         x = chr(ord (x) - ord ('0')  +ord ('A'))
632                 elif x not in string.letters:
633                         x = 'x'
634                 elif x in string.lowercase and lastx == '_':
635                         x = string.upper (x)
636                 s = s + x
637                 lastx = x
638         return s
639
640 if 1:
641         def conv (str):
642                 
643                 def regularize_dollar_reference (match):
644                         return regularize_id (match.group (1))
645                 def regularize_assignment (match):
646                         return '\n' + regularize_id (match.group (1)) + ' = '
647                 str = re.sub ('\$([^\t\n ]+)', regularize_dollar_reference, str)
648                 str = re.sub ('\n([^ \t\n]+) = ', regularize_assignment, str)
649                 return str
650         
651         conversions.append (((1,3,117), conv, 'identifier names: $!foo_bar_123 -> xfooBarABC'))
652
653
654 if 1:
655         def conv (str):
656                 def regularize_paper (match):
657                         return regularize_id (match.group (1))
658                 
659                 str = re.sub ('(paper_[a-z]+)', regularize_paper, str)
660                 str = re.sub ('sustainup', 'sustainUp', str)
661                 str = re.sub ('nobreak', 'noBreak', str)
662                 str = re.sub ('sustaindown', 'sustainDown', str)
663                 str = re.sub ('sostenutoup', 'sostenutoUp', str)
664                 str = re.sub ('sostenutodown', 'sostenutoDown', str)
665                 str = re.sub ('unachorda', 'unaChorda', str)
666                 str = re.sub ('trechorde', 'treChorde', str)
667         
668                 return str
669         
670         conversions.append (((1,3,120), conv, 'paper_xxx -> paperXxxx, pedalup -> pedalUp.'))
671
672 if 1:
673         def conv (str):
674                 str = re.sub ('drarnChords', 'chordChanges', str)
675                 str = re.sub ('\\musicalpitch', '\\pitch', str)
676                 return str
677         
678         conversions.append (((1,3,122), conv, 'drarnChords -> chordChanges, \\musicalpitch -> \\pitch'))
679
680
681 ############################
682         
683
684 def get_conversions (from_version, to_version):
685         def version_b (v, f = from_version, t = to_version):
686                 return version_cmp (v[0], f) > 0 and version_cmp (v[0], t) <= 0
687         return filter (version_b, conversions)
688
689
690 def latest_version ():
691         return conversions[-1][0]
692
693 def do_conversion (infile, from_version, outfile, to_version):
694         conv_list = get_conversions (from_version, to_version)
695
696         sys.stderr.write ('Applying conversions: ')
697         str = infile.read ()
698         last_conversion = ()
699         try:
700                 for x in conv_list:
701                         sys.stderr.write (tup_to_str (x[0])  + ', ')
702                         str = x[1] (str)
703                         last_conversion = x[0]
704
705         except FatalConversionError:
706                 sys.stderr.write ('Error while converting; I won\'t convert any further')
707
708         if last_conversion:
709                 sys.stderr.write ('\n')
710                 new_ver =  '\\version \"%s\"' % tup_to_str (last_conversion)
711                 # JUNKME?
712                 # ugh: this all really doesn't help
713                 # esp. as current conversion rules are soo incomplete
714                 if re.search (lilypond_version_re_str, str):
715                         str = re.sub (lilypond_version_re_str,'\\'+new_ver , str)
716                 #else:
717                 #       str = new_ver + '\n' + str
718
719                 outfile.write(str)
720
721         return last_conversion
722         
723 class UnknownVersion:
724         pass
725
726 def do_one_file (infile_name):
727         sys.stderr.write ('Processing `%s\' ... '% infile_name)
728         outfile_name = ''
729         if __main__.edit:
730                 outfile_name = infile_name + '.NEW'
731         elif __main__.outfile_name:
732                 outfile_name = __main__.outfile_name
733
734         if __main__.from_version:
735                 from_version = __main__.from_version
736         else:
737                 guess = guess_lilypond_version (infile_name)
738                 if not guess:
739                         raise UnknownVersion()
740                 from_version = str_to_tuple (guess)
741
742         if __main__.to_version:
743                 to_version = __main__.to_version
744         else:
745                 to_version = latest_version ()
746
747
748         if infile_name:
749                 infile = open (infile_name,'r')
750         else:
751                 infile = sys.stdin
752
753         if outfile_name:
754                 outfile =  open (outfile_name, 'w')
755         else:
756                 outfile = sys.stdout
757
758         touched = do_conversion (infile, from_version, outfile, to_version)
759
760         if infile_name:
761                 infile.close ()
762
763         if outfile_name:
764                 outfile.close ()
765
766         if __main__.edit and touched:
767                 try:
768                         os.remove(infile_name + '~')
769                 except:
770                         pass
771                 os.rename (infile_name, infile_name + '~')
772                 os.rename (infile_name + '.NEW', infile_name)
773
774         sys.stderr.write ('\n')
775         sys.stderr.flush ()
776
777 edit = 0
778 to_version = ()
779 from_version = ()
780 outfile_name = ''
781
782 (options, files) = getopt.getopt (
783         sys.argv[1:], 'o:f:t:seh', ['version', 'output', 'show-rules', 'help', 'edit', 'from=', 'to='])
784
785 for opt in options:
786         o = opt[0]
787         a = opt[1]
788         if o== '--help' or o == '-h':
789                 usage ()
790                 sys.exit (0)
791         if o == '--version' or o == '-v':
792                 print_version ()
793                 sys.exit (0)
794         elif o== '--from' or o=='-f':
795                 from_version = str_to_tuple (a)
796         elif o== '--to' or o=='-t':
797                 to_version = str_to_tuple (a)
798         elif o== '--edit' or o == '-e':
799                 edit = 1
800         elif o== '--show-rules' or o == '-s':
801                 show_rules (sys.stdout)
802                 sys.exit(0)
803         elif o == '--output' or o == '-o':
804                 outfile_name = a
805         else:
806                 print o
807                 raise getopt.error
808
809 identify ()
810 for f in files:
811         if f == '-':
812                 f = ''
813         try:
814                 do_one_file (f)
815         except UnknownVersion:
816                 sys.stderr.write ('\n')
817                 sys.stderr.write ("%s: can't determine version for %s" % (program_name, f))
818                 sys.stderr.write ('\n')
819                 sys.stderr.write ("%s: skipping" % program_name)
820                 pass
821 sys.stderr.write ('\n')