]> git.donarmstrong.com Git - lilypond.git/blob - scripts/convert-ly.py
910d57d5a7cb8daa4829214bc955bf3fa36dcf19
[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 ('minimumVerticalExtent', 'minimumV@rticalExtent', str)            
909                 str = re.sub ('ExtraVerticalExtent', 'extraV@rticalExtent', str)
910                 str = re.sub ('extraVerticalExtent', 'extraV@rticalExtent', str)                
911                 str = re.sub ('VerticalExtent', 'verticalExtent', str)
912                 str = re.sub ('extraV@rticalExtent', 'extraVerticalExtent', str)
913                 str = re.sub ('minimumV@rticalExtent', 'minimumVerticalExtent', str)            
914                 return str
915
916         conversions.append (((1,5,59), conv,
917         'XxxxVerticalExtent -> xxxVerticalExtent'))
918
919 if 1:
920         def conv (str):
921                 str = re.sub ('visibility-lambda', 'break-visibility', str)
922                 return str
923
924         conversions.append (((1,5,62), conv,
925         'visibility-lambda -> break-visibility'))
926         
927
928 if 1:
929         def conv (str):
930                 if re.search (r'\addlyrics',str) \
931                        and re.search ('automaticMelismata', str)  == None:
932                         sys.stderr.write  ('automaticMelismata is turned on by default since 1.5.67. Please fix this by hand.')
933                         raise FatalConversionError()
934                 return str
935
936         conversions.append (((1,5,67), conv,
937                              'automaticMelismata turned on by default'))
938
939 if 1:
940         def conv (str):
941                 str = re.sub ('ly-set-grob-property([^!])', 'ly-set-grob-property!\1', str)
942                 str = re.sub ('ly-set-mus-property([^!])', 'ly-set-mus-property!\1', str)               
943                 return str
944         
945         conversions.append (((1,5,68), conv, 'ly-set-X-property -> ly-set-X-property!'))
946
947 if 1:
948         def conv (str):
949                 str = re.sub ('extent-X', 'X-extent', str)
950                 str = re.sub ('extent-Y', 'Y-extent', str)              
951                 return str
952         
953         conversions.append (((1,5,71), conv, 'extent-[XY] -> [XY]-extent'))
954
955
956 if 1:
957         def conv (str):
958                 str = re.sub ("""#\(set! +point-and-click +line-column-location\)""",
959                               """#(set-point-and-click! \'line-column)""", str)
960                 str = re.sub ("""#\(set![ \t]+point-and-click +line-location\)""",
961                               '#(set-point-and-click! \'line)', str)
962                 str = re.sub ('#\(set! +point-and-click +#f\)',
963                               '#(set-point-and-click! \'none)', str)
964                 return str
965         
966         conversions.append (((1,5,72), conv, 'set! point-and-click -> set-point-and-click!'))
967
968
969 if 1:
970         def conv (str):
971                 str = re.sub ('flag-style', 'stroke-style', str)
972                 str = re.sub (r"""Stem([ ]+)\\override #'style""", r"""Stem \\override #'flag-style""", str);
973                 str = re.sub (r"""Stem([ ]+)\\set([ ]+)#'style""", r"""Stem \\set #'flag-style""", str);
974                 return str
975         
976         conversions.append (((1,6,5), conv, 'Stems: flag-style -> stroke-style; style -> flag-style'))
977
978
979 if 1:
980         def subst_req_name (match):
981                 return "(make-music-by-name \'%sEvent)" % regularize_id (match.group(1))
982
983         def conv (str):
984                 str = re.sub ('\\(ly-make-music *\"([A-Z][a-z_]+)_req\"\\)', subst_req_name, str)
985                 str = re.sub ('Request_chord', 'EventChord', str)
986                 return str
987         
988         conversions.append (((1,7,1), conv, 'ly-make-music foo_bar_req -> make-music-by-name FooBarEvent'))
989
990
991 if 1:
992         spanner_subst ={
993                 "text" : 'TextSpanEvent',
994                 "decrescendo" : 'DecrescendoEvent',
995                 "crescendo" : 'CrescendoEvent',
996                 "Sustain" : 'SustainPedalEvent',
997                 "slur" : 'SlurEvent',
998                 "UnaCorda" : 'UnaCordaEvent',
999                 "Sostenuto" : 'SostenutoEvent',
1000                 }
1001         def subst_ev_name (match):
1002                 stype = 'STOP'
1003                 if re.search ('start', match.group(1)):
1004                         stype= 'START'
1005
1006                 mtype = spanner_subst[match.group(2)]
1007                 return "(make-span-event '%s %s)" % (mtype , stype)
1008
1009         def subst_definition_ev_name(match):
1010                 return ' = #%s' % subst_ev_name (match) 
1011         def subst_inline_ev_name (match):
1012                 s = subst_ev_name (match)
1013                 return '#(ly-export %s)' % s
1014         def subst_csp_definition (match):
1015                 return ' = #(make-event-chord (list %s))' % subst_ev_name (match)
1016         def subst_csp_inline (match):
1017                 return '#(ly-export (make-event-chord (list %s)))' % subst_ev_name (match)
1018                 
1019         def conv (str):
1020                 str = re.sub (r' *= *\\spanrequest *([^ ]+) *"([^"]+)"', subst_definition_ev_name, str)
1021                 str = re.sub (r'\\spanrequest *([^ ]+) *"([^"]+)"', subst_inline_ev_name, str)
1022                 str = re.sub (r' *= *\\commandspanrequest *([^ ]+) *"([^"]+)"', subst_csp_definition, str)
1023                 str = re.sub (r'\\commandspanrequest *([^ ]+) *"([^"]+)"', subst_csp_inline, str)
1024                 str = re.sub (r'ly-id ', 'ly-import ', str)
1025
1026                 str = re.sub (r' *= *\\script "([^"]+)"', ' = #(make-articulation "\\1")', str)
1027                 str = re.sub (r'\\script "([^"]+)"', '#(ly-export (make-articulation "\\1"))', str)
1028                 return str
1029
1030         conversions.append (((1,7,2), conv, '\\spanrequest -> #(make-span-event .. ), \script -> #(make-articulation .. )'))
1031
1032 if 1:
1033         def conv(str):
1034                 str = re.sub (r'\(ly-', '(ly:', str)
1035
1036                 changed = [
1037                         r'duration\?',
1038                         r'font-metric\?',
1039                         r'molecule\?',
1040                         r'moment\?',
1041                         r'music\?',
1042                         r'pitch\?',
1043                         'make-duration',
1044                         'music-duration-length',
1045                         'duration-log',
1046                         'duration-dotcount',
1047                         'intlog2',
1048                         'duration-factor',
1049                         'transpose-key-alist',
1050                         'get-system',
1051                         'get-broken-into',
1052                         'get-original',
1053                         'set-point-and-click!',
1054                         'make-moment',
1055                         'make-pitch',
1056                         'pitch-octave',
1057                         'pitch-alteration',
1058                         'pitch-notename',
1059                         'pitch-semitones',
1060                         r'pitch<\?',
1061                         r'dir\?',
1062                         'music-duration-compress',
1063                         'set-point-and-click!'
1064                         ]
1065
1066                 origre = r'\b(%s)' % string.join (changed, '|')
1067                 
1068                 str = re.sub (origre, r'ly:\1',str)
1069                 str = re.sub ('set-point-and-click!', 'set-point-and-click', str)
1070                 
1071                 return str
1072         
1073         conversions.append (((1,7,3), conv, 'ly- -> ly:'))
1074
1075 if 1:
1076         def conv(str):
1077                 str = re.sub (r'<<', '< <', str)
1078                 str = re.sub (r'>>', '> >', str)
1079
1080                 return str
1081         
1082         conversions.append (((1,7,4), conv, '<< >> -> < <  > >'))
1083
1084
1085 ################################
1086 #       END OF CONVERSIONS      
1087 ################################
1088
1089 def get_conversions (from_version, to_version):
1090         def version_b (v, f = from_version, t = to_version):
1091                 return version_cmp (v[0], f) > 0 and version_cmp (v[0], t) <= 0
1092         return filter (version_b, conversions)
1093
1094
1095 def latest_version ():
1096         return conversions[-1][0]
1097
1098 def do_conversion (infile, from_version, outfile, to_version):
1099         conv_list = get_conversions (from_version, to_version)
1100
1101         sys.stderr.write ('Applying conversions: ')
1102         str = infile.read ()
1103         last_conversion = ()
1104         try:
1105                 for x in conv_list:
1106                         sys.stderr.write (tup_to_str (x[0])  + ', ')
1107                         str = x[1] (str)
1108                         last_conversion = x[0]
1109
1110         except FatalConversionError:
1111                 sys.stderr.write ('Error while converting; I won\'t convert any further')
1112
1113         if last_conversion:
1114                 sys.stderr.write ('\n')
1115                 new_ver =  '\\version \"%s\"' % tup_to_str (last_conversion)
1116
1117                 if re.search (lilypond_version_re_str, str):
1118                         str = re.sub (lilypond_version_re_str,'\\'+new_ver , str)
1119                 elif add_version:
1120                         str = new_ver + '\n' + str
1121
1122                 outfile.write(str)
1123
1124         return last_conversion
1125         
1126 class UnknownVersion:
1127         pass
1128
1129 def do_one_file (infile_name):
1130         sys.stderr.write ('Processing `%s\' ... '% infile_name)
1131         outfile_name = ''
1132         if __main__.edit:
1133                 outfile_name = infile_name + '.NEW'
1134         elif __main__.outfile_name:
1135                 outfile_name = __main__.outfile_name
1136
1137         if __main__.from_version:
1138                 from_version = __main__.from_version
1139         else:
1140                 guess = guess_lilypond_version (infile_name)
1141                 if not guess:
1142                         raise UnknownVersion()
1143                 from_version = str_to_tuple (guess)
1144
1145         if __main__.to_version:
1146                 to_version = __main__.to_version
1147         else:
1148                 to_version = latest_version ()
1149
1150
1151         if infile_name:
1152                 infile = open (infile_name,'r')
1153         else:
1154                 infile = sys.stdin
1155
1156         if outfile_name:
1157                 outfile =  open (outfile_name, 'w')
1158         else:
1159                 outfile = sys.stdout
1160
1161         touched = do_conversion (infile, from_version, outfile, to_version)
1162
1163         if infile_name:
1164                 infile.close ()
1165
1166         if outfile_name:
1167                 outfile.close ()
1168
1169         if __main__.edit and touched:
1170                 try:
1171                         os.remove(infile_name + '~')
1172                 except:
1173                         pass
1174                 os.rename (infile_name, infile_name + '~')
1175                 os.rename (infile_name + '.NEW', infile_name)
1176
1177         sys.stderr.write ('\n')
1178         sys.stderr.flush ()
1179
1180 edit = 0
1181 assume_old = 0
1182 to_version = ()
1183 from_version = ()
1184 outfile_name = ''
1185
1186 (options, files) = getopt.getopt (
1187         sys.argv[1:], 'ao:f:t:senh', ['no-version', 'assume-old', 'version', 'output', 'show-rules', 'help', 'edit', 'from=', 'to='])
1188
1189 for opt in options:
1190         o = opt[0]
1191         a = opt[1]
1192         if o== '--help' or o == '-h':
1193                 usage ()
1194                 sys.exit (0)
1195         if o == '--version' or o == '-v':
1196                 print_version ()
1197                 sys.exit (0)
1198         elif o== '--from' or o=='-f':
1199                 from_version = str_to_tuple (a)
1200         elif o== '--to' or o=='-t':
1201                 to_version = str_to_tuple (a)
1202         elif o== '--edit' or o == '-e':
1203                 edit = 1
1204         elif o== '--show-rules' or o == '-s':
1205                 show_rules (sys.stdout)
1206                 sys.exit(0)
1207         elif o == '--output' or o == '-o':
1208                 outfile_name = a
1209         elif o == '--assume-old' or o == '-a':
1210                 assume_old = 1
1211         elif o == '--no-version' or o == '-n':
1212                 add_version = 0
1213         else:
1214                 print o
1215                 raise getopt.error
1216
1217 identify ()
1218 for f in files:
1219         if f == '-':
1220                 f = ''
1221         if not os.path.isfile (f):
1222                 continue
1223         try:
1224                 do_one_file (f)
1225         except UnknownVersion:
1226                 sys.stderr.write ('\n')
1227                 sys.stderr.write ("%s: can't determine version for `%s'" % (program_name, f))
1228                 sys.stderr.write ('\n')
1229                 if assume_old:
1230                         fv = from_version
1231                         from_version = (0,0,0)
1232                         do_one_file (f)
1233                         from_version = fv
1234                 else:
1235                         sys.stderr.write ("%s: skipping: `%s' " % (program_name,  f))
1236                 pass
1237 sys.stderr.write ('\n')