]> git.donarmstrong.com Git - lilypond.git/blob - scripts/convert-ly.py
* scm/grob-description.scm (all-grob-descriptions): set
[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 if 1:
844         def conv (str):
845                 str = re.sub ('noAutoBeaming *= *##f', 'autoBeaming = ##t', str)
846                 str = re.sub ('noAutoBeaming *= *##t', 'autoBeaming = ##f', str)
847                 return str
848         
849         conversions.append (((1,5,49), conv, 'noAutoBeaming -> autoBeaming'))
850
851 if 1:
852         def conv (str):
853                 str = re.sub ('tuplet-bracket-visibility', 'bracket-visibility', str)
854                 str = re.sub ('tuplet-number-visibility', 'number-visibility', str)             
855                 return str
856         
857         conversions.append (((1,5,52), conv, 'tuplet-X-visibility -> X-visibility'))
858
859 if 1:
860         def conv (str):
861                 str = re.sub ('Pitch::transpose', 'ly-transpose-pitch', str)
862
863                 return str
864         
865         conversions.append (((1,5,56), conv, 'Pitch::transpose -> ly-transpose-pitch'))
866
867 if 1:
868         def conv (str):
869                 str = re.sub ('textNonEmpty *= *##t', "TextScript \\set #'no-spacing-rods = ##f", str)
870                 str = re.sub ('textNonEmpty *= *##f', "TextScript \\set #'no-spacing-rods = ##t", str)
871                 return str
872         
873         conversions.append (((1,5,58), conv, 'deprecate textNonEmpty'))
874
875
876 if 1:
877         def conv (str):
878                 str = re.sub ('MinimumVerticalExtent', 'MinimumV@rticalExtent', str)
879                 str = re.sub ('ExtraVerticalExtent', 'ExtraV@rticalExtent', str)
880                 str = re.sub ('VerticalExtent', 'verticalExtent', str)
881                 str = re.sub ('ExtraV@rticalExtent', 'extraVerticalExtent', str)
882                 str = re.sub ('MinimumV@rticalExtent', 'minimumVerticalExtent', str)            
883                 return str
884
885         conversions.append (((1,5,59), conv,
886         'XxxxVerticalExtent -> xxxVerticalExtent'))
887
888 if 1:
889         def conv (str):
890                 str = re.sub ('visibility-lambda', 'break-visibility', str)
891                 return str
892
893         conversions.append (((1,5,62), conv,
894         'visibility-lambda -> break-visibility'))
895         
896
897 if 1:
898         def conv (str):
899                 if re.search (r'\addlyrics',str) \
900                        and re.search ('automaticMelismata', str)  == None:
901                         sys.stderr.write  ('automaticMelismata is turned on by default since 1.5.67. Please fix this by hand.')
902                         raise FatalConversionError()
903                 return str
904
905         conversions.append (((1,5,67), conv,
906                              'automaticMelismata turned on by default'))
907
908 if 1:
909         def conv (str):
910                 str = re.sub ('ly-set-grob-property', 'ly-set-grob-property!', str)
911                 str = re.sub ('ly-set-mus-property', 'ly-set-mus-property!', str)               
912                 return str
913         
914         conversions.append (((1,5,68), conv, 'ly-set-X-property -> ly-set-X-property!'))
915
916 if 1:
917         def conv (str):
918                 break_dict = {
919                 "Instrument_name": "instrument-name",
920                 "Left_edge_item": "left-edge",
921                 "Span_bar": "span-bar",
922                 "Breathing_sign": "breathing-sign",
923                 "Staff_bar": "staff-bar",
924                 "Clef_item": "clef",
925                 "Key_item": "key-signature",
926                 "Time_signature": "time-signature",
927                 "Custos": "custos"
928                 }
929                 def func(match):
930                         props =  m.group (1)
931                         for (k,v) in break_dict.items():
932                                 props = re.sub (k, v, props)
933
934                         
935                         return  "breakAlignOrder = #'( %s )" % props
936                 str = re.sub (r"breakAlignOrder *= *#'\(([a-z_A-Z ]+)\)", func, str)
937                 return str
938
939         # 40 ? 
940         conversions.append (((1,5,40), conv, 'breakAlignOrder property names'))
941         
942
943 ################################
944 #       END OF CONVERSIONS      
945 ################################
946
947 def get_conversions (from_version, to_version):
948         def version_b (v, f = from_version, t = to_version):
949                 return version_cmp (v[0], f) > 0 and version_cmp (v[0], t) <= 0
950         return filter (version_b, conversions)
951
952
953 def latest_version ():
954         return conversions[-1][0]
955
956 def do_conversion (infile, from_version, outfile, to_version):
957         conv_list = get_conversions (from_version, to_version)
958
959         sys.stderr.write ('Applying conversions: ')
960         str = infile.read ()
961         last_conversion = ()
962         try:
963                 for x in conv_list:
964                         sys.stderr.write (tup_to_str (x[0])  + ', ')
965                         str = x[1] (str)
966                         last_conversion = x[0]
967
968         except FatalConversionError:
969                 sys.stderr.write ('Error while converting; I won\'t convert any further')
970
971         if last_conversion:
972                 sys.stderr.write ('\n')
973                 new_ver =  '\\version \"%s\"' % tup_to_str (last_conversion)
974
975                 if re.search (lilypond_version_re_str, str):
976                         str = re.sub (lilypond_version_re_str,'\\'+new_ver , str)
977                 elif add_version:
978                         str = new_ver + '\n' + str
979
980                 outfile.write(str)
981
982         return last_conversion
983         
984 class UnknownVersion:
985         pass
986
987 def do_one_file (infile_name):
988         sys.stderr.write ('Processing `%s\' ... '% infile_name)
989         outfile_name = ''
990         if __main__.edit:
991                 outfile_name = infile_name + '.NEW'
992         elif __main__.outfile_name:
993                 outfile_name = __main__.outfile_name
994
995         if __main__.from_version:
996                 from_version = __main__.from_version
997         else:
998                 guess = guess_lilypond_version (infile_name)
999                 if not guess:
1000                         raise UnknownVersion()
1001                 from_version = str_to_tuple (guess)
1002
1003         if __main__.to_version:
1004                 to_version = __main__.to_version
1005         else:
1006                 to_version = latest_version ()
1007
1008
1009         if infile_name:
1010                 infile = open (infile_name,'r')
1011         else:
1012                 infile = sys.stdin
1013
1014         if outfile_name:
1015                 outfile =  open (outfile_name, 'w')
1016         else:
1017                 outfile = sys.stdout
1018
1019         touched = do_conversion (infile, from_version, outfile, to_version)
1020
1021         if infile_name:
1022                 infile.close ()
1023
1024         if outfile_name:
1025                 outfile.close ()
1026
1027         if __main__.edit and touched:
1028                 try:
1029                         os.remove(infile_name + '~')
1030                 except:
1031                         pass
1032                 os.rename (infile_name, infile_name + '~')
1033                 os.rename (infile_name + '.NEW', infile_name)
1034
1035         sys.stderr.write ('\n')
1036         sys.stderr.flush ()
1037
1038 edit = 0
1039 assume_old = 0
1040 to_version = ()
1041 from_version = ()
1042 outfile_name = ''
1043
1044 (options, files) = getopt.getopt (
1045         sys.argv[1:], 'ao:f:t:senh', ['no-version', 'assume-old', 'version', 'output', 'show-rules', 'help', 'edit', 'from=', 'to='])
1046
1047 for opt in options:
1048         o = opt[0]
1049         a = opt[1]
1050         if o== '--help' or o == '-h':
1051                 usage ()
1052                 sys.exit (0)
1053         if o == '--version' or o == '-v':
1054                 print_version ()
1055                 sys.exit (0)
1056         elif o== '--from' or o=='-f':
1057                 from_version = str_to_tuple (a)
1058         elif o== '--to' or o=='-t':
1059                 to_version = str_to_tuple (a)
1060         elif o== '--edit' or o == '-e':
1061                 edit = 1
1062         elif o== '--show-rules' or o == '-s':
1063                 show_rules (sys.stdout)
1064                 sys.exit(0)
1065         elif o == '--output' or o == '-o':
1066                 outfile_name = a
1067         elif o == '--assume-old' or o == '-a':
1068                 assume_old = 1
1069         elif o == '--no-version' or o == '-n':
1070                 add_version = 0
1071         else:
1072                 print o
1073                 raise getopt.error
1074
1075 identify ()
1076 for f in files:
1077         if f == '-':
1078                 f = ''
1079         if not os.path.isfile (f):
1080                 continue
1081         try:
1082                 do_one_file (f)
1083         except UnknownVersion:
1084                 sys.stderr.write ('\n')
1085                 sys.stderr.write ("%s: can't determine version for `%s'" % (program_name, f))
1086                 sys.stderr.write ('\n')
1087                 if assume_old:
1088                         fv = from_version
1089                         from_version = (0,0,0)
1090                         do_one_file (f)
1091                         from_version = fv
1092                 else:
1093                         sys.stderr.write ("%s: skipping: `%s' " % (program_name,  f))
1094                 pass
1095 sys.stderr.write ('\n')