release commit
[lilypond.git] / scripts / convert-ly.py
blobb571c8330b4dc850686e630fa903202a7e0d5e7d
1 #!@PYTHON@
3 # convert-ly.py -- convertor for lilypond versions
4 #
5 # source file of the GNU LilyPond music typesetter
6 #
7 # (c) 1998--2001
9 # TODO
10 # use -f and -t for -s output
12 # NEWS
13 # 0.2
14 # - rewrite in python
16 program_name = 'convert-ly'
17 version = '@TOPLEVEL_VERSION@'
19 import os
20 import sys
21 import __main__
22 import getopt
23 import string
24 import re
25 import time
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
34 def program_id ():
35 return '%s (GNU LilyPond) %s' %(program_name, version);
37 def identify ():
38 sys.stderr.write (program_id () + '\n')
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
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
56 Report bugs to bugs-gnu-music@gnu.org
58 """ % program_name)
61 sys.exit (0)
63 def print_version ():
65 sys.stdout.write (r"""%s
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.
72 """ % (program_id() , program_name))
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
89 def str_to_tuple (s):
90 return tuple (map (string.atoi, string.split (s,'.')))
92 def tup_to_str (t):
93 return string.join (map (lambda x: '%s' % x, list (t)), '.')
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
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 ''
109 class FatalConversionError:
110 pass
112 conversions = []
114 def show_rules (file):
115 for x in conversions:
116 file.write ('%s: %s\n' % (tup_to_str (x[0]), x[2]))
118 ############################
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
126 conversions.append (((0,1,9), conv, '\\header { key = concat + with + operator }'))
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()
134 return str
136 conversions.append ((
137 ((0,1,19), conv, 'deprecated \\octave; can\'t convert automatically')))
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)
147 return str
149 conversions.append ((
150 ((0,1,20), conv, 'deprecated \\textstyle, new \key syntax')))
153 if 1:
154 def conv (str):
155 str = re.sub ('\\\\musical_pitch', '\\\\musicalpitch',str)
156 str = re.sub ('\\\\meter', '\\\\time',str)
158 return str
160 conversions.append ((
161 ((0,1,21), conv, '\\musical_pitch -> \\musicalpitch, '+
162 '\\meter -> \\time')))
164 if 1:
165 def conv (str):
166 return str
168 conversions.append ((
169 ((1,0,0), conv, '0.1.21 -> 1.0.0 ')))
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)
178 return str
180 conversions.append ((
181 ((1,0,1), conv, '\\accidentals -> \\keysignature, ' +
182 'specialaccidentals -> keyoctaviation')))
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
190 conversions.append (((1,0,2), conv, '\\header { key = concat + with + operator }'))
192 if 1:
193 def conv(str):
194 str = re.sub ('\\\\melodic([^a-zA-Z])', '\\\\notes\\1',str)
195 return str
197 conversions.append (((1,0,3), conv, '\\melodic -> \\notes'))
199 if 1:
200 def conv(str):
201 str = re.sub ('default_paper *=', '',str)
202 str = re.sub ('default_midi *=', '',str)
203 return str
205 conversions.append (((1,0,4), conv, 'default_{paper,midi}'))
207 if 1:
208 def conv(str):
209 str = re.sub ('ChoireStaff', 'ChoirStaff',str)
210 str = re.sub ('\\\\output', 'output = ',str)
212 return str
214 conversions.append (((1,0,5), conv, 'ChoireStaff -> ChoirStaff'))
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
223 conversions.append (((1,0,6), conv, 'foo = \\translator {\\type .. } ->\\translator {\\type ..; foo; }'))
226 if 1:
227 def conv(str):
228 str = re.sub ('\\\\lyrics*', '\\\\lyrics',str)
230 return str
232 conversions.append (((1,0,7), conv, '\\lyric -> \\lyrics'))
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
245 conversions.append (((1,0,10), conv, '[2/3 ]1/1 -> \\times 2/3 '))
247 if 1:
248 def conv(str):
249 return str
250 conversions.append (((1,0,12), conv, 'Chord syntax stuff'))
253 if 1:
254 def conv(str):
257 str = re.sub ('<([^>~]+)~([^>]*)>','<\\1 \\2> ~', str)
259 return str
261 conversions.append (((1,0,13), conv, '<a ~ b> c -> <a b> ~ c'))
263 if 1:
264 def conv(str):
265 str = re.sub ('<\\[','[<', str)
266 str = re.sub ('\\]>','>]', str)
268 return str
270 conversions.append (((1,0,14), conv, '<[a b> <a b]>c -> [<a b> <a b>]'))
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)
281 return str
283 conversions.append (((1,0,16), conv, '\\type -> \\context, textstyle -> textStyle'))
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
293 conversions.append (((1,0,18), conv,
294 '\\repeat NUM Music Alternative -> \\repeat FOLDSTR Music Alternative'))
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)
302 return str
304 conversions.append (((1,0,19), conv,
305 'fontsize -> fontSize, midi_instrument -> midiInstrument, SkipBars -> skipBars'))
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)
314 return str
316 conversions.append (((1,0,20), conv,
317 '{,tie,slur}ydirection -> {v,tieV,slurV}erticalDirection'))
320 if 1:
321 def conv(str):
322 str = re.sub ('hshift','horizontalNoteShift', str)
324 return str
326 conversions.append (((1,0,21), conv,
327 'hshift -> horizontalNoteShift'))
330 if 1:
331 def conv(str):
332 str = re.sub ('\\\\grouping[^;]*;','', str)
334 return str
336 conversions.append (((1,1,52), conv,
337 'deprecate \\grouping'))
340 if 1:
341 def conv(str):
342 str = re.sub ('\\\\wheel','\\\\coda', str)
344 return str
346 conversions.append (((1,1,55), conv,
347 '\\wheel -> \\coda'))
349 if 1:
350 def conv(str):
351 str = re.sub ('keyoctaviation','keyOctaviation', str)
352 str = re.sub ('slurdash','slurDash', str)
354 return str
356 conversions.append (((1,1,65), conv,
357 'slurdash -> slurDash, keyoctaviation -> keyOctaviation'))
359 if 1:
360 def conv(str):
361 str = re.sub ('\\\\repeat *\"?semi\"?','\\\\repeat "volta"', str)
363 return str
365 conversions.append (((1,1,66), conv,
366 'semi -> volta'))
369 if 1:
370 def conv(str):
371 str = re.sub ('\"?beamAuto\"? *= *\"?0?\"?','noAutoBeaming = "1"', str)
373 return str
375 conversions.append (((1,1,67), conv,
376 'beamAuto -> noAutoBeaming'))
378 if 1:
379 def conv(str):
380 str = re.sub ('automaticMelismas', 'automaticMelismata', str)
382 return str
384 conversions.append (((1,2,0), conv,
385 'automaticMelismas -> automaticMelismata'))
387 if 1:
388 def conv(str):
389 str = re.sub ('dynamicDir\\b', 'dynamicDirection', str)
391 return str
393 conversions.append (((1,2,1), conv,
394 'dynamicDir -> dynamicDirection'))
396 if 1:
397 def conv(str):
398 str = re.sub ('\\\\cadenza *0 *;', '\\\\cadenzaOff', str)
399 str = re.sub ('\\\\cadenza *1 *;', '\\\\cadenzaOn', str)
401 return str
403 conversions.append (((1,3,4), conv,
404 '\\cadenza -> \cadenza{On|Off}'))
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
413 conversions.append (((1,3,5), conv, 'beamAuto moment properties'))
415 if 1:
416 def conv (str):
417 str = re.sub ('stemStyle',
418 'flagStyle',
419 str)
420 return str
422 conversions.append (((1,3,17), conv, 'stemStyle -> flagStyle'))
424 if 1:
425 def conv (str):
426 str = re.sub ('staffLineLeading',
427 'staffSpace',
428 str)
429 return str
431 conversions.append (((1,3,18), conv, 'staffLineLeading -> staffSpace'))
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
441 conversions.append (((1,3,23), conv,
442 '\\\\repetitions feature dropped'))
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
455 conversions.append (((1,3,35), conv, 'textEmptyDimension -> textNonEmpty'))
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
467 conversions.append (((1,3,38), conv, '\musicalpitch { a b c } -> #\'(a b c)'))
469 if 1:
470 def conv (str):
471 def replace (match):
472 return '\\key %s;' % string.lower (match.group (1))
474 str = re.sub ("\\\\key ([^;]+);", replace, str)
475 return str
477 conversions.append (((1,3,39), conv, '\\key A ; ->\\key a;'))
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
485 conversions.append (((1,3,41), conv,
486 '[:16 c4 d4 ] -> \\repeat "tremolo" 2 { c16 d16 }'))
488 if 1:
489 def conv (str):
490 str = re.sub ('Staff_margin_engraver' , 'Instrument_name_engraver', str)
491 return str
493 conversions.append (((1,3,42), conv,
494 'Staff_margin_engraver deprecated, use Instrument_name_engraver'))
496 if 1:
497 def conv (str):
498 str = re.sub ('note[hH]eadStyle\\s*=\\s*"?(\\w+)"?' , "noteHeadStyle = #'\\1", str)
499 return str
501 conversions.append (((1,3,49), conv,
502 'noteHeadStyle value: string -> symbol'))
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
511 conversions.append (((1,3,58), conv,
512 'noteHeadStyle value: string -> symbol'))
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; '))
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"'))
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)
539 str = re.sub ('basicClefItemProperties' ,"Clef", str)
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)
546 str = re.sub ('Repeat_engraver' ,'Volta_engraver', str)
547 return str
549 conversions.append (((1,3,92), conv, 'basicXXXProperties -> XXX, Repeat_engraver -> Volta_engraver'))
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)
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)
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)
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)
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)
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)
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)
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)
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)
600 str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)Dash[^=]*= *#?"?(0|(""))"?', '\\\\\\1NoDots', str)
601 str = re.sub ('\\\\property *[^ .]*[.]?([a-z]+)Dash[^=]*= *#?"?([1-9]+)"?', '\\\\\\1Dotted', str)
603 str = re.sub ('\\\\property *[^ .]*[.]?noAutoBeaming[^=]*= *#?"?(0|(""))"?', '\\\\autoBeamOn', str)
604 str = re.sub ('\\\\property *[^ .]*[.]?noAutoBeaming[^=]*= *#?"?([1-9]+)"?', '\\\\autoBeamOff', str)
608 return str
610 conversions.append (((1,3,93), conv,
611 'property definiton case (eg. onevoice -> oneVoice)'))
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')
620 str = re.sub ('\\textscript +("[^"]*")', '\\textscript #\\1', str)
622 return str
624 conversions.append (((1,3,97), conv, 'ChordName -> ChordNames'))
627 # TODO: add lots of these
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)
634 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?timeSignatureStyle"? *= *"([^"]*)"', '\\\\property \\1.TimeSignature \\\\override #\'style = #\'\\2', str)
636 str = re.sub ('"?timeSignatureStyle"? *= *#?""', 'TimeSignature \\\\override #\'style = ##f', str)
638 str = re.sub ('"?timeSignatureStyle"? *= *#?"([^"]*)"', 'TimeSignature \\\\override #\'style = #\'\\1', str)
640 str = re.sub ('#\'style *= #*"([^"])"', '#\'style = #\'\\1', str)
642 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?horizontalNoteShift"? *= *"?#?([-0-9]+)"?', '\\\\property \\1.NoteColumn \\\\override #\'horizontal-shift = #\\2', str)
644 # ugh
645 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?flagStyle"? *= *""', '\\\\property \\1.Stem \\\\override #\'flag-style = ##f', str)
647 str = re.sub ('\\\\property *"?([^.]+)"? *[.] *"?flagStyle"? *= *"([^"]*)"', '\\\\property \\1.Stem \\\\override #\'flag-style = #\'\\2', str)
648 return str
650 conversions.append (((1,3,98), conv, 'CONTEXT.textStyle -> GROB.#font-style '))
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)
660 return str
662 conversions.append (((1,3,102), conv, 'beamAutoEnd -> autoBeamSettings \\push (end * * * *)'))
665 if 1:
666 def conv (str):
667 str = re.sub ('\\\\push', '\\\\override', str)
668 str = re.sub ('\\\\pop', '\\\\revert', str)
670 return str
672 conversions.append (((1,3,111), conv, '\\push -> \\override, \\pop -> \\revert'))
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
682 conversions.append (((1,3,113), conv, 'LyricVoice -> LyricsVoice'))
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
701 if 1:
702 def conv (str):
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
712 conversions.append (((1,3,117), conv, 'identifier names: $!foo_bar_123 -> xfooBarABC'))
715 if 1:
716 def conv (str):
717 def regularize_paper (match):
718 return regularize_id (match.group (1))
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)
729 return str
731 conversions.append (((1,3,120), conv, 'paper_xxx -> paperXxxx, pedalup -> pedalUp.'))
733 if 1:
734 def conv (str):
735 str = re.sub ('drarnChords', 'chordChanges', str)
736 str = re.sub ('\\musicalpitch', '\\pitch', str)
737 return str
739 conversions.append (((1,3,122), conv, 'drarnChords -> chordChanges, \\musicalpitch -> \\pitch'))
741 if 1:
742 def conv (str):
743 str = re.sub ('ly-([sg])et-elt-property', 'ly-\\1et-grob-property', str)
744 return str
746 conversions.append (((1,3,136), conv, 'ly-X-elt-property -> ly-X-grob-property'))
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
753 conversions.append (((1,3,138), conv, 'point-and-click argument changed to procedure.'))
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
762 conversions.append (((1,3,138), conv, 'followThread -> followVoice.'))
764 if 1:
765 def conv (str):
766 str = re.sub ('font-point-size', 'font-design-size', str)
767 return str
769 conversions.append (((1,3,139), conv, 'font-point-size -> font-design-size.'))
771 if 1:
772 def conv (str):
773 str = re.sub ('([a-zA-Z]*)NoDots', '\\1Solid', str)
774 return str
776 conversions.append (((1,3,141), conv, 'xNoDots -> xSolid'))
778 if 1:
779 def conv (str):
780 str = re.sub ('([Cc])hord([ea])', '\\1ord\\2', str)
781 return str
783 conversions.append (((1,3,144), conv, 'Chorda -> Corda'))
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
795 conversions.append (((1,3,145), conv,
796 'ContextNameXxxxVerticalExtent -> XxxxVerticalExtent'))
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)
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)
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)
812 return str
813 conversions.append (((1,3,146), conv, 'semicolons removed'))
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'))
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"'))
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'))
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
841 conversions.append (((1,5,38), conv, 'SystemStartDelimiter -> systemStartDelimiter'))
844 if 1:
845 def conv (str):
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"
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
864 str = re.sub ("breakAlignOrder *= *#'\\(([a-z_\n\tA-Z ]+)\\)",
865 func, str)
866 return str
868 # 40 ?
869 conversions.append (((1,5,40), conv, 'breakAlignOrder property names'))
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
878 conversions.append (((1,5,49), conv, 'noAutoBeaming -> autoBeaming'))
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
886 conversions.append (((1,5,52), conv, 'tuplet-X-visibility -> X-visibility'))
888 if 1:
889 def conv (str):
890 str = re.sub ('Pitch::transpose', 'ly-transpose-pitch', str)
892 return str
894 conversions.append (((1,5,56), conv, 'Pitch::transpose -> ly-transpose-pitch'))
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
902 conversions.append (((1,5,58), conv, 'deprecate textNonEmpty'))
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
916 conversions.append (((1,5,59), conv,
917 'XxxxVerticalExtent -> xxxVerticalExtent'))
919 if 1:
920 def conv (str):
921 str = re.sub ('visibility-lambda', 'break-visibility', str)
922 return str
924 conversions.append (((1,5,62), conv,
925 'visibility-lambda -> break-visibility'))
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
936 conversions.append (((1,5,67), conv,
937 'automaticMelismata turned on by default'))
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
945 conversions.append (((1,5,68), conv, 'ly-set-X-property -> ly-set-X-property!'))
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
953 conversions.append (((1,5,71), conv, 'extent-[XY] -> [XY]-extent'))
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
966 conversions.append (((1,5,72), conv, 'set! point-and-click -> set-point-and-click!'))
969 ################################
970 # END OF CONVERSIONS
971 ################################
973 def get_conversions (from_version, to_version):
974 def version_b (v, f = from_version, t = to_version):
975 return version_cmp (v[0], f) > 0 and version_cmp (v[0], t) <= 0
976 return filter (version_b, conversions)
979 def latest_version ():
980 return conversions[-1][0]
982 def do_conversion (infile, from_version, outfile, to_version):
983 conv_list = get_conversions (from_version, to_version)
985 sys.stderr.write ('Applying conversions: ')
986 str = infile.read ()
987 last_conversion = ()
988 try:
989 for x in conv_list:
990 sys.stderr.write (tup_to_str (x[0]) + ', ')
991 str = x[1] (str)
992 last_conversion = x[0]
994 except FatalConversionError:
995 sys.stderr.write ('Error while converting; I won\'t convert any further')
997 if last_conversion:
998 sys.stderr.write ('\n')
999 new_ver = '\\version \"%s\"' % tup_to_str (last_conversion)
1001 if re.search (lilypond_version_re_str, str):
1002 str = re.sub (lilypond_version_re_str,'\\'+new_ver , str)
1003 elif add_version:
1004 str = new_ver + '\n' + str
1006 outfile.write(str)
1008 return last_conversion
1010 class UnknownVersion:
1011 pass
1013 def do_one_file (infile_name):
1014 sys.stderr.write ('Processing `%s\' ... '% infile_name)
1015 outfile_name = ''
1016 if __main__.edit:
1017 outfile_name = infile_name + '.NEW'
1018 elif __main__.outfile_name:
1019 outfile_name = __main__.outfile_name
1021 if __main__.from_version:
1022 from_version = __main__.from_version
1023 else:
1024 guess = guess_lilypond_version (infile_name)
1025 if not guess:
1026 raise UnknownVersion()
1027 from_version = str_to_tuple (guess)
1029 if __main__.to_version:
1030 to_version = __main__.to_version
1031 else:
1032 to_version = latest_version ()
1035 if infile_name:
1036 infile = open (infile_name,'r')
1037 else:
1038 infile = sys.stdin
1040 if outfile_name:
1041 outfile = open (outfile_name, 'w')
1042 else:
1043 outfile = sys.stdout
1045 touched = do_conversion (infile, from_version, outfile, to_version)
1047 if infile_name:
1048 infile.close ()
1050 if outfile_name:
1051 outfile.close ()
1053 if __main__.edit and touched:
1054 try:
1055 os.remove(infile_name + '~')
1056 except:
1057 pass
1058 os.rename (infile_name, infile_name + '~')
1059 os.rename (infile_name + '.NEW', infile_name)
1061 sys.stderr.write ('\n')
1062 sys.stderr.flush ()
1064 edit = 0
1065 assume_old = 0
1066 to_version = ()
1067 from_version = ()
1068 outfile_name = ''
1070 (options, files) = getopt.getopt (
1071 sys.argv[1:], 'ao:f:t:senh', ['no-version', 'assume-old', 'version', 'output', 'show-rules', 'help', 'edit', 'from=', 'to='])
1073 for opt in options:
1074 o = opt[0]
1075 a = opt[1]
1076 if o== '--help' or o == '-h':
1077 usage ()
1078 sys.exit (0)
1079 if o == '--version' or o == '-v':
1080 print_version ()
1081 sys.exit (0)
1082 elif o== '--from' or o=='-f':
1083 from_version = str_to_tuple (a)
1084 elif o== '--to' or o=='-t':
1085 to_version = str_to_tuple (a)
1086 elif o== '--edit' or o == '-e':
1087 edit = 1
1088 elif o== '--show-rules' or o == '-s':
1089 show_rules (sys.stdout)
1090 sys.exit(0)
1091 elif o == '--output' or o == '-o':
1092 outfile_name = a
1093 elif o == '--assume-old' or o == '-a':
1094 assume_old = 1
1095 elif o == '--no-version' or o == '-n':
1096 add_version = 0
1097 else:
1098 print o
1099 raise getopt.error
1101 identify ()
1102 for f in files:
1103 if f == '-':
1104 f = ''
1105 if not os.path.isfile (f):
1106 continue
1107 try:
1108 do_one_file (f)
1109 except UnknownVersion:
1110 sys.stderr.write ('\n')
1111 sys.stderr.write ("%s: can't determine version for `%s'" % (program_name, f))
1112 sys.stderr.write ('\n')
1113 if assume_old:
1114 fv = from_version
1115 from_version = (0,0,0)
1116 do_one_file (f)
1117 from_version = fv
1118 else:
1119 sys.stderr.write ("%s: skipping: `%s' " % (program_name, f))
1120 pass
1121 sys.stderr.write ('\n')