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