]> git.donarmstrong.com Git - lilypond.git/blob - scripts/convert-ly.py
2e7f64fb1a7d95dcd9440873cb1ce563219a3435
[lilypond.git] / scripts / convert-ly.py
1 #!@PYTHON@
2 #
3 # convert-ly.py -- convertor for lilypond versions
4
5 # source file of the GNU LilyPond music typesetter
6
7 # (c) 1998--2001
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 add_version = 1
32
33
34 def program_id ():
35         return '%s (GNU LilyPond) %s' %(program_name,  version);
36
37 def identify ():
38         sys.stderr.write (program_id () + '\n')
39
40 def usage ():
41         sys.stdout.write (
42                 r"""Usage: %s [OPTION]... [FILE]... 
43 Try to convert to newer lilypond-versions.  The version number of the
44 input is guessed by default from \version directive
45
46 Options:
47   -a, --assume-old       apply all conversions to unversioned files
48   -h, --help             print this help
49   -e, --edit             in place edit
50   -f, --from=VERSION     start from version. Overrides \version found in file.
51   -s, --show-rules       print all rules.
52   -t, --to=VERSION       target version
53   -n, --no-version       don't add new version stamp.
54       --version          print program version
55
56 Report bugs to bugs-gnu-music@gnu.org
57
58 """ % program_name)
59         
60         
61         sys.exit (0)
62
63 def print_version ():
64         
65         sys.stdout.write (r"""%s
66
67 This is free software.  It is covered by the GNU General Public
68 License, and you are welcome to change it and/or distribute copies of
69 it under certain conditions.  invoke as `%s --warranty' for more
70 information.
71
72 """ % (program_id() , program_name))
73         
74 def gulp_file(f):
75         try:
76                 i = open(f)
77                 i.seek (0, 2)
78                 n = i.tell ()
79                 i.seek (0,0)
80         except:
81                 print 'can\'t open file: ' + f + '\n'
82                 return ''
83         s = i.read (n)
84         if len (s) <= 0:
85                 print 'gulped empty file: ' + f + '\n'
86         i.close ()
87         return s
88
89 def str_to_tuple (s):
90         return tuple (map (string.atoi, string.split (s,'.')))
91
92 def tup_to_str (t):
93         return string.join (map (lambda x: '%s' % x, list (t)), '.')
94
95 def version_cmp (t1, t2):
96         for x in [0,1,2]:
97                 if t1[x] - t2[x]:
98                         return t1[x] - t2[x]
99         return 0
100
101 def guess_lilypond_version (filename):
102         s = gulp_file (filename)
103         m = lilypond_version_re.search (s)
104         if m:
105                 return m.group (2)
106         else:
107                 return ''
108
109 class FatalConversionError:
110         pass
111
112 conversions = []
113
114 def show_rules (file):
115         for x in conversions:
116                 file.write  ('%s: %s\n' % (tup_to_str (x[0]), x[2]))
117
118 ############################
119                 
120 if 1:
121         def conv(str):
122                 if re.search ('\\\\multi', str):
123                         sys.stderr.write ('\nNot smart enough to convert \\multi')
124                 return str
125         
126         conversions.append (((0,1,9), conv, '\\header { key = concat + with + operator }'))
127
128 if 1:                                   # need new a namespace
129         def conv (str):
130                 if re.search ('\\\\octave', str):
131                         sys.stderr.write ('\nNot smart enough to convert \\octave')
132                 #       raise FatalConversionError()
133                 
134                 return str
135
136         conversions.append ((
137                 ((0,1,19), conv, 'deprecated \\octave; can\'t convert automatically')))
138
139
140 if 1:                                   # need new a namespace
141         def conv (str):
142                 str = re.sub ('\\\\textstyle([^;]+);',
143                                          '\\\\property Lyrics . textstyle = \\1', str)
144                 # harmful to current .lys
145                 # str = re.sub ('\\\\key([^;]+);', '\\\\accidentals \\1;', str)
146                         
147                 return str
148
149         conversions.append ((
150                 ((0,1,20), conv, 'deprecated \\textstyle, new \key syntax')))
151
152
153 if 1:
154         def conv (str):
155                 str = re.sub ('\\\\musical_pitch', '\\\\musicalpitch',str)
156                 str = re.sub ('\\\\meter', '\\\\time',str)
157                         
158                 return str
159
160         conversions.append ((
161                 ((0,1,21), conv, '\\musical_pitch -> \\musicalpitch, '+
162                  '\\meter -> \\time')))
163
164 if 1:
165         def conv (str):
166                 return str
167
168         conversions.append ((
169                 ((1,0,0), conv, '0.1.21 -> 1.0.0 ')))
170
171
172 if 1:
173         def conv (str):
174                 str = re.sub ('\\\\accidentals', '\\\\keysignature',str)
175                 str = re.sub ('specialaccidentals *= *1', 'keyoctaviation = 0',str)
176                 str = re.sub ('specialaccidentals *= *0', 'keyoctaviation = 1',str)
177                         
178                 return str
179
180         conversions.append ((
181                 ((1,0,1), conv, '\\accidentals -> \\keysignature, ' +
182                  'specialaccidentals -> keyoctaviation')))
183
184 if 1:
185         def conv(str):
186                 if re.search ('\\\\header', str):
187                         sys.stderr.write ('\nNot smart enough to convert to new \\header format')
188                 return str
189         
190         conversions.append (((1,0,2), conv, '\\header { key = concat + with + operator }'))
191
192 if 1:
193         def conv(str):
194                 str =  re.sub ('\\\\melodic([^a-zA-Z])', '\\\\notes\\1',str)
195                 return str
196         
197         conversions.append (((1,0,3), conv, '\\melodic -> \\notes'))
198
199 if 1:
200         def conv(str):
201                 str =  re.sub ('default_paper *=', '',str)
202                 str =  re.sub ('default_midi *=', '',str)
203                 return str
204         
205         conversions.append (((1,0,4), conv, 'default_{paper,midi}'))
206
207 if 1:
208         def conv(str):
209                 str =  re.sub ('ChoireStaff', 'ChoirStaff',str)
210                 str =  re.sub ('\\\\output', 'output = ',str)
211                         
212                 return str
213         
214         conversions.append (((1,0,5), conv, 'ChoireStaff -> ChoirStaff'))
215
216 if 1:
217         def conv(str):
218                 if re.search ('[a-zA-Z]+ = *\\translator',str):
219                         sys.stderr.write ('\nNot smart enough to change \\translator syntax')
220                 #       raise FatalConversionError()
221                 return str
222         
223         conversions.append (((1,0,6), conv, 'foo = \\translator {\\type .. } ->\\translator {\\type ..; foo; }'))
224
225
226 if 1:
227         def conv(str):
228                 str =  re.sub ('\\\\lyrics*', '\\\\lyrics',str)
229                         
230                 return str
231         
232         conversions.append (((1,0,7), conv, '\\lyric -> \\lyrics'))
233
234 if 1:
235         def conv(str):
236                 str =  re.sub ('\\\\\\[/3+', '\\\\times 2/3 { ',str)
237                 str =  re.sub ('\\[/3+', '\\\\times 2/3 { [',str)
238                 str =  re.sub ('\\\\\\[([0-9/]+)', '\\\\times \\1 {',str)
239                 str =  re.sub ('\\[([0-9/]+)', '\\\\times \\1 { [',str)
240                 str =  re.sub ('\\\\\\]([0-9/]+)', '}', str)
241                 str =  re.sub ('\\\\\\]', '}',str)
242                 str =  re.sub ('\\]([0-9/]+)', '] }', str)
243                 return str
244         
245         conversions.append (((1,0,10), conv, '[2/3 ]1/1 -> \\times 2/3 '))
246
247 if 1:
248         def conv(str):
249                 return str
250         conversions.append (((1,0,12), conv, 'Chord syntax stuff'))
251
252
253 if 1:
254         def conv(str):
255                 
256                 
257                 str =  re.sub ('<([^>~]+)~([^>]*)>','<\\1 \\2> ~', str)
258                         
259                 return str
260         
261         conversions.append (((1,0,13), conv, '<a ~ b> c -> <a b> ~ c'))
262
263 if 1:
264         def conv(str):
265                 str =  re.sub ('<\\[','[<', str)
266                 str =  re.sub ('\\]>','>]', str)
267                         
268                 return str
269         
270         conversions.append (((1,0,14), conv, '<[a b> <a b]>c -> [<a b> <a b>]'))
271
272
273 if 1:
274         def conv(str):
275                 str =  re.sub ('\\\\type([^\n]*engraver)','\\\\TYPE\\1', str)
276                 str =  re.sub ('\\\\type([^\n]*performer)','\\\\TYPE\\1', str)
277                 str =  re.sub ('\\\\type','\\\\context', str)
278                 str =  re.sub ('\\\\TYPE','\\\\type', str)
279                 str =  re.sub ('textstyle','textStyle', str)
280                         
281                 return str
282         
283         conversions.append (((1,0,16), conv, '\\type -> \\context, textstyle -> textStyle'))
284
285
286 if 1:
287         def conv(str):
288                 if re.search ('\\\\repeat',str):
289                         sys.stderr.write ('\nNot smart enough to convert \\repeat')
290                 #       raise FatalConversionError()
291                 return str
292         
293         conversions.append (((1,0,18), conv,
294                 '\\repeat NUM Music Alternative -> \\repeat FOLDSTR Music Alternative'))
295
296 if 1:
297         def conv(str):
298                 str =  re.sub ('SkipBars','skipBars', str)
299                 str =  re.sub ('fontsize','fontSize', str)
300                 str =  re.sub ('midi_instrument','midiInstrument', str)                 
301                         
302                 return str
303
304         conversions.append (((1,0,19), conv,
305                 'fontsize -> fontSize, midi_instrument -> midiInstrument, SkipBars -> skipBars'))
306
307
308 if 1:
309         def conv(str):
310                 str =  re.sub ('tieydirection','tieVerticalDirection', str)
311                 str =  re.sub ('slurydirection','slurVerticalDirection', str)
312                 str =  re.sub ('ydirection','verticalDirection', str)                   
313                         
314                 return str
315
316         conversions.append (((1,0,20), conv,
317                 '{,tie,slur}ydirection -> {v,tieV,slurV}erticalDirection'))
318
319
320 if 1:
321         def conv(str):
322                 str =  re.sub ('hshift','horizontalNoteShift', str)
323                         
324                 return str
325
326         conversions.append (((1,0,21), conv,
327                 'hshift -> horizontalNoteShift'))
328
329
330 if 1:
331         def conv(str):
332                 str =  re.sub ('\\\\grouping[^;]*;','', str)
333                         
334                 return str
335
336         conversions.append (((1,1,52), conv,
337                 'deprecate \\grouping'))
338
339
340 if 1:
341         def conv(str):
342                 str =  re.sub ('\\\\wheel','\\\\coda', str)
343                         
344                 return str
345
346         conversions.append (((1,1,55), conv,
347                 '\\wheel -> \\coda'))
348
349 if 1:
350         def conv(str):
351                 str =  re.sub ('keyoctaviation','keyOctaviation', str)
352                 str =  re.sub ('slurdash','slurDash', str)
353                         
354                 return str
355
356         conversions.append (((1,1,65), conv,
357                 'slurdash -> slurDash, keyoctaviation -> keyOctaviation'))
358
359 if 1:
360         def conv(str):
361                 str =  re.sub ('\\\\repeat *\"?semi\"?','\\\\repeat "volta"', str)
362                         
363                 return str
364
365         conversions.append (((1,1,66), conv,
366                 'semi -> volta'))
367
368
369 if 1:
370         def conv(str):
371                 str =  re.sub ('\"?beamAuto\"? *= *\"?0?\"?','noAutoBeaming = "1"', str)
372                         
373                 return str
374
375         conversions.append (((1,1,67), conv,
376                 'beamAuto -> noAutoBeaming'))
377
378 if 1:
379         def conv(str):
380                 str =  re.sub ('automaticMelismas', 'automaticMelismata', str)
381                         
382                 return str
383
384         conversions.append (((1,2,0), conv,
385                 'automaticMelismas -> automaticMelismata'))
386
387 if 1:
388         def conv(str):
389                 str =  re.sub ('dynamicDir\\b', 'dynamicDirection', str)
390                         
391                 return str
392
393         conversions.append (((1,2,1), conv,
394                 'dynamicDir -> dynamicDirection'))
395
396 if 1:
397         def conv(str):
398                 str =  re.sub ('\\\\cadenza *0 *;', '\\\\cadenzaOff', str)
399                 str =  re.sub ('\\\\cadenza *1 *;', '\\\\cadenzaOn', str)               
400                         
401                 return str
402
403         conversions.append (((1,3,4), conv,
404                 '\\cadenza -> \cadenza{On|Off}'))
405
406 if 1:
407         def conv (str):
408                 str = re.sub ('"?beamAuto([^"=]+)"? *= *"([0-9]+)/([0-9]+)" *;*',
409                               'beamAuto\\1 = #(make-moment \\2 \\3)',
410                               str)
411                 return str
412
413         conversions.append (((1,3,5), conv, 'beamAuto moment properties'))
414
415 if 1:
416         def conv (str):
417                 str = re.sub ('stemStyle',
418                               'flagStyle',
419                               str)
420                 return str
421
422         conversions.append (((1,3,17), conv, 'stemStyle -> flagStyle'))
423
424 if 1:
425         def conv (str):
426                 str = re.sub ('staffLineLeading',
427                               'staffSpace',
428                               str)
429                 return str
430
431         conversions.append (((1,3,18), conv, 'staffLineLeading -> staffSpace'))
432
433
434 if 1:
435         def conv(str):
436                 if re.search ('\\\\repetitions',str):
437                         sys.stderr.write ('\nNot smart enough to convert \\repetitions')
438                 #       raise FatalConversionError()
439                 return str
440         
441         conversions.append (((1,3,23), conv,
442                 '\\\\repetitions feature dropped'))
443
444
445 if 1:
446         def conv (str):
447                 str = re.sub ('textEmptyDimension *= *##t',
448                               'textNonEmpty = ##f',
449                               str)
450                 str = re.sub ('textEmptyDimension *= *##f',
451                               'textNonEmpty = ##t',
452                               str)
453                 return str
454
455         conversions.append (((1,3,35), conv, 'textEmptyDimension -> textNonEmpty'))
456
457 if 1:
458         def conv (str):
459                 str = re.sub ("([a-z]+)[ \t]*=[ \t]*\\\\musicalpitch *{([- 0-9]+)} *\n",
460                               "(\\1 . (\\2))\n", str)
461                 str = re.sub ("\\\\musicalpitch *{([0-9 -]+)}",
462                               "\\\\musicalpitch #'(\\1)", str)
463                 if re.search ('\\\\notenames',str):
464                         sys.stderr.write ('\nNot smart enough to convert to new \\notenames format')
465                 return str
466
467         conversions.append (((1,3,38), conv, '\musicalpitch { a b c } -> #\'(a b c)'))
468
469 if 1:
470         def conv (str):
471                 def replace (match):
472                         return '\\key %s;' % string.lower (match.group (1))
473                 
474                 str = re.sub ("\\\\key ([^;]+);",  replace, str)
475                 return str
476         
477         conversions.append (((1,3,39), conv, '\\key A ;  ->\\key a;'))
478
479 if 1:
480         def conv (str):
481                 if re.search ('\\[:',str):
482                         sys.stderr.write ('\nNot smart enough to convert to new tremolo format')
483                 return str
484
485         conversions.append (((1,3,41), conv,
486                 '[:16 c4 d4 ] -> \\repeat "tremolo" 2 { c16 d16 }'))
487
488 if 1:
489         def conv (str):
490                 str = re.sub ('Staff_margin_engraver' , 'Instrument_name_engraver', str)
491                 return str
492
493         conversions.append (((1,3,42), conv,
494                 'Staff_margin_engraver deprecated, use Instrument_name_engraver'))
495
496 if 1:
497         def conv (str):
498                 str = re.sub ('note[hH]eadStyle\\s*=\\s*"?(\\w+)"?' , "noteHeadStyle = #'\\1", str)
499                 return str
500
501         conversions.append (((1,3,49), conv,
502                 'noteHeadStyle value: string -> symbol'))
503
504 if 1:
505         def conv (str):
506                 if re.search ('\\\\keysignature', str):
507                         sys.stderr.write ('\nNot smart enough to convert to new tremolo format')
508                 return str
509
510
511         conversions.append (((1,3,58), conv,
512                 'noteHeadStyle value: string -> symbol'))
513
514 if 1:
515         def conv (str):
516                 str = re.sub (r"""\\key *([a-z]+) *;""", r"""\\key \1 \major;""",str);
517                 return str
518         conversions.append (((1,3,59), conv,
519                 '\key X ; -> \key X major; ')) 
520
521 if 1:
522         def conv (str):
523                 str = re.sub (r'latexheaders *= *"\\\\input ',
524                               'latexheaders = "',
525                               str)
526                 return str
527         conversions.append (((1,3,68), conv, 'latexheaders = "\\input global" -> latexheaders = "global"'))
528
529
530
531
532 # TODO: lots of other syntax change should be done here as well
533 if 1:
534         def conv (str):
535                 str = re.sub ('basicCollisionProperties', 'NoteCollision', str)
536                 str = re.sub ('basicVoltaSpannerProperties' , "VoltaBracket", str)
537                 str = re.sub ('basicKeyProperties' , "KeySignature", str)
538
539                 str = re.sub ('basicClefItemProperties' ,"Clef", str)
540
541
542                 str = re.sub ('basicLocalKeyProperties' ,"Accidentals", str)
543                 str = re.sub ('basicMarkProperties' ,"Accidentals", str)
544                 str = re.sub ('basic([A-Za-z_]+)Properties', '\\1', str)
545
546                 str = re.sub ('Repeat_engraver' ,'Volta_engraver', str)
547                 return str
548         
549         conversions.append (((1,3,92), conv, 'basicXXXProperties -> XXX, Repeat_engraver -> Volta_engraver'))
550
551 if 1:
552         def conv (str):
553                 # Ugh, but meaning of \stemup changed too
554                 # maybe we should do \stemup -> \stemUp\slurUp\tieUp ?
555                 str = re.sub ('\\\\stemup', '\\\\stemUp', str)
556                 str = re.sub ('\\\\stemdown', '\\\\stemDown', str)
557                 str = re.sub ('\\\\stemboth', '\\\\stemBoth', str)
558                 
559                 str = re.sub ('\\\\slurup', '\\\\slurUp', str)
560                 str = re.sub ('\\\\slurboth', '\\\\slurBoth', str)
561                 str = re.sub ('\\\\slurdown', '\\\\slurDown', str)
562                 str = re.sub ('\\\\slurdotted', '\\\\slurDotted', str)
563                 str = re.sub ('\\\\slurnormal', '\\\\slurNoDots', str)          
564                 
565                 str = re.sub ('\\\\shiftoff', '\\\\shiftOff', str)
566                 str = re.sub ('\\\\shifton', '\\\\shiftOn', str)
567                 str = re.sub ('\\\\shiftonn', '\\\\shiftOnn', str)
568                 str = re.sub ('\\\\shiftonnn', '\\\\shiftOnnn', str)
569
570                 str = re.sub ('\\\\onevoice', '\\\\oneVoice', str)
571                 str = re.sub ('\\\\voiceone', '\\\\voiceOne', str)
572                 str = re.sub ('\\\\voicetwo', '\\\\voiceTwo', str)
573                 str = re.sub ('\\\\voicethree', '\\\\voiceThree', str)
574                 str = re.sub ('\\\\voicefour', '\\\\voiceFour', str)
575
576                 # I don't know exactly when these happened...
577                 # ugh, we loose context setting here...
578                 str = re.sub ('\\\\property *[^ ]*verticalDirection[^=]*= *#?"?(1|(\\\\up))"?', '\\\\stemUp\\\\slurUp\\\\tieUp', str)
579                 str = re.sub ('\\\\property *[^ ]*verticalDirection[^=]*= *#?"?((-1)|(\\\\down))"?', '\\\\stemDown\\\\slurDown\\\\tieDown', str)
580                 str = re.sub ('\\\\property *[^ ]*verticalDirection[^=]*= *#?"?(0|(\\\\center))"?', '\\\\stemBoth\\\\slurBoth\\\\tieBoth', str)
581
582                 str = re.sub ('verticalDirection[^=]*= *#?"?(1|(\\\\up))"?', 'Stem \\\\override #\'direction = #0\nSlur \\\\override #\'direction = #0\n Tie \\\\override #\'direction = #1', str)
583                 str = re.sub ('verticalDirection[^=]*= *#?"?((-1)|(\\\\down))"?', 'Stem \\\\override #\'direction = #0\nSlur \\\\override #\'direction = #0\n Tie \\\\override #\'direction = #-1', str)
584                 str = re.sub ('verticalDirection[^=]*= *#?"?(0|(\\\\center))"?', 'Stem \\\\override #\'direction = #0\nSlur \\\\override #\'direction = #0\n Tie \\\\override #\'direction = #0', str)
585                 
586                 str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)VerticalDirection[^=]*= *#?"?(1|(\\\\up))"?', '\\\\\\1Up', str)
587                 str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)VerticalDirection[^=]*= *#?"?((-1)|(\\\\down))"?', '\\\\\\1Down', str)
588                 str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)VerticalDirection[^=]*= *#?"?(0|(\\\\center))"?', '\\\\\\1Both', str)
589
590                 # (lacks capitalisation slur -> Slur)
591                 str = re.sub ('([a-z]+)VerticalDirection[^=]*= *#?"?(1|(\\\\up))"?', '\\1 \\\\override #\'direction = #1', str)
592                 str = re.sub ('([a-z]+)VerticalDirection[^=]*= *#?"?((-1)|(\\\\down))"?', '\\1 \\override #\'direction = #-1', str)
593                 str = re.sub ('([a-z]+)VerticalDirection[^=]*= *#?"?(0|(\\\\center))"?', '\\1 \\\\override #\'direction = #0', str)
594
595                 ## dynamic..
596                 str = re.sub ('\\\\property *[^ .]*[.]?dynamicDirection[^=]*= *#?"?(1|(\\\\up))"?', '\\\\dynamicUp', str)
597                 str = re.sub ('\\\\property *[^ .]*[.]?dyn[^=]*= *#?"?((-1)|(\\\\down))"?', '\\\\dynamicDown', str)
598                 str = re.sub ('\\\\property *[^ .]*[.]?dyn[^=]*= *#?"?(0|(\\\\center))"?', '\\\\dynamicBoth', str)
599
600                 str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)Dash[^=]*= *#?"?(0|(""))"?', '\\\\\\1NoDots', str)
601                 str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)Dash[^=]*= *#?"?([1-9]+)"?', '\\\\\\1Dotted', str)
602
603                 str = re.sub ('\\\\property *[^ .]*[.]?noAutoBeaming[^=]*= *#?"?(0|(""))"?', '\\\\autoBeamOn', str)
604                 str = re.sub ('\\\\property *[^ .]*[.]?noAutoBeaming[^=]*= *#?"?([1-9]+)"?', '\\\\autoBeamOff', str)
605
606
607
608                 return str
609         
610         conversions.append (((1,3,93), conv,
611                 'property definiton case (eg. onevoice -> oneVoice)'))
612
613
614 if 1:
615         def conv (str):
616                 str = re.sub ('ChordNames*', 'ChordNames', str)
617                 if re.search ('\\\\textscript "[^"]* *"[^"]*"', str):
618                         sys.stderr.write ('\nNot smart enough to convert to new \\textscript markup text')
619
620                 str = re.sub ('\\textscript +("[^"]*")', '\\textscript #\\1', str)
621
622                 return str
623         
624         conversions.append (((1,3,97), conv, 'ChordName -> ChordNames'))
625
626
627 # TODO: add lots of these
628         
629 if 1:
630         def conv (str):
631                 str = re.sub ('\\\\property *"?Voice"? *[.] *"?textStyle"? *= *"([^"]*)"', '\\\\property Voice.TextScript \\\\set #\'font-style = #\'\\1', str)
632                 str = re.sub ('\\\\property *"?Lyrics"? *[.] *"?textStyle"? *= *"([^"]*)"', '\\\\property Lyrics.LyricText \\\\set #\'font-style = #\'\\1', str)
633
634                 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?timeSignatureStyle"? *= *"([^"]*)"', '\\\\property \\1.TimeSignature \\\\override #\'style = #\'\\2', str) 
635
636                 str = re.sub ('"?timeSignatureStyle"? *= *#?""', 'TimeSignature \\\\override #\'style = ##f', str)
637                 
638                 str = re.sub ('"?timeSignatureStyle"? *= *#?"([^"]*)"', 'TimeSignature \\\\override #\'style = #\'\\1', str)
639                 
640                 str = re.sub ('#\'style *= #*"([^"])"', '#\'style = #\'\\1', str)
641                 
642                 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?horizontalNoteShift"? *= *"?#?([-0-9]+)"?', '\\\\property \\1.NoteColumn \\\\override #\'horizontal-shift = #\\2', str) 
643
644                 # ugh
645                 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?flagStyle"? *= *""', '\\\\property \\1.Stem \\\\override #\'flag-style = ##f', str)
646                 
647                 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?flagStyle"? *= *"([^"]*)"', '\\\\property \\1.Stem \\\\override #\'flag-style = #\'\\2', str) 
648                 return str
649         
650         conversions.append (((1,3,98), conv, 'CONTEXT.textStyle -> GROB.#font-style '))
651
652 if 1:
653         def conv (str):
654                 str = re.sub ('"?beamAutoEnd_([0-9]*)"? *= *(#\\([^)]*\\))', 'autoBeamSettings \\push #\'(end 1 \\1 * *) = \\2', str)
655                 str = re.sub ('"?beamAutoBegin_([0-9]*)"? *= *(#\\([^)]*\))', 'autoBeamSettings \\push #\'(begin 1 \\1 * *) = \\2', str)
656                 str = re.sub ('"?beamAutoEnd"? *= *(#\\([^)]*\\))', 'autoBeamSettings \\push #\'(end * * * *) = \\1', str)
657                 str = re.sub ('"?beamAutoBegin"? *= *(#\\([^)]*\\))', 'autoBeamSettings \\push #\'(begin * * * *) = \\1', str)
658
659
660                 return str
661         
662         conversions.append (((1,3,102), conv, 'beamAutoEnd -> autoBeamSettings \\push (end * * * *)'))
663
664
665 if 1:
666         def conv (str):
667                 str = re.sub ('\\\\push', '\\\\override', str)
668                 str = re.sub ('\\\\pop', '\\\\revert', str)
669
670                 return str
671         
672         conversions.append (((1,3,111), conv, '\\push -> \\override, \\pop -> \\revert'))
673
674 if 1:
675         def conv (str):
676                 str = re.sub ('LyricVoice', 'LyricsVoice', str)
677                 # old fix
678                 str = re.sub ('Chord[Nn]ames*.Chord[Nn]ames*', 'ChordNames.ChordName', str)
679                 str = re.sub ('Chord[Nn]ames([ \t\n]+\\\\override)', 'ChordName\\1', str)
680                 return str
681         
682         conversions.append (((1,3,113), conv, 'LyricVoice -> LyricsVoice'))
683
684 def regularize_id (str):
685         s = ''
686         lastx = ''
687         for x in str:
688                 if x == '_':
689                         lastx = x
690                         continue
691                 elif x in string.digits:
692                         x = chr(ord (x) - ord ('0')  +ord ('A'))
693                 elif x not in string.letters:
694                         x = 'x'
695                 elif x in string.lowercase and lastx == '_':
696                         x = string.upper (x)
697                 s = s + x
698                 lastx = x
699         return s
700
701 if 1:
702         def conv (str):
703                 
704                 def regularize_dollar_reference (match):
705                         return regularize_id (match.group (1))
706                 def regularize_assignment (match):
707                         return '\n' + regularize_id (match.group (1)) + ' = '
708                 str = re.sub ('\$([^\t\n ]+)', regularize_dollar_reference, str)
709                 str = re.sub ('\n([^ \t\n]+)[ \t]*= *', regularize_assignment, str)
710                 return str
711         
712         conversions.append (((1,3,117), conv, 'identifier names: $!foo_bar_123 -> xfooBarABC'))
713
714
715 if 1:
716         def conv (str):
717                 def regularize_paper (match):
718                         return regularize_id (match.group (1))
719                 
720                 str = re.sub ('(paper_[a-z]+)', regularize_paper, str)
721                 str = re.sub ('sustainup', 'sustainUp', str)
722                 str = re.sub ('nobreak', 'noBreak', str)
723                 str = re.sub ('sustaindown', 'sustainDown', str)
724                 str = re.sub ('sostenutoup', 'sostenutoUp', str)
725                 str = re.sub ('sostenutodown', 'sostenutoDown', str)
726                 str = re.sub ('unachorda', 'unaChorda', str)
727                 str = re.sub ('trechorde', 'treChorde', str)
728         
729                 return str
730         
731         conversions.append (((1,3,120), conv, 'paper_xxx -> paperXxxx, pedalup -> pedalUp.'))
732
733 if 1:
734         def conv (str):
735                 str = re.sub ('drarnChords', 'chordChanges', str)
736                 str = re.sub ('\\musicalpitch', '\\pitch', str)
737                 return str
738         
739         conversions.append (((1,3,122), conv, 'drarnChords -> chordChanges, \\musicalpitch -> \\pitch'))
740
741 if 1:
742         def conv (str):
743                 str = re.sub ('ly-([sg])et-elt-property', 'ly-\\1et-grob-property', str)
744                 return str
745         
746         conversions.append (((1,3,136), conv, 'ly-X-elt-property -> ly-X-grob-property'))
747
748 if 1:
749         def conv (str):
750                 str = re.sub ('point-and-click +#t', 'point-and-click line-column-location', str)
751                 return str
752         
753         conversions.append (((1,3,138), conv, 'point-and-click argument changed to procedure.'))
754
755 if 1:
756         def conv (str):
757                 str = re.sub ('followThread', 'followVoice', str)
758                 str = re.sub ('Thread.FollowThread', 'Voice.VoiceFollower', str)
759                 str = re.sub ('FollowThread', 'VoiceFollower', str)
760                 return str
761         
762         conversions.append (((1,3,138), conv, 'followThread -> followVoice.'))
763
764 if 1:
765         def conv (str):
766                 str = re.sub ('font-point-size', 'font-design-size', str)
767                 return str
768         
769         conversions.append (((1,3,139), conv, 'font-point-size -> font-design-size.'))
770
771 if 1:
772         def conv (str):
773                 str = re.sub ('([a-zA-Z]*)NoDots', '\\1Solid', str)
774                 return str
775         
776         conversions.append (((1,3,141), conv, 'xNoDots -> xSolid'))
777
778 if 1:
779         def conv (str):
780                 str = re.sub ('([Cc])hord([ea])', '\\1ord\\2', str)
781                 return str
782         
783         conversions.append (((1,3,144), conv, 'Chorda -> Corda'))
784
785
786 if 1:
787         def conv (str):
788                 str = re.sub ('([A-Za-z]+)MinimumVerticalExtent', 'MinimumV@rticalExtent', str)
789                 str = re.sub ('([A-Za-z]+)ExtraVerticalExtent', 'ExtraV@rticalExtent', str)
790                 str = re.sub ('([A-Za-z]+)VerticalExtent', 'VerticalExtent', str)
791                 str = re.sub ('ExtraV@rticalExtent', 'ExtraVerticalExtent', str)
792                 str = re.sub ('MinimumV@rticalExtent', 'MinimumVerticalExtent', str)            
793                 return str
794
795         conversions.append (((1,3,145), conv,
796         'ContextNameXxxxVerticalExtent -> XxxxVerticalExtent'))
797
798 if 1:
799         def conv (str):
800                 str = re.sub ('\\\\key[ \t]*;', '\\key \\default;', str)
801                 str = re.sub ('\\\\mark[ \t]*;', '\\mark \\default;', str)
802
803                 # Make sure groups of more than one ; have space before
804                 # them, so that non of them gets removed by next rule
805                 str = re.sub ("([^ \n\t;]);(;+)", "\\1 ;\\2", str)
806                 
807                 # Only remove ; that are not after spaces, # or ;
808                 # Otherwise  we interfere with Scheme comments,
809                 # which is badbadbad.
810                 str = re.sub ("([^ \t;#]);", "\\1", str)
811
812                 return str
813         conversions.append (((1,3,146), conv, 'semicolons removed'))
814
815 if 1:
816         def conv (str):
817                 str = re.sub ('default-neutral-direction', 'neutral-direction',str)
818                 return str
819         conversions.append (((1,3,147), conv, 'default-neutral-direction -> neutral-direction'))
820
821 if 1:
822         def conv (str):
823                 str = re.sub ('\(align', '(axis', str)
824                 str = re.sub ('\(rows', '(columns', str)
825                 return str
826         conversions.append (((1,3,148), conv, '"(align" -> "(axis", "(rows" -> "(columns"'))
827
828
829 if 1:
830         def conv (str):
831                 str = re.sub ('SystemStartDelimiter', 'systemStartDelimiter', str)
832                 return str
833         conversions.append (((1,5,33), conv, 'SystemStartDelimiter -> systemStartDelimiter'))
834
835 if 1:
836         def conv (str):
837                 str = re.sub ('arithmetic-multiplier', 'spacing-increment', str)
838                 str = re.sub ('arithmetic-basicspace', 'shortest-duration-space', str)          
839                 return str
840         
841         conversions.append (((1,5,38), conv, 'SystemStartDelimiter -> systemStartDelimiter'))
842
843
844 if 1:
845         def conv (str):
846         
847                 def func(match):
848                         break_dict = {
849                         "Instrument_name": "instrument-name",
850                         "Left_edge_item": "left-edge",
851                         "Span_bar": "span-bar",
852                         "Breathing_sign": "breathing-sign",
853                         "Staff_bar": "staff-bar",
854                         "Clef_item": "clef",
855                         "Key_item": "key-signature",
856                         "Time_signature": "time-signature",
857                         "Custos": "custos"
858                         }
859                         props =  match.group (1)
860                         for (k,v) in break_dict.items():
861                                 props = re.sub (k, v, props)
862                         return  "breakAlignOrder = #'(%s)" % props
863
864                 str = re.sub ("breakAlignOrder *= *#'\\(([a-z_\n\tA-Z ]+)\\)",
865                               func, str)
866                 return str
867
868         # 40 ? 
869         conversions.append (((1,5,40), conv, 'breakAlignOrder property names'))
870         
871
872 if 1:
873         def conv (str):
874                 str = re.sub ('noAutoBeaming *= *##f', 'autoBeaming = ##t', str)
875                 str = re.sub ('noAutoBeaming *= *##t', 'autoBeaming = ##f', str)
876                 return str
877         
878         conversions.append (((1,5,49), conv, 'noAutoBeaming -> autoBeaming'))
879
880 if 1:
881         def conv (str):
882                 str = re.sub ('tuplet-bracket-visibility', 'bracket-visibility', str)
883                 str = re.sub ('tuplet-number-visibility', 'number-visibility', str)             
884                 return str
885         
886         conversions.append (((1,5,52), conv, 'tuplet-X-visibility -> X-visibility'))
887
888 if 1:
889         def conv (str):
890                 str = re.sub ('Pitch::transpose', 'ly-transpose-pitch', str)
891
892                 return str
893         
894         conversions.append (((1,5,56), conv, 'Pitch::transpose -> ly-transpose-pitch'))
895
896 if 1:
897         def conv (str):
898                 str = re.sub ('textNonEmpty *= *##t', "TextScript \\set #'no-spacing-rods = ##f", str)
899                 str = re.sub ('textNonEmpty *= *##f', "TextScript \\set #'no-spacing-rods = ##t", str)
900                 return str
901         
902         conversions.append (((1,5,58), conv, 'deprecate textNonEmpty'))
903
904
905 if 1:
906         def conv (str):
907                 str = re.sub ('MinimumVerticalExtent', 'MinimumV@rticalExtent', str)
908                 str = re.sub ('ExtraVerticalExtent', 'ExtraV@rticalExtent', str)
909                 str = re.sub ('VerticalExtent', 'verticalExtent', str)
910                 str = re.sub ('ExtraV@rticalExtent', 'extraVerticalExtent', str)
911                 str = re.sub ('MinimumV@rticalExtent', 'minimumVerticalExtent', str)            
912                 return str
913
914         conversions.append (((1,5,59), conv,
915         'XxxxVerticalExtent -> xxxVerticalExtent'))
916
917 if 1:
918         def conv (str):
919                 str = re.sub ('visibility-lambda', 'break-visibility', str)
920                 return str
921
922         conversions.append (((1,5,62), conv,
923         'visibility-lambda -> break-visibility'))
924         
925
926 if 1:
927         def conv (str):
928                 if re.search (r'\addlyrics',str) \
929                        and re.search ('automaticMelismata', str)  == None:
930                         sys.stderr.write  ('automaticMelismata is turned on by default since 1.5.67. Please fix this by hand.')
931                         raise FatalConversionError()
932                 return str
933
934         conversions.append (((1,5,67), conv,
935                              'automaticMelismata turned on by default'))
936
937 if 1:
938         def conv (str):
939                 str = re.sub ('ly-set-grob-property', 'ly-set-grob-property!', str)
940                 str = re.sub ('ly-set-mus-property', 'ly-set-mus-property!', str)               
941                 return str
942         
943         conversions.append (((1,5,68), conv, 'ly-set-X-property -> ly-set-X-property!'))
944
945 ################################
946 #       END OF CONVERSIONS      
947 ################################
948
949 def get_conversions (from_version, to_version):
950         def version_b (v, f = from_version, t = to_version):
951                 return version_cmp (v[0], f) > 0 and version_cmp (v[0], t) <= 0
952         return filter (version_b, conversions)
953
954
955 def latest_version ():
956         return conversions[-1][0]
957
958 def do_conversion (infile, from_version, outfile, to_version):
959         conv_list = get_conversions (from_version, to_version)
960
961         sys.stderr.write ('Applying conversions: ')
962         str = infile.read ()
963         last_conversion = ()
964         try:
965                 for x in conv_list:
966                         sys.stderr.write (tup_to_str (x[0])  + ', ')
967                         str = x[1] (str)
968                         last_conversion = x[0]
969
970         except FatalConversionError:
971                 sys.stderr.write ('Error while converting; I won\'t convert any further')
972
973         if last_conversion:
974                 sys.stderr.write ('\n')
975                 new_ver =  '\\version \"%s\"' % tup_to_str (last_conversion)
976
977                 if re.search (lilypond_version_re_str, str):
978                         str = re.sub (lilypond_version_re_str,'\\'+new_ver , str)
979                 elif add_version:
980                         str = new_ver + '\n' + str
981
982                 outfile.write(str)
983
984         return last_conversion
985         
986 class UnknownVersion:
987         pass
988
989 def do_one_file (infile_name):
990         sys.stderr.write ('Processing `%s\' ... '% infile_name)
991         outfile_name = ''
992         if __main__.edit:
993                 outfile_name = infile_name + '.NEW'
994         elif __main__.outfile_name:
995                 outfile_name = __main__.outfile_name
996
997         if __main__.from_version:
998                 from_version = __main__.from_version
999         else:
1000                 guess = guess_lilypond_version (infile_name)
1001                 if not guess:
1002                         raise UnknownVersion()
1003                 from_version = str_to_tuple (guess)
1004
1005         if __main__.to_version:
1006                 to_version = __main__.to_version
1007         else:
1008                 to_version = latest_version ()
1009
1010
1011         if infile_name:
1012                 infile = open (infile_name,'r')
1013         else:
1014                 infile = sys.stdin
1015
1016         if outfile_name:
1017                 outfile =  open (outfile_name, 'w')
1018         else:
1019                 outfile = sys.stdout
1020
1021         touched = do_conversion (infile, from_version, outfile, to_version)
1022
1023         if infile_name:
1024                 infile.close ()
1025
1026         if outfile_name:
1027                 outfile.close ()
1028
1029         if __main__.edit and touched:
1030                 try:
1031                         os.remove(infile_name + '~')
1032                 except:
1033                         pass
1034                 os.rename (infile_name, infile_name + '~')
1035                 os.rename (infile_name + '.NEW', infile_name)
1036
1037         sys.stderr.write ('\n')
1038         sys.stderr.flush ()
1039
1040 edit = 0
1041 assume_old = 0
1042 to_version = ()
1043 from_version = ()
1044 outfile_name = ''
1045
1046 (options, files) = getopt.getopt (
1047         sys.argv[1:], 'ao:f:t:senh', ['no-version', 'assume-old', 'version', 'output', 'show-rules', 'help', 'edit', 'from=', 'to='])
1048
1049 for opt in options:
1050         o = opt[0]
1051         a = opt[1]
1052         if o== '--help' or o == '-h':
1053                 usage ()
1054                 sys.exit (0)
1055         if o == '--version' or o == '-v':
1056                 print_version ()
1057                 sys.exit (0)
1058         elif o== '--from' or o=='-f':
1059                 from_version = str_to_tuple (a)
1060         elif o== '--to' or o=='-t':
1061                 to_version = str_to_tuple (a)
1062         elif o== '--edit' or o == '-e':
1063                 edit = 1
1064         elif o== '--show-rules' or o == '-s':
1065                 show_rules (sys.stdout)
1066                 sys.exit(0)
1067         elif o == '--output' or o == '-o':
1068                 outfile_name = a
1069         elif o == '--assume-old' or o == '-a':
1070                 assume_old = 1
1071         elif o == '--no-version' or o == '-n':
1072                 add_version = 0
1073         else:
1074                 print o
1075                 raise getopt.error
1076
1077 identify ()
1078 for f in files:
1079         if f == '-':
1080                 f = ''
1081         if not os.path.isfile (f):
1082                 continue
1083         try:
1084                 do_one_file (f)
1085         except UnknownVersion:
1086                 sys.stderr.write ('\n')
1087                 sys.stderr.write ("%s: can't determine version for `%s'" % (program_name, f))
1088                 sys.stderr.write ('\n')
1089                 if assume_old:
1090                         fv = from_version
1091                         from_version = (0,0,0)
1092                         do_one_file (f)
1093                         from_version = fv
1094                 else:
1095                         sys.stderr.write ("%s: skipping: `%s' " % (program_name,  f))
1096                 pass
1097 sys.stderr.write ('\n')