Welcome To Our Shell

Mister Spy & Souheyl Bypass Shell

Current Path : /proc/thread-self/root/usr/local/lib/python3.8/dist-packages/iftlib/abc/55/

Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64
Upload File :
Current File : //proc/thread-self/root/usr/local/lib/python3.8/dist-packages/iftlib/abc/55/abcm2ps-7.8.13.tar

abcm2ps-7.8.13/Changes0000644000175000017500000010701412461214345012533 0ustar  jefjef---- Version 7.8.13 - 15/01/25 ----

Fix bad beams when tremolo inside beamed notes
	(reported by David Lacroix).
Fix loss of ABC lines after %%abc-include when %%select did not
		match the last included tune.
Fix loop on %%voice since 7.8.10.
Fix display of rests in empty staves when "%%staffnonote 0".
Fix loss of key signatures and meters when voice in empty staff
	(reported by Willem).
Fix loss of the 'svg' definition used by the PostScript code on SVG output.

---- Version 7.8.12 - 14/12/16 ----

Fix bad handling of "K:none", especially when transposition.
Fix bad transposition of latin guitar chord "La".
Fix loss of 'exp none' in K:.
Fix some compilation warnings
	(reported by John Chambers).
Fix problems with decorations or guitar chords/annotations
		in sequence/measure repeat.
	(reported by Frédéric Boulanger).

---- Version 7.8.11 - 14/11/26 ----

Fix bad position of grace notes in overlay voices at start of measure
	(reported by Jean-Luc Zins).
Fix bad repeat font when staves/voices with different scales
	(reported by  Gerhard Schacherl).

---- Version 7.8.10 - 14/11/01 ----

Change the PS font scale of the accidentals according to the FontMatrix
	(reported by Chuck Boody).
Fix loss of voice options when many %%voice's without "%%voice end" in %%tune.
Fix lost of lyrics when ABC version 2.1 and generation restart.
Fix bad transposition of notes when %%transpose after K:.

---- Version 7.8.9 - 14/10/14 ----

Fix crash when %%combinevoices on beamed notes since 7.8.7
	(reported by David Lacroix).
Fix bad start/stop of ties since 7.8.4.
Fix possible crash with %%alignbars.
Fix crash when tune starting with grace note in the middle voice
	of a 3-voices staff.

---- Version 7.8.8 - 14/08/29 ----

Fix loss of indentation since 7.8.4
	(reported by David Lacroix).
Fix bad stem direction in lowest voice when invisible and visible rests
		at a same time in a measure since 7.8.4
	(reported by Eric Reinbold).
Fix crash when multi-rest at start of a second voice of a staff.

---- Version 7.8.7 - 14/08/09 ----

Fix crash when %%combinevoices and different beaming.
Always remove the invisible rests at start of tune when L:auto.
Fix some compilation warnings
	(reported by Daniel Branning).
Fix bad split of tune into music lines (imported from 8.1.5)
	(reported by Stephen West).
Fix bad horizontal offset of rests alone in a measure
	(reported by Stephen West).

---- Version 7.8.6 - 14/07/17 ----

Fix lack of source last character in syntax errors.
Fix double information about the titles/subtitles in the PostScript
	output for (external) index generation since 7.8.5
	(reported by Tim Macdonald).
Fix double interpretation of '.' in "!p!.(c"
	(reported by David Lacroix).
Fix the size of font of the page header/footer, broken in 7.8.5
	(reported by Francis Stevens).

---- Version 7.8.5 - 14/07/01 ----

Add more information about the titles/subtitles in the PostScript
	output for (external) index generation
	(asked by Tim Macdonald).
Add Δ (delta) in the known glyphs
	(asked by Chuck Boody).
Fix some bad 'Line overfull' messages when automatic line break.
Fix bad interval between staff systems according to %%staffsep
	(reported by Eric Reinbold and David Lacroix).
Fix bad %%header/%%footer vertical offsets.
Don't put the last music line on a new page when page overflow on W:.

---- Version 7.8.4 - 14/06/18 ----

Fix clash of voice name with staff when new voice after %%staves.
Fix bad indentation when more staves further in the tune.
Set the ties closer to the notes.
Fix bad handling of '|' when first character in w:
	(reported by Alex Scheutzow).
Check the floating voices in %%score/%%staves.
Fix bad stem direction when %%combinevoices.
Fix crash when measure bar numbering and less notes in the upper staff
	(reported by : J.Joao Almeida).
Fix too big syntax error messages
	(reported by David Lacroix).
Fix bad horizontal offset of full rests in voice overlay
	(reported by J.C.L.).

---- Version 7.8.3 - 14/05/23 ----

Fix too wide space between text paragraphs when not fill or justify.
Fix crash when utf-8 and latin characters in a same file
	(reported by Henry Bley-Vroman).
Change internal fonts to 'serif' on SVG output.
Forbid rests in grace note sequences.
Fix crash when rest in grace note sequence.
Fix direction of ties in chords with odd number of notes.
Fix bad direction of beam stub when last note with !beambr1! / !beambr2!
	(reported by David Lacroix).
Fix crash when only P: or Q: in a generation sequence
	(reported by Henry Bley-Vroman).

---- Version 7.8.2 - 14/05/05 ----

Fix non-function of %%voice inside %%tune since some 7.5.x
	(reported by Gerhard Schacherl).
Fix small internal problem with decorations.
Fix position of accent marks (!>!)
	(reported by Paul Rosen).
Fix bad margins when tune inside %%multicol
	(reported by A.B. Steen).
Don't draw repeat brackets when bar between 2 staves.
Fix lack of EOS in some internal strings
	(fixed by Olivier Levon).
Fix bad guitar chord / annotation when '\' inside.
Fix double transposition of 2 octaves when both %%abc2pscompat
	and octave= in K:/V:.
Fix compilation warnings on MAC
	(reported by Chuck Boody).

---- Version 7.8.1 - 14/04/02 ----

Fix bad text justication with PostScript output
	(reported by Gerhard Schacherl).
Fix loss of positions (decorations, lyrics..) when described in format file
	(reported by John Taylor).
Fix loss of tie at end of line
	(reported by David Lacroix).
Fix loss of vertical space above the staves (%%staffsep) since 7.6.10
	(reported by David Lacroix).

---- Version 7.8.0 - 14/03/26 ----

Fix bad buffer size when blank after '-k'.
Fix time shift when L:auto and multi-rests in 2nd voices.
Fix bad %%abcm2ps and %%abc-charset when redefined inside previous tune.
Fix loss of time signature when empty staff system at start of tune.
Add 'forall', 'search' and string comparison to the mini PS interpreter
	(asked by Chuck Boody for easynotes.fmt).
Fix bad handling of %%abcm2ps.
Fix bad tie when %%combinevoices and chord behind measure bar and other symbol.

---- Version 7.7.2 - 14/03/07 ----

Fix loss of parameters after '--abcm2ps x' in command line.
Fix loss of lyric word when note as last music line symbol.
Fix bad handling of multi-rests when L:auto.
Fix bad vertical of rests when no notes in voice and clef != treble.
Fix lack of time signature at start of line when %%timewarn.
Fix %%stretchstaff which did not work.
Fix %%parskipfac for non fill/justified texts.
Fix %%infoline in some cases.
Fix %%combinevoices 0 and the rests.
Fix %%break which could not be put in the tune header.
Fix bad generation when SVG output of justified text.
Fix bad %%voice filtering.
Remove option '-u' (abs2pscompat in command line).
Fix bad 'M' decoration when abc2pscompat.
Fix bad duration of notes when grace notes and L:auto.
Fix bad behaviour of '%%gstemdir 3' when at start of n-plet
	(reported by David Lacroix).

---- Version 7.7.1 - 14/02/18 ----

Fix crash when decoration at start of tune
	(reported by Jean-Luc Zins).

---- Version 7.7.0 - 14/02/17 ----

Fix bad indentation when new name of a voice appearing later in the
	music line.
Fix bad rest offset when in 2nd voice and longer than notes of 1st voice.
Fix bad tie when combinevoices and chord behind measure bar.
Change again the behaviour of %%staffnonote.
Set correct vertical space for elements of invisible staves.
Don't output errors when w: found in ignored voice (not in %%staves).
Add option 'opposite' in %%gstemdir
	(requested by David Lacroix).
Fix documentation about the default value of %%staffnonote.
Add line number in more 'Too many words..' error messages.
Fix compilation warning.

---- Version 7.6.10 - 14/01/23 ----

Fix crash with rests in previous release
	(reported by David Lacroix).

---- Version 7.6.9 - 14/01/23 ----

Change the function name to 'fraction of tone' instead of 'fraction of
	semitone' when no 'microscale=', but '%%micronewps 1'
	!!compatibility!!.
Add line number when 'Too many words in lyric line' error
	(reported by Seymour Shlien).
Fix bad PS functions when K: with explicit list of microtone accidentals.
Include glyphs for microscale=4.
Set %%micronewps when 'microscale=' in K: or V:.
Fix erroneous 'bad tie' when tie at end of line and clef change
	in the upper voice.
Do %%tablature work again.
Fix clash of rest with notes when rest between notes since 7.6.8
	(reported by David Lacroix).
Change the behaviour of %%staffnonote
	(asked by Atte André Jensen and Steve West).
Fix crash when last music line contains only invisible rests
	and %%cfmt.measurenb >= 0.

---- Version 7.6.8 - 13/11/21 ----

Don't display the staves which contain only invisible rests.
Keep the brace staff systems when '%%staffnonote 0' and
	at least one staff has some notes.
Have better ties when clef or staff change.
Have better vertical offset of rests in multi-voice tunes
	(reported by Eric Reinbold).
Fix bad slur endpoint when above/below a tuplet.
Have better display of mixed slurs and tuplets
	(asked by David Lacroix).
Accept %%bgcolor for .xhtml output.
Adjust the offset of elements in empty staves when '%%staffnonote 0'.
Fix bad handling of tuplets with %%combinevoices, sometimes
	giving a program crash.
Permit output to stdout with option '-v'.

---- Version 7.6.7 - 13/11/03 ----

Fix again bad <meta> tag in XHTML output
	(reported by David Lacroix).

---- Version 7.6.6 - 13/11/03 ----

Add page/sequence information in the SVG headers.
Fix bad <meta> tag in XHTML output
	(reported by David Lacroix).

---- Version 7.6.5 - 13/11/02 ----

Fix bad SVG/XHTML output when '--' in the command line.
Put program information in XHTML header only.

---- Version 7.6.4 - 13/11/01 ----

Add more information in svg images (program, command line,
	title for building index).
Set no margin for XHTML printing.
Adjust the scale of the SVG images.

---- Version 7.6.3 - 13/10/25 ----

Fix loss of line break when %%postscript at start of line.
Fix bad SVG output when 'show' before 'stroke' or 'fill'
	(reported by David Lacroix).
Fix bad position of elements built from PostScript code with 'ltr'
		in SVG rendering.
	(reported by David Lacroix).
Update config.guess and config.sub from http://git.savannah.gnu.org/
	(asked by Deepak C Shetty and Snehal).
Add 'color="black"' in <svg> tag.
Fix bad font of string starting with non-ascii character (PS output)
	(reported by David Lacroix).

---- Version 7.6.2 - 13/10/18 ----

Fix bad tie when ending note is combined with previous voice
	(reported by Brian J. Dumont).
Fix loss of gchord/annotation when combine voices and
		both notes have guitar chord/annotation
	(reported by Atte André Jensen).
Fix bad dash lines with SVG output
	(reported by David Lacroix).
Accept XML character references in texts.
Fix bad glyph names of characters greater than latin2
	(reported by David Lacroix).

---- Version 7.6.1 - 13/10/16 ----

Fix bad staff system when %%staves with floating voices.
Permit unlimited PS elements in SVG rendering.
Fix memory overflow with PS 'getinterval' in SVG rendering.
Fix loss of tempo when tune starts with invisible symbol (n-plet, P:..).
Don't raise errors when "%%writefields w 0" and "+:xxx" lines of w:.
Accept a string in 'cvx' for SVG output.
Fix tuplet number vertical offset when slur starting/ending on a same note
	(reported by David Lacroix).
Set a correct approximate width of the unicode characters of which
		the ending bits are ASCII control characters
	(reported by Mike Scott).
Adjust the SVG output closer to PS:
	- greater font sizes,
	- smaller note heads,
	- thiner staff lines and stems.
Update documentation about %%continueall.

---- Version 7.6.0 - 13/08/20 ----

Add build with ninja-build and clang.
Fix %%staves parsing problem which could give bad PS output.
%%glyph added.
Change PS utf-8 handling !!compatibility!!.

---- Version 7.5.8 - 13/08/07 ----

Fix bad offset of rests when under the duration of an upper voice
	(reported by David Lacroix).
Check '!' as linebreak only when <EOL> does a linebreak.
Accept latin names of guitar chords on %%transpose.
Fix loss of lyrics under staff when %%alignbars.
Do %%clip without start work again.
Fix bad PS output when many lines in program command line.
Apply L:auto to all voices when declared in the tune header.
Fix L:auto when duration of auto measure > M: duration.
Add more explanations in the file format.txt
	(thanks to Seymour Shlien).

---- Version 7.5.7 - 13/07/16 ----

Fix bad horizontal offset of EPS images
	(reported by Gerhard Schacherl).
Fix bad clef change when 2 voices on the staff and invisible rests.
Add 'L:auto'.
Better vertical offset of rests when many voices per staff
	(reported by David Lacroix).
Fix bad staff on multi-rest expansion when the voice goes later
	to an other staff.
Fix bad line break when asked before a bar.
Do %%clip work again.
Fix bad music line breaks with %%break after generation restart.
Fix bad music line breaks with %%barperline and generation restart
	(reported by David Lacroix).
Add the command line option '-k'.
Fix bad horizontal offset of stems in SVG output.

---- Version 7.5.6 - 13/06/17 ----

Have better horizontal spacing when music line is too much shrunk.
Fix bad horizontal spacing when high long notes before measure bars
	(reported by Mike Scott).
Handle more than 2 unison notes in chords
	(asked by Hudson Flávio Meneses Lacerda).
Remove the shift of volume decorations which does not work well
	(reported by Jean-Luc Zins).
Fix crash when beam to a repeated sequence
	(reported by Søren Bak Vestergaard).
Fix abnormal slur when tuplet or slur over a repeated sequence
	(reported by Søren Bak Vestergaard).

---- Version 7.5.5 - 13/06/06 ----

Fix bad position of shifted volume decorations
	(reported by David Lacroix).
Fix bad %%transpose of more than one octave down.
Extend %%shiftunison
	(asked by David Lacroix).
Keep the natural accidentals when transposing K:none
	(reported by David Lacroix).
Fix bad handling of %%splittune
	(reported by Gerhard Schacherl).
Allow back text insertion commands in tune header.
Put the measure number a bit higher when at start of line with
	a key signature with sharps.
Look to the next note for B stem direction when at start of bar
	(requested by Mike Scott).

---- Version 7.5.4 - 13/05/27 ----

Fix abnormal note shift when inverted voices in the staff
	since previous release.
Accept %%ps the same as %%postscript
	(asked by David Lacroix).
Fix crash with grace notes since previous release
	(reported by David Lacroix).
Fix again bad accidentals of 2nd notes in a measure when transposing K:none
	(reported by David Lacroix).

---- Version 7.5.3 - 13/05/24 ----

Fix clash of stem and note when bigger stem due to beam
	(reported by Hudson Flávio Meneses Lacerda).
Permit %%break in tune header (i.e. out of %%tune).
Fix abnormal error when %%tune folowed by %%break.
Have less width of explicit key signature with same accidentals at octave.
Better handling of %%staffbreak.
Fix lack of staves after %%staves and new staves.
Fix bad line splitting with measure repeat
	(reported by Gerhard Schacherl).
Fix bad vertical offset of tune on auto newpage
	(reported by Gerhard Schacherl).
Fix the behaviour of "\n" in guitar chord since version 7.x.x
	(reported by Gerhard Schacherl).
Don't raise error when %%textfont in tune header.
Have smaller stems in some cases when the voices are inverted on a staff.
Fix loss of deco/stem position/direction when declared in V:
	after T: / %%vskip / ...
	(reported by Colin Hume).
Don't set natural accidentals when transposing K:none.
Fix bad accidentals of 2nd notes in a measure when transposing K:none
	(reported by David Lacroix).
Have half ties when clef or staff change
	(reported by David Webber).
Don't shift a voice when no overlap with the previous one.
Don't have one head when unison and different dots
	(reported by Hudson Flávio Meneses Lacerda).
Center the repeat measure signs.
Don't have any slur starting from measure repeat signs
	(reported by Søren Bak Vestergaard).
Have a longer tie when the ending note is shifted.
Vertically center the rests when alone in a staff
	(reported by Hudson Flávio Meneses Lacerda).
Shift on the left the volume decorations (ff, pp..) when under a note
	with a stem down
	(asked by Hudson Flávio Meneses Lacerda).
Fix loss of rest when %%combinevoices >= 0 and invisible 1st rest.
Extend %%combinevoices and remove %%comball.
Put the dot decorations on the stems
	(asked by Hudson Flávio Meneses Lacerda).
Have a better tie vertical offset
	(asked by Hudson Flávio Meneses Lacerda).
Fix loss of position/direction commands when after K: or T: inside tune
	(reported by Hudson Flávio Meneses Lacerda).
Fix loss of tempo when 'y' at start of tune in secondary voice
	(reported by Hudson Flávio Meneses Lacerda).
Don't allow text insertion commands in tune header.
Fix bad horizontal offset of stem when unison and shifted note head
	(reported by Hudson Flávio Meneses Lacerda).
Fix nested tuplets vertical offset when slurs
	(reported by Hudson Flávio Meneses Lacerda).
Fix a crash when tune with only repeat bars
	(reported by Colin Hume).
Fix a crash when K:none and %%transpose
	(reported by David Lacroix).

---- Version 7.5.2 - 13/03/22 ----

Fix bad display when %%combinevoice + %%comball and imbricated chords.
Have wider horizontal space at end of music line when no bar.
Fix a crash on explicit music break without a bar
	since previous version
	(reported by Hudson Flávio Meneses Lacerda).
Define the page format in the PS output.
	This fixes page size problems when converting PS to PDF
	(asked by Martin Tarenskeen).
Fix a loop when a tune ends with Z, a bar and a chord
	(reported by Hudson Flávio Meneses Lacerda).
Check the number of measures of X/Z (multi-rests).

---- Version 7.5.1 - 13/03/17 ----

Fix some clashes of accidentals when same notes in 2 voices on the same staff
	(reported by Hudson Flávio Meneses Lacerda).
Fix loss of line at end of %%tune/%%voice
	(reported by Hudson Flávio Meneses Lacerda).
Fix bad handling of many %%voice's in %%tune
	(reported by Hudson Flávio Meneses Lacerda).
Fix bad horizontal space when note with stem up followed by note
	with stem down
	(reported by Hudson Flávio Meneses Lacerda).
Fix bad accidentals of tied notes when transpose with K:none
	(reported by David Lacroix).
Have smaller vertical space for !emphasis! (accent)
	(asked by Hudson Flávio Meneses Lacerda).
Have thicker slurs
	(asked by Hudson Flávio Meneses Lacerda).
Have one more beam in feathered beams
	(asked by Hudson Flávio Meneses Lacerda).
Fix bad note head when !beam-rall! on quavers
	(reported by Hudson Flávio Meneses Lacerda).
Replace the clef of V: in case of voice filter with %%clef
	(reported by Hudson Flávio Meneses Lacerda).
Fix bad handling of %%score/%%staves when found after %%voice
	(reported by Hudson Flávio Meneses Lacerda).
Fix bad handling of %%beginxx/%%endxx with different abcm2ps
	pseudo-comment prefixes.
	(reported by Hudson Flávio Meneses Lacerda).
Fix bad music line cut when less notes in the master voice
	and no bar at end of line
	(reported by Hudson Flávio Meneses Lacerda).
Add 'true' and 'false' in the PS to SVG interpreter
	(asked by Hudson Flávio Meneses Lacerda).
Fix bad PS output when 2 empty lines at end of a justified text sequence
	(reported by Hudson Flávio Meneses Lacerda).
Fix crash when %%clef in %%voice
	(reported by Hudson Flávio Meneses Lacerda).
Fix overlay voice inheritance (%%transpose and glyph placements).
Apply %%transpose in tune header or after first K: to all voices.

---- Version 7.5.0 - 13/03/01 ----

Fix loss of multi-rest when alone in a music line.
Fix clash of rests when 3 voices per staff
	(reported by David Lacroix).
Fix loss of %%clef after first K:.
Implement "^8" and "_8" in clef= and %%clef.
Fix abnormal subtitle output when T: found outside of tune
	(reported by Henry Bley-Vroman).
Fix bad transposition of chords
	(reported by Jean-Luc Zins).
Don't scale the measure numbers when the first staff is scaled
	(asked by Hudson Flávio Meneses Lacerda).
!! Accept 'clef=F' as 'clef=F,' !!
	(needed for ABC 2.1.1).
Handle many times 'repeat 2 measures'
	(asked by Atte André Jensen).
Permit a measure repeat to be at start of music line
	(asked by Atte André Jensen).
Fix crash when measure repeat at start of music line
	(reported by Atte André Jensen).
Don't output error when info-like 'x:' found outside of tune.

---- Version 7.4.2 - 13/02/13 ----

Fix bad vertical offset of Q: when %%text after first K:.
Extend %%abcm2ps with up to 3 characters.
Don't output the words after tune on %%leftmargin/rightmargin/scale.
Fix bad horizontal place of the tune title when %%leftmargin after K:
	(reported by Tim Goetze).
!! Don't start anymore a tune on T: !!
	(asked by Henry Bley-Vroman).
Handle %%stafflines after %%score.
Add missing definitions for Microsoft Visual Basic
	(reported by Jean-Luc Zins).
Fix bad test of buffer overflow on command options
	(reported by Jean-Luc Zins).
Remove extra invisible staff when %%score before %%vskip
	(reported by Tim Goetze).
Fix bad warning message when "P: K: Q:" at end of line
	(reported by Jean-Luc Zins).
Fix bad tune selection when many files in the command line
	(reported by Larry).
Fix lack of slurs when beam on 2 staves
	(reported by David Lacroix).
Fix abnormal natural signs after some %%transpose
	(reported by Jean-Luc Zins).

---- Version 7.4.1 - 13/02/11 ----

Better error messages when error found at end of ABC line.
Warn on deprecated syntaxes of Q:
	(asked by Chuck Boody).
Fix double slurs when beam on 2 staves
	(reported by David Lacroix).
Extend %%repeat for working with many voices
	(reported by Atte André Jensen).

---- Version 7.4.0 - 13/01/29 ----

Do better transposition of microtonal tunes
	(asked by David Lacroix).
Fix bad vertical offset of some decorations (dot, tenuto) when inverted
	stems and multi-voice
	(reported by David Lacroix).
Use the glyphs of the simple accidentals of PS fonts instead of internal ones
	when they exist.
!! Always use UTF-8 characters for simple accidentals (sharp, flat, natural)
	in PS output !! (see the new insertion of ellipsis in sample.abc)
Fix double tie when beam continued on next line
	(reported by David Lacroix).
Extend the %%voicescale possible values to [0.6 .. 1.5].

---- Version 7.3.5 - 13/01/15 ----

Fix crash when "%%gchord hidden".

---- Version 7.3.4 - 13/01/08 ----

%%abcm2ps added.
Bad octave in overlay voices when "octave=" in main voice
	(reported by Colin Hume).
Let more slurs under the tuplets
	(asked by David Lacroix).
Don't keep the K:'s with same key signature when %%keywarn is set
	(reported by Henry Bley-Vroman).

---- Version 7.3.3 - 12/12/14 ----

Remove some example files from the distribution.
Draw the staves with spaces ('y') only and "%%staffnonote 1".
Fix %%alignbars which was broken in 7.2.1.
Set as tune global some info fields (K:, M: and Q:) and pseudo-comments
	after the first K: and middle-tune T:.
Better note shifts of 3rd voice of a same staff.
Change %%shiftunisson to %%shiftunison.
In unison, shift the note with a down stem
	(reported by Paolo Minazzi).
Fix bad output file when note head decoration since 7.3.2.
%%voicescale added.
Fix loss of %%indent since 7.2.2
	(reported by David Lacroix).
Remove the horizontal space of empty key signatures
	(reported by David Lacroix).
Fix bad beam at end of voice overlay since 7.3.0
	(reported by David Lacroix).

---- Version 7.3.2 - 12/12/07 ----

Don't do a page break after the tune title when %%scale after 1st K:.
Fix clash of beams with grace notes when down stems.
Display better slurs on grace notes with down stems.
Fix abnormal error on w: ending with '\' (continuation).
Fix loss of tempo (Q: in tune header) when %%scale/%%rightmargin/...
	after first K:.
Fix again clash of slurs with decorations/tuplets/...
Fix bad slurs when inside the staff since 7.3.0
	(reported by David Lacroix).
Fix %%select when tunes have blank lines (%%begintext..)
	(reported by Henry Bley-Vroman).

---- Version 7.3.1 - 12/11/28 ----

Fix left width of heads in flute.fmt.
Fix the documentation about flute.fmt.
Do %%ornament work.
Add "hidden" in %%dynamic, %%gchord, %%ornament, %%vocal and %%volume.
Don't do an error on the information field "r:".
Fix no output when lack of "%%multicol end"
	(reported by Henry Bley-Vroman).
Fix crash on "%%multicol end" with -E or -g.
Handle "%% endxx" (space after %%)
	(reported by Henry Bley-Vroman).
Check again if not enough words in lyrics (w:)
	(asked by Steve West).
Handle ties from notes to grace notes
	(asked by David Lacroix).
Fix bad width of hole on %%staffbreak multi-voice.
Fix bad offset of the slurs since previous version
	(reported by David Lacroix).
Don't display a key signature on %%transpose from K:none
	(reported by David Lacroix).

---- Version 7.3.0 - 12/11/17 ----

Don't let annotations move the next key or time signature to the right.
Fix lack of key/time warnings at end of line
	(reported by Jean-Luc Zins).
Don't continue beaming in voice overlay
	(reported by Jean-Luc Zins).
Don't shift notes with guitar chord after repeat bracket with long text
	(reported by Norman Bearon).
Fix bad ties from grace notes
	(reported by David Lacroix).
!! Change %%stretchlast to a floating point value. !!
Fix clash of slurs with decorations/tuplets/...
	(reported by John Walsh).

---- Version 7.2.2 - 12/11/07 ----

Fix bad bars between staves with %%score.
Fix bad explicit line breaks after notes.
Don't try to stretch the last music line when %%stretchlast 0
	(reported by Chuck Boody).
Fix too much space above the staff when scaled staff and P: or Q:.
Fix left indentation when empty staves and %%staffnonote.
Fix bad offset of measure numbers when 1st staff empty and %%staffnonote.
Fix bad offset of measure numbers when 1st staff is scaled
	(reported by Hudson Flávio Meneses Lacerda).
Change default value of %%hyphencont to 1
	(asked by David Webber).
Don't draw repeat brackets when bar between 2 staves
	(reported by David Webber).

---- Version 7.2.1 - 12/10/30 ----

Fix crash when centered decoration under staff at start of new staff system.
Add %%breaklimit.
Change the internal algorithm of automatic line breaking.
	(reported by Steve West).
Fix loss of gchord/annot or bad font when scaled staves
	(reported by Hudson Flávio Meneses Lacerda).
Fix bad vertical offset of lyrics when scaled staves and slurs in lower voice.
Fix bad horizontal offset of lyrics on scaled staves.
Handle the line breaks of the top voice only.
Add %%staffscale and %%stafflines.
Fix bad handling of '=' in M:none.
Fix bad handling of %%barsperline when M:none
	(reported by David Lacroix).

---- Version 7.2.0 - 12/10/25 ----

Fix crash when mid-staff decoration in new voice at start of line
	(reported by David Lacroix).
Add "ignore" as special U: value.
Extend %%linebreak to * ; ? and @.
!! Put the output annotations (-A) after the symbols. !!
Add more symbols in output annotations (-A).
Adjust the width scale of all fonts when set in %%font.
Fix "error w: without music" in secondary voices when ABC version >= 2.1
	(reported by Frédéric Aupépin).

---- Version 7.1.3 - 12/10/18 ----

Fix bad slur vertical offsets on scaled staves.
Fix loss of key/time warning when preceeded by %%stave
	(reported by Mike Scott).
Fix bad left side of staff systems when some %%score in the line.
Handle the line breaks of all primary voices.
Fix internal linkage errors.
Fix error "w: without music" when Q: in tune header
	(reported by Frédéric Aupépin).
Fix bad line width after some decorations in SVG output.
Bad measure number after time signature change
	(reported by Jean-Luc Zins).
Bad clef when P: or Q: between first K: and %%staves
	followed by K: or V: with a clef != treble
	(reported by Jean-Luc Zins).

---- Version 7.1.2 - 12/10/09 ----

Treat "%%writefield M 0".
Add %%dblrepbar and draw :|: and :||: as ::
	(asked by Nils Liberg).
Fix bad parsing of the "%abc-<version>" at start of file.
Do more control of ties between two different notes.
Add %%keywarn
	(asked by John Chambers).
Fix clash of subtitle and guitar chord since 7.1.1.
Fix bad staff key signature when "| $ [P:] [K:] |"
	(reported by John Chambers).
Fix bad staff key/time signatures when P: or Q: before K:/M: in tune
	(reported by John Chambers).
Fix crash when %%continueall and music line cut on a bar with !beamon!
	(also when %%breakoneoln 0) and handle beams on two music lines
	(reported by Guido Gonzato).

---- Version 7.1.1 - 12/09/29 ----

Convert multi-rests of one measure to rests
	(reported by David Webber).
Move the decorations to the last rest on multi-rest expand
	(reported by David Webber).
Remove the test messages 'y_set i:-xx'.
May change the guitar chord position (%%gchord) inside the tunes
	(and internal change of guitar chord / annotation handling).
Add %%user.
Add !beam-accel! and !beam-rall!
	(asked by Hudson Flávio Meneses Lacerda).
Reduce a bit the space before the measure bars.

---- Version 7.1.0 - 12/09/13 ----

Fix bad accidentals when clef one octave higher or lower than normal.
Add a letter to select a repeated measure in tune selection
	(asked by Hudson Flávio Meneses Lacerda).
Fix bad music position in tune selection (%%break / %%clip)
	(reported by Hudson Flávio Meneses Lacerda).
Fix lack of tune selection (%%break / %%clip) of the first measures (0 and 1)
	(reported by Hudson Flávio Meneses Lacerda).
Remove extra vertical space between staves after a staff with no note
	(reported by Chuck Boody).
Add "%%tune end" and authorize blank lines in %%tune sequences
	!! compatibility !!
	(asked by Hudson Flávio Meneses Lacerda).
Change %%acccancel to %%cancelkey !! compatibility !!.
Accept time signatures as "M:5 ((2+3)/4)" and "M:5 (2/4+3/4)".
Display the parenthesis of "M:7/8 (3+2+2)"
	(reported by Guido Gonzato).

---- Version 7.0.16 - 12/09/06 ----

Fix bad measure numbering when contbarnb and "y" between "|" and "[number"
	(reported by Hudson Flávio Meneses Lacerda).
Fix clash of measure numbering with key signature.
Add 'microscale= in K: and V:.
Fix bad handling of '/symbol' for "cvx" in the mini PS interpreter.
Add %%micronewps.
Fix abnormal new music line when Q: or P: followed by [V:x] and grace notes.
Fix loss of tempo when second voice starting with grace notes
	(reported by Wim Rotty).

---- Version 7.0.15 - 12/08/27 ----

Fix %%transpose ignored in file or tune header
	(reported by David Webber).
Fix octave= ignored when no clef= in K: and V:
	(reported by Alex Scheutzow).
Add %%acccancel.

---- Version 7.0.14 - 12/07/22 ----

Fix crash with floating point sensitive machines as ARM.
Remove the 'title only' selection in %%select.
Extend the %%tune filter to the whole tune header.
Fix bad file date in header/footer ('$d') when %%format in the ABC file
	(reported by D. Glenn Arthur Jr.).

---- Version 7.0.13 - 12/06/17 ----

Fix array overflow on %%writefields Q.
Fix bad note heads when both normal and percussion voices in a same staff
	(reported by Frédéric Boulanger).
Don't transpose the percussion voices.
Fix bad expansion of 'Xn' when multi-staves
	(reported by Jose Joao Dias de Almeida).

---- Version 7.0.12 - 12/06/10 ----

Fix bad tie when at end of repeat and start of new repeat ("c- :|2 c")
	(reported by Nils Liberg).
Fix crash when PS code at end of line since 7.0.11
	(reported by David Lacroix).
Fix loss of next lyric lines when error found in a w: line
	(reported by Nils Liberg).

---- Version 7.0.11 - 12/06/02 ----

Better hyphen in lyrics lines when big space between notes
	(reported by Nils Liberg).
Fix presence of tempo when "%%writefields Q 0" before first K:
	(reported by Nils Liberg).
Fix abnormal line with one note when line cut should be on a clef change
	(reported by Alex Scheutzow).
Fix presence of meter at start of line when empty voice.
Don't remove '%%' in %%beginps/%%endps sequences.
Fix array overflow and possible crash with empty %%beginxxx/%endxxx
	(reported by Nils Liberg).

---- Version 7.0.10 - 12/05/28 ----

Extend %%voice to any options.
Fix crash when K: without more symbol at end of tune
	(reported by Nils Liberg).
Add %%stemdir, %%gstemdir and %%clef.
Fix clash of '8' in clef with octave +/-8
	(reported by David Lacroix).

---- Version 7.0.9 - 12/05/23 ----

Fix program loop when width of measure bigger than staff width.
Fix bad last measure bar position again
	(reported by many people).
Fix loss of music line break when line ending with grace note(s),
		note and no bar
	(reported by John Chambers).

---- Version 7.0.8 - 12/05/21 ----

Fix loss of paragraph break on empty lines.
Fix crash in %%begintext with fill/justify and pango on an empty line.
Fix bad offset of lyrics after tune when new page
	(reported by Christian Schnarr).
Fix bad last measure bar position since 7.0.6.
Handle 'X' (invisible multi-rest).
Don't do "titletrim" when the length of last word of the title
	is greater than 4.
Fix lack of tempo at start of tune when "%%writefields Q 0" is declared
	further in the tune.

---- Version 7.0.7 - 12/05/16 ----

Fix bad line numbers in errors and svg annotations
	(reported by Nils Liberg).

---- Version 7.0.6 - 12/05/13 ----

Fix lack of key signature when K: + clef inside music line.
Fix lack of accidentals when spaces in the accidental list of K:.
Fix placement errors when scaled voice or staff
	(reported by D. Glenn Arthur Jr.).
Don't put a measure bar at end of line when the measure is incomplete
	(reported by Christian Schnarr).
Fix ps2pdf error when unknown UTF-8 characters
	(reported by Nils Liberg).

---- Version 7.0.5 - 12/04/30 ----

Update the documentation: there is no %%ignore
	(reported-by D. Glenn Arthur Jr.).
Bad offset of %%EPS since version 5.x.x
	(reported-by D. Glenn Arthur Jr.).
Handle more lowercase to uppercase letters when %%titlecaps
	(reported by Christian Schnarr).

---- Version 7.0.4 - 12/03/31 ----

Fix loss of music after abc 2.0 continuation ('\').
Fix a loss of voices when appearing in a new %%staves/%%score.
Handle the ABC 2.1 "w:" behaviour (with "+:").
Fix misplaced part (P:) when followed by K:, or M:
	(reported by Richard Walker).
Accept 'K' in %%titleformat and (text) notes after tune.
Crash when misplaced dble repeat bar in second voice at end of tune
	(reported by Simon Wascher).
Fix X: value in title when ', The' at end of T:
	(reported by Paul Hardy).

---- Version 7.0.3 - 12/03/03 ----

Don't print the tempo in tune when '%%writefields Q 0'
	(reported by Martin Tarenskeen).
Let less space at end of line when key signature change.
Fix a scanning problem with the command line parameter '--header'.
Update the %%staves/%%score in tune(s) when defined in %%tune.

---- Version 7.0.2 - 12/02/21 ----

Don't add the %%transpose values
	(reported by Alex Scheutzow).
Accept empty K: as K:none.
Fix lack of key signature change when exp accidental list of the same size.
Fix bad slur on grace notes when staffscale != 1
	(reported by Pete Showman).
Treat 'I:' as '%%' (accept I:abc-include and I:abc-charset).
Ignore %%sep and %%vskip when global and -E or -g.
Accept any format parameter in %%tune sequences.
Fix crash when some output needed in format files by ignoring %%text...
Stop %%tune/%%voice options on empty lines.
Fix %%abc2pscompat again.
Fix some errors "??? buffer not empty:".
Fix vertical offset problems on page breaks with %%multicol.
Fix bad page header when %%multicol outside and inside tunes.
Don't use pango when only accidentals in string
	(reported by John Collins).
Ignore %%writefields when outputting %%titleformat
	(reported by Pete S).
Reset the default standard title format when %%titleformat is empty.

---- Version 7.0.1 - 12/02/06 ----

Fix loss of music when voices disappear and reappear by %%score
	(reported by John Collins).
Fix some warnings in slre.c compilation
	(reported by Chuck Boody).
Add %%custos.
Fix some cases of error "Line too much shrunk".
Bad computation of the page height letting to much space in (portrait)
	or going out of (landscape) the bottom of the page when
	using %%multicol.

---- Version 7.0.0 - 12/02/02 ----

Permit more pseudo-comments to be defined at command-line level.
Add %%tune, %%voice, %%break, %%clip and %%select.
Add tune selection with '-e' by regular expression.
Permit the clefs to go under or above the notes/rests.
Creation from abcm2ps version 6.6.4.
abcm2ps-7.8.13/INSTALL0000644000175000017500000000331211336716162012271 0ustar  jefjef		--- abcm2ps installation ---


Unix(-like) systems
===================

This version uses the GNU 'autoconf' package, so, after untarring the
sources, run:

	./configure
	make

and then, as root, do:

	make install

The 'abcm2ps' command should work if '/usr/local/bin' is in your path
(try 'abcm2ps -h' for a list of the command line options).

You may change some compile options at configure level. To know which,
run:

	configure --help


Windows or MAC systems
======================

Change the file 'config.h' according to your preferences, compile all
the '.c' files using an ANSI C compiler, and link them together. The
resulting binary file should run immediately from where it has been
generated. You may then move it at any place you want.


Testing
=======

To test the program, run it with one of the .abc files as the command
line argument:

	abcm2ps sample

The resulting file, 'Out.ps', may be displayed using a PostScript
previewer such as ghostscript, or may be sent directly to a PostScript
printer, or indirectly to a simple printer using a postscript filter.


About the 'pango' library
=========================

abcm2ps now uses the 'pango' library to render texts with non latin
characters. If you don't have such texts, you don't need this library.

In Unix(-like) systems, at configure time, the pango generation elements
are searched by pkg-config in the gdk-2.0 library. If this library or
pkg_config are not found, the rendering of non latin characters with
pango will be disabled, but this rendering may be done by other means,
especially by CMap (see the file chinese.abc). Note also that, when
pango is defined, it may be disabled at command line level by
'--pango 0' (you may try it with chinese.abc).
abcm2ps-7.8.13/License0000644000175000017500000004307607005373333012555 0ustar  jefjef		    GNU GENERAL PUBLIC LICENSE
		       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
                          675 Mass Ave, Cambridge, MA 02139, USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

			    Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

		    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

			    NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

		     END OF TERMS AND CONDITIONS

	Appendix: How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) 19yy  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) 19yy name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Library General
Public License instead of this License.
abcm2ps-7.8.13/Makefile0000644000175000017500000000742312444057273012711 0ustar  jefjef# Makefile source for abcm2ps

VERSION = 7.8.12

CC = gcc
INSTALL = /usr/bin/install -c
INSTALL_DATA = ${INSTALL} -m 644
INSTALL_PROGRAM = ${INSTALL}

CPPFLAGS = -DHAVE_CONFIG_H  -I.
CPPPANGO = 
CFLAGS = -g -O2 -Wall -pipe
LDFLAGS =  -lm

prefix = /usr/local
exec_prefix = ${prefix}

srcdir = .

bindir = ${exec_prefix}/bin
libdir = ${exec_prefix}/lib
datadir = ${prefix}/share
docdir = /usr/local/doc

# unix
OBJECTS=abc2ps.o \
	abcparse.o buffer.o deco.o draw.o format.o front.o glyph.o music.o parse.o \
	slre.o subs.o svg.o syms.o
abcm2ps: $(OBJECTS)
	$(CC) $(CFLAGS) -o $@ $(OBJECTS) $(LDFLAGS)

$(OBJECTS): abcparse.h config.h Makefile
abc2ps.o buffer.o deco.o draw.o format.o front.o glyph.o music.o parse.o \
	subs.o svg.o syms.o: abc2ps.h
abc2ps.o front.o: front.h
front.o parse.o slre.o: slre.h
subs.o: subs.c
	$(CC) $(CFLAGS) $(CPPFLAGS) $(CPPPANGO) -c -o $@ $<

abcmfe: front.c front.h slre.h
	$(CC) $(CFLAGS) -DMAIN -o $@ $< slre.o

DOCFILES=$(addprefix $(srcdir)/,Changes License README *.abc *.eps *.txt)

install: abcm2ps
	mkdir -p $(bindir); \
	mkdir -p $(datadir)/abcm2ps; \
	mkdir -p $(docdir)/abcm2ps; \
	$(INSTALL_PROGRAM) abcm2ps $(bindir)
	for f in $(srcdir)/*.fmt; do \
		$(INSTALL_DATA) $$f $(datadir)/abcm2ps; \
	done
	for f in $(DOCFILES); do \
		$(INSTALL_DATA) $$f $(docdir)/abcm2ps; \
	done

uninstall:
	echo "uninstalling..."; \
	rm -f $(bindir)/abcm2ps; \
	rm -rf $(datadir)/abcm2ps; \
	rm -rf $(docdir)/abcm2ps

DIST_FILES = \
	abcm2ps-$(VERSION)/Changes \
	abcm2ps-$(VERSION)/INSTALL \
	abcm2ps-$(VERSION)/License \
	abcm2ps-$(VERSION)/Makefile \
	abcm2ps-$(VERSION)/Makefile.in \
	abcm2ps-$(VERSION)/README \
	abcm2ps-$(VERSION)/abc2ps.c \
	abcm2ps-$(VERSION)/abc2ps.h \
	abcm2ps-$(VERSION)/abcparse.c \
	abcm2ps-$(VERSION)/abcparse.h \
	abcm2ps-$(VERSION)/accordion.abc \
	abcm2ps-$(VERSION)/build.ninja \
	abcm2ps-$(VERSION)/buffer.c \
	abcm2ps-$(VERSION)/chinese.abc \
	abcm2ps-$(VERSION)/configure \
	abcm2ps-$(VERSION)/configure.in \
	abcm2ps-$(VERSION)/config.h \
	abcm2ps-$(VERSION)/config.h.in \
	abcm2ps-$(VERSION)/config.guess \
	abcm2ps-$(VERSION)/config.sub \
	abcm2ps-$(VERSION)/deco.c \
	abcm2ps-$(VERSION)/deco.abc \
	abcm2ps-$(VERSION)/draw.c \
	abcm2ps-$(VERSION)/features.txt \
	abcm2ps-$(VERSION)/flute.fmt \
	abcm2ps-$(VERSION)/format.c \
	abcm2ps-$(VERSION)/format.txt \
	abcm2ps-$(VERSION)/front.c \
	abcm2ps-$(VERSION)/front.h \
	abcm2ps-$(VERSION)/glyph.c \
	abcm2ps-$(VERSION)/install.sh \
	abcm2ps-$(VERSION)/landscape.fmt \
	abcm2ps-$(VERSION)/music.c \
	abcm2ps-$(VERSION)/musicfont.fmt \
	abcm2ps-$(VERSION)/newfeatures.abc \
	abcm2ps-$(VERSION)/options.txt \
	abcm2ps-$(VERSION)/parse.c \
	abcm2ps-$(VERSION)/sample.abc \
	abcm2ps-$(VERSION)/sample2.abc \
	abcm2ps-$(VERSION)/sample3.abc \
	abcm2ps-$(VERSION)/sample3.eps \
	abcm2ps-$(VERSION)/sample4.abc \
	abcm2ps-$(VERSION)/sample5.abc \
	abcm2ps-$(VERSION)/slre.c \
	abcm2ps-$(VERSION)/slre.h \
	abcm2ps-$(VERSION)/subs.c \
	abcm2ps-$(VERSION)/svg.c \
	abcm2ps-$(VERSION)/syms.c \
	abcm2ps-$(VERSION)/tight.fmt \
	abcm2ps-$(VERSION)/voices.abc

dist:
	ln -s . abcm2ps-$(VERSION); \
	tar -zcvf abcm2ps-$(VERSION).tar.gz $(DIST_FILES); \
	rm abcm2ps-$(VERSION)

zip-dist:
	ln -s . abcm2ps-$(VERSION); \
	zip -r abcm2ps-$(VERSION).zip $(DIST_FILES); \
	rm abcm2ps-$(VERSION)

zip: abcm2ps.exe
	strip abcm2ps.exe; \
	cd ..; zip -r abcm2ps-$(VERSION).zip \
	abcm2ps-$(VERSION)/abcm2ps.exe \
	abcm2ps-$(VERSION)/License \
	abcm2ps-$(VERSION)/Changes \
	abcm2ps-$(VERSION)/INSTALL \
	abcm2ps-$(VERSION)/sample3.eps \
	abcm2ps-$(VERSION)/*.abc \
	abcm2ps-$(VERSION)/*.fmt \
	abcm2ps-$(VERSION)/*.txt ; cd -

EXAMPLES = accordion.ps \
	chinese.ps \
	deco.ps \
	newfeatures.ps \
	sample.ps \
	sample2.ps \
	sample3.ps \
	sample4.ps \
	sample5.ps \
	voices.ps

test:	$(EXAMPLES)
%.ps: %.abc
	./abcm2ps -O $@ $<

clean:
	rm -f *.o $(EXAMPLES) # *.obj
abcm2ps-7.8.13/Makefile.in0000644000175000017500000000743412243365635013321 0ustar  jefjef# Makefile source for abcm2ps

VERSION = @VERSION@

CC = @CC@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@

CPPFLAGS = @DEFS@ @CPPFLAGS@ -I.
CPPPANGO = @CPPPANGO@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@ -lm

prefix = @prefix@
exec_prefix = @exec_prefix@

srcdir = @srcdir@
VPATH = @srcdir@
bindir = @bindir@
libdir = @libdir@
datadir = @datarootdir@
docdir = @prefix@/doc

# unix
OBJECTS=abc2ps.o \
	abcparse.o buffer.o deco.o draw.o format.o front.o glyph.o music.o parse.o \
	slre.o subs.o svg.o syms.o
abcm2ps: $(OBJECTS)
	$(CC) $(CFLAGS) -o $@ $(OBJECTS) $(LDFLAGS)

$(OBJECTS): abcparse.h config.h Makefile
abc2ps.o buffer.o deco.o draw.o format.o front.o glyph.o music.o parse.o \
	subs.o svg.o syms.o: abc2ps.h
abc2ps.o front.o: front.h
front.o parse.o slre.o: slre.h
subs.o: subs.c
	$(CC) $(CFLAGS) $(CPPFLAGS) $(CPPPANGO) -c -o $@ $<

abcmfe: front.c front.h slre.h
	$(CC) $(CFLAGS) -DMAIN -o $@ $< slre.o

DOCFILES=$(addprefix $(srcdir)/,Changes License README *.abc *.eps *.txt)

install: abcm2ps
	mkdir -p $(bindir); \
	mkdir -p $(datadir)/abcm2ps; \
	mkdir -p $(docdir)/abcm2ps; \
	$(INSTALL_PROGRAM) abcm2ps $(bindir)
	for f in $(srcdir)/*.fmt; do \
		$(INSTALL_DATA) $$f $(datadir)/abcm2ps; \
	done
	for f in $(DOCFILES); do \
		$(INSTALL_DATA) $$f $(docdir)/abcm2ps; \
	done

uninstall:
	echo "uninstalling..."; \
	rm -f $(bindir)/abcm2ps; \
	rm -rf $(datadir)/abcm2ps; \
	rm -rf $(docdir)/abcm2ps

DIST_FILES = \
	abcm2ps-$(VERSION)/Changes \
	abcm2ps-$(VERSION)/INSTALL \
	abcm2ps-$(VERSION)/License \
	abcm2ps-$(VERSION)/Makefile \
	abcm2ps-$(VERSION)/Makefile.in \
	abcm2ps-$(VERSION)/README \
	abcm2ps-$(VERSION)/abc2ps.c \
	abcm2ps-$(VERSION)/abc2ps.h \
	abcm2ps-$(VERSION)/abcparse.c \
	abcm2ps-$(VERSION)/abcparse.h \
	abcm2ps-$(VERSION)/accordion.abc \
	abcm2ps-$(VERSION)/build.ninja \
	abcm2ps-$(VERSION)/buffer.c \
	abcm2ps-$(VERSION)/chinese.abc \
	abcm2ps-$(VERSION)/configure \
	abcm2ps-$(VERSION)/configure.in \
	abcm2ps-$(VERSION)/config.h \
	abcm2ps-$(VERSION)/config.h.in \
	abcm2ps-$(VERSION)/config.guess \
	abcm2ps-$(VERSION)/config.sub \
	abcm2ps-$(VERSION)/deco.c \
	abcm2ps-$(VERSION)/deco.abc \
	abcm2ps-$(VERSION)/draw.c \
	abcm2ps-$(VERSION)/features.txt \
	abcm2ps-$(VERSION)/flute.fmt \
	abcm2ps-$(VERSION)/format.c \
	abcm2ps-$(VERSION)/format.txt \
	abcm2ps-$(VERSION)/front.c \
	abcm2ps-$(VERSION)/front.h \
	abcm2ps-$(VERSION)/glyph.c \
	abcm2ps-$(VERSION)/install.sh \
	abcm2ps-$(VERSION)/landscape.fmt \
	abcm2ps-$(VERSION)/music.c \
	abcm2ps-$(VERSION)/musicfont.fmt \
	abcm2ps-$(VERSION)/newfeatures.abc \
	abcm2ps-$(VERSION)/options.txt \
	abcm2ps-$(VERSION)/parse.c \
	abcm2ps-$(VERSION)/sample.abc \
	abcm2ps-$(VERSION)/sample2.abc \
	abcm2ps-$(VERSION)/sample3.abc \
	abcm2ps-$(VERSION)/sample3.eps \
	abcm2ps-$(VERSION)/sample4.abc \
	abcm2ps-$(VERSION)/sample5.abc \
	abcm2ps-$(VERSION)/slre.c \
	abcm2ps-$(VERSION)/slre.h \
	abcm2ps-$(VERSION)/subs.c \
	abcm2ps-$(VERSION)/svg.c \
	abcm2ps-$(VERSION)/syms.c \
	abcm2ps-$(VERSION)/tight.fmt \
	abcm2ps-$(VERSION)/voices.abc

dist:
	ln -s . abcm2ps-$(VERSION); \
	tar -zcvf abcm2ps-$(VERSION).tar.gz $(DIST_FILES); \
	rm abcm2ps-$(VERSION)

zip-dist:
	ln -s . abcm2ps-$(VERSION); \
	zip -r abcm2ps-$(VERSION).zip $(DIST_FILES); \
	rm abcm2ps-$(VERSION)

zip: abcm2ps.exe
	strip abcm2ps.exe; \
	cd ..; zip -r abcm2ps-$(VERSION).zip \
	abcm2ps-$(VERSION)/abcm2ps.exe \
	abcm2ps-$(VERSION)/License \
	abcm2ps-$(VERSION)/Changes \
	abcm2ps-$(VERSION)/INSTALL \
	abcm2ps-$(VERSION)/sample3.eps \
	abcm2ps-$(VERSION)/*.abc \
	abcm2ps-$(VERSION)/*.fmt \
	abcm2ps-$(VERSION)/*.txt ; cd -

EXAMPLES = accordion.ps \
	chinese.ps \
	deco.ps \
	newfeatures.ps \
	sample.ps \
	sample2.ps \
	sample3.ps \
	sample4.ps \
	sample5.ps \
	voices.ps

test:	$(EXAMPLES)
%.ps: %.abc
	./abcm2ps -O $@ $<

clean:
	rm -f *.o $(EXAMPLES) # *.obj
abcm2ps-7.8.13/README0000644000175000017500000000512112024034430012102 0ustar  jefjef		--- abcm2ps version 7.x.x ---

Overview
========

abcm2ps is a program which converts music tunes from ABC format to
PostScript or SVG. Based on abc2ps version 1.2.5 (see Contacts below),
it was developped mainly to print barock organ scores which have
independant voices played on one or many keyboards and a pedal-board
(the 'm' of abcm2ps stands for many or multi staves/voices).


Features
========

The main features of abcm2ps are quite the same as the abc2ps ones,
but they are closer to the ABC standard 2.0 (draft IV - 14/8/2003):

	http://abc.sourceforge.net/standard/abc2-draft.html


Installation and usage
======================

The installation procedure is described in the file INSTALL.

Basically, the program usage is:

   abcm2ps [options] file1 [file1_options] file2 [file2_options] ...

where file1, file2, .. are the ABC input files. This will generate
a Postscript file (default name: 'Out.ps' - run 'abcm2ps -h' to
know the list of the command line options).


Documentation
=============

- options.txt contains the list of the command line options.

- format.txt contains the list of the format parameters.

- features.txt lists the differences from the current ABC standard.


Differences with abc2ps
=======================

- the algorithms relative to voice and staff handling are different and
  may give better or worse results depending on the tunes.

- abcm2ps does not print the list of tunes and has different filtering
  functions. On the command line:
	- '-o' is implicit
	- '-e' accepts only one parameter.
	- '-C', '-R', '-S', '-T' don't exist anymore. If you want such
	  filtering, you should to use some external script or program
	  instead.

- There is no interactive mode ('-i').

- The scale is global (it was restricted to the music part in abc2ps).

- The characters '\\' don't do a line break.

- In landscape format, the values of 'pagewidth' and 'pageheight'
  are internally exchanged, so there is no need to set them explicitely.

- The format 'staffwidth' is obsolete. Use 'pagewidth' instead.

- Look also in the file 'sample.abc' for other incompatibilities.


Limits
======

Many limits may be changed at compilation time (number of voices, staves,
..).


Contacts
========

The primary abcm2ps site is:

	http://moinejf.free.fr/

Guido Gonzatto maintains Win32 and RedHat binaries and some more
documentation at:

	http://abcplus.sourceforge.net/

abc2ps was developped by Michael Methfessel:

	http://www.ihp-ffo.de/~msm/
	mailto:msm@ihp-ffo.de

To know more about the ABC notation, have a look at:

	http://abcnotation.com/

For any comment:
	mailto:moinejf (at) free (dot) fr
abcm2ps-7.8.13/abc2ps.c0000644000175000017500000005364412314505364012570 0ustar  jefjef/*
 * abcm2ps: a program to typeset tunes written in ABC format using PostScript
 *
 * Copyright (C) 1998-2014 Jean-François Moine (http://moinejf.free.fr)
 *
 * Adapted from abc2ps-1.2.5:
 *  Copyright (C) 1996,1997  Michael Methfessel (msm@ihp-ffo.de)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#ifdef linux
#include <unistd.h>
#endif

#include "abc2ps.h"
#include "front.h"

/* -- global variables -- */

INFO info;
unsigned char deco[256];
struct SYMBOL *sym;		/* (points to the symbols of the current voice) */

int tunenum;			/* number of current tune */
int pagenum = 1;		/* current page in output file */

				/* switches modified by command line flags: */
int quiet;			/* quiet mode */
int secure;			/* secure mode */
int annotate;			/* output source references */
int pagenumbers;		/* write page numbers */
int epsf;			/* for EPSF (1) or SVG (2) output */
int svg;			/* SVG (1) or XML (2 - HTML + SVG) output */
int showerror;			/* show the errors */

char outfn[FILENAME_MAX];	/* output file name */
int file_initialized;		/* for output file */
FILE *fout;			/* output file */
char *in_fname;			/* current input file name */
time_t mtime;			/* last modification time of the input file */
static time_t fmtime;		/*	"	"	of all files */

int s_argc;			/* command line arguments */
char **s_argv;

struct tblt_s *tblts[MAXTBLT];
struct cmdtblt_s cmdtblts[MAXCMDTBLT];
int ncmdtblt;

/* -- local variables -- */

static char abc_fn[FILENAME_MAX]; /* buffer for ABC file name */
static char *styd = DEFAULT_FDIR; /* format search directory */
static int def_fmt_done = 0;	/* default format read */
static struct SYMBOL notitle;

/* memory arena (for clrarena, lvlarena & getarena) */
#define MAXAREAL 3		/* max area levels:
				 * 0; global, 1: tune, 2: generation */
#define AREANASZ 8192		/* standard allocation size */
#define MAXAREANASZ 0x20000	/* biggest allocation size */
static int str_level;		/* current arena level */
static struct str_a {
	struct str_a *n;	/* next area */
	char	*p;		/* pointer in area */
	int	r;		/* remaining space in area */
	int	sz;		/* size of str[] */
	char	str[2];		/* start of memory area */
} *str_r[MAXAREAL], *str_c[MAXAREAL];	/* root and current area pointers */

/* -- local functions -- */
static void read_def_format(void);
static void treat_file(char *fn, char *ext);

static FILE *open_ext(char *fn, char *ext)
{
	FILE *fp;
	char *p;

	if ((fp = fopen(fn, "rb")) != NULL)
		return fp;
	if ((p = strrchr(fn, DIRSEP)) == NULL)
		p = fn;
	if (strrchr(p, '.') != NULL)
		return NULL;
	strcat(p, ".");
	strcat(p, ext);
	if ((fp = fopen(fn, "rb")) != NULL)
		return fp;
	return NULL;
}

/* -- open a file for reading -- */
FILE *open_file(char *fn,	/* file name */
		char *ext,	/* file type */
		char *rfn)	/* returned real file name */
{
	FILE *fp;
	char *p;
	int l;

	/* if there was some ABC file, try its directory */
	if (in_fname && in_fname != fn
	 && (p = strrchr(in_fname, DIRSEP)) != NULL) {
		l = p - in_fname + 1;
		strncpy(rfn, in_fname, l);
		strcpy(&rfn[l], fn);
		if ((fp = open_ext(rfn, ext)) != NULL)
			return fp;
	}

	/* try locally */
	strcpy(rfn, fn);
	if ((fp = open_ext(rfn, ext)) != NULL)
		return fp;

	/* try a format in the format directory */
	if (*ext != 'f' || *styd == '\0')
		return NULL;
	l = strlen(styd) - 1;
	if (styd[l] == DIRSEP)
		sprintf(rfn, "%s%s", styd, fn);
	else
		sprintf(rfn, "%s%c%s", styd, DIRSEP, fn);
	return open_ext(rfn, ext);
}

/* -- read a whole input file -- */
/* the real/full file name is put in tex_buf[] */
static char *read_file(char *fn, char *ext)
{
	size_t fsize;
	FILE *fin;
	char *file;

	if (*fn == '\0') {
		strcpy(tex_buf, "stdin");
		fsize = 0;
		file = malloc(8192);
		for (;;) {
			int l;

			l = fread(&file[fsize], 1, 8192, stdin);
			fsize += l;
			if (l != 8192)
				break;
			file = realloc(file, fsize + 8192);
		}
		if (ferror(stdin) != 0) {
			free(file);
			return 0;
		}
		if (fsize % 8192 == 0)
			file = realloc(file, fsize + 2);
		time(&fmtime);
	} else {
		struct stat sbuf;

		fin = open_file(fn, ext, tex_buf);
		if (!fin)
			return NULL;
		if (fseek(fin, 0L, SEEK_END) < 0) {
			fclose(fin);
			return NULL;
		}
		fsize = ftell(fin);
		rewind(fin);
		if ((file = malloc(fsize + 2)) == NULL) {
			fclose(fin);
			return NULL;
		}

		if (fread(file, 1, fsize, fin) != fsize) {
			fclose(fin);
			free(file);
			return NULL;
		}
		fstat(fileno(fin), &sbuf);
		memcpy(&fmtime, &sbuf.st_mtime, sizeof fmtime);
		fclose(fin);
	}
	file[fsize] = '\0';
	return file;
}

/* call back to handle %%format/%%abc-include - see front.c */
static void include_cb(unsigned char *fn)
{
	char abc_fn_sav[FILENAME_MAX];

	strcpy(abc_fn_sav, abc_fn);
	treat_file((char *) fn, "fmt");
	strcpy(abc_fn, abc_fn_sav);
}

/* -- treat an input file and generate the ABC file -- */
static void treat_file(char *fn, char *ext)
{
	struct abctune *t;
	char *file, *file2;
	int file_type, l;
	static int nbfiles;

	if (nbfiles > 2) {
		error(1, 0, "Too many included files");
		return;
	}

	/* initialize if not already done */
	if (!fout)
		read_def_format();

	/* read the file into memory */
	/* the real/full file name is in tex_buf[] */
	if ((file = read_file(fn, ext)) == NULL) {
		if (strcmp(fn, "default.fmt") != 0) {
			error(1, NULL, "Cannot read the input file '%s'", fn);
#if defined(unix) || defined(__unix__)
			perror("    read_file");
#endif
		}
		return;
	}
	if (!quiet)
		fprintf(stderr, "File %s\n", tex_buf);

	/* convert the strings */
	l = strlen(tex_buf);
	if (strcmp(&tex_buf[l - 3], ".ps") == 0) {
		file_type = FE_PS;
		frontend((unsigned char *) "%%beginps\n", 0);
	} else if (strcmp(&tex_buf[l - 4], ".fmt") == 0) {
		file_type = FE_FMT;
	} else {
		file_type = FE_ABC;
		strcpy(abc_fn, tex_buf);
		in_fname = abc_fn;
		mtime = fmtime;
	}

	nbfiles++;
	file2 = (char *) frontend((unsigned char *) file, file_type);
	nbfiles--;
	free(file);

	if (file_type == FE_PS)			/* PostScript file */
		file2 = (char *) frontend((unsigned char *) "%%endps", 0);

	if (nbfiles > 0)		/* if %%format */
		return;			/* don't free the preprocessed buffer */

//	memcpy(&deco_tune, &deco_glob, sizeof deco_tune);
	if (file_type == FE_ABC) {		/* if ABC file */
//		if (!epsf)
//			open_output_file();
		clrarena(1);			/* clear previous tunes */
	}
	t = abc_parse(file2);
	free(file2);
	front_init(0, 0, include_cb);		/* reinit the front-end */
	if (!t) {
		if (file_type == FE_ABC)
			error(1, NULL, "File '%s' is empty!", tex_buf);
		return;
	}

	while (t) {
		if (t->first_sym)		/*fixme:last tune*/
			do_tune(t);		/* generate */
		t = t->next;
	}
/*	abc_free(t);	(useless) */
}

/* -- read the default format -- */
static void read_def_format(void)
{
	if (def_fmt_done)
		return;
	def_fmt_done = 1;
	treat_file("default.fmt", "fmt");
}

/* -- set extension on a file name -- */
void strext(char *fn, char *ext)
{
	char *p, *q;

	if ((p = strrchr(fn, DIRSEP)) == NULL)
		p = fn;
	if ((q = strrchr(p, '.')) == NULL)
		strcat(p, ".");
	else
		q[1] = '\0';
	strcat(p, ext);
}

/* -- write the program version -- */
static void display_version(int full)
{
	fputs("abcm2ps-" VERSION " (" VDATE ")\n", stderr);
	if (!full)
		return;
	fputs("Compiled: " __DATE__ "\n"
	       "Options:"
#ifdef A4_FORMAT
		" A4_FORMAT"
#endif
#ifdef DECO_IS_ROLL
		" DECO_IS_ROLL"
#endif
#ifdef HAVE_PANGO
		" PANGO"
#endif
#if !defined(A4_FORMAT) && !defined(DECO_IS_ROLL) && !defined(HAVE_PANGO)
		" NONE"
#endif
		"\n", stderr);
	if (styd[0] != '\0')
		fprintf(stderr, "Default format directory: %s\n", styd);
}

/* -- display usage and exit -- */
static void usage(void)
{
	display_version(0);
	printf(	"ABC to Postscript translator.\n"
		"Usage: abcm2ps [options] file [file_options] ..\n"
		"where:\n"
		" file        input ABC file, or '-'\n"
		" options and file_options:\n"
		"  .output file options:\n"
		"     -E      produce EPSF output, one tune per file\n"
		"     -g      produce SVG output, one tune per file\n"
		"     -v      produce SVG output, one page per file\n"
		"     -X      produce SVG output in one XHTML file\n"
		"     -O fff  set outfile name to fff\n"
		"     -O =    make outfile name from infile/title\n"
		"     -i      indicate where are the errors\n"
		"     -k kk   size of the PS output buffer in Kibytes\n"
		"  .output formatting:\n"
		"     -s xx   set scale factor to xx\n"
		"     -w xx   set staff width (cm/in/pt)\n"
		"     -m xx   set left margin (cm/in/pt)\n"
		"     -d xx   set staff separation (cm/in/pt)\n"
		"     -a xx   set max shrinkage to xx (between 0 and 1)\n"
		"     -F foo  read format file \"foo.fmt\"\n"
		"     -D bar  look for format files in directory \"bar\"\n"
		"  .output options:\n"
		"     -l      landscape mode\n"
		"     -I xx   indent 1st line (cm/in/pt)\n"
		"     -x      add xref numbers in titles\n"
		"     -M      don't output the lyrics\n"
		"     -N n    set page numbering mode to n=\n"
		"             0=off 1=left 2=right 3=even left,odd right 4=even right,odd left\n"
		"     -1      write one tune per page\n"
		"     -G      no slur in grace notes\n"
		"     -j n[b] number the measures every n bars (or on the left if n=0)\n"
		"             if 'b', display in a box\n"
		"     -b n    set the first measure number to n\n"
		"     -f      have flat beams\n"
		"     -T n[v]   output the tablature 'n' for voice 'v' / all voices\n"
		"  .line breaks:\n"
		"     -c      auto line break\n"
		"     -B n    break every n bars\n"
		"  .input file selection/options:\n"
		"     -e pattern\n"
		"             tune selection\n"
		"  .help/configuration:\n"
		"     -V      show program version\n"
		"     -h      show this command summary\n"
		"     -H      show the format parameters\n"
		"     -S      secure mode\n"
		"     -q      quiet mode\n");
	exit(EXIT_SUCCESS);
}

#ifdef linux
/* -- where is the default format directory -- */
static void wherefmtdir(void)
{
	char exe[512], *p;
	FILE *f;
	int l;

	if ((l = readlink("/proc/self/exe", exe, sizeof exe)) <= 0)
		return;
	if ((p = strrchr(exe, '/')) == NULL)
		return;
	p++;
	if (p > &exe[5] && strncmp(p - 5, "/bin", 4) == 0) {
		strcpy(p - 4, "share/abcm2ps/");
		p += -4 + 14;
	}
	/* else, assume this is the source directory */

	/* check if a format file is present */
	strcpy(p, "tight.fmt");
	if ((f = fopen(exe, "r")) == NULL)
		return;
	fclose(f);

	/* change the format directory */
	p[-1] = '\0';
	styd = strdup(exe);
}
#endif

/* -- parse the tablature command ('-T n[v]') -- */
static struct cmdtblt_s *cmdtblt_parse(char *p)
{
	struct cmdtblt_s *cmdtblt;
	short val;

	if (ncmdtblt >= MAXCMDTBLT) {
		error(1, NULL, "++++ Too many '-T'");
		return NULL;
	}
	if (*p == '\0')
		val = -1;
	else {
		val = *p++ - '0' - 1;
		if ((unsigned) val > MAXTBLT) {
			error(1, NULL, "++++ Bad tablature number in '-T'\n");
			return 0;
		}
	}
	cmdtblt = &cmdtblts[ncmdtblt++];
	cmdtblt->index = val;
	cmdtblt->vn = p;
	return cmdtblt;
}

/* set a command line option */
static void set_opt(char *w, char *v)
{
	static char prefix = '%';	/* pseudo-comment prefix */

	if (!v)
		v = "";
	if (strlen(w) + strlen(v) >= TEX_BUF_SZ - 10) {
		error(1, NULL, "Command line '%s' option too long", w);
		return;
	}
	sprintf(tex_buf,		/* this buffer is available */
		"%%%c%s %s lock\n", prefix, w, v);
	if (strcmp(w, "abcm2ps") == 0)
		prefix = *v;
	frontend((unsigned char *) tex_buf, 0);
}

/* -- main program -- */
int main(int argc, char **argv)
{
	unsigned j;
	char *p, c, *aaa;

	if (argc <= 1)
		usage();

	/* set the global flags */
	s_argc = argc;
	s_argv = argv;
	aaa = NULL;
	while (--argc > 0) {
		argv++;
		p = *argv;
		if (*p != '-' || p[1] == '-') {
			if (*p == '+' && p[1] == 'F')	/* +F : no default format */
				def_fmt_done = 1;
			continue;
		}
		while ((c = *++p) != '\0') {	/* '-xxx' */
			switch (c) {
			case 'E':
				svg = 0;	/* EPS */
				epsf = 1;
				break;
			case 'g':
				svg = 0;	/* SVG one file per tune */
				epsf = 2;
				break;
			case 'h':
				usage();	/* no return */
			case 'q':
				quiet = 1;
				break;
			case 'S':
				secure = 1;
				break;
			case 'V':
				display_version(1);
				return EXIT_SUCCESS;
			case 'v':
				svg = 1;	/* SVG one file per pagee */
				epsf = 0;
				break;
			case 'X':
				svg = 2;	/* SVG/XHTML */
				epsf = 0;
				break;
			case 'k':
				if (p[1] == '\0') {
					if (--argc <= 0) {
						error(1, NULL, "No value for '-k' - aborting");
						return EXIT_FAILURE;
					}
					aaa = *++argv;
				} else {
					aaa = p + 1;
					p += strlen(p) - 1;
				}
				break;
			default:
				if (strchr("aBbDdeFfIjmNOsTw", c)) /* if with arg */
					p += strlen(p) - 1;	/* skip */
				break;
			}
		}
	}
	if (!quiet)
		display_version(0);

	/* initialize */
	outfn[0] = '\0';
	clrarena(0);				/* global */
	clrarena(1);				/* tunes */
	clrarena(2);				/* generation */
	if (aaa) {				/* '-k' output buffer size */
		int kbsz;

		sscanf(aaa, "%d", &kbsz);
		init_outbuf(kbsz);
	} else {
		init_outbuf(0);
	}
	abc_init(getarena,			/* alloc */
		0,				/* free */
		(void (*)(int level)) lvlarena, /* new level */
		sizeof(struct SYMBOL) - sizeof(struct abcsym),
		0);				/* don't keep comments */
//	memset(&info, 0, sizeof info);
	info['T' - 'A'] = &notitle;
	notitle.as.text = "T:";
	set_format();
	reset_deco();
	front_init(0, 0, include_cb);

#ifdef linux
	/* if not set, try to find where is the default format directory */
	if (styd[0] == '\0')
		wherefmtdir();
#endif
#ifdef HAVE_PANGO
	pg_init();
#endif

	/* parse the arguments - finding a new file, treat the previous one */
	argc = s_argc;
	argv = s_argv;
	while (--argc > 0) {
		argv++;
		p = *argv;
		if ((c = *p) == '\0')
			continue;
		if (c == '-') {
			int i;

			if (p[1] == '\0') {		/* '-' alone */
				if (in_fname) {
					treat_file(in_fname, "abc");
					frontend((unsigned char *) "select\n", 0);
				}
				in_fname = "";		/* read from stdin */
				continue;
			}
			i = strlen(p) - 1;
			if (p[i] == '-'
			 && p[1] != '-'
//fixme: 'e' may be preceded by other options
			 && p[1] != 'e'
			 && p[i -1] != 'O')
				c = '+'; /* switch off flags with '-x-' */
		}
		if (c == '+') {		/* switch off flags with '+' */
			while (*++p != '\0') {
				switch (*p) {
				case '-':
					break;
				case 'B':
					cfmt.barsperstaff = 0;
					lock_fmt(&cfmt.barsperstaff);
					break;
				case 'c':
					cfmt.continueall = 0;
					lock_fmt(&cfmt.continueall);
					break;
				case 'F':
//					 def_fmt_done = 1;
					break;
				case 'G':
					cfmt.graceslurs = 1;
					lock_fmt(&cfmt.graceslurs);
					break;
				case 'i':
					showerror = 0;
					break;
				case 'j':
					cfmt.measurenb = -1;
					lock_fmt(&cfmt.measurenb);
					break;
				case 'l':
					cfmt.landscape = 0;
					lock_fmt(&cfmt.landscape);
					break;
				case 'M':
					cfmt.fields[1] = 1 << ('w' - 'a');
					lock_fmt(&cfmt.fields);
					break;
				case 'N':
					pagenumbers = 0;
					break;
				case 'O':
					outfn[0] = '\0';
					break;
				case 'T': {
					struct cmdtblt_s *cmdtblt;

					aaa = p + 1;
					if (*aaa == '\0') {
						if (argc > 1
						    && argv[1][0] != '-') {
							aaa = *++argv;
							argc--;
						}
					} else {
						while (p[1] != '\0')	/* stop */
							p++;
						if (*p == '-')
							*p-- = '\0';	/* (not clean) */
					}
					cmdtblt = cmdtblt_parse(aaa);
					if (cmdtblt != 0)
						cmdtblt->active = 0;
					break;
				   }
				case 'x':
					cfmt.fields[0] &= ~(1 << ('X' - 'A'));
					lock_fmt(&cfmt.fields);
					break;
				case '0':
					cfmt.splittune = 0;
					lock_fmt(&cfmt.splittune);
					break;
				case '1':
					cfmt.oneperpage = 0;
					lock_fmt(&cfmt.oneperpage);
					break;
				default:
					error(1, NULL,
						"++++ Cannot switch off flag: +%c",
						*p);
					break;
				}
			}
			continue;
		}

		if (c == '-') {		     /* interpret a flag with '-' */
			if (p[1] == '-') {		/* long argument */
				p += 2;
				if (--argc <= 0) {
					error(1, NULL, "No argument for '--'");
					return EXIT_FAILURE;
				}
				argv++;
				set_opt(p, *argv);
				continue;
			}
			while ((c = *++p) != '\0') {
				switch (c) {

					/* simple flags */
				case 'A':
					annotate = 1;
					break;
				case 'c':
					cfmt.continueall = 1;
					lock_fmt(&cfmt.continueall);
					break;
				case 'E':
					break;
				case 'f':
					cfmt.flatbeams = 1;
					lock_fmt(&cfmt.flatbeams);
					break;
				case 'G':
					cfmt.graceslurs = 0;
					lock_fmt(&cfmt.graceslurs);
					break;
				case 'g':
					break;
				case 'H':
					if (!fout) {
						read_def_format();
						make_font_list();
					}
					print_format();
					return EXIT_SUCCESS;
				case 'i':
					showerror = 1;
					break;
				case 'l':
					cfmt.landscape = 1;
					lock_fmt(&cfmt.landscape);
					break;
				case 'M':
					cfmt.fields[1] &= ~(1 << ('w' - 'a'));
					lock_fmt(&cfmt.fields);
					break;
				case 'q':
				case 'S':
					break;
				case 'v':
				case 'X':
					break;
				case 'x':
					cfmt.fields[0] |= 1 << ('X' - 'A');
					lock_fmt(&cfmt.fields);
					break;
				case '0':
					cfmt.splittune = 1;
					lock_fmt(&cfmt.splittune);
					break;
				case '1':
					cfmt.oneperpage = 1;
					lock_fmt(&cfmt.oneperpage);
					break;

					/* flag with optional parameter */
				case 'N':
					if (p[1] == '\0'
					 && (argc <= 1
					  || !isdigit((unsigned) argv[1][0]))) {
						pagenumbers = 2; /* old behaviour */
						break;
					}
					/* fall thru */
					/* flags with parameter.. */
				case 'a':
				case 'B':
				case 'b':
				case 'D':
				case 'd':
				case 'e':
				case 'F':
				case 'I':
				case 'j':
				case 'k':
				case 'L':
				case 'm':
				case 'O':
				case 's':
				case 'T':
				case 'w':
					aaa = p + 1;
					if (*aaa == '\0') {
						aaa = *++argv;
						if (--argc <= 0
						 || (*aaa == '-' && c != 'O')) {
							error(1, NULL,
								"Missing parameter after '-%c' - aborting",
								c);
							return EXIT_FAILURE;
						}
					} else {
						p += strlen(p) - 1;	/* stop */
					}

					if (strchr("BbfjkNs", c)) {	/* check num args */
						for (j = 0; j < strlen(aaa); j++) {
							if (!strchr("0123456789.",
								    aaa[j])) {
								if (aaa[j] == 'b'
								 && aaa[j + 1] == '\0'
								 && c == 'j')
									break;
								error(1, NULL,
									"Invalid parameter <%s> for flag -%c",
									aaa, c);
								return EXIT_FAILURE;
							}
						}
					}

					switch (c) {
					case 'a':
						set_opt("maxshrink", aaa);
						break;
					case 'B':
						set_opt("barsperstaff", aaa);
						break;
					case 'b':
						set_opt("measurefirst", aaa);
						break;
					case 'D':
						styd = aaa;
						break;
					case 'd':
						set_opt("staffsep", aaa);
						break;
					case 'e':
						set_opt("select", aaa);
						break;
					case 'F':
						treat_file(aaa, "fmt");
						break;
					case 'I':
						set_opt("indent", aaa);
						break;
					case 'j':
						sscanf(aaa, "%d", &cfmt.measurenb);
						lock_fmt(&cfmt.measurenb);
						if (aaa[strlen(aaa) - 1] == 'b')
							cfmt.measurebox = 1;
						else
							cfmt.measurebox = 0;
						lock_fmt(&cfmt.measurebox);
						break;
					case 'k':
						break;
					case 'm':
						set_opt("leftmargin", aaa);
						break;
					case 'N':
						sscanf(aaa, "%d", &pagenumbers);
						if ((unsigned) pagenumbers > 4) {
							error(1, NULL,
								"'-N' value %s - changed to 2",
								aaa);
							pagenumbers = 2;
						}
						break;
					case 'O':
						if (strlen(aaa) >= sizeof outfn) {
							error(1, NULL, "'-O' too large - aborting");
							exit(EXIT_FAILURE);
						}
						strcpy(outfn, aaa);
						break;
					case 's':
						set_opt("scale", aaa);
						break;
					case 'T': {
						struct cmdtblt_s *cmdtblt;

						cmdtblt = cmdtblt_parse(aaa);
						if (cmdtblt)
							cmdtblt->active = 1;
						break;
					    }
					case 'w':
						set_opt("staffwidth", aaa);
						break;
					}
					break;
				default:
					error(1, NULL,
						"Unknown flag: -%c ignored", c);
					break;
				}
			}
			continue;
		}

		if (in_fname) {
			treat_file(in_fname, "abc");
			frontend((unsigned char *) "select\n", 0);
		}
		in_fname = p;
	}

	if (in_fname)
		treat_file(in_fname, "abc");
	if (multicol_start != 0) {		/* lack of %%multicol end */
		error(1, NULL, "Lack of %%%%multicol end");
		multicol_start = 0;
		buffer_eob();
		if (!info['X' - 'A']
		 && !epsf)
			write_buffer();
	}
	if (!epsf && !fout) {
		error(1, NULL, "No input file specified");
		return EXIT_FAILURE;
	}
	close_output_file();
	return severity == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}

/* -- arena routines -- */
void clrarena(int level)
{
	struct str_a *a_p;

	if ((a_p = str_r[level]) == NULL) {
		str_r[level] = a_p = malloc(sizeof *str_r[0] + AREANASZ - 2);
		a_p->sz = AREANASZ;
		a_p->n = 0;
	}
	str_c[level] = a_p;
	a_p->p = a_p->str;
	a_p->r = sizeof a_p->str;
}

int lvlarena(int level)
{
	int old_level;

	old_level = str_level;
	str_level = level;
	return old_level;
}

/* The area is 8 bytes aligned to handle correctly int and pointers access
 * on some machines as Sun Sparc. */
void *getarena(int len)
{
	char *p;
	struct str_a *a_p;

	a_p = str_c[str_level];
	len = (len + 7) & ~7;		/* align at 64 bits boundary */
	if (len > a_p->r) {
		if (len > MAXAREANASZ) {
			error(1, NULL,
				"getarena - data too wide %d - aborting",
				len);
			exit(EXIT_FAILURE);
		}
		if (len > AREANASZ) {			/* big allocation */
			struct str_a *a_n;

			a_n = a_p->n;
			a_p->n = malloc(sizeof *str_r[0] + len - 2);
			a_p->n->n = a_n;
			a_p->n->sz = len;
		} else if (a_p->n == 0) {		/* standard allocation */
			a_p->n = malloc(sizeof *str_r[0] + AREANASZ - 2);
			a_p->n->n = 0;
			a_p->n->sz = AREANASZ;
		}
		str_c[str_level] = a_p = a_p->n;
		a_p->p = a_p->str;
		a_p->r = a_p->sz;
	}
	p = a_p->p;
	a_p->p += len;
	a_p->r -= len;
	return p;
}
abcm2ps-7.8.13/abc2ps.h0000644000175000017500000005067312316602053012567 0ustar  jefjef/* -- general macros -- */

#include <stdio.h>
#include <time.h>

#include "config.h"
#include "abcparse.h"

#define OUTPUTFILE	"Out.ps"	/* standard output file */
#ifndef WIN32
#define DIRSEP '/'
#else
#define DIRSEP '\\'
#endif

#define CM		* 28.35	/* factor to transform cm to pt */
#define PT			/* factor to transform pt to pt */
#define IN		* 72.0	/* factor to transform inch to pt */

/* basic page dimensions */
#ifdef A4_FORMAT
#define PAGEHEIGHT	(29.7 CM)
#define PAGEWIDTH	(21.0 CM)
#define MARGIN		(1.8 CM)
#else
#define PAGEHEIGHT	(11.0 IN)
#define PAGEWIDTH	(8.5 IN)
#define MARGIN		(0.7 IN)
#endif

/* -- macros controlling music typesetting -- */

#define STEM_YOFF	1.0	/* offset stem from note center */
#define STEM_XOFF	3.5
#define STEM		20	/* default stem height */
#define STEM_MIN	16	/* min stem height under beams */
#define STEM_MIN2	14	/* ... for notes with two beams */
#define STEM_MIN3	12	/* ... for notes with three beams */
#define STEM_MIN4	10	/* ... for notes with four beams */
#define STEM_CH_MIN	14	/* min stem height for chords under beams */
#define STEM_CH_MIN2	10	/* ... for notes with two beams */
#define STEM_CH_MIN3	 9	/* ... for notes with three beams */
#define STEM_CH_MIN4	 9	/* ... for notes with four beams */
#define BEAM_DEPTH	3.2	/* width of a beam stroke */
#define BEAM_OFFSET	0.25	/* pos of flat beam relative to staff line */
#define BEAM_SHIFT	5.0	/* shift of second and third beams */
/*  To align the 4th beam as the 1st: shift=6-(depth-2*offset)/3  */
#define BEAM_FLATFAC	0.6	/* factor to decrease slope of long beams */
#define BEAM_THRESH	0.06	/* flat beam if slope below this threshold */
#define BEAM_SLOPE	0.5	/* max slope of a beam */
#define BEAM_STUB	6.0	/* length of stub for flag under beam */ 
#define SLUR_SLOPE	1.0	/* max slope of a slur */
#define DOTSHIFT	5	/* dot shift when up flag on note */
#define GSTEM		14	/* grace note stem length */
#define GSTEM_XOFF	1.6	/* x offset for grace note stem */

#define BETA_C		0.1	/* max expansion for flag -c */
#define BETA_X		1.0	/* max expansion before complaining */

#define VOCPRE		0.4	/* portion of vocals word before note */
#define GCHPRE		0.4	/* portion of guitar chord before note */

/* -- Parameters for note spacing -- */
/* fnn multiplies the spacing under a beam, to compress the notes a bit */

#define fnnp 0.9

/* -- macros for program internals -- */

#define STRL1		256	/* string length for file names */
#define MAXSTAFF	16	/* max staves */
#define BSIZE		512	/* buffer size for one input string */

#define BREVE		(BASE_LEN * 2)	/* double note (square note) */
#define SEMIBREVE	BASE_LEN	/* whole note */
#define MINIM		(BASE_LEN / 2)	/* half note (white note) */
#define CROTCHET 	(BASE_LEN / 4)	/* quarter note (black note) */
#define QUAVER		(BASE_LEN / 8)	/* 1/8 note */
#define SEMIQUAVER	(BASE_LEN / 16)	/* 1/16 note */

#define MAXFONTS	30	/* max number of fonts */

#define T_LEFT		0
#define T_JUSTIFY	1
#define T_FILL		2
#define T_CENTER	3
#define T_SKIP		4
#define T_RIGHT		5

#define YSTEP	128		/* number of steps for y offsets */

extern unsigned char deco[256];

struct FONTSPEC {
	int fnum;		/* index to font tables in format.c */
	float size;
	float swfac;
};
extern char *fontnames[MAXFONTS];	/* list of font names */

/* lyrics */
#define LY_HYPH	0x10	/* replacement character for hyphen */
#define LY_UNDER 0x11	/* replacement character for underscore */
#define MAXLY	16	/* max number of lyrics */
struct lyl {
	struct FONTSPEC *f;	/* font */
	float w;		/* width */
	float s;		/* shift / note */
	char t[1];		/* word */
};
struct lyrics {
	struct lyl *lyl[MAXLY];	/* ptr to lyric lines */
};

/* guitar chord / annotations */
#define MAXGCH 8		/* max number of guitar chords / annotations */
struct gch {
	char type;		/* ann. char, 'g' gchord, 'r' repeat, '\0' end */
	unsigned char idx;	/* index in as.text */
	unsigned char font;	/* font */
	char box;		/* 1 if in box */
	float x, y;		/* x y offset / note + (top or bottom) of staff */
	float w;		/* width */
};

/* positions / directions */
/* 0: auto, 1: above/up (SL_ABOVE), 2: below/down (SL_BELOW)
 * 3: hidden (SL_AUTO) or opposite for gstemdir */
#define SL_HIDDEN SL_AUTO
struct posit_s {
	unsigned short dyn:2;	/* %%dynamic */
	unsigned short gch:2;	/* %%gchord */
	unsigned short orn:2;	/* %%ornament */
	unsigned short voc:2;	/* %%vocal */
	unsigned short vol:2;	/* %%volume */
	unsigned short std:2;	/* %%stemdir */
	unsigned short gsd:2;	/* %%gstemdir */
};

/* music element */
struct SYMBOL { 		/* struct for a drawable symbol */
	struct abcsym as;	/* abc symbol !!must be the first field!! */
	struct SYMBOL *next, *prev;	/* voice linkage */
	struct SYMBOL *ts_next, *ts_prev; /* time linkage */
	struct SYMBOL *extra;	/* extra symbols (grace notes, tempo... */
	unsigned char type;	/* symbol type */
#define NO_TYPE		0	/* invalid type */
#define NOTEREST	1	/* valid symbol types */
#define SPACE		2
#define BAR		3
#define CLEF		4
#define TIMESIG 	5
#define KEYSIG		6
#define TEMPO		7
#define STAVES		8
#define MREST		9
#define PART		10
#define GRACE		11
#define FMTCHG		12
#define TUPLET		13
#define STBRK		14
#define CUSTOS		15
#define NSYMTYPES	16
	unsigned char voice;	/* voice (0..nvoice) */
	unsigned char staff;	/* staff (0..nstaff) */
	unsigned char nhd;	/* number of notes in chord - 1 */
	int dur;		/* main note duration */
	signed char pits[MAXHD]; /* pitches for notes */
	int time;		/* starting time */
	unsigned int sflags;	/* symbol flags */
#define S_EOLN		0x0001		/* end of line */
#define S_BEAM_ST	0x0002		/* beam starts here */
#define S_BEAM_BR1	0x0004		/* 2nd beam must restart here */
#define S_BEAM_BR2	0x0008		/* 3rd beam must restart here */
#define S_BEAM_END	0x0010		/* beam ends here */
#define S_OTHER_HEAD	0x0020		/* don't draw any note head */
#define S_IN_TUPLET	0x0040		/* in a tuplet */
#define S_TREM2		0x0080		/* tremolo on 2 notes */
#define S_RRBAR		0x0100		/* right repeat bar (when bar) */
#define S_XSTEM		0x0200		/* cross-staff stem (when note) */
#define S_BEAM_ON	0x0400		/* continue beaming */
#define S_SL1		0x0800		/* some chord slur start */
#define S_SL2		0x1000		/* some chord slur end */
#define S_TI1		0x2000		/* some chord tie start */
#define S_PERC		0x4000		/* percussion */
#define S_RBSTOP	0x8000		/* repeat bracket stop */
#define S_FEATHERED_BEAM 0x00010000	/* feathered beam */
#define S_REPEAT	0x00020000	/* sequence / measure repeat */
#define S_NL		0x00040000	/* start of new music line */
#define S_SEQST		0x00080000	/* start of vertical sequence */
#define S_SECOND	0x00100000	/* symbol on a secondary voice */
#define S_FLOATING	0x00200000	/* symbol on a floating voice */
#define S_NOREPBRA	0x00400000	/* don't print the repeat bracket */
#define S_TREM1		0x00800000	/* tremolo on 1 note */
#define S_TEMP		0x01000000	/* temporary symbol */
#define S_SHIFTUNISON_1	0x02000000	/* %%shiftunison 1 */
#define S_SHIFTUNISON_2	0x04000000	/* %%shiftunison 2 */
	struct posit_s posit;	/* positions / directions */
	signed char stem;	/* 1 / -1 for stem up / down */
	signed char nflags;	/* number of note flags when > 0 */
	char dots;		/* number of dots */
	unsigned char head;	/* head type */
#define H_FULL		0
#define H_EMPTY 	1
#define H_OVAL		2
#define H_SQUARE	3
	signed char multi;	/* multi voice in the staff (+1, 0, -1) */
	signed char nohdix;	/* no head index (for unison) */
	short u;		/* auxillary information:
				 *	- CLEF: small clef
				 *	- KEYSIG: old key signature
				 *	- BAR: new bar number
				 *	- TUPLET: tuplet format
				 *	- NOTE: tremolo number / feathered beam
				 *	- FMTCHG (format change): subtype */
#define PSSEQ 0				/* postscript sequence */
#define SVGSEQ 1			/* SVG sequence */
#define REPEAT 2			/* repeat sequence or measure
					 *	doty: # measures if > 0
					 *	      # notes/rests if < 0
					 *	nohdix: # repeat */
	float x;		/* x offset */
	signed char y;		/* y offset of note head */
	signed char ymn, ymx, yav; /* min, max, avg note head y offset */
	float xmx;		/* max h-pos of a head rel to top
				 * width when STBRK */
	float xs, ys;		/* coord of stem end / bar height */
	float wl, wr;		/* left, right min width */
	float space;		/* natural space before symbol */
	float shrink;		/* minimum space before symbol */
	float xmax;		/* max x offset */
	float shhd[MAXHD];	/* horizontal shift for heads */
	float shac[MAXHD];	/* horizontal shift for accidentals */
	struct gch *gch;	/* guitar chords / annotations */
	struct lyrics *ly;	/* lyrics */
	signed char doty;	/* NOTEREST: y pos of dot when voices overlap
				 * STBRK: forced
				 * FMTCHG REPEAT: infos */
};

/* bar types !tied to abcparse.h! */
#define B_SINGLE B_BAR		/* |	single bar */
#define B_DOUBLE 0x11		/* ||	thin double bar */
#define B_THIN_THICK 0x13	/* |]	thick at section end  */
#define B_THICK_THIN 0x21	/* [|	thick at section start */
#define B_LREP 0x14		/* |:	left repeat bar */
#define B_RREP 0x41		/* :|	right repeat bar */
#define B_DREP 0x44		/* ::	double repeat bar */
#define B_DASH 0x04		/* :	dashed bar */

extern unsigned short *micro_tb; /* ptr to the microtone table of the tune */

struct FORMAT { 		/* struct for page layout */
	float pageheight, pagewidth;
	float topmargin, botmargin, leftmargin, rightmargin;
	float topspace, wordsspace, titlespace, subtitlespace, partsspace;
	float composerspace, musicspace, vocalspace, textspace;
	float breaklimit, maxshrink, lineskipfac, parskipfac, stemheight;
	float indent, infospace, slurheight, notespacingfactor, scale;
	float staffsep, sysstaffsep, maxstaffsep, maxsysstaffsep, stretchlast;
	int abc2pscompat, alignbars, aligncomposer, autoclef;
	int barsperstaff, breakoneoln, bstemdown, cancelkey;
	int combinevoices, contbarnb, continueall, custos;
	int dblrepbar, dynalign, flatbeams;
	int infoline, gchordbox, graceslurs, gracespace, hyphencont;
	int keywarn, landscape, linewarn;
	int measurebox, measurefirst, measurenb, micronewps, microscale;
	int oneperpage;
#ifdef HAVE_PANGO
	int pango;
#endif
	int partsbox, pdfmark;
	int setdefl, shiftunison, splittune, squarebreve;
	int staffnonote, straightflags, stretchstaff;
	int textoption, titlecaps, titleleft, titletrim;
	int timewarn, transpose, tuplets;
	char *bgcolor, *dateformat, *header, *footer, *titleformat;
#define FONT_UMAX 5		/* max number of user fonts */
#define ANNOTATIONFONT 5
#define COMPOSERFONT 6
#define FOOTERFONT 7
#define GCHORDFONT 8
#define HEADERFONT 9
#define HISTORYFONT 10
#define INFOFONT 11
#define MEASUREFONT 12
#define PARTSFONT 13
#define REPEATFONT 14
#define SUBTITLEFONT 15
#define TEMPOFONT 16
#define TEXTFONT 17
#define TITLEFONT 18
#define VOCALFONT 19
#define VOICEFONT 20
#define WORDSFONT 21
#define FONT_DYN 22		/* index of dynamic fonts (gch, an, ly) */
#define FONT_DYNX 12		/* number of dynamic fonts */
#define FONT_MAX (FONT_DYN+FONT_DYNX)		/* whole number of fonts */
	struct FONTSPEC font_tb[FONT_MAX];
	char ndfont;		/* current index of dynamic fonts */
	unsigned char gcf, anf, vof;	/* fonts for guitar chords,
					 * annotations and lyrics */
	unsigned int fields[2];	/* info fields to print
				 *[0] is 'A'..'Z', [1] is 'a'..'z' */
	struct posit_s posit;
};

extern struct FORMAT cfmt;	/* current format */
extern struct FORMAT dfmt;	/* global format */

typedef struct SYMBOL *INFO[26]; /* information fields ('A' .. 'Z') */
extern INFO info;

extern char *outbuf;		/* output buffer.. should hold one tune */
extern char *mbf;		/* where to PUTx() */
extern int use_buffer;		/* 1 if lines are being accumulated */

extern int outft;		/* last font in the output file */
extern int tunenum;		/* number of current tune */
extern int pagenum;		/* current page number */
extern int nbar;		/* current measure number */
extern int in_page;
extern int defl;		/* decoration flags */
#define DEF_NOST 0x01		/* long deco with no start */
#define DEF_NOEN 0x02		/* long deco with no end */
#define DEF_STEMUP 0x04		/* stem up (1) or down (0) */

		/* switches modified by flags: */
extern int quiet;		/* quiet mode */
extern int secure;		/* secure mode */
extern int annotate;		/* output source references */
extern int pagenumbers; 	/* write page numbers */
extern int epsf;		/* EPSF (1) / SVG (2) output */
extern int svg;			/* SVG (1) or XML (2 - HTML + SVG) output */
extern int showerror;		/* show the errors */

extern char outfn[FILENAME_MAX]; /* output file name */
extern char *in_fname;		/* current input file name */
extern time_t mtime;		/* last modification time of the input file */

extern int file_initialized;	/* for output file */
extern FILE *fout;		/* output file */

#define MAXTBLT 8
struct tblt_s {
	char *head;		/* PS head function */
	char *note;		/* PS note function */
	char *bar;		/* PS bar function */
	float wh;		/* width of head */
	float ha;		/* height above the staff */
	float hu;		/* height under the staff */
	short pitch;		/* pitch when no associated 'w:' / 0 */
	char instr[2];		/* instrument pitch */
};
extern struct tblt_s *tblts[MAXTBLT];

#define MAXCMDTBLT	4	/* max number of -T in command line */
struct cmdtblt_s {
	short index;		/* tablature number */
	short active;		/* activate or not */
	char *vn;		/* voice name */
};
extern struct cmdtblt_s cmdtblts[MAXCMDTBLT];
extern int ncmdtblt;

extern int s_argc;		/* command line arguments */
extern char **s_argv;

struct STAFF_S {
	struct clef_s clef;	/* base clef */
	char forced_clef;	/* explicit clef */
	char empty;		/* no symbol on this staff */
	short botbar, topbar;	/* bottom and top of bar */
	float y;		/* y position */
	float top[YSTEP], bot[YSTEP];	/* top/bottom y offsets */
};
extern struct STAFF_S staff_tb[MAXSTAFF];
extern int nstaff;		/* (0..MAXSTAFF-1) */

struct VOICE_S {
	struct VOICE_S *next;	/* link */
	struct SYMBOL *sym;	/* associated symbols */
	struct SYMBOL *last_sym; /* last symbol while scanning */
	struct SYMBOL *lyric_start;	/* start of lyrics while scanning */
	char id[VOICE_ID_SZ];	/* voice id */
	char *nm;		/* voice name */
	char *snm;		/* voice subname */
	char *bar_text;		/* bar text at start of staff when bar_start */
	struct gch *bar_gch;	/* bar text */
	struct SYMBOL *tie;	/* note with ties of previous line */
	struct SYMBOL *rtie;	/* note with ties before 1st repeat bar */
	struct tblt_s *tblts[2]; /* tablatures */
	float scale;		/* scale */
	int time;		/* current time (parsing) */
	struct clef_s clef;	/* current clef */
	struct key_s key;	/* current key signature */
	struct meter_s meter;	/* current time signature */
	struct key_s ckey;	/* key signature while parsing */
	struct key_s okey;	/* original key signature (parsing) */
	unsigned hy_st;		/* lyrics hyphens at start of line (bit array) */
	unsigned ignore:1;	/* ignore this voice (%%staves) */
	unsigned forced_clef:1;	/* explicit clef */
	unsigned second:1;	/* secondary voice in a brace/parenthesis */
	unsigned floating:1;	/* floating voice in a brace system */
	unsigned bar_repeat:1;	/* bar at start of staff is a repeat bar */
	unsigned norepbra:1;	/* don't display the repeat brackets */
	unsigned have_ly:1;	/* some lyrics in this voice */
	unsigned new_name:1;	/* redisplay the voice name */
	unsigned space:1;	/* have a space before the next note (parsing) */
	unsigned perc:1;	/* percussion */
	unsigned auto_len:1;	/* auto L: (parsing) */
	short wmeasure;		/* measure duration (parsing) */
	short transpose;	/* transposition (parsing) */
	short bar_start;	/* bar type at start of staff / 0 */
	struct posit_s posit;	/* positions / directions */
	signed char octave;	/* octave (parsing) */
	signed char clone;	/* duplicate from this voice number */
	signed char over;	/* overlay of this voice number */
	unsigned char staff;	/* staff (0..n-1) */
	unsigned char cstaff;	/* staff (parsing) */
	unsigned char slur_st;	/* slurs at start of staff */
};
extern struct VOICE_S voice_tb[MAXVOICE]; /* voice table */
extern struct VOICE_S *first_voice; /* first_voice */

extern struct SYMBOL *tsfirst;	/* first symbol in the time linked list */
extern struct SYMBOL *tsnext;	/* next line when cut */
extern float realwidth;		/* real staff width while generating */

#define NFLAGS_SZ 10		/* size of note flags tables */
#define C_XFLAGS 5		/* index of crotchet in flags tables */
extern float space_tb[NFLAGS_SZ]; /* note spacing */

struct SYSTEM {			/* staff system */
	struct SYSTEM *next;
	short top_voice;	/* first voice in the staff system */
	short nstaff;
	struct {
		short flags;
#define OPEN_BRACE 0x01
#define CLOSE_BRACE 0x02
#define OPEN_BRACKET 0x04
#define CLOSE_BRACKET 0x08
#define OPEN_PARENTH 0x10
#define CLOSE_PARENTH 0x20
#define STOP_BAR 0x40
#define FL_VOICE 0x80
#define OPEN_BRACE2 0x0100
#define CLOSE_BRACE2 0x0200
#define OPEN_BRACKET2 0x0400
#define CLOSE_BRACKET2 0x0800
		char empty;
		char dum;
		struct clef_s clef;
		float sep, maxsep;
	} staff[MAXSTAFF];
	struct {
		signed char range;
		unsigned char staff;
		char second;
		char dum;
		float sep, maxsep;
		struct clef_s clef;
	} voice[MAXVOICE];
};
struct SYSTEM *cursys;		/* current staff system */

/* -- external routines -- */
/* abc2ps.c */
void clrarena(int level);
int lvlarena(int level);
void *getarena(int len);
void strext(char *fid, char *ext);
/* buffer.c */
void a2b(char *fmt, ...)
#ifdef __GNUC__
	__attribute__ ((format (printf, 1, 2)))
#endif
	;
void block_put(void);
void buffer_eob(void);
void marg_init(void);
void bskip(float h);
void check_buffer(void);
void init_outbuf(int kbsz);
void close_output_file(void);
void close_page(void);
float get_bposy(void);
void write_buffer(void);
int (*output)(FILE *out, const char *fmt, ...)
#ifdef __GNUC__
	__attribute__ ((format (printf, 2, 3)))
#endif
	;
void write_eps(void);
/* deco.c */
void deco_add(char *text);
void deco_cnv(struct deco *dc, struct SYMBOL *s, struct SYMBOL *prev);
unsigned char deco_intern(unsigned char deco);
unsigned char deco_define(char *name);
void deco_update(struct SYMBOL *s, float dx);
float deco_width(struct SYMBOL *s);
void draw_all_deco(void);
int draw_deco_head(int deco, float x, float y, int stem);
void draw_all_deco_head(struct SYMBOL *s, float x, float y);
void draw_deco_near(void);
void draw_deco_note(void);
void draw_deco_staff(void);
float draw_partempo(int staff, float top);
void draw_measnb(void);
void reset_deco(void);
void set_defl(int new_defl);
float tempo_width(struct SYMBOL *s);
void write_tempo(struct SYMBOL *s,
		int beat,
		float sc);
float y_get(int staff,
		int up,
		float x,
		float w);
void y_set(int staff,
		int up,
		float x,
		float w,
		float y);
/* draw.c */
void draw_sym_near(void);
void draw_all_symb(void);
float draw_systems(float indent);
void output_ps(struct SYMBOL *s, int state);
void putf(float f);
void putx(float x);
void puty(float y);
void putxy(float x, float y);
void set_scale(struct SYMBOL *s);
void set_sscale(int staff);
/* format.c */
void define_fonts(void);
int get_textopt(char *p);
int get_font_encoding(int ft);
void interpret_fmt_line(char *w, char *p, int lock);
void lock_fmt(void *fmt);
void make_font_list(void);
FILE *open_file(char *fn,
		char *ext,
		char *rfn);
void print_format(void);
void set_font(int ft);
void set_format(void);
void set_voice_param(struct VOICE_S *p_voice, int state, char *w, char *p);
struct tblt_s *tblt_parse(char *p);
/* glyph.c */
char *glyph_out(char *p);
void glyph_add(char *p);
/* music.c */
void output_music(void);
void reset_gen(void);
void unlksym(struct SYMBOL *s);
/* parse.c */
extern float multicol_start;
void do_tune(struct abctune *t);
void identify_note(struct SYMBOL *s,
		int len,
		int *p_head,
		int *p_dots,
		int *p_flags);
void sort_pitch(struct SYMBOL *s, int combine);
struct SYMBOL *sym_add(struct VOICE_S *p_voice,
			int type);
/* subs.c */
void bug(char *msg, int fatal);
void error(int sev, struct SYMBOL *s, char *fmt, ...);
float scan_u(char *str);
float cwid(unsigned short c);
void get_str_font(int *cft, int *dft);
void set_str_font(int cft, int dft);
#ifdef HAVE_PANGO
void pg_init(void);
void pg_reset_font(void);
#endif
void put_history(void);
void put_words(struct SYMBOL *words);
void str_font(int ft);
#define A_LEFT 0
#define A_CENTER 1
#define A_RIGHT 2
#define A_LYRIC 3
#define A_GCHORD 4
#define A_ANNOT 5
#define A_GCHEXP 6
void str_out(char *p, int action);
void put_str(char *str, int action);
float tex_str(char *s);
extern char tex_buf[];	/* result of tex_str() */
#define TEX_BUF_SZ 512
char *trim_title(char *p, struct SYMBOL *title);
void user_ps_add(char *s, char use);
void user_ps_write(void);
void write_title(struct SYMBOL *s);
void write_heading(struct abctune *t);
void write_user_ps(void);
void write_text(char *cmd, char *s, int job);
/* svg.c */
void define_svg_symbols(char *title, int num, float w, float h);
int svg_output(FILE *out, const char *fmt, ...)
#ifdef __GNUC__
	__attribute__ ((format (printf, 2, 3)))
#endif
	;
void svg_write(char *buf, int len);
void svg_close();
/* syms.c */
void define_font(char *name, int num, int enc);
void define_symbols(void);
abcm2ps-7.8.13/abcparse.c0000644000175000017500000016702412442636320013173 0ustar  jefjef/*
 * Generic ABC parser.
 *
 * Copyright (C) 1998-2014 Jean-François Moine
 * Adapted from abc2ps, Copyright (C) 1996, 1997 Michael Methfessel
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 */

#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "abcparse.h"

/* interface */
static void *(*alloc_f)(int size);
static void (*free_f)(void *);
static void (*level_f)(int level);
static int client_sz;
static int keep_comment;

/* global values */
char *deco_tb[128];		/* decoration names */
int severity;			/* error severity */

static int abc_vers;		/* abc version */
static short abc_state;		/* parse state */
static short ulen;		/* unit note length set by M: or L: */
static short meter;		/* upper value of time sig for n-plets */
static unsigned char microscale; /* current microtone scale */
static signed char vover;	/* voice overlay (1: single bar, -1: multi-bar */
static char lyric_started;	/* lyric started */
static char *gchord;		/* guitar chord */
static struct deco dc;		/* decorations */
static struct abcsym *deco_start; /* 1st note of the line for d: / s: */
static struct abcsym *deco_cont; /* current symbol when d: / s: continuation */
static unsigned short *p_micro;	/* ptr to the microtone table of the tune */

#define VOICE_NAME_SZ 64	/* max size of a voice name */

static char *file;		/* remaining abc file */
static int linenum;		/* current source line number */
static int colnum;		/* current source column number */
static char *abc_line;		/* line being parsed */
static struct abcsym *last_sym;	/* last symbol for errors */

static short nvoice;		/* number of voices (0..n-1) */
static struct {			/* voice table and current pointer */
	char id[VOICE_ID_SZ];		/* voice ID */
	struct abcsym *last_note;	/* last note or rest */
	short ulen;			/* unit note length */
	unsigned char microscale;	/* microtone scale */
	unsigned char mvoice;		/* main voice when voice overlay */
} voice_tb[MAXVOICE], *curvoice;

/* char table for note line parsing */
#define CHAR_BAD 0
#define CHAR_IGN 1
#define CHAR_NOTE 2
#define CHAR_REST 3
#define CHAR_ACC 4
#define CHAR_GR_ST 5
#define CHAR_DECO 6
#define CHAR_GCHORD 7
#define CHAR_BSLASH 8
#define CHAR_OBRA 9
#define CHAR_BAR 10
#define CHAR_OPAR 11
#define CHAR_VOV 12
#define CHAR_SPAC 13
#define CHAR_MINUS 14
#define CHAR_CPAR 15
#define CHAR_BRHY 16
#define CHAR_DECOS 17
#define CHAR_SLASH 18
#define CHAR_GR_EN 19
#define CHAR_LINEBREAK 20
static char char_tb[256] = {
	0, 0, 0, 0, 0, 0, 0, 0,				/* 00 - 07 */
	0, CHAR_SPAC, CHAR_LINEBREAK, 0, 0, 0, 0, 0,	/* 08 - 0f */
	0, 0, 0, 0, 0, 0, 0, 0,				/* 10 - 17 */
	0, 0, 0, 0, 0, 0, 0, 0,				/* 18 - 1f */
	CHAR_SPAC, CHAR_DECOS, CHAR_GCHORD, CHAR_BAD,	/* (sp) ! " # */
	CHAR_BAD, CHAR_BAD, CHAR_VOV, CHAR_BAD, 	/* $ % & ' */
	CHAR_OPAR, CHAR_CPAR, CHAR_BAD, CHAR_DECOS, 	/* ( ) * + */
	CHAR_BAD, CHAR_MINUS, CHAR_DECO, CHAR_SLASH, 	/* , - . / */
	CHAR_BAD, CHAR_BAD, CHAR_BAD, CHAR_BAD, 	/* 0 1 2 3 */
	CHAR_BAD, CHAR_BAD, CHAR_BAD, CHAR_BAD, 	/* 4 5 6 7 */
	CHAR_BAD, CHAR_BAD, CHAR_BAR, CHAR_BAD, 	/* 8 9 : ; */
	CHAR_BRHY, CHAR_ACC, CHAR_BRHY, CHAR_BAD, 	/* < = > ? */
	CHAR_BAD, CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, 	/* @ A B C */
	CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, 	/* D E F G */
	CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, 	/* H I J K */
	CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, 	/* L M N O */
	CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, 	/* P Q R S */
	CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, 	/* T U V W */
	CHAR_REST, CHAR_DECO, CHAR_REST, CHAR_OBRA, 	/* X Y Z [ */
	CHAR_BSLASH, CHAR_BAR, CHAR_ACC, CHAR_ACC, 	/* \ ] ^ _ */
	CHAR_IGN, CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, 	/* ` a b c */
	CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, 	/* d e f g */
	CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, 	/* h i j k */
	CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, 	/* l m n o */
	CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, 	/* p q r s */
	CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, 	/* t u v w */
	CHAR_REST, CHAR_REST, CHAR_REST, CHAR_GR_ST, 	/* x y z { */
	CHAR_BAR, CHAR_GR_EN, CHAR_DECO, CHAR_BAD, 	/* | } ~ (del) */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* 80 - 8f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* 90 - 9f */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* a0 - af */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* b0 - bf */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* c0 - cf */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* d0 - df */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* e0 - ef */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,		/* f0 - ff */
};

static const char all_notes[] = "CDEFGABcdefgab";

static char *get_line(void);
static char *parse_len(char *p,
			int *p_len);
static char *parse_basic_note(char *p,
			      int *pitch,
			      int *length,
			      int *accidental,
			      int *stemless);
static int parse_info(struct abctune *t,
		       char *p,
		       char *comment);
static char *parse_gchord(char *p);
static int parse_line(struct abctune *t,
		      char *p);
static char *parse_note(struct abctune *t,
			char *p,
			int flags);
static void syntax(char *msg, char *q);
static void vover_new(void);

/* -- abcMIDI like errors -- */
static void print_error(char *s, int col)
{
	if (col >= 0)
		fprintf(stderr, "Error in line %d.%d: %s\n", linenum, col, s);
	else
		fprintf(stderr, "Error in line %d: %s\n", linenum, s);
}

/* -- delete an ABC symbol -- */
void abc_delete(struct abcsym *as)
{
	switch (as->type) {
	case ABC_T_INFO:
		switch (as->text[0]) {
		case 'Q':
			if (as->u.tempo.str1)
				free_f(as->u.tempo.str1);
			if (as->u.tempo.value)
				free_f(as->u.tempo.value);
			if (as->u.tempo.str2)
				free_f(as->u.tempo.str2);
			break;
		case 'V':
			if (as->u.voice.fname)
				free_f(as->u.voice.fname);
			if (as->u.voice.nname)
				free_f(as->u.voice.nname);
			break;
		}
		break;
	}
	if (as->text)
		free_f(as->text);
	if (as->comment)
		free_f(as->comment);

	if (as->prev)
		as->prev->next = as->next;
	if (as->next)
		as->next->prev = as->prev;
	if (as->tune->first_sym == as)
		as->tune->first_sym = as->next;
	if (as->tune->last_sym == as)
		as->tune->last_sym = as->prev;
	free_f(as);
}

/* -- free the memory areas of all tunes -- */
void abc_free(struct abctune *t)
{
	struct abctune *tn;
	struct abcsym *s, *sn;

	if (!free_f)
		return;
	for (;;) {
		if (!t)
			break;
		s = t->first_sym;

		/* free the associated symbols */
		for (;;) {
			sn = s->next;
			abc_delete(s);
			if ((s = sn) == NULL)
				break;
		}

		/* free the tune */
		tn = t->next;
		free_f(t);
		t = tn;
	}
}

/* -- initialize the parser -- */
void abc_init(void *alloc_f_api(int size),
	      void free_f_api(void *ptr),
	      void level_f_api(int level),
	      int client_sz_api,
	      int keep_comment_api)
{
	if (alloc_f) {
		fprintf(stderr, "abc_init already initialized\n");
		return;
	}
	alloc_f = alloc_f_api;
	free_f = free_f_api;
	level_f = level_f_api;
	client_sz = client_sz_api;
	keep_comment = keep_comment_api;
}

/* -- insert an ABC description -- */
void abc_insert(char *file_api,
		struct abcsym *s)
{
	struct abctune *t;
	char *p;

	/* initialize */
	file = file_api;
	if (level_f)
		level_f(abc_state != ABC_S_GLOBAL);
	abc_state = ABC_S_TUNE;
	linenum = 0;
	t = s->tune;
	t->last_sym = s;

	/* scan till end of description */
	for (;;) {
		if ((p = get_line()) == NULL)
			break;			/* done */
		if (*p == '\0')
			break;			/* blank line --> done */
/*fixme-insert: don't accept X:*/
		/* parse the music line */
		if (parse_line(t, p))
			break;
	}
}

/* -- new symbol -- */
struct abcsym *abc_new(struct abctune *t,
		       char *text,
		       char *comment)
{
	struct abcsym *s;

	s = alloc_f(sizeof *s + client_sz);
	memset(s, 0, sizeof *s + client_sz);
	s->tune = t;
	if (text) {
		s->text = alloc_f(strlen(text) + 1);
		strcpy(s->text, text);
	}
	if (comment) {
		s->comment = alloc_f(strlen(comment) + 1);
		strcpy(s->comment, comment);
	}
	if (!t->last_sym) {
		t->first_sym = s;
	} else {
		if ((s->next = t->last_sym->next) != NULL)
			s->next->prev = s;
		t->last_sym->next = s;
		s->prev = t->last_sym;
	}
	last_sym = t->last_sym = s;
	s->state = abc_state;
	s->linenum = linenum;
	s->colnum = colnum;
	return s;
}

/* get the ABC version */
static void get_vers(char *p)
{
	int i, j,k;

	i = j = k = 0;
	if (sscanf(p, "%d.%d.%d", &i, &j, &k) != 3)
		if (sscanf(p, "%d.%d", &i, &j) != 2)
			sscanf(p, "%d", &i);
	abc_vers = (i << 16) + (j << 8) + k;
}

/* -- parse an ABC file -- */
struct abctune *abc_parse(char *file_api)
{
	struct abctune *first_tune = NULL;
	struct abctune *t, *last_tune;
	/* saved global variables */
	int g_abc_vers, g_ulen, g_microscale;
	char *p;
	char g_char_tb[128];

	/* initialize */
	file = file_api;
	t = NULL;
	abc_state = ABC_S_GLOBAL;
	if (level_f)
		level_f(0);
	linenum = 0;
	last_tune = NULL;
	g_abc_vers = g_ulen = g_microscale = 0;	/* (have gcc happy) */

	/* scan till end of file */
	for (;;) {
		if ((p = get_line()) == NULL) {
			if (abc_state == ABC_S_HEAD) {
				syntax("Unexpected EOF in header definition",
					p);
				severity = 1;
			}
			if (t)
				t->abc_vers = abc_vers;
			if (abc_state != ABC_S_GLOBAL) {
				abc_vers = g_abc_vers;
				ulen = g_ulen;
				microscale = g_microscale;
				memcpy(char_tb, g_char_tb, sizeof g_char_tb);
			}
			break;			/* done */
		}

		/* start a new tune if not done */
		if (!t) {
			if (*p == '\0')
				continue;
			t = alloc_f(sizeof *t);
			memset(t, 0 , sizeof *t);
			if (!last_tune)
				first_tune = t;
			else
				last_tune->next = t;
			last_tune = t;
			p_micro = t->micro_tb;
			meter = 0;
		}

		/* parse the music line */
		switch (parse_line(t, p)) {
		case 2:				/* start of tune */
			g_abc_vers = abc_vers;
			g_ulen = ulen;
			g_microscale = microscale;
			memcpy(g_char_tb, char_tb, sizeof g_char_tb);
			break;
		case 1:				/* end of tune */
			t->abc_vers = abc_vers;
			abc_state = ABC_S_GLOBAL;
			t = NULL;
			abc_vers = g_abc_vers;
			ulen = g_ulen;
			microscale = g_microscale;
			memcpy(char_tb, g_char_tb, sizeof g_char_tb);
			if (level_f)
				level_f(0);
			if (dc.n > 0)
				syntax("Decoration without symbol", 0);
			dc.n = dc.h = dc.s = 0;
			break;
		}
	}
	return first_tune;
}

/* -- cut off after % and remove trailing blanks -- */
static char *decomment_line(char *p)
{
	char *q, c, *comment = NULL;

	q = p;
	for (;;) {
		c = *p;
		if (c == '\0')
			break;
		if (c == '\\') {
			p++;
			if (*p == '\0')
				return 0;
			p++;
			continue;
		}
		if (c == '%') {
			if (keep_comment) {
				comment = p + 1;
				break;
			}
			break;
		}
		if (c == '"') {
			for (;;) {
				p++;
				if (*p == '\0')
					break;
				if (*p == '"' && p[-1] != '\\') {
					p++;
					break;
				}
			}
		} else {
			p++;
		}
	}

	/* remove the trailing blanks */
	while (p > q) {
		c = *--p;
		if (!isspace((unsigned char) c)) {
			p[1] = '\0';
			break;
		}
	}
	return comment;
}

/* -- treat the broken rhythm '>' and '<' -- */
static void broken_rhythm(struct note *note,
			  int num)	/* >0: do dot, <0: do half */
{
	int l, m, n;

	num *= 2;
	if (num > 0) {
		if (num == 6)
			num = 8;
		n = num * 2 - 1;
		for (m = 0; m <= note->nhd; m++)
			note->lens[m] = (note->lens[m] * n) / num;
	} else {
		n = -num;
		if (n == 6)
			n = 8;
		for (m = 0; m <= note->nhd; m++)
			note->lens[m] /= n;
	}
	l = note->lens[0];
	for (m = 1; m <= note->nhd; m++)
		if (note->lens[m] < l)
			l = note->lens[m];
}

/* -- check for the '!' as end of line (ABC2Win) -- */
static int check_nl(char *p)
{
	while (*p != '\0') {
		switch (*p++) {
		case '!':
			return 0;
		case '|':
		case '[':
		case ':':
		case ']':
		case ' ':
		case '\t':
			return 1;
		}
	}
	return 1;
}

/* -- parse extra K: or V: definitions (clef, octave and microscale  -- */
static char *parse_extra(char *p,
			char **p_name,
			char **p_middle,
			char **p_lines,
			char **p_scale,
			char **p_octave)
{
	for (;;) {
		if (strncmp(p, "clef=", 5) == 0
		 || strncmp(p, "bass", 4) == 0
		 || strncmp(p, "treble", 6) == 0
		 || strncmp(p, "alto", 4) == 0
		 || strncmp(p, "tenor", 5) == 0
		 || strncmp(p, "perc", 4) == 0) {
			if (*p_name)
				syntax("Double clef name", p);
			*p_name = p;
		} else if (strncmp(p, "microscale=", 11) == 0) {
			int i;

			i = atoi(p + 11);
			if (i < 4 || i > 256)
				syntax("Invalid value in microscale=", p);
			else
				microscale = i;
		} else if (strncmp(p, "middle=", 7) == 0
			|| strncmp(p, "m=", 2) == 0) {
			if (*p_middle)
				syntax("Double clef middle", p);
			*p_middle = p + (p[1] == '=' ? 2 : 7);
		} else if (strncmp(p, "octave=", 7) == 0) {
			if (*p_octave)
				syntax("Double octave=", p);
			*p_octave = p + 7;
		} else if (strncmp(p, "stafflines=", 11) == 0) {
			if (*p_lines)
				syntax("Double stafflines", p);
			*p_lines = p + 11;
		} else if (strncmp(p, "staffscale=", 11) == 0) {
			if (*p_scale)
				syntax("Double staffscale", p);
			*p_scale = p + 11;
		} else if (strncmp(p, "transpose=", 10) == 0
			|| strncmp(p, "t=", 2) == 0) {
			;		/* ignored */
		} else {
			break;
		}
		while (!isspace((unsigned char) *p) && *p != '\0')
			p++;
		while (isspace((unsigned char) *p))
			p++;
		if (*p == '\0')
			break;
	}
	return p;
}

/* -- parse a decoration 'xxx<decosep>' -- */
static char *get_deco(char *p,
		      unsigned char *p_deco)
{
	char *q, sep, **t;
	unsigned i, l;

	*p_deco = 0;
	q = p;
	sep = q[-1];
	if (char_tb[(unsigned char) sep] == CHAR_DECOS) {
		if (sep == '+') {
			if (*p == '+' && p[1] == '+')
				p++;		/* special case "+++" */
		}
	} else {
		sep = '\0';			/* Barfly U: */
	}
	while (*p != sep) {
		if (*p == '\0') {
			syntax("Decoration not terminated", q);
			return p;
		}
		p++;
	}
	l = p - q;
	if (*p == sep)
		p++;
	for (i = 1, t = &deco_tb[1];
	     *t && i < 128;
	     i++, t++) {
		if (strlen(*t) == l
		 && strncmp(*t, q, l) == 0) {
			*p_deco = i + 128;
			return p;
		}
	}

	/* new decoration */
	if (i < 128) {
		if (level_f && abc_state != ABC_S_GLOBAL)
			level_f(0);
		*t = alloc_f(l + 1);
		if (level_f && abc_state != ABC_S_GLOBAL)
			level_f(1);
		memcpy(*t, q, l);
		(*t)[l] = '\0';
		*p_deco = i + 128;
	} else {
		syntax("Too many decoration types", q);
	}
	return p;
}

/* -- parse a list of accidentals (K:) -- */
static char *parse_acc(char *p,
			struct abcsym *s)
{
	int pit, len, acc, nostem;
	unsigned nacc;

	if (s->u.key.empty == 2)
		syntax("cannot have 'none' and a list of accidentals", p);
	nacc = 0;
	for (;;) {
		if (nacc >= sizeof s->u.key.pits) {
			syntax("Too many accidentals", p);
			break;
		}
		p = parse_basic_note(p, &pit, &len, &acc, &nostem);
		s->u.key.pits[nacc] = pit;
		s->u.key.accs[nacc++] = acc;
		while (isspace((unsigned char) *p))
			p++;
		if (*p == '\0')
			break;
		if (*p != '^' && *p != '_' && *p != '=')
			break;
	}
	s->u.key.microscale = microscale;
	if (s->u.key.empty != 2)
		s->u.key.nacc = nacc;
	return p;
}

/* -- parse a clef (K: or V:) -- */
static void parse_clef(struct abcsym *s,
			char *name,
			char *middle,
			char *lines,
			char *scale)
{
	int clef = -1;
	int transpose = 0;
	int clef_line = 2;
	char *warn = NULL;
	char str[80];

	str[0] = '\0';
	if (name && strncmp(name, "clef=", 5) == 0) {
		name += 5;
		switch (*name) {
		case '\"':
			name = get_str(str, name, sizeof str);
			s->u.clef.name = alloc_f(strlen(str) + 1);
			strcpy(s->u.clef.name, str);
			clef = TREBLE;
			break;
		case 'g':
			warn = name;
			transpose = -7;
		case 'G':
			clef = TREBLE;
			break;
		case 'f':
			warn = name;
			transpose = -14;
			clef = BASS;
			clef_line = 4;
			break;
		case 'F':
			if (name[1] == ',')	/* abc2.1.1 clef=F == clef=F, */
				transpose = -7;
			clef = BASS;
			clef_line = 4;
			break;
		case 'c':
			warn = name;
			transpose = -7;
		case 'C':
			clef = ALTO;
			clef_line = 3;
			break;
		case 'P':
			clef = PERC;
			break;
		}
		if (clef >= 0) {
			name++;
			if (*name == ',' || *name== '\'')
				warn = name;
			while (*name == ',') {
				transpose += 7;
				name++;
			}
			while (*name == '\'') {
				transpose -= 7;
				name++;
			}
		}
	}
	if (name && clef < 0) {
		if (!strncmp(name, "bass", 4)) {
			clef = BASS;
			clef_line = 4;
			s->u.clef.check_pitch = 1;
			name += 4;
		} else if (!strncmp(name, "treble", 6)) {
			clef = TREBLE;
			name += 6;
		} else if (!strncmp(name, "alto", 4)
			|| !strncmp(name, "tenor", 5)) {
			clef = ALTO;
			clef_line = *name == 'a' ? 3 : 4;
			s->u.clef.check_pitch = 1;
			if (*name == 'a')
				name += 4;
			else
				name += 5;
		} else if (!strncmp(name, "perc", 4)) {
			clef = PERC;
			name += 4;
		} else if (strncmp(name, "none", 4) == 0) {
			clef = TREBLE;
			s->u.clef.invis = 1;
			s->flags |= ABC_F_INVIS;
			name += 4;
		} else {
			syntax("Unknown clef", name);
		}
	}

	if (clef >= 0) {
		switch (*name) {
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
			clef_line = *name++ - '0';
			break;
		}
		if (name[1] == '8') {
			switch (*name) {
			case '^':
				transpose -= 7;
			case '+':
				s->u.clef.octave = 1;
				break;
			case '_':
				transpose += 7;
			case '-':
				s->u.clef.octave = -1;
				break;
			}
		}
	}

	if (middle) {
		int pit, len, acc, nostem, l;
		static const char line_tb[7] =
			{ALTO, TREBLE, ALTO, BASS, ALTO, BASS, ALTO};

		warn = middle;
		/* 'middle=<note pitch>' */
		parse_basic_note(middle, &pit, &len, &acc, &nostem);

		if (clef < 0)
			clef = line_tb[(pit + 7) % 7];
	
		switch (clef) {
		default:
			l = 20 + 4;
			break;
		case ALTO:
			l = 16 + 4;
			break;
		case BASS:
			l = 12 + 4;
			break;
		}
		clef_line = (l - pit + 28) % 7;
		if (clef_line & 1) {
			syntax("Bad 'middle' value for the clef", middle);
			pit++;
		}
		clef_line = clef_line / 2 + 1;

		transpose = l - (clef_line - 1) * 2 - pit;
		s->u.clef.check_pitch = 0;
	}

	s->u.clef.type = clef;
	s->u.clef.line = clef_line;
	s->u.clef.transpose = transpose;
	s->u.clef.stafflines = -1;
	s->u.clef.staffscale = 0;
	if (lines) {
		int l;

		l = atoi(lines);
		if ((unsigned) l < 10)
			s->u.clef.stafflines = l;
		else
			syntax("Bad value of stafflines", lines);
	}
	if (scale) {
		float sc;

		sc = atof(scale);
		if (sc >= 0.5 && sc <= 3)
			s->u.clef.staffscale = sc;
		else
			syntax("Bad value of staffscale", scale);
	}
	if (warn) {
		int sev_sav;

		sev_sav = severity;
		syntax("Warning: Deprecated or non-standard item", warn);
		severity = sev_sav;
	}
}

/* get the octave= value */
static int parse_octave(char *p)
{
	int oct;

	if (p) {
		oct = 1;
		if (*p == '-') {
			oct = -1;
			p++;
		}
		if (*p >= '0' && *p <= '4')
			return oct * (*p - '0');
		syntax("Bad octave value", p);
	}
	return NO_OCTAVE;
}

/* -- parse a 'K:' -- */
static void parse_key(char *p,
		      struct abcsym *s)
{
	int sf, mode, key_end;
	char *clef_name, *clef_middle, *clef_lines, *clef_scale;
	char *p_octave;

	if (*p == '\0') {
		s->u.key.empty = 2;
		return;
	}
	sf = 0;
	mode = MAJOR;
	key_end = 0;
	switch (*p++) {
	case 'F': sf = -1; break;
	case 'B': sf++;
	case 'E': sf++;
	case 'A': sf++;
	case 'D': sf++;
	case 'G': sf++;
	case 'C': break;
	case 'H':
		if (*p == 'P') {
			mode = BAGPIPE;
			p++;
		} else if (*p == 'p') {
			mode = BAGPIPE + 1;
			sf = 2;
			p++;
		} else {
			syntax("Unknown bagpipe-like key", p);
		}
		break;
	case 'n':
		if (strncmp(p, "one", 3) == 0) {
			s->u.key.empty = 2;
			p += 3;
			while (isspace((unsigned char) *p))
				p++;
			if (*p == '\0')
				return;
			key_end = 1;
			break;
		}
		// fall thru
	default:
		p--;
		key_end = 1;
		break;
	}
	if (!key_end) {
		if (*p == '#') {
			sf += 7;
			p++;
		} else if (*p == 'b') {
			sf -= 7;
			p++;
		}
		while (isspace((unsigned char) *p))
			p++;
		switch (*p) {
		case 'a':
		case 'A':
			if (strncasecmp(p, "aeo", 3) == 0) {
				sf -= 3;
				mode = 5;
				break;
			}
			goto unk;
		case 'd':
		case 'D':
			if (strncasecmp(p, "dor", 3) == 0) {
				sf -= 2;
				mode = 1;
				break;
			}
			goto unk;
		case 'i':
		case 'I':
			if (strncasecmp(p, "ion", 3) == 0) {
				mode = 0;
				break;
			}
			goto unk;
		case 'l':
		case 'L':
			if (strncasecmp(p, "loc", 3) == 0) {
				sf -= 5;
				mode = 6;
				break;
			}
			if (strncasecmp(p, "lyd", 3) == 0) {
				sf += 1;
				mode = 3;
				break;
			}
			goto unk;
		case 'm':
		case 'M':
			if (strncasecmp(p, "maj", 3) == 0)
				break;
			if (strncasecmp(p, "mix", 3) == 0) {
				sf -= 1;
				mode = 4;
				break;
			}
			if (strncasecmp(p, "min", 3) == 0
			 || !isalpha((unsigned char) p[1])) { /* 'm' alone */
				sf -= 3;
				mode = MINOR;
				break;
			}
			goto unk;
		case 'p':
		case 'P':
			if (strncasecmp(p, "phr", 3) == 0) {
				sf -= 4;
				mode = 2;
				break;
			}
			goto unk;
		default:
unk:
			key_end = 1;
			break;
		}
		if (!key_end) {
			while (isalpha((unsigned char) *p))
				p++;
			while (isspace((unsigned char) *p))
				p++;
		}

		// [exp] accidentals
		if (strncmp(p, "exp ", 4) == 0) {
			p += 4;
			while (isspace((unsigned char) *p))
				p++;
			if (*p == '\0')
				syntax("no accidental after 'exp'", p);
			s->u.key.exp = 1;
		}
		if (s->u.key.exp && strncmp(p, "none", 4) == 0) {
			sf = 0;
			p += 4;
			while (isspace((unsigned char) *p))
				p++;
		} else switch (*p) {
			case '^':
			case '_':
			case '=':
				p = parse_acc(p, s);		/* accidentals */
				break;
		}
	}

	if (sf > 7 || sf < -7) {
		syntax("Too many sharps/flats", p);
		if (sf > 0)
			sf -= 12;
		else
			sf += 12;
	}

	// extra parameters
	clef_name = clef_middle = clef_lines = clef_scale = NULL;
	p_octave = NULL;
	parse_extra(p, &clef_name, &clef_middle, &clef_lines,
			&clef_scale, &p_octave);
	s->u.key.sf = sf;
	s->u.key.mode = mode;
	s->u.key.octave = parse_octave(p_octave);

	if (clef_name || clef_middle || clef_lines || clef_scale) {
		s = abc_new(s->tune, NULL, NULL);
		s->type = ABC_T_CLEF;
		parse_clef(s, clef_name, clef_middle, clef_lines,
				clef_scale);
	}
}

/* -- set default length from 'L:' -- */
static char *get_len(char *p,
		     struct abcsym *s)
{
	int l1, l2, d;
	char *error_txt = NULL;

	if (strcmp(p, "auto") == 0) {		/* L:auto */
		s->u.length.base_length = -1;
		return error_txt;
	}
	l1 = 0;
	l2 = 1;
	if (sscanf(p, "%d /%d ", &l1, &l2) != 2
	 || l1 == 0) {
		s->u.length.base_length = ulen ? ulen : BASE_LEN / 8;
		return "Bad unit note length: unchanged";
	}

	if (l2 == 0) {
		error_txt = "Bad length divisor, set to 4";
		l2 = 4;
	}
	d = BASE_LEN / l2;
	if (d * l2 != BASE_LEN) {
		error_txt = "Length incompatible with BASE, using 1/8";
		d = BASE_LEN / 8;
	} else 	{
		d *= l1;
		if (l1 != 1
		 || (l2 & (l2 - 1))) {
			error_txt = "Incorrect unit note length, using 1/8";
			d = BASE_LEN / 8;
		}
	}
	s->u.length.base_length = d;
	return error_txt;
}

/* -- get a new line from the current file in memory -- */
static char *get_line(void)
{
	int l;
	char *p, *q;

	p = file;
	if (*p == '\0')
		return 0;
	abc_line = p;
	linenum++;

	/* handle %%begin .. %%end */
	if (strncmp(p, "%%begin", 7) == 0) {
		for (;;) {
			while (*p != '\0'
			    && *p != '\n')
				p++;
			if (*p == '\0') {
				syntax("No %%end after %%begin", 0);
				break;
			}
			linenum++;
			p++;
			if (strncmp(p, "%%end", 5) == 0) {
				p[-1] = '\0';
				while (*p != '\0'
				    && *p != '\n')
					p++;
				if (*p != '\0')
					*p++ = '\0';
				break;
			}
		}
		file = p;
		return abc_line;
	}

	/* set the end of line and
	 * memorize the beginning of the next line */
	while (*p != '\0'
	    && *p != '\n')
		p++;
	if (*p != '\0')
		*p++ = '\0';
	file = p;

	/* special case for continuation lines in ABC version 2.0 */
	if (abc_vers == (2 << 16)) {
		p = abc_line;
		for (;;) {
			while (*p != '\0') {
				if (*p == '"') {
					for (;;) {
						p++;
						if (*p == '\0')
							break;
						if (*p == '"' && p[-1] != '\\') {
							p++;
							break;
						}
					}
					continue;
				}
				if (*p == '\\'
				 && p[1] != '\\'
				 && p[1] != '%') {
					q = p + 1;
					while (isspace((unsigned char) *q))
						q++;
					if (*q == '\0' || *q == '%')
						break;
					p = q;
					continue;
				}
				p++;
			}
			if (*p == '\0')
				break;

			/* continuation found */
			q = file;
			if (*q == '\0')
				break;
			linenum++;
			while (*q != '\0'
			    && *q != '\n')
				q++;
			l = q - file;
			memmove(p, file, l);	/* concatenate */
			p[l] = '\0';
			if (*q == '\0')
				break;
			file = q + 1;
		}
	}
	return abc_line;
}

/* -- parse a 'M:' -- */
static char *parse_meter(char *p,
			 struct abcsym *s)
{
	int m1, m2, d, wmeasure, nm, in_parenth;
	unsigned i;
	char *q;
static char *top_err = "Cannot identify meter top";

	if (*p == '\0')
		return "Empty meter string";
	nm = 0;
	in_parenth = 0;
	wmeasure = 0;
	m1 = 0;
	if (strncmp(p, "none", 4) == 0) {
		p += 4;				/* no meter */
	} else while (*p != '\0') {
		if (*p == '=')
			break;
		if (nm >= MAX_MEASURE)
			return "Too many values in M:";
		switch (*p) {
		case 'C':
			s->u.meter.meter[nm].top[0] = *p++;
			if (*p == '|')
				s->u.meter.meter[nm].top[1] = *p++;
			m1 = 4;
			m2 = 4;
			break;
		case 'c':
		case 'o':
			if (*p == 'c')
				m1 = 4;
			else
				m1 = 3;
			m2 = 4;
			s->u.meter.meter[nm].top[0] = *p++;
			if (*p == '.')
				s->u.meter.meter[nm].top[1] = *p++;
			break;
		case '(':
			if (p[1] == '(') {	/* "M:5/4 ((2+3)/4)" */
				in_parenth = 1;
				s->u.meter.meter[nm++].top[0] = *p++;
			}
			q = p + 1;
			while (*q != '\0') {
				if (*q == ')' || *q == '/')
					break;
				q++;
			}
			if (*q == ')' && q[1] == '/') {	/* "M:5/4 (2+3)/4" */
				p++;		/* remove the parenthesis */
				continue;
			}			/* "M:5 (2+3)" */
			/* fall thru */
		case ')':
			in_parenth = *p == '(';
			s->u.meter.meter[nm++].top[0] = *p++;
			continue;
		default:
			if (sscanf(p, "%d", &m1) != 1
			 || m1 <= 0)
				return top_err;
			i = 0;
			m2 = 2;			/* default when no bottom value */
			for (;;) {
				while (isdigit((unsigned char) *p)
				    && i < sizeof s->u.meter.meter[0].top)
					s->u.meter.meter[nm].top[i++] = *p++;
				if (*p == ')') {
					if (p[1] != '/')
						break;
					p++;
				}
				if (*p == '/') {
					p++;
					if (sscanf(p, "%d", &m2) != 1
					 || m2 <= 0)
						return "Cannot identify meter bottom";
					i = 0;
					while (isdigit((unsigned char) *p)
					    && i < sizeof s->u.meter.meter[0].bot)
						s->u.meter.meter[nm].bot[i++] = *p++;
					break;
				}
				if (*p != ' ' && *p != '+')
					break;
				if (*p == '\0' || p[1] == '(')	/* "M:5 (2/4+3/4)" */
					break;
				if (i < sizeof s->u.meter.meter[0].top)
					s->u.meter.meter[nm].top[i++] = *p++;
				if (sscanf(p, "%d", &d) != 1
				 || d <= 0)
					return top_err;
				if (p[-1] == ' ') {
					if (d > m1)
						m1 = d;
				} else {
					m1 += d;
				}
			}
			break;
		}
		if (!in_parenth)
			wmeasure += m1 * BASE_LEN / m2;
		nm++;
		if (*p == ' ')
			p++;
		else if (*p == '+')
			s->u.meter.meter[nm++].top[0] = *p++;
	}
	meter = m1;
	if (*p == '=') {
		if (sscanf(++p, "%d/%d", &m1, &m2) != 2
		 || m1 <= 0
		 || m2 <= 0)
			return "Cannot identify meter explicit duration";
		wmeasure = m1 * BASE_LEN / m2;
		s->u.meter.expdur = 1;
	}
	s->u.meter.wmeasure = wmeasure;
	s->u.meter.nmeter = nm;

	/* if in the header, change the unit note length */
	if (abc_state == ABC_S_HEAD && ulen == 0) {
		if (wmeasure >= BASE_LEN * 3 / 4
		 || wmeasure == 0)
			ulen = BASE_LEN / 8;
		else
			ulen = BASE_LEN / 16;
	}
	return 0;
}

/* -- get a possibly quoted string -- */
char *get_str(char *d,		/* destination */
	      char *s,		/* source */
	      int maxlen)	/* max length */
{
	char c;

	maxlen--;		/* have place for the EOS */
	while (isspace((unsigned char) *s))
		s++;
	if (*s == '"') {
		s++;
		while ((c = *s) != '\0') {
			if (c == '"') {
				s++;
				break;
			}
			if (c == '\\') {
				if (--maxlen > 0)
					*d++ = c;
				c = *++s;
			}
			if (--maxlen > 0)
				*d++ = c;
			s++;
		}
	} else {
		while ((c = *s) != '\0') {
			if (isspace((unsigned char) c))
				break;
			if (--maxlen > 0)
				*d++ = c;
			s++;
		}
	}
	*d = '\0';
	while (isspace((unsigned char) *s))
		s++;
	return s;
}

/* -- parse a tempo (Q:) -- */
static char *parse_tempo(char *p,
			 struct abcsym *s)
{
	int l;
	char *q, str[80];

	/* string before */
	if (*p == '"') {
		p = get_str(str, p, sizeof str);
		s->u.tempo.str1 = alloc_f(strlen(str) + 1);
		strcpy(s->u.tempo.str1, str);
	}

	/* beat */
	if (*p == 'C' || *p == 'c'
	 || *p == 'L' || *p == 'l') {
		int len;

		p++;
		if (*p != '=')
			goto inval;
		p = parse_len(p + 1, &len);
		if (len <= 0)
			goto inval;
		s->u.tempo.length[0] = len * ulen / BASE_LEN;
		while (isspace((unsigned char) *p))
			p++;
		if (abc_vers >= (2 << 16))
			syntax("Deprecated Q: value", p);
	} else if (isdigit((unsigned char) *p) && strchr(p, '/') != 0) {
		unsigned i;

		i = 0;
		while (isdigit((unsigned char) *p)) {
			int top, bot, n;

			if (sscanf(p, "%d /%d%n", &top, &bot, &n) != 2
			 || bot <= 0)
				goto inval;
			l = (BASE_LEN * top) / bot;
			if (l <= 0
			 || i >= sizeof s->u.tempo.length
					/ sizeof s->u.tempo.length[0])
				goto inval;
			s->u.tempo.length[i++] = l;
			p += n;
			while (isspace((unsigned char) *p))
				p++;
		}
	}

	/* tempo value ('Q:beat=value' or 'Q:value') */
	if (*p == '=') {
		p++;
		while (isspace((unsigned char) *p))
			p++;
	}
	if (*p != '\0' && *p != '"') {
		q = p;
		while (*p != '"' && *p != '\0')
			p++;
		while (isspace((unsigned char) p[-1]))
			p--;
		l = p - q;
		s->u.tempo.value = alloc_f(l + 1);
		strncpy(s->u.tempo.value, q, l);
		s->u.tempo.value[l] = '\0';
		while (isspace((unsigned char) *p))
			p++;
	}

	/* string after */
	if (*p == '"') {
		p = get_str(str, p, sizeof str);
		s->u.tempo.str2 = alloc_f(strlen(str) + 1);
		strcpy(s->u.tempo.str2, str);
	}

	if (!s->u.tempo.str1 && !s->u.tempo.str2
	 && s->u.tempo.length[0] == 0) {
		if (s->u.tempo.value == 0)
			return "Empty tempo";
		if (abc_vers >= (2 << 16))
			syntax("Deprecated Q: value", p);
	}
	return 0;
inval:
	return "Invalid tempo";
}

/* -- get a user defined symbol (U:) -- */
static char *get_user(char *p,
		      struct abcsym *s)
{
	unsigned char c;
	char *value;

	c = (unsigned char) *p++;
	if (c == '\\') {
		c = (unsigned char) *p++;
		switch (c) {
		case 'n':
			c = '\n';
			break;
		case 't':
			c = '\t';
			break;
		}
	}
	switch (char_tb[c]) {
	default:
		return "Bad decoration character";
	case CHAR_DECO:
		break;
	case CHAR_BAD:
	case CHAR_IGN:
	case CHAR_SPAC:
	case CHAR_DECOS:
	case CHAR_LINEBREAK:
		char_tb[c] = CHAR_DECO;
		break;
	}
	s->u.user.symbol = c;

	/* skip '=' */
	while (isspace((unsigned char) *p) || *p == '=')
		p++;
	if (char_tb[(unsigned char) *p] == CHAR_DECOS)
		p++;
/*fixme: 'U: <char> = "text"' is not treated */
	get_deco(p, &s->u.user.value);

	/* treat special pseudo decorations */
	value = deco_tb[s->u.user.value - 128];
	if (strcmp(value, "beambreak") == 0)
		char_tb[c] = CHAR_SPAC;
	else if (strcmp(value, "ignore") == 0)
		char_tb[c] = CHAR_IGN;
	else if (strcmp(value, "nil") == 0
	      || strcmp(value, "none") == 0)
		char_tb[c] = CHAR_BAD;
	else
		return 0;
	s->u.user.value	= 0;		/* not a decoration */
	return 0;
}

/* -- parse the voice parameters (V:) -- */
static char *parse_voice(char *p,
			 struct abcsym *s)
{
	int voice;
	char *error_txt = NULL;
	char name[VOICE_NAME_SZ];
	char *clef_name, *clef_middle, *clef_lines, *clef_scale;
	char *p_octave;
	signed char *p_stem;
static struct kw_s {
	char *name;
	short len;
	short index;
} kw_tb[] = {
	{"name=", 5, 0},
	{"nm=", 3, 0},
	{"subname=", 8, 1},
	{"sname=", 6, 1},
	{"snm=", 4, 1},
	{"merge", 5, 2},
	{"up", 2, 3},
	{"down", 4, 4},
	{"stem=", 5, 5},
	{"gstem=", 6, 6},
	{"auto", 4, 7},
	{"dyn=", 4, 8},
	{"lyrics=", 7, 9},
	{"scale=", 6, 10},
	{"gchord=", 7, 11},
	{0}
};
	struct kw_s *kw;

	/* save the parameters of the previous voice */
	curvoice->ulen = ulen;
	curvoice->microscale = microscale;

	if (voice_tb[0].id[0] == '\0') {
		switch (s->prev->type) {
		case ABC_T_EOLN:
		case ABC_T_NOTE:
		case ABC_T_REST:
		case ABC_T_BAR:
			/* the previous voice was implicit (after K:) */
			voice_tb[0].id[0] = '1';
			break;
		}
	}
	{
		char *id, sep;

		id = p;
		while (isalnum((unsigned char) *p) || *p == '_')
			p++;
		sep = *p;
		*p = '\0';
		if (voice_tb[0].id[0] == '\0') {
			voice = 0;			/* first voice */
		} else {
			for (voice = 0; voice <= nvoice; voice++) {
				if (strcmp(id, voice_tb[voice].id) == 0)
					goto found;
			}
			if (voice >= MAXVOICE) {
				syntax("Too many voices", id);
				voice--;
			}
		}
		nvoice = voice;
		strncpy(voice_tb[voice].id, id, sizeof voice_tb[voice].id - 1);
		voice_tb[voice].mvoice = voice;
	found:
		strcpy(s->u.voice.id, voice_tb[voice].id);
		*p = sep;
	}
	curvoice = &voice_tb[voice];
	s->u.voice.voice = voice;

	/* if in tune, set the voice parameters */
	if (abc_state == ABC_S_TUNE) {
		ulen = curvoice->ulen;
		microscale = curvoice->microscale;
	}

	/* parse the other parameters */
	clef_name = clef_middle = clef_lines = clef_scale = NULL;
	p_octave = NULL;
	p_stem = &s->u.voice.stem;
	for (;;) {
		while (isspace((unsigned char) *p))
			p++;
		if (*p == '\0')
			break;
		p = parse_extra(p, &clef_name, &clef_middle, &clef_lines,
				&clef_scale, &p_octave);
		if (*p == '\0')
			break;
		for (kw = kw_tb; kw->name; kw++) {
			if (strncmp(p, kw->name, kw->len) == 0)
				break;
		}
		if (!kw->name) {
			while (!isspace((unsigned char) *p) && *p != '\0')
				p++;	/* ignore unknown keywords */
			continue;
		}
		p += kw->len;
		switch (kw->index) {
		case 0:			/* name */
			p = get_str(name, p, VOICE_NAME_SZ);
			s->u.voice.fname = alloc_f(strlen(name) + 1);
			strcpy(s->u.voice.fname, name);
			break;
		case 1:			/* subname */
			p = get_str(name, p, VOICE_NAME_SZ);
			s->u.voice.nname = alloc_f(strlen(name) + 1);
			strcpy(s->u.voice.nname, name);
			break;
		case 2:			/* merge */
			s->u.voice.merge = 1;
			break;
		case 3:			/* up */
			*p_stem = 1;
			break;
		case 4:			/* down */
			*p_stem = -1;
			break;
		case 5:			/* stem= */
			p_stem = &s->u.voice.stem;
			break;
		case 6:			/* gstem= */
			p_stem = &s->u.voice.gstem;
			break;
		case 7:			/* auto */
			*p_stem = 2;
			break;
		case 8:			/* dyn= */
			p_stem = &s->u.voice.dyn;
			break;
		case 9:			/* lyrics= */
			p_stem = &s->u.voice.lyrics;
			break;
		case 10: {		/* scale= */
			float sc;

			sc = atof(p);
			if (sc >= 0.5 && sc <= 2)
				s->u.voice.scale = sc;
			else
				error_txt = "Bad value for voice scale";
			while (!isspace((unsigned char) *p) && *p != '\0')
				p++;
			break;
		    }
		case 11:		/* gchord= */
			p_stem = &s->u.voice.gchord;
			break;
		}
	}

	s->u.voice.octave = parse_octave(p_octave);

	if (clef_name || clef_middle || clef_lines || clef_scale) {
		s = abc_new(s->tune, NULL, NULL);
		s->type = ABC_T_CLEF;
		parse_clef(s, clef_name, clef_middle, clef_lines,
				clef_scale);
	}
	return error_txt;
}

/* -- parse a bar -- */
static char *parse_bar(struct abctune *t,
		       char *p)
{
	struct abcsym *s;
	int bar_type;
	char repeat_value[32];

	p--;
	bar_type = 0;
	for (;;) {
		switch (*p++) {
		case '|':
			bar_type <<= 4;
			bar_type |= B_BAR;
			continue;
		case '[':
			bar_type <<= 4;
			bar_type |= B_OBRA;
			continue;
		case ']':
			bar_type <<= 4;
			bar_type |= B_CBRA;
			continue;
		case ':':
			bar_type <<= 4;
			bar_type |= B_COL;
			continue;
		default:
			break;
		}
		break;
	}
	p--;

	/* if the last element is '[', it may start
	 * a chord, an embedded header or an other bar */
	if ((bar_type & 0x0f) == B_OBRA && bar_type != B_OBRA
	 && *p != ' ') {
		bar_type >>= 4;
		p--;
	}

	if (bar_type == (B_OBRA << 8) + (B_BAR << 4) + B_CBRA)	/* [|] */
		bar_type = (B_OBRA << 4) + B_CBRA;		/* [] */

/*	curvoice->last_note = NULL; */
	if (vover > 0) {
		curvoice = &voice_tb[curvoice->mvoice];
		vover = 0;
	}
	s = abc_new(t, gchord, NULL);
	if (gchord) {
		if (free_f)
			free_f(gchord);
		gchord = NULL;
	}
	s->type = ABC_T_BAR;
	s->u.bar.type = bar_type;

	if (dc.n > 0) {
		memcpy(&s->u.bar.dc, &dc, sizeof s->u.bar.dc);
		dc.n = dc.h = dc.s = 0;
	}
	if (!lyric_started) {
		lyric_started = 1;
		s->flags |= ABC_F_LYRIC_START;
	}

	if (!isdigit((unsigned char) *p)	/* if not a repeat bar */
	 && (*p != '"' || p[-1] != '['))	/* ('["' only) */
		return p;

	if (*p == '"') {
		p = get_str(repeat_value, p, sizeof repeat_value);
	} else {
		char *q;

		q = repeat_value;
		while (isdigit((unsigned char) *p)
		    || *p == ','
		    || *p == '-'
		    || (*p == '.' && isdigit((unsigned char) p[1]))) {
			if (q < &repeat_value[sizeof repeat_value - 1])
				*q++ = *p++;
			else
				p++;
		}
		*q = '\0';
	}
	if (bar_type != B_OBRA
	 || s->text) {
		s = abc_new(t, repeat_value, NULL);
		s->type = ABC_T_BAR;
		s->u.bar.type = B_OBRA;
	} else {
		s->text = alloc_f(strlen(repeat_value) + 1);
		strcpy(s->text, repeat_value);
	}
	s->u.bar.repeat_bar = 1;
	return p;
}

/* -- parse note or rest with pitch and length -- */
/* in case of error, 'accidental' is set to -1 */
static char *parse_basic_note(char *p,
			      int *pitch,
			      int *length,
			      int *accidental,
			      int *stemless)
{
	int pit, len, acc, nostem;

	acc = pit = nostem = 0;

	/* look for accidental sign */
	switch (*p) {
	case '^':
		p++;
		if (*p == '^') {
			p++;
			acc = A_DS;
		} else {
			acc = A_SH;
		}
		break;
	case '=':
		p++;
		acc = A_NT;
		break;
	case '_':
		p++;
		if (*p == '_') {
			p++;
			acc = A_DF;
		} else {
			acc = A_FT;
		}
		break;
	}

	/* look for microtone value */
	if (acc != 0
	 && (isdigit((unsigned char) *p)
	  || (*p == '/' && microscale == 0))) {
		int n, d;
		char *q;

		n = d = 1;
		if (*p != '/') {
			n = strtol(p, &q, 10);
			p = q;
		}
		if (*p == '/') {
			p++;
			if (!isdigit((unsigned char) *p)) {
				d = 2;
			} else {
				d = strtol(p, &q, 10);
				p = q;
			}
		}
		if (microscale == 0) {
			d--;
			d += (n - 1) << 8;	/* short [ (n-1) | (d-1) ] */
			for (n = 1; n < MAXMICRO; n++) {
				if (p_micro[n] == d)
					break;
				if (p_micro[n] == 0) {
					p_micro[n] = d;
					break;
				}
			}
			if (n == MAXMICRO) {
				syntax("Too many microtone accidentals", p);
				n = 0;
			}
		}
		acc += (n << 3);
	}

	/* get the pitch */
	{
		char *p_n;

		p_n = strchr(all_notes, *p);
		if (!p_n) {
			syntax(acc ? "Missing note after accidental"
				   : "Not a note", p);
			acc = -1;
			if (*p == '\0')
				p--;
		} else {
			pit = p_n - all_notes + 16;
		}
		p++;
	}
	while (*p == '\'') {		/* eat up following ' chars */
		pit += 7;
		p++;
	}
	while (*p == ',') {		/* eat up following , chars */
		pit -= 7;
		p++;
	}
	if (*p == '0') {
		nostem = 1;
		p++;
	}
	p = parse_len(p, &len);

	*pitch = pit;
	*length = len;
	*accidental = acc;
	*stemless = nostem;
	return p;
}

/* -- parse the decorations of notes and bars -- */
char *parse_deco(char *p,
		 struct deco *deco)
{
	int n;
	unsigned char c, d;

	n = deco->n;
	for (;;) {
		c = (unsigned char) *p++;
		if (char_tb[c] != CHAR_DECO && char_tb[c] != CHAR_DECOS)
			break;
		if (char_tb[c] == CHAR_DECOS) {
			p = get_deco(p, &d);
			c = d;
		}
		if (n >= MAXDC)
			syntax("Too many decorations for the note", p);
		else if (c != 0)
			deco->t[n++] = c;
	}
	deco->n = n;
	return p - 1;
}

/* -- parse a decoration line (d: or s:) -- */
static char *parse_decoline(char *p)
{
	struct abcsym *is;
	unsigned char d;
	int n;

	if ((is = deco_cont) == NULL)
		is = deco_start;
	else
		deco_cont = NULL;

	/* scan the decoration line */
	while (*p != '\0') {
		while (isspace((unsigned char) *p))
			p++;
		if (*p == '\0')
			break;
		switch (*p) {
		case '|':
			while (is && (is->type != ABC_T_BAR
					|| is->u.bar.type == B_OBRA))
				is = is->next;
			if (!is) {
				syntax("Not enough bar lines for deco line", p);
				return NULL;
			}
			is = is->next;
			p++;
			continue;
		case '*':
			while (is && is->type != ABC_T_NOTE)
				is = is->next;
			if (!is) {
				syntax("Not enough notes for deco line", p);
				return NULL;
			}
			is = is->next;
			p++;
			continue;
		case '\\':
			if (p[1] == '\0') {
				if (!is)
					return "Not enough notes for deco line";
				deco_cont = is;
				return NULL;
			}
			syntax("'\\' ignored", p);
			p++;
			continue;
		case '"':
			p = parse_gchord(p + 1);
			break;
		default:
			if (char_tb[(unsigned char) *p] == CHAR_DECOS)
				p = get_deco(p + 1, &d);
			else
				d = (unsigned char) *p++;
			break;
		}

		/* store the decoration / gchord/annotation in the next note */
		while (is && (is->type != ABC_T_NOTE
				|| (is->flags & ABC_F_GRACE)))
			is = is->next;
		if (!is)
			return "Not enough notes for deco line";

		if (gchord) {
			if (is->text) {
				char *gch;

				n = strlen(is->text);
				gch = alloc_f(n + strlen(gchord) + 2);
				strcpy(gch, is->text);
				gch[n] = '\n';
				strcpy(gch + n + 1, gchord);
				if (free_f) {
					free_f(gchord);
					free_f(is->text);
				}
				gchord = gch;
			}
			is->text = gchord;
			gchord = NULL;
		} else {
			n = is->u.note.dc.n;
			if (n >= MAXDC) {
				syntax("Too many decorations for the note", p);
			} else if (d != 0) {
				is->u.note.dc.t[n] = d;
				is->u.note.dc.n = n + 1;
			}
		}
		is = is->next;
	}
	return NULL;
}

/* -- parse a guitar chord / annotation -- */
static char *parse_gchord(char *p)
{
	char *q;
	int l, l2;

	q = p;
	while (*p != '"') {
		if (*p == '\\')
			p++;
		if (*p == '\0') {
			syntax("No end of guitar chord", p);
			break;
		}
		p++;
	}
	l = p - q;
	if (gchord) {
		char *gch;

		/* many guitar chords: concatenate with '\n' */
		l2 = strlen(gchord);
		gch = alloc_f(l2 + 1 + l + 1);
		strcpy(gch, gchord);
		gch[l2++] = '\n';
		strncpy(&gch[l2], q, l);
		gch[l2 + l] = '\0';
		if (free_f)
			free_f(gchord);
		gchord = gch;
	} else {
		gchord = alloc_f(l + 1);
		strncpy(gchord, q, l);
		gchord[l] = '\0';
	}
	if (*p != '\0')
		p++;
	return p;
}

/* -- parse a note length -- */
static char *parse_len(char *p,
			int *p_len)
{
	int len, fac;
	char *q;

	len = BASE_LEN;
	if (isdigit((unsigned char) *p)) {
		len *= strtol(p, &q, 10);
		if (len <= 0) {
			syntax("Bad length", p);
			len = BASE_LEN;
		}
		p = q;
	}
	fac = 1;
	while (*p == '/') {
		p++;
		if (isdigit((unsigned char) *p)) {
			fac *= strtol(p, &q, 10);
			if (fac == 0) {
				syntax("Bad length divisor", p - 1);
				fac = 1;
			}
			p = q;
		} else {
			fac *= 2;
		}
	}
	if (len % fac)
		syntax("Bad length divisor", p - 1);
	len /= fac;
	*p_len = len;
	return p;
}

/* -- parse a ABC line -- */
/* return 1 on end of tune, and 2 on start of new tune */
static int parse_line(struct abctune *t,
		      char *p)
{
	struct abcsym *s;
	char *comment, *q, c;
	struct abcsym *last_note_sav = NULL;
	struct deco dc_sav;
	int i, flags, flags_sav = 0, slur;
	static char qtb[10] = {0, 1, 3, 2, 3, 0, 2, 0, 3, 0};

	colnum = 0;
	switch (*p) {
	case '\0':			/* blank line */
		switch (abc_state) {
		case ABC_S_GLOBAL:
		case ABC_S_HEAD:	/*fixme: may have blank lines in headers?*/
			if (keep_comment || abc_state == ABC_S_GLOBAL) {
				if (t->last_sym
				 && t->last_sym->type != ABC_T_NULL) {
					s = abc_new(t, NULL, NULL);
					s->type = ABC_T_NULL;
				}
			}
			return 0;
		}
		return 1;
	case '%':
		if (p[1] == '@') {		/* line number - see front.c */
			linenum = atol(p + 2);
			if (linenum == 0 && strncmp(file, "%abc-", 5) == 0)
				get_vers(file + 5);
			return 0;
		}
		if (p[1] == '%') {
			if (strncmp(p + 2, "begin", 5) != 0)
				comment = decomment_line(p + 2);
			else
				comment = NULL;
			s = abc_new(t, p, comment);
			s->type = ABC_T_PSCOM;
			p += 2;				/* skip '%%' */
			if (strncasecmp(p, "abc-version ", 12) == 0) {
				get_vers(p + 12);
				return 0;
			}
			if (strncasecmp(p, "decoration ", 11) == 0) {
				p += 11;
				while (isspace((unsigned char) *p))
					p++;
				switch (*p) {
				case '!':
					char_tb['!'] = CHAR_DECOS;
					char_tb['+'] = CHAR_BAD;
					break;
				case '+':
					char_tb['+'] = CHAR_DECOS;
					char_tb['!'] = CHAR_BAD;
					break;
				}
				return 0;
			}
			if (strncasecmp(p, "linebreak ", 10) == 0) {
				for (i = 0; i < sizeof char_tb; i++) {
					if (char_tb[i] == CHAR_LINEBREAK)
						char_tb[i] = i != '!' ?
								CHAR_BAD :
								CHAR_DECOS;
				}
				p += 10;
				for (;;) {
					while (isspace((unsigned char) *p))
						p++;
					if (*p == '\0')
						break;
					switch (*p) {
					case '!':
					case '$':
					case '*':
					case ';':
					case '?':
					case '@':
						char_tb[(unsigned char) *p++]
								= CHAR_LINEBREAK;
						break;
					case '<':
						if (strcmp(p, "<none>") == 0)
							return 0;
						if (strcmp(p, "<EOL>") == 0) {
							char_tb['\n'] = CHAR_LINEBREAK;
							p += 5;
							break;
						}
						/* fall thru */
					default:
						if (strcmp(p, "lock") != 0)
							syntax("Invalid character in %%%%linebreak",
								p);
						return 0;
					}
				}
				return 0;
			}
			if (strncasecmp(p, "user ", 5) == 0) {
				p += 5;
				while (isspace((unsigned char) *p))
					p++;
				get_user(p, s);
				return 0;
			}
			return 0;
		}
		/* fall thru */
	case '\\':				/* abc2mtex specific lines */
		if (keep_comment) {
			s = abc_new(t, p, NULL);
			s->type = ABC_T_NULL;
		}
		return 0;			/* skip */
	}
	comment = decomment_line(p);

	/* header fields */
	if (p[1] == ':'
	 && *p != '|' && *p != ':') {		/* not '|:' nor '::' */
		int new_tune;

		new_tune = parse_info(t, p, comment);

		/* handle BarFly voice definition */
		/* 'V:n <note line ending with a bar>' */
		if (*p != 'V'
		 || abc_state != ABC_S_TUNE)
			return new_tune;		/* (normal return) */
		c = p[strlen(p) - 1];
		if (c != '|' && c != ']')
			return new_tune;
		while (!isspace((unsigned char) *p) && *p != '\0')
			p++;
		while (isspace((unsigned char) *p))
			p++;
	}
	if (abc_state != ABC_S_TUNE) {
		if (keep_comment) {
			s = abc_new(t, p, comment);
			s->type = ABC_T_NULL;
		}
		return 0;
	}

	flags = 0;

	if (abc_vers <= (2 << 16))
		lyric_started = 0;
	deco_start = deco_cont = NULL;
	slur = 0;
	while (*p != '\0') {
		colnum = p - abc_line;
		switch (char_tb[(unsigned char) *p++]) {
		case CHAR_GCHORD:			/* " */
			if (flags & ABC_F_GRACE)
				goto bad_char;
			p = parse_gchord(p);
			break;
		case CHAR_GR_ST:		/* '{' */
			if (flags & ABC_F_GRACE)
				goto bad_char;
			last_note_sav = curvoice->last_note;
			curvoice->last_note = NULL;
			memcpy(&dc_sav, &dc, sizeof dc);
			dc.n = dc.h = dc.s = 0;
			flags_sav = flags;
			flags = ABC_F_GRACE;
			if (*p == '/') {
				flags |= ABC_F_SAPPO;
				p++;
			}
			break;
		case CHAR_GR_EN:		/* '}' */
			if (!(flags & ABC_F_GRACE))
				goto bad_char;
			t->last_sym->flags |= ABC_F_GR_END;
			curvoice->last_note = last_note_sav;
			memcpy(&dc, &dc_sav, sizeof dc);
			flags = flags_sav;
			break;
		case CHAR_DECOS:
			if (p[-1] == '!'
			 && char_tb['\n'] == CHAR_LINEBREAK
			 && check_nl(p)) {
				s = abc_new(t, NULL, NULL);	/* abc2win EOL */
				s->type = ABC_T_EOLN;
				s->u.eoln.type = 2;
				break;
			}
			/* fall thru */
		case CHAR_DECO:
			if (p[-1] == '.') {
				if (*p == '(' || *p == '-' || *p == ')')
					break;
				if (*p == '|') {
					p = parse_bar(t, p + 1);
					t->last_sym->u.bar.dotted = 1;
					break;
				}
			}
			p = parse_deco(p - 1, &dc);
			dc.h = dc.s = dc.n;
			break;
		case CHAR_LINEBREAK:
			s = abc_new(t, NULL, NULL);
			s->type = ABC_T_EOLN;
//			s->u.eoln.type = 0;
			break;
		case CHAR_ACC:
		case CHAR_NOTE:
		case CHAR_REST:
			p = parse_note(t, p - 1, flags);
			flags &= ABC_F_GRACE;
			t->last_sym->u.note.slur_st = slur;
			slur = 0;
			if (t->last_sym->u.note.lens[0] > 0)	/* if not space */
				curvoice->last_note = t->last_sym;
			break;
		case CHAR_SLASH:		/* '/' */
			if (flags & ABC_F_GRACE)
				goto bad_char;
			q = p;
			while (*q == '/')
				q++;
			if (char_tb[(unsigned char) *q] != CHAR_BAR)
				goto bad_char;
			s = abc_new(t, NULL, NULL);
			s->type = ABC_T_MREP;
			s->u.bar.type = 0;
			s->u.bar.len = q - p + 1;
			syntax("Non standard measure repeat syntax", p - 1);
			p = q;
			break;
		case CHAR_BSLASH:		/* '\\' */
			if (*p == '\0')
				break;
			syntax("'\\' ignored", p - 1);
			break;
		case CHAR_OBRA:			/* '[' */
			if (*p == '|' || *p == ']' || *p == ':'
			 || isdigit((unsigned char) *p) || *p == '"'
			 || *p == ' ') {
				if (flags & ABC_F_GRACE)
					goto bad_char;
				p = parse_bar(t, p);
				break;
			}
			if (p[1] != ':') {
				p = parse_note(t, p - 1, flags); /* chord */
				flags &= ABC_F_GRACE;
				t->last_sym->u.note.slur_st = slur;
				slur = 0;
				curvoice->last_note = t->last_sym;
				break;
			}

			/* embedded header */
#if 0
/*fixme:OK for [I:staff n], ?? for other headers*/
			if (flags & ABC_F_GRACE)
				goto bad_char;
#endif
			while (p[2] == ' ') {		/* remove the spaces */
				p[2] = ':';
				p[1] = *p;
				p++;
			}
			c = ']';
			q = p;
			while (*p != '\0' && *p != c)
				p++;
			if (*p == '\0') {
				syntax("Escape sequence [..] not closed", q);
				c = '\0';
			} else {
				*p = '\0';
			}
			parse_info(t, q, NULL);
			*p = c;
			if (c != '\0')
				p++;
			break;
		case CHAR_BAR:			/* '|', ':' or ']' */
			if (flags & ABC_F_GRACE)
				goto bad_char;
			p = parse_bar(t, p);
			break;
		case CHAR_OPAR:			/* '(' */
			if (isdigit((unsigned char) *p)) {
				int pplet, qplet, rplet;

				pplet = strtol(p, &q, 10);
				if (pplet <= 1) {
					syntax("Invalid 'p' in tuplet", p);
					pplet = 0;
				}
				p = q;
				if ((unsigned) pplet < sizeof qtb / sizeof qtb[0])
					qplet = qtb[pplet];
				else
					qplet = qtb[0];
				rplet = pplet;
				if (*p == ':') {
					p++;
					if (isdigit((unsigned char) *p)) {
						qplet = strtol(p, &q, 10);
						p = q;
					}
					if (*p == ':') {
						p++;
						if (isdigit((unsigned char) *p)) {
							rplet = strtol(p, &q, 10);
							p = q;
						}
					}
				}
				if (pplet == 0)
					break;
				if (rplet < 1) {
					syntax("Invalid 'r' in tuplet", p);
					break;
				}
				if (qplet == 0)
					qplet = meter % 3 == 0 ? 3 : 2;
				s = abc_new(t, NULL, NULL);
				s->type = ABC_T_TUPLET;
				s->u.tuplet.p_plet = pplet;
				s->u.tuplet.q_plet = qplet;
				s->u.tuplet.r_plet = rplet;
				s->flags |= flags;
				break;
			}
			if (*p == '&') {
				if (flags & ABC_F_GRACE)
					goto bad_char;
				p++;
				if (vover != 0) {
					syntax("Nested voice overlay", p - 1);
					break;
				}
				s = abc_new(t, NULL, NULL);
				s->type = ABC_T_V_OVER;
				s->u.v_over.type = V_OVER_S;
				s->u.v_over.voice = curvoice - voice_tb;
				vover = -1;		/* multi-bars */
				break;
			}
			slur <<= 3;
			if (p[-2] == '.' && dc.n == 0)
				slur |= SL_DOTTED;
			switch (*p) {
			case '\'':
				slur += SL_ABOVE;
				p++;
				break;
			case ',':
				slur += SL_BELOW;
				p++;
				break;
			default:
				slur += SL_AUTO;
				break;
			}
			break;
		case CHAR_CPAR:			/* ')' */
			switch (t->last_sym->type) {
			case ABC_T_NOTE:
			case ABC_T_REST:
				break;
			default:
				goto bad_char;
			}
			t->last_sym->u.note.slur_end++;
			break;
		case CHAR_VOV:			/* '&' */
			if (flags & ABC_F_GRACE)
				goto bad_char;
			if (*p != ')'
			 || vover == 0) {		/*??*/
				if (!curvoice->last_note) {
					syntax("Bad start of voice overlay", p);
					break;
				}
				s = abc_new(t, NULL, NULL);
				s->type = ABC_T_V_OVER;
				/*s->u.v_over.type = V_OVER_V; */
				vover_new();
				s->u.v_over.voice = curvoice - voice_tb;
				if (vover == 0)
					vover = 1;	/* single bar */
				break;
			}
			p++;
			vover = 0;
			s = abc_new(t, NULL, NULL);
			s->type = ABC_T_V_OVER;
			s->u.v_over.type = V_OVER_E;
			s->u.v_over.voice = curvoice->mvoice;
			curvoice->last_note = NULL;	/* ?? */
			curvoice = &voice_tb[curvoice->mvoice];
			break;
		case CHAR_SPAC:			/* ' ' and '\t' */
			flags |= ABC_F_SPACE;
			break;
		case CHAR_MINUS: {		/* '-' */
			int tie_pos;

			if (!curvoice->last_note
			 || curvoice->last_note->type != ABC_T_NOTE)
				goto bad_char;
			if (p[-2] == '.' && dc.n == 0)
				tie_pos = SL_DOTTED;
			else
				tie_pos = 0;
			switch (*p) {
			case '\'':
				tie_pos += SL_ABOVE;
				p++;
				break;
			case ',':
				tie_pos += SL_BELOW;
				p++;
				break;
			default:
				tie_pos += SL_AUTO;
				break;
			}
			for (i = 0; i <= curvoice->last_note->u.note.nhd; i++) {
				if (curvoice->last_note->u.note.ti1[i] == 0)
					curvoice->last_note->u.note.ti1[i] = tie_pos;
				else if (curvoice->last_note->u.note.nhd == 0)
					syntax("Too many ties", p);
			}
			break;
		    }
		case CHAR_BRHY:			/* '>' and '<' */
			if (!curvoice->last_note)
				goto bad_char;
			i = 1;
			while (*p == p[-1]) {
				i++;
				p++;
			}
			if (i > 3) {
				syntax("Bad broken rhythm", p - 1);
				i = 3;
			}
			if (p[-1] == '<')
				i = -i;
			broken_rhythm(&curvoice->last_note->u.note, i);
			curvoice->last_note->u.note.brhythm = i;
			break;
		case CHAR_IGN:			/* '*' & '`' */
			break;
		default:
		bad_char:
			syntax((flags & ABC_F_GRACE)
					? "Bad character in grace note sequence"
					: "Bad character",
				p - 1);
			break;
		}
	}

/*fixme: may we have grace notes across lines?*/
	if (flags & ABC_F_GRACE) {
		syntax("EOLN in grace note sequence", p - 1);
		if (curvoice->last_note)
			curvoice->last_note->flags |= ABC_F_GR_END;
		curvoice->last_note = last_note_sav;
		memcpy(&dc, &dc_sav, sizeof dc);
	}

	/* add eoln */
	s = abc_new(t, NULL, NULL);
	s->type = ABC_T_EOLN;
	if (flags & ABC_F_SPACE)
		s->flags |= ABC_F_SPACE;
	if (p[-1] == '\\'
	 || char_tb['\n'] != CHAR_LINEBREAK)
		s->u.eoln.type = 1;		/* no break */
	return 0;
}

/* -- parse a note or a rest -- */
static char *parse_note(struct abctune *t,
			char *p,
			int flags)
{
	struct abcsym *s;
	char *q;
	int pit, len, acc, nostem, chord, j, m;

	if (flags & ABC_F_GRACE) {	/* in a grace note sequence */
		s = abc_new(t, NULL, NULL);
	} else {
		s = abc_new(t, gchord, NULL);
		if (gchord) {
			if (free_f)
				free_f(gchord);
			gchord = NULL;
		}
	}
	s->type = ABC_T_NOTE;
	s->flags |= flags;

	if (!lyric_started) {
		lyric_started = 1;
		s->flags |= ABC_F_LYRIC_START;
	}
	if (*p != 'X' && *p != 'Z'
	 && !(flags & ABC_F_GRACE)) {
		if (!deco_start)
			deco_start = s;
	}

	/* rest */
	switch (*p) {
	case 'X':
	case 'Z':			/* multi-rest */
		s->type = ABC_T_MREST;
		if (*p == 'X')
			s->flags |= ABC_F_INVIS;
		p++;
		len = 1;
		if (isdigit((unsigned char) *p)) {
			len = strtol(p, &q, 10);
			if (len == 0 && len > 100) {
				syntax("Bad number of measures", p);
				len = 1;
			}
			p = q;
		}
		s->u.bar.type = 0;
		s->u.bar.len = len;
		goto add_deco;
	case 'y':			/* space (BarFly) */
		s->type = ABC_T_REST;
		s->flags |= ABC_F_INVIS;
		p++;
		if (isdigit((unsigned char) *p)) {	/* number of points */
			s->u.note.lens[1] = strtol(p, &q, 10);
			p = q;
		} else {
			s->u.note.lens[1] = -1;
		}
		goto add_deco;
	case 'x':			/* invisible rest */
		s->flags |= ABC_F_INVIS;
		/* fall thru */
	case 'z':
		s->type = ABC_T_REST;
		p = parse_len(p + 1, &len);
		s->u.note.lens[0] = len * ulen / BASE_LEN;
		goto do_brhythm;
	}

	chord = 0;
	q = p;
	if (*p == '[') {	/* '[..]' = chord */
		chord = 1;
		p++;
	}

	/* get pitch, length and possible accidental */
	m = 0;
	nostem = 0;
	for (;;) {
		int tmp;

		if (chord) {
			if (m >= MAXHD) {
				syntax("Too many notes in chord", p);
				m--;
			}
			tmp = 0;
			if (*p == '.') {
				tmp = SL_DOTTED;
				p++;
			}
			if (*p == '(') {
				p++;
				switch (*p) {
				case '\'':
					tmp += SL_ABOVE;
					p++;
					break;
				case ',':
					tmp += SL_BELOW;
					p++;
					break;
				default:
					tmp += SL_AUTO;
					break;
				}
				s->u.note.sl1[m] = (s->u.note.sl1[m] << 3)
							+ tmp;
			}
		}
		tmp = dc.n;
		p = parse_deco(p, &dc);		/* note head decorations */
		if (dc.n != tmp) {
			if (dc.n - tmp >= 8) {
				syntax("Too many decorations on this head", p);
				tmp = dc.n - 7;
			}
			s->u.note.decs[m] = (tmp << 3) + dc.n - tmp;
			dc.s = dc.n;
		}
		p = parse_basic_note(p, &pit, &len, &acc, &tmp);
		if (!(flags & ABC_F_GRACE))
			len = len * ulen / BASE_LEN;
		else
			len /= 8;		/* for grace note alone */

		s->u.note.pits[m] = pit;
		s->u.note.lens[m] = len;
		s->u.note.accs[m] = acc;
		nostem |= tmp;

		if (chord) {
			for (;;) {
				if (*p == '.') {
					if (p[1] != '-')
						break;
					p++;
				}
				if (*p == '-') {
					switch (p[1]) {
					case '\'':
						s->u.note.ti1[m] = SL_ABOVE;
						p++;
						break;
					case ',':
						s->u.note.ti1[m] = SL_BELOW;
						p++;
						break;
					default:
						s->u.note.ti1[m] = SL_AUTO;
						break;
					}
				} else if (*p == ')') {
					s->u.note.sl2[m]++;
				} else {
					break;
				}
				p++;
			}
		}
		if (acc >= 0)			/* if no error */
			m++;			/* normal case */

		if (!chord)
			break;
		if (*p == ']') {
			p++;
			if (*p == '0') {
				nostem |= 1;
				p++;
			}
			if (*p == '/' || isdigit((unsigned char) *p)) {
				p = parse_len(p, &len);
				s->u.note.chlen = len;
				for (j = 0; j < m; j++) {
					tmp = len * s->u.note.lens[j];
					s->u.note.lens[j] = tmp / BASE_LEN;
				}
			}
			break;
		}
		if (*p == '\0') {
			syntax("Chord not closed", q);
			break;
		}
	}
	if (nostem)
		s->flags |= ABC_F_STEMLESS;

	if (m == 0)			/* if no note (or error) */
		goto err;

	s->u.note.microscale = microscale;
	s->u.note.nhd = m - 1;
do_brhythm:
	if (curvoice->last_note
	 && curvoice->last_note->u.note.brhythm != 0)
		broken_rhythm(&s->u.note,
			      -curvoice->last_note->u.note.brhythm);
add_deco:
	if (dc.n > 0) {
		memcpy(s->type != ABC_T_MREST ? &s->u.note.dc
				: &s->u.bar.dc,
			&dc, sizeof dc);
		dc.n = dc.h = dc.s = 0;
	}
	/* forbid rests in grace note sequences */
	if (s->type != ABC_T_NOTE && (flags & ABC_F_GRACE)) {
		syntax("Not a note in grace note sequence", p);
		goto err;
	}
	return p;

err:
	if ((t->last_sym = s->prev) == NULL) {
		t->first_sym = NULL;
	} else {
		s->prev->next = NULL;
		s->prev->flags |= (s->flags & ABC_F_ERROR);
	}
	return p;
}

/* -- parse an information field -- */
/* return 2 on start of new tune */
static int parse_info(struct abctune *t,
			char *p,
			char *comment)
{
	struct abcsym *s;
	char info_type = *p;
	char *error_txt = NULL;

	s = abc_new(t, p, comment);
	s->type = ABC_T_INFO;

	p += 2;

	switch (info_type) {
	case 'd':
	case 's':
		if (abc_state == ABC_S_GLOBAL)
			break;
		if (!deco_start) {
			error_txt = "Erroneous 'd:'/'s:'";
			break;
		}
		error_txt = parse_decoline(p);
		break;
	case 'K':
		if (abc_state == ABC_S_GLOBAL)
			break;
		parse_key(p, s);
		if (abc_state == ABC_S_HEAD) {
			int i;

			abc_state = ABC_S_TUNE;
			if (ulen == 0)
				ulen = BASE_LEN / 8;
			for (i = MAXVOICE; --i >= 0; )
				voice_tb[i].ulen = ulen;
			lyric_started = 0;
		}
		break;
	case 'L':
		error_txt = get_len(p, s);
		if (s->u.length.base_length > 0)
			ulen = s->u.length.base_length;
		break;
	case 'M':
		error_txt = parse_meter(p, s);
		break;
	case 'Q':
		error_txt = parse_tempo(p, s);
		break;
	case 'U':
		error_txt = get_user(p, s);
		break;
	case 'V':
		if (abc_state == ABC_S_GLOBAL)
			break;
		error_txt = parse_voice(p, s);
		break;
	case 'X':
		memset(voice_tb, 0, sizeof voice_tb);
		nvoice = 0;
		curvoice = &voice_tb[0];
		abc_state = ABC_S_HEAD;
		if (level_f)
			level_f(1);
		return 2;
	}
	if (error_txt)
		syntax(error_txt, p);
	return 0;
}

/* -- print a syntax error message -- */
static void syntax(char *msg,
		   char *q)
{
	int n, len, m1, m2, pp;
	int maxcol = 73;

	severity = 1;
	n = q - abc_line;
	len = strlen(abc_line);
	if ((unsigned) n > (unsigned) len)
		n = -1;
	print_error(msg, n);
	if (n < 0) {
		if (q && *q != '\0')
			fprintf(stderr, " (near '%s')\n", q);
		return;
	}
	m1 = 0;
	m2 = len;
	if (m2 > maxcol) {
		if (n < maxcol) {
			m2 = maxcol;
		} else {
			m1 = n - 20;
			m2 = m1 + maxcol;
			if (m2 > len)
				m2 = len;
		}
	}

	fprintf(stderr, "%4d ", linenum);
	pp = 6;
	if (m1 > 0) {
		fprintf(stderr, "...");
		pp += 3;
	}
	fprintf(stderr, "%.*s", m2 - m1, &abc_line[m1]);
	if (m2 < len)
		fprintf(stderr, "...");
	fprintf(stderr, "\n");

	if ((unsigned) n < 200)
		fprintf(stderr, "%*s\n", n + pp - m1, "^");

	if (last_sym)
		last_sym->flags |= ABC_F_ERROR;
}

/* -- switch to a new voice overlay -- */
static void vover_new(void)
{
	int voice, mvoice;

	mvoice = curvoice->mvoice;
	for (voice = curvoice - voice_tb + 1; voice <= nvoice; voice++)
		if (voice_tb[voice].mvoice == mvoice)
			break;
	if (voice > nvoice) {
		if (nvoice >= MAXVOICE) {
			syntax("Too many voices", 0);
			return;
		}
		nvoice = voice;
		voice_tb[voice].id[0] = '&';
		voice_tb[voice].mvoice = mvoice;
	}
	voice_tb[voice].ulen = curvoice->ulen;
	voice_tb[voice].microscale = curvoice->microscale;
	curvoice = &voice_tb[voice];
}
abcm2ps-7.8.13/abcparse.h0000644000175000017500000001657112314503216013173 0ustar  jefjef/*++
 * Declarations for abcparse.c.
 *
 *-*/

#define MAXVOICE 32	/* max number of voices */

#define MAXHD	8	/* max heads in a chord */
#define MAXDC	45	/* max decorations per note/chord/bar */
#define MAXMICRO 32	/* max microtone values (5 bits in accs[]) */

#define BASE_LEN 1536	/* basic note length (semibreve or whole note - same as MIDI) */

#define VOICE_ID_SZ 16	/* max size of the voice identifiers */

/* accidentals */
enum accidentals {
	A_NULL,		/* none */
	A_SH,		/* sharp */
	A_NT,		/* natural */
	A_FT,		/* flat */
	A_DS,		/* double sharp */
	A_DF		/* double flat */
};

/* bar types - 4 bits per symbol */
#define B_BAR 1		/* | */
#define B_OBRA 2	/* [ */
#define B_CBRA 3	/* ] */
#define B_COL 4		/* : */

/* slur/tie types (3 bits) */
#define SL_ABOVE 0x01
#define SL_BELOW 0x02
#define SL_AUTO 0x03
#define SL_DOTTED 0x04		/* (modifier bit) */

/* note structure */
struct deco {		/* decorations */
	char n;			/* whole number of decorations */
	char h;			/* start of head decorations */
	char s;			/* start of decorations from s: (d:) */
	unsigned char t[MAXDC];	/* decoration type */
};

struct note {		/* note or rest */
	signed char pits[MAXHD]; /* pitches */
	short lens[MAXHD];	/* note lengths (# pts in [1] if space) */
	unsigned char accs[MAXHD]; /* code for accidentals & index in micro_tb */
	unsigned char sl1[MAXHD]; /* slur start per head */
	char sl2[MAXHD];	/* number of slur end per head */
	char ti1[MAXHD];	/* flag to start tie here */
	unsigned char decs[MAXHD]; /* head decorations (index: 5 bits, len: 3 bits) */
	short chlen;		/* chord length */
	char nhd;		/* number of notes in chord - 1 */
	unsigned char slur_st;	/* slurs starting here (2 bits array) */
	char slur_end;		/* number of slurs ending here */
	signed char brhythm;	/* broken rhythm */
	unsigned char microscale; /* microtone denominator - 1 */
	struct deco dc;		/* decorations */
};

/* symbol definition */
struct abctune;
struct abcsym {
	struct abctune *tune;	/* tune */
	struct abcsym *next, *prev; /* next / previous symbol */
	char type;		/* symbol type */
#define ABC_T_NULL	0
#define ABC_T_INFO 	1		/* (text[0] gives the info type) */
#define ABC_T_PSCOM	2
#define ABC_T_CLEF	3
#define ABC_T_NOTE	4
#define ABC_T_REST	5
#define ABC_T_BAR	6
#define ABC_T_EOLN	7
#define ABC_T_MREST	8		/* multi-measure rest */
#define ABC_T_MREP	9		/* measure repeat */
#define ABC_T_V_OVER	10		/* voice overlay */
#define ABC_T_TUPLET	11
	char state;		/* symbol state in file/tune */
#define ABC_S_GLOBAL 0			/* global */
#define ABC_S_HEAD 1			/* in header (after X:) */
#define ABC_S_TUNE 2			/* in tune (after K:) */
	unsigned short flags;
#define ABC_F_ERROR	0x0001		/* error around this symbol */
#define ABC_F_INVIS	0x0002		/* invisible symbol */
#define ABC_F_SPACE	0x0004		/* space before a note */
#define ABC_F_STEMLESS	0x0008		/* note with no stem */
#define ABC_F_LYRIC_START 0x0010	/* may start a lyric here */
#define ABC_F_GRACE	0x0020		/* grace note */
#define ABC_F_GR_END	0x0040		/* end of grace note sequence */
#define ABC_F_SAPPO	0x0080		/* short appoggiatura */
	unsigned short colnum;	/* ABC source column number */
	int linenum;		/* ABC source line number */
	char *fn;		/* ABC source file name */
	char *text;		/* main text (INFO, PSCOM),
				 * guitar chord (NOTE, REST, BAR) */
	char *comment;		/* comment part (when keep_comment) */
	union {			/* type dependent part */
		struct key_s {		/* K: info */
			signed char sf;		/* sharp (> 0) flats (< 0) */
			char empty;		/* clef alone if 1, 'none' if 2 */
			char exp;		/* exp (1) or mod (0) */
			char mode;		/* mode */
/* 0: Ionian, 1: Dorian, 2: Phrygian, 3: Lydian, 4: Mixolydian
 * 5: Aeolian, 6: Locrian, 7: major, 8:minor, 9: HP, 10: Hp */
#define MAJOR 7
#define MINOR 8
#define BAGPIPE 9				/* bagpipe when >= 8 */
			signed char nacc;	/* number  of explicit accidentals */
						/* (-1) if no accidental */
			signed char octave;	/* 'octave=' */
#define NO_OCTAVE 10				/* no 'octave=' */
			unsigned char microscale; /* microtone denominator - 1 */
			signed char pits[8];
			unsigned char accs[8];
		} key;
		struct {		/* L: info */
			int base_length;	/* basic note length */
		} length;
		struct meter_s {	/* M: info */
			short wmeasure;		/* duration of a measure */
			unsigned char nmeter;	/* number of meter elements */
			char expdur;		/* explicit measure duration */
#define MAX_MEASURE 6
			struct {
				char top[8];	/* top value */
				char bot[2];	/* bottom value */
			} meter[MAX_MEASURE];
		} meter;
		struct {		/* Q: info */
			char *str1;		/* string before */
			short length[4];	/* up to 4 note lengths */
			char *value;		/* tempo value */
			char *str2;		/* string after */
		} tempo;
		struct {		/* V: info */
			char id[VOICE_ID_SZ];	/* voice ID */
			char *fname;		/* full name */
			char *nname;		/* nick name */
			float scale;		/* != 0 when change */
			unsigned char voice;	/* voice number */
			signed char octave;	/* 'octave=' - same as in K: */
			char merge;		/* merge with previous voice */
			signed char stem;	/* have stems up or down (2 = auto) */
			signed char gstem;	/* have grace stems up or down (2 = auto) */
			signed char dyn;	/* have dynamic marks above or below the staff */
			signed char lyrics;	/* have lyrics above or below the staff */
			signed char gchord;	/* have gchord above or below the staff */
		} voice;
		struct {		/* bar, mrest or mrep */
			int type;
			char repeat_bar;
			char len;		/* len if mrest or mrep */
			char dotted;
			struct deco dc;		/* decorations */
		} bar;
		struct clef_s {		/* clef (and staff!) */
			char *name;		/* PS drawing function */
			float staffscale;	/* != 0 when change */
			signed char stafflines;	/* >= 0 when change */
			signed char type;	/* no clef if < 0 */
#define TREBLE 0
#define ALTO 1
#define BASS 2
#define PERC 3
			char line;
			signed char octave;
			signed char transpose;
			char invis;
			char check_pitch;	/* check if old abc2ps transposition */
		} clef;
		struct note note;	/* note, rest */
		struct {		/* user defined accent */
			unsigned char symbol;
			unsigned char value;
		} user;
		struct {
			char type;	/* 0: end of line
					 * 1: continuation ('\')
					 * 2: line break ('!') */
		} eoln;
		struct {		/* voice overlay */
			char type;
#define V_OVER_V 0				/* & */
#define V_OVER_S 1				/* (& */
#define V_OVER_E 2				/* &) */
			unsigned char voice;
		} v_over;
		struct {		/* tuplet */
			char p_plet, q_plet, r_plet;
		} tuplet;
	} u;
};

/* tune definition */
struct abctune {
	struct abctune *next;	/* next tune */
	struct abcsym *first_sym; /* first symbol */
	struct abcsym *last_sym; /* last symbol */
	int abc_vers;		/* ABC version = (H << 16) + (M << 8) + L */
	void *client_data;	/* client data */
	unsigned short micro_tb[MAXMICRO]; /* microtone values [ (n-1) | (d-1) ] */
};

#ifdef WIN32
#define strcasecmp stricmp
#define strncasecmp strnicmp
#endif

#if defined(__cplusplus)
extern "C" {
#endif
extern char *deco_tb[];
extern int severity;

void abc_delete(struct abcsym *as);
void abc_free(struct abctune *first_tune);
void abc_init(void *alloc_f_api(int size),
	      void free_f_api(void *ptr),
	      void level_f_api(int level),
	      int client_sz_api,
	      int keep_comment_api);
void abc_insert(char *file_api,
		struct abcsym *s);
struct abcsym *abc_new(struct abctune *t,
		       char *p,
		       char *comment);
struct abctune *abc_parse(char *file_api);
char *get_str(char *d,
	      char *s,
	      int maxlen);
char *parse_deco(char *p,
		 struct deco *deco);
#if defined(__cplusplus)
}
#endif
abcm2ps-7.8.13/accordion.abc0000644000175000017500000000445111654555736013670 0ustar  jefjef% tablature examples
% --- diatonic accordion
%%beginps
% length x y n accordh - accordion tablature header with 2 or 3 lines
/accordh{
%	/Times-Roman 14 selectfont
	/nlines exch def
	.8 SLW
	gsave 20 add T /w exch def
	0 0 M w 0 RL
	0 3 M w 0 RL
	0 21 M w 0 RL
	0 39 M w 0 RL
	nlines 2 eq{
		0 42 M w 0 RL
		stroke
		/barh 42 def
		3 7 M (T:) show
		3 25 M (P:) show
	}{
		0 57 M w 0 RL
		0 60 M w 0 RL
		stroke
		/barh 60 def
		3 7 M (B/a:) show
		3 25 M (T:) show
		3 43 M (P:) show
	}ifelse
	grestore
}!
% string x y n accordn - accordion tablature
/accordn{
	-18 mul add barh add 3 add M showc
}!
/accordb{
	0 eq{20 add M 0 barh RL stroke}
	{pop pop}ifelse pop}!
%%endps

X:3
T:Andro à Patrice Corbel
N: validé 03/05/01 -- 04/08/02
R:Andro
O:Bretagne
M:4/4
K:Am
%%tablature 70 accordh accordn accordb
 "A"A2 cA "F" aAce | "G"dGBd "C"e4 | "F"fedc "G"B2 AB |1 "F"cABc "E"B4 :|2 "F"cABc "A"A4 :|\
w:    *  * * * * * *   8 6 7 8  7'   * * * *  * * *   * * * *  7   * * * *  *  
w:    7  8 7 11 7 8 9   * * * *  *   8' 9 7' 8  6' 7 6'   8 7 6' 8  *   8 7 6' 8  7  
 "A"A2 GF "E"E3 B | "E"c2 d2 "C"e4 | "F"fedc "G"B2 AB |1 "F"cABc "E"B4 :|2 "F"cABc "A"A4 :|
w:    * 6 *  4' 7   6' 8  7'   * * * *  * * *   * * * *  7   * * * *  *  
w:    7 * 4'  * *   * *  *   8' 9 7' 8  6' 7 6'   8 7 6' 8  *   8 7 6' 8  7  

X:51
T:Jeune fille de quinze ans (50-51-52)
T:Une fille de rose
N: rev. 01/06/01
R:hanter dro
C:trad
A:Bretagne
O:France
M:3/4
L:1/8
Q:100
K:Am
%%tablature 90 accordh accordn accordb
 |: "Am" ee/f/ "Am" ed "Am" c2   | "Am" ed/c/ "G" Bd "Am" cA | "Am" ee/f/ "Am" ed "Am" c2   |1 "Am" ed/c/ "G" BG "Em" E2 :|2 "Am" ed/c/ "G" BG "Am" A2 |
w:     * * *  * *  * | * * *  7 8  * * | * * *  * *  * | * * *  7 6  4'| * * *  7 6  *  
w:     9 9 8'  9 7'  8 | 9 7' 8  * *  8 7 | 9 9 8'  9 7'  8 | 9 7' 8  * *  * | 9 7' 8  * *  7  
w: A a *  A a A~~a | A a * G g E e | A a *  A a A~~a | A a * G g E~~e | A a * G g E~~e | 
 |: "Am" AA/B/ "Am" cd "C" e2 | "G" de/f/ "F" af "Am" e2 | "Am" cd/e/ "F" fe "G" d2 |1 "G" Bc/d/ "Em" cB "Em" cB :|2 "G" Bc/d/ "Em" cB "Am" A2 ||
w:     * * *  * *  7' | 8 7' *  * *  * | * * *  * *  8 | 7 6' 8  6' 7  6' 7 | 7 6' 8  6' 7  *  
w:     7 7 6'  8 7' * | * * 8'  9' 8'  9 | 8 7' 9  8' 9  * | * * *  * *  * * | * * *  * *  7  
w: A a * A a C~c | G g * F f A~a | A a * F f G~g | G g * E e E e | G g * E e A~a |  
abcm2ps-7.8.13/build.ninja0000644000175000017500000000577512461214571013374 0ustar  jefjef# rules for ninja (ninja-build)

VERSION = 7.8.13

cflags = -g -O2 -Wall -pipe -DHAVE_CONFIG_H  -I.
#cflags = -g -Wall -pipe -DHAVE_CONFIG_H  -I.
ldflags = -lm

rule cc
#  command = gcc $cflags -c $in -o $out
  command = clang $cflags -c $in -o $out
# -mcpu=iwmmxt
# -mcpu=iwmmxt2
# -mthumb -march=armv7-a

rule ld
#  command = cc $ldflags -o $out $in
  command = clang $ldflags -o $out $in

build abc2ps.o: cc abc2ps.c | config.h abcparse.h abc2ps.h front.h
build abcparse.o: cc abcparse.c | config.h abcparse.h
build buffer.o: cc buffer.c | config.h abcparse.h abc2ps.h
build deco.o: cc deco.c | config.h abcparse.h abc2ps.h
build draw.o: cc draw.c | config.h abcparse.h abc2ps.h
build format.o: cc format.c | config.h abcparse.h abc2ps.h
build front.o: cc front.c | config.h abcparse.h abc2ps.h front.h slre.h
build glyph.o: cc glyph.c | config.h abcparse.h abc2ps.h
build music.o: cc music.c | config.h abcparse.h abc2ps.h
build parse.o: cc parse.c | config.h abcparse.h abc2ps.h
build slre.o: cc slre.c | slre.h
build subs.o: cc subs.c | config.h abcparse.h abc2ps.h
build svg.o: cc svg.c | config.h abcparse.h abc2ps.h
build syms.o: cc syms.c | config.h abcparse.h abc2ps.h

build abcm2ps: ld abc2ps.o abcparse.o buffer.o deco.o draw.o format.o front.o $
  glyph.o music.o parse.o slre.o subs.o svg.o syms.o

default abcm2ps

rule dist_tar
  command = ln -s . abcm2ps-$VERSION; $
   tar -zcvf $out $
  abcm2ps-$VERSION/Changes $
  abcm2ps-$VERSION/INSTALL $
  abcm2ps-$VERSION/License $
  abcm2ps-$VERSION/Makefile $
  abcm2ps-$VERSION/Makefile.in $
  abcm2ps-$VERSION/README $
  abcm2ps-$VERSION/abc2ps.c $
  abcm2ps-$VERSION/abc2ps.h $
  abcm2ps-$VERSION/abcparse.c $
  abcm2ps-$VERSION/abcparse.h $
  abcm2ps-$VERSION/accordion.abc $
  abcm2ps-$VERSION/build.ninja $
  abcm2ps-$VERSION/buffer.c $
  abcm2ps-$VERSION/chinese.abc $
  abcm2ps-$VERSION/configure $
  abcm2ps-$VERSION/configure.in $
  abcm2ps-$VERSION/config.h $
  abcm2ps-$VERSION/config.h.in $
  abcm2ps-$VERSION/config.guess $
  abcm2ps-$VERSION/config.sub $
  abcm2ps-$VERSION/deco.c $
  abcm2ps-$VERSION/deco.abc $
  abcm2ps-$VERSION/draw.c $
  abcm2ps-$VERSION/features.txt $
  abcm2ps-$VERSION/flute.fmt $
  abcm2ps-$VERSION/format.c $
  abcm2ps-$VERSION/format.txt $
  abcm2ps-$VERSION/front.c $
  abcm2ps-$VERSION/front.h $
  abcm2ps-$VERSION/glyph.c $
  abcm2ps-$VERSION/install.sh $
  abcm2ps-$VERSION/landscape.fmt $
  abcm2ps-$VERSION/music.c $
  abcm2ps-$VERSION/musicfont.fmt $
  abcm2ps-$VERSION/newfeatures.abc $
  abcm2ps-$VERSION/options.txt $
  abcm2ps-$VERSION/parse.c $
  abcm2ps-$VERSION/sample.abc $
  abcm2ps-$VERSION/sample2.abc $
  abcm2ps-$VERSION/sample3.abc $
  abcm2ps-$VERSION/sample3.eps $
  abcm2ps-$VERSION/sample4.abc $
  abcm2ps-$VERSION/sample5.abc $
  abcm2ps-$VERSION/slre.c $
  abcm2ps-$VERSION/slre.h $
  abcm2ps-$VERSION/subs.c $
  abcm2ps-$VERSION/svg.c $
  abcm2ps-$VERSION/syms.c $
  abcm2ps-$VERSION/tight.fmt $
  abcm2ps-$VERSION/voices.abc;$
   rm abcm2ps-$VERSION

build abcm2ps-$VERSION.tar.gz: dist_tar

build dist: phony abcm2ps-$VERSION.tar.gz
abcm2ps-7.8.13/buffer.c0000644000175000017500000005241412355567026012671 0ustar  jefjef/*
 * Postscript buffering functions.
 *
 * This file is part of abcm2ps.
 *
 * Copyright (C) 1998-2014 Jean-François Moine
 * Adapted from abc2ps, Copyright (C) 1996,1997 Michael Methfessel
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 */

#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#ifdef WIN32
#define snprintf _snprintf
#endif

#include "abc2ps.h" 

#define BUFFLN	80		/* max number of lines in output buffer */

static int ln_num;		/* number of lines in buffer */
static float ln_pos[BUFFLN];	/* vertical positions of buffered lines */
static char *ln_buf[BUFFLN];	/* buffer location of buffered lines */
static float ln_lmarg[BUFFLN];	/* left margin of buffered lines */
static float ln_scale[BUFFLN];	/* scale of buffered lines */
static signed char ln_font[BUFFLN];	/* font of buffered lines */
static float cur_lmarg = 0;	/* current left margin */
static float min_lmarg, max_rmarg;	/* margins for -E/-g */
static float cur_scale = 1.0;	/* current scale */
static float maxy;		/* remaining vertical space in page */
static float bposy;		/* current position in buffered data */
static int nepsf;		/* counter for -E/-g output files */
static int nbpages;		/* number of pages in the output file */
static int outbufsz;		/* size of outbuf */
static char outfnam[FILENAME_MAX]; /* internal file name for open/close */
static struct FORMAT *p_fmt;	/* current format while treating a new page */

int (*output)(FILE *out, const char *fmt, ...);

int in_page;			/* filling a PostScript page */
char *outbuf;			/* output buffer.. should hold one tune */
char *mbf;			/* where to a2b() */
int use_buffer;			/* 1 if lines are being accumulated */

/* -- cut off extension on a file identifier -- */
static void cutext(char *fid)
{
	char *p;

	if ((p = strrchr(fid, DIRSEP)) == NULL)
		p = fid;
	if ((p = strrchr(p, '.')) != NULL)
		*p = '\0';
}

/* -- open the output file -- */
static void open_fout(void)
{
	int i;
	char fnm[FILENAME_MAX];

	strcpy(fnm, outfn);
	i = strlen(fnm) - 1;
	if (i < 0) {
		strcpy(fnm, svg ? "Out.xhtml" : OUTPUTFILE);
#if 1
	} else if (i != 0 || fnm[0] != '-') {
#else
	} else if (i == 0 && fnm[0] == '-') {
		if (svg == 1) {
			error(1, 0, "Cannot use stdout with '-v' - abort");
			exit(EXIT_FAILURE);
		}
	} else {
#endif
		if (fnm[i] == '=') {
			char *p;

			if ((p = strrchr(in_fname, DIRSEP)) == 0)
				p = in_fname;
			else
				p++;
/*fixme: should check if there is a DIRSEP at the end of fnm*/
			strcpy(&fnm[i], p);
			strext(fnm, svg ? "xhtml" : "ps");
		} else if (fnm[i] == DIRSEP) {
			strcpy(&fnm[i + 1], OUTPUTFILE);
		}
#if 0
/*fixme: fnm may be a directory*/
		else	...
#endif
	}
	if (svg == 1
	 && (i != 0 || fnm[0] != '-')) {
		cutext(fnm);
		i = strlen(fnm) - 1;
		if (strncmp(fnm, outfnam, i) != 0)
			nepsf = 0;
		sprintf(&fnm[i + 1], "%03d.svg", ++nepsf);
	} else if (strcmp(fnm, outfnam) == 0) {
		return;				/* same output file */
	}

	close_output_file();
	strcpy(outfnam, fnm);
	if (i != 0 || fnm[0] != '-') {
		if ((fout = fopen(fnm, "w")) == NULL) {
			error(1, NULL, "Cannot create output file %s - abort", fnm);
			exit(EXIT_FAILURE);
		}
	} else {
		fout = stdout;
	}
}

/* -- convert a date -- */
static void cnv_date(time_t *ltime)
{
	char buf[TEX_BUF_SZ];

	tex_str(cfmt.dateformat);
	strcpy(buf, tex_buf);
	strftime(tex_buf, TEX_BUF_SZ, buf, localtime(ltime));
}

/* initialize the min/max margin values */
/* (used only with eps -E and svg -g) */
void marg_init(void)
{
	min_lmarg = cfmt.pagewidth;
	max_rmarg = cfmt.pagewidth;
}

/* -- initialize the postscript file (PS or EPS) -- */
static void init_ps(char *str)
{
	time_t ltime;
	unsigned i;
	char version[32];

	if (epsf) {
		cur_lmarg = min_lmarg - 10;
		fprintf(fout, "%%!PS-Adobe-2.0 EPSF-2.0\n"
			"%%%%BoundingBox: 0 0 %.0f %.0f\n",
			(p_fmt->landscape ? p_fmt->pageheight : p_fmt->pagewidth)
				- cur_lmarg - max_rmarg + 10,
			-bposy);
		marg_init();
	} else {
		if (!fout)
			open_fout();
		fprintf(fout, "%%!PS-Adobe-2.0\n");
		fprintf(fout, "%%%%BoundingBox: 0 0 %.0f %.0f\n",
			p_fmt->pagewidth,
			p_fmt->pageheight);
	}
	fprintf(fout, "%%%%Title: %s\n", str);
	time(&ltime);
#ifndef WIN32
	strftime(tex_buf, TEX_BUF_SZ, "%b %e, %Y %H:%M", localtime(&ltime));
#else
	strftime(tex_buf, TEX_BUF_SZ, "%b %#d, %Y %H:%M", localtime(&ltime));
#endif
	fprintf(fout, "%%%%Creator: abcm2ps-" VERSION "\n"
		"%%%%CreationDate: %s\n", tex_buf);
	if (!epsf)
		fprintf(fout, "%%%%Pages: (atend)\n");
	fprintf(fout, "%%%%LanguageLevel: 3\n"
		"%%%%EndComments\n"
		"%%CommandLine:");
	for (i = 1; i < (unsigned) s_argc; i++) {
		char *p, *q;
		int space;

		p = s_argv[i];
		space = strchr(p, ' ') != NULL || strchr(p, '\n') != NULL;
		fputc(' ', fout);
		if (space)
			fputc('\'', fout);
		for (;;) {
			q = strchr(p, '\n');
			if (!q)
				break;
			fprintf(fout, " %.*s\n%%", (int) (q - p), p);
			p = q + 1;
		}
		fprintf(fout, "%s", p);
		if (space)
			fputc('\'', fout);
	}
	fprintf(fout, "\n\n");
	if (epsf)
		fprintf(fout, "save\n");
	strcpy(version, "/creator [(abcm2ps) " VERSION "] def");
	for (i = 0; i < strlen(version); i++) {
		if (version[i] == '.')
			version[i] = ' ';
	}
	fprintf(fout, "%%%%BeginSetup\n"
		"/!{bind def}bind def\n"
		"/bdef{bind def}!\n"		/* for compatibility */
		"/T/translate load def\n"
		"/M/moveto load def\n"
		"/RM/rmoveto load def\n"
		"/L/lineto load def\n"
		"/RL/rlineto load def\n"
		"/C/curveto load def\n"
		"/RC/rcurveto load def\n"
		"/SLW/setlinewidth load def\n"
		"/defl 0 def\n"	/* decoration flags - see deco.c for values */
		"/dlw{0.7 SLW}!\n"

		"%s\n", version);
	define_symbols();
	output = fprintf;
	user_ps_write();
	define_fonts();
	if (!epsf)
		fprintf(fout, "/setpagedevice where{pop\n"
			"	<</PageSize[%.0f %.0f]>>setpagedevice}if\n",
				p_fmt->pagewidth, p_fmt->pageheight);
	fprintf(fout, "%%%%EndSetup\n");
	file_initialized = 1;
}

/* -- initialize the svg file (option '-g') -- */
static void init_svg(char *str)
{
	cur_lmarg = min_lmarg - 10;
	output = svg_output;
#if 1 //fixme:test
	if (file_initialized)
		fprintf(stderr, "??? init_svg: file_initialized");
#endif
	define_svg_symbols(str, nepsf,
		(p_fmt->landscape ? p_fmt->pageheight : p_fmt->pagewidth)
				- cur_lmarg - max_rmarg + 10,
		-bposy);
	file_initialized = 1;
	user_ps_write();
}

static void close_fout(void)
{
	long m;

	if (fout == stdout)
		goto out2;
	if (quiet)
		goto out1;
	m = ftell(fout);
	if (epsf || svg == 1)
		fprintf(stderr, "Output written on %s (%ld bytes)\n",
			outfnam, m);
	else
		fprintf(stderr,
			"Output written on %s (%d page%s, %d title%s, %ld bytes)\n",
			outfnam,
			nbpages, nbpages == 1 ? "" : "s",
			tunenum, tunenum == 1 ? "" : "s",
			m);
out1:
	fclose(fout);
out2:
	fout = NULL;
	file_initialized = 0;
}

/* -- close the output file -- */
/* epsf is always null */
void close_output_file(void)
{
	if (!fout)
		return;
	if (multicol_start != 0) {	/* if no '%%multicol end' */
		error(1, NULL, "No \"%%%%multicol end\"");
		multicol_start = 0;
		write_buffer();
	}
	if (tunenum == 0)
		error(0, NULL, "No tunes written to output file");
	close_page();
	if (!svg) {
		fprintf(fout, "%%%%Trailer\n"
			"%%%%Pages: %d\n"
			"%%EOF\n", nbpages);
		close_fout();
	} else if (svg == 2) {
		fputs("</body>\n"
			"</html>\n", fout);
		close_fout();
	}				/* else (svg == 1)
					 * 'fout' is closed in close_page */
	nbpages = tunenum = 0;
	defl = 0;
}

/* -- close the PS / SVG page -- */
void close_page(void)
{
	if (!in_page)
		return;
	in_page = 0;
	if (svg) {
		svg_close();
		if (svg == 1 && fout != stdout)
			close_fout();
		else
			fputs("</p>\n", fout);
	} else {
#if 1
		fprintf(fout, "grestore\n"
				"showpage\n"
				"%%%%EndPage: %d %d\n",
				nbpages, nbpages);
#else
		fputs("%%PageTrailer\n"
			"grestore\n"
			"showpage\n", fout);
#endif
	}
	cur_lmarg = 0;
	cur_scale = 1.0;
	outft = -1;
}

/* -- output a header/footer element -- */
static void format_hf(char *d, char *p)
{
	char *q;
	time_t ltime;

	for (;;) {
		if (*p == '\0')
			break;
		if ((q = strchr(p, '$')) != NULL)
			*q = '\0';
		d += sprintf(d, "%s", p);
		if (!q)
			break;
		p = q + 1;
		switch (*p) {
		case 'd':
			ltime = mtime;
			goto dput;
		case 'D':
			time(&ltime);
		dput:	cnv_date(&ltime);
			d += sprintf(d, "%s", tex_buf);
			break;
		case 'F':		/* ABC file name */
#if DIRSEP!='\\'
			d += sprintf(d, "%s", in_fname);
#else
			{
				int i;

				q = in_fname;
				i = TEX_BUF_SZ;
				for (;;) {
					if (--i <= 0 || *q == '\0')
						break;
					if ((*d++ = *q++) == '\\') {
						i--;
						*d++ = '\\';
					}
				}
				*d = '\0';
			}
#endif
			break;
		case 'I':		/* information field */
			p++;
			if (*p < 'A' || *p > 'Z' || !info[*p - 'A'])
				break;
			d += sprintf(d, "%s", &info[*p - 'A']->as.text[2]);
			break;
		case 'P':		/* page number */
			if (p[1] == '0') {
				p++;
				if (pagenum & 1)
					break;
			} else if (p[1] == '1') {
				p++;
				if ((pagenum & 1) == 0)
					break;
			}
			d += sprintf(d, "%d", pagenum);
			break;
		case 'T':		/* tune title */
			q = &info['T' - 'A']->as.text[2];
			tex_str(q);
			d += sprintf(d, "%s", tex_buf);
			break;
		case 'V':
			d += sprintf(d,"abcm2ps-"  VERSION);
			break;
		default:
			continue;
		}
		p++;
	}
	*d = '\0';		/* in case of empty string */
}

/* -- output the header or footer -- */
static float headfooter(int header,
			float pwidth,
			float pheight)
{
	char tmp[TEX_BUF_SZ], str[TEX_BUF_SZ + 1024];
	char *p, *q, *r, *mbf_sav;
	float size, y, wsize;
	struct FONTSPEC *f, f_sav;
	int cft_sav, dft_sav;

	if (header) {
		p = cfmt.header;
		f = &cfmt.font_tb[HEADERFONT];
		size = f->size;
		y = -size;
	} else {
		p = cfmt.footer;
		f = &cfmt.font_tb[FOOTERFONT];
		size = f->size;
		y = - (pheight - cfmt.topmargin - cfmt.botmargin)
			+ size;
	}
	if (*p == '-') {
		if (pagenum == 1)
			return 0;
		p++;
	}
	get_str_font(&cft_sav, &dft_sav);
	memcpy(&f_sav, &cfmt.font_tb[0], sizeof f_sav);
	str_font(f - cfmt.font_tb);
	output(fout, "%.1f F%d ", size, f->fnum);
	outft = f - cfmt.font_tb;

	/* may have 2 lines */
	wsize = size;
	if ((r = strstr(p, "\\n")) != NULL) {
		if (!header)
			y += size;
		wsize += size;
		*r = '\0';
	}
	mbf_sav = mbf;
	for (;;) {
		tex_str(p);
		strcpy(tmp, tex_buf);
		format_hf(str, tmp);

		/* left side */
		p = str;
		if ((q = strchr(p, '\t')) != NULL) {
			if (q != p) {
				*q = '\0';
				output(fout, "%.1f %.1f M ",
					p_fmt->leftmargin, y);
				str_out(p, A_LEFT);
				a2b("\n");
				mbf = mbf_sav;
				if (svg)
					svg_write(mbf, strlen(mbf));
				else
					fputs(mbf, fout);
			}
			p = q + 1;
		}
		if ((q = strchr(p, '\t')) != NULL)
			*q = '\0';

		/* center */
		if (q != p) {
			output(fout, "%.1f %.1f M ",
				pwidth * 0.5, y);
			str_out(p, A_CENTER);
			a2b("\n");
			mbf = mbf_sav;
			if (svg)
				svg_write(mbf, strlen(mbf));
			else
				fputs(mbf, fout);
		}

		/* right side */
		if (q) {
			p = q + 1;
			if (*p != '\0') {
				output(fout, "%.1f %.1f M ",
					pwidth - p_fmt->rightmargin, y);
				str_out(p, A_RIGHT);
				a2b("\n");
				mbf = mbf_sav;
				if (svg)
					svg_write(mbf, strlen(mbf));
				else
					fputs(mbf, fout);
			}
		}
		if (!r)
			break;
		*r = '\\';
		p = r + 2;
		r = NULL;
		y -= size;
	}

	/* restore the fonts */
	*mbf_sav = '\0';
	memcpy(&cfmt.font_tb[0], &f_sav, sizeof cfmt.font_tb[0]);
	set_str_font(cft_sav, dft_sav);
	return wsize;
}

/* -- initialize the first page or a new page for svg -- */
/* the flag 'in_page' is always false and epsf is always null */
static void init_page(void)
{
	float pheight, pwidth;

	p_fmt = !info['X' - 'A'] ? &cfmt : &dfmt;	/* global format */

	nbpages++;
	if (svg) {
		if (!file_initialized) {
			if (!fout)
				open_fout();
			define_svg_symbols(in_fname, nbpages,
				cfmt.landscape ? p_fmt->pageheight : p_fmt->pagewidth,
				cfmt.landscape ? p_fmt->pagewidth : p_fmt->pageheight);
			file_initialized = 1;
			output = svg_output;
		} else {
			define_svg_symbols(in_fname, nbpages,
				cfmt.landscape ? p_fmt->pageheight : p_fmt->pagewidth,
				cfmt.landscape ? p_fmt->pagewidth : p_fmt->pageheight);
		}
		user_ps_write();
	} else if (!file_initialized) {
		init_ps(in_fname);
	}
	in_page = 1;
	outft = -1;

	if (!svg)
		fprintf(fout, "%%%%Page: %d %d\n",
			nbpages, nbpages);
	if (cfmt.landscape) {
		pheight = p_fmt->pagewidth;
		pwidth = cfmt.pageheight;
		if (!svg)
			fprintf(fout, "%%%%PageOrientation: Landscape\n"
				"gsave 90 rotate 0 %.1f T\n",
				-cfmt.topmargin);
	} else {
		pheight = cfmt.pageheight;
		pwidth = p_fmt->pagewidth;
		if (!svg)
			fprintf(fout, "gsave 0 %.1f T\n",
				pheight - cfmt.topmargin);
	}
	if (svg)
		output(fout, "0 %.1f T\n", -cfmt.topmargin);
	else
		output(fout,
			"%% --- width %.1f\n",		/* for index */
			((cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth)
			 - cfmt.leftmargin - cfmt.rightmargin) / cfmt.scale);

	maxy = pheight - cfmt.topmargin - cfmt.botmargin;

	/* output the header and footer */
	if (!cfmt.header) {
		char *p = NULL;

		switch (pagenumbers) {
		case 1: p = "$P\t"; break;
		case 2: p = "\t\t$P"; break;
		case 3: p = "$P0\t\t$P1"; break;
		case 4: p = "$P1\t\t$P0"; break;
		}
		if (p)
			cfmt.header = strdup(p);
	}
	if (cfmt.header) {
		float dy;

		dy = headfooter(1, pwidth, pheight);
		if (dy != 0) {
			output(fout, "0 %.1f T\n", -dy);
			maxy -= dy;
		}
	}
	if (cfmt.footer)
		maxy -= headfooter(0, pwidth, pheight);
	pagenum++;
	outft = -1;
}

/* -- adjust the tune title part of the output file name -- */
static void epsf_fn_adj(char *p)
{
	char c;

	while ((c = *p) != '\0') {
		if (c == ' ')
			*p = '_';
		else if (c == DIRSEP || (unsigned) c >= 127)
			*p = '.';
		p++;
	}
}

/* -- build the title of the eps/svg file and check if correct utf-8 -- */
static void epsf_title(char *p, int sz)
{
	unsigned char c;

	snprintf(p, sz, "%.72s (%.4s)", in_fname, &info['X' - 'A']->as.text[2]);
	while ((c = (unsigned char) *p) != '\0') {
		if (c >= 0x80) {
			if ((c & 0xf8) == 0xf0) {
				if ((p[1] & 0xc0) != 0x80
				 && (p[2] & 0xc0) != 0x80
				 && (p[3] & 0xc0) != 0x80)
					*p = ' ';
			} else if ((c & 0xf0) == 0xe0) {
				if ((p[1] & 0xc0) != 0x80
				 && (p[2] & 0xc0) != 0x80)
					*p = ' ';
			} else if ((c & 0xe0) == 0xc0) {
				if ((p[1] & 0xc0) != 0x80)
					*p = ' ';
			} else {
				*p = ' ';
			}
		}
		p++;
	}
}

/* -- output a EPS (-E) or SVG (-g) file -- */
void write_eps(void)
{
	unsigned i;
	char *p, title[80];

	if (mbf == outbuf
	 || !info['X' - 'A'])
		return;

	p_fmt = &cfmt;				/* tune format */

	strcpy(outfnam, outfn);
	if (outfnam[0] == '\0')
		strcpy(outfnam, OUTPUTFILE);
	cutext(outfnam);
	i = strlen(outfnam) - 1;
	if (i == 0 && outfnam[0] == '-') {
		if (epsf == 1) {
			error(1, NULL, "Cannot use stdout with '-E' - abort");
			exit(EXIT_FAILURE);
		}
		fout = stdout;
	} else {
		if (outfnam[i] == '=') {
			p = &info['T' - 'A']->as.text[2];
			while (isspace((unsigned char) *p))
				p++;
			strncpy(&outfnam[i], p, sizeof outfnam - i - 4);
			outfnam[sizeof outfnam - 5] = '\0';
			epsf_fn_adj(&outfnam[i]);
		} else {
			if (i >= sizeof outfnam - 4 - 3)
				i = sizeof outfnam - 4 - 3;
			sprintf(&outfnam[i + 1], "%03d", ++nepsf);
		}
		strcat(outfnam, epsf == 1 ? ".eps" : ".svg");
		if ((fout = fopen(outfnam, "w")) == NULL) {
			error(1, NULL, "Cannot open output file %s - abort",
					outfnam);
			exit(EXIT_FAILURE);
		}
	}
	epsf_title(title, sizeof title);
	if (epsf == 1) {
		init_ps(title);
		fprintf(fout, "0 %.1f T\n", -bposy);
		write_buffer();
		fprintf(fout, "showpage\nrestore\n");
	} else {
		init_svg(title);
		write_buffer();
		svg_close();
	}
	close_fout();
	cur_lmarg = 0;
	cur_scale = 1.0;
}

/* -- start a new page -- */
/* epsf is always null */
static void newpage(void)
{
	close_page();
	init_page();
}

/*  subroutines to handle output buffer  */

/* -- update the output buffer pointer -- */
void a2b(char *fmt, ...)
{
	va_list args;

	if (mbf + BSIZE > outbuf + outbufsz) {
		if (epsf) {
			error(1, NULL, "Output buffer overflow - increase outbufsz");
			fprintf(stderr, "*** abort\n");
			exit(EXIT_FAILURE);
		}
		error(0, NULL, "Possible buffer overflow");
		write_buffer();
		use_buffer = 0;
	}
	va_start(args, fmt);
	mbf += vsnprintf(mbf, outbuf + outbufsz - mbf, fmt, args);
	va_end(args);
}

/* -- translate down by 'h' scaled points in output buffer -- */
void bskip(float h)
{
	bposy -= h * cfmt.scale;
	a2b("0 %.2f T\n", -h);
}

/* -- initialize the output buffer -- */
void init_outbuf(int kbsz)
{
	if (outbuf)
		free(outbuf);
	outbufsz = kbsz * 1024;
	if (outbufsz < 0x10000)
		outbufsz = 0x10000;
	outbuf = malloc(outbufsz);
	if (!outbuf) {
		error(1, NULL, "Out of memory for outbuf - abort");
		exit(EXIT_FAILURE);
	}
	bposy = 0;
	ln_num = 0;
	mbf = outbuf;
}

/* -- write buffer contents, break at full pages -- */
void write_buffer(void)
{
	char *p_buf;
	int l, np;
	float p1, dp;
	int outft_sav;

	if (mbf == outbuf || multicol_start != 0)
		return;
	if (!in_page && !epsf)
		init_page();
	outft_sav = outft;
	p1 = 0;
	p_buf = outbuf;
	for (l = 0; l < ln_num; l++) {
		if (ln_pos[l] > 0) {		/* if in multicol */
			int ll;
			float pos;

			for (ll = l + 1; ll < ln_num; ll++) {
				if (ln_pos[ll] <= 0) {
					pos = ln_pos[ll];
					while (--ll >= l)
						ln_pos[ll] = pos;
					break;
				}
			}
		}
		dp = ln_pos[l] - p1;
		np = maxy + dp < 0 && !epsf;
		if (np) {
			newpage();
			if (ln_font[l] >= 0) {
				struct FONTSPEC *f;

				f = &cfmt.font_tb[ln_font[l]];
				output(fout, "%.1f F%d\n",
					f->size, f->fnum);
			}
		}
		if (ln_scale[l] != cur_scale) {
			output(fout, "%.3f dup scale\n",
				ln_scale[l] / cur_scale);
			cur_scale = ln_scale[l];
		}
		if (ln_lmarg[l] != cur_lmarg) {
			output(fout, "%.2f 0 T\n",
				(ln_lmarg[l] - cur_lmarg) / cur_scale);
			cur_lmarg = ln_lmarg[l];
		}
		if (np) {
			output(fout, "0 %.2f T\n", -cfmt.topspace);
			maxy -= cfmt.topspace * cfmt.scale;
		}
		if (*p_buf != '\001') {
			if (epsf == 2 || svg)
				svg_write(p_buf, ln_buf[l] - p_buf);
			else
				fwrite(p_buf, 1, ln_buf[l] - p_buf, fout);
		} else {			/* %%EPS - see parse.c */
			FILE *f;
			char line[BSIZE], *p, *q;

			p = strchr(p_buf + 1, '\n');
			fwrite(p_buf + 1, 1, p - p_buf, fout);
			p_buf = p + 1;
			p = strchr(p_buf, '%');
			*p++ = '\0';
			q = strchr(p, '\n');
			*q = '\0';
			if ((f = fopen(p, "r")) == NULL) {
				error(1, NULL, "Cannot open EPS file '%s'", p);
			} else {
				if (epsf == 2 || svg) {
					fprintf(fout, "<!--Begin document %s-->\n",
							p);
					svg_output(fout, "gsave\n"
							"%s T\n",
							p_buf);
					while (fgets(line, sizeof line, f))	/* copy the file */
						svg_write(line, strlen(line));
					svg_output(fout, "grestore\n"
							"%s T\n",
							p_buf);
					fprintf(fout, "<!--End document %s-->\n",
							p);
				} else {
					fprintf(fout,
						"save\n"
						"/showpage{}def/setpagedevice{pop}def\n"
						"%s T\n"
						"%%%%BeginDocument: %s\n",
						p_buf, p);
					while (fgets(line, sizeof line, f))	/* copy the file */
						fwrite(line, 1, strlen(line), fout);
					fprintf(fout, "%%%%EndDocument\n"
							"restore\n");
				}
				fclose(f);
			}
		}
		p_buf = ln_buf[l];
		maxy += dp;
		p1 = ln_pos[l];
	}
#if 1 //fixme:test
	if (*p_buf != '\0')
		fprintf(stderr, "??? bug - buffer not empty:\n%s\n", p_buf);
#endif
	outft = outft_sav;
	bposy = 0;
	ln_num = 0;
	mbf = outbuf;
}

/* -- add a block in the output buffer -- */
void block_put(void)
{
	if (mbf == outbuf)
		return;
//fixme: should be done sooner and should be adjusted when cfmt change...
	if (maxy == 0)
		maxy = (cfmt.landscape ? cfmt.pagewidth : cfmt.pageheight)
			- cfmt.topmargin - cfmt.botmargin;
	if (ln_num > 0 && mbf == ln_buf[ln_num - 1])
		return;				/* no data */
	if (ln_num >= BUFFLN) {
		char c, *p;

		error(1, NULL, "max number of buffer lines exceeded"
				" -- check BUFFLN");
		multicol_start = 0;
		p = ln_buf[ln_num - 1];
		c = *p;				/* (avoid "buffer not empty") */
		*p = '\0';
		write_buffer();
		multicol_start = maxy + bposy;
		*p = c;
		strcpy(outbuf, p);
		use_buffer = 0;
	}
	ln_buf[ln_num] = mbf;
	ln_pos[ln_num] = multicol_start == 0 ? bposy : 1;
	ln_lmarg[ln_num] = cfmt.leftmargin;
	if (epsf) {
		if (cfmt.leftmargin < min_lmarg)
			min_lmarg = cfmt.leftmargin;
		if (cfmt.rightmargin < max_rmarg)
			max_rmarg = cfmt.rightmargin;
	}
	ln_scale[ln_num] = cfmt.scale;
	ln_font[ln_num] = outft;
	ln_num++;

	if (!use_buffer) {
		write_buffer();
		return;
	}
}

/* -- handle completed block in buffer -- */
/* if the added stuff does not fit on current page, write it out
   after page break and change buffer handling mode to pass though */
void buffer_eob(void)
{
	block_put();
	if (maxy + bposy < 0
	 && !epsf
	 && multicol_start == 0) {
		if (in_page)
			newpage();
		write_buffer();
		use_buffer = 0;
	}
}

/* -- dump buffer if not enough place for a music line -- */
void check_buffer(void)
{
	if (mbf + 5000 > outbuf + outbufsz) { /* assume music line < 5000 bytes */
		error(0, NULL,
		      "Possibly bad page breaks, outbufsz exceeded");
		write_buffer();
		use_buffer = 0;
	}
}

/* -- return the current vertical offset in the page -- */
float get_bposy(void)
{
	return maxy + bposy;
}
abcm2ps-7.8.13/chinese.abc0000644000175000017500000000514611700610745013327 0ustar  jefjef% abcm2ps sample file with chinese characters

% define the chinese utf-8 truetype font
%%font UKaiCN-UTF8-H native

% add the utf8 -> CID translator
%%beginps nosvg
/UKaiCN-UTF8-H /UniGB-UTF8-H [ /UKaiCN ] composefont pop
%%endps

% define some fonts
%%titlefont UKaiCN-UTF8-H native 20
%%subtitlefont UKaiCN-UTF8-H native 16
%%textfont UKaiCN-UTF8-H native 16
%%vocalfont UKaiCN-UTF8-H native 13
%%wordsfont UKaiCN-UTF8-H native 16

X: 1
T: Green Island Serenade
T: 绿岛小夜曲
T: 綠島小夜曲
T: Lǜ Dǎo Xiǎoyèqǔ
T: Зелёный Остров
T: جزيرة اخضرة
C: Chen Chang-shou
D: Vienna Teng "Warm Strangers"
M: 4/4
L: 1/8
K: D
A,2 \
| "D"A3 B "(F#m)"A2 F2 | "A7"E2 {FE}DE "Bm"F3 E \
| "G"DD2 B, "D"A,3 B, | "D"A,4 "(A7)"z4 \
| "G"B,3 A, B,2 D2 | "A7"E2 {FE}DE "D"F3 A \
| "Em"EE2 F "A7"A3 B | "D"A4 "(A7)"z4 |
| "G"BB2 A "D"F2 FE | "Bm"DE F[AD] "F#m"F4 \
| "Em"EE2 D "G"B,A, B,D | "A7"E4 z4 \
| "D"FF2 E "Bm"FA F2 | "Em"EF ED "G"B,4 \
| "D"A,A FE "A7"AB FE | "D"{E}D4 z4 |]
[|"G"B>B BA "D"F F3 | "Em"EE2 D "G"B,A, B,D | "A7"E4 z4 \
| "D"A>B AE "F#m"FF2 F | "Em"EE2 D "G"B,2 D2 | "D"A4 "A7"z3A |
| "D"A2 {BA}FA "G"B3 d | "D"AB AF "Em"E4 \
| "Bm"F2 ED "G"B,3 D | "A7"E2 {FE}DE "D"F3A \
| "G"B3 F "A7"E3 F/E/ | "D"D4 z2 |]
%
W: 这绿岛像一隻船在月夜里摇呀摇
W: 姑娘哟妳也在我的心海裡飘呀飘
W: 让我的歌声随那微风吹開了妳的窗簾
W: 让我的衷情随那流水不断的向妳倾诉
W:
W: 椰子树的长影掩不住我的情意
W: 明媚的月光更照亮了我的心
W: 这绿岛的夜已经这样沉静
W: 姑娘哟妳为什么还是默默无语
W:
W: zhè lǜ dǎo xiàng yī zhī chuàn, zài yué yè lǐ yáo ya yáo.
W: gū niang yo, nǐ ye zài wǒde xīn hǎi lǐ piao ya piao.
W: ràng wǒde ge sheng sui na wei feng, chui kai le nǐ de chuang lian.
W: ràng wǒde zhong qing sui na liu shui, bu duan de xiang nǐ qing su.
W:
W: ye zi shu de chang ying yan bu zhu wǒde qing yi;
W: mìng mèi de yuè guang geng zhao liang le wǒde xīn.
W: zhe lǜ dao de ye yi jing zhe yang de chen jing
W: gū niang ya, nǐ wei shen ma hai shì muò muò wú yǚ?
W:
W: This Green Island is like a boat, floating in the moonlight,
W: My darling, you too are floating in the sea of my heart,
W: Let the sound of my song follow the breeze, blowing open the curtain of your window,
W: Let my love follow the flowing water, endlessly pouring out its feelings for you.
W:
W: The long shadows of the palm trees cannot conceal my love,
W: The bright beauty of the moonlight casts its brilliance into my heart.
W: This Green Island night is so calm and serene,
W: My darling, why are you silent, saying nothing?
abcm2ps-7.8.13/configure0000755000175000017500000042143212461214442013150 0ustar  jefjef#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.68.
#
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
# Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
## -------------------- ##
## M4sh Initialization. ##
## -------------------- ##

# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
  emulate sh
  NULLCMD=:
  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
  # is contrary to our usage.  Disable this feature.
  alias -g '${1+"$@"}'='"$@"'
  setopt NO_GLOB_SUBST
else
  case `(set -o) 2>/dev/null` in #(
  *posix*) :
    set -o posix ;; #(
  *) :
     ;;
esac
fi


as_nl='
'
export as_nl
# Printing a long string crashes Solaris 7 /usr/bin/printf.
as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
# Prefer a ksh shell builtin over an external printf program on Solaris,
# but without wasting forks for bash or zsh.
if test -z "$BASH_VERSION$ZSH_VERSION" \
    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='print -r --'
  as_echo_n='print -rn --'
elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='printf %s\n'
  as_echo_n='printf %s'
else
  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
    as_echo_n='/usr/ucb/echo -n'
  else
    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
    as_echo_n_body='eval
      arg=$1;
      case $arg in #(
      *"$as_nl"*)
	expr "X$arg" : "X\\(.*\\)$as_nl";
	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
      esac;
      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
    '
    export as_echo_n_body
    as_echo_n='sh -c $as_echo_n_body as_echo'
  fi
  export as_echo_body
  as_echo='sh -c $as_echo_body as_echo'
fi

# The user is always right.
if test "${PATH_SEPARATOR+set}" != set; then
  PATH_SEPARATOR=:
  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
      PATH_SEPARATOR=';'
  }
fi


# IFS
# We need space, tab and new line, in precisely that order.  Quoting is
# there to prevent editors from complaining about space-tab.
# (If _AS_PATH_WALK were called with IFS unset, it would disable word
# splitting by setting IFS to empty value.)
IFS=" ""	$as_nl"

# Find who we are.  Look in the path if we contain no directory separator.
as_myself=
case $0 in #((
  *[\\/]* ) as_myself=$0 ;;
  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
  done
IFS=$as_save_IFS

     ;;
esac
# We did not find ourselves, most probably we were run as `sh COMMAND'
# in which case we are not to be found in the path.
if test "x$as_myself" = x; then
  as_myself=$0
fi
if test ! -f "$as_myself"; then
  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
  exit 1
fi

# Unset variables that we do not need and which cause bugs (e.g. in
# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
# suppresses any "Segmentation fault" message there.  '((' could
# trigger a bug in pdksh 5.2.14.
for as_var in BASH_ENV ENV MAIL MAILPATH
do eval test x\${$as_var+set} = xset \
  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
done
PS1='$ '
PS2='> '
PS4='+ '

# NLS nuisances.
LC_ALL=C
export LC_ALL
LANGUAGE=C
export LANGUAGE

# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH

if test "x$CONFIG_SHELL" = x; then
  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
  emulate sh
  NULLCMD=:
  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
  # is contrary to our usage.  Disable this feature.
  alias -g '\${1+\"\$@\"}'='\"\$@\"'
  setopt NO_GLOB_SUBST
else
  case \`(set -o) 2>/dev/null\` in #(
  *posix*) :
    set -o posix ;; #(
  *) :
     ;;
esac
fi
"
  as_required="as_fn_return () { (exit \$1); }
as_fn_success () { as_fn_return 0; }
as_fn_failure () { as_fn_return 1; }
as_fn_ret_success () { return 0; }
as_fn_ret_failure () { return 1; }

exitcode=0
as_fn_success || { exitcode=1; echo as_fn_success failed.; }
as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :

else
  exitcode=1; echo positional parameters were not saved.
fi
test x\$exitcode = x0 || exit 1"
  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
test \$(( 1 + 1 )) = 2 || exit 1"
  if (eval "$as_required") 2>/dev/null; then :
  as_have_required=yes
else
  as_have_required=no
fi
  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :

else
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
as_found=false
for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
  as_found=:
  case $as_dir in #(
	 /*)
	   for as_base in sh bash ksh sh5; do
	     # Try only shells that exist, to save several forks.
	     as_shell=$as_dir/$as_base
	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
  CONFIG_SHELL=$as_shell as_have_required=yes
		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
  break 2
fi
fi
	   done;;
       esac
  as_found=false
done
$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
  CONFIG_SHELL=$SHELL as_have_required=yes
fi; }
IFS=$as_save_IFS


      if test "x$CONFIG_SHELL" != x; then :
  # We cannot yet assume a decent shell, so we have to provide a
	# neutralization value for shells without unset; and this also
	# works around shells that cannot unset nonexistent variables.
	# Preserve -v and -x to the replacement shell.
	BASH_ENV=/dev/null
	ENV=/dev/null
	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
	export CONFIG_SHELL
	case $- in # ((((
	  *v*x* | *x*v* ) as_opts=-vx ;;
	  *v* ) as_opts=-v ;;
	  *x* ) as_opts=-x ;;
	  * ) as_opts= ;;
	esac
	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
fi

    if test x$as_have_required = xno; then :
  $as_echo "$0: This script requires a shell more modern than all"
  $as_echo "$0: the shells that I found on your system."
  if test x${ZSH_VERSION+set} = xset ; then
    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
  else
    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
$0: including any error possibly output before this
$0: message. Then install a modern shell, or manually run
$0: the script under such a shell if you do have one."
  fi
  exit 1
fi
fi
fi
SHELL=${CONFIG_SHELL-/bin/sh}
export SHELL
# Unset more variables known to interfere with behavior of common tools.
CLICOLOR_FORCE= GREP_OPTIONS=
unset CLICOLOR_FORCE GREP_OPTIONS

## --------------------- ##
## M4sh Shell Functions. ##
## --------------------- ##
# as_fn_unset VAR
# ---------------
# Portably unset VAR.
as_fn_unset ()
{
  { eval $1=; unset $1;}
}
as_unset=as_fn_unset

# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
as_fn_set_status ()
{
  return $1
} # as_fn_set_status

# as_fn_exit STATUS
# -----------------
# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
as_fn_exit ()
{
  set +e
  as_fn_set_status $1
  exit $1
} # as_fn_exit

# as_fn_mkdir_p
# -------------
# Create "$as_dir" as a directory, including parents if necessary.
as_fn_mkdir_p ()
{

  case $as_dir in #(
  -*) as_dir=./$as_dir;;
  esac
  test -d "$as_dir" || eval $as_mkdir_p || {
    as_dirs=
    while :; do
      case $as_dir in #(
      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
      *) as_qdir=$as_dir;;
      esac
      as_dirs="'$as_qdir' $as_dirs"
      as_dir=`$as_dirname -- "$as_dir" ||
$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$as_dir" : 'X\(//\)[^/]' \| \
	 X"$as_dir" : 'X\(//\)$' \| \
	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$as_dir" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
      test -d "$as_dir" && break
    done
    test -z "$as_dirs" || eval "mkdir $as_dirs"
  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"


} # as_fn_mkdir_p
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
  eval 'as_fn_append ()
  {
    eval $1+=\$2
  }'
else
  as_fn_append ()
  {
    eval $1=\$$1\$2
  }
fi # as_fn_append

# as_fn_arith ARG...
# ------------------
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
  eval 'as_fn_arith ()
  {
    as_val=$(( $* ))
  }'
else
  as_fn_arith ()
  {
    as_val=`expr "$@" || test $? -eq 1`
  }
fi # as_fn_arith


# as_fn_error STATUS ERROR [LINENO LOG_FD]
# ----------------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
# script with STATUS, using 1 if that was 0.
as_fn_error ()
{
  as_status=$1; test $as_status -eq 0 && as_status=1
  if test "$4"; then
    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
  fi
  $as_echo "$as_me: error: $2" >&2
  as_fn_exit $as_status
} # as_fn_error

if expr a : '\(a\)' >/dev/null 2>&1 &&
   test "X`expr 00001 : '.*\(...\)'`" = X001; then
  as_expr=expr
else
  as_expr=false
fi

if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
  as_basename=basename
else
  as_basename=false
fi

if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
  as_dirname=dirname
else
  as_dirname=false
fi

as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
	 X"$0" : 'X\(//\)$' \| \
	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X/"$0" |
    sed '/^.*\/\([^/][^/]*\)\/*$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`

# Avoid depending upon Character Ranges.
as_cr_letters='abcdefghijklmnopqrstuvwxyz'
as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits


  as_lineno_1=$LINENO as_lineno_1a=$LINENO
  as_lineno_2=$LINENO as_lineno_2a=$LINENO
  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
  sed -n '
    p
    /[$]LINENO/=
  ' <$as_myself |
    sed '
      s/[$]LINENO.*/&-/
      t lineno
      b
      :lineno
      N
      :loop
      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
      t loop
      s/-\n.*//
    ' >$as_me.lineno &&
  chmod +x "$as_me.lineno" ||
    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }

  # Don't try to exec as it changes $[0], causing all sort of problems
  # (the dirname of $[0] is not the place where we might find the
  # original and so on.  Autoconf is especially sensitive to this).
  . "./$as_me.lineno"
  # Exit status is that of the last command.
  exit
}

ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
  case `echo 'xy\c'` in
  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
  xy)  ECHO_C='\c';;
  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
       ECHO_T='	';;
  esac;;
*)
  ECHO_N='-n';;
esac

rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
  rm -f conf$$.dir/conf$$.file
else
  rm -f conf$$.dir
  mkdir conf$$.dir 2>/dev/null
fi
if (echo >conf$$.file) 2>/dev/null; then
  if ln -s conf$$.file conf$$ 2>/dev/null; then
    as_ln_s='ln -s'
    # ... but there are two gotchas:
    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
    # In both cases, we have to default to `cp -p'.
    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
      as_ln_s='cp -p'
  elif ln conf$$.file conf$$ 2>/dev/null; then
    as_ln_s=ln
  else
    as_ln_s='cp -p'
  fi
else
  as_ln_s='cp -p'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null

if mkdir -p . 2>/dev/null; then
  as_mkdir_p='mkdir -p "$as_dir"'
else
  test -d ./-p && rmdir ./-p
  as_mkdir_p=false
fi

if test -x / >/dev/null 2>&1; then
  as_test_x='test -x'
else
  if ls -dL / >/dev/null 2>&1; then
    as_ls_L_option=L
  else
    as_ls_L_option=
  fi
  as_test_x='
    eval sh -c '\''
      if test -d "$1"; then
	test -d "$1/.";
      else
	case $1 in #(
	-*)set "./$1";;
	esac;
	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
	???[sx]*):;;*)false;;esac;fi
    '\'' sh
  '
fi
as_executable_p=$as_test_x

# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"

# Sed expression to map a string onto a valid variable name.
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"


test -n "$DJDIR" || exec 7<&0 </dev/null
exec 6>&1

# Name of the host.
# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
# so uname gets run too.
ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`

#
# Initializations.
#
ac_default_prefix=/usr/local
ac_clean_files=
ac_config_libobj_dir=.
LIBOBJS=
cross_compiling=no
subdirs=
MFLAGS=
MAKEFLAGS=

# Identity of this package.
PACKAGE_NAME=
PACKAGE_TARNAME=
PACKAGE_VERSION=
PACKAGE_STRING=
PACKAGE_BUGREPORT=
PACKAGE_URL=

ac_unique_file="abc2ps.h"
# Factoring default headers for most tests.
ac_includes_default="\
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
#  include <stdlib.h>
# endif
#endif
#ifdef HAVE_STRING_H
# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
#  include <memory.h>
# endif
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif"

ac_subst_vars='LTLIBOBJS
LIBOBJS
CPPPANGO
VERSION
EGREP
GREP
CPP
INSTALL_DATA
INSTALL_SCRIPT
INSTALL_PROGRAM
OBJEXT
EXEEXT
ac_ct_CC
CPPFLAGS
LDFLAGS
CFLAGS
CC
target_os
target_vendor
target_cpu
target
host_os
host_vendor
host_cpu
host
build_os
build_vendor
build_cpu
build
target_alias
host_alias
build_alias
LIBS
ECHO_T
ECHO_N
ECHO_C
DEFS
mandir
localedir
libdir
psdir
pdfdir
dvidir
htmldir
infodir
docdir
oldincludedir
includedir
localstatedir
sharedstatedir
sysconfdir
datadir
datarootdir
libexecdir
sbindir
bindir
program_transform_name
prefix
exec_prefix
PACKAGE_URL
PACKAGE_BUGREPORT
PACKAGE_STRING
PACKAGE_VERSION
PACKAGE_TARNAME
PACKAGE_NAME
PATH_SEPARATOR
SHELL'
ac_subst_files=''
ac_user_opts='
enable_option_checking
enable_pango
enable_a4
enable_deco_is_roll
with_def_fdir
'
      ac_precious_vars='build_alias
host_alias
target_alias
CC
CFLAGS
LDFLAGS
LIBS
CPPFLAGS
CPP'


# Initialize some variables set by options.
ac_init_help=
ac_init_version=false
ac_unrecognized_opts=
ac_unrecognized_sep=
# The variables have the same names as the options, with
# dashes changed to underlines.
cache_file=/dev/null
exec_prefix=NONE
no_create=
no_recursion=
prefix=NONE
program_prefix=NONE
program_suffix=NONE
program_transform_name=s,x,x,
silent=
site=
srcdir=
verbose=
x_includes=NONE
x_libraries=NONE

# Installation directory options.
# These are left unexpanded so users can "make install exec_prefix=/foo"
# and all the variables that are supposed to be based on exec_prefix
# by default will actually change.
# Use braces instead of parens because sh, perl, etc. also accept them.
# (The list follows the same order as the GNU Coding Standards.)
bindir='${exec_prefix}/bin'
sbindir='${exec_prefix}/sbin'
libexecdir='${exec_prefix}/libexec'
datarootdir='${prefix}/share'
datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}'
infodir='${datarootdir}/info'
htmldir='${docdir}'
dvidir='${docdir}'
pdfdir='${docdir}'
psdir='${docdir}'
libdir='${exec_prefix}/lib'
localedir='${datarootdir}/locale'
mandir='${datarootdir}/man'

ac_prev=
ac_dashdash=
for ac_option
do
  # If the previous option needs an argument, assign it.
  if test -n "$ac_prev"; then
    eval $ac_prev=\$ac_option
    ac_prev=
    continue
  fi

  case $ac_option in
  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
  *=)   ac_optarg= ;;
  *)    ac_optarg=yes ;;
  esac

  # Accept the important Cygnus configure options, so we can diagnose typos.

  case $ac_dashdash$ac_option in
  --)
    ac_dashdash=yes ;;

  -bindir | --bindir | --bindi | --bind | --bin | --bi)
    ac_prev=bindir ;;
  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
    bindir=$ac_optarg ;;

  -build | --build | --buil | --bui | --bu)
    ac_prev=build_alias ;;
  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
    build_alias=$ac_optarg ;;

  -cache-file | --cache-file | --cache-fil | --cache-fi \
  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
    ac_prev=cache_file ;;
  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
    cache_file=$ac_optarg ;;

  --config-cache | -C)
    cache_file=config.cache ;;

  -datadir | --datadir | --datadi | --datad)
    ac_prev=datadir ;;
  -datadir=* | --datadir=* | --datadi=* | --datad=*)
    datadir=$ac_optarg ;;

  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
  | --dataroo | --dataro | --datar)
    ac_prev=datarootdir ;;
  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
    datarootdir=$ac_optarg ;;

  -disable-* | --disable-*)
    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
    # Reject names that are not valid shell variable names.
    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error $? "invalid feature name: $ac_useropt"
    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"enable_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval enable_$ac_useropt=no ;;

  -docdir | --docdir | --docdi | --doc | --do)
    ac_prev=docdir ;;
  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
    docdir=$ac_optarg ;;

  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
    ac_prev=dvidir ;;
  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
    dvidir=$ac_optarg ;;

  -enable-* | --enable-*)
    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
    # Reject names that are not valid shell variable names.
    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error $? "invalid feature name: $ac_useropt"
    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"enable_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval enable_$ac_useropt=\$ac_optarg ;;

  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
  | --exec | --exe | --ex)
    ac_prev=exec_prefix ;;
  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
  | --exec=* | --exe=* | --ex=*)
    exec_prefix=$ac_optarg ;;

  -gas | --gas | --ga | --g)
    # Obsolete; use --with-gas.
    with_gas=yes ;;

  -help | --help | --hel | --he | -h)
    ac_init_help=long ;;
  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
    ac_init_help=recursive ;;
  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
    ac_init_help=short ;;

  -host | --host | --hos | --ho)
    ac_prev=host_alias ;;
  -host=* | --host=* | --hos=* | --ho=*)
    host_alias=$ac_optarg ;;

  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
    ac_prev=htmldir ;;
  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
  | --ht=*)
    htmldir=$ac_optarg ;;

  -includedir | --includedir | --includedi | --included | --include \
  | --includ | --inclu | --incl | --inc)
    ac_prev=includedir ;;
  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
  | --includ=* | --inclu=* | --incl=* | --inc=*)
    includedir=$ac_optarg ;;

  -infodir | --infodir | --infodi | --infod | --info | --inf)
    ac_prev=infodir ;;
  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
    infodir=$ac_optarg ;;

  -libdir | --libdir | --libdi | --libd)
    ac_prev=libdir ;;
  -libdir=* | --libdir=* | --libdi=* | --libd=*)
    libdir=$ac_optarg ;;

  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
  | --libexe | --libex | --libe)
    ac_prev=libexecdir ;;
  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
  | --libexe=* | --libex=* | --libe=*)
    libexecdir=$ac_optarg ;;

  -localedir | --localedir | --localedi | --localed | --locale)
    ac_prev=localedir ;;
  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
    localedir=$ac_optarg ;;

  -localstatedir | --localstatedir | --localstatedi | --localstated \
  | --localstate | --localstat | --localsta | --localst | --locals)
    ac_prev=localstatedir ;;
  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
    localstatedir=$ac_optarg ;;

  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
    ac_prev=mandir ;;
  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
    mandir=$ac_optarg ;;

  -nfp | --nfp | --nf)
    # Obsolete; use --without-fp.
    with_fp=no ;;

  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
  | --no-cr | --no-c | -n)
    no_create=yes ;;

  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
    no_recursion=yes ;;

  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
  | --oldin | --oldi | --old | --ol | --o)
    ac_prev=oldincludedir ;;
  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
    oldincludedir=$ac_optarg ;;

  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
    ac_prev=prefix ;;
  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
    prefix=$ac_optarg ;;

  -program-prefix | --program-prefix | --program-prefi | --program-pref \
  | --program-pre | --program-pr | --program-p)
    ac_prev=program_prefix ;;
  -program-prefix=* | --program-prefix=* | --program-prefi=* \
  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
    program_prefix=$ac_optarg ;;

  -program-suffix | --program-suffix | --program-suffi | --program-suff \
  | --program-suf | --program-su | --program-s)
    ac_prev=program_suffix ;;
  -program-suffix=* | --program-suffix=* | --program-suffi=* \
  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
    program_suffix=$ac_optarg ;;

  -program-transform-name | --program-transform-name \
  | --program-transform-nam | --program-transform-na \
  | --program-transform-n | --program-transform- \
  | --program-transform | --program-transfor \
  | --program-transfo | --program-transf \
  | --program-trans | --program-tran \
  | --progr-tra | --program-tr | --program-t)
    ac_prev=program_transform_name ;;
  -program-transform-name=* | --program-transform-name=* \
  | --program-transform-nam=* | --program-transform-na=* \
  | --program-transform-n=* | --program-transform-=* \
  | --program-transform=* | --program-transfor=* \
  | --program-transfo=* | --program-transf=* \
  | --program-trans=* | --program-tran=* \
  | --progr-tra=* | --program-tr=* | --program-t=*)
    program_transform_name=$ac_optarg ;;

  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
    ac_prev=pdfdir ;;
  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
    pdfdir=$ac_optarg ;;

  -psdir | --psdir | --psdi | --psd | --ps)
    ac_prev=psdir ;;
  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
    psdir=$ac_optarg ;;

  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
  | -silent | --silent | --silen | --sile | --sil)
    silent=yes ;;

  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
    ac_prev=sbindir ;;
  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
  | --sbi=* | --sb=*)
    sbindir=$ac_optarg ;;

  -sharedstatedir | --sharedstatedir | --sharedstatedi \
  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
  | --sharedst | --shareds | --shared | --share | --shar \
  | --sha | --sh)
    ac_prev=sharedstatedir ;;
  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
  | --sha=* | --sh=*)
    sharedstatedir=$ac_optarg ;;

  -site | --site | --sit)
    ac_prev=site ;;
  -site=* | --site=* | --sit=*)
    site=$ac_optarg ;;

  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
    ac_prev=srcdir ;;
  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
    srcdir=$ac_optarg ;;

  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
  | --syscon | --sysco | --sysc | --sys | --sy)
    ac_prev=sysconfdir ;;
  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
    sysconfdir=$ac_optarg ;;

  -target | --target | --targe | --targ | --tar | --ta | --t)
    ac_prev=target_alias ;;
  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
    target_alias=$ac_optarg ;;

  -v | -verbose | --verbose | --verbos | --verbo | --verb)
    verbose=yes ;;

  -version | --version | --versio | --versi | --vers | -V)
    ac_init_version=: ;;

  -with-* | --with-*)
    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
    # Reject names that are not valid shell variable names.
    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error $? "invalid package name: $ac_useropt"
    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"with_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval with_$ac_useropt=\$ac_optarg ;;

  -without-* | --without-*)
    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
    # Reject names that are not valid shell variable names.
    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
      as_fn_error $? "invalid package name: $ac_useropt"
    ac_useropt_orig=$ac_useropt
    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
    case $ac_user_opts in
      *"
"with_$ac_useropt"
"*) ;;
      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
	 ac_unrecognized_sep=', ';;
    esac
    eval with_$ac_useropt=no ;;

  --x)
    # Obsolete; use --with-x.
    with_x=yes ;;

  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
  | --x-incl | --x-inc | --x-in | --x-i)
    ac_prev=x_includes ;;
  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
    x_includes=$ac_optarg ;;

  -x-libraries | --x-libraries | --x-librarie | --x-librari \
  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
    ac_prev=x_libraries ;;
  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
    x_libraries=$ac_optarg ;;

  -*) as_fn_error $? "unrecognized option: \`$ac_option'
Try \`$0 --help' for more information"
    ;;

  *=*)
    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
    # Reject names that are not valid shell variable names.
    case $ac_envvar in #(
      '' | [0-9]* | *[!_$as_cr_alnum]* )
      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
    esac
    eval $ac_envvar=\$ac_optarg
    export $ac_envvar ;;

  *)
    # FIXME: should be removed in autoconf 3.0.
    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
    ;;

  esac
done

if test -n "$ac_prev"; then
  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
  as_fn_error $? "missing argument to $ac_option"
fi

if test -n "$ac_unrecognized_opts"; then
  case $enable_option_checking in
    no) ;;
    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
  esac
fi

# Check all directory arguments for consistency.
for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
		datadir sysconfdir sharedstatedir localstatedir includedir \
		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
		libdir localedir mandir
do
  eval ac_val=\$$ac_var
  # Remove trailing slashes.
  case $ac_val in
    */ )
      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
      eval $ac_var=\$ac_val;;
  esac
  # Be sure to have absolute directory names.
  case $ac_val in
    [\\/$]* | ?:[\\/]* )  continue;;
    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
  esac
  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
done

# There might be people who depend on the old broken behavior: `$host'
# used to hold the argument of --host etc.
# FIXME: To remove some day.
build=$build_alias
host=$host_alias
target=$target_alias

# FIXME: To remove some day.
if test "x$host_alias" != x; then
  if test "x$build_alias" = x; then
    cross_compiling=maybe
    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
    If a cross compiler is detected then cross compile mode will be used" >&2
  elif test "x$build_alias" != "x$host_alias"; then
    cross_compiling=yes
  fi
fi

ac_tool_prefix=
test -n "$host_alias" && ac_tool_prefix=$host_alias-

test "$silent" = yes && exec 6>/dev/null


ac_pwd=`pwd` && test -n "$ac_pwd" &&
ac_ls_di=`ls -di .` &&
ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
  as_fn_error $? "working directory cannot be determined"
test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
  as_fn_error $? "pwd does not report name of working directory"


# Find the source files, if location was not specified.
if test -z "$srcdir"; then
  ac_srcdir_defaulted=yes
  # Try the directory containing this script, then the parent directory.
  ac_confdir=`$as_dirname -- "$as_myself" ||
$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$as_myself" : 'X\(//\)[^/]' \| \
	 X"$as_myself" : 'X\(//\)$' \| \
	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$as_myself" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
  srcdir=$ac_confdir
  if test ! -r "$srcdir/$ac_unique_file"; then
    srcdir=..
  fi
else
  ac_srcdir_defaulted=no
fi
if test ! -r "$srcdir/$ac_unique_file"; then
  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
fi
ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
ac_abs_confdir=`(
	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
	pwd)`
# When building in place, set srcdir=.
if test "$ac_abs_confdir" = "$ac_pwd"; then
  srcdir=.
fi
# Remove unnecessary trailing slashes from srcdir.
# Double slashes in file names in object file debugging info
# mess up M-x gdb in Emacs.
case $srcdir in
*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
esac
for ac_var in $ac_precious_vars; do
  eval ac_env_${ac_var}_set=\${${ac_var}+set}
  eval ac_env_${ac_var}_value=\$${ac_var}
  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
  eval ac_cv_env_${ac_var}_value=\$${ac_var}
done

#
# Report the --help message.
#
if test "$ac_init_help" = "long"; then
  # Omit some internal or obsolete options to make the list less imposing.
  # This message is too long to be a string in the A/UX 3.1 sh.
  cat <<_ACEOF
\`configure' configures this package to adapt to many kinds of systems.

Usage: $0 [OPTION]... [VAR=VALUE]...

To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE.  See below for descriptions of some of the useful variables.

Defaults for the options are specified in brackets.

Configuration:
  -h, --help              display this help and exit
      --help=short        display options specific to this package
      --help=recursive    display the short help of all the included packages
  -V, --version           display version information and exit
  -q, --quiet, --silent   do not print \`checking ...' messages
      --cache-file=FILE   cache test results in FILE [disabled]
  -C, --config-cache      alias for \`--cache-file=config.cache'
  -n, --no-create         do not create output files
      --srcdir=DIR        find the sources in DIR [configure dir or \`..']

Installation directories:
  --prefix=PREFIX         install architecture-independent files in PREFIX
                          [$ac_default_prefix]
  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
                          [PREFIX]

By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
an installation prefix other than \`$ac_default_prefix' using \`--prefix',
for instance \`--prefix=\$HOME'.

For better control, use the options below.

Fine tuning of the installation directories:
  --bindir=DIR            user executables [EPREFIX/bin]
  --sbindir=DIR           system admin executables [EPREFIX/sbin]
  --libexecdir=DIR        program executables [EPREFIX/libexec]
  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
  --libdir=DIR            object code libraries [EPREFIX/lib]
  --includedir=DIR        C header files [PREFIX/include]
  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
  --infodir=DIR           info documentation [DATAROOTDIR/info]
  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
  --mandir=DIR            man documentation [DATAROOTDIR/man]
  --docdir=DIR            documentation root [DATAROOTDIR/doc/PACKAGE]
  --htmldir=DIR           html documentation [DOCDIR]
  --dvidir=DIR            dvi documentation [DOCDIR]
  --pdfdir=DIR            pdf documentation [DOCDIR]
  --psdir=DIR             ps documentation [DOCDIR]
_ACEOF

  cat <<\_ACEOF

System types:
  --build=BUILD     configure for building on BUILD [guessed]
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
  --target=TARGET   configure for building compilers for TARGET [HOST]
_ACEOF
fi

if test -n "$ac_init_help"; then

  cat <<\_ACEOF

Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
  --enable-pango          Use pango if available [default: yes]
  --enable-a4             Handle european A4 format instead of default US letter
  --enable-deco-is-roll   Have ~ as roll instead of twiddle

Optional Packages:
  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
  --with-def-fdir=directory  Default format directory

Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags
  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
              nonstandard directory <lib dir>
  LIBS        libraries to pass to the linker, e.g. -l<library>
  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
              you have headers in a nonstandard directory <include dir>
  CPP         C preprocessor

Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.

Report bugs to the package provider.
_ACEOF
ac_status=$?
fi

if test "$ac_init_help" = "recursive"; then
  # If there are subdirs, report their specific --help.
  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
    test -d "$ac_dir" ||
      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
      continue
    ac_builddir=.

case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
  # A ".." for each directory in $ac_dir_suffix.
  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
  case $ac_top_builddir_sub in
  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
  esac ;;
esac
ac_abs_top_builddir=$ac_pwd
ac_abs_builddir=$ac_pwd$ac_dir_suffix
# for backward compatibility:
ac_top_builddir=$ac_top_build_prefix

case $srcdir in
  .)  # We are building in place.
    ac_srcdir=.
    ac_top_srcdir=$ac_top_builddir_sub
    ac_abs_top_srcdir=$ac_pwd ;;
  [\\/]* | ?:[\\/]* )  # Absolute name.
    ac_srcdir=$srcdir$ac_dir_suffix;
    ac_top_srcdir=$srcdir
    ac_abs_top_srcdir=$srcdir ;;
  *) # Relative name.
    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
    ac_top_srcdir=$ac_top_build_prefix$srcdir
    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix

    cd "$ac_dir" || { ac_status=$?; continue; }
    # Check for guested configure.
    if test -f "$ac_srcdir/configure.gnu"; then
      echo &&
      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
    elif test -f "$ac_srcdir/configure"; then
      echo &&
      $SHELL "$ac_srcdir/configure" --help=recursive
    else
      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
    fi || ac_status=$?
    cd "$ac_pwd" || { ac_status=$?; break; }
  done
fi

test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
  cat <<\_ACEOF
configure
generated by GNU Autoconf 2.68

Copyright (C) 2010 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
  exit
fi

## ------------------------ ##
## Autoconf initialization. ##
## ------------------------ ##

# ac_fn_c_try_compile LINENO
# --------------------------
# Try to compile conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_compile ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  rm -f conftest.$ac_objext
  if { { ac_try="$ac_compile"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compile") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    grep -v '^ *+' conftest.err >conftest.er1
    cat conftest.er1 >&5
    mv -f conftest.er1 conftest.err
  fi
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && {
	 test -z "$ac_c_werror_flag" ||
	 test ! -s conftest.err
       } && test -s conftest.$ac_objext; then :
  ac_retval=0
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

	ac_retval=1
fi
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
  as_fn_set_status $ac_retval

} # ac_fn_c_try_compile

# ac_fn_c_try_cpp LINENO
# ----------------------
# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_cpp ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  if { { ac_try="$ac_cpp conftest.$ac_ext"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    grep -v '^ *+' conftest.err >conftest.er1
    cat conftest.er1 >&5
    mv -f conftest.er1 conftest.err
  fi
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } > conftest.i && {
	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
	 test ! -s conftest.err
       }; then :
  ac_retval=0
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

    ac_retval=1
fi
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
  as_fn_set_status $ac_retval

} # ac_fn_c_try_cpp

# ac_fn_c_try_run LINENO
# ----------------------
# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
# that executables *can* be run.
ac_fn_c_try_run ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  if { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
  { { case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_try") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; }; then :
  ac_retval=0
else
  $as_echo "$as_me: program exited with status $ac_status" >&5
       $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

       ac_retval=$ac_status
fi
  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
  as_fn_set_status $ac_retval

} # ac_fn_c_try_run

# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists, giving a warning if it cannot be compiled using
# the include files in INCLUDES and setting the cache variable VAR
# accordingly.
ac_fn_c_check_header_mongrel ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  if eval \${$3+:} false; then :
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if eval \${$3+:} false; then :
  $as_echo_n "(cached) " >&6
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
else
  # Is the header compilable?
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
$as_echo_n "checking $2 usability... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_header_compiler=yes
else
  ac_header_compiler=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
$as_echo "$ac_header_compiler" >&6; }

# Is the header present?
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
$as_echo_n "checking $2 presence... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <$2>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
  ac_header_preproc=yes
else
  ac_header_preproc=no
fi
rm -f conftest.err conftest.i conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
$as_echo "$ac_header_preproc" >&6; }

# So?  What about this header?
case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
  yes:no: )
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
    ;;
  no:yes:* )
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
    ;;
esac
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if eval \${$3+:} false; then :
  $as_echo_n "(cached) " >&6
else
  eval "$3=\$ac_header_compiler"
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
fi
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_c_check_header_mongrel

# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
# -------------------------------------------------------
# Tests whether HEADER exists and can be compiled using the include files in
# INCLUDES, setting the cache variable VAR accordingly.
ac_fn_c_check_header_compile ()
{
  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
$as_echo_n "checking for $2... " >&6; }
if eval \${$3+:} false; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
$4
#include <$2>
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  eval "$3=yes"
else
  eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
eval ac_res=\$$3
	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno

} # ac_fn_c_check_header_compile
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by $as_me, which was
generated by GNU Autoconf 2.68.  Invocation command line was

  $ $0 $@

_ACEOF
exec 5>>config.log
{
cat <<_ASUNAME
## --------- ##
## Platform. ##
## --------- ##

hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
uname -m = `(uname -m) 2>/dev/null || echo unknown`
uname -r = `(uname -r) 2>/dev/null || echo unknown`
uname -s = `(uname -s) 2>/dev/null || echo unknown`
uname -v = `(uname -v) 2>/dev/null || echo unknown`

/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`

/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`

_ASUNAME

as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    $as_echo "PATH: $as_dir"
  done
IFS=$as_save_IFS

} >&5

cat >&5 <<_ACEOF


## ----------- ##
## Core tests. ##
## ----------- ##

_ACEOF


# Keep a trace of the command line.
# Strip out --no-create and --no-recursion so they do not pile up.
# Strip out --silent because we don't want to record it for future runs.
# Also quote any args containing shell meta-characters.
# Make two passes to allow for proper duplicate-argument suppression.
ac_configure_args=
ac_configure_args0=
ac_configure_args1=
ac_must_keep_next=false
for ac_pass in 1 2
do
  for ac_arg
  do
    case $ac_arg in
    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
    | -silent | --silent | --silen | --sile | --sil)
      continue ;;
    *\'*)
      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
    esac
    case $ac_pass in
    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
    2)
      as_fn_append ac_configure_args1 " '$ac_arg'"
      if test $ac_must_keep_next = true; then
	ac_must_keep_next=false # Got value, back to normal.
      else
	case $ac_arg in
	  *=* | --config-cache | -C | -disable-* | --disable-* \
	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
	  | -with-* | --with-* | -without-* | --without-* | --x)
	    case "$ac_configure_args0 " in
	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
	    esac
	    ;;
	  -* ) ac_must_keep_next=true ;;
	esac
      fi
      as_fn_append ac_configure_args " '$ac_arg'"
      ;;
    esac
  done
done
{ ac_configure_args0=; unset ac_configure_args0;}
{ ac_configure_args1=; unset ac_configure_args1;}

# When interrupted or exit'd, cleanup temporary files, and complete
# config.log.  We remove comments because anyway the quotes in there
# would cause problems or look ugly.
# WARNING: Use '\'' to represent an apostrophe within the trap.
# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
trap 'exit_status=$?
  # Save into config.log some information that might help in debugging.
  {
    echo

    $as_echo "## ---------------- ##
## Cache variables. ##
## ---------------- ##"
    echo
    # The following way of writing the cache mishandles newlines in values,
(
  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
    eval ac_val=\$$ac_var
    case $ac_val in #(
    *${as_nl}*)
      case $ac_var in #(
      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
      esac
      case $ac_var in #(
      _ | IFS | as_nl) ;; #(
      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
      *) { eval $ac_var=; unset $ac_var;} ;;
      esac ;;
    esac
  done
  (set) 2>&1 |
    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
    *${as_nl}ac_space=\ *)
      sed -n \
	"s/'\''/'\''\\\\'\'''\''/g;
	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
      ;; #(
    *)
      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
      ;;
    esac |
    sort
)
    echo

    $as_echo "## ----------------- ##
## Output variables. ##
## ----------------- ##"
    echo
    for ac_var in $ac_subst_vars
    do
      eval ac_val=\$$ac_var
      case $ac_val in
      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
      esac
      $as_echo "$ac_var='\''$ac_val'\''"
    done | sort
    echo

    if test -n "$ac_subst_files"; then
      $as_echo "## ------------------- ##
## File substitutions. ##
## ------------------- ##"
      echo
      for ac_var in $ac_subst_files
      do
	eval ac_val=\$$ac_var
	case $ac_val in
	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
	esac
	$as_echo "$ac_var='\''$ac_val'\''"
      done | sort
      echo
    fi

    if test -s confdefs.h; then
      $as_echo "## ----------- ##
## confdefs.h. ##
## ----------- ##"
      echo
      cat confdefs.h
      echo
    fi
    test "$ac_signal" != 0 &&
      $as_echo "$as_me: caught signal $ac_signal"
    $as_echo "$as_me: exit $exit_status"
  } >&5
  rm -f core *.core core.conftest.* &&
    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
    exit $exit_status
' 0
for ac_signal in 1 2 13 15; do
  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
done
ac_signal=0

# confdefs.h avoids OS command line length limits that DEFS can exceed.
rm -f -r conftest* confdefs.h

$as_echo "/* confdefs.h */" > confdefs.h

# Predefined preprocessor variables.

cat >>confdefs.h <<_ACEOF
#define PACKAGE_NAME "$PACKAGE_NAME"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_VERSION "$PACKAGE_VERSION"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_STRING "$PACKAGE_STRING"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define PACKAGE_URL "$PACKAGE_URL"
_ACEOF


# Let the site file select an alternate cache file if it wants to.
# Prefer an explicitly selected file to automatically selected ones.
ac_site_file1=NONE
ac_site_file2=NONE
if test -n "$CONFIG_SITE"; then
  # We do not want a PATH search for config.site.
  case $CONFIG_SITE in #((
    -*)  ac_site_file1=./$CONFIG_SITE;;
    */*) ac_site_file1=$CONFIG_SITE;;
    *)   ac_site_file1=./$CONFIG_SITE;;
  esac
elif test "x$prefix" != xNONE; then
  ac_site_file1=$prefix/share/config.site
  ac_site_file2=$prefix/etc/config.site
else
  ac_site_file1=$ac_default_prefix/share/config.site
  ac_site_file2=$ac_default_prefix/etc/config.site
fi
for ac_site_file in "$ac_site_file1" "$ac_site_file2"
do
  test "x$ac_site_file" = xNONE && continue
  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
$as_echo "$as_me: loading site script $ac_site_file" >&6;}
    sed 's/^/| /' "$ac_site_file" >&5
    . "$ac_site_file" \
      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "failed to load site script $ac_site_file
See \`config.log' for more details" "$LINENO" 5; }
  fi
done

if test -r "$cache_file"; then
  # Some versions of bash will fail to source /dev/null (special files
  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
$as_echo "$as_me: loading cache $cache_file" >&6;}
    case $cache_file in
      [\\/]* | ?:[\\/]* ) . "$cache_file";;
      *)                      . "./$cache_file";;
    esac
  fi
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
$as_echo "$as_me: creating cache $cache_file" >&6;}
  >$cache_file
fi

# Check that the precious variables saved in the cache have kept the same
# value.
ac_cache_corrupted=false
for ac_var in $ac_precious_vars; do
  eval ac_old_set=\$ac_cv_env_${ac_var}_set
  eval ac_new_set=\$ac_env_${ac_var}_set
  eval ac_old_val=\$ac_cv_env_${ac_var}_value
  eval ac_new_val=\$ac_env_${ac_var}_value
  case $ac_old_set,$ac_new_set in
    set,)
      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
      ac_cache_corrupted=: ;;
    ,set)
      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
      ac_cache_corrupted=: ;;
    ,);;
    *)
      if test "x$ac_old_val" != "x$ac_new_val"; then
	# differences in whitespace do not lead to failure.
	ac_old_val_w=`echo x $ac_old_val`
	ac_new_val_w=`echo x $ac_new_val`
	if test "$ac_old_val_w" != "$ac_new_val_w"; then
	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
	  ac_cache_corrupted=:
	else
	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
	  eval $ac_var=\$ac_old_val
	fi
	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
      fi;;
  esac
  # Pass precious variables to config.status.
  if test "$ac_new_set" = set; then
    case $ac_new_val in
    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
    *) ac_arg=$ac_var=$ac_new_val ;;
    esac
    case " $ac_configure_args " in
      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
    esac
  fi
done
if $ac_cache_corrupted; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
fi
## -------------------- ##
## Main body of script. ##
## -------------------- ##

ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu



VERSION=7.8.13
VDATE='January 25, 2015'

ac_aux_dir=
for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
  if test -f "$ac_dir/install-sh"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/install-sh -c"
    break
  elif test -f "$ac_dir/install.sh"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/install.sh -c"
    break
  elif test -f "$ac_dir/shtool"; then
    ac_aux_dir=$ac_dir
    ac_install_sh="$ac_aux_dir/shtool install -c"
    break
  fi
done
if test -z "$ac_aux_dir"; then
  as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
fi

# These three variables are undocumented and unsupported,
# and are intended to be withdrawn in a future Autoconf release.
# They can cause serious problems if a builder's source tree is in a directory
# whose full name contains unusual characters.
ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.


# Make sure we can run config.sub.
$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5

{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
$as_echo_n "checking build system type... " >&6; }
if ${ac_cv_build+:} false; then :
  $as_echo_n "(cached) " >&6
else
  ac_build_alias=$build_alias
test "x$ac_build_alias" = x &&
  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
test "x$ac_build_alias" = x &&
  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
$as_echo "$ac_cv_build" >&6; }
case $ac_cv_build in
*-*-*) ;;
*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
esac
build=$ac_cv_build
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_build
shift
build_cpu=$1
build_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
build_os=$*
IFS=$ac_save_IFS
case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
$as_echo_n "checking host system type... " >&6; }
if ${ac_cv_host+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test "x$host_alias" = x; then
  ac_cv_host=$ac_cv_build
else
  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
fi

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
$as_echo "$ac_cv_host" >&6; }
case $ac_cv_host in
*-*-*) ;;
*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
esac
host=$ac_cv_host
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_host
shift
host_cpu=$1
host_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
host_os=$*
IFS=$ac_save_IFS
case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
$as_echo_n "checking target system type... " >&6; }
if ${ac_cv_target+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test "x$target_alias" = x; then
  ac_cv_target=$ac_cv_host
else
  ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
fi

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
$as_echo "$ac_cv_target" >&6; }
case $ac_cv_target in
*-*-*) ;;
*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
esac
target=$ac_cv_target
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_target
shift
target_cpu=$1
target_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
target_os=$*
IFS=$ac_save_IFS
case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac


# The aliases save the names the user supplied, while $host etc.
# will get canonicalized.
test -n "$target_alias" &&
  test "$program_prefix$program_suffix$program_transform_name" = \
    NONENONEs,x,x, &&
  program_prefix=${target_alias}-


ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test -n "$ac_tool_prefix"; then
  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
set dummy ${ac_tool_prefix}gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_CC="${ac_tool_prefix}gcc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$ac_cv_prog_CC"; then
  ac_ct_CC=$CC
  # Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_ac_ct_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_CC"; then
  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_CC="gcc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
$as_echo "$ac_ct_CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi

  if test "x$ac_ct_CC" = x; then
    CC=""
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    CC=$ac_ct_CC
  fi
else
  CC="$ac_cv_prog_CC"
fi

if test -z "$CC"; then
          if test -n "$ac_tool_prefix"; then
    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_CC="${ac_tool_prefix}cc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  fi
fi
if test -z "$CC"; then
  # Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
  ac_prog_rejected=no
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
       ac_prog_rejected=yes
       continue
     fi
    ac_cv_prog_CC="cc"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

if test $ac_prog_rejected = yes; then
  # We found a bogon in the path, so make sure we never use it.
  set dummy $ac_cv_prog_CC
  shift
  if test $# != 0; then
    # We chose a different compiler from the bogus one.
    # However, it has the same basename, so the bogon will be chosen
    # first if we set CC to just the basename; use the full file name.
    shift
    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
  fi
fi
fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


fi
if test -z "$CC"; then
  if test -n "$ac_tool_prefix"; then
  for ac_prog in cl.exe
  do
    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$CC"; then
  ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


    test -n "$CC" && break
  done
fi
if test -z "$CC"; then
  ac_ct_CC=$CC
  for ac_prog in cl.exe
do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_ac_ct_CC+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -n "$ac_ct_CC"; then
  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_exec_ext in '' $ac_executable_extensions; do
  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
    ac_cv_prog_ac_ct_CC="$ac_prog"
    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
    break 2
  fi
done
  done
IFS=$as_save_IFS

fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
$as_echo "$ac_ct_CC" >&6; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


  test -n "$ac_ct_CC" && break
done

  if test "x$ac_ct_CC" = x; then
    CC=""
  else
    case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
    CC=$ac_ct_CC
  fi
fi

fi


test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "no acceptable C compiler found in \$PATH
See \`config.log' for more details" "$LINENO" 5; }

# Provide some information about the compiler.
$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
set X $ac_compile
ac_compiler=$2
for ac_option in --version -v -V -qversion; do
  { { ac_try="$ac_compiler $ac_option >&5"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
  ac_status=$?
  if test -s conftest.err; then
    sed '10a\
... rest of stderr output deleted ...
         10q' conftest.err >conftest.er1
    cat conftest.er1 >&5
  fi
  rm -f conftest.er1 conftest.err
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }
done

cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
# Try to create an executable without -o first, disregard a.out.
# It will help us diagnose broken compilers, and finding out an intuition
# of exeext.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
$as_echo_n "checking whether the C compiler works... " >&6; }
ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`

# The possible output files:
ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"

ac_rmfiles=
for ac_file in $ac_files
do
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
  esac
done
rm -f $ac_rmfiles

if { { ac_try="$ac_link_default"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link_default") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then :
  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
# in a Makefile.  We should not override ac_cv_exeext if it was cached,
# so that the user can short-circuit this test for compilers unknown to
# Autoconf.
for ac_file in $ac_files ''
do
  test -f "$ac_file" || continue
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
	;;
    [ab].out )
	# We found the default executable, but exeext='' is most
	# certainly right.
	break;;
    *.* )
	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
	then :; else
	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
	fi
	# We set ac_cv_exeext here because the later test for it is not
	# safe: cross compilers may not add the suffix if given an `-o'
	# argument, so we may need to know it at that point already.
	# Even if this section looks crufty: it has the advantage of
	# actually working.
	break;;
    * )
	break;;
  esac
done
test "$ac_cv_exeext" = no && ac_cv_exeext=

else
  ac_file=''
fi
if test -z "$ac_file"; then :
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
$as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "C compiler cannot create executables
See \`config.log' for more details" "$LINENO" 5; }
else
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
$as_echo_n "checking for C compiler default output file name... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
$as_echo "$ac_file" >&6; }
ac_exeext=$ac_cv_exeext

rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
ac_clean_files=$ac_clean_files_save
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
$as_echo_n "checking for suffix of executables... " >&6; }
if { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then :
  # If both `conftest.exe' and `conftest' are `present' (well, observable)
# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
# work properly (i.e., refer to `conftest.exe'), while it won't with
# `rm'.
for ac_file in conftest.exe conftest conftest.*; do
  test -f "$ac_file" || continue
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
	  break;;
    * ) break;;
  esac
done
else
  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot compute suffix of executables: cannot compile and link
See \`config.log' for more details" "$LINENO" 5; }
fi
rm -f conftest conftest$ac_cv_exeext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
$as_echo "$ac_cv_exeext" >&6; }

rm -f conftest.$ac_ext
EXEEXT=$ac_cv_exeext
ac_exeext=$EXEEXT
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <stdio.h>
int
main ()
{
FILE *f = fopen ("conftest.out", "w");
 return ferror (f) || fclose (f) != 0;

  ;
  return 0;
}
_ACEOF
ac_clean_files="$ac_clean_files conftest.out"
# Check that the compiler produces executables we can run.  If not, either
# the compiler is broken, or we cross compile.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
$as_echo_n "checking whether we are cross compiling... " >&6; }
if test "$cross_compiling" != yes; then
  { { ac_try="$ac_link"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_link") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }
  if { ac_try='./conftest$ac_cv_exeext'
  { { case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_try") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; }; then
    cross_compiling=no
  else
    if test "$cross_compiling" = maybe; then
	cross_compiling=yes
    else
	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot run C compiled programs.
If you meant to cross compile, use \`--host'.
See \`config.log' for more details" "$LINENO" 5; }
    fi
  fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
$as_echo "$cross_compiling" >&6; }

rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
ac_clean_files=$ac_clean_files_save
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
$as_echo_n "checking for suffix of object files... " >&6; }
if ${ac_cv_objext+:} false; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
rm -f conftest.o conftest.obj
if { { ac_try="$ac_compile"
case "(($ac_try" in
  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
  *) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
  (eval "$ac_compile") 2>&5
  ac_status=$?
  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
  test $ac_status = 0; }; then :
  for ac_file in conftest.o conftest.obj conftest.*; do
  test -f "$ac_file" || continue;
  case $ac_file in
    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
       break;;
  esac
done
else
  $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot compute suffix of object files: cannot compile
See \`config.log' for more details" "$LINENO" 5; }
fi
rm -f conftest.$ac_cv_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
$as_echo "$ac_cv_objext" >&6; }
OBJEXT=$ac_cv_objext
ac_objext=$OBJEXT
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
if ${ac_cv_c_compiler_gnu+:} false; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{
#ifndef __GNUC__
       choke me
#endif

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_compiler_gnu=yes
else
  ac_compiler_gnu=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_cv_c_compiler_gnu=$ac_compiler_gnu

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
$as_echo "$ac_cv_c_compiler_gnu" >&6; }
if test $ac_compiler_gnu = yes; then
  GCC=yes
else
  GCC=
fi
ac_test_CFLAGS=${CFLAGS+set}
ac_save_CFLAGS=$CFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
$as_echo_n "checking whether $CC accepts -g... " >&6; }
if ${ac_cv_prog_cc_g+:} false; then :
  $as_echo_n "(cached) " >&6
else
  ac_save_c_werror_flag=$ac_c_werror_flag
   ac_c_werror_flag=yes
   ac_cv_prog_cc_g=no
   CFLAGS="-g"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_prog_cc_g=yes
else
  CFLAGS=""
      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :

else
  ac_c_werror_flag=$ac_save_c_werror_flag
	 CFLAGS="-g"
	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_prog_cc_g=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
   ac_c_werror_flag=$ac_save_c_werror_flag
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
$as_echo "$ac_cv_prog_cc_g" >&6; }
if test "$ac_test_CFLAGS" = set; then
  CFLAGS=$ac_save_CFLAGS
elif test $ac_cv_prog_cc_g = yes; then
  if test "$GCC" = yes; then
    CFLAGS="-g -O2"
  else
    CFLAGS="-g"
  fi
else
  if test "$GCC" = yes; then
    CFLAGS="-O2"
  else
    CFLAGS=
  fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
if ${ac_cv_prog_cc_c89+:} false; then :
  $as_echo_n "(cached) " >&6
else
  ac_cv_prog_cc_c89=no
ac_save_CC=$CC
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
struct buf { int x; };
FILE * (*rcsopen) (struct buf *, struct stat *, int);
static char *e (p, i)
     char **p;
     int i;
{
  return p[i];
}
static char *f (char * (*g) (char **, int), char **p, ...)
{
  char *s;
  va_list v;
  va_start (v,p);
  s = g (p, va_arg (v,int));
  va_end (v);
  return s;
}

/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
   function prototypes and stuff, but not '\xHH' hex character constants.
   These don't provoke an error unfortunately, instead are silently treated
   as 'x'.  The following induces an error, until -std is added to get
   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
   array size at least.  It's necessary to write '\x00'==0 to get something
   that's true only with -std.  */
int osf4_cc_array ['\x00' == 0 ? 1 : -1];

/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
   inside strings and character constants.  */
#define FOO(x) 'x'
int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];

int test (int i, double x);
struct s1 {int (*f) (int a);};
struct s2 {int (*f) (double a);};
int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
int argc;
char **argv;
int
main ()
{
return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
  ;
  return 0;
}
_ACEOF
for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
do
  CC="$ac_save_CC $ac_arg"
  if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_prog_cc_c89=$ac_arg
fi
rm -f core conftest.err conftest.$ac_objext
  test "x$ac_cv_prog_cc_c89" != "xno" && break
done
rm -f conftest.$ac_ext
CC=$ac_save_CC

fi
# AC_CACHE_VAL
case "x$ac_cv_prog_cc_c89" in
  x)
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
$as_echo "none needed" >&6; } ;;
  xno)
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
$as_echo "unsupported" >&6; } ;;
  *)
    CC="$CC $ac_cv_prog_cc_c89"
    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
esac
if test "x$ac_cv_prog_cc_c89" != xno; then :

fi

ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu

# Find a good install program.  We prefer a C program (faster),
# so one script is as good as another.  But avoid the broken or
# incompatible versions:
# SysV /etc/install, /usr/sbin/install
# SunOS /usr/etc/install
# IRIX /sbin/install
# AIX /bin/install
# AmigaOS /C/install, which installs bootblocks on floppy discs
# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
# AFS /usr/afsws/bin/install, which mishandles nonexistent args
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# OS/2's system install, which has a completely different semantic
# ./install, which can be erroneously created by make from ./install.sh.
# Reject install programs that cannot install multiple files.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
$as_echo_n "checking for a BSD-compatible install... " >&6; }
if test -z "$INSTALL"; then
if ${ac_cv_path_install+:} false; then :
  $as_echo_n "(cached) " >&6
else
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    # Account for people who put trailing slashes in PATH elements.
case $as_dir/ in #((
  ./ | .// | /[cC]/* | \
  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
  /usr/ucb/* ) ;;
  *)
    # OSF1 and SCO ODT 3.0 have their own names for install.
    # Don't use installbsd from OSF since it installs stuff as root
    # by default.
    for ac_prog in ginstall scoinst install; do
      for ac_exec_ext in '' $ac_executable_extensions; do
	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
	  if test $ac_prog = install &&
	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
	    # AIX install.  It has an incompatible calling convention.
	    :
	  elif test $ac_prog = install &&
	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
	    # program-specific install script used by HP pwplus--don't use.
	    :
	  else
	    rm -rf conftest.one conftest.two conftest.dir
	    echo one > conftest.one
	    echo two > conftest.two
	    mkdir conftest.dir
	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
	      test -s conftest.one && test -s conftest.two &&
	      test -s conftest.dir/conftest.one &&
	      test -s conftest.dir/conftest.two
	    then
	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
	      break 3
	    fi
	  fi
	fi
      done
    done
    ;;
esac

  done
IFS=$as_save_IFS

rm -rf conftest.one conftest.two conftest.dir

fi
  if test "${ac_cv_path_install+set}" = set; then
    INSTALL=$ac_cv_path_install
  else
    # As a last resort, use the slow shell script.  Don't cache a
    # value for INSTALL within a source directory, because that will
    # break other packages using the cache if that directory is
    # removed, or if the value is a relative name.
    INSTALL=$ac_install_sh
  fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
$as_echo "$INSTALL" >&6; }

# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
# It thinks the first close brace ends the variable substitution.
test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'

test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'

test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'


ac_config_headers="$ac_config_headers config.h"



ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
$as_echo_n "checking how to run the C preprocessor... " >&6; }
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
  CPP=
fi
if test -z "$CPP"; then
  if ${ac_cv_prog_CPP+:} false; then :
  $as_echo_n "(cached) " >&6
else
      # Double quotes because CPP needs to be expanded
    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
    do
      ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
  # Use a header file that comes with gcc, so configuring glibc
  # with a fresh cross-compiler works.
  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
  # <limits.h> exists even on freestanding compilers.
  # On the NeXT, cc -E runs the code through the compiler's parser,
  # not just through cpp. "Syntax error" is here to catch this case.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
		     Syntax error
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :

else
  # Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.i conftest.$ac_ext

  # OK, works on sane cases.  Now check whether nonexistent headers
  # can be detected and how.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <ac_nonexistent.h>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
  # Broken: success on invalid input.
continue
else
  # Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.i conftest.$ac_ext

done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.i conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :
  break
fi

    done
    ac_cv_prog_CPP=$CPP

fi
  CPP=$ac_cv_prog_CPP
else
  ac_cv_prog_CPP=$CPP
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
$as_echo "$CPP" >&6; }
ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
  # Use a header file that comes with gcc, so configuring glibc
  # with a fresh cross-compiler works.
  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
  # <limits.h> exists even on freestanding compilers.
  # On the NeXT, cc -E runs the code through the compiler's parser,
  # not just through cpp. "Syntax error" is here to catch this case.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
		     Syntax error
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :

else
  # Broken: fails on valid input.
continue
fi
rm -f conftest.err conftest.i conftest.$ac_ext

  # OK, works on sane cases.  Now check whether nonexistent headers
  # can be detected and how.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <ac_nonexistent.h>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
  # Broken: success on invalid input.
continue
else
  # Passes both tests.
ac_preproc_ok=:
break
fi
rm -f conftest.err conftest.i conftest.$ac_ext

done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.i conftest.err conftest.$ac_ext
if $ac_preproc_ok; then :

else
  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
See \`config.log' for more details" "$LINENO" 5; }
fi

ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
if ${ac_cv_path_GREP+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if test -z "$GREP"; then
  ac_path_GREP_found=false
  # Loop through the user's path and test for each of PROGNAME-LIST
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_prog in grep ggrep; do
    for ac_exec_ext in '' $ac_executable_extensions; do
      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
# Check for GNU ac_path_GREP and select it if it is found.
  # Check for GNU $ac_path_GREP
case `"$ac_path_GREP" --version 2>&1` in
*GNU*)
  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
*)
  ac_count=0
  $as_echo_n 0123456789 >"conftest.in"
  while :
  do
    cat "conftest.in" "conftest.in" >"conftest.tmp"
    mv "conftest.tmp" "conftest.in"
    cp "conftest.in" "conftest.nl"
    $as_echo 'GREP' >> "conftest.nl"
    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
    as_fn_arith $ac_count + 1 && ac_count=$as_val
    if test $ac_count -gt ${ac_path_GREP_max-0}; then
      # Best one so far, save it but keep looking for a better one
      ac_cv_path_GREP="$ac_path_GREP"
      ac_path_GREP_max=$ac_count
    fi
    # 10*(2^10) chars as input seems more than enough
    test $ac_count -gt 10 && break
  done
  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac

      $ac_path_GREP_found && break 3
    done
  done
  done
IFS=$as_save_IFS
  if test -z "$ac_cv_path_GREP"; then
    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
  fi
else
  ac_cv_path_GREP=$GREP
fi

fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
$as_echo "$ac_cv_path_GREP" >&6; }
 GREP="$ac_cv_path_GREP"


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
$as_echo_n "checking for egrep... " >&6; }
if ${ac_cv_path_EGREP+:} false; then :
  $as_echo_n "(cached) " >&6
else
  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
   then ac_cv_path_EGREP="$GREP -E"
   else
     if test -z "$EGREP"; then
  ac_path_EGREP_found=false
  # Loop through the user's path and test for each of PROGNAME-LIST
  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    for ac_prog in egrep; do
    for ac_exec_ext in '' $ac_executable_extensions; do
      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
# Check for GNU ac_path_EGREP and select it if it is found.
  # Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in
*GNU*)
  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
*)
  ac_count=0
  $as_echo_n 0123456789 >"conftest.in"
  while :
  do
    cat "conftest.in" "conftest.in" >"conftest.tmp"
    mv "conftest.tmp" "conftest.in"
    cp "conftest.in" "conftest.nl"
    $as_echo 'EGREP' >> "conftest.nl"
    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
    as_fn_arith $ac_count + 1 && ac_count=$as_val
    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
      # Best one so far, save it but keep looking for a better one
      ac_cv_path_EGREP="$ac_path_EGREP"
      ac_path_EGREP_max=$ac_count
    fi
    # 10*(2^10) chars as input seems more than enough
    test $ac_count -gt 10 && break
  done
  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac

      $ac_path_EGREP_found && break 3
    done
  done
  done
IFS=$as_save_IFS
  if test -z "$ac_cv_path_EGREP"; then
    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
  fi
else
  ac_cv_path_EGREP=$EGREP
fi

   fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
$as_echo "$ac_cv_path_EGREP" >&6; }
 EGREP="$ac_cv_path_EGREP"


{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
$as_echo_n "checking for ANSI C header files... " >&6; }
if ${ac_cv_header_stdc+:} false; then :
  $as_echo_n "(cached) " >&6
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>

int
main ()
{

  ;
  return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
  ac_cv_header_stdc=yes
else
  ac_cv_header_stdc=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext

if test $ac_cv_header_stdc = yes; then
  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <string.h>

_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
  $EGREP "memchr" >/dev/null 2>&1; then :

else
  ac_cv_header_stdc=no
fi
rm -f conftest*

fi

if test $ac_cv_header_stdc = yes; then
  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <stdlib.h>

_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
  $EGREP "free" >/dev/null 2>&1; then :

else
  ac_cv_header_stdc=no
fi
rm -f conftest*

fi

if test $ac_cv_header_stdc = yes; then
  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
  if test "$cross_compiling" = yes; then :
  :
else
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */
#include <ctype.h>
#include <stdlib.h>
#if ((' ' & 0x0FF) == 0x020)
# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
#else
# define ISLOWER(c) \
		   (('a' <= (c) && (c) <= 'i') \
		     || ('j' <= (c) && (c) <= 'r') \
		     || ('s' <= (c) && (c) <= 'z'))
# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
#endif

#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
int
main ()
{
  int i;
  for (i = 0; i < 256; i++)
    if (XOR (islower (i), ISLOWER (i))
	|| toupper (i) != TOUPPER (i))
      return 2;
  return 0;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :

else
  ac_cv_header_stdc=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
  conftest.$ac_objext conftest.beam conftest.$ac_ext
fi

fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
$as_echo "$ac_cv_header_stdc" >&6; }
if test $ac_cv_header_stdc = yes; then

$as_echo "#define STDC_HEADERS 1" >>confdefs.h

fi

# On IRIX 5.3, sys/types and inttypes.h are conflicting.
for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
		  inttypes.h stdint.h unistd.h
do :
  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
"
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
  cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF

fi

done


for ac_header in malloc.h
do :
  ac_fn_c_check_header_mongrel "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default"
if test "x$ac_cv_header_malloc_h" = xyes; then :
  cat >>confdefs.h <<_ACEOF
#define HAVE_MALLOC_H 1
_ACEOF

fi

done


if test "X$GCC" = "Xyes" ; then
	CFLAGS="$CFLAGS -Wall -pipe"
fi

test "x$prefix" = xNONE && prefix=$ac_default_prefix


# Check whether --enable-pango was given.
if test "${enable_pango+set}" = set; then :
  enableval=$enable_pango; checkpango="$enableval"
else
  checkpango="yes"
fi


if test "$checkpango" = "yes"; then
$as_echo_n "checking for pango... " >&6
if which pkg-config > /dev/null ; then

	if pkg-config --exists freetype2 ; then
		if pkg-config --exists pangocairo ; then
			$as_echo "yes" >&6
			CPPFLAGS="$CPPFLAGS -DHAVE_PANGO=1"
			CPPPANGO="`pkg-config pango cairo freetype2 --cflags`"
			LDFLAGS="$LDFLAGS `pkg-config pangocairo pangoft2 freetype2 --libs`"
		else
			$as_echo "no" >&6
		fi
	else
		$as_echo "pangocairo not found" >&6
	fi
else
	$as_echo "pkg-config not found" >&6
fi
fi

# Check whether --enable-a4 was given.
if test "${enable_a4+set}" = set; then :
  enableval=$enable_a4; if test "$enableval" = "yes"; then
  $as_echo "#define A4_FORMAT 1" >>confdefs.h
fi
fi


# Check whether --enable-deco-is-roll was given.
if test "${enable_deco_is_roll+set}" = set; then :
  enableval=$enable_deco_is_roll; if test "$enableval" = "yes"; then
  $as_echo "#define DECO_IS_ROLL 1" >>confdefs.h
fi
fi


DEFAULT_FDIR="$prefix/share/abcm2ps"

# Check whether --with-def-fdir was given.
if test "${with_def_fdir+set}" = set; then :
  withval=$with_def_fdir; DEFAULT_FDIR="$withval"
fi





cat >>confdefs.h <<_ACEOF
#define VERSION "$VERSION"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define VDATE "$VDATE"
_ACEOF

cat >>confdefs.h <<_ACEOF
#define DEFAULT_FDIR "$DEFAULT_FDIR"
_ACEOF


ac_config_files="$ac_config_files Makefile"

cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
# scripts and configure runs, see configure's option --config-cache.
# It is not useful on other systems.  If it contains results you don't
# want to keep, you may remove or edit it.
#
# config.status only pays attention to the cache file if you give it
# the --recheck option to rerun configure.
#
# `ac_cv_env_foo' variables (set or unset) will be overridden when
# loading this file, other *unset* `ac_cv_foo' will be assigned the
# following values.

_ACEOF

# The following way of writing the cache mishandles newlines in values,
# but we know of no workaround that is simple, portable, and efficient.
# So, we kill variables containing newlines.
# Ultrix sh set writes to stderr and can't be redirected directly,
# and sets the high bit in the cache file unless we assign to the vars.
(
  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
    eval ac_val=\$$ac_var
    case $ac_val in #(
    *${as_nl}*)
      case $ac_var in #(
      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
      esac
      case $ac_var in #(
      _ | IFS | as_nl) ;; #(
      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
      *) { eval $ac_var=; unset $ac_var;} ;;
      esac ;;
    esac
  done

  (set) 2>&1 |
    case $as_nl`(ac_space=' '; set) 2>&1` in #(
    *${as_nl}ac_space=\ *)
      # `set' does not quote correctly, so add quotes: double-quote
      # substitution turns \\\\ into \\, and sed turns \\ into \.
      sed -n \
	"s/'/'\\\\''/g;
	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
      ;; #(
    *)
      # `set' quotes correctly as required by POSIX, so do not add quotes.
      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
      ;;
    esac |
    sort
) |
  sed '
     /^ac_cv_env_/b end
     t clear
     :clear
     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
     t end
     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
     :end' >>confcache
if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
  if test -w "$cache_file"; then
    if test "x$cache_file" != "x/dev/null"; then
      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
$as_echo "$as_me: updating cache $cache_file" >&6;}
      if test ! -f "$cache_file" || test -h "$cache_file"; then
	cat confcache >"$cache_file"
      else
        case $cache_file in #(
        */* | ?:*)
	  mv -f confcache "$cache_file"$$ &&
	  mv -f "$cache_file"$$ "$cache_file" ;; #(
        *)
	  mv -f confcache "$cache_file" ;;
	esac
      fi
    fi
  else
    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
  fi
fi
rm -f confcache

test "x$prefix" = xNONE && prefix=$ac_default_prefix
# Let make expand exec_prefix.
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'

DEFS=-DHAVE_CONFIG_H

ac_libobjs=
ac_ltlibobjs=
U=
for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
  # 1. Remove the extension, and $U if already installed.
  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
  #    will be set to the directory where LIBOBJS objects are built.
  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
done
LIBOBJS=$ac_libobjs

LTLIBOBJS=$ac_ltlibobjs



: "${CONFIG_STATUS=./config.status}"
ac_write_fail=0
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
as_write_fail=0
cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
#! $SHELL
# Generated by $as_me.
# Run this file to recreate the current configuration.
# Compiler output produced by configure, useful for debugging
# configure, is in config.log if it exists.

debug=false
ac_cs_recheck=false
ac_cs_silent=false

SHELL=\${CONFIG_SHELL-$SHELL}
export SHELL
_ASEOF
cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
## -------------------- ##
## M4sh Initialization. ##
## -------------------- ##

# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
  emulate sh
  NULLCMD=:
  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
  # is contrary to our usage.  Disable this feature.
  alias -g '${1+"$@"}'='"$@"'
  setopt NO_GLOB_SUBST
else
  case `(set -o) 2>/dev/null` in #(
  *posix*) :
    set -o posix ;; #(
  *) :
     ;;
esac
fi


as_nl='
'
export as_nl
# Printing a long string crashes Solaris 7 /usr/bin/printf.
as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
# Prefer a ksh shell builtin over an external printf program on Solaris,
# but without wasting forks for bash or zsh.
if test -z "$BASH_VERSION$ZSH_VERSION" \
    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='print -r --'
  as_echo_n='print -rn --'
elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
  as_echo='printf %s\n'
  as_echo_n='printf %s'
else
  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
    as_echo_n='/usr/ucb/echo -n'
  else
    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
    as_echo_n_body='eval
      arg=$1;
      case $arg in #(
      *"$as_nl"*)
	expr "X$arg" : "X\\(.*\\)$as_nl";
	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
      esac;
      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
    '
    export as_echo_n_body
    as_echo_n='sh -c $as_echo_n_body as_echo'
  fi
  export as_echo_body
  as_echo='sh -c $as_echo_body as_echo'
fi

# The user is always right.
if test "${PATH_SEPARATOR+set}" != set; then
  PATH_SEPARATOR=:
  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
      PATH_SEPARATOR=';'
  }
fi


# IFS
# We need space, tab and new line, in precisely that order.  Quoting is
# there to prevent editors from complaining about space-tab.
# (If _AS_PATH_WALK were called with IFS unset, it would disable word
# splitting by setting IFS to empty value.)
IFS=" ""	$as_nl"

# Find who we are.  Look in the path if we contain no directory separator.
as_myself=
case $0 in #((
  *[\\/]* ) as_myself=$0 ;;
  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
  IFS=$as_save_IFS
  test -z "$as_dir" && as_dir=.
    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
  done
IFS=$as_save_IFS

     ;;
esac
# We did not find ourselves, most probably we were run as `sh COMMAND'
# in which case we are not to be found in the path.
if test "x$as_myself" = x; then
  as_myself=$0
fi
if test ! -f "$as_myself"; then
  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
  exit 1
fi

# Unset variables that we do not need and which cause bugs (e.g. in
# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
# suppresses any "Segmentation fault" message there.  '((' could
# trigger a bug in pdksh 5.2.14.
for as_var in BASH_ENV ENV MAIL MAILPATH
do eval test x\${$as_var+set} = xset \
  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
done
PS1='$ '
PS2='> '
PS4='+ '

# NLS nuisances.
LC_ALL=C
export LC_ALL
LANGUAGE=C
export LANGUAGE

# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH


# as_fn_error STATUS ERROR [LINENO LOG_FD]
# ----------------------------------------
# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
# script with STATUS, using 1 if that was 0.
as_fn_error ()
{
  as_status=$1; test $as_status -eq 0 && as_status=1
  if test "$4"; then
    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
  fi
  $as_echo "$as_me: error: $2" >&2
  as_fn_exit $as_status
} # as_fn_error


# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
as_fn_set_status ()
{
  return $1
} # as_fn_set_status

# as_fn_exit STATUS
# -----------------
# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
as_fn_exit ()
{
  set +e
  as_fn_set_status $1
  exit $1
} # as_fn_exit

# as_fn_unset VAR
# ---------------
# Portably unset VAR.
as_fn_unset ()
{
  { eval $1=; unset $1;}
}
as_unset=as_fn_unset
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
  eval 'as_fn_append ()
  {
    eval $1+=\$2
  }'
else
  as_fn_append ()
  {
    eval $1=\$$1\$2
  }
fi # as_fn_append

# as_fn_arith ARG...
# ------------------
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
  eval 'as_fn_arith ()
  {
    as_val=$(( $* ))
  }'
else
  as_fn_arith ()
  {
    as_val=`expr "$@" || test $? -eq 1`
  }
fi # as_fn_arith


if expr a : '\(a\)' >/dev/null 2>&1 &&
   test "X`expr 00001 : '.*\(...\)'`" = X001; then
  as_expr=expr
else
  as_expr=false
fi

if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
  as_basename=basename
else
  as_basename=false
fi

if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
  as_dirname=dirname
else
  as_dirname=false
fi

as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
	 X"$0" : 'X\(//\)$' \| \
	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X/"$0" |
    sed '/^.*\/\([^/][^/]*\)\/*$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\/\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`

# Avoid depending upon Character Ranges.
as_cr_letters='abcdefghijklmnopqrstuvwxyz'
as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits

ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
  case `echo 'xy\c'` in
  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
  xy)  ECHO_C='\c';;
  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
       ECHO_T='	';;
  esac;;
*)
  ECHO_N='-n';;
esac

rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
  rm -f conf$$.dir/conf$$.file
else
  rm -f conf$$.dir
  mkdir conf$$.dir 2>/dev/null
fi
if (echo >conf$$.file) 2>/dev/null; then
  if ln -s conf$$.file conf$$ 2>/dev/null; then
    as_ln_s='ln -s'
    # ... but there are two gotchas:
    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
    # In both cases, we have to default to `cp -p'.
    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
      as_ln_s='cp -p'
  elif ln conf$$.file conf$$ 2>/dev/null; then
    as_ln_s=ln
  else
    as_ln_s='cp -p'
  fi
else
  as_ln_s='cp -p'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null


# as_fn_mkdir_p
# -------------
# Create "$as_dir" as a directory, including parents if necessary.
as_fn_mkdir_p ()
{

  case $as_dir in #(
  -*) as_dir=./$as_dir;;
  esac
  test -d "$as_dir" || eval $as_mkdir_p || {
    as_dirs=
    while :; do
      case $as_dir in #(
      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
      *) as_qdir=$as_dir;;
      esac
      as_dirs="'$as_qdir' $as_dirs"
      as_dir=`$as_dirname -- "$as_dir" ||
$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$as_dir" : 'X\(//\)[^/]' \| \
	 X"$as_dir" : 'X\(//\)$' \| \
	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$as_dir" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
      test -d "$as_dir" && break
    done
    test -z "$as_dirs" || eval "mkdir $as_dirs"
  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"


} # as_fn_mkdir_p
if mkdir -p . 2>/dev/null; then
  as_mkdir_p='mkdir -p "$as_dir"'
else
  test -d ./-p && rmdir ./-p
  as_mkdir_p=false
fi

if test -x / >/dev/null 2>&1; then
  as_test_x='test -x'
else
  if ls -dL / >/dev/null 2>&1; then
    as_ls_L_option=L
  else
    as_ls_L_option=
  fi
  as_test_x='
    eval sh -c '\''
      if test -d "$1"; then
	test -d "$1/.";
      else
	case $1 in #(
	-*)set "./$1";;
	esac;
	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
	???[sx]*):;;*)false;;esac;fi
    '\'' sh
  '
fi
as_executable_p=$as_test_x

# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"

# Sed expression to map a string onto a valid variable name.
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"


exec 6>&1
## ----------------------------------- ##
## Main body of $CONFIG_STATUS script. ##
## ----------------------------------- ##
_ASEOF
test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Save the log message, to keep $0 and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by $as_me, which was
generated by GNU Autoconf 2.68.  Invocation command line was

  CONFIG_FILES    = $CONFIG_FILES
  CONFIG_HEADERS  = $CONFIG_HEADERS
  CONFIG_LINKS    = $CONFIG_LINKS
  CONFIG_COMMANDS = $CONFIG_COMMANDS
  $ $0 $@

on `(hostname || uname -n) 2>/dev/null | sed 1q`
"

_ACEOF

case $ac_config_files in *"
"*) set x $ac_config_files; shift; ac_config_files=$*;;
esac

case $ac_config_headers in *"
"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
esac


cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
# Files that config.status was made for.
config_files="$ac_config_files"
config_headers="$ac_config_headers"

_ACEOF

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
ac_cs_usage="\
\`$as_me' instantiates files and other configuration actions
from templates according to the current configuration.  Unless the files
and actions are specified as TAGs, all are instantiated by default.

Usage: $0 [OPTION]... [TAG]...

  -h, --help       print this help, then exit
  -V, --version    print version number and configuration settings, then exit
      --config     print configuration, then exit
  -q, --quiet, --silent
                   do not print progress messages
  -d, --debug      don't remove temporary files
      --recheck    update $as_me by reconfiguring in the same conditions
      --file=FILE[:TEMPLATE]
                   instantiate the configuration file FILE
      --header=FILE[:TEMPLATE]
                   instantiate the configuration header FILE

Configuration files:
$config_files

Configuration headers:
$config_headers

Report bugs to the package provider."

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
config.status
configured by $0, generated by GNU Autoconf 2.68,
  with options \\"\$ac_cs_config\\"

Copyright (C) 2010 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."

ac_pwd='$ac_pwd'
srcdir='$srcdir'
INSTALL='$INSTALL'
test -n "\$AWK" || AWK=awk
_ACEOF

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# The default lists apply if the user does not specify any file.
ac_need_defaults=:
while test $# != 0
do
  case $1 in
  --*=?*)
    ac_option=`expr "X$1" : 'X\([^=]*\)='`
    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
    ac_shift=:
    ;;
  --*=)
    ac_option=`expr "X$1" : 'X\([^=]*\)='`
    ac_optarg=
    ac_shift=:
    ;;
  *)
    ac_option=$1
    ac_optarg=$2
    ac_shift=shift
    ;;
  esac

  case $ac_option in
  # Handling of the options.
  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
    ac_cs_recheck=: ;;
  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
    $as_echo "$ac_cs_version"; exit ;;
  --config | --confi | --conf | --con | --co | --c )
    $as_echo "$ac_cs_config"; exit ;;
  --debug | --debu | --deb | --de | --d | -d )
    debug=: ;;
  --file | --fil | --fi | --f )
    $ac_shift
    case $ac_optarg in
    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
    '') as_fn_error $? "missing file argument" ;;
    esac
    as_fn_append CONFIG_FILES " '$ac_optarg'"
    ac_need_defaults=false;;
  --header | --heade | --head | --hea )
    $ac_shift
    case $ac_optarg in
    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
    esac
    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
    ac_need_defaults=false;;
  --he | --h)
    # Conflict between --help and --header
    as_fn_error $? "ambiguous option: \`$1'
Try \`$0 --help' for more information.";;
  --help | --hel | -h )
    $as_echo "$ac_cs_usage"; exit ;;
  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
  | -silent | --silent | --silen | --sile | --sil | --si | --s)
    ac_cs_silent=: ;;

  # This is an error.
  -*) as_fn_error $? "unrecognized option: \`$1'
Try \`$0 --help' for more information." ;;

  *) as_fn_append ac_config_targets " $1"
     ac_need_defaults=false ;;

  esac
  shift
done

ac_configure_extra_args=

if $ac_cs_silent; then
  exec 6>/dev/null
  ac_configure_extra_args="$ac_configure_extra_args --silent"
fi

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then
  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
  shift
  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
  CONFIG_SHELL='$SHELL'
  export CONFIG_SHELL
  exec "\$@"
fi

_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
exec 5>>config.log
{
  echo
  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
## Running $as_me. ##
_ASBOX
  $as_echo "$ac_log"
} >&5

_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACEOF

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1

# Handling of arguments.
for ac_config_target in $ac_config_targets
do
  case $ac_config_target in
    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;

  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
  esac
done


# If the user did not use the arguments to specify the items to instantiate,
# then the envvar interface is used.  Set only those that are not.
# We use the long form for the default assignment because of an extremely
# bizarre bug on SunOS 4.1.3.
if $ac_need_defaults; then
  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
fi

# Have a temporary directory for convenience.  Make it in the build tree
# simply because there is no reason against having it here, and in addition,
# creating and moving files from /tmp can sometimes cause problems.
# Hook for its removal unless debugging.
# Note that there is a small window in which the directory will not be cleaned:
# after its creation but before its name has been assigned to `$tmp'.
$debug ||
{
  tmp= ac_tmp=
  trap 'exit_status=$?
  : "${ac_tmp:=$tmp}"
  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
' 0
  trap 'as_fn_exit 1' 1 2 13 15
}
# Create a (secure) tmp directory for tmp files.

{
  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
  test -d "$tmp"
}  ||
{
  tmp=./conf$$-$RANDOM
  (umask 077 && mkdir "$tmp")
} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
ac_tmp=$tmp

# Set up the scripts for CONFIG_FILES section.
# No need to generate them if there are no CONFIG_FILES.
# This happens for instance with `./config.status config.h'.
if test -n "$CONFIG_FILES"; then


ac_cr=`echo X | tr X '\015'`
# On cygwin, bash can eat \r inside `` if the user requested igncr.
# But we know of no other shell where ac_cr would be empty at this
# point, so we can use a bashism as a fallback.
if test "x$ac_cr" = x; then
  eval ac_cr=\$\'\\r\'
fi
ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
  ac_cs_awk_cr='\\r'
else
  ac_cs_awk_cr=$ac_cr
fi

echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
_ACEOF


{
  echo "cat >conf$$subs.awk <<_ACEOF" &&
  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
  echo "_ACEOF"
} >conf$$subs.sh ||
  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
ac_delim='%!_!# '
for ac_last_try in false false false false false :; do
  . ./conf$$subs.sh ||
    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5

  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
  if test $ac_delim_n = $ac_delim_num; then
    break
  elif $ac_last_try; then
    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
  else
    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
  fi
done
rm -f conf$$subs.sh

cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
_ACEOF
sed -n '
h
s/^/S["/; s/!.*/"]=/
p
g
s/^[^!]*!//
:repl
t repl
s/'"$ac_delim"'$//
t delim
:nl
h
s/\(.\{148\}\)..*/\1/
t more1
s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
p
n
b repl
:more1
s/["\\]/\\&/g; s/^/"/; s/$/"\\/
p
g
s/.\{148\}//
t nl
:delim
h
s/\(.\{148\}\)..*/\1/
t more2
s/["\\]/\\&/g; s/^/"/; s/$/"/
p
b
:more2
s/["\\]/\\&/g; s/^/"/; s/$/"\\/
p
g
s/.\{148\}//
t delim
' <conf$$subs.awk | sed '
/^[^""]/{
  N
  s/\n//
}
' >>$CONFIG_STATUS || ac_write_fail=1
rm -f conf$$subs.awk
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
_ACAWK
cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
  for (key in S) S_is_set[key] = 1
  FS = ""

}
{
  line = $ 0
  nfields = split(line, field, "@")
  substed = 0
  len = length(field[1])
  for (i = 2; i < nfields; i++) {
    key = field[i]
    keylen = length(key)
    if (S_is_set[key]) {
      value = S[key]
      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
      len += length(value) + length(field[++i])
      substed = 1
    } else
      len += 1 + keylen
  }

  print line
}

_ACAWK
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
else
  cat
fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
_ACEOF

# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
# trailing colons and then remove the whole line if VPATH becomes empty
# (actually we leave an empty line to preserve line numbers).
if test "x$srcdir" = x.; then
  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
h
s///
s/^/:/
s/[	 ]*$/:/
s/:\$(srcdir):/:/g
s/:\${srcdir}:/:/g
s/:@srcdir@:/:/g
s/^:*//
s/:*$//
x
s/\(=[	 ]*\).*/\1/
G
s/\n//
s/^[^=]*=[	 ]*$//
}'
fi

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
fi # test -n "$CONFIG_FILES"

# Set up the scripts for CONFIG_HEADERS section.
# No need to generate them if there are no CONFIG_HEADERS.
# This happens for instance with `./config.status Makefile'.
if test -n "$CONFIG_HEADERS"; then
cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
BEGIN {
_ACEOF

# Transform confdefs.h into an awk script `defines.awk', embedded as
# here-document in config.status, that substitutes the proper values into
# config.h.in to produce config.h.

# Create a delimiter string that does not exist in confdefs.h, to ease
# handling of long lines.
ac_delim='%!_!# '
for ac_last_try in false false :; do
  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
  if test -z "$ac_tt"; then
    break
  elif $ac_last_try; then
    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
  else
    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
  fi
done

# For the awk script, D is an array of macro values keyed by name,
# likewise P contains macro parameters if any.  Preserve backslash
# newline sequences.

ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
sed -n '
s/.\{148\}/&'"$ac_delim"'/g
t rset
:rset
s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
t def
d
:def
s/\\$//
t bsnl
s/["\\]/\\&/g
s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
D["\1"]=" \3"/p
s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
d
:bsnl
s/["\\]/\\&/g
s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
D["\1"]=" \3\\\\\\n"\\/p
t cont
s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
t cont
d
:cont
n
s/.\{148\}/&'"$ac_delim"'/g
t clear
:clear
s/\\$//
t bsnlc
s/["\\]/\\&/g; s/^/"/; s/$/"/p
d
:bsnlc
s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
b cont
' <confdefs.h | sed '
s/'"$ac_delim"'/"\\\
"/g' >>$CONFIG_STATUS || ac_write_fail=1

cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
  for (key in D) D_is_set[key] = 1
  FS = ""
}
/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
  line = \$ 0
  split(line, arg, " ")
  if (arg[1] == "#") {
    defundef = arg[2]
    mac1 = arg[3]
  } else {
    defundef = substr(arg[1], 2)
    mac1 = arg[2]
  }
  split(mac1, mac2, "(") #)
  macro = mac2[1]
  prefix = substr(line, 1, index(line, defundef) - 1)
  if (D_is_set[macro]) {
    # Preserve the white space surrounding the "#".
    print prefix "define", macro P[macro] D[macro]
    next
  } else {
    # Replace #undef with comments.  This is necessary, for example,
    # in the case of _POSIX_SOURCE, which is predefined and required
    # on some systems where configure will not decide to define it.
    if (defundef == "undef") {
      print "/*", prefix defundef, macro, "*/"
      next
    }
  }
}
{ print }
_ACAWK
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
fi # test -n "$CONFIG_HEADERS"


eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    "
shift
for ac_tag
do
  case $ac_tag in
  :[FHLC]) ac_mode=$ac_tag; continue;;
  esac
  case $ac_mode$ac_tag in
  :[FHL]*:*);;
  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
  :[FH]-) ac_tag=-:-;;
  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
  esac
  ac_save_IFS=$IFS
  IFS=:
  set x $ac_tag
  IFS=$ac_save_IFS
  shift
  ac_file=$1
  shift

  case $ac_mode in
  :L) ac_source=$1;;
  :[FH])
    ac_file_inputs=
    for ac_f
    do
      case $ac_f in
      -) ac_f="$ac_tmp/stdin";;
      *) # Look for the file first in the build tree, then in the source tree
	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
	 # because $ac_f cannot contain `:'.
	 test -f "$ac_f" ||
	   case $ac_f in
	   [\\/$]*) false;;
	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
	   esac ||
	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
      esac
      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
      as_fn_append ac_file_inputs " '$ac_f'"
    done

    # Let's still pretend it is `configure' which instantiates (i.e., don't
    # use $as_me), people would be surprised to read:
    #    /* config.h.  Generated by config.status.  */
    configure_input='Generated from '`
	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
	`' by configure.'
    if test x"$ac_file" != x-; then
      configure_input="$ac_file.  $configure_input"
      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
$as_echo "$as_me: creating $ac_file" >&6;}
    fi
    # Neutralize special characters interpreted by sed in replacement strings.
    case $configure_input in #(
    *\&* | *\|* | *\\* )
       ac_sed_conf_input=`$as_echo "$configure_input" |
       sed 's/[\\\\&|]/\\\\&/g'`;; #(
    *) ac_sed_conf_input=$configure_input;;
    esac

    case $ac_tag in
    *:-:* | *:-) cat >"$ac_tmp/stdin" \
      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
    esac
    ;;
  esac

  ac_dir=`$as_dirname -- "$ac_file" ||
$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
	 X"$ac_file" : 'X\(//\)[^/]' \| \
	 X"$ac_file" : 'X\(//\)$' \| \
	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
$as_echo X"$ac_file" |
    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)[^/].*/{
	    s//\1/
	    q
	  }
	  /^X\(\/\/\)$/{
	    s//\1/
	    q
	  }
	  /^X\(\/\).*/{
	    s//\1/
	    q
	  }
	  s/.*/./; q'`
  as_dir="$ac_dir"; as_fn_mkdir_p
  ac_builddir=.

case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
  # A ".." for each directory in $ac_dir_suffix.
  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
  case $ac_top_builddir_sub in
  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
  esac ;;
esac
ac_abs_top_builddir=$ac_pwd
ac_abs_builddir=$ac_pwd$ac_dir_suffix
# for backward compatibility:
ac_top_builddir=$ac_top_build_prefix

case $srcdir in
  .)  # We are building in place.
    ac_srcdir=.
    ac_top_srcdir=$ac_top_builddir_sub
    ac_abs_top_srcdir=$ac_pwd ;;
  [\\/]* | ?:[\\/]* )  # Absolute name.
    ac_srcdir=$srcdir$ac_dir_suffix;
    ac_top_srcdir=$srcdir
    ac_abs_top_srcdir=$srcdir ;;
  *) # Relative name.
    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
    ac_top_srcdir=$ac_top_build_prefix$srcdir
    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix


  case $ac_mode in
  :F)
  #
  # CONFIG_FILE
  #

  case $INSTALL in
  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
  esac
_ACEOF

cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# If the template does not know about datarootdir, expand it.
# FIXME: This hack should be removed a few years after 2.60.
ac_datarootdir_hack=; ac_datarootdir_seen=
ac_sed_dataroot='
/datarootdir/ {
  p
  q
}
/@datadir@/p
/@docdir@/p
/@infodir@/p
/@localedir@/p
/@mandir@/p'
case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
*datarootdir*) ac_datarootdir_seen=yes;;
*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
  ac_datarootdir_hack='
  s&@datadir@&$datadir&g
  s&@docdir@&$docdir&g
  s&@infodir@&$infodir&g
  s&@localedir@&$localedir&g
  s&@mandir@&$mandir&g
  s&\\\${datarootdir}&$datarootdir&g' ;;
esac
_ACEOF

# Neutralize VPATH when `$srcdir' = `.'.
# Shell code in configure.ac might set extrasub.
# FIXME: do we really want to maintain this feature?
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_sed_extra="$ac_vpsub
$extrasub
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
:t
/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
s|@configure_input@|$ac_sed_conf_input|;t t
s&@top_builddir@&$ac_top_builddir_sub&;t t
s&@top_build_prefix@&$ac_top_build_prefix&;t t
s&@srcdir@&$ac_srcdir&;t t
s&@abs_srcdir@&$ac_abs_srcdir&;t t
s&@top_srcdir@&$ac_top_srcdir&;t t
s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
s&@builddir@&$ac_builddir&;t t
s&@abs_builddir@&$ac_abs_builddir&;t t
s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
s&@INSTALL@&$ac_INSTALL&;t t
$ac_datarootdir_hack
"
eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5

test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
      "$ac_tmp/out"`; test -z "$ac_out"; } &&
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined.  Please make sure it is defined" >&5
$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined.  Please make sure it is defined" >&2;}

  rm -f "$ac_tmp/stdin"
  case $ac_file in
  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
  esac \
  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
 ;;
  :H)
  #
  # CONFIG_HEADER
  #
  if test x"$ac_file" != x-; then
    {
      $as_echo "/* $configure_input  */" \
      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
    } >"$ac_tmp/config.h" \
      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
$as_echo "$as_me: $ac_file is unchanged" >&6;}
    else
      rm -f "$ac_file"
      mv "$ac_tmp/config.h" "$ac_file" \
	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
    fi
  else
    $as_echo "/* $configure_input  */" \
      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
      || as_fn_error $? "could not create -" "$LINENO" 5
  fi
 ;;


  esac

done # for ac_tag


as_fn_exit 0
_ACEOF
ac_clean_files=$ac_clean_files_save

test $ac_write_fail = 0 ||
  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5


# configure is writing to config.log, and then calls config.status.
# config.status does its own redirection, appending to config.log.
# Unfortunately, on DOS this fails, as config.log is still kept open
# by configure, so config.status won't be able to write to it; its
# output is simply discarded.  So we exec the FD to /dev/null,
# effectively closing config.log, so it can be properly (re)opened and
# appended to by config.status.  When coming back to configure, we
# need to make the FD available again.
if test "$no_create" != yes; then
  ac_cs_success=:
  ac_config_status_args=
  test "$silent" = yes &&
    ac_config_status_args="$ac_config_status_args --quiet"
  exec 5>/dev/null
  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
  exec 5>>config.log
  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
  # would make configure fail if this is the last instruction.
  $ac_cs_success || as_fn_exit 1
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
fi

abcm2ps-7.8.13/configure.in0000644000175000017500000000352212461214407013547 0ustar  jefjefdnl Configure source for abcm2ps -*- sh -*-
dnl Copyright (C) 2001-2015 JF Moine.

AC_INIT(abc2ps.h)

VERSION=7.8.13
VDATE='January 25, 2015'

AC_CANONICAL_SYSTEM

dnl Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
dnl AC_PROG_MAKE_SET

AC_CONFIG_HEADER(config.h)

dnl Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS(malloc.h)

if test "X$GCC" = "Xyes" ; then
	CFLAGS="$CFLAGS -Wall -pipe"
fi

test "x$prefix" = xNONE && prefix=$ac_default_prefix

dnl Check for options

AC_ARG_ENABLE(pango,
[  --enable-pango          Use pango if available [[default: yes]]],
[checkpango="$enableval"],
[checkpango="yes"])

if test "$checkpango" = "yes"; then
$as_echo_n "checking for pango... " >&6
if which pkg-config > /dev/null ; then

dnl Checks freetype2
	if pkg-config --exists freetype2 ; then
dnl Checks pangocairo
		if pkg-config --exists pangocairo ; then
			$as_echo "yes" >&6
			CPPFLAGS="$CPPFLAGS -DHAVE_PANGO=1"
			CPPPANGO="`pkg-config pango cairo freetype2 --cflags`"
			LDFLAGS="$LDFLAGS `pkg-config pangocairo pangoft2 freetype2 --libs`"
		else
			$as_echo "no" >&6
		fi
	else
		$as_echo "pangocairo not found" >&6
	fi
else
	$as_echo "pkg-config not found" >&6
fi
fi

AC_ARG_ENABLE(a4,
[  --enable-a4             Handle european A4 format instead of default US letter],
[if test "$enableval" = "yes"; then
  AC_DEFINE(A4_FORMAT)dnl
fi])

AC_ARG_ENABLE(deco-is-roll,
[  --enable-deco-is-roll   Have ~ as roll instead of twiddle],
[if test "$enableval" = "yes"; then
  AC_DEFINE(DECO_IS_ROLL)dnl
fi])

DEFAULT_FDIR="$prefix/share/abcm2ps"
AC_ARG_WITH(def-fdir,
  [  --with-def-fdir=directory  Default format directory],
  [DEFAULT_FDIR="$withval"])

dnl Build characteristics
AC_SUBST(VERSION)
AC_SUBST(CPPPANGO)

AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
AC_DEFINE_UNQUOTED(VDATE, "$VDATE")
AC_DEFINE_UNQUOTED(DEFAULT_FDIR, "$DEFAULT_FDIR")

AC_OUTPUT(Makefile)
abcm2ps-7.8.13/config.h0000644000175000017500000000103312461214472012651 0ustar  jefjef/* config.h.  Generated from config.h.in by configure.  */
/* config.h.in */

/* default directory to search for format files */
#define DEFAULT_FDIR "/usr/local/share/abcm2ps"

/* Define if you have the strtol function.  */
/* #undef HAVE_STRTOL */

/* Define if you have the <malloc.h> header file.  */
#define HAVE_MALLOC_H 1

/* Define to handle the european A4 format.  */
/* #undef A4_FORMAT */

/* Define to have ~ as roll instead of twiddle.  */
/* #undef DECO_IS_ROLL */

#define VERSION "7.8.13"
#define VDATE "January 25, 2015"
abcm2ps-7.8.13/config.h.in0000644000175000017500000000064011334064351013256 0ustar  jefjef/* config.h.in */

/* default directory to search for format files */
#define DEFAULT_FDIR xxx

/* Define if you have the strtol function.  */
#undef HAVE_STRTOL

/* Define if you have the <malloc.h> header file.  */
#undef HAVE_MALLOC_H

/* Define to handle the european A4 format.  */
#undef A4_FORMAT

/* Define to have ~ as roll instead of twiddle.  */
#undef DECO_IS_ROLL

#define VERSION xxx
#define VDATE xxx
abcm2ps-7.8.13/config.guess0000644000175000017500000013036112232133043013545 0ustar  jefjef#! /bin/sh
# Attempt to guess a canonical system name.
#   Copyright 1992-2013 Free Software Foundation, Inc.

timestamp='2013-06-10'

# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that
# program.  This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
#
# Originally written by Per Bothner.
#
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
#
# Please send patches with a ChangeLog entry to config-patches@gnu.org.


me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
Usage: $0 [OPTION]

Output the configuration name of the system \`$me' is run on.

Operation modes:
  -h, --help         print this help, then exit
  -t, --time-stamp   print date of last modification, then exit
  -v, --version      print version number, then exit

Report bugs and patches to <config-patches@gnu.org>."

version="\
GNU config.guess ($timestamp)

Originally written by Per Bothner.
Copyright 1992-2013 Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

help="
Try \`$me --help' for more information."

# Parse command line
while test $# -gt 0 ; do
  case $1 in
    --time-stamp | --time* | -t )
       echo "$timestamp" ; exit ;;
    --version | -v )
       echo "$version" ; exit ;;
    --help | --h* | -h )
       echo "$usage"; exit ;;
    -- )     # Stop option processing
       shift; break ;;
    - )	# Use stdin as input.
       break ;;
    -* )
       echo "$me: invalid option $1$help" >&2
       exit 1 ;;
    * )
       break ;;
  esac
done

if test $# != 0; then
  echo "$me: too many arguments$help" >&2
  exit 1
fi

trap 'exit 1' 1 2 15

# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
# temporary files to be created and, as you can see below, it is a
# headache to deal with in a portable fashion.

# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
# use `HOST_CC' if defined, but it is deprecated.

# Portable tmp directory creation inspired by the Autoconf team.

set_cc_for_build='
trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
: ${TMPDIR=/tmp} ;
 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
 { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
 { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
 { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
dummy=$tmp/dummy ;
tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
case $CC_FOR_BUILD,$HOST_CC,$CC in
 ,,)    echo "int x;" > $dummy.c ;
	for c in cc gcc c89 c99 ; do
	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
	     CC_FOR_BUILD="$c"; break ;
	  fi ;
	done ;
	if test x"$CC_FOR_BUILD" = x ; then
	  CC_FOR_BUILD=no_compiler_found ;
	fi
	;;
 ,,*)   CC_FOR_BUILD=$CC ;;
 ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
esac ; set_cc_for_build= ;'

# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 1994-08-24)
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
	PATH=$PATH:/.attbin ; export PATH
fi

UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown

case "${UNAME_SYSTEM}" in
Linux|GNU|GNU/*)
	# If the system lacks a compiler, then just pick glibc.
	# We could probably try harder.
	LIBC=gnu

	eval $set_cc_for_build
	cat <<-EOF > $dummy.c
	#include <features.h>
	#if defined(__UCLIBC__)
	LIBC=uclibc
	#elif defined(__dietlibc__)
	LIBC=dietlibc
	#else
	LIBC=gnu
	#endif
	EOF
	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
	;;
esac

# Note: order is significant - the case branches are not exclusive.

case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
    *:NetBSD:*:*)
	# NetBSD (nbsd) targets should (where applicable) match one or
	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
	# switched to ELF, *-*-netbsd* would select the old
	# object file format.  This provides both forward
	# compatibility and a consistent mechanism for selecting the
	# object file format.
	#
	# Note: NetBSD doesn't particularly care about the vendor
	# portion of the name.  We always set it to "unknown".
	sysctl="sysctl -n hw.machine_arch"
	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
	case "${UNAME_MACHINE_ARCH}" in
	    armeb) machine=armeb-unknown ;;
	    arm*) machine=arm-unknown ;;
	    sh3el) machine=shl-unknown ;;
	    sh3eb) machine=sh-unknown ;;
	    sh5el) machine=sh5le-unknown ;;
	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
	esac
	# The Operating System including object format, if it has switched
	# to ELF recently, or will in the future.
	case "${UNAME_MACHINE_ARCH}" in
	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
		eval $set_cc_for_build
		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
			| grep -q __ELF__
		then
		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
		    # Return netbsd for either.  FIX?
		    os=netbsd
		else
		    os=netbsdelf
		fi
		;;
	    *)
		os=netbsd
		;;
	esac
	# The OS release
	# Debian GNU/NetBSD machines have a different userland, and
	# thus, need a distinct triplet. However, they do not need
	# kernel version information, so it can be replaced with a
	# suitable tag, in the style of linux-gnu.
	case "${UNAME_VERSION}" in
	    Debian*)
		release='-gnu'
		;;
	    *)
		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
		;;
	esac
	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
	# contains redundant information, the shorter form:
	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
	echo "${machine}-${os}${release}"
	exit ;;
    *:Bitrig:*:*)
	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
	exit ;;
    *:OpenBSD:*:*)
	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
	exit ;;
    *:ekkoBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
	exit ;;
    *:SolidBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
	exit ;;
    macppc:MirBSD:*:*)
	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
	exit ;;
    *:MirBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
	exit ;;
    alpha:OSF1:*:*)
	case $UNAME_RELEASE in
	*4.0)
		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
		;;
	*5.*)
		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
		;;
	esac
	# According to Compaq, /usr/sbin/psrinfo has been available on
	# OSF/1 and Tru64 systems produced since 1995.  I hope that
	# covers most systems running today.  This code pipes the CPU
	# types through head -n 1, so we only detect the type of CPU 0.
	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
	case "$ALPHA_CPU_TYPE" in
	    "EV4 (21064)")
		UNAME_MACHINE="alpha" ;;
	    "EV4.5 (21064)")
		UNAME_MACHINE="alpha" ;;
	    "LCA4 (21066/21068)")
		UNAME_MACHINE="alpha" ;;
	    "EV5 (21164)")
		UNAME_MACHINE="alphaev5" ;;
	    "EV5.6 (21164A)")
		UNAME_MACHINE="alphaev56" ;;
	    "EV5.6 (21164PC)")
		UNAME_MACHINE="alphapca56" ;;
	    "EV5.7 (21164PC)")
		UNAME_MACHINE="alphapca57" ;;
	    "EV6 (21264)")
		UNAME_MACHINE="alphaev6" ;;
	    "EV6.7 (21264A)")
		UNAME_MACHINE="alphaev67" ;;
	    "EV6.8CB (21264C)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.8AL (21264B)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.8CX (21264D)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.9A (21264/EV69A)")
		UNAME_MACHINE="alphaev69" ;;
	    "EV7 (21364)")
		UNAME_MACHINE="alphaev7" ;;
	    "EV7.9 (21364A)")
		UNAME_MACHINE="alphaev79" ;;
	esac
	# A Pn.n version is a patched version.
	# A Vn.n version is a released version.
	# A Tn.n version is a released field test version.
	# A Xn.n version is an unreleased experimental baselevel.
	# 1.2 uses "1.2" for uname -r.
	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
	exitcode=$?
	trap '' 0
	exit $exitcode ;;
    Alpha\ *:Windows_NT*:*)
	# How do we know it's Interix rather than the generic POSIX subsystem?
	# Should we change UNAME_MACHINE based on the output of uname instead
	# of the specific Alpha model?
	echo alpha-pc-interix
	exit ;;
    21064:Windows_NT:50:3)
	echo alpha-dec-winnt3.5
	exit ;;
    Amiga*:UNIX_System_V:4.0:*)
	echo m68k-unknown-sysv4
	exit ;;
    *:[Aa]miga[Oo][Ss]:*:*)
	echo ${UNAME_MACHINE}-unknown-amigaos
	exit ;;
    *:[Mm]orph[Oo][Ss]:*:*)
	echo ${UNAME_MACHINE}-unknown-morphos
	exit ;;
    *:OS/390:*:*)
	echo i370-ibm-openedition
	exit ;;
    *:z/VM:*:*)
	echo s390-ibm-zvmoe
	exit ;;
    *:OS400:*:*)
	echo powerpc-ibm-os400
	exit ;;
    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
	echo arm-acorn-riscix${UNAME_RELEASE}
	exit ;;
    arm*:riscos:*:*|arm*:RISCOS:*:*)
	echo arm-unknown-riscos
	exit ;;
    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
	echo hppa1.1-hitachi-hiuxmpp
	exit ;;
    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
	if test "`(/bin/universe) 2>/dev/null`" = att ; then
		echo pyramid-pyramid-sysv3
	else
		echo pyramid-pyramid-bsd
	fi
	exit ;;
    NILE*:*:*:dcosx)
	echo pyramid-pyramid-svr4
	exit ;;
    DRS?6000:unix:4.0:6*)
	echo sparc-icl-nx6
	exit ;;
    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
	case `/usr/bin/uname -p` in
	    sparc) echo sparc-icl-nx7; exit ;;
	esac ;;
    s390x:SunOS:*:*)
	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4H:SunOS:5.*:*)
	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
	echo i386-pc-auroraux${UNAME_RELEASE}
	exit ;;
    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
	eval $set_cc_for_build
	SUN_ARCH="i386"
	# If there is a compiler, see if it is configured for 64-bit objects.
	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
	# This test works for both compilers.
	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
		grep IS_64BIT_ARCH >/dev/null
	    then
		SUN_ARCH="x86_64"
	    fi
	fi
	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:6*:*)
	# According to config.sub, this is the proper way to canonicalize
	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
	# it's likely to be more like Solaris than SunOS4.
	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:*:*)
	case "`/usr/bin/arch -k`" in
	    Series*|S4*)
		UNAME_RELEASE=`uname -v`
		;;
	esac
	# Japanese Language versions have a version number like `4.1.3-JL'.
	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
	exit ;;
    sun3*:SunOS:*:*)
	echo m68k-sun-sunos${UNAME_RELEASE}
	exit ;;
    sun*:*:4.2BSD:*)
	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
	case "`/bin/arch`" in
	    sun3)
		echo m68k-sun-sunos${UNAME_RELEASE}
		;;
	    sun4)
		echo sparc-sun-sunos${UNAME_RELEASE}
		;;
	esac
	exit ;;
    aushp:SunOS:*:*)
	echo sparc-auspex-sunos${UNAME_RELEASE}
	exit ;;
    # The situation for MiNT is a little confusing.  The machine name
    # can be virtually everything (everything which is not
    # "atarist" or "atariste" at least should have a processor
    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
    # to the lowercase version "mint" (or "freemint").  Finally
    # the system name "TOS" denotes a system which is actually not
    # MiNT.  But MiNT is downward compatible to TOS, so this should
    # be no problem.
    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
	echo m68k-atari-mint${UNAME_RELEASE}
	exit ;;
    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
	echo m68k-atari-mint${UNAME_RELEASE}
	exit ;;
    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
	echo m68k-atari-mint${UNAME_RELEASE}
	exit ;;
    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
	echo m68k-milan-mint${UNAME_RELEASE}
	exit ;;
    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
	echo m68k-hades-mint${UNAME_RELEASE}
	exit ;;
    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
	echo m68k-unknown-mint${UNAME_RELEASE}
	exit ;;
    m68k:machten:*:*)
	echo m68k-apple-machten${UNAME_RELEASE}
	exit ;;
    powerpc:machten:*:*)
	echo powerpc-apple-machten${UNAME_RELEASE}
	exit ;;
    RISC*:Mach:*:*)
	echo mips-dec-mach_bsd4.3
	exit ;;
    RISC*:ULTRIX:*:*)
	echo mips-dec-ultrix${UNAME_RELEASE}
	exit ;;
    VAX*:ULTRIX*:*:*)
	echo vax-dec-ultrix${UNAME_RELEASE}
	exit ;;
    2020:CLIX:*:* | 2430:CLIX:*:*)
	echo clipper-intergraph-clix${UNAME_RELEASE}
	exit ;;
    mips:*:*:UMIPS | mips:*:*:RISCos)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
#ifdef __cplusplus
#include <stdio.h>  /* for printf() prototype */
	int main (int argc, char *argv[]) {
#else
	int main (argc, argv) int argc; char *argv[]; {
#endif
	#if defined (host_mips) && defined (MIPSEB)
	#if defined (SYSTYPE_SYSV)
	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
	#endif
	#if defined (SYSTYPE_SVR4)
	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
	#endif
	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
	#endif
	#endif
	  exit (-1);
	}
EOF
	$CC_FOR_BUILD -o $dummy $dummy.c &&
	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
	  SYSTEM_NAME=`$dummy $dummyarg` &&
	    { echo "$SYSTEM_NAME"; exit; }
	echo mips-mips-riscos${UNAME_RELEASE}
	exit ;;
    Motorola:PowerMAX_OS:*:*)
	echo powerpc-motorola-powermax
	exit ;;
    Motorola:*:4.3:PL8-*)
	echo powerpc-harris-powermax
	exit ;;
    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
	echo powerpc-harris-powermax
	exit ;;
    Night_Hawk:Power_UNIX:*:*)
	echo powerpc-harris-powerunix
	exit ;;
    m88k:CX/UX:7*:*)
	echo m88k-harris-cxux7
	exit ;;
    m88k:*:4*:R4*)
	echo m88k-motorola-sysv4
	exit ;;
    m88k:*:3*:R3*)
	echo m88k-motorola-sysv3
	exit ;;
    AViiON:dgux:*:*)
	# DG/UX returns AViiON for all architectures
	UNAME_PROCESSOR=`/usr/bin/uname -p`
	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
	then
	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
	       [ ${TARGET_BINARY_INTERFACE}x = x ]
	    then
		echo m88k-dg-dgux${UNAME_RELEASE}
	    else
		echo m88k-dg-dguxbcs${UNAME_RELEASE}
	    fi
	else
	    echo i586-dg-dgux${UNAME_RELEASE}
	fi
	exit ;;
    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
	echo m88k-dolphin-sysv3
	exit ;;
    M88*:*:R3*:*)
	# Delta 88k system running SVR3
	echo m88k-motorola-sysv3
	exit ;;
    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
	echo m88k-tektronix-sysv3
	exit ;;
    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
	echo m68k-tektronix-bsd
	exit ;;
    *:IRIX*:*:*)
	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
	exit ;;
    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
    i*86:AIX:*:*)
	echo i386-ibm-aix
	exit ;;
    ia64:AIX:*:*)
	if [ -x /usr/bin/oslevel ] ; then
		IBM_REV=`/usr/bin/oslevel`
	else
		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
	fi
	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
	exit ;;
    *:AIX:2:3)
	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
		eval $set_cc_for_build
		sed 's/^		//' << EOF >$dummy.c
		#include <sys/systemcfg.h>

		main()
			{
			if (!__power_pc())
				exit(1);
			puts("powerpc-ibm-aix3.2.5");
			exit(0);
			}
EOF
		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
		then
			echo "$SYSTEM_NAME"
		else
			echo rs6000-ibm-aix3.2.5
		fi
	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
		echo rs6000-ibm-aix3.2.4
	else
		echo rs6000-ibm-aix3.2
	fi
	exit ;;
    *:AIX:*:[4567])
	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
		IBM_ARCH=rs6000
	else
		IBM_ARCH=powerpc
	fi
	if [ -x /usr/bin/oslevel ] ; then
		IBM_REV=`/usr/bin/oslevel`
	else
		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
	fi
	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
	exit ;;
    *:AIX:*:*)
	echo rs6000-ibm-aix
	exit ;;
    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
	echo romp-ibm-bsd4.4
	exit ;;
    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
	exit ;;                             # report: romp-ibm BSD 4.3
    *:BOSX:*:*)
	echo rs6000-bull-bosx
	exit ;;
    DPX/2?00:B.O.S.:*:*)
	echo m68k-bull-sysv3
	exit ;;
    9000/[34]??:4.3bsd:1.*:*)
	echo m68k-hp-bsd
	exit ;;
    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
	echo m68k-hp-bsd4.4
	exit ;;
    9000/[34678]??:HP-UX:*:*)
	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
	case "${UNAME_MACHINE}" in
	    9000/31? )            HP_ARCH=m68000 ;;
	    9000/[34]?? )         HP_ARCH=m68k ;;
	    9000/[678][0-9][0-9])
		if [ -x /usr/bin/getconf ]; then
		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
		    case "${sc_cpu_version}" in
		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
		      532)                      # CPU_PA_RISC2_0
			case "${sc_kernel_bits}" in
			  32) HP_ARCH="hppa2.0n" ;;
			  64) HP_ARCH="hppa2.0w" ;;
			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
			esac ;;
		    esac
		fi
		if [ "${HP_ARCH}" = "" ]; then
		    eval $set_cc_for_build
		    sed 's/^		//' << EOF >$dummy.c

		#define _HPUX_SOURCE
		#include <stdlib.h>
		#include <unistd.h>

		int main ()
		{
		#if defined(_SC_KERNEL_BITS)
		    long bits = sysconf(_SC_KERNEL_BITS);
		#endif
		    long cpu  = sysconf (_SC_CPU_VERSION);

		    switch (cpu)
			{
			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
			case CPU_PA_RISC2_0:
		#if defined(_SC_KERNEL_BITS)
			    switch (bits)
				{
				case 64: puts ("hppa2.0w"); break;
				case 32: puts ("hppa2.0n"); break;
				default: puts ("hppa2.0"); break;
				} break;
		#else  /* !defined(_SC_KERNEL_BITS) */
			    puts ("hppa2.0"); break;
		#endif
			default: puts ("hppa1.0"); break;
			}
		    exit (0);
		}
EOF
		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
		    test -z "$HP_ARCH" && HP_ARCH=hppa
		fi ;;
	esac
	if [ ${HP_ARCH} = "hppa2.0w" ]
	then
	    eval $set_cc_for_build

	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
	    # generating 64-bit code.  GNU and HP use different nomenclature:
	    #
	    # $ CC_FOR_BUILD=cc ./config.guess
	    # => hppa2.0w-hp-hpux11.23
	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
	    # => hppa64-hp-hpux11.23

	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
		grep -q __LP64__
	    then
		HP_ARCH="hppa2.0w"
	    else
		HP_ARCH="hppa64"
	    fi
	fi
	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
	exit ;;
    ia64:HP-UX:*:*)
	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
	echo ia64-hp-hpux${HPUX_REV}
	exit ;;
    3050*:HI-UX:*:*)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
	#include <unistd.h>
	int
	main ()
	{
	  long cpu = sysconf (_SC_CPU_VERSION);
	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
	     results, however.  */
	  if (CPU_IS_PA_RISC (cpu))
	    {
	      switch (cpu)
		{
		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
		  default: puts ("hppa-hitachi-hiuxwe2"); break;
		}
	    }
	  else if (CPU_IS_HP_MC68K (cpu))
	    puts ("m68k-hitachi-hiuxwe2");
	  else puts ("unknown-hitachi-hiuxwe2");
	  exit (0);
	}
EOF
	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
		{ echo "$SYSTEM_NAME"; exit; }
	echo unknown-hitachi-hiuxwe2
	exit ;;
    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
	echo hppa1.1-hp-bsd
	exit ;;
    9000/8??:4.3bsd:*:*)
	echo hppa1.0-hp-bsd
	exit ;;
    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
	echo hppa1.0-hp-mpeix
	exit ;;
    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
	echo hppa1.1-hp-osf
	exit ;;
    hp8??:OSF1:*:*)
	echo hppa1.0-hp-osf
	exit ;;
    i*86:OSF1:*:*)
	if [ -x /usr/sbin/sysversion ] ; then
	    echo ${UNAME_MACHINE}-unknown-osf1mk
	else
	    echo ${UNAME_MACHINE}-unknown-osf1
	fi
	exit ;;
    parisc*:Lites*:*:*)
	echo hppa1.1-hp-lites
	exit ;;
    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
	echo c1-convex-bsd
	exit ;;
    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
	if getsysinfo -f scalar_acc
	then echo c32-convex-bsd
	else echo c2-convex-bsd
	fi
	exit ;;
    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
	echo c34-convex-bsd
	exit ;;
    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
	echo c38-convex-bsd
	exit ;;
    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
	echo c4-convex-bsd
	exit ;;
    CRAY*Y-MP:*:*:*)
	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*[A-Z]90:*:*:*)
	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
	      -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*TS:*:*:*)
	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*T3E:*:*:*)
	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*SV1:*:*:*)
	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    *:UNICOS/mp:*:*)
	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
	exit ;;
    5000:UNIX_System_V:4.*:*)
	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
	exit ;;
    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
	exit ;;
    sparc*:BSD/OS:*:*)
	echo sparc-unknown-bsdi${UNAME_RELEASE}
	exit ;;
    *:BSD/OS:*:*)
	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
	exit ;;
    *:FreeBSD:*:*)
	UNAME_PROCESSOR=`/usr/bin/uname -p`
	case ${UNAME_PROCESSOR} in
	    amd64)
		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
	    *)
		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
	esac
	exit ;;
    i*:CYGWIN*:*)
	echo ${UNAME_MACHINE}-pc-cygwin
	exit ;;
    *:MINGW64*:*)
	echo ${UNAME_MACHINE}-pc-mingw64
	exit ;;
    *:MINGW*:*)
	echo ${UNAME_MACHINE}-pc-mingw32
	exit ;;
    i*:MSYS*:*)
	echo ${UNAME_MACHINE}-pc-msys
	exit ;;
    i*:windows32*:*)
	# uname -m includes "-pc" on this system.
	echo ${UNAME_MACHINE}-mingw32
	exit ;;
    i*:PW*:*)
	echo ${UNAME_MACHINE}-pc-pw32
	exit ;;
    *:Interix*:*)
	case ${UNAME_MACHINE} in
	    x86)
		echo i586-pc-interix${UNAME_RELEASE}
		exit ;;
	    authenticamd | genuineintel | EM64T)
		echo x86_64-unknown-interix${UNAME_RELEASE}
		exit ;;
	    IA64)
		echo ia64-unknown-interix${UNAME_RELEASE}
		exit ;;
	esac ;;
    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
	echo i${UNAME_MACHINE}-pc-mks
	exit ;;
    8664:Windows_NT:*)
	echo x86_64-pc-mks
	exit ;;
    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
	# How do we know it's Interix rather than the generic POSIX subsystem?
	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
	# UNAME_MACHINE based on the output of uname instead of i386?
	echo i586-pc-interix
	exit ;;
    i*:UWIN*:*)
	echo ${UNAME_MACHINE}-pc-uwin
	exit ;;
    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
	echo x86_64-unknown-cygwin
	exit ;;
    p*:CYGWIN*:*)
	echo powerpcle-unknown-cygwin
	exit ;;
    prep*:SunOS:5.*:*)
	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    *:GNU:*:*)
	# the GNU system
	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
	exit ;;
    *:GNU/*:*:*)
	# other systems with GNU libc and userland
	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
	exit ;;
    i*86:Minix:*:*)
	echo ${UNAME_MACHINE}-pc-minix
	exit ;;
    aarch64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    aarch64_be:Linux:*:*)
	UNAME_MACHINE=aarch64_be
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    alpha:Linux:*:*)
	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
	  EV5)   UNAME_MACHINE=alphaev5 ;;
	  EV56)  UNAME_MACHINE=alphaev56 ;;
	  PCA56) UNAME_MACHINE=alphapca56 ;;
	  PCA57) UNAME_MACHINE=alphapca56 ;;
	  EV6)   UNAME_MACHINE=alphaev6 ;;
	  EV67)  UNAME_MACHINE=alphaev67 ;;
	  EV68*) UNAME_MACHINE=alphaev68 ;;
	esac
	objdump --private-headers /bin/sh | grep -q ld.so.1
	if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    arc:Linux:*:* | arceb:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    arm*:Linux:*:*)
	eval $set_cc_for_build
	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
	    | grep -q __ARM_EABI__
	then
	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	else
	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
		| grep -q __ARM_PCS_VFP
	    then
		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
	    else
		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
	    fi
	fi
	exit ;;
    avr32*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    cris:Linux:*:*)
	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
	exit ;;
    crisv32:Linux:*:*)
	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
	exit ;;
    frv:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    hexagon:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    i*86:Linux:*:*)
	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
	exit ;;
    ia64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    m32r*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    m68*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    mips:Linux:*:* | mips64:Linux:*:*)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
	#undef CPU
	#undef ${UNAME_MACHINE}
	#undef ${UNAME_MACHINE}el
	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
	CPU=${UNAME_MACHINE}el
	#else
	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
	CPU=${UNAME_MACHINE}
	#else
	CPU=
	#endif
	#endif
EOF
	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
	;;
    or1k:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    or32:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    padre:Linux:*:*)
	echo sparc-unknown-linux-${LIBC}
	exit ;;
    parisc64:Linux:*:* | hppa64:Linux:*:*)
	echo hppa64-unknown-linux-${LIBC}
	exit ;;
    parisc:Linux:*:* | hppa:Linux:*:*)
	# Look for CPU level
	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
	  *)    echo hppa-unknown-linux-${LIBC} ;;
	esac
	exit ;;
    ppc64:Linux:*:*)
	echo powerpc64-unknown-linux-${LIBC}
	exit ;;
    ppc:Linux:*:*)
	echo powerpc-unknown-linux-${LIBC}
	exit ;;
    ppc64le:Linux:*:*)
	echo powerpc64le-unknown-linux-${LIBC}
	exit ;;
    ppcle:Linux:*:*)
	echo powerpcle-unknown-linux-${LIBC}
	exit ;;
    s390:Linux:*:* | s390x:Linux:*:*)
	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
	exit ;;
    sh64*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    sh*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    sparc:Linux:*:* | sparc64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    tile*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    vax:Linux:*:*)
	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
	exit ;;
    x86_64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    xtensa*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    i*86:DYNIX/ptx:4*:*)
	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
	# earlier versions are messed up and put the nodename in both
	# sysname and nodename.
	echo i386-sequent-sysv4
	exit ;;
    i*86:UNIX_SV:4.2MP:2.*)
	# Unixware is an offshoot of SVR4, but it has its own version
	# number series starting with 2...
	# I am not positive that other SVR4 systems won't match this,
	# I just have to hope.  -- rms.
	# Use sysv4.2uw... so that sysv4* matches it.
	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
	exit ;;
    i*86:OS/2:*:*)
	# If we were able to find `uname', then EMX Unix compatibility
	# is probably installed.
	echo ${UNAME_MACHINE}-pc-os2-emx
	exit ;;
    i*86:XTS-300:*:STOP)
	echo ${UNAME_MACHINE}-unknown-stop
	exit ;;
    i*86:atheos:*:*)
	echo ${UNAME_MACHINE}-unknown-atheos
	exit ;;
    i*86:syllable:*:*)
	echo ${UNAME_MACHINE}-pc-syllable
	exit ;;
    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
	echo i386-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    i*86:*DOS:*:*)
	echo ${UNAME_MACHINE}-pc-msdosdjgpp
	exit ;;
    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
	else
		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
	fi
	exit ;;
    i*86:*:5:[678]*)
	# UnixWare 7.x, OpenUNIX and OpenServer 6.
	case `/bin/uname -X | grep "^Machine"` in
	    *486*)	     UNAME_MACHINE=i486 ;;
	    *Pentium)	     UNAME_MACHINE=i586 ;;
	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
	esac
	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
	exit ;;
    i*86:*:3.2:*)
	if test -f /usr/options/cb.name; then
		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
	elif /bin/uname -X 2>/dev/null >/dev/null ; then
		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
			&& UNAME_MACHINE=i586
		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
			&& UNAME_MACHINE=i686
		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
			&& UNAME_MACHINE=i686
		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
	else
		echo ${UNAME_MACHINE}-pc-sysv32
	fi
	exit ;;
    pc:*:*:*)
	# Left here for compatibility:
	# uname -m prints for DJGPP always 'pc', but it prints nothing about
	# the processor, so we play safe by assuming i586.
	# Note: whatever this is, it MUST be the same as what config.sub
	# prints for the "djgpp" host, or else GDB configury will decide that
	# this is a cross-build.
	echo i586-pc-msdosdjgpp
	exit ;;
    Intel:Mach:3*:*)
	echo i386-pc-mach3
	exit ;;
    paragon:*:*:*)
	echo i860-intel-osf1
	exit ;;
    i860:*:4.*:*) # i860-SVR4
	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
	else # Add other i860-SVR4 vendors below as they are discovered.
	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
	fi
	exit ;;
    mini*:CTIX:SYS*5:*)
	# "miniframe"
	echo m68010-convergent-sysv
	exit ;;
    mc68k:UNIX:SYSTEM5:3.51m)
	echo m68k-convergent-sysv
	exit ;;
    M680?0:D-NIX:5.3:*)
	echo m68k-diab-dnix
	exit ;;
    M68*:*:R3V[5678]*:*)
	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
	OS_REL=''
	test -r /etc/.relid \
	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
	  && { echo i486-ncr-sysv4; exit; } ;;
    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
	OS_REL='.3'
	test -r /etc/.relid \
	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
	echo m68k-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    mc68030:UNIX_System_V:4.*:*)
	echo m68k-atari-sysv4
	exit ;;
    TSUNAMI:LynxOS:2.*:*)
	echo sparc-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    rs6000:LynxOS:2.*:*)
	echo rs6000-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
	echo powerpc-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    SM[BE]S:UNIX_SV:*:*)
	echo mips-dde-sysv${UNAME_RELEASE}
	exit ;;
    RM*:ReliantUNIX-*:*:*)
	echo mips-sni-sysv4
	exit ;;
    RM*:SINIX-*:*:*)
	echo mips-sni-sysv4
	exit ;;
    *:SINIX-*:*:*)
	if uname -p 2>/dev/null >/dev/null ; then
		UNAME_MACHINE=`(uname -p) 2>/dev/null`
		echo ${UNAME_MACHINE}-sni-sysv4
	else
		echo ns32k-sni-sysv
	fi
	exit ;;
    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
			# says <Richard.M.Bartel@ccMail.Census.GOV>
	echo i586-unisys-sysv4
	exit ;;
    *:UNIX_System_V:4*:FTX*)
	# From Gerald Hewes <hewes@openmarket.com>.
	# How about differentiating between stratus architectures? -djm
	echo hppa1.1-stratus-sysv4
	exit ;;
    *:*:*:FTX*)
	# From seanf@swdc.stratus.com.
	echo i860-stratus-sysv4
	exit ;;
    i*86:VOS:*:*)
	# From Paul.Green@stratus.com.
	echo ${UNAME_MACHINE}-stratus-vos
	exit ;;
    *:VOS:*:*)
	# From Paul.Green@stratus.com.
	echo hppa1.1-stratus-vos
	exit ;;
    mc68*:A/UX:*:*)
	echo m68k-apple-aux${UNAME_RELEASE}
	exit ;;
    news*:NEWS-OS:6*:*)
	echo mips-sony-newsos6
	exit ;;
    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
	if [ -d /usr/nec ]; then
		echo mips-nec-sysv${UNAME_RELEASE}
	else
		echo mips-unknown-sysv${UNAME_RELEASE}
	fi
	exit ;;
    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
	echo powerpc-be-beos
	exit ;;
    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
	echo powerpc-apple-beos
	exit ;;
    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
	echo i586-pc-beos
	exit ;;
    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
	echo i586-pc-haiku
	exit ;;
    x86_64:Haiku:*:*)
	echo x86_64-unknown-haiku
	exit ;;
    SX-4:SUPER-UX:*:*)
	echo sx4-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-5:SUPER-UX:*:*)
	echo sx5-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-6:SUPER-UX:*:*)
	echo sx6-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-7:SUPER-UX:*:*)
	echo sx7-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-8:SUPER-UX:*:*)
	echo sx8-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-8R:SUPER-UX:*:*)
	echo sx8r-nec-superux${UNAME_RELEASE}
	exit ;;
    Power*:Rhapsody:*:*)
	echo powerpc-apple-rhapsody${UNAME_RELEASE}
	exit ;;
    *:Rhapsody:*:*)
	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
	exit ;;
    *:Darwin:*:*)
	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
	eval $set_cc_for_build
	if test "$UNAME_PROCESSOR" = unknown ; then
	    UNAME_PROCESSOR=powerpc
	fi
	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
	    if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
		grep IS_64BIT_ARCH >/dev/null
	    then
		case $UNAME_PROCESSOR in
		    i386) UNAME_PROCESSOR=x86_64 ;;
		    powerpc) UNAME_PROCESSOR=powerpc64 ;;
		esac
	    fi
	fi
	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
	exit ;;
    *:procnto*:*:* | *:QNX:[0123456789]*:*)
	UNAME_PROCESSOR=`uname -p`
	if test "$UNAME_PROCESSOR" = "x86"; then
		UNAME_PROCESSOR=i386
		UNAME_MACHINE=pc
	fi
	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
	exit ;;
    *:QNX:*:4*)
	echo i386-pc-qnx
	exit ;;
    NEO-?:NONSTOP_KERNEL:*:*)
	echo neo-tandem-nsk${UNAME_RELEASE}
	exit ;;
    NSE-*:NONSTOP_KERNEL:*:*)
	echo nse-tandem-nsk${UNAME_RELEASE}
	exit ;;
    NSR-?:NONSTOP_KERNEL:*:*)
	echo nsr-tandem-nsk${UNAME_RELEASE}
	exit ;;
    *:NonStop-UX:*:*)
	echo mips-compaq-nonstopux
	exit ;;
    BS2000:POSIX*:*:*)
	echo bs2000-siemens-sysv
	exit ;;
    DS/*:UNIX_System_V:*:*)
	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
	exit ;;
    *:Plan9:*:*)
	# "uname -m" is not consistent, so use $cputype instead. 386
	# is converted to i386 for consistency with other x86
	# operating systems.
	if test "$cputype" = "386"; then
	    UNAME_MACHINE=i386
	else
	    UNAME_MACHINE="$cputype"
	fi
	echo ${UNAME_MACHINE}-unknown-plan9
	exit ;;
    *:TOPS-10:*:*)
	echo pdp10-unknown-tops10
	exit ;;
    *:TENEX:*:*)
	echo pdp10-unknown-tenex
	exit ;;
    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
	echo pdp10-dec-tops20
	exit ;;
    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
	echo pdp10-xkl-tops20
	exit ;;
    *:TOPS-20:*:*)
	echo pdp10-unknown-tops20
	exit ;;
    *:ITS:*:*)
	echo pdp10-unknown-its
	exit ;;
    SEI:*:*:SEIUX)
	echo mips-sei-seiux${UNAME_RELEASE}
	exit ;;
    *:DragonFly:*:*)
	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
	exit ;;
    *:*VMS:*:*)
	UNAME_MACHINE=`(uname -p) 2>/dev/null`
	case "${UNAME_MACHINE}" in
	    A*) echo alpha-dec-vms ; exit ;;
	    I*) echo ia64-dec-vms ; exit ;;
	    V*) echo vax-dec-vms ; exit ;;
	esac ;;
    *:XENIX:*:SysV)
	echo i386-pc-xenix
	exit ;;
    i*86:skyos:*:*)
	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
	exit ;;
    i*86:rdos:*:*)
	echo ${UNAME_MACHINE}-pc-rdos
	exit ;;
    i*86:AROS:*:*)
	echo ${UNAME_MACHINE}-pc-aros
	exit ;;
    x86_64:VMkernel:*:*)
	echo ${UNAME_MACHINE}-unknown-esx
	exit ;;
esac

eval $set_cc_for_build
cat >$dummy.c <<EOF
#ifdef _SEQUENT_
# include <sys/types.h>
# include <sys/utsname.h>
#endif
main ()
{
#if defined (sony)
#if defined (MIPSEB)
  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
     I don't know....  */
  printf ("mips-sony-bsd\n"); exit (0);
#else
#include <sys/param.h>
  printf ("m68k-sony-newsos%s\n",
#ifdef NEWSOS4
	"4"
#else
	""
#endif
	); exit (0);
#endif
#endif

#if defined (__arm) && defined (__acorn) && defined (__unix)
  printf ("arm-acorn-riscix\n"); exit (0);
#endif

#if defined (hp300) && !defined (hpux)
  printf ("m68k-hp-bsd\n"); exit (0);
#endif

#if defined (NeXT)
#if !defined (__ARCHITECTURE__)
#define __ARCHITECTURE__ "m68k"
#endif
  int version;
  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
  if (version < 4)
    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
  else
    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
  exit (0);
#endif

#if defined (MULTIMAX) || defined (n16)
#if defined (UMAXV)
  printf ("ns32k-encore-sysv\n"); exit (0);
#else
#if defined (CMU)
  printf ("ns32k-encore-mach\n"); exit (0);
#else
  printf ("ns32k-encore-bsd\n"); exit (0);
#endif
#endif
#endif

#if defined (__386BSD__)
  printf ("i386-pc-bsd\n"); exit (0);
#endif

#if defined (sequent)
#if defined (i386)
  printf ("i386-sequent-dynix\n"); exit (0);
#endif
#if defined (ns32000)
  printf ("ns32k-sequent-dynix\n"); exit (0);
#endif
#endif

#if defined (_SEQUENT_)
    struct utsname un;

    uname(&un);

    if (strncmp(un.version, "V2", 2) == 0) {
	printf ("i386-sequent-ptx2\n"); exit (0);
    }
    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
	printf ("i386-sequent-ptx1\n"); exit (0);
    }
    printf ("i386-sequent-ptx\n"); exit (0);

#endif

#if defined (vax)
# if !defined (ultrix)
#  include <sys/param.h>
#  if defined (BSD)
#   if BSD == 43
      printf ("vax-dec-bsd4.3\n"); exit (0);
#   else
#    if BSD == 199006
      printf ("vax-dec-bsd4.3reno\n"); exit (0);
#    else
      printf ("vax-dec-bsd\n"); exit (0);
#    endif
#   endif
#  else
    printf ("vax-dec-bsd\n"); exit (0);
#  endif
# else
    printf ("vax-dec-ultrix\n"); exit (0);
# endif
#endif

#if defined (alliant) && defined (i860)
  printf ("i860-alliant-bsd\n"); exit (0);
#endif

  exit (1);
}
EOF

$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
	{ echo "$SYSTEM_NAME"; exit; }

# Apollos put the system type in the environment.

test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }

# Convex versions that predate uname can use getsysinfo(1)

if [ -x /usr/convex/getsysinfo ]
then
    case `getsysinfo -f cpu_type` in
    c1*)
	echo c1-convex-bsd
	exit ;;
    c2*)
	if getsysinfo -f scalar_acc
	then echo c32-convex-bsd
	else echo c2-convex-bsd
	fi
	exit ;;
    c34*)
	echo c34-convex-bsd
	exit ;;
    c38*)
	echo c38-convex-bsd
	exit ;;
    c4*)
	echo c4-convex-bsd
	exit ;;
    esac
fi

cat >&2 <<EOF
$0: unable to guess system type

This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from

  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
and
  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD

If the version you run ($0) is already up to date, please
send the following data and any information you think might be
pertinent to <config-patches@gnu.org> in order to provide the needed
information to handle your system.

config.guess timestamp = $timestamp

uname -m = `(uname -m) 2>/dev/null || echo unknown`
uname -r = `(uname -r) 2>/dev/null || echo unknown`
uname -s = `(uname -s) 2>/dev/null || echo unknown`
uname -v = `(uname -v) 2>/dev/null || echo unknown`

/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`

hostinfo               = `(hostinfo) 2>/dev/null`
/bin/universe          = `(/bin/universe) 2>/dev/null`
/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
/bin/arch              = `(/bin/arch) 2>/dev/null`
/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`

UNAME_MACHINE = ${UNAME_MACHINE}
UNAME_RELEASE = ${UNAME_RELEASE}
UNAME_SYSTEM  = ${UNAME_SYSTEM}
UNAME_VERSION = ${UNAME_VERSION}
EOF

exit 1

# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
abcm2ps-7.8.13/config.sub0000644000175000017500000010541212232135067013217 0ustar  jefjef#! /bin/sh
# Configuration validation subroutine script.
#   Copyright 1992-2013 Free Software Foundation, Inc.

timestamp='2013-10-01'

# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that
# program.  This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").


# Please send patches with a ChangeLog entry to config-patches@gnu.org.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1.
# Otherwise, we print the canonical config type on stdout and succeed.

# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD

# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
# that are meaningful with *any* GNU software.
# Each package is responsible for reporting which valid configurations
# it does not support.  The user should be able to distinguish
# a failure to support a valid configuration from a meaningless
# configuration.

# The goal of this file is to map all the various variations of a given
# machine specification into a single specification in the form:
#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
# or in some cases, the newer four-part form:
#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.

me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS
       $0 [OPTION] ALIAS

Canonicalize a configuration name.

Operation modes:
  -h, --help         print this help, then exit
  -t, --time-stamp   print date of last modification, then exit
  -v, --version      print version number, then exit

Report bugs and patches to <config-patches@gnu.org>."

version="\
GNU config.sub ($timestamp)

Copyright 1992-2013 Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

help="
Try \`$me --help' for more information."

# Parse command line
while test $# -gt 0 ; do
  case $1 in
    --time-stamp | --time* | -t )
       echo "$timestamp" ; exit ;;
    --version | -v )
       echo "$version" ; exit ;;
    --help | --h* | -h )
       echo "$usage"; exit ;;
    -- )     # Stop option processing
       shift; break ;;
    - )	# Use stdin as input.
       break ;;
    -* )
       echo "$me: invalid option $1$help"
       exit 1 ;;

    *local*)
       # First pass through any local machine types.
       echo $1
       exit ;;

    * )
       break ;;
  esac
done

case $# in
 0) echo "$me: missing argument$help" >&2
    exit 1;;
 1) ;;
 *) echo "$me: too many arguments$help" >&2
    exit 1;;
esac

# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
  knetbsd*-gnu* | netbsd*-gnu* | \
  kopensolaris*-gnu* | \
  storm-chaos* | os2-emx* | rtmk-nova*)
    os=-$maybe_os
    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
    ;;
  android-linux)
    os=-linux-android
    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
    ;;
  *)
    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
    if [ $basic_machine != $1 ]
    then os=`echo $1 | sed 's/.*-/-/'`
    else os=; fi
    ;;
esac

### Let's recognize common machines as not being operating systems so
### that things like config.sub decstation-3100 work.  We also
### recognize some manufacturers as not being operating systems, so we
### can provide default operating systems below.
case $os in
	-sun*os*)
		# Prevent following clause from handling this invalid input.
		;;
	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
	-apple | -axis | -knuth | -cray | -microblaze*)
		os=
		basic_machine=$1
		;;
	-bluegene*)
		os=-cnk
		;;
	-sim | -cisco | -oki | -wec | -winbond)
		os=
		basic_machine=$1
		;;
	-scout)
		;;
	-wrs)
		os=-vxworks
		basic_machine=$1
		;;
	-chorusos*)
		os=-chorusos
		basic_machine=$1
		;;
	-chorusrdb)
		os=-chorusrdb
		basic_machine=$1
		;;
	-hiux*)
		os=-hiuxwe2
		;;
	-sco6)
		os=-sco5v6
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco5)
		os=-sco3.2v5
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco4)
		os=-sco3.2v4
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco3.2.[4-9]*)
		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco3.2v[4-9]*)
		# Don't forget version if it is 3.2v4 or newer.
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco5v6*)
		# Don't forget version if it is 3.2v4 or newer.
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco*)
		os=-sco3.2v2
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-udk*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-isc)
		os=-isc2.2
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-clix*)
		basic_machine=clipper-intergraph
		;;
	-isc*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-lynx*178)
		os=-lynxos178
		;;
	-lynx*5)
		os=-lynxos5
		;;
	-lynx*)
		os=-lynxos
		;;
	-ptx*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
		;;
	-windowsnt*)
		os=`echo $os | sed -e 's/windowsnt/winnt/'`
		;;
	-psos*)
		os=-psos
		;;
	-mint | -mint[0-9]*)
		basic_machine=m68k-atari
		os=-mint
		;;
esac

# Decode aliases for certain CPU-COMPANY combinations.
case $basic_machine in
	# Recognize the basic CPU types without company name.
	# Some are omitted here because they have special meanings below.
	1750a | 580 \
	| a29k \
	| aarch64 | aarch64_be \
	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
	| am33_2.0 \
	| arc | arceb \
	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
	| avr | avr32 \
	| be32 | be64 \
	| bfin \
	| c4x | c8051 | clipper \
	| d10v | d30v | dlx | dsp16xx \
	| epiphany \
	| fido | fr30 | frv \
	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
	| hexagon \
	| i370 | i860 | i960 | ia64 \
	| ip2k | iq2000 \
	| k1om \
	| le32 | le64 \
	| lm32 \
	| m32c | m32r | m32rle | m68000 | m68k | m88k \
	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
	| mips | mipsbe | mipseb | mipsel | mipsle \
	| mips16 \
	| mips64 | mips64el \
	| mips64octeon | mips64octeonel \
	| mips64orion | mips64orionel \
	| mips64r5900 | mips64r5900el \
	| mips64vr | mips64vrel \
	| mips64vr4100 | mips64vr4100el \
	| mips64vr4300 | mips64vr4300el \
	| mips64vr5000 | mips64vr5000el \
	| mips64vr5900 | mips64vr5900el \
	| mipsisa32 | mipsisa32el \
	| mipsisa32r2 | mipsisa32r2el \
	| mipsisa64 | mipsisa64el \
	| mipsisa64r2 | mipsisa64r2el \
	| mipsisa64sb1 | mipsisa64sb1el \
	| mipsisa64sr71k | mipsisa64sr71kel \
	| mipsr5900 | mipsr5900el \
	| mipstx39 | mipstx39el \
	| mn10200 | mn10300 \
	| moxie \
	| mt \
	| msp430 \
	| nds32 | nds32le | nds32be \
	| nios | nios2 | nios2eb | nios2el \
	| ns16k | ns32k \
	| open8 \
	| or1k | or32 \
	| pdp10 | pdp11 | pj | pjl \
	| powerpc | powerpc64 | powerpc64le | powerpcle \
	| pyramid \
	| rl78 | rx \
	| score \
	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
	| sh64 | sh64le \
	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
	| spu \
	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
	| ubicom32 \
	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
	| we32k \
	| x86 | xc16x | xstormy16 | xtensa \
	| z8k | z80)
		basic_machine=$basic_machine-unknown
		;;
	c54x)
		basic_machine=tic54x-unknown
		;;
	c55x)
		basic_machine=tic55x-unknown
		;;
	c6x)
		basic_machine=tic6x-unknown
		;;
	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
		basic_machine=$basic_machine-unknown
		os=-none
		;;
	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
		;;
	ms1)
		basic_machine=mt-unknown
		;;

	strongarm | thumb | xscale)
		basic_machine=arm-unknown
		;;
	xgate)
		basic_machine=$basic_machine-unknown
		os=-none
		;;
	xscaleeb)
		basic_machine=armeb-unknown
		;;

	xscaleel)
		basic_machine=armel-unknown
		;;

	# We use `pc' rather than `unknown'
	# because (1) that's what they normally are, and
	# (2) the word "unknown" tends to confuse beginning users.
	i*86 | x86_64)
	  basic_machine=$basic_machine-pc
	  ;;
	# Object if more than one company name word.
	*-*-*)
		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
		exit 1
		;;
	# Recognize the basic CPU types with company name.
	580-* \
	| a29k-* \
	| aarch64-* | aarch64_be-* \
	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
	| avr-* | avr32-* \
	| be32-* | be64-* \
	| bfin-* | bs2000-* \
	| c[123]* | c30-* | [cjt]90-* | c4x-* \
	| c8051-* | clipper-* | craynv-* | cydra-* \
	| d10v-* | d30v-* | dlx-* \
	| elxsi-* \
	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
	| h8300-* | h8500-* \
	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
	| hexagon-* \
	| i*86-* | i860-* | i960-* | ia64-* \
	| ip2k-* | iq2000-* \
	| k1om-* \
	| le32-* | le64-* \
	| lm32-* \
	| m32c-* | m32r-* | m32rle-* \
	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
	| microblaze-* | microblazeel-* \
	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
	| mips16-* \
	| mips64-* | mips64el-* \
	| mips64octeon-* | mips64octeonel-* \
	| mips64orion-* | mips64orionel-* \
	| mips64r5900-* | mips64r5900el-* \
	| mips64vr-* | mips64vrel-* \
	| mips64vr4100-* | mips64vr4100el-* \
	| mips64vr4300-* | mips64vr4300el-* \
	| mips64vr5000-* | mips64vr5000el-* \
	| mips64vr5900-* | mips64vr5900el-* \
	| mipsisa32-* | mipsisa32el-* \
	| mipsisa32r2-* | mipsisa32r2el-* \
	| mipsisa64-* | mipsisa64el-* \
	| mipsisa64r2-* | mipsisa64r2el-* \
	| mipsisa64sb1-* | mipsisa64sb1el-* \
	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
	| mipsr5900-* | mipsr5900el-* \
	| mipstx39-* | mipstx39el-* \
	| mmix-* \
	| mt-* \
	| msp430-* \
	| nds32-* | nds32le-* | nds32be-* \
	| nios-* | nios2-* | nios2eb-* | nios2el-* \
	| none-* | np1-* | ns16k-* | ns32k-* \
	| open8-* \
	| orion-* \
	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
	| pyramid-* \
	| rl78-* | romp-* | rs6000-* | rx-* \
	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
	| sparclite-* \
	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
	| tahoe-* \
	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
	| tile*-* \
	| tron-* \
	| ubicom32-* \
	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
	| vax-* \
	| we32k-* \
	| x86-* | x86_64-* | xc16x-* | xps100-* \
	| xstormy16-* | xtensa*-* \
	| ymp-* \
	| z8k-* | z80-*)
		;;
	# Recognize the basic CPU types without company name, with glob match.
	xtensa*)
		basic_machine=$basic_machine-unknown
		;;
	# Recognize the various machine names and aliases which stand
	# for a CPU type and a company and sometimes even an OS.
	386bsd)
		basic_machine=i386-unknown
		os=-bsd
		;;
	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
		basic_machine=m68000-att
		;;
	3b*)
		basic_machine=we32k-att
		;;
	a29khif)
		basic_machine=a29k-amd
		os=-udi
		;;
	abacus)
		basic_machine=abacus-unknown
		;;
	adobe68k)
		basic_machine=m68010-adobe
		os=-scout
		;;
	alliant | fx80)
		basic_machine=fx80-alliant
		;;
	altos | altos3068)
		basic_machine=m68k-altos
		;;
	am29k)
		basic_machine=a29k-none
		os=-bsd
		;;
	amd64)
		basic_machine=x86_64-pc
		;;
	amd64-*)
		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	amdahl)
		basic_machine=580-amdahl
		os=-sysv
		;;
	amiga | amiga-*)
		basic_machine=m68k-unknown
		;;
	amigaos | amigados)
		basic_machine=m68k-unknown
		os=-amigaos
		;;
	amigaunix | amix)
		basic_machine=m68k-unknown
		os=-sysv4
		;;
	apollo68)
		basic_machine=m68k-apollo
		os=-sysv
		;;
	apollo68bsd)
		basic_machine=m68k-apollo
		os=-bsd
		;;
	aros)
		basic_machine=i386-pc
		os=-aros
		;;
	aux)
		basic_machine=m68k-apple
		os=-aux
		;;
	balance)
		basic_machine=ns32k-sequent
		os=-dynix
		;;
	blackfin)
		basic_machine=bfin-unknown
		os=-linux
		;;
	blackfin-*)
		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
		os=-linux
		;;
	bluegene*)
		basic_machine=powerpc-ibm
		os=-cnk
		;;
	c54x-*)
		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	c55x-*)
		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	c6x-*)
		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	c90)
		basic_machine=c90-cray
		os=-unicos
		;;
	cegcc)
		basic_machine=arm-unknown
		os=-cegcc
		;;
	convex-c1)
		basic_machine=c1-convex
		os=-bsd
		;;
	convex-c2)
		basic_machine=c2-convex
		os=-bsd
		;;
	convex-c32)
		basic_machine=c32-convex
		os=-bsd
		;;
	convex-c34)
		basic_machine=c34-convex
		os=-bsd
		;;
	convex-c38)
		basic_machine=c38-convex
		os=-bsd
		;;
	cray | j90)
		basic_machine=j90-cray
		os=-unicos
		;;
	craynv)
		basic_machine=craynv-cray
		os=-unicosmp
		;;
	cr16 | cr16-*)
		basic_machine=cr16-unknown
		os=-elf
		;;
	crds | unos)
		basic_machine=m68k-crds
		;;
	crisv32 | crisv32-* | etraxfs*)
		basic_machine=crisv32-axis
		;;
	cris | cris-* | etrax*)
		basic_machine=cris-axis
		;;
	crx)
		basic_machine=crx-unknown
		os=-elf
		;;
	da30 | da30-*)
		basic_machine=m68k-da30
		;;
	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
		basic_machine=mips-dec
		;;
	decsystem10* | dec10*)
		basic_machine=pdp10-dec
		os=-tops10
		;;
	decsystem20* | dec20*)
		basic_machine=pdp10-dec
		os=-tops20
		;;
	delta | 3300 | motorola-3300 | motorola-delta \
	      | 3300-motorola | delta-motorola)
		basic_machine=m68k-motorola
		;;
	delta88)
		basic_machine=m88k-motorola
		os=-sysv3
		;;
	dicos)
		basic_machine=i686-pc
		os=-dicos
		;;
	djgpp)
		basic_machine=i586-pc
		os=-msdosdjgpp
		;;
	dpx20 | dpx20-*)
		basic_machine=rs6000-bull
		os=-bosx
		;;
	dpx2* | dpx2*-bull)
		basic_machine=m68k-bull
		os=-sysv3
		;;
	ebmon29k)
		basic_machine=a29k-amd
		os=-ebmon
		;;
	elxsi)
		basic_machine=elxsi-elxsi
		os=-bsd
		;;
	encore | umax | mmax)
		basic_machine=ns32k-encore
		;;
	es1800 | OSE68k | ose68k | ose | OSE)
		basic_machine=m68k-ericsson
		os=-ose
		;;
	fx2800)
		basic_machine=i860-alliant
		;;
	genix)
		basic_machine=ns32k-ns
		;;
	gmicro)
		basic_machine=tron-gmicro
		os=-sysv
		;;
	go32)
		basic_machine=i386-pc
		os=-go32
		;;
	h3050r* | hiux*)
		basic_machine=hppa1.1-hitachi
		os=-hiuxwe2
		;;
	h8300hms)
		basic_machine=h8300-hitachi
		os=-hms
		;;
	h8300xray)
		basic_machine=h8300-hitachi
		os=-xray
		;;
	h8500hms)
		basic_machine=h8500-hitachi
		os=-hms
		;;
	harris)
		basic_machine=m88k-harris
		os=-sysv3
		;;
	hp300-*)
		basic_machine=m68k-hp
		;;
	hp300bsd)
		basic_machine=m68k-hp
		os=-bsd
		;;
	hp300hpux)
		basic_machine=m68k-hp
		os=-hpux
		;;
	hp3k9[0-9][0-9] | hp9[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hp9k2[0-9][0-9] | hp9k31[0-9])
		basic_machine=m68000-hp
		;;
	hp9k3[2-9][0-9])
		basic_machine=m68k-hp
		;;
	hp9k6[0-9][0-9] | hp6[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hp9k7[0-79][0-9] | hp7[0-79][0-9])
		basic_machine=hppa1.1-hp
		;;
	hp9k78[0-9] | hp78[0-9])
		# FIXME: really hppa2.0-hp
		basic_machine=hppa1.1-hp
		;;
	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
		# FIXME: really hppa2.0-hp
		basic_machine=hppa1.1-hp
		;;
	hp9k8[0-9][13679] | hp8[0-9][13679])
		basic_machine=hppa1.1-hp
		;;
	hp9k8[0-9][0-9] | hp8[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hppa-next)
		os=-nextstep3
		;;
	hppaosf)
		basic_machine=hppa1.1-hp
		os=-osf
		;;
	hppro)
		basic_machine=hppa1.1-hp
		os=-proelf
		;;
	i370-ibm* | ibm*)
		basic_machine=i370-ibm
		;;
	i*86v32)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv32
		;;
	i*86v4*)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv4
		;;
	i*86v)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv
		;;
	i*86sol2)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-solaris2
		;;
	i386mach)
		basic_machine=i386-mach
		os=-mach
		;;
	i386-vsta | vsta)
		basic_machine=i386-unknown
		os=-vsta
		;;
	iris | iris4d)
		basic_machine=mips-sgi
		case $os in
		    -irix*)
			;;
		    *)
			os=-irix4
			;;
		esac
		;;
	isi68 | isi)
		basic_machine=m68k-isi
		os=-sysv
		;;
	m68knommu)
		basic_machine=m68k-unknown
		os=-linux
		;;
	m68knommu-*)
		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
		os=-linux
		;;
	m88k-omron*)
		basic_machine=m88k-omron
		;;
	magnum | m3230)
		basic_machine=mips-mips
		os=-sysv
		;;
	merlin)
		basic_machine=ns32k-utek
		os=-sysv
		;;
	microblaze*)
		basic_machine=microblaze-xilinx
		;;
	mingw64)
		basic_machine=x86_64-pc
		os=-mingw64
		;;
	mingw32)
		basic_machine=i686-pc
		os=-mingw32
		;;
	mingw32ce)
		basic_machine=arm-unknown
		os=-mingw32ce
		;;
	miniframe)
		basic_machine=m68000-convergent
		;;
	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
		basic_machine=m68k-atari
		os=-mint
		;;
	mips3*-*)
		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
		;;
	mips3*)
		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
		;;
	monitor)
		basic_machine=m68k-rom68k
		os=-coff
		;;
	morphos)
		basic_machine=powerpc-unknown
		os=-morphos
		;;
	msdos)
		basic_machine=i386-pc
		os=-msdos
		;;
	ms1-*)
		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
		;;
	msys)
		basic_machine=i686-pc
		os=-msys
		;;
	mvs)
		basic_machine=i370-ibm
		os=-mvs
		;;
	nacl)
		basic_machine=le32-unknown
		os=-nacl
		;;
	ncr3000)
		basic_machine=i486-ncr
		os=-sysv4
		;;
	netbsd386)
		basic_machine=i386-unknown
		os=-netbsd
		;;
	netwinder)
		basic_machine=armv4l-rebel
		os=-linux
		;;
	news | news700 | news800 | news900)
		basic_machine=m68k-sony
		os=-newsos
		;;
	news1000)
		basic_machine=m68030-sony
		os=-newsos
		;;
	news-3600 | risc-news)
		basic_machine=mips-sony
		os=-newsos
		;;
	necv70)
		basic_machine=v70-nec
		os=-sysv
		;;
	next | m*-next )
		basic_machine=m68k-next
		case $os in
		    -nextstep* )
			;;
		    -ns2*)
		      os=-nextstep2
			;;
		    *)
		      os=-nextstep3
			;;
		esac
		;;
	nh3000)
		basic_machine=m68k-harris
		os=-cxux
		;;
	nh[45]000)
		basic_machine=m88k-harris
		os=-cxux
		;;
	nindy960)
		basic_machine=i960-intel
		os=-nindy
		;;
	mon960)
		basic_machine=i960-intel
		os=-mon960
		;;
	nonstopux)
		basic_machine=mips-compaq
		os=-nonstopux
		;;
	np1)
		basic_machine=np1-gould
		;;
	neo-tandem)
		basic_machine=neo-tandem
		;;
	nse-tandem)
		basic_machine=nse-tandem
		;;
	nsr-tandem)
		basic_machine=nsr-tandem
		;;
	op50n-* | op60c-*)
		basic_machine=hppa1.1-oki
		os=-proelf
		;;
	openrisc | openrisc-*)
		basic_machine=or32-unknown
		;;
	os400)
		basic_machine=powerpc-ibm
		os=-os400
		;;
	OSE68000 | ose68000)
		basic_machine=m68000-ericsson
		os=-ose
		;;
	os68k)
		basic_machine=m68k-none
		os=-os68k
		;;
	pa-hitachi)
		basic_machine=hppa1.1-hitachi
		os=-hiuxwe2
		;;
	paragon)
		basic_machine=i860-intel
		os=-osf
		;;
	parisc)
		basic_machine=hppa-unknown
		os=-linux
		;;
	parisc-*)
		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
		os=-linux
		;;
	pbd)
		basic_machine=sparc-tti
		;;
	pbb)
		basic_machine=m68k-tti
		;;
	pc532 | pc532-*)
		basic_machine=ns32k-pc532
		;;
	pc98)
		basic_machine=i386-pc
		;;
	pc98-*)
		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentium | p5 | k5 | k6 | nexgen | viac3)
		basic_machine=i586-pc
		;;
	pentiumpro | p6 | 6x86 | athlon | athlon_*)
		basic_machine=i686-pc
		;;
	pentiumii | pentium2 | pentiumiii | pentium3)
		basic_machine=i686-pc
		;;
	pentium4)
		basic_machine=i786-pc
		;;
	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentiumpro-* | p6-* | 6x86-* | athlon-*)
		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentium4-*)
		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pn)
		basic_machine=pn-gould
		;;
	power)	basic_machine=power-ibm
		;;
	ppc | ppcbe)	basic_machine=powerpc-unknown
		;;
	ppc-* | ppcbe-*)
		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppcle | powerpclittle | ppc-le | powerpc-little)
		basic_machine=powerpcle-unknown
		;;
	ppcle-* | powerpclittle-*)
		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppc64)	basic_machine=powerpc64-unknown
		;;
	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
		basic_machine=powerpc64le-unknown
		;;
	ppc64le-* | powerpc64little-*)
		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ps2)
		basic_machine=i386-ibm
		;;
	pw32)
		basic_machine=i586-unknown
		os=-pw32
		;;
	rdos | rdos64)
		basic_machine=x86_64-pc
		os=-rdos
		;;
	rdos32)
		basic_machine=i386-pc
		os=-rdos
		;;
	rom68k)
		basic_machine=m68k-rom68k
		os=-coff
		;;
	rm[46]00)
		basic_machine=mips-siemens
		;;
	rtpc | rtpc-*)
		basic_machine=romp-ibm
		;;
	s390 | s390-*)
		basic_machine=s390-ibm
		;;
	s390x | s390x-*)
		basic_machine=s390x-ibm
		;;
	sa29200)
		basic_machine=a29k-amd
		os=-udi
		;;
	sb1)
		basic_machine=mipsisa64sb1-unknown
		;;
	sb1el)
		basic_machine=mipsisa64sb1el-unknown
		;;
	sde)
		basic_machine=mipsisa32-sde
		os=-elf
		;;
	sei)
		basic_machine=mips-sei
		os=-seiux
		;;
	sequent)
		basic_machine=i386-sequent
		;;
	sh)
		basic_machine=sh-hitachi
		os=-hms
		;;
	sh5el)
		basic_machine=sh5le-unknown
		;;
	sh64)
		basic_machine=sh64-unknown
		;;
	sparclite-wrs | simso-wrs)
		basic_machine=sparclite-wrs
		os=-vxworks
		;;
	sps7)
		basic_machine=m68k-bull
		os=-sysv2
		;;
	spur)
		basic_machine=spur-unknown
		;;
	st2000)
		basic_machine=m68k-tandem
		;;
	stratus)
		basic_machine=i860-stratus
		os=-sysv4
		;;
	strongarm-* | thumb-*)
		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	sun2)
		basic_machine=m68000-sun
		;;
	sun2os3)
		basic_machine=m68000-sun
		os=-sunos3
		;;
	sun2os4)
		basic_machine=m68000-sun
		os=-sunos4
		;;
	sun3os3)
		basic_machine=m68k-sun
		os=-sunos3
		;;
	sun3os4)
		basic_machine=m68k-sun
		os=-sunos4
		;;
	sun4os3)
		basic_machine=sparc-sun
		os=-sunos3
		;;
	sun4os4)
		basic_machine=sparc-sun
		os=-sunos4
		;;
	sun4sol2)
		basic_machine=sparc-sun
		os=-solaris2
		;;
	sun3 | sun3-*)
		basic_machine=m68k-sun
		;;
	sun4)
		basic_machine=sparc-sun
		;;
	sun386 | sun386i | roadrunner)
		basic_machine=i386-sun
		;;
	sv1)
		basic_machine=sv1-cray
		os=-unicos
		;;
	symmetry)
		basic_machine=i386-sequent
		os=-dynix
		;;
	t3e)
		basic_machine=alphaev5-cray
		os=-unicos
		;;
	t90)
		basic_machine=t90-cray
		os=-unicos
		;;
	tile*)
		basic_machine=$basic_machine-unknown
		os=-linux-gnu
		;;
	tx39)
		basic_machine=mipstx39-unknown
		;;
	tx39el)
		basic_machine=mipstx39el-unknown
		;;
	toad1)
		basic_machine=pdp10-xkl
		os=-tops20
		;;
	tower | tower-32)
		basic_machine=m68k-ncr
		;;
	tpf)
		basic_machine=s390x-ibm
		os=-tpf
		;;
	udi29k)
		basic_machine=a29k-amd
		os=-udi
		;;
	ultra3)
		basic_machine=a29k-nyu
		os=-sym1
		;;
	v810 | necv810)
		basic_machine=v810-nec
		os=-none
		;;
	vaxv)
		basic_machine=vax-dec
		os=-sysv
		;;
	vms)
		basic_machine=vax-dec
		os=-vms
		;;
	vpp*|vx|vx-*)
		basic_machine=f301-fujitsu
		;;
	vxworks960)
		basic_machine=i960-wrs
		os=-vxworks
		;;
	vxworks68)
		basic_machine=m68k-wrs
		os=-vxworks
		;;
	vxworks29k)
		basic_machine=a29k-wrs
		os=-vxworks
		;;
	w65*)
		basic_machine=w65-wdc
		os=-none
		;;
	w89k-*)
		basic_machine=hppa1.1-winbond
		os=-proelf
		;;
	xbox)
		basic_machine=i686-pc
		os=-mingw32
		;;
	xps | xps100)
		basic_machine=xps100-honeywell
		;;
	xscale-* | xscalee[bl]-*)
		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
		;;
	ymp)
		basic_machine=ymp-cray
		os=-unicos
		;;
	z8k-*-coff)
		basic_machine=z8k-unknown
		os=-sim
		;;
	z80-*-coff)
		basic_machine=z80-unknown
		os=-sim
		;;
	none)
		basic_machine=none-none
		os=-none
		;;

# Here we handle the default manufacturer of certain CPU types.  It is in
# some cases the only manufacturer, in others, it is the most popular.
	w89k)
		basic_machine=hppa1.1-winbond
		;;
	op50n)
		basic_machine=hppa1.1-oki
		;;
	op60c)
		basic_machine=hppa1.1-oki
		;;
	romp)
		basic_machine=romp-ibm
		;;
	mmix)
		basic_machine=mmix-knuth
		;;
	rs6000)
		basic_machine=rs6000-ibm
		;;
	vax)
		basic_machine=vax-dec
		;;
	pdp10)
		# there are many clones, so DEC is not a safe bet
		basic_machine=pdp10-unknown
		;;
	pdp11)
		basic_machine=pdp11-dec
		;;
	we32k)
		basic_machine=we32k-att
		;;
	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
		basic_machine=sh-unknown
		;;
	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
		basic_machine=sparc-sun
		;;
	cydra)
		basic_machine=cydra-cydrome
		;;
	orion)
		basic_machine=orion-highlevel
		;;
	orion105)
		basic_machine=clipper-highlevel
		;;
	mac | mpw | mac-mpw)
		basic_machine=m68k-apple
		;;
	pmac | pmac-mpw)
		basic_machine=powerpc-apple
		;;
	*-unknown)
		# Make sure to match an already-canonicalized machine name.
		;;
	*)
		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
		exit 1
		;;
esac

# Here we canonicalize certain aliases for manufacturers.
case $basic_machine in
	*-digital*)
		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
		;;
	*-commodore*)
		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
		;;
	*)
		;;
esac

# Decode manufacturer-specific aliases for certain operating systems.

if [ x"$os" != x"" ]
then
case $os in
	# First match some system type aliases
	# that might get confused with valid system types.
	# -solaris* is a basic system type, with this one exception.
	-auroraux)
		os=-auroraux
		;;
	-solaris1 | -solaris1.*)
		os=`echo $os | sed -e 's|solaris1|sunos4|'`
		;;
	-solaris)
		os=-solaris2
		;;
	-svr4*)
		os=-sysv4
		;;
	-unixware*)
		os=-sysv4.2uw
		;;
	-gnu/linux*)
		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
		;;
	# First accept the basic system types.
	# The portable systems comes first.
	# Each alternative MUST END IN A *, to match a version number.
	# -sysv* is not here because it comes later, after sysvr4.
	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
	      | -sym* | -kopensolaris* | -plan9* \
	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
	      | -aos* | -aros* \
	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
	      | -bitrig* | -openbsd* | -solidbsd* \
	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
	      | -chorusos* | -chorusrdb* | -cegcc* \
	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
	      | -uxpv* | -beos* | -mpeix* | -udk* \
	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
	# Remember, each alternative MUST END IN *, to match a version number.
		;;
	-qnx*)
		case $basic_machine in
		    x86-* | i*86-*)
			;;
		    *)
			os=-nto$os
			;;
		esac
		;;
	-nto-qnx*)
		;;
	-nto*)
		os=`echo $os | sed -e 's|nto|nto-qnx|'`
		;;
	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
		;;
	-mac*)
		os=`echo $os | sed -e 's|mac|macos|'`
		;;
	-linux-dietlibc)
		os=-linux-dietlibc
		;;
	-linux*)
		os=`echo $os | sed -e 's|linux|linux-gnu|'`
		;;
	-sunos5*)
		os=`echo $os | sed -e 's|sunos5|solaris2|'`
		;;
	-sunos6*)
		os=`echo $os | sed -e 's|sunos6|solaris3|'`
		;;
	-opened*)
		os=-openedition
		;;
	-os400*)
		os=-os400
		;;
	-wince*)
		os=-wince
		;;
	-osfrose*)
		os=-osfrose
		;;
	-osf*)
		os=-osf
		;;
	-utek*)
		os=-bsd
		;;
	-dynix*)
		os=-bsd
		;;
	-acis*)
		os=-aos
		;;
	-atheos*)
		os=-atheos
		;;
	-syllable*)
		os=-syllable
		;;
	-386bsd)
		os=-bsd
		;;
	-ctix* | -uts*)
		os=-sysv
		;;
	-nova*)
		os=-rtmk-nova
		;;
	-ns2 )
		os=-nextstep2
		;;
	-nsk*)
		os=-nsk
		;;
	# Preserve the version number of sinix5.
	-sinix5.*)
		os=`echo $os | sed -e 's|sinix|sysv|'`
		;;
	-sinix*)
		os=-sysv4
		;;
	-tpf*)
		os=-tpf
		;;
	-triton*)
		os=-sysv3
		;;
	-oss*)
		os=-sysv3
		;;
	-svr4)
		os=-sysv4
		;;
	-svr3)
		os=-sysv3
		;;
	-sysvr4)
		os=-sysv4
		;;
	# This must come after -sysvr4.
	-sysv*)
		;;
	-ose*)
		os=-ose
		;;
	-es1800*)
		os=-ose
		;;
	-xenix)
		os=-xenix
		;;
	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
		os=-mint
		;;
	-aros*)
		os=-aros
		;;
	-zvmoe)
		os=-zvmoe
		;;
	-dicos*)
		os=-dicos
		;;
	-nacl*)
		;;
	-none)
		;;
	*)
		# Get rid of the `-' at the beginning of $os.
		os=`echo $os | sed 's/[^-]*-//'`
		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
		exit 1
		;;
esac
else

# Here we handle the default operating systems that come with various machines.
# The value should be what the vendor currently ships out the door with their
# machine or put another way, the most popular os provided with the machine.

# Note that if you're going to try to match "-MANUFACTURER" here (say,
# "-sun"), then you have to tell the case statement up towards the top
# that MANUFACTURER isn't an operating system.  Otherwise, code above
# will signal an error saying that MANUFACTURER isn't an operating
# system, and we'll never get to this point.

case $basic_machine in
	score-*)
		os=-elf
		;;
	spu-*)
		os=-elf
		;;
	*-acorn)
		os=-riscix1.2
		;;
	arm*-rebel)
		os=-linux
		;;
	arm*-semi)
		os=-aout
		;;
	c4x-* | tic4x-*)
		os=-coff
		;;
	c8051-*)
		os=-elf
		;;
	hexagon-*)
		os=-elf
		;;
	tic54x-*)
		os=-coff
		;;
	tic55x-*)
		os=-coff
		;;
	tic6x-*)
		os=-coff
		;;
	# This must come before the *-dec entry.
	pdp10-*)
		os=-tops20
		;;
	pdp11-*)
		os=-none
		;;
	*-dec | vax-*)
		os=-ultrix4.2
		;;
	m68*-apollo)
		os=-domain
		;;
	i386-sun)
		os=-sunos4.0.2
		;;
	m68000-sun)
		os=-sunos3
		;;
	m68*-cisco)
		os=-aout
		;;
	mep-*)
		os=-elf
		;;
	mips*-cisco)
		os=-elf
		;;
	mips*-*)
		os=-elf
		;;
	or1k-*)
		os=-elf
		;;
	or32-*)
		os=-coff
		;;
	*-tti)	# must be before sparc entry or we get the wrong os.
		os=-sysv3
		;;
	sparc-* | *-sun)
		os=-sunos4.1.1
		;;
	*-be)
		os=-beos
		;;
	*-haiku)
		os=-haiku
		;;
	*-ibm)
		os=-aix
		;;
	*-knuth)
		os=-mmixware
		;;
	*-wec)
		os=-proelf
		;;
	*-winbond)
		os=-proelf
		;;
	*-oki)
		os=-proelf
		;;
	*-hp)
		os=-hpux
		;;
	*-hitachi)
		os=-hiux
		;;
	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
		os=-sysv
		;;
	*-cbm)
		os=-amigaos
		;;
	*-dg)
		os=-dgux
		;;
	*-dolphin)
		os=-sysv3
		;;
	m68k-ccur)
		os=-rtu
		;;
	m88k-omron*)
		os=-luna
		;;
	*-next )
		os=-nextstep
		;;
	*-sequent)
		os=-ptx
		;;
	*-crds)
		os=-unos
		;;
	*-ns)
		os=-genix
		;;
	i370-*)
		os=-mvs
		;;
	*-next)
		os=-nextstep3
		;;
	*-gould)
		os=-sysv
		;;
	*-highlevel)
		os=-bsd
		;;
	*-encore)
		os=-bsd
		;;
	*-sgi)
		os=-irix
		;;
	*-siemens)
		os=-sysv4
		;;
	*-masscomp)
		os=-rtu
		;;
	f30[01]-fujitsu | f700-fujitsu)
		os=-uxpv
		;;
	*-rom68k)
		os=-coff
		;;
	*-*bug)
		os=-coff
		;;
	*-apple)
		os=-macos
		;;
	*-atari*)
		os=-mint
		;;
	*)
		os=-none
		;;
esac
fi

# Here we handle the case where we know the os, and the CPU type, but not the
# manufacturer.  We pick the logical manufacturer.
vendor=unknown
case $basic_machine in
	*-unknown)
		case $os in
			-riscix*)
				vendor=acorn
				;;
			-sunos*)
				vendor=sun
				;;
			-cnk*|-aix*)
				vendor=ibm
				;;
			-beos*)
				vendor=be
				;;
			-hpux*)
				vendor=hp
				;;
			-mpeix*)
				vendor=hp
				;;
			-hiux*)
				vendor=hitachi
				;;
			-unos*)
				vendor=crds
				;;
			-dgux*)
				vendor=dg
				;;
			-luna*)
				vendor=omron
				;;
			-genix*)
				vendor=ns
				;;
			-mvs* | -opened*)
				vendor=ibm
				;;
			-os400*)
				vendor=ibm
				;;
			-ptx*)
				vendor=sequent
				;;
			-tpf*)
				vendor=ibm
				;;
			-vxsim* | -vxworks* | -windiss*)
				vendor=wrs
				;;
			-aux*)
				vendor=apple
				;;
			-hms*)
				vendor=hitachi
				;;
			-mpw* | -macos*)
				vendor=apple
				;;
			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
				vendor=atari
				;;
			-vos*)
				vendor=stratus
				;;
		esac
		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
		;;
esac

echo $basic_machine$os
exit

# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
abcm2ps-7.8.13/deco.c0000644000175000017500000014466712440017170012327 0ustar  jefjef/*
 * Decoration handling.
 *
 * This file is part of abcm2ps.
 *
 * Copyright (C) 2000-2014, Jean-François Moine.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 */

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#ifdef WIN32
#define lroundf(x) ((long) ((x) + 0.5))
#endif

#include "abc2ps.h"

int defl;		/* decoration flags */

static struct deco_elt {
	struct deco_elt *next, *prev;	/* next/previous decoration */
	struct SYMBOL *s;	/* symbol */
	struct deco_elt *start;	/* start a long decoration ending here */
	unsigned char t;	/* decoration index */
	unsigned char staff;	/* staff */
	unsigned char flags;
#define DE_VAL	0x01		/* put extra value if 1 */
#define DE_UP	0x02		/* above the staff */
#define DE_BELOW 0x08		/* below the staff */
#define DE_GRACE 0x10		/* in grace note */
#define DE_INV 0x20		/* invert the glyph */
#define DE_LDST 0x40		/* start of long decoration */
#define DE_LDEN 0x80		/* end of long decoration */
	unsigned char defl;	/* decorations flags - see DEF_xx */
	float x, y;		/* x, y */
	float v;		/* extra value */
	char *str;		/* string / 0 */
} *deco_head, *deco_tail;

typedef void draw_f(struct deco_elt *de);
static draw_f d_arp, d_cresc, d_near, d_slide, d_upstaff, d_pf, d_trill;

/* decoration table */
/* !! don't change the order of the numbered items !! */
static struct deco_def_s {
	char *name;
	unsigned char func;	/* function index */
	signed char ps_func;	/* postscript function index */
	unsigned char h;	/* height */
	unsigned char wl;	/* width */
	unsigned char wr;
	unsigned char strx;	/* string index - 255=deco name */
	unsigned char ld_end;	/* index of end of long decoration */
	unsigned char dum;
} deco_def_tb[128];

/* c function table */
static draw_f *func_tb[] = {
	d_near,		/* 0 - near the note */
	d_slide,	/* 1 */
	d_arp,		/* 2 */
	d_upstaff,	/* 3 - tied to note */
	d_upstaff,	/* 4 (below the staff) */
	d_trill,	/* 5 */
	d_pf,		/* 6 - tied to staff (dynamic marks) */
	d_cresc,	/* 7 */
};

/* postscript function table */
static char *ps_func_tb[128];

static char *str_tb[32];

/* standard decorations */
static char *std_deco_tb[] = {
	"dot 0 stc 5 1 1",
	"roll 3 cpu 7 6 6",
	"fermata 3 hld 12 7 7",
	"emphasis 3 accent 7 4 4",
	"lowermordent 3 lmrd 10 2 2",
	"coda 3 coda 24 10 10",
	"uppermordent 3 umrd 10 2 2",
	"segno 3 sgno 20 4 4",
	"trill 3 trl 11 4 4",
	"upbow 3 upb 10 5 5",
	"downbow 3 dnb 9 5 5",
	"gmark 3 grm 6 5 5",
	"slide 1 sld 3 7 0",
	"tenuto 0 emb 5 2 2",
	"breath 3 brth 0 1 20",
	"longphrase 3 lphr 0 1 1",
	"mediumphrase 3 mphr 0 1 1",
	"shortphrase 3 sphr 0 1 1",
	"invertedfermata 3 hld 12 7 7",
	"invertedturn 3 turn 10 0 5",
	"invertedturnx 3 turnx 10 0 5",
	"0 3 fng 8 3 3 0",
	"1 3 fng 8 3 3 1",
	"2 3 fng 8 3 3 2",
	"3 3 fng 8 3 3 3",
	"4 3 fng 8 3 3 4",
	"5 3 fng 8 3 3 5",
	"plus 3 dplus 7 3 3",
	"+ 3 dplus 7 3 3",
	"accent 3 accent 7 4 4",
	"> 3 accent 7 4 4",
	"D.C. 3 dacs 16 10 10 D.C.",
	"D.S. 3 dacs 16 10 10 D.S.",
	"fine 3 dacs 16 10 10 FINE",
	"f 6 pf 18 1 7",
	"ff 6 pf 18 2 10",
	"fff 6 pf 18 4 13",
	"ffff 6 pf 18 6 16",
	"mf 6 pf 18 6 13",
	"mp 6 pf 18 6 16",
	"mordent 3 lmrd 10 2 2",
	"open 3 opend 10 2 2",
	"p 6 pf 18 2 8",
	"pp 6 pf 18 5 14",
	"ppp 6 pf 18 8 20",
	"pppp 6 pf 18 10 25",
	"pralltriller 3 umrd 10 2 2",
	"sfz 6 sfz 18 4 10",
	"turn 3 turn 10 0 5",
	"wedge 3 wedge 8 1 1",
	"turnx 3 turnx 10 0 5",
	"trill( 5 - 8 0 0",
	"trill) 5 ltr 8 0 0",
	"snap 3 snap 14 3 3",
	"thumb 3 thumb 14 2 2",
	"arpeggio 2 arp 12 10 0",
	"crescendo( 7 - 18 0 0",
	"crescendo) 7 cresc 18 0 0",
	"<( 7 - 18 0 0",
	"<) 7 cresc 18 0 0",
	"diminuendo( 7 - 18 0 0",
	"diminuendo) 7 dim 18 0 0",
	">( 7 - 18 0 0",
	">) 7 dim 18 0 0",
	"invisible 32 0 0 0 0",
	"beamon 33 0 0 0 0",
	"trem1 34 0 0 0 0",
	"trem2 34 0 0 0 0",
	"trem3 34 0 0 0 0",
	"trem4 34 0 0 0 0",
	"xstem 35 0 0 0 0",
	"beambr1 36 0 0 0 0",
	"beambr2 36 0 0 0 0",
	"rbstop 37 0 0 0 0",
	"/ 38 0 0 6 6",
	"// 38 0 0 6 6",
	"/// 38 0 0 6 6",
	"beam-accel 39 0 0 0 0",
	"beam-rall 39 0 0 0 0",
	0
};

/* user decorations */
static struct u_deco {
	struct u_deco *next;
	char text[2];
} *user_deco;

static struct SYMBOL *first_note;	/* first note/rest of the line */

static void draw_gchord(struct SYMBOL *s, float gchy_min, float gchy_max);

/* -- get the max/min vertical offset -- */
float y_get(int staff,
		int up,
		float x,
		float w)
{
	struct STAFF_S *p_staff;
	int i, j;
	float y;

	p_staff = &staff_tb[staff];
	i = (int) (x / realwidth * YSTEP);
	if (i < 0) {
//		fprintf(stderr, "y_get i:%d\n", i);
		i = 0;
	}
	j = (int) ((x + w) / realwidth * YSTEP);
	if (j >= YSTEP) {
		j = YSTEP - 1;
		if (i > j)
			i = j;
	}
	if (up) {
		y = p_staff->top[i++];
		while (i <= j) {
			if (y < p_staff->top[i])
				y = p_staff->top[i];
			i++;
		}
	} else {
		y = p_staff->bot[i++];
		while (i <= j) {
			if (y > p_staff->bot[i])
				y = p_staff->bot[i];
			i++;
		}
	}
	return y;
}

/* -- adjust the vertical offsets -- */
void y_set(int staff,
		int up,
		float x,
		float w,
		float y)
{
	struct STAFF_S *p_staff;
	int i, j;

	p_staff = &staff_tb[staff];
	i = (int) (x / realwidth * YSTEP);
	/* (may occur when annotation on 'y' at start of an empty staff) */
	if (i < 0) {
//		fprintf(stderr, "y_set i:%d\n", i);
		i = 0;
	}
	j = (int) ((x + w) / realwidth * YSTEP);
	if (j >= YSTEP) {
		j = YSTEP - 1;
		if (i > j)
			i = j;
	}
	if (up) {
		while (i <= j) {
			if (p_staff->top[i] < y)
				p_staff->top[i] = y;
			i++;
		}
	} else {
		while (i <= j) {
			if (p_staff->bot[i] > y)
				p_staff->bot[i] = y;
			i++;
		}
	}
}

/* -- get the staff position of the dynamic and volume marks -- */
static int up_p(struct SYMBOL *s, int pos)
{
	switch (pos) {
	case SL_ABOVE:
		return 1;
	case SL_BELOW:
		return 0;
	}
	if (s->multi != 0)
		return s->multi > 0;
	if (!voice_tb[s->voice].have_ly)
		return 0;

	/* above if the lyrics are below the staff */
	return s->posit.voc != SL_ABOVE;
}

/* -- drawing functions -- */
/* special case for arpeggio */
static void d_arp(struct deco_elt *de)
{
	struct SYMBOL *s;
	struct deco_def_s *dd;
	int m, h;
	float xc, dx;

	s = de->s;
	dd = &deco_def_tb[de->t];
	xc = 0;
	for (m = 0; m <= s->nhd; m++) {
		if (s->as.u.note.accs[m]) {
			dx = 5 + s->shac[m];
		} else {
			dx = 6 - s->shhd[m];
			switch (s->head) {
			case H_SQUARE:
			case H_OVAL:
				dx += 2.5;
				break;
			}
		}
		if (dx > xc)
			xc = dx;
	}
	h = 3 * (s->pits[s->nhd] - s->pits[0]) + 4;
	m = dd->h;		/* minimum height */
	if (h < m)
		h = m;

	de->flags |= DE_VAL;
	de->v = h;
	de->x = s->x - xc;
	de->y = (float) (3 * (s->pits[0] - 18)) - 3;
}

/* special case for crescendo/diminuendo */
static void d_cresc(struct deco_elt *de)
{
	struct SYMBOL *s, *s2;
	struct deco_def_s *dd, *dd2;
	struct deco_elt *de1;
	int up;
	float x, dx, x2;

	if (de->flags & DE_LDST)
		return;
	s2 = de->s;
	de1 = de->start;		/* start of the deco */
	if (de1) {
		s = de1->s;
		x = s->x + 3;
	} else {			/* end without start */
		s = first_note;
		x = s->x - s->wl - 4;
	}
	de->staff = s2->staff;
	de->flags &= ~DE_LDEN;		/* old behaviour */
	de->flags |= DE_VAL;
	up = up_p(s2, s2->posit.dyn);
	if (up)
		de->flags |= DE_UP;

	/* shift the starting point if any dynamic mark on the left */
	if (de1 && de1->prev && de1->prev->s == s
	 && ((de->flags ^ de1->prev->flags) & DE_UP) == 0) {
		dd2 = &deco_def_tb[de1->prev->t];
		if (dd2->func >= 6) {
			x2 = de1->prev->x + de1->prev->v + 4;
			if (x2 > x)
				x = x2;
		}
	}

	if (de->defl & DEF_NOEN) {	/* if no decoration end */
		dx = de->x - x;
		if (dx < 20) {
			x = de->x - 20 - 3;
			dx = 20;
		}
	} else {
		x2 = s2->x;
		if (de->next && de->next->s == s
		 && ((de->flags ^ de->next->flags) & DE_UP) == 0) {
			dd2 = &deco_def_tb[de->next->t];
			if (dd2->func >= 6)	/* if dynamic mark */
				x2 -= 5;
		}
		dx = x2 - x - 4;
		if (dx < 20) {
			x -= (20 - dx) * 0.5;
			if (de->start == 0)
				x -= (20 - dx) * 0.5;
			dx = 20;
		}
	}

	de->v = dx;
	de->x = x;
	dd = &deco_def_tb[de->t];
	de->y = y_get(de->staff, up, x, dx);
	if (!up)
		de->y -= dd->h;
	/* (y_set is done later in draw_deco_staff) */
}

/* near the note (dot, tenuto) */
static void d_near(struct deco_elt *de)
{
	struct SYMBOL *s;
	struct deco_def_s *dd;
	int y, up;

	s = de->s;
	dd = &deco_def_tb[de->t];
	if (s->multi)
		up = s->multi > 0;
	else
		up = s->stem < 0;
	if (up)
		y = s->ymx;
	else
		y = s->ymn - dd->h;
	if (y > -6 && y < 24) {
		if (up)
			y += 3;
		y = (y + 6) / 6 * 6 - 6;	/* between lines */
	}
	if (up)
		s->ymx = y + dd->h;
	else
		s->ymn = y;
	de->y = (float) y;
	de->x = s->x + s->shhd[s->stem >= 0 ? 0 : s->nhd];
	if (dd->name[0] == 'd'			/* if dot decoration */
	 && s->nflags >= -1) {			/* on stem */
		if (up) {
			if (s->stem > 0)
				de->x += STEM_XOFF;
		} else {
			if (s->stem < 0)
				de->x -= STEM_XOFF;
		}
	}
}

/* special case for piano/forte indications */
static void d_pf(struct deco_elt *de)
{
	struct SYMBOL *s;
	struct deco_def_s *dd, *dd2;
	float x, x2;
	char *str;
	int up;

	s = de->s;
	dd = &deco_def_tb[de->t];

	de->v = dd->wl + dd->wr;

	up = up_p(s, s->posit.vol);
	if (up)
		de->flags |= DE_UP;

	x = s->x - dd->wl;
	if (de->prev && de->prev->s == s
	 && ((de->flags ^ de->prev->flags) & DE_UP) == 0) {
		dd2 = &deco_def_tb[de->prev->t];
		if (dd2->func >= 6) {	/* if dynamic mark */
			x2 = de->prev->x + de->prev->v + 4;
			if (x2 > x)
				x = x2;
		}
#if 0
//fixme:test volume shift
// does not work with
//	cE!p!E !fff!Ceg|
	} else if (!up && s->stem < 0 && s->ymn < 10) {
		float y;

		x2 = x - (STEM_XOFF + dd->wr + 4);
		y = y_get(s->staff, up, x2, de->v);
		if (y > s->ymn) {
			x = x2;
		} else {
			x2 -= 3;
			y = y_get(s->staff, up, x2, de->v);
			if (y > s->ymn)
				x = x2;
		}
#endif
	}

	str = dd->name;
	if (dd->strx != 0 && dd->strx != 255)
		str = str_tb[dd->strx];

	de->x = x;
	de->y = y_get(s->staff, up, x, de->v);
	if (!up)
		de->y -= dd->h;
	de->str = str;
	/* (y_set is done later in draw_deco_staff) */
}

/* special case for slide and tremolo */
static void d_slide(struct deco_elt *de)
{
	struct SYMBOL *s;
	int m, yc;
	float xc, dx;

	s = de->s;
	yc = s->pits[0];
	xc = 5;
	for (m = 0; m <= s->nhd; m++) {
		if (s->as.u.note.accs[m]) {
			dx = 4 + s->shac[m];
		} else {
			dx = 5 - s->shhd[m];
			switch (s->head) {
			case H_SQUARE:
			case H_OVAL:
				dx += 2.5;
				break;
			}
		}
		if (s->pits[m] <= yc + 3 && dx > xc)
			xc = dx;
	}
	de->x = s->x - xc;
	de->y = (float) (3 * (yc - 18));
}

/* special case for long trill */
static void d_trill(struct deco_elt *de)
{
	struct SYMBOL *s, *s2;
	struct deco_def_s *dd;
	int staff, up;
	float x, y, w;

	if (de->flags & DE_LDST)
		return;
	s2 = de->s;

	if (de->start) {		/* deco start */
		s = de->start->s;
		x = s->x;
		if (s->as.type == ABC_T_NOTE
		 && s->as.u.note.dc.n > 1)
			x += 10;
	} else {			/* end without start */
		s = first_note;
		x = s->x - s->wl - 4;
	}
	de->staff = staff = s2->staff;

	up = s2->multi >= 0;
	if (de->defl & DEF_NOEN) {	/* if no decoration end */
		w = de->x - x;
		if (w < 20) {
			x = de->x - 20 - 3;
			w = 20;
		}
	} else {
		w = s2->x - x - 6;
		if (s2->as.type == ABC_T_NOTE)
			w -= 6;
		if (w < 20) {
			x -= (20 - w) * 0.5;
			if (de->start == 0)
				x -= (20 - w) * 0.5;
			w = 20;
		}
	}

	dd = &deco_def_tb[de->t];
	y = y_get(staff, up, x, w);
	if (up) {
		float stafft;

		stafft = staff_tb[s->staff].topbar + 2;
		if (y < stafft)
			y = stafft;
	} else {
		float staffb;

		y -= dd->h;
		staffb = staff_tb[s->staff].botbar - 2;
		if (y > staffb)
			y = staffb;
	}
	de->flags &= ~DE_LDEN;
	de->flags |= DE_VAL;
	de->v = w;
	de->x = x;
	de->y = y;
	if (up)
		y += dd->h;
	y_set(staff, up, x, w, y);
	if (up)
		s->ymx = s2->ymx = y;
	else
		s->ymn = s2->ymn = y;
}

/* above (or below) the staff */
static void d_upstaff(struct deco_elt *de)
{
	struct SYMBOL *s;
	struct deco_def_s *dd;
	float x, yc, stafft, staffb, w;
	int inv;

	s = de->s;
	dd = &deco_def_tb[de->t];
	inv = 0;
	x = s->x + s->shhd[s->stem >= 0 ? 0 : s->nhd];
	w = dd->wl + dd->wr;
	stafft = staff_tb[s->staff].topbar + 2;
	staffb = staff_tb[s->staff].botbar - 2;
	if (dd->strx != 0)
		de->str = dd->strx == 255 ? dd->name : str_tb[dd->strx];

	switch (s->posit.orn) {
	case SL_ABOVE:
		de->flags &= ~DE_BELOW;
		break;
	case SL_BELOW:
		de->flags |= DE_BELOW;
		break;
	}

	if (strcmp(dd->name, ">") == 0
	 || strcmp(dd->name, "accent") == 0
	 || strcmp(dd->name, "emphasis") == 0
	 || strcmp(dd->name, "roll") == 0) {
		if (s->multi < 0
		 || (s->multi == 0 && s->stem > 0)) {
			yc = y_get(s->staff, 0, s->x - dd->wl, w);
			if (yc > staffb)
				yc = staffb;
			yc -= dd->h;
			y_set(s->staff, 0, s->x, 0, yc);
			inv = 1;
			s->ymn = yc;
		} else {
			yc = y_get(s->staff, 1, s->x, 0);
			if (yc < stafft)
				yc = stafft;
//			if (s->stem <= 0
//			 && (s->dots == 0 || ((int) s->y % 6)))
//				yc -= 2;
			y_set(s->staff, 1, s->x - dd->wl, w, yc + dd->h);
			s->ymx = yc + dd->h;
		}
	} else if (strcmp(dd->name, "breath") == 0
		|| strcmp(dd->name, "longphrase") == 0
		|| strcmp(dd->name, "mediumphrase") == 0
		|| strcmp(dd->name, "shortphrase") == 0) {
		yc = stafft + 1;
		for (s = s->ts_next; s; s = s->ts_next)
			if (s->shrink != 0)
				break;
		if (s)
			x += (s->x - x) * 0.4;
		else
			x += (realwidth - x) * 0.4;
	} else {
		if (strcmp(dd->name, "invertedturn") == 0
		 || strcmp(dd->name, "invertedturnx") == 0)
			inv = 1;
		if (s->multi >= 0
		 && strcmp(dd->name, "invertedfermata") != 0
		 && !(de->flags & DE_BELOW)) {
			yc = y_get(s->staff, 1, s->x - dd->wl, w);
			if (yc < stafft)
				yc = stafft;
			y_set(s->staff, 1, s->x - dd->wl, w, yc + dd->h);
			s->ymx = yc + dd->h;
		} else {
			yc = y_get(s->staff, 0, s->x - dd->wl, w);
			if (yc > staffb)
				yc = staffb;
			yc -= dd->h;
			y_set(s->staff, 0, s->x - dd->wl, w, yc);
			if (strcmp(dd->name, "fermata") == 0
			 || strcmp(dd->name, "invertedfermata") == 0)
				inv = 1;
			s->ymn = yc;
		}
	}
	if (inv) {
		yc += dd->h;
		de->flags |= DE_INV;
	}
	de->x = x;
	de->y = yc;
}

/* -- add a decoration - from %%deco -- */
/* syntax:
 *	%%deco <name> <c_func> <ps_func> <h> <wl> <wr> [<str>]
 */
void deco_add(char *s)
{
	struct u_deco *d;
	int l;

	l = strlen(s);
	d = malloc(sizeof *user_deco - sizeof user_deco->text + l + 1);
	strcpy(d->text, s);
	d->next = user_deco;
	user_deco = d;
}

static unsigned char deco_build(char *text)
{
	struct deco_def_s *dd;
	int c_func, ideco, h, o, wl, wr, n;
	unsigned l, ps_x, strx;
	char name[32];
	char ps_func[16];

	/* extract the arguments */
	if (sscanf(text, "%15s %d %15s %d %d %d%n",
			name, &c_func, ps_func, &h, &wl, &wr, &n) != 6) {
		error(1, 0, "Invalid deco %s", text);
		return 128;
	}
	if ((unsigned) c_func >= sizeof func_tb / sizeof func_tb[0]
	 && (c_func < 32 || c_func > 39)) {
		error(1, 0, "%%%%deco: bad C function index (%s)", text);
		return 128;
	}
	if (h < 0 || wl < 0 || wr < 0) {
		error(1, 0, "%%%%deco: cannot have a negative value (%s)", text);
		return 128;
	}
	if (h > 50 || wl > 80 || wr > 80) {
		error(1, 0, "%%%%deco: abnormal h/wl/wr value (%s)", text);
		return 128;
	}
	text += n;
	while (isspace((unsigned char) *text))
		text++;

	/* search the decoration */
	for (ideco = 1, dd = &deco_def_tb[1]; ideco < 128; ideco++, dd++) {
		if (!dd->name
		 || strcmp(dd->name, name) == 0)
			break;
	}
	if (ideco == 128) {
		error(1, 0, "Too many decorations");
		return 128;
	}

	/* search the postscript function */
	for (ps_x = 0; ps_x < sizeof ps_func_tb / sizeof ps_func_tb[0]; ps_x++) {
		if (ps_func_tb[ps_x] == 0
		 || strcmp(ps_func_tb[ps_x], ps_func) == 0)
			break;
	}
	if (ps_x == sizeof ps_func_tb / sizeof ps_func_tb[0]) {
		error(1, 0, "Too many postscript functions");
		return 128;
	}

	/* have an index for the string */
	if (*text == '\0') {
		strx = 0;
	} else if (strcmp(text, name) == 0) {
		strx = 255;
	} else {
		for (strx = 1;
		     strx < sizeof str_tb / sizeof str_tb[0];
		     strx++) {
			if (str_tb[strx] == 0) {
				if (*text == '"') {
					text++;
					l = strlen(text);
					str_tb[strx] = malloc(l);
					memcpy(str_tb[strx], text, l - 1);
					str_tb[strx][l - 1] = '\0';
				} else {
					str_tb[strx] = strdup(text);
				}
				break;
			}
			if (strcmp(str_tb[strx], text) == 0)
				break;
		}
		if (strx == sizeof str_tb / sizeof str_tb[0]) {
			error(1, 0, "Too many decoration strings");
			return 128;
		}
	}

	/* set the values */
	if (!dd->name)
		dd->name = strdup(name);	/* new decoration */
	dd->func = c_func;
	if (!ps_func_tb[ps_x]) {
		if (ps_func[0] == '-' && ps_func[1] == '\0')
			ps_x = -1;
		else
			ps_func_tb[ps_x] = strdup(ps_func);
	}
	dd->ps_func = ps_x;
	dd->h = h;
	dd->wl = wl;
	dd->wr = wr;
 	dd->strx = strx;

	/* link the start and end of long decorations */
	l = strlen(name);
	if (l == 0)
		return ideco;
	l--;
	if (name[l] == '(' || name[l] == ')') {
		struct deco_def_s *ddo;

		for (o = 1, ddo = &deco_def_tb[1]; o < 128; o++, ddo++) {
			if (!ddo->name)
				break;
			if (strlen(ddo->name) == l + 1
			 && strncmp(ddo->name, name, l) == 0) {
				if (name[l] == '('
				 && ddo->name[l] == ')') {
					dd->ld_end = o;
					break;
				}
				if (name[l] == ')'
				 && ddo->name[l] == '(') {
					ddo->ld_end = ideco;
					break;
				}
			}
		}
	}
	return ideco;
}

/* -- set the duration of the notes under a feathered beam -- */
static void set_feathered_beam(struct SYMBOL *s1,
				int accel)
{
	struct SYMBOL *s, *s2;
	int n, t, tt, d, b, i;
	float a;

	/* search the end of the beam */
	d = s1->dur;
	s2 = NULL;
	n = 1;
	for (s = (struct SYMBOL *) s1->as.next;
	     s;
	     s = (struct SYMBOL *) s->as.next) {
		if (s->dur != d
		 || (s->as.flags & ABC_F_SPACE))
			break;
		s2 = s;
		n++;
	}
	if (!s2)
		return;
	b = d / 2;			/* smallest note duration */
	a = (float) d / (n - 1);		/* delta duration */
	tt = d * n;
	t = 0;
	if (accel) {				/* !beam-accel! */
		for (s = s1, i = n - 1;
		     s != s2;
		     s = (struct SYMBOL *) s->as.next, i--) {
			d = (int) lroundf(a * i) + b;
			s->dur = d;
			t += d;
		}
	} else {				/* !beam-rall! */
		for (s = s1, i = 0;
		     s != s2;
		     s = (struct SYMBOL *) s->as.next, i++) {
			d = (int) lroundf(a * i) + b;
			s->dur = d;
			t += d;
		}
	}
	s2->dur = tt - t;
}

/* -- convert the decorations -- */
void deco_cnv(struct deco *dc,
		struct SYMBOL *s,
		struct SYMBOL *prev)
{
	int i, j;
	struct deco_def_s *dd;
	unsigned char ideco;
	static char must_note_fmt[] = "Deco !%s! must be on a note";

	for (i = dc->n; --i >= 0; ) {
		if ((ideco = dc->t[i]) == 0)
			continue;
		if (ideco < 128) {
			ideco = deco[ideco];
			if (ideco == 0)
				error(1, s,
					"Notation '%c' not treated", dc->t[i]);
		} else {
			ideco = deco_intern(ideco);
		}
		dc->t[i] = ideco;
		if (ideco == 0)
			continue;

		/* special decorations */
		dd = &deco_def_tb[ideco];
		switch (dd->func) {
		default:
			continue;
		case 32:		/* 32 = invisible */
			s->as.flags |= ABC_F_INVIS;
			break;
		case 33:		/* 33 = beamon */
			s->sflags |= S_BEAM_ON;
			break;
		case 34:		/* 34 = trem1..trem4 */
			if (s->as.type != ABC_T_NOTE
			 || !prev
			 || prev->as.type != ABC_T_NOTE) {
				error(1, s,
					"!%s! must be on the last of a couple of notes",
					dd->name);
				break;
			}
			s->sflags |= (S_TREM2 | S_BEAM_END);
			s->sflags &= ~S_BEAM_ST;
			prev->sflags |= (S_TREM2 | S_BEAM_ST);
			prev->sflags &= ~S_BEAM_END;
			s->u = prev->u = dd->name[4] - '0';
			for (j = 0; j <= s->nhd; j++)
				s->as.u.note.lens[j] *= 2;
			for (j = 0; j <= prev->nhd; j++)
				prev->as.u.note.lens[j] *= 2;
			break;
		case 35:		/* 35 = xstem */
			if (s->as.type != ABC_T_NOTE) {
				error(1, s, must_note_fmt, dd->name);
				break;
			}
			s->sflags |= S_XSTEM;
			break;
		case 36:		/* 36 = beambr1 / beambr2 */
			if (s->as.type != ABC_T_NOTE) {
				error(1, s, must_note_fmt, dd->name);
				break;
			}
			s->sflags |= dd->name[6] == '1' ?
					S_BEAM_BR1 : S_BEAM_BR2;
			break;
		case 37:		/* 37 = rbstop */
			s->sflags |= S_RBSTOP;
			break;
		case 38:		/* 38 = /, // and /// = tremolo */
			if (s->as.type != ABC_T_NOTE) {
				error(1, s, must_note_fmt, dd->name);
				break;
			}
			s->sflags |= S_TREM1;
			s->u = strlen(dd->name);	/* 1, 2 or 3 */
			break;
		case 39:		/* 39 = beam-accel/beam-rall */
			if (s->as.type != ABC_T_NOTE) {
				error(1, s, must_note_fmt, dd->name);
				break;
			}
			s->sflags |= S_FEATHERED_BEAM;
			set_feathered_beam(s, dd->name[5] == 'a');
			break;
		}
		dc->t[i] = 0;			/* already treated */
	}
}

/* -- define a user decoration -- */
static unsigned char user_deco_define(char *name)
{
	struct u_deco *d;
	int l;

	l = strlen(name);
	for (d = user_deco; d; d = d->next) {
		if (strncmp(d->text, name, l) == 0
		 && d->text[l] == ' ')
			return deco_build(d->text);
	}
	return 128;
}

/* -- define a standard decoration -- */
unsigned char deco_define(char *name)
{
	unsigned char ideco;
	int l;

	l = strlen(name);
	for (ideco = 0; ; ideco++) {
		if (!std_deco_tb[ideco])
			return 128;
		if (strncmp(std_deco_tb[ideco], name, l) == 0
		 && std_deco_tb[ideco][l] == ' ')
			break;
	}
	return deco_build(std_deco_tb[ideco]);
}

/* -- convert the external deco number to the internal one -- */
unsigned char deco_intern(unsigned char ideco)
{
	char *name;

	if (ideco == 0)
		return ideco;
	name = deco_tb[ideco - 128];
	for (ideco = 1; ideco < 128; ideco++) {
		if (!deco_def_tb[ideco].name) {
			ideco = user_deco_define(name);	/* try a user decoration */
			if (ideco == 128)		/* try a standard decoration */
				ideco = deco_define(name);
			break;
		}
		if (strcmp(deco_def_tb[ideco].name, name) == 0)
			break;
	}
	if (ideco == 128) {
		error(1, 0, "Decoration !%s! not treated", name);
		ideco = 0;
	}
	return ideco;
}

/* -- update the x position of a decoration -- */
void deco_update(struct SYMBOL *s, float dx)
{
	struct deco_elt *de;

	for (de = deco_head; de; de = de->next) {
		if (de->s == s) {
			while (de && de->s == s) {
				de->x += dx;
				de = de->next;
			}
			break;
		}
	}
}

/* -- adjust the symbol width -- */
float deco_width(struct SYMBOL *s)
{
	struct deco *dc;
	int i;
	float wl;

	wl = 0;
	if (s->type == BAR)
		dc = &s->as.u.bar.dc;
	else
		dc = &s->as.u.note.dc;
	for (i = dc->n; --i >= 0; ) {
		struct deco_def_s *dd;

		dd =  &deco_def_tb[dc->t[i]];
		switch (dd->func) {
		case 1:			/* slide */
			if (wl < 7)
				wl = 7;
			break;
		case 2:			/* arpeggio */
			if (wl < 14)
				wl = 14;
			break;
		}
	}
	if (wl != 0 && s->prev && s->prev->type == BAR)
		wl -= 3;
	return wl;
}

/* -- draw the decorations -- */
/* (the staves are defined) */
void draw_all_deco(void)
{
	struct deco_elt *de;
	struct deco_def_s *dd;
	int f, staff;
	float x, y, y2, ym;
	float ymid[MAXSTAFF];

	if (!cfmt.dynalign) {
		staff = nstaff;
		y = staff_tb[staff].y;
		while (--staff >= 0) {
			y2 = staff_tb[staff].y;
			ymid[staff] = (y + 24 + y2) * 0.5;
			y = y2;
		}
	}

	for (de = deco_head; de; de = de->next) {
		dd = &deco_def_tb[de->t];
		if ((f = dd->ps_func) < 0)
			continue;
		staff = de->staff;
		y = de->y + staff_tb[staff].y;

		/* center the dynamic marks between two staves */
/*fixme: KO when deco on other voice and same direction*/
		if (dd->func >= 6 && !cfmt.dynalign
		 && (((de->flags & DE_UP) && staff > 0)
		  || (!(de->flags & DE_UP) && staff < nstaff))) {
			if (de->flags & DE_UP)
				ym = ymid[--staff];
			else
				ym = ymid[staff++];
			ym -= dd->h * 0.5;
			if (((de->flags & DE_UP) && y < ym)
			 || (!(de->flags & DE_UP) && y > ym)) {
				struct SYMBOL *s;

				s = de->s;
				if (s->staff > staff) {
					while (s->staff != staff)
						s = s->ts_prev;
				} else if (s->staff < staff) {
					while (s->staff != staff)
						s = s->ts_next;
				}
				y2 = y_get(staff, !(de->flags & DE_UP),
							de->x, de->v)
					+ staff_tb[staff].y;
				if (de->flags & DE_UP)
					y2 -= dd->h;
				if (((de->flags & DE_UP) && y2 > ym)
				 || (!(de->flags & DE_UP) && y2 < ym)) {
					y = ym;
					y_set(staff, de->flags & DE_UP,
							de->x, de->v,
						  ((de->flags & DE_UP) ? y + dd->h : y)
						- staff_tb[staff].y);
				}
			}
		}

		set_scale(de->s);
		set_defl(de->defl);
/*fixme: scaled or not?*/
		if (de->flags & DE_VAL)
			putf(de->v);
		if (de->str) {
			char *p, *q;

			a2b("(");
			q = p = de->str;
			while (*p != '\0') {
				if (*p == '(' || *p == ')') {
					if (p != q)
						a2b("%.*s", (int) (p - q), q);
					a2b("\\");
					q = p;
				}
				p++;
			}
			if (p != q)
				a2b("%.*s", (int) (p - q), q);
			a2b(")");
		}
		putxy(de->x, y);
		if (de->flags & DE_LDEN) {
			if (de->start) {
				x = de->start->x;
				y = de->start->y + staff_tb[de->start->staff].y;
			} else {
				x = first_note->x - first_note->wl - 4;
			}
			if (x > de->x - 20)
				x = de->x - 20;
			putxy(x, y);
		}
		if (de->flags & DE_GRACE) {
			if (de->flags & DE_INV)
				a2b("gsave T 0.7 -0.7 scale 0 0 %s grestore\n",
						ps_func_tb[f]);
			else
				a2b("gsave T 0.7 dup scale 0 0 %s grestore\n",
						ps_func_tb[f]);
		} else {
			if (de->flags & DE_INV)
				a2b("gsave 1 -1 scale neg %s grestore\n",
						ps_func_tb[f]);
			else
				a2b("%s\n", ps_func_tb[f]);
		}
	}
	set_sscale(-1);			/* restore the scale */
}

/* -- draw a decoration relative to a note head -- */
/* return 1 if the decoration is a head */
int draw_deco_head(int ideco, float x, float y, int stem)
{
	struct deco_def_s *dd;
	char *str;

	if (ideco == 0)
		return 0;
	dd = &deco_def_tb[ideco];
	if (dd->ps_func < 0)
		return 0;
	if (cfmt.setdefl)
		set_defl(stem >= 0 ? DEF_STEMUP : 0);
	switch (dd->func) {
	case 2:
	case 5:
	case 7:
		a2b("0 ");
		break;
	case 3:
	case 4:
		if (dd->strx == 0)
			break;
		/* fall thru */
	case 6:
		str = dd->name;
		if (dd->strx != 0 && dd->strx != 255)
			str = str_tb[dd->strx];
		a2b("(%s)", str);
		break;
	}
	putxy(x, y);
	a2b("%s ", ps_func_tb[dd->ps_func]);
	return strncmp(dd->name, "head-", 5) == 0;
}

/* -- draw the chord decorations relative to the heads -- */
void draw_all_deco_head(struct SYMBOL *s, float x, float y)
{
	int k;
	unsigned char ideco;
	struct deco *dc;
	struct deco_def_s *dd;

	dc = &s->as.u.note.dc;
	for (k = dc->n; --k >= 0; ) {
		if (k >= dc->h && k < dc->s)	/* skip the head decorations */
			continue;
		if ((ideco = dc->t[k]) == 0)
			continue;
		dd = &deco_def_tb[ideco];

		if (strncmp(dd->name, "head-", 5) != 0)
			continue;
		draw_deco_head(ideco, x, y, s->stem);
	}
}

/* -- create the deco elements, and treat the near ones -- */
static void deco_create(struct SYMBOL *s,
			struct deco *dc)
{
	int k, l, posit;
	unsigned char ideco;
	struct deco_def_s *dd;
	struct deco_elt *de;
#if 1
/*fixme:pb with decorations above the staff*/
	for (k = 0; k < dc->n; k++) {
		if (k >= dc->h && k < dc->s)	/* skip the head decorations */
			continue;
		if ((ideco = dc->t[k]) == 0)
			continue;
		dd = &deco_def_tb[ideco];
#else
	int i, j;
	struct deco_def_s *d_tb[MAXDC];

	/* the decorations above the staff must be treated in reverse order */ 
	memset(&d_tb, 0, sizeof d_tb);
	i = 0;
	j = dc->n;
	for (k = 0; k < dc->n; k++) {
		if (k >= dc->h && k < dc->s)	/* skip the head decorations */
			continue;
		if ((ideco = dc->t[k]) == 0)
			continue;
		dd = &deco_def_tb[ideco];
		if (dd->func < 3) {		/* if near the note */
			if (s->multi > 0
			 || (s->multi == 0 && s->stem < 0)) {
				d_tb[--j] = dd;
				continue;
			}
		} else if (dd->func == 3	/* if tied to note (not below) */
			|| dd->func == 5) {
			if (s->multi >= 0) {
				d_tb[--j] = dd;
				continue;
			}
		}
		d_tb[i++] = dd;
	}

	for (k = 0; k < dc->n; k++) {
		if ((dd = d_tb[k]) == 0)
			continue;
#endif
		/* check if hidden */
		switch (dd->func) {
		default:
			posit = 0;
			break;
		case 3:				/* d_upstaff */
		case 4:
//fixme:trill does not work yet
		case 5:				/* trill */
			posit = s->posit.orn;
			break;
		case 6:				/* d_pf */
			posit = s->posit.vol;
			break;
		case 7:				/* d_cresc */
			posit = s->posit.dyn;
			break;
		}
		if (posit == SL_HIDDEN) {
			dc->t[k] = 0;
			continue;
		}

		/* memorize the decorations, but not the head ones */
		if (strncmp(dd->name, "head-", 5) == 0) {
			switch (s->type) {
			case NOTEREST:
				s->sflags |= S_OTHER_HEAD;
				break;
			default:
				error(1, s, "Cannot have !%s! on a bar",
					dd->name);
				break;
			}
			continue;
		}
		de = (struct deco_elt *) getarena(sizeof *de);
		memset(de, 0, sizeof *de);
		de->prev = deco_tail;
		if (!deco_tail)
			deco_head = de;
		else
			deco_tail->next = de;
		deco_tail = de;
		de->s = s;
		de->t = dd - deco_def_tb;
		de->staff = s->staff;
		if (s->as.type == ABC_T_NOTE
		 && (s->as.flags & ABC_F_GRACE))
			de->flags = DE_GRACE;
		if (dd->ld_end != 0) {
			de->flags |= DE_LDST;
		} else {
			l = strlen(dd->name) - 1;
			if (l > 0 && dd->name[l] == ')') {
				if (strchr(dd->name, '(') == 0) {
					de->flags |= DE_LDEN;
					de->defl = DEF_NOST;
				}
			}
		}
		if (cfmt.setdefl && s->stem >= 0)
			de->defl |= DEF_STEMUP;

		if (dd->func >= 3)	/* if not near the note */
			continue;
		if (s->as.type != ABC_T_NOTE) {
			error(1, s,
				"Cannot have !%s! on a rest or a bar",
				dd->name);
			continue;
		}
		func_tb[dd->func](de);
	}
}

/* -- create the decorations and treat the ones near the notes -- */
/* (the staves are not yet defined) */
/* this function must be called first as it builds the deco element table */
void draw_deco_near(void)
{
	struct SYMBOL *s, *g;
	struct deco *dc;
	struct SYMBOL *first;

	deco_head = deco_tail = NULL;
	first = NULL;
	for (s = tsfirst; s; s = s->ts_next) {
		switch (s->type) {
		case BAR:
		case MREST:
			if (s->as.u.bar.dc.n == 0)
				continue;
			dc = &s->as.u.bar.dc;
			break;
		case NOTEREST:
		case SPACE:
			if (!first)
				first = s;
			if (s->as.u.note.dc.n == 0)
				continue;
			dc = &s->as.u.note.dc;
			break;
		case GRACE:
			for (g = s->extra; g; g = g->next) {
				if (g->as.type != ABC_T_NOTE
				 || g->as.u.note.dc.n == 0)
					continue;
				dc = &g->as.u.note.dc;
				deco_create(g, dc);
			}
			/* fall thru */
		default:
			continue;
		}
		deco_create(s, dc);
	}
	first_note = first;
}

/* -- draw the decorations tied to a note -- */
/* (the staves are not yet defined) */
void draw_deco_note(void)
{
	struct deco_elt *de, *de2;
	struct deco_def_s *dd;
	int f, t, staff, voice;

	for (de = deco_head; de; de = de->next) {
		t = de->t;
		dd = &deco_def_tb[t];
		if (de->flags & DE_LDST) {	/* start of long decoration */
			t = dd->ld_end;
			voice = de->s->voice;	/* search in the voice */
			for (de2 = de->next; de2; de2 = de2->next)
				if (de2->t == t && de2->s->voice == voice)
					break;
			if (!de2) {		/* search in the staff */
				staff = de->s->staff;
				for (de2 = de->next; de2; de2 = de2->next)
					if (de2->t == t && de2->s->staff == staff)
						break;
			}
			if (!de2) {		/* no end, insert one */
				de2 = (struct deco_elt *) getarena(sizeof *de2);
				memset(de2, 0, sizeof *de2);
				de2->prev = deco_tail;
				deco_tail->next = de2;
				deco_tail = de2;
				de2->s = de->s;
				de2->t = t;
				de2->defl = DEF_NOEN;
				de2->flags = DE_LDEN;
				de2->x = realwidth - 6;
				de2->y = de->s->y;
			}
			de2->start = de;
			de2->defl &= ~DEF_NOST;
		}
		f = dd->func;
		if (f < 3 || f >= 6)
			continue;	/* not tied to the note */
		if (f == 4)
			de->flags |= DE_BELOW;
		func_tb[f](de);
	}
}

/* -- draw the music elements tied to the staff -- */
/* (the staves are not yet defined) */
void draw_deco_staff(void)
{
	struct SYMBOL *s, *first_gchord;
	struct VOICE_S *p_voice;
	float x, y, w;
	struct deco_elt *de;
	struct {
		float ymin, ymax;
	} minmax[MAXSTAFF];

//	outft = -1;				/* force font output */

	/* search the vertical offset for the guitar chords */
	memset(minmax, 0, sizeof minmax);
	first_gchord = 0;
	for (s = tsfirst; s; s = s->ts_next) {
		struct gch *gch;
		int ix, ig;

		gch = s->gch;
		if (!gch)
			continue;
		if (!first_gchord)
			first_gchord = s;
		ig = -1;
		for (ix = 0; ix < MAXGCH; ix++, gch++) {
			if (gch->type == '\0')
				break;
			if (gch->type != 'g')
				continue;
			ig = ix;	/* guitar chord closest to the staff */
			if (gch->y < 0)
				break;
		}
		if (ig >= 0) {
			gch = s->gch + ig;
			w = gch->w;
			if (gch->y >= 0) {
				y = y_get(s->staff, 1, s->x, w);
				if (y > minmax[s->staff].ymax)
					minmax[s->staff].ymax = y;
			} else {
				y = y_get(s->staff, 0, s->x, w);
				if (y < minmax[s->staff].ymin)
					minmax[s->staff].ymin = y;
			}
		}
	}

	/* draw the guitar chords if any */
	if (first_gchord) {
		int i;

		for (i = 0; i <= nstaff; i++) {
			int top, bot;

			bot = staff_tb[i].botbar;
			minmax[i].ymin -= 3;
			if (minmax[i].ymin > bot - 10)
				minmax[i].ymin = bot -10;
			top = staff_tb[i].topbar;
			minmax[i].ymax += 3;
			if (minmax[i].ymax < top + 10)
				minmax[i].ymax = top + 10;
		}
		set_sscale(-1);		/* restore the scale parameters */
		for (s = first_gchord; s; s = s->ts_next) {
			if (!s->gch)
				continue;
			switch (s->type) {
			case NOTEREST:
			case SPACE:
			case MREST:
				break;
			case BAR:
				if (!s->as.u.bar.repeat_bar)
					break;
			default:
				continue;
			}
			draw_gchord(s, minmax[s->staff].ymin,
					minmax[s->staff].ymax);
		}
	}

	/* draw the repeat brackets */
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		struct SYMBOL *s1, *s2, *first_repeat;
		float y2;
		int i, repnl;

		if (p_voice->second || !p_voice->sym)
			continue;

		/* search the max y offset and set the end of bracket */
		y = staff_tb[p_voice->staff].topbar + 6 + 20;
		first_repeat = 0;
		for (s = p_voice->sym->next; s; s = s->next) {
			if (s->type != BAR
			 || !s->as.u.bar.repeat_bar
			 || (s->sflags & S_NOREPBRA))
				continue;
/*fixme: line cut on repeat!*/
			if (!s->next)
				break;
			if (!first_repeat)
				first_repeat = s;
			s1 = s;

			/* a bracket may be 4 measures
			 * but only 2 measures when it has no start */
			i = s1->as.text ? 4 : 2;
			for (;;) {
				if (!s->next)
					break;
				s = s->next;
				if (s->sflags & S_RBSTOP)
					break;
				if (s->type != BAR)
					continue;
				if (((s->as.u.bar.type & 0xf0)	/* if complex bar */
				   && s->as.u.bar.type != (B_OBRA << 4) + B_CBRA)
				  || s->as.u.bar.type == B_CBRA
				  || s->as.u.bar.repeat_bar)
					break;
				if (--i <= 0) {

					/* have a shorter repeat bracket */
					s = s1;
					i = 2;
					for (;;) {
						s = s->next;
						if (s->type != BAR)
							continue;
						if (--i <= 0)
							break;
					}
					s->sflags |= S_RBSTOP;
					break;
				}
			}
			y2 = y_get(p_voice->staff, 1, s1->x, s->x - s1->x);
			if (y < y2)
				y = y2;

			/* have room for the repeat numbers */
			if (s1->gch) {
				w = s1->gch->w;
				y2 = y_get(p_voice->staff, 1, s1->x + 4, w);
				y2 += cfmt.font_tb[REPEATFONT].size + 2;
				if (y < y2)
					y = y2;
			}
			if (s->as.u.bar.repeat_bar)
				s = s->prev;
		}

		/* draw the repeat indications */
		s = first_repeat;
		if (!s)
			continue;
		set_sscale(p_voice->staff);
		set_font(REPEATFONT);
		repnl = 0;
		for ( ; s; s = s->next) {
			char *p;

			if (s->type != BAR
			 || !s->as.u.bar.repeat_bar
			 || (s->sflags & S_NOREPBRA))
				continue;
			s1 = s;
			for (;;) {
				if (!s->next)
					break;
				s = s->next;
				if (s->sflags & S_RBSTOP)
					break;
				if (s->type != BAR)
					continue;
				if (((s->as.u.bar.type & 0xf0)	/* if complex bar */
				  && s->as.u.bar.type != (B_OBRA << 4) + B_CBRA)
				 || s->as.u.bar.type == B_CBRA
				 || s->as.u.bar.repeat_bar)
					break;
			}
			s2 = s;
			if (s1 == s2)
				break;
			x = s1->x;
			if ((s1->as.u.bar.type & 0x07) == B_COL)
				x -= 4;
			i = 0;				/* no bracket end */
			if (s2->sflags & S_RBSTOP) {
				w = 8;			/* (w = left shift) */
			} else if (s2->type != BAR) {
				w = s2->x - realwidth + 4;
			} else if (((s2->as.u.bar.type & 0xf0)	/* if complex bar */
				 && s2->as.u.bar.type != (B_OBRA << 4) + B_CBRA)
				|| s2->as.u.bar.type == B_CBRA) {
				i = 2;			/* bracket start and stop */
/*fixme:%%staves: cursys moved?*/
				if (s->staff > 0
				 && !(cursys->staff[s->staff - 1].flags & STOP_BAR)) {
					w = s2->wl;
				} else if ((s2->as.u.bar.type & 0x0f) == B_COL) {
					w = 12;
				} else if (!(s2->sflags & S_RRBAR)
					|| s2->as.u.bar.type == B_CBRA) {
					w = 0;		/* explicit repeat end */

					/* if ']', don't display as thick bar */
					if (s2->as.u.bar.type == B_CBRA)
						s2->as.flags |= ABC_F_INVIS;
				} else {
					w = 8;
				}
			} else {
				w = 8;
			}
			w = s2->x - x - w;
			p = s1->as.text;
			if (!p) {
				i--;		/* no bracket start (1) or not drawn */
				p = "";
			}
			if (i == 0 && !s2->next	/* 2nd ending at end of line */
			 && !(s2->sflags & S_RBSTOP)) {
				if (p_voice->bar_start == 0)
					repnl = 1;	/* continue on next line */
			}
			if (i >= 0) {
				a2b("(%s)-%.1f %d ",
					p, cfmt.font_tb[REPEATFONT].size * 0.8 + 1, i);
				putx(w);
				putxy(x, y);
				a2b("y%d repbra\n", s1->staff);
				y_set(s1->staff, 1, x, w, y + 2);
			}
			if (s->as.u.bar.repeat_bar)
				s = s->prev;
		}
		if (repnl) {
			p_voice->bar_start = B_OBRA;
			p_voice->bar_repeat = 1;
		}
	}

	/* create the decorations tied to the staves */
	memset(minmax, 0, sizeof minmax);
	for (de = deco_head; de; de = de->next) {
		struct deco_def_s *dd;

		dd = &deco_def_tb[de->t];
		if (dd->func < 6)		/* if not tied to the staff */
			continue;
		func_tb[dd->func](de);
		if (dd->ps_func < 0)
			continue;
		if (cfmt.dynalign) {
			if (de->flags & DE_UP) {
				if (de->y > minmax[de->staff].ymax)
					minmax[de->staff].ymax = de->y;
			} else {
				if (de->y < minmax[de->staff].ymin)
					minmax[de->staff].ymin = de->y;
			}
		}
	}

	/* and, if wanted, set them at a same vertical offset */
	for (de = deco_head; de; de = de->next) {
		struct deco_def_s *dd;

		dd = &deco_def_tb[de->t];
		if (dd->ps_func < 0
		 || dd->func < 6)
			continue;
		if (cfmt.dynalign) {
			if (de->flags & DE_UP)
				y = minmax[de->staff].ymax;
			else
				y = minmax[de->staff].ymin;
			de->y = y;
		} else {
			y = de->y;
		}
		if (de->flags & DE_UP)
			y += dd->h;
		y_set(de->staff, de->flags & DE_UP, de->x, de->v, y);
	}
}

/* -- draw the guitar chords and annotations -- */
/* (the staves are not yet defined) */
static void draw_gchord(struct SYMBOL *s,
			float gchy_min, float gchy_max)
{
	struct gch *gch;
	int action, ix, ig, box;
	float x, y, w, h, y_above, y_below;
	float hbox, xboxh, xboxl, yboxh, yboxl, expdx;

	/* adjust the vertical offset according to the guitar chords */
//fixme: w may be too small
	w = s->gch->w;
#if 1
	y_above = y_get(s->staff, 1, s->x - 2, w);
	y_below = y_get(s->staff, 0, s->x - 2, w);
#else
	y_above = y_get(s->staff, 1, s->x - 2, w) + 2;
	y_below = y_get(s->staff, 0, s->x - 2, w) - 2;
#endif
	ig = -1;
	for (ix = 0, gch = s->gch; ix < MAXGCH; ix++, gch++) {
		if (gch->type == '\0')
			break;
		if (gch->type != 'g')
			continue;
		ig = ix;	/* index of guitar chord closest to the staff */
		if (gch->y < 0)
			break;
	}
	if (ig >= 0) {
		gch = s->gch + ig;
		if (gch->y >= 0) {
			if (y_above < gchy_max)
				y_above = gchy_max;
		} else {
			if (y_below > gchy_min)
				y_below = gchy_min;
		}
	}

	str_font(s->gch->font);
	set_font(s->gch->font);			/* needed if scaled staff */
	set_sscale(s->staff);
	action = A_GCHORD;
	xboxh = xboxl = s->x;
	yboxh = -100;
	yboxl = 100;
	box = 0;
	expdx = 0;
	for (ix = 0, gch = s->gch; ix < MAXGCH; ix++, gch++) {
		if (gch->type == '\0')
			break;
		h = cfmt.font_tb[gch->font].size;
		str_font(gch->font);
		w = tex_str(s->as.text + gch->idx);
		if (gch->type == 'g') {			/* guitar chord */
			if (!strchr(tex_buf, '\t')) {
				action = A_GCHORD;
			} else {
				struct SYMBOL *next;
				char *r;
				int n;

				/* some TAB: expand the guitar chord */
				x = realwidth;
				next = s->next;
				while (next) {
					switch (next->type) {
					default:
						next = next->next;
						continue;
					case NOTEREST:
					case BAR:
						x = next->x;
						break;
					}
					break;
				}
				n = 0;
				r = tex_buf;
				for (;;) {
					n++;
					r = strchr(r, '\t');
					if (!r)
						break;
					r++;
				}
				expdx = (x - s->x - w) / n;
				action = A_GCHEXP;
			}
		} else {
			action = A_ANNOT;
		}
		x = s->x + gch->x;
		switch (gch->type) {
		case '_':			/* below */
			y = gch->y + y_below;
			y_set(s->staff, 0, x, w, y - h * 0.2 - 2);
			break;
		case '^':			/* above */
			y = gch->y + y_above;
			y_set(s->staff, 1, x, w, y + h * 0.8 + 2);
			break;
		default:			/* guitar chord */
			hbox = gch->box ? 3 : 2;
			if (gch->y >= 0) {
				y = gch->y + y_above;
				y_set(s->staff, 1, x, w, y + h + hbox);
			} else {
				y = gch->y + y_below;
				y_set(s->staff, 0, x, w, y - hbox);
			}
			if (gch->box) {
				if (xboxl > x)
					xboxl = x;
				w += x;
				if (xboxh < w)
					xboxh = w;
				if (yboxl > y)
					yboxl = y;
				if (yboxh < y + h)
					yboxh = y + h;
				box++;
			}
			break;
		case '<':			/* left */
/*fixme: what symbol space?*/
			if (s->as.u.note.accs[0])
				x -= s->shac[0];
			y = s->yav + gch->y;
			break;
		case '>':			/* right */
			x += s->xmx;
			if (s->dots > 0)
				x += 1.5 + 3.5 * s->dots;
			y = s->yav + gch->y;
			break;
		case '@':			/* absolute */
			y = s->yav + gch->y;
			break;
		}
		putxy(x, y + h * 0.2);		/* (descent) */
		a2b("y%d M ", s->staff);
		if (action == A_GCHEXP)
			a2b("%.2f ", expdx);
		str_out(tex_buf, action);
		if (gch->type == 'g' && box > 0)
			a2b(" boxstart");
		a2b("\n");
	}

	/* draw the box of the guitar chords */
	if (xboxh != xboxl) {		/* if any normal guitar chord */
		xboxl -= 2;
		w = xboxh - xboxl + 2;
		putxy(xboxl, yboxl - 2);
#if 1
		a2b("y%d %.1f boxdraw\n",
			s->staff, yboxh - yboxl + 3);
#else
		a2b("y%d %.1f %.1f box\n",
			s->staff, w, yboxh - yboxl + 3);
#endif
	}
}

/* -- draw the measure bar numbers -- */
void draw_measnb(void)
{
	struct SYMBOL *s;
	struct SYSTEM *sy;
	char *showm;
	int any_nb, staff, bar_num;
	float x, y, w, font_size;

	showm = cfmt.measurebox ? "showb" : "show";
	any_nb = 0;

	/* search the first staff */
	sy = cursys;
	for (staff = 0; staff <= nstaff; staff++) {
		if (!sy->staff[staff].empty)
			break;
	}
	if (staff > nstaff)
		return;				/* no visible staff */
//fixme: must use the scale, otherwise bad y offset (y0 empty)
	set_sscale(staff);

	/* leave the measure numbers as unscaled */
	font_size = cfmt.font_tb[MEASUREFONT].size;
	cfmt.font_tb[MEASUREFONT].size /= staff_tb[staff].clef.staffscale;

	s = tsfirst;				/* clef */
	bar_num = nbar;
	if (bar_num > 1) {
		if (cfmt.measurenb == 0) {
			set_font(MEASUREFONT);
			any_nb = 1;
			x = 0;
			w = 20;
//			while (s->staff != staff)
//				s = s->ts_next;
			y = y_get(staff, 1, x, w);
			if (y < staff_tb[staff].topbar + 14)
				y = staff_tb[staff].topbar + 14;
			a2b("0 ");
			puty(y);
			a2b("y%d M(%d)%s", staff, bar_num, showm);
			y_set(staff, 1, x, w, y + cfmt.font_tb[MEASUREFONT].size + 2);
		} else if (bar_num % cfmt.measurenb == 0) {
			for ( ; ; s = s->ts_next) {
				switch (s->type) {
				case TIMESIG:
				case CLEF:
				case KEYSIG:
				case FMTCHG:
				case STBRK:
					continue;
				}
				break;
			}
//			while (s->staff != staff)
//				s = s->ts_next;
			if (s->prev->type != CLEF)
				s = s->prev;
			x = s->x - s->wl;
			set_font(MEASUREFONT);
			any_nb = 1;
			w = cwid('0') * cfmt.font_tb[MEASUREFONT].size;
			if (bar_num >= 10) {
				if (bar_num >= 100)
					w *= 3;
				else
					w *= 2;
			}
			if (cfmt.measurebox)
				w += 4;
			y = y_get(staff, 1, x, w);
			if (y < staff_tb[staff].topbar + 6)
				y = staff_tb[staff].topbar + 6;
			y += 2;
			putxy(x, y);
			a2b("y%d M(%d)%s", staff, bar_num, showm);
			y += cfmt.font_tb[MEASUREFONT].size;
			y_set(staff, 1, x, w, y);
			s->ymx = y;
		}
	}

	for ( ; s; s = s->ts_next) {
		switch (s->type) {
		case STAVES:
			sy = sy->next;
			for (staff = 0; staff < nstaff; staff++) {
				if (!sy->staff[staff].empty)
					break;
			}
			set_sscale(staff);
			continue;
		default:
			continue;
		case BAR:
			break;
		}
		if (s->u <= 0)
			continue;
		bar_num = s->u;
		if (cfmt.measurenb == 0
		 || (bar_num % cfmt.measurenb) != 0
		 || !s->next)
			continue;
//		while (s->staff != staff)
//			s = s->ts_next;
		if (!any_nb) {
			any_nb = 1;
			set_font(MEASUREFONT);
		}
		w = cwid('0') * cfmt.font_tb[MEASUREFONT].size;
		if (bar_num >= 10) {
			if (bar_num >= 100)
				w *= 3;
			else
				w *= 2;
		}
		if (cfmt.measurebox)
			w += 4;
		x = s->x - w * 0.4;
		y = y_get(staff, 1, x, w);
		if (y < staff_tb[staff].topbar + 6)
			y = staff_tb[staff].topbar + 6;
		if (s->next->as.type == ABC_T_NOTE) {
			if (s->next->stem > 0) {
				if (y < s->next->ys - cfmt.font_tb[MEASUREFONT].size)
					y = s->next->ys - cfmt.font_tb[MEASUREFONT].size;
			} else {
				if (y < s->next->y)
					y = s->next->y;
			}
		}
		y += 2;
		a2b(" ");
		putxy(x, y);
		a2b("y%d M(%d)%s", staff, bar_num, showm);
		y += cfmt.font_tb[MEASUREFONT].size;
		y_set(staff, 1, x, w, y);
		s->ymx = y;
	}
	if (any_nb)
		a2b("\n");
	nbar = bar_num;

	cfmt.font_tb[MEASUREFONT].size = font_size;
}

/* -- get the beat from a time signature -- */
static int get_beat(struct meter_s *m)
{
	int top, bot;

	if (m->meter[0].top[0] == 'C') {
		if (m->meter[0].top[0] == '|')
			return BASE_LEN / 2;
		return BASE_LEN / 4;
	}
	if (m->meter[0].bot[0] == '\0')
		return BASE_LEN / 4;
	sscanf(m->meter[0].top, "%d", &top);
	sscanf(m->meter[0].bot, "%d", &bot);
	if (bot >= 8 && top >= 6 && top % 3 == 0)
		return BASE_LEN * 3 / 8;
	return BASE_LEN / bot;
}

/* -- draw the note of the tempo -- */
static void draw_notempo(struct SYMBOL *s, int len, float sc)
{
	int head, dots, flags;
	float dx;

	a2b("gsave %.2f dup scale 8 3 RM currentpoint ", sc);
	identify_note(s, len, &head, &dots, &flags);
	switch (head) {
	case H_OVAL:
		a2b("HD");
		break;
	case H_EMPTY:
		a2b("Hd");
		break;
	default:
		a2b("hd");
		break;
	}
	dx = 4;
	if (dots) {
		float dotx;

		dotx = 8;
		if (flags > 0)
			dotx += 4;
		switch (head) {
		case H_SQUARE:
		case H_OVAL:
			dotx += 2;
			break;
		case H_EMPTY:
			dotx += 1;
			break;
		}
		while (--dots >= 0) {
			a2b(" %.1f 0 dt", dotx);
			dx = dotx;
			dotx += 3.5;
		}
	}
	if (len < SEMIBREVE) {
		if (flags <= 0) {
			a2b(" %d su", STEM);
		} else {
			a2b(" %d %d sfu", flags, STEM);
			if (dx < 6)
				dx = 6;
		}
	}
	a2b(" grestore %.1f 0 RM\n", (dx + 15) * sc);
}

/* -- return the tempo width -- */
float tempo_width(struct SYMBOL *s)
{
	unsigned i;
	float w;

	w = 0;
	if (s->as.u.tempo.str1)
		w += tex_str(s->as.u.tempo.str1);
	if (s->as.u.tempo.value != 0) {
		i = 1;
		while (i < sizeof s->as.u.tempo.length
				/ sizeof s->as.u.tempo.length[0]
		       && s->as.u.tempo.length[i] > 0) {
			w += 10;
			i++;
		}
		w += 6 + cwid(' ') * cfmt.font_tb[TEMPOFONT].size * 6
			+ 10 + 10;
	}
	if (s->as.u.tempo.str2)
		w += tex_str(s->as.u.tempo.str2);
	return w;
}

/* - output a tempo --*/
void write_tempo(struct SYMBOL *s,
		 int beat,
		 float sc)
{
	int top, bot;
	unsigned j;

	if (s->as.u.tempo.str1)
		put_str(s->as.u.tempo.str1, A_LEFT);
	if (s->as.u.tempo.value != 0) {
		sc *= 0.7 * cfmt.font_tb[TEMPOFONT].size / 15.0;
						/*fixme: 15.0 = initial tempofont*/
		if (s->as.u.tempo.length[0] == 0) {
			if (beat == 0)
				beat = get_beat(&voice_tb[cursys->top_voice].meter);
			s->as.u.tempo.length[0] = beat;
		}
		for (j = 0;
		     j < sizeof s->as.u.tempo.length
				/ sizeof s->as.u.tempo.length[0]
			&& s->as.u.tempo.length[j] > 0;
		     j++) {
			draw_notempo(s, s->as.u.tempo.length[j], sc);
		}
		put_str("= ", A_LEFT);
		if (sscanf(s->as.u.tempo.value, "%d/%d", &top, &bot) == 2
		 && bot > 0)
			draw_notempo(s, top * BASE_LEN / bot, sc);
		else
			put_str(s->as.u.tempo.value, A_LEFT);
	}
	if (s->as.u.tempo.str2)
		put_str(s->as.u.tempo.str2, A_LEFT);
}

/* -- draw the parts and the tempo information -- */
/* (the staves are being defined) */
float draw_partempo(int staff, float top)
{
	struct SYMBOL *s, *g;
	int beat, dosh, shift;
	int some_part, some_tempo;
	float h, ht, w, x, y, ymin, dy;

	/* put the tempo indication at top */
	dy = 0;
	ht = 0;
	some_part = some_tempo = 0;

	/* get the minimal y offset */
	ymin = staff_tb[staff].topbar + 12;
	dosh = 0;
	shift = 1;
	x = 0;
	for (s = tsfirst; s; s = s->ts_next) {
		g = s->extra;
		if (!g)
			continue;
		for ( ; g; g = g->next)
			if (g->type == TEMPO)
				break;
		if (!g)
			continue;
		if (!some_tempo) {
			some_tempo = 1;
			str_font(TEMPOFONT);
		}
		w = tempo_width(g);
		y = y_get(staff, 1, s->x - 5, w) + 2;
		if (y > ymin)
			ymin = y;
		if (x >= s->x - 5 && !(dosh & (shift >> 1)))
			dosh |= shift;
		shift <<= 1;
		x = s->x - 5 + w;
	}
	if (some_tempo) {
		ht = cfmt.font_tb[TEMPOFONT].size + 2 + 2;
		y = 2 - ht;
		h = y - ht;
		if (dosh != 0)
			ht *= 2;
		if (top < ymin + ht)
			dy = ymin + ht - top;

		/* draw the tempo indications */
		str_font(TEMPOFONT);
		beat = 0;
		for (s = tsfirst; s; s = s->ts_next) {
			if (!(s->sflags & S_SEQST))
				continue;
			if (s->type == TIMESIG)
				beat = get_beat(&s->as.u.meter);
			g = s->extra;
			if (!g)
				continue;
			for ( ; g; g = g->next)
				if (g->type == TEMPO)
					break;
			if (!g)
				continue;

			/*fixme: cf left shift (-5)*/
			a2b("%.1f %.1f M ", s->x - 5,
					(dosh & 1) ? h : y);
			dosh >>= 1;
			write_tempo(g, beat, 1);
		}
	}

	/* then, put the parts */
/*fixme: should reduce if parts don't overlap tempo...*/
	ymin = staff_tb[staff].topbar + 14;
	for (s = tsfirst; s; s = s->ts_next) {
		g = s->extra;
		if (!g)
			continue;
		for (; g; g = g->next)
			if (g->type == PART)
				break;
		if (!g)
			continue;
		if (!some_part) {
			some_part = 1;
			str_font(PARTSFONT);
		}
		w = tex_str(&g->as.text[2]);
		y = y_get(staff, 1, s->x - 10, w + 15) + 5;
		if (ymin < y)
			ymin = y;
	}
	if (!some_part)
		goto out;

	h = cfmt.font_tb[PARTSFONT].size + 2 + 2;
						/* + cfmt.partsspace; ?? */
	if (top < ymin + h + ht)
		dy = ymin + h + ht - top;

	set_font(PARTSFONT);
	for (s = tsfirst; s; s = s->ts_next) {
		g = s->extra;
		if (!g)
			continue;
		for (; g; g = g->next)
			if (g->type == PART)
				break;
		if (!g)
			continue;
		w = tex_str(&g->as.text[2]);
		a2b("%.1f %.1f M", s->x - 10, 2 - ht - h);
		str_out(tex_buf, A_LEFT);
		if (cfmt.partsbox)
			a2b(" %.1f %.1f %.1f %.1f box",
				s->x - 10 - 2, 2 - ht - h - 4,
				w + 4, h);
		a2b("\n");
	}
out:
	return dy * staff_tb[staff].clef.staffscale;
}

/* -- initialize the default decorations -- */
void reset_deco(void)
{
	memset(&deco, 0, sizeof deco);

	/* standard */
	deco['.'] = deco_define("dot");
#ifdef DECO_IS_ROLL
	deco['~'] = deco_define("roll");
#endif
	deco['H'] = deco_define("fermata");
	deco['L'] = deco_define("emphasis");
	deco['M'] = deco_define("lowermordent");
	deco['O'] = deco_define("coda");
	deco['P'] = deco_define("uppermordent");
	deco['S'] = deco_define("segno");
	deco['T'] = deco_define("trill");
	deco['u'] = deco_define("upbow");
	deco['v'] = deco_define("downbow");

	/* non-standard */
#ifndef DECO_IS_ROLL
	deco['~'] = deco_define("gmark");
#endif
	deco['J'] = deco_define("slide");
	deco['R'] = deco_define("roll");
}

/* -- set the decoration flags -- */
void set_defl(int new_defl)
{
	if (defl == new_defl)
		return;
	defl = new_defl;
	a2b("/defl %d def ", new_defl);
}
abcm2ps-7.8.13/deco.abc0000644000175000017500000003013012254372702012615 0ustar  jefjef%!! here is an experimental decoration extension !!
%!! syntax may change in next releases !!
%
% this option is required for !trem!
% %setdefl 1
%
% == postscript definitions - must be before any tune ==
%
%%beginps
% -- cresc / decresc / dimin
/crdc{		% usage: str x y crdc - cresc, decresc, ..
	/Times-Italic 14 selectfont
	M -6 4 RM show}!
%
% -- alternate piano/forte indication between parenthesis
/apf{		% usage: str x y apf
	M -6 5 RM
	/Times-Italic 16 selectfont(\()show
	/Times-BoldItalic 16 selectfont show
	/Times-Italic 16 selectfont(\))show}!
%
% -- draw parenthesis around a note
/opnot{		% usage: x y opnot
	M -5.5 -3 RM /Times-Roman 15 selectfont(\(   \))show}!
% -- same, but inside a chord (x is not the same)
/opchnot{	% usage: x y opchnot
	M -10.5 -3 RM /Times-Roman 15 selectfont(\(   \))show}!
%
% -- sforzando accent
/sfa{		% usage: x y sfa	
	1.2 SLW M -2.4 4.8 RM
	2.4 8.0 RL
	2.4 -7.4 RL
	-1.0 0.0 RL
	-1.8 6.4 RL
	stroke}!
%
% -- draw octava indication
/octava{	% usage: w x y octava
	exch -10 add exch 2 copy
	M 0 10 RM /Times-Roman 16 selectfont(8)show
	/Times-Roman 12 selectfont(va)show
	M 0 6 RL currentpoint stroke M
	[6] 0 setdash 30 add 0 RL currentpoint stroke M
	[] 0 setdash 0 -6 RL stroke}!
/octavab{	% usage: w x y octavab
	exch -14 add exch 2 copy 
	M 0 2 RM /Times-Roman 16 selectfont(8)show
	/Times-Roman 12 selectfont(va basso)show
	22 add M 0 -6 RL currentpoint stroke M
	[6] 0 setdash 30 add 0 RL stroke
	[] 0 setdash}!
%
% -- write big letters (position marks) above the staff
% (from Guido Gonzato)
/bigl{		% usage: str x y bigl
	/Times-Bold 26 selectfont
	4 add M showc
	1 SLW 1 -2 RM 
	0 22 RL -22 0 RL
	0 -22 RL 22 0 RL stroke}!
% (from Jonas Petersson)
/biglc{		% usage: str x y biglc
	2 copy 5 2 roll /Times-Bold 22 selectfont
	6 add M showc
	1 SLW 13 add newpath
	12 0 360 arc stroke}!
%
% -- pedal glyph
% (from CMN http://ccrma-www.stanford.edu/software/cmn/cmn/cmn.html)
/ped{		% usage: str x y ped
	gsave 4 add exch -10 add exch T 26 dup scale
	0.368 0.074 moveto
	0.341 0.121 0.335 0.147 0.371 0.203 curveto
	0.435 0.289 0.531 0.243 0.488 0.155 curveto
	0.472 0.117 0.434 0.096 0.414 0.080 curveto
	0.429 0.038 0.494 -0.006 0.541 0.075 curveto
	0.559 0.123 0.558 0.224 0.663 0.252 curveto
	0.603 0.354 0.449 0.393 0.461 0.405 curveto
	0.902 0.262 0.705 -0.124 0.555 0.046 curveto
	0.488 -0.032 0.417 0.021 0.389 0.055 curveto
	0.303 -0.018 0.303 -0.020 0.248 0.040 curveto
	0.218 0.108 0.191 0.062 0.164 0.047 curveto
	0.010 -0.056 0.032 0.019 0.124 0.062 curveto
	0.229 0.117 0.200 0.091 0.228 0.195 curveto
	0.240 0.241 0.149 0.250 0.166 0.311 curveto
	0.207 0.493 lineto
	-0.041 0.441 0.049 0.261 0.126 0.387 curveto
	0.138 0.381 lineto
	-0.020 0.119 -0.100 0.472 0.220 0.507 curveto
	0.548 0.486 0.399 0.171 0.254 0.374 curveto
	0.264 0.384 lineto
	0.338 0.259 0.521 0.449 0.228 0.488 curveto
	0.198 0.356 lineto
	0.181 0.304 0.273 0.294 0.262 0.241 curveto
	0.229 0.101 lineto
	0.273 0.070 0.282 -0.038 0.368 0.074 curveto
	0.391 0.094 moveto
	0.456 0.130 0.476 0.171 0.468 0.213 curveto
	0.452 0.276 0.333 0.171 0.391 0.094 curveto
	0.627 0.019 moveto
	0.533 0.041 0.586 0.228 0.678 0.229 curveto
	0.729 0.170 0.712 0.025 0.627 0.019 curveto
	eofill
	0.8 0.04 0.04 0 360 newpath arc fill
	pop grestore}!
%
% -- pedal off glyph
% (from CMN http://ccrma-www.stanford.edu/software/cmn/cmn/cmn.html)
/pedoff{	% usage: str x y ped
	gsave 4 add exch -5 add exch T 26 dup scale
	0.219 0.198 moveto
	0.231 0.172 0.195 0.138 0.162 0.173 curveto
	0.149 0.219 0.206 0.231 0.219 0.198 curveto
	0.144 0.242 moveto
	0.166 0.223 0.193 0.230 0.181 0.267 curveto
	0.178 0.306 0.144 0.302 0.151 0.335 curveto
	0.160 0.381 0.225 0.377 0.224 0.330 curveto
	0.228 0.302 0.198 0.306 0.197 0.267 curveto
	0.194 0.237 0.213 0.222 0.237 0.247 curveto
	0.263 0.276 0.234 0.297 0.268 0.322 curveto
	0.314 0.347 0.354 0.297 0.316 0.259 curveto
	0.296 0.237 0.273 0.266 0.246 0.237 curveto
	0.223 0.217 0.232 0.194 0.266 0.197 curveto
	0.303 0.202 0.302 0.232 0.332 0.228 curveto
	0.381 0.232 0.388 0.156 0.332 0.152 curveto
	0.302 0.148 0.302 0.185 0.266 0.183 curveto
	0.231 0.186 0.228 0.169 0.245 0.143 curveto
	0.273 0.116 0.297 0.141 0.316 0.117 curveto
	0.350 0.075 0.303 0.029 0.258 0.062 curveto
	0.237 0.082 0.261 0.102 0.233 0.133 curveto
	0.212 0.151 0.194 0.147 0.197 0.113 curveto
	0.203 0.075 0.232 0.075 0.230 0.043 curveto
	0.223 -0.004 0.159 -0.002 0.152 0.042 curveto
	0.148 0.075 0.185 0.076 0.183 0.113 curveto
	0.183 0.147 0.163 0.150 0.141 0.133 curveto
	0.113 0.104 0.140 0.079 0.113 0.059 curveto
	0.069 0.037 0.033 0.077 0.063 0.117 curveto
	0.082 0.141 0.104 0.117 0.132 0.142 curveto
	0.153 0.163 0.144 0.188 0.113 0.182 curveto
	0.073 0.182 0.075 0.147 0.046 0.152 curveto
	-0.003 0.152 -0.003 0.227 0.048 0.227 curveto
	0.075 0.231 0.075 0.198 0.113 0.196 curveto
	0.141 0.197 0.147 0.207 0.133 0.237 curveto
	0.102 0.264 0.082 0.237 0.062 0.261 curveto
	0.028 0.302 0.077 0.347 0.118 0.318 curveto
	0.138 0.297 0.116 0.275 0.144 0.242 curveto
	fill pop grestore}!
%
% -- glissendo
/gliss{	% usage: x2 y2 x1 y1 gliss
	gsave exch 13 add exch 2 copy T 0 0 M
	exch 4 -1 roll exch sub 3 1 roll sub	% dx dy
	2 copy exch atan dup rotate	% dx dy alpha
	exch pop cos div		% len
% 	9 sub 0 RL			% simple line
	9 sub 0 8 3 -1 roll{		% squiggly line
		2 -1.15 2.30 150 30 arcn 4 0 T
		2 1.15 2.30 -150 -30 arc 4 0 T pop
	}for
	1 SLW stroke grestore}!
%
% -- upper glissendo
/glissup{	% usage: x y glissup
	gsave T 5 0 T
	25 rotate 10 0 T 0 0 M
	0 8 8{
		2 -1.15 2.30 150 30 arcn 4 0 T
		2 1.15 2.30 -150 -30 arc 4 0 T pop
	}for
	1 SLW stroke grestore}!
%
% -- note decorations
% (sorry for I don't know the name of these: there so many ones)
% The convention I use here is:
%	- t2 or t3: mordent with 2 or 3 peeks
%	- ta or tb: turn from above or from below
%	- b, ub or db: middle, upper or lower bar
/tr3{		% usage: x y tr3 - mordent with 3 peeks
	M 2.2 2.2 RL 2.1 -2.9 RL 0.7 0.7 RL
	2.2 2.2 RL 2.1 -2.9 RL 0.7 0.7 RL
	2.2 2.2 RL 2.1 -2.9 RL 0.7 0.7 RL
	-2.2 -2.2 RL -2.1 2.9 RL -0.7 -0.7 RL
	-2.2 -2.2 RL -2.1 2.9 RL -0.7 -0.7 RL
	-2.2 -2.2 RL -2.1 2.9 RL -0.7 -0.7 RL fill}!
/t2ub{		% usage: x y t2ub - mordent ending with an upper bar
	2 copy umrd 0.6 SLW
	M 5 4 RM 0 6 RL stroke}!
/t3tab{		% usage: x y t3tab - mordent + upper turn and bar
	4 add 2 copy exch 7.5 sub exch tr3 exch 7.5 add exch
	2 copy 0.6 SLW M 2 6 14 6 16 0 RC
	M 8 1 RM 0 6 RL stroke}!
/ubt3ta{	% usage: x y ubt3ta - up bar + mordent + upper turn
	4 add 2 copy 0.6 SLW
	M -7.5 0 RM 0 6 RL stroke
	2 copy exch 7.5 sub exch tr3
	M 7.5 0 RM 2 6 14 6 16 0 RC stroke}!
/tbt3{		% usage: x y tbt3 - low turn + long mordent
	exch 10 sub exch 6 add 2 copy 0.6 SLW
	M -8 0 RM 2 -6 14 -6 16 0 RC stroke
	exch 8 add exch tr3}!
/t2ta{		% usage: x y t2ta - mordent + upper turn
	2 copy umrd
	M 5 4 RM 1 5 9 5 10 0 RC stroke}!
/t3b{		% usage: x y t3b - upper + lower mordent
	2 copy exch -7.5 add exch 4 add tr3 0.6 SLW
	M 2.5 0 RM 0 8 RL stroke}!
/sharp{		% usage: x y sharp - sharp above note
	4 add gsave T 0.6 dup scale 0 0 sh0 grestore}!
/flat{		% usage: x y flat - flat above note
	4 add gsave T 0.6 dup scale 0 0 ft0 grestore}!
/natural{	% usage: x y natural - natural sign above note
	4 add gsave T 0.6 dup scale 0 0 nt0 grestore}!
%
% -- 'treble-8' customization
/octl{
	/Times-BoldItalic 16 selectfont M 5.5 -14 RM(8vb)show}!
%
% -- latin guitar chords
% note: 'Ré' cannot be used
/gcshow{
	dup 0 get
	dup dup 65 ge exch 71 le and{
		65 sub[(La)(Si)(Do)(Re)(Mi)(Fa)(Sol )]exch get show
		dup length 1 sub 1 exch getinterval
	}if show}!
%
% -- 'tr' + long trill
/trtrill{	% usage: w x y trtrill
	2 copy trl
	3 1 roll 9 add 3 1 roll 9 sub 3 1 roll 2 add ltr}!
%
% -- guitar diagrams
/guitar{	% usage: x y guitar
	gsave exch 10 sub exch 8 add T
	1.5 SLW -0.3 24.6 M 20.6 0 RL stroke
	0.6 SLW 0 0 M 20 0 RL 0 6 M 20 0 RL
	0 12 M 20 0 RL 0 18 M 20 0 RL
	0 0 M 0 24 RL 4 0 M 0 24 RL 8 0 M 0 24 RL
	12 0 M 0 24 RL 16 0 M 0 24 RL 20 0 M 0 24 RL
	stroke 0.5 SLW}!
/gdot{newpath 1.4 0 360 arc fill}!
/gx{28 M -1.3 -1.3 RM 2.6 2.6 RL 0 -2.6 RM -2.6 2.6 RL stroke}!
/go{28 newpath 1.5 0 360 arc stroke}!
/Dm{		% usage: x y Dm
	guitar
	0 gx 4 gx 8 go
	20 21 gdot 12 15 gdot 16 9 gdot
	grestore}!
/Bb{
	guitar
	0 gx 20 gx
	4 21 gdot 8 9 gdot 12 9 gdot 16 9 gdot
	grestore}!
/C7{
	guitar
	0 gx 20 go
	16 21 gdot 8 15 gdot 4 9 gdot 12 9 gdot
	grestore}!
%
% -- arpeggio variations
%	arpeggio with arrow 1st version
/arpu{	2 copy 4 index add M -6.5 0 RM 2.5 5 RL 2.5 -5 RL fill
	arp}!
/arpd{	2 copy M -6.5 0 RM 2.5 -5 RL 2.5 5 RL fill
	arp}!
%	arpeggio with arrow other version
% /arpu{	2 copy 4 index add M -7 0 RM 3 5 RL 3 -5 RL
%	0.7 SLW stroke arp}!
% /arpd{	2 copy M -7 0 RM 3 -5 RL 3 5 RL
%	0.7 SLW stroke arp}!
%	arpeggio crossing the staves
% (! this works because the decoration are drawn sorted by time !)
/arps{		% arpeggio start - stack: h x ylow
	exch /x exch def	% memorize 'x'
	add /y exch def}!	% memorize the upper vert offset
/arpe{		% arpeggio end - stack: h x ylow
	3 -1 roll pop		% discard 'h'
	exch dup x gt {pop x} if exch	% have room for accidentals
	y 1 index sub 3 1 roll	% new height
	arp}!
%
% -- optional breath
/brth{6 add /xbr 2 index def /ybr 1 index def
	/Times-BoldItalic 30 selectfont M (,) show}!
/opbrth{pop pop xbr 10 sub ybr 5 sub
	/Times-Roman 20 selectfont M (\(  \)) show}!
%
% -- head decorations / replacement
% lower mordent
/hlmrd{		% usage: x y hlmrd
	exch 12 sub exch 4 sub lmrd}!
% small note head
/shd{		% usage: x y shd
	M 3 1.3 RM
	-1 2.5 -6.5 0 -5.5 -2.5 RC
	1 -2.5 6.5 0 5.5 2.5 RC fill}!
% -- measure bar between two staves (1 and 2)
/hbar{		% usage: x y hbar
	dlw pop dup 0 y0 M 24 y1 lineto stroke}!
%%endps
%
% == decoration definitions ==
%
% actual syntax (see format.txt):
%	%%deco <name> <c_func> <ps_func> <h> <wl> <wr> [<str>]
%
% -- accent near the note / sforzando
%%deco accn 0 accent 8 4 4
%%deco sfa 3 sfa 12 5 5
%
% -- dynamic indication below the staff
%%deco fp 6 pf 18 5 11 fp
%%deco cresc 6 crdc 20 4 28 Cresc.
%%deco decresc 6 crdc 20 4 32 Decresc.
%%deco dimin 6 crdc 20 4 28 Dimin.
%%deco riten 6 crdc 20 8 40 Poco riten.
%
% -- dynamic indication below the staff between parenthesis
%%deco (p) 6 apf 20 8 16 p
%%deco (pp) 6 apf 20 8 24 pp
%%deco (f) 6 apf 20 8 16 f
%%deco (ff) 6 apf 20 8 24 ff
%
% -- repeat indication above the staff
%%deco alcoda 3 dacs 20 0 0 al Coda
%
% -- who asked for a Pedal indication ?
%%deco ped 6 ped 20 0 0
%%deco ped-end 6 pedoff 20 0 0
%
% -- optional note
%%deco () 1 opnot 0 0 0
%
% -- start / stop of octava indication
%%deco 8( 5 - 24 0 0
%%deco 8) 5 octava 24 0 0
%%deco 8b( 7 - 24 0 0
%%deco 8b) 7 octavab 24 0 0
%
% -- big letters
%%deco biga 3 bigl 20 0 0 A
%%deco bigb 3 biglc 20 0 0 B
% ...
%
% -- glissendo
%%deco -( 1 - 0 0 0
%%deco -) 1 gliss 0 0 0
%%deco - 1 glissup 0 2 10
%
% -- note decorations
%%deco t2ub 3 t2ub 12 5 5
%%deco t3tab 3 t3tab 12 8 24
%%deco ubt3ta 3 ubt3ta 12 8 24
%%deco tbt3 3 tbt3 14 14 18
%%deco t2ta 3 t2ta 12 5 15
%%deco t3b 3 t3b 12 5 15
%%deco # 3 sharp 8 0 0
%%deco b 3 flat 8 0 0
%%deco = 3 natural 8 0 0
%
% -- 'tr' + long trill
%%deco tr( 5 - 11 0 0
%%deco tr) 5 trtrill 11 0 0
%
% -- guitar chords
%%deco Dm 3 Dm 36 0 0
%%deco Bb 3 Bb 36 0 0
%%deco C7 3 C7 36 0 0
%
% -- arpeggios
%%deco arpu 2 arpu 0 0 0
%%deco arpd 2 arpd 0 0 0
%%deco arps 2 arps 0 0 0
%%deco arpe 2 arpe 0 0 0
%
% -- optional breath
%%deco opbrth 3 opbrth 0 0 0
%
% -- head decorations
%%deco op 1 opchnot 0 0 0	% optional head
%%deco m 0 hlmrd 0 0 0		% lower mordent on the left
%%deco head-x 0 dsh0 0 0 0	% X head
%%deco head-shd 0 shd 0 0 0	% small head
%
% -- measure bar between two staves
%%deco hbar 3 hbar 0 0 0

X:1
T:Customized decorations
M:C
L:1/8
K:C treble-8
!biga!y!fp!"C"C!t2ub!C !cresc!"D"D!t3tab!D !decresc!"E"E!ubt3ta!E !dimin!"F"F!tbt3!F|\
!mp!"G"G!t2ta!G !(p)!A!t3b!c T!b!!(pp)!A2 P!#!!(f)!B2|M!=!!(ff)!c8|
%
K: clef=treble
!8(!!riten!EF !-!G2 !ped!GA!ped-end!B!8)!c|!8b(!!bigb!C2!()!E2 !tr(!G3!tr)!!8b)!c!alcoda!|\
CE!-(!G2!-)!C2c2|
%
"Dm"!Dm!e3/d/ d6 | "Bb"!Bb!z2 d/d3/ "C7"!C7!cB/A/- AG |\
F!accent!G!accn!AB !sfa!c4||

X:3
T:Decorations with abcm2ps 4.x.x
M:C
L:1/4
%%staves {1 2}
K:C
V:1
!arpu![!op!C!op!Gc]4 !hbar![] !breath!!opbrth!!arpd![CGc]4 |\
	!arps![CGc]4 | z3/[!head-x!B]/ [c!m!eg]2 | c4 ||
V:2
!arpeggio![C,,G,,C,]4 [] [C,,G,,C,]4 |\
	!arpe![C,,G,,C,]4 | [C,,!head-shd!C,][G,,!head-shd!G,]C,2 | C,4 ||
abcm2ps-7.8.13/draw.c0000644000175000017500000033017312461214622012343 0ustar  jefjef/*
 * Drawing functions.
 *
 * This file is part of abcm2ps.
 *
 * Copyright (C) 1998-2015 Jean-François Moine
 * Adapted from abc2ps, Copyright (C) 1996,1997 Michael Methfessel
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 */

#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "abc2ps.h"

struct BEAM {			/* packages info on one beam */
	struct SYMBOL *s1, *s2;
	float a, b;
	short nflags;
};

static char *acc_tb[] = { "", "sh", "nt", "ft", "dsh", "dft" };

/* scaling stuff */
static int scale_voice;		/* staff (0) or voice(1) scaling */
static float cur_scale = 1;	/* voice or staff scale */
static float cur_trans = 0;	/* != 0 when scaled staff */
static float cur_staff = 1;	/* current scaled staff */

static void draw_note(float x,
		      struct SYMBOL *s,
		      int fl);
static void set_tie_room(void);

/* output debug annotations */
static void anno_out(struct SYMBOL *s, char type)
{
	if (s->as.linenum == 0)
		return;
	if (mbf[-1] != '\n')
		*mbf++ = '\n';
	a2b("%%A %c %d %d ", type, s->as.linenum, s->as.colnum);
	putxy(s->x - s->wl - 2, staff_tb[s->staff].y + s->ymn - 2);
	if (type != 'b' && type != 'e')		/* if not beam */
		a2b("%.1f %d", s->wl + s->wr + 4, s->ymx - s->ymn + 4);
	a2b("\n");
}

/* -- up/down shift needed to get k*6 -- */
static float rnd6(float y)
{
	int iy;

	iy = ((int) (y + 2.999) + 12) / 6 * 6 - 12;
	return iy - y;
}

/* -- compute the best vertical offset for the beams -- */
static float b_pos(int grace,
		   int stem,
		   int flags,
		   float b)
{
	float d1, d2, shift, depth;
	float top, bot;

	shift = !grace ? BEAM_SHIFT : 3;
	depth = !grace ? BEAM_DEPTH : 1.7;
	if (stem > 0) {
		bot = b - (flags - 1) * shift - depth;
		if (bot > 26)
			return 0;
		top = b;
	} else {
		top = b + (flags - 1) * shift + depth;
		if (top < -2)
			return 0;
		bot = b;
	}

	d1 = rnd6(top - BEAM_OFFSET);
	d2 = rnd6(bot + BEAM_OFFSET);
	if (d1 * d1 > d2 * d2)
		return d2;
	return d1;
}

/* duplicate a note for beaming continuation */
static struct SYMBOL *sym_dup(struct SYMBOL *s_orig)
{
	struct SYMBOL *s;

	s = (struct SYMBOL *) getarena(sizeof *s);
	memcpy(s, s_orig, sizeof *s);
	s->as.flags |= ABC_F_INVIS;
	s->as.text = NULL;
	memset(s->as.u.note.sl1, 0, sizeof s->as.u.note.sl1);
	memset(s->as.u.note.decs, 0, sizeof s->as.u.note.decs);
	memset(&s->as.u.note.dc, 0, sizeof s->as.u.note.dc);
	s->gch = NULL;
	s->ly = NULL;
	return s;
}

/* -- calculate a beam -- */
/* (the staves may be defined or not) */
static int calculate_beam(struct BEAM *bm,
			  struct SYMBOL *s1)
{
	struct SYMBOL *s, *s2;
	int notes, nflags, staff, voice, two_staves, two_dir;
	float x, y, ys, a, b, max_stem_err;
	float sx, sy, sxx, sxy, syy, a0, stem_xoff, scale;
	static float min_tb[2][6] = {
		{STEM_MIN, STEM_MIN,
			STEM_MIN2, STEM_MIN3, STEM_MIN4, STEM_MIN4},
		{STEM_CH_MIN, STEM_CH_MIN,
			STEM_CH_MIN2, STEM_CH_MIN3, STEM_CH_MIN4, STEM_CH_MIN4}
	};

	/* must have one printed note head */
	if (s1->as.flags & ABC_F_INVIS) {
		if (!s1->next
		 || (s1->next->as.flags & ABC_F_INVIS))
			return 0;
	}

	if (!(s1->sflags & S_BEAM_ST)) {	/* beam from previous music line */
		s = sym_dup(s1);
		s1->prev->next = s;
		s->prev = s1->prev;
		s1->prev = s;
		s->next = s1;
		s1->ts_prev->ts_next = s;
		s->ts_prev = s1->ts_prev;
		s1->ts_prev = s;
		s->ts_next = s1;
		s->x -= 12;
		if (s->x > s1->prev->x + 12)
			s->x = s1->prev->x + 12;
		s->sflags &= S_SEQST;
		s->sflags |= S_BEAM_ST | S_TEMP;
		s->as.u.note.slur_st = 0;
		s->as.u.note.slur_end = 0;
		s1 = s;
	}

	/* search last note in beam */
	notes = nflags = 0;	/* set x positions, count notes and flags */
	two_staves = two_dir = 0;
	staff = s1->staff;
	voice = s1->voice;
	stem_xoff = (s1->as.flags & ABC_F_GRACE) ? GSTEM_XOFF : STEM_XOFF;
	for (s2 = s1; ; s2 = s2->next) {
		if (s2->as.type == ABC_T_NOTE) {
			if (s2->nflags > nflags)
				nflags = s2->nflags;
			notes++;
			if (s2->staff != staff)
				two_staves = 1;
			if (s2->stem != s1->stem)
				two_dir = 1;
			if (s2->sflags & S_BEAM_END)
				break;
		}
		if (!s2->next) {		/* beam towards next music line */
			for (; ; s2 = s2->prev) {
				if (s2->as.type == ABC_T_NOTE)
					break;
			}
			s = sym_dup(s2);
			s->next = s2->next;
			if (s->next)
				s->next->prev = s;
			s2->next = s;
			s->prev = s2;
			s->ts_next = s2->ts_next;
			if (s->ts_next)
				s->ts_next->ts_prev = s;
			s2->ts_next = s;
			s->ts_prev = s2;
			s->sflags &= S_SEQST;
			s->sflags |= S_BEAM_END | S_TEMP;
			s->as.u.note.slur_st = 0;
			s->as.u.note.slur_end = 0;
			s->x += 12;
			if (s->x < realwidth - 12)
				s->x = realwidth - 12;
			s2 = s;
			notes++;
			break;
		}
	}
	bm->s2 = s2;			/* (don't display the flags) */
	if (staff_tb[staff].y == 0) {	/* staves not defined */
		if (two_staves)
			return 0;
	} else {			/* staves defined */
		if (!two_staves && !(s1->as.flags & ABC_F_GRACE)) {
			bm->s1 = s1;	/* beam already calculated */
			bm->a = (s1->ys- s2->ys) / (s1->xs - s2->xs);
			bm->b = s1->ys - s1->xs * bm->a
				+ staff_tb[staff].y;
			bm->nflags = nflags;
			return 1;
		}
	}

	sx = sy = sxx = sxy = syy = 0;	/* linear fit through stem ends */
	for (s = s1; ; s = s->next) {
		if (s->as.type != ABC_T_NOTE)
			continue;
		if ((scale = voice_tb[s->voice].scale) == 1)
			scale = staff_tb[s->staff].clef.staffscale;
		if (s->stem >= 0)
			x = stem_xoff + s->shhd[0];
		else
			x = -stem_xoff + s->shhd[s->nhd];
		x *= scale;
		x += s->x;
		s->xs = x;
		y = s->ys + staff_tb[s->staff].y;
		sx += x; sy += y;
		sxx += x * x; sxy += x * y; syy += y * y;
		if (s == s2)
			break;
	}

	/* beam fct: y=ax+b */
	a = (sxy * notes - sx * sy) / (sxx * notes - sx * sx);
	b = (sy - a * sx) / notes;

	/* the next few lines modify the slope of the beam */
	if (!(s1->as.flags & ABC_F_GRACE)) {
		if (notes >= 3) {
			float hh;

			hh = syy - a * sxy - b * sy;	/* flatten if notes not in line */
			if (hh > 0
			 && hh / (notes - 2) > .5)
				a *= BEAM_FLATFAC;
		}
		if (a >= 0)
			a = BEAM_SLOPE * a / (BEAM_SLOPE + a);	/* max steepness for beam */
		else
			a = BEAM_SLOPE * a / (BEAM_SLOPE - a);
	} else {
		if (a > BEAM_SLOPE)
			a = BEAM_SLOPE;
		else if (a < -BEAM_SLOPE)
			a = -BEAM_SLOPE;
	}

	/* to decide if to draw flat etc. use normalized slope a0 */
	a0 = a * (s2->xs - s1->xs) / (20 * (notes - 1));

	if (a0 * a0 < BEAM_THRESH * BEAM_THRESH)
		a = 0;			/* flat below threshhold */

	b = (sy - a * sx) / notes;	/* recalculate b for new slope */

/*  if (nflags>1) b=b+2*stem;*/	/* leave a bit more room if several beams */

	/* have flat beams when asked */
	if (cfmt.flatbeams) {
		if (!(s1->as.flags & ABC_F_GRACE))
			b = -11 + staff_tb[staff].y;
		else
			b = 35 + staff_tb[staff].y;
		a = 0;
	}

/*fixme: have a look again*/
	/* have room for the symbols in the staff */
	max_stem_err = 0;		/* check stem lengths */
	s = s1;
	if (two_dir) {				/* 2 directions */
/*fixme: more to do*/
		if (!(s1->as.flags & ABC_F_GRACE))
			ys = BEAM_SHIFT;
		else
			ys = 3;
		ys *= (nflags - 1);
		ys += BEAM_DEPTH;
		ys *= .5;
		if (s1->stem != s2->stem && s1->nflags < s2->nflags)
			ys *= s2->stem;
		else
			ys *= s1->stem;
		b += ys;
	} else if (!(s1->as.flags & ABC_F_GRACE)) {	/* normal notes */
		float stem_err, beam_h;

		beam_h = BEAM_DEPTH + BEAM_SHIFT * (nflags - 1);
		while (s->ts_prev->as.type == ABC_T_NOTE
		    && s->ts_prev->time == s->time
		    && s->ts_prev->x > s1->xs)
			s = s->ts_prev;

		for (; s && s->time <= s2->time; s = s->ts_next) {
			if (s->as.type != ABC_T_NOTE
			 || (s->as.flags & ABC_F_INVIS)
			 || (s->staff != staff
			  && s->voice != voice)) {
				continue;
			}
			x = s->voice == voice ? s->xs : s->x;
			ys = a * x + b - staff_tb[s->staff].y;
			if (s->voice == voice) {
				if (s->nhd == 0)
					stem_err = min_tb[0][(unsigned) s->nflags];
				else
					stem_err = min_tb[1][(unsigned) s->nflags];
				if (s->stem > 0) {
					if (s->pits[s->nhd] > 26) {
						stem_err -= 2;
						if (s->pits[s->nhd] > 28)
							stem_err -= 2;
					}
					stem_err -= ys - (float) (3 * (s->pits[s->nhd] - 18));
				} else {
					if (s->pits[0] < 18) {
						stem_err -= 2;
						if (s->pits[0] < 16)
							stem_err -= 2;
					}
					stem_err -= (float) (3 * (s->pits[0] - 18)) - ys;
				}
				stem_err += BEAM_DEPTH + BEAM_SHIFT * (s->nflags - 1);
			} else {
/*fixme: KO when two_staves*/
				if (s1->stem > 0) {
					if (s->stem > 0) {
/*fixme: KO when the voice numbers are inverted*/
						if (s->ymn > ys + 4
						 || s->ymx < ys - beam_h - 2)
							continue;
						if (s->voice > voice)
							stem_err = s->ymx - ys;
						else
							stem_err = s->ymn + 8 - ys;
					} else {
						stem_err = s->ymx - ys;
					}
				} else {
					if (s->stem < 0) {
						if (s->ymx < ys - 4
						 || s->ymn > ys - beam_h - 2)
							continue;
						if (s->voice < voice)
							stem_err = ys - s->ymn;
						else
							stem_err = ys - s->ymx + 8;
					} else {
						stem_err = ys - s->ymn;
					}
				}
				stem_err += 2 + beam_h;
			}
			if (stem_err > max_stem_err)
				max_stem_err = stem_err;
		}
	} else {				/* grace notes */
		for ( ; ; s = s->next) {
			float stem_err;

			ys = a * s->xs + b - staff_tb[s->staff].y;
			stem_err = GSTEM - 2;
			if (s->stem > 0)
				stem_err -= ys - (float) (3 * (s->pits[s->nhd] - 18));
			else
				stem_err += ys - (float) (3 * (s->pits[0] - 18));
			stem_err += 3 * (s->nflags - 1);
			if (stem_err > max_stem_err)
				max_stem_err = stem_err;
			if (s == s2)
				break;
		}
	}

	if (max_stem_err > 0)		/* shift beam if stems too short */
		b += s1->stem * max_stem_err;

	/* have room for the gracenotes, bars and clefs */
/*fixme: test*/
    if (!two_staves && !two_dir)
	for (s = s1->next; ; s = s->next) {
		struct SYMBOL *g;

		switch (s->type) {
		case NOTEREST:		/* cannot move rests in multi-voices */
			if (s->as.type != ABC_T_REST)
				break;
			g = s->ts_next;
			if (!g || g->staff != staff
			 || g->type != NOTEREST)
				break;
//fixme:too much vertical shift if some space above the note
//fixme:this does not fix rest under beam in second voice (ts_prev)
			/*fall thru*/
		case BAR:
#if 1
			if (s->as.flags & ABC_F_INVIS)
#else
//??
			if (!(s->as.flags & ABC_F_INVIS))
#endif
				break;
			/*fall thru*/
		case CLEF:
			y = a * s->x + b;
			if (s1->stem > 0) {
				y = s->ymx - y
					+ BEAM_DEPTH + BEAM_SHIFT * (nflags - 1)
					+ 2;
				if (y > 0)
					b += y;
			} else {
				y = s->ymn - y
					- BEAM_DEPTH - BEAM_SHIFT * (nflags - 1)
					- 2;
				if (y < 0)
					b += y;
			}
			break;
		case GRACE:
			g = s->extra;
			for ( ; g; g = g->next) {
				if (g->type != NOTEREST)
					continue;
				y = a * g->x + b;
				if (s1->stem > 0) {
					y = g->ymx - y
						+ BEAM_DEPTH + BEAM_SHIFT * (nflags - 1)
						+ 2;
					if (y > 0)
						b += y;
				} else {
					y = g->ymn - y
						- BEAM_DEPTH - BEAM_SHIFT * (nflags - 1)
						- 2;
					if (y < 0)
						b += y;
				}
			}
			break;
		}
		if (s == s2)
			break;
	}

	if (a == 0)		/* shift flat beams onto staff lines */
		b += b_pos(s1->as.flags & ABC_F_GRACE, s1->stem, nflags,
				b - staff_tb[staff].y);

	/* adjust final stems and rests under beam */
	for (s = s1; ; s = s->next) {
		float dy;

		switch (s->as.type) {
		case ABC_T_NOTE:
			s->ys = a * s->xs + b - staff_tb[s->staff].y;
			if (s->stem > 0) {
				s->ymx = s->ys + 2.5;
//fixme: hack
				if (s->ts_prev
				 && s->ts_prev->stem > 0
				 && s->ts_prev->staff == s->staff
				 && s->ts_prev->ymn < s->ymx
				 && s->ts_prev->x == s->x
				 && s->shhd[0] == 0) {
					s->ts_prev->x -= 5;	/* fix stem clash */
					s->ts_prev->xs -= 5;
				}
			} else {
				s->ymn = s->ys - 2.5;
			}
			break;
		case ABC_T_REST:
			y = a * s->x + b - staff_tb[s->staff].y;
			dy = BEAM_DEPTH + BEAM_SHIFT * (nflags - 1)
				+ (s->head != H_FULL ? 4 : 9);
			if (s1->stem > 0) {
				y -= dy;
				if (s1->multi == 0 && y > 12)
					y = 12;
				if (s->y <= y)
					break;
			} else {
				y += dy;
				if (s1->multi == 0 && y < 12)
					y = 12;
				if (s->y >= y)
					break;
			}
			if (s->head != H_FULL) {
				int iy;

				iy = ((int) y + 3 + 12) / 6 * 6 - 12;
				y = iy;
			}
			s->y = y;
			break;
		}
		if (s == s2)
			break;
	}

	/* save beam parameters */
	if (staff_tb[staff].y == 0)	/* if staves not defined */
		return 0;
	bm->s1 = s1;
	bm->a = a;
	bm->b = b;
	bm->nflags = nflags;
	return 1;
}

/* -- draw a single beam -- */
/* (the staves are defined) */
static void draw_beam(float x1,
		      float x2,
		      float dy,
		      float h,
		      struct BEAM *bm,
		      int n)			/* beam number (1..n) */
{
	struct SYMBOL *s;
	float y1, dy2;

	s = bm->s1;
	if (n > s->nflags - s->u
	 && (s->sflags & S_TREM2) && s->head != H_EMPTY) {
		if (s->head >= H_OVAL) {
			x1 = s->x + 6;
			x2 = bm->s2->x - 6;
		} else {
			x1 += 5;
			x2 -= 6;
		}
	}

	y1 = bm->a * x1 + bm->b - dy;
	x2 -= x1;
	dy2 = bm->a * x2;

	putf(h);
	putx(x2);
	putf(dy2);
	putxy(x1, y1);
	a2b("bm\n");
}

/* -- draw the beams for one word -- */
/* (the staves are defined) */
static void draw_beams(struct BEAM *bm)
{
	struct SYMBOL *s, *s1, *s2;
	int i, beam_dir;
	float shift, bshift, bstub, bh, da;

	s1 = bm->s1;
/*fixme: KO if many staves with different scales*/
	set_scale(s1);
	s2 = bm->s2;
	if (!(s1->as.flags & ABC_F_GRACE)) {
		bshift = BEAM_SHIFT;
		bstub = BEAM_STUB;
		shift = .34;		/* (half width of the stem) */
		bh = BEAM_DEPTH;
	} else {
		bshift = 3;
		bstub = 3.2;
		shift = .29;
		bh = 1.6;
	}

/*fixme: quick hack for stubs at end of beam and different stem directions*/
	beam_dir = s1->stem;
	if (s1->stem != s2->stem
	 && s1->nflags < s2->nflags)
		beam_dir = s2->stem;
	if (beam_dir < 0)
		bh = -bh;
	if (cur_trans == 0 && cur_scale != 1) {
		bm->a /= cur_scale;
		bm->b = s1->ys - s1->xs * bm->a
			+ staff_tb[s1->staff].y;
		bshift *= cur_scale;
	}

	/* make first beam over whole word and adjust the stem lengths */
	draw_beam(s1->xs - shift, s2->xs + shift, 0., bh, bm, 1);
	da = 0;
	for (s = s1; ; s = s->next) {
		if (s->as.type == ABC_T_NOTE
		 && s->stem != beam_dir)
			s->ys = bm->a * s->xs + bm->b
				- staff_tb[s->staff].y
				+ bshift * (s->nflags - 1) * s->stem
				- bh;
		if (s == s2)
			break;
	}

	if (s1->sflags & S_FEATHERED_BEAM) {
		da = bshift / (s2->xs - s1->xs);
		if (s1->dur > s2->dur) {
			da = -da;
			bshift = da * s1->xs;
		} else {
			bshift = da * s2->xs;
		}
		da = da * beam_dir;
	}

	/* other beams with two or more flags */
	shift = 0;
	for (i = 2; i <= bm->nflags; i++) {
		shift += bshift;
		if (da != 0)
			bm->a += da;
		for (s = s1; ; s = s->next) {
			struct SYMBOL *k1, *k2;
			float x1;

			if (s->as.type != ABC_T_NOTE
			 || s->nflags < i) {
				if (s == s2)
					break;
				continue;
			}
			if ((s->sflags & S_TREM1)
			 && i > s->nflags - s->u) {
				if (s->head >= H_OVAL)
					x1 = s->x;
				else
					x1 = s->xs;
				draw_beam(x1 - 5, x1 + 5,
					  (shift + 2.5) * beam_dir,
					  bh, bm, i);
				if (s == s2)
					break;
				continue;
			}
			k1 = s;
			for (;;) {
				if (s == s2)
					break;
				if ((s->next->type == NOTEREST
				 && s->next->nflags - s->next->u < i)
				  || (s->next->sflags & S_BEAM_BR1)
				  || ((s->next->sflags & S_BEAM_BR2)
					 && i > 2))
					break;
				s = s->next;
			}
			k2 = s;
			while (k2->as.type != ABC_T_NOTE)
				k2 = k2->prev;
			x1 = k1->xs;
			if (k1 == k2) {
				if (k1 == s1) {
					x1 += bstub;
				} else if (k1 == s2) {
					x1 -= bstub;
				} else if ((k1->sflags & S_BEAM_BR1)
				       || ((k1->sflags & S_BEAM_BR2)
					&& i > 2)) {
					x1 += bstub;
				} else {
					struct SYMBOL *k;

					k = k1->next;
					while (k->as.type != ABC_T_NOTE)
						k = k->next;
					if ((k->sflags & S_BEAM_BR1)
					 || ((k->sflags & S_BEAM_BR2)
						&& i > 2)) {
						x1 -= bstub;
					} else {
						k1 = k1->prev;
						while (k1->as.type != ABC_T_NOTE)
							k1 = k1->prev;
						if (k1->nflags < k->nflags
						 || (k1->nflags == k->nflags
							&& k1->dots < k->dots))
							x1 += bstub;
						else
						x1 -= bstub;
					}
				}
			}
			draw_beam(x1, k2->xs,
#if 1
				  shift * beam_dir,
#else
				  shift * k1->stem,	/*fixme: more complicated */
#endif
				  bh, bm, i);
			if (s == s2)
				break;
		}
	}
	if (s1->sflags & S_TEMP)
		unlksym(s1);
	else if (s2->sflags & S_TEMP)
		unlksym(s2);
}

/* -- draw a system brace or bracket -- */
static void draw_sysbra(float x, int staff, int flag)
{
	int i, end;
	float yt, yb;

	while (cursys->staff[staff].empty
	    || staff_tb[staff].clef.stafflines == 0) {
		if (cursys->staff[staff].flags & flag)
			return;
		staff++;
	}
	i = end = staff;
	for (;;) {
		if (!cursys->staff[i].empty
		 && staff_tb[i].clef.stafflines != 0)
			end = i;
		if (cursys->staff[i].flags & flag)
			break;
		i++;
	}
	yt = staff_tb[staff].y + staff_tb[staff].topbar
				* staff_tb[staff].clef.staffscale;
	yb = staff_tb[end].y + staff_tb[end].botbar
				* staff_tb[end].clef.staffscale;
	a2b("%.1f %.1f %.1f %s\n",
	     yt - yb, x, yt,
	     (flag & (CLOSE_BRACE | CLOSE_BRACE2)) ? "brace" : "bracket");
}

/* -- draw the left side of the staves -- */
static void draw_lstaff(float x)
{
	int i, j, l, nst;
	float yb;

	if (cfmt.alignbars)
		return;
	nst = cursys->nstaff;
	l = 0;
	for (i = 0; ; i++) {
		if (cursys->staff[i].flags & (OPEN_BRACE | OPEN_BRACKET))
			l++;
		if (!cursys->staff[i].empty
		 && staff_tb[i].clef.stafflines != 0)
			break;
		if (cursys->staff[i].flags & (CLOSE_BRACE | CLOSE_BRACKET))
			l--;
		if (i == nst)
			break;
	}
	for (j = nst; j > i; j--) {
		if (!cursys->staff[j].empty
		 && staff_tb[j].clef.stafflines != 0)
			break;
	}
	if (i == j && l == 0)
		return;
	set_sscale(-1);
	yb = staff_tb[j].y + staff_tb[j].botbar
				* staff_tb[j].clef.staffscale;
	a2b("%.1f %.1f %.1f bar\n",
	     staff_tb[i].y
		+ staff_tb[i].topbar * staff_tb[i].clef.staffscale
		- yb,
	     x, yb);
	for (i = 0; i <= nst; i++) {
		if (cursys->staff[i].flags & OPEN_BRACE)
			draw_sysbra(x, i, CLOSE_BRACE);
		if (cursys->staff[i].flags & OPEN_BRACKET)
			draw_sysbra(x, i, CLOSE_BRACKET);
		if (cursys->staff[i].flags & OPEN_BRACE2)
			draw_sysbra(x - 6, i, CLOSE_BRACE2);
		if (cursys->staff[i].flags & OPEN_BRACKET2)
			draw_sysbra(x - 6, i, CLOSE_BRACKET2);
	}
}

/* -- draw a staff -- */
static void draw_staff(int staff,
			float x1, float x2)
{
	int nlines;
	float y;

	/* draw the staff */
	set_sscale(staff);
	y = staff_tb[staff].y;
	nlines = cursys->staff[staff].clef.stafflines;
	switch (nlines) {
	case 0:
		return;
	case 1:
		y += 12;
		break;
	case 2:
	case 3:
		y += 6;
		break;
	}
	putx(x2 - x1);
	a2b("%d ", nlines);
	putxy(x1, y);
	a2b("staff\n");
}

/* -- draw the time signature -- */
static void draw_timesig(float x,
			 struct SYMBOL *s)
{
	unsigned i, staff, l, l2;
	char *f, meter[64];
	float dx;

	if (s->as.u.meter.nmeter == 0)
		return;
	staff = s->staff;
	x -= s->wl;
	for (i = 0; i < s->as.u.meter.nmeter; i++) {
		l = strlen(s->as.u.meter.meter[i].top);
		if (l > sizeof s->as.u.meter.meter[i].top)
			l = sizeof s->as.u.meter.meter[i].top;
		if (s->as.u.meter.meter[i].bot[0] != '\0') {
			sprintf(meter, "(%.8s)(%.2s)",
				s->as.u.meter.meter[i].top,
				s->as.u.meter.meter[i].bot);
			f = "tsig";
			l2 = strlen(s->as.u.meter.meter[i].bot);
			if (l2 > sizeof s->as.u.meter.meter[i].bot)
				l2 = sizeof s->as.u.meter.meter[i].bot;
			if (l2 > l)
				l = l2;
		} else switch (s->as.u.meter.meter[i].top[0]) {
			case 'C':
				if (s->as.u.meter.meter[i].top[1] != '|') {
					f = "csig";
				} else {
					f = "ctsig";
					l--;
				}
				meter[0] = '\0';
				break;
			case 'c':
				if (s->as.u.meter.meter[i].top[1] != '.') {
					f = "imsig";
				} else {
					f = "iMsig";
					l--;
				}
				meter[0] = '\0';
				break;
			case 'o':
				if (s->as.u.meter.meter[i].top[1] != '.') {
					f = "pmsig";
				} else {
					f = "pMsig";
					l--;
				}
				meter[0] = '\0';
				break;
			case '(':
			case ')':
				sprintf(meter, "(\\%s)",
					s->as.u.meter.meter[i].top);
				f = "stsig";
				break;
			default:
				sprintf(meter, "(%.8s)",
					s->as.u.meter.meter[i].top);
				f = "stsig";
				break;
		}
		if (meter[0] != '\0')
			a2b("%s ", meter);
		dx = (float) (13 * l);
		putxy(x + dx * .5, staff_tb[staff].y);
		a2b("%s\n", f);
		x += dx;
	}
}

/* -- draw an accidental -- */
static void draw_acc(int acc, int microscale)
{
	int n, d;

	n = micro_tb[acc >> 3];
	if (acc >> 3 != 0
	 && (cfmt.micronewps || microscale)) {
		if (microscale) {
			d = microscale;
			n = acc >> 3;
		} else {
			d = ((n & 0xff) + 1) * 2;
			n = (n >> 8) + 1;
		}
		a2b("%d %s%d ", n, acc_tb[acc & 0x07], d);
	} else {
		a2b("%s%d ", acc_tb[acc & 0x07], n);
	}
}

/* -- draw a key signature -- */
static void draw_keysig(struct VOICE_S *p_voice,
			float x,
			struct SYMBOL *s)
{
	int old_sf = s->u;
	int staff = p_voice->staff;
	float staffb = staff_tb[staff].y;
	int i, clef_ix, shift;
	const signed char *p_seq;

	static const char sharp_cl[7] = {24, 9, 15, 21, 6, 12, 18};
	static const char flat_cl[7] = {12, 18, 24, 9, 15, 21, 6};
	static const signed char sharp1[6] = {-9, 12, -9, -9, 12, -9};
	static const signed char sharp2[6] = {12, -9, 12, -9, 12, -9};
	static const signed char flat1[6] = {9, -12, 9, -12, 9, -12};
	static const signed char flat2[6] = {-12, 9, -12, 9, -12, 9};

	clef_ix = s->pits[0];
	if (clef_ix & 1)
		clef_ix += 7;
	clef_ix /= 2;
	while (clef_ix < 0)
		clef_ix += 7;
	clef_ix %= 7;

	/* normal accidentals */
	if (s->as.u.key.nacc == 0 && !s->as.u.key.empty) {

		/* put neutrals if not 'accidental cancel' */
		if (cfmt.cancelkey || s->as.u.key.sf == 0) {

			/* when flats to sharps, or sharps to flats, */
			if (s->as.u.key.sf == 0
			 || old_sf * s->as.u.key.sf < 0) {

				/* old sharps */
				shift = sharp_cl[clef_ix];
				p_seq = shift > 9 ? sharp1 : sharp2;
				for (i = 0; i < old_sf; i++) {
					putxy(x, staffb + shift);
					a2b("nt0 ");
					shift += *p_seq++;
					x += 5.5;
				}

				/* old flats */
				shift = flat_cl[clef_ix];
				p_seq = shift < 18 ? flat1 : flat2;
				for (i = 0; i > old_sf; i--) {
					putxy(x, staffb + shift);
					a2b("nt0 ");
					shift += *p_seq++;
					x += 5.5;
				}
				if (s->as.u.key.sf != 0)
					x += 3;		/* extra space */

			/* or less sharps or flats */
			} else if (s->as.u.key.sf > 0) {	/* sharps */
				if (s->as.u.key.sf < old_sf) {
					shift = sharp_cl[clef_ix];
					p_seq = shift > 9 ? sharp1 : sharp2;
					for (i = 0; i < s->as.u.key.sf; i++)
						shift += *p_seq++;
					for (; i < old_sf; i++) {
						putxy(x, staffb + shift);
						a2b("nt0 ");
						shift += *p_seq++;
						x += 5.5;
					}
					x += 3;			/* extra space */
				}
			} else /*if (s->as.u.key.sf < 0)*/ {	/* flats */
				if (s->as.u.key.sf > old_sf) {
					shift = flat_cl[clef_ix];
					p_seq = shift < 18 ? flat1 : flat2;
					for (i = 0; i > s->as.u.key.sf; i--)
						shift += *p_seq++;
					for (; i > old_sf; i--) {
						putxy(x, staffb + shift);
						a2b("nt0 ");
						shift += *p_seq++;
						x += 5.5;
					}
					x += 3;			/* extra space */
				}
			}
		}

		/* new sharps */
		shift = sharp_cl[clef_ix];
		p_seq = shift > 9 ? sharp1 : sharp2;
		for (i = 0; i < s->as.u.key.sf; i++) {
			putxy(x, staffb + shift);
			a2b("sh0 ");
			shift += *p_seq++;
			x += 5.5;
		}

		/* new flats */
		shift = flat_cl[clef_ix];
		p_seq = shift < 18 ? flat1 : flat2;
		for (i = 0; i > s->as.u.key.sf; i--) {
			putxy(x, staffb + shift);
			a2b("ft0 ");
			shift += *p_seq++;
			x += 5.5;
		}
	} else {
		int acc, last_acc, last_shift;

		/* explicit accidentals */
		last_acc = s->as.u.key.accs[0];
		last_shift = 100;
		for (i = 0; i < s->as.u.key.nacc; i++) {
			acc = s->as.u.key.accs[i];
			if (acc != last_acc) {
				last_acc = acc;
				x += 3;
			}
			shift = s->pits[0] * 3
				+ 3 * (s->as.u.key.pits[i] - 18);
			while (shift < -3)
				shift += 21;
			while (shift > 24 + 3)
				shift -= 21;
			if (shift == last_shift + 21
			 || shift == last_shift - 21)
				x -= 5.5;		/* octave */
			last_shift = shift;
			putxy(x, staffb + shift);
			draw_acc(acc, s->as.u.key.microscale);
			x += 5.5;
		}
	}
	if (old_sf != 0 || s->as.u.key.sf != 0 || s->as.u.key.nacc >= 0)
		a2b("\n");
}

/* -- convert the standard measure bars -- */
static int bar_cnv(int bar_type)
{
	switch (bar_type) {
	case B_OBRA:
/*	case B_CBRA: */
	case (B_OBRA << 4) + B_CBRA:
		return 0;			/* invisible */
	case B_COL:
		return B_BAR;			/* dotted */
#if 0
	case (B_CBRA << 4) + B_BAR:
		return B_BAR;
#endif
	case (B_BAR << 4) + B_COL:
		bar_type |= (B_OBRA << 8);		/* |: -> [|: */
		break;
	case (B_BAR << 8) + (B_COL << 4) + B_COL:
		bar_type |= (B_OBRA << 12);		/* |:: -> [|:: */
		break;
	case (B_BAR << 12) + (B_COL << 8) + (B_COL << 4) + B_COL:
		bar_type |= (B_OBRA << 16);		/* |::: -> [|::: */
		break;
	case (B_COL << 4) + B_BAR:
	case (B_COL << 8) + (B_COL << 4) + B_BAR:
	case (B_COL << 12) + (B_COL << 8) + (B_COL << 4) + B_BAR:
		bar_type <<= 4;
		bar_type |= B_CBRA;			/* :..| -> :..|] */
		break;
	case (B_COL << 4) + B_COL:
		bar_type = cfmt.dblrepbar;		/* :: -> dble repeat bar */
		break;
	}
	return bar_type;
}

/* -- draw a measure bar -- */
static void draw_bar(struct SYMBOL *s, float bot, float h)
{
	int staff, bar_type, dotted;
	float x, yb;
	char *psf;

	staff = s->staff;
	yb = staff_tb[staff].y;
	x = s->x;

	/* if measure repeat, draw the '%' like glyphs */
	if (s->as.u.bar.len != 0) {
		struct SYMBOL *s2;

		set_scale(s);
		if (s->as.u.bar.len == 1) {
			for (s2 = s->prev; s2->as.type != ABC_T_REST; s2 = s2->prev)
				;
			putxy(s2->x, yb);
			a2b("mrep\n");
		} else {
			putxy(x, yb);
			a2b("mrep2\n");
			if (s->voice == cursys->top_voice) {
/*fixme				set_font(s->gcf); */
				set_font(cfmt.anf);
				putxy(x, yb + staff_tb[staff].topbar + 4);
				a2b("M(%d)showc\n", s->as.u.bar.len);
			}
		}
	}
	dotted = s->as.u.bar.dotted || s->as.u.bar.type == B_COL;
	bar_type = bar_cnv(s->as.u.bar.type);
	if (bar_type == 0)
		return;				/* invisible */
	for (;;) {
		psf = "bar";
		switch (bar_type & 0x07) {
		case B_BAR:
			if (dotted)
				psf = "dotbar";
			break;
		case B_OBRA:
		case B_CBRA:
			psf = "thbar";
			x -= 3;
			break;
		case B_COL:
			x -= 2;
			break;
		}
		switch (bar_type & 0x07) {
		default:
			set_sscale(-1);
			a2b("%.1f %.1f %.1f %s ", h, x, bot, psf);
			break;
		case B_COL:
			set_sscale(staff);
			putxy(x + 1, staff_tb[staff].y);
			a2b("rdots ");
			break;
		}
		bar_type >>= 4;
		if (bar_type == 0)
			break;
		x -= 3;
	}
	a2b("\n");
}

/* -- draw a rest -- */
/* (the staves are defined) */
static void draw_rest(struct SYMBOL *s)
{
	int i, y;
	float x, dotx, staffb;

static char *rest_tb[NFLAGS_SZ] = {
	"r128", "r64", "r32", "r16", "r8",
	"r4",
	"r2", "r1", "r0", "r00"
};

	/* if rest alone in the measure, center */
	x = s->x + s->shhd[0] * cur_scale;
	if (s->dur == voice_tb[s->voice].meter.wmeasure) {
		struct SYMBOL *s2;

		/* don't use next/prev: there is no bar in voice averlay */
		s2 = s->ts_next;
		while (s2 && s2->time != s->time + s->dur)
			s2 = s2->ts_next;
		if (s2)
			x = s2->x;
		else
			x = realwidth;
		s2 = s;
		while (!(s2->sflags & S_SEQST))
			s2 = s2->ts_prev;
		s2 = s2->ts_prev;
		x = (x + s2->x) * .5;

		/* center the associated decorations */
		if (s->as.u.note.dc.n > 0)
			deco_update(s, x - s->x);
		s->x = x;
	}
	if ((s->as.flags & ABC_F_INVIS)
	 && !(s->sflags & S_OTHER_HEAD))
		return;

	staffb = staff_tb[s->staff].y;		/* bottom of staff */

	if (s->sflags & S_REPEAT) {
		putxy(x, staffb);
		if (s->doty < 0) {
			a2b("srep\n");
		} else {
			a2b("mrep\n");
			if (s->doty > 2
			 && s->voice == cursys->top_voice) {
/*fixme				set_font(s->gcf); */
				set_font(cfmt.anf);
				putxy(x, staffb + 24 + 4);
				a2b("M(%d)showc\n", s->doty);
			}
		}
		return;
	}

	y = s->y;

	if (s->sflags & S_OTHER_HEAD) {
		draw_all_deco_head(s, x, y + staffb);
		return;
	}

	i = C_XFLAGS - s->nflags;		/* rest_tb index */
	if (i == 7 && y == 12
	 && staff_tb[s->staff].clef.stafflines <= 2)
		y -= 6;				/* semibreve a bit lower */

	putxy(x, y + staffb);				/* rest */
	a2b("%s ", rest_tb[i]);

	/* output ledger line(s) when greater than minim */
	if (i >= 6) {
		int yb, yt;

		switch (staff_tb[s->staff].clef.stafflines) {
		case 0:
			yb = 12;
			yt = 12;
			break;
		case 1:
			yb = 6;
			yt = 18;
			break;
		case 2:
			yb = 0;
			yt = 18;
			break;
		case 3:
			yb = 0;
			yt = 24;
			break;
		default:
			yb = -6;
			yt = staff_tb[s->staff].clef.stafflines * 6;
			break;
		}
		switch (i) {
		case 6:					/* minim */
			if (y <= yb || y >= yt) {
				putxy(x, y + staffb);
				a2b("hl ");
			}
			break;
		case 7:					/* semibreve */
			if (y < yb || y >= yt - 6) {
				putxy(x, y + 6 + staffb);
				a2b("hl ");
			}
			break;
		default:
			if (y < yb || y >= yt - 6) {
				putxy(x,y + 6 + staffb);
				a2b("hl ");
			}
			if (i == 9)			/* longa */
				y -= 6;
			if (y <= yb || y >= yt) {
				putxy(x, y + staffb);
				a2b("hl ");
			}
			break;
		}
	}

	dotx = 8;
	for (i = 0; i < s->dots; i++) {
		a2b("%.1f 3 dt ", dotx);
		dotx += 3.5;
	}
	a2b("\n");
}

/* -- draw grace notes -- */
/* (the staves are defined) */
static void draw_gracenotes(struct SYMBOL *s)
{
	int yy;
	float x0, y0, x1, y1, x2, y2, x3, y3, bet1, bet2, dy1, dy2;
	struct SYMBOL *g, *last;
	struct BEAM bm;

	/* draw the notes */
	bm.s2 = NULL;				/* (draw flags) */
	for (g = s->extra; g; g = g->next) {
		if (g->type != NOTEREST)
			continue;
		if ((g->sflags & (S_BEAM_ST | S_BEAM_END)) == S_BEAM_ST) {
			if (annotate)
				anno_out(g, 'b');
			if (calculate_beam(&bm, g))
				draw_beams(&bm);
		}
		draw_note(g->x, g, bm.s2 == NULL);
		if (annotate)
			anno_out(s, 'g');
		if (g == bm.s2)
			bm.s2 = NULL;			/* (draw flags again) */

		if (g->as.flags & ABC_F_SAPPO) {	/* (on 1st note only) */
			if (!g->next) {			/* if one note */
				x1 = 9;
				y1 = g->stem > 0 ? 5 : -5;
			} else {			/* many notes */
				x1 = (g->next->x - g->x) * .5 + 4;
				y1 = (g->ys + g->next->ys) * .5 - g->y;
				if (g->stem > 0)
					y1 -= 1;
				else
					y1 += 1;
			}
			putxy(x1, y1);
			a2b("g%ca\n", g->stem > 0 ? 'u' : 'd');
		}
		if (annotate
		 && (g->sflags & (S_BEAM_ST | S_BEAM_END)) == S_BEAM_END)
			anno_out(g, 'e');
		if (!g->next)
			break;			/* (keep the last note) */
	}

	/* slur */
	if (voice_tb[s->voice].key.mode >= BAGPIPE /* no slur when bagpipe */
	 || !cfmt.graceslurs
	 || s->as.u.note.slur_st		/* explicit slur */
	 || !s->next
	 || s->next->as.type != ABC_T_NOTE)
		return;
	last = g;
	if (last->stem >= 0) {
		yy = 127;
		for (g = s->extra; g; g = g->next) {
			if (g->type != NOTEREST)
				continue;
			if (g->y < yy) {
				yy = g->y;
				last = g;
			}
		}
		x0 = last->x;
		y0 = last->y - 5;
		if (s->extra != last) {
			x0 -= 4;
			y0 += 1;
		}
		s = s->next;
		x3 = s->x - 1;
		if (s->stem < 0)
			x3 -= 4;
		y3 = 3 * (s->pits[0] - 18) - 5;
		dy1 = (x3 - x0) * .4;
		if (dy1 > 3)
			dy1 = 3;
			dy2 = dy1;
		bet1 = .2;
		bet2 = .8;
		if (y0 > y3 + 7) {
			x0 = last->x - 1;
			y0 += .5;
			y3 += 6.5;
			x3 = s->x - 5.5;
			dy1 = (y0 - y3) * .8;
			dy2 = (y0 - y3) * .2;
			bet1 = 0;
		} else if (y3 > y0 + 4) {
			y3 = y0 + 4;
			x0 = last->x + 2;
			y0 = last->y - 4;
		}
	} else {
		yy = -127;
		for (g = s->extra; g; g = g->next) {
			if (g->type != NOTEREST)
				continue;
			if (g->y > yy) {
				yy = g->y;
				last = g;
			}
		}
		x0 = last->x;
		y0 = last->y + 5;
		if (s->extra != last) {
			x0 -= 4;
			y0 -= 1;
		}
		s = s->next;
		x3 = s->x - 1;
		if (s->stem >= 0)
			x3 -= 2;
		y3 = 3 * (s->pits[s->nhd] - 18) + 5;
		dy1 = (x0 - x3) * .4;
		if (dy1 < -3)
			dy1 = -3;
		dy2 = dy1;
		bet1 = .2;
		bet2 = .8;
		if (y0 < y3 - 7) {
			x0 = last->x - 1;
			y0 -= .5;
			y3 -= 6.5;
			x3 = s->x - 5.5;
			dy1 = (y0 - y3) * .8;
			dy2 = (y0 - y3) * .2;
			bet1 = 0;
		} else if (y3 < y0 - 4) {
			y3 = y0 - 4;
			x0 = last->x + 2;
			y0 = last->y + 4;
		}
	}

	x1 = bet1 * x3 + (1 - bet1) * x0;
	y1 = bet1 * y3 + (1 - bet1) * y0 - dy1;
	x2 = bet2 * x3 + (1 - bet2) * x0;
	y2 = bet2 * y3 + (1 - bet2) * y0 - dy2;

	a2b("%.2f %.2f %.2f %.2f %.2f %.2f ",
		x1 - x0, y1 - y0,
		x2 - x0, y2 - y0,
		x3 - x0, y3 - y0);
	putxy(x0, y0 + staff_tb[s->staff].y);
	a2b("gsl\n");
}

/* -- set the y offset of the dots -- */
static void setdoty(struct SYMBOL *s,
		    signed char *y_tb)
{
	int m, m1, y, doty;

	/* set the normal offsets */
	doty = s->doty;
	for (m = 0; m <= s->nhd; m++) {
		y = 3 * (s->pits[m] - 18);	/* note height on staff */
		if ((y % 6) == 0) {
			if (doty != 0)
				y -= 3;
			else
				y += 3;
		}
		y_tb[m] = y;
	}

	/* dispatch and recenter the dots in the staff spaces */
	for (m = 0; m < s->nhd; m++) {
		if (y_tb[m + 1] > y_tb[m])
			continue;
		m1 = m;
		while (m1 > 0) {
			if (y_tb[m1] > y_tb[m1 - 1] + 6)
				break;
			m1--;
		}
		if (3 * (s->pits[m1] - 18) - y_tb[m1]
				< y_tb[m + 1] - 3 * (s->pits[m + 1] - 18)) {
			while (m1 <= m)
				y_tb[m1++] -= 6;
		} else {
			y_tb[m + 1] = y_tb[m] + 6;
		}
	}
}

/* -- draw m-th head with accidentals and dots -- */
/* (the staves are defined) */
static void draw_basic_note(float x,
			    struct SYMBOL *s,
			    int m,
			    signed char *y_tb)
{
	int i, y, no_head, head, dots, nflags;
	float staffb, shhd;
	char *p;
	char perc_hd[8];

	staffb = staff_tb[s->staff].y;		/* bottom of staff */
	y = 3 * (s->pits[m] - 18);		/* note height on staff */
	shhd = s->shhd[m] * cur_scale;

	/* draw the note decorations */
	no_head = (s->sflags & S_OTHER_HEAD);
	if (no_head)
		draw_all_deco_head(s, x + shhd, y + staffb);
	if (s->as.u.note.decs[m] != 0) {
		int n;

		i = s->as.u.note.decs[m] >> 3;		/* index */
		n = i + (s->as.u.note.decs[m] & 0x07);	/* # deco */
		for ( ; i < n; i++)
			no_head |= draw_deco_head(s->as.u.note.dc.t[i],
						  x + shhd,
						  y + staffb,
						  s->stem);
	}
	if (s->as.flags & ABC_F_INVIS)
		return;

	/* special case when no head */
	if (s->nohdix >= 0) {
		if ((s->stem > 0 && m <= s->nohdix)
		 || (s->stem < 0 && m >= s->nohdix)) {
			a2b("/x ");			/* set x y */
			putx(x + shhd);
			a2b("def/y ");
			puty(y + staffb);
			a2b("def");
			return;
		}
	}

	identify_note(s, s->as.u.note.lens[m],
		      &head, &dots, &nflags);

	/* output a ledger line if horizontal shift / chord
	 * and note on a line */
	if (y % 6 == 0
	 && shhd != (s->stem > 0 ? s->shhd[0] : s->shhd[s->nhd])) {
		int yy;

		yy = 0;
		if (y >= 30) {
			yy = y;
			if (yy % 6)
				yy -= 3;
		} else if (y <= -6) {
			yy = y;
			if (yy % 6)
				yy += 3;
		}
		if (yy) {
			putxy(x + shhd, yy + staffb);
			a2b("hl ");
		}
	}

	/* draw the head */
	putxy(x + shhd, y + staffb);
	if (no_head) {
		p = "/y exch def/x exch def";
	} else if (s->as.flags & ABC_F_GRACE) {
		p = "ghd";
	} else if (s->type == CUSTOS) {
		p = "custos";
	} else if ((s->sflags & S_PERC)
	        && (i = s->as.u.note.accs[m]) != 0) {
		i &= 0x07;
		sprintf(perc_hd, "p%shd", acc_tb[i]);
		p = perc_hd;
	} else {
		switch (head) {
		case H_OVAL:
			if (s->as.u.note.lens[m] < BREVE) {
				p = "HD";
				break;
			}
			if (s->head != H_SQUARE) {
				p = "HDD";
				break;
			}
			/* fall thru */
		case H_SQUARE:
			if (s->as.u.note.lens[m] < BREVE * 2)
				p = "breve";
			else
				p = "longa";

			/* don't display dots on last note of the tune */
			if (!tsnext && s->next
			 && s->next->type == BAR && !s->next->next)
				dots = 0;
			break;
		case H_EMPTY:
			p = "Hd"; break;
		default:
			p = "hd"; break;
		}
	}
	a2b("%s", p);

	/* draw the dots */
/*fixme: to see for grace notes*/
	if (dots) {
		float dotx;
		int doty;

		dotx = (int) (8. + s->xmx);
		doty = y_tb[m] - y;
		while (--dots >= 0) {
			a2b(" %.1f %d dt", dotx - shhd, doty);
			dotx += 3.5;
		}
	}

	/* draw the accidental */
	if ((i = s->as.u.note.accs[m]) != 0
	 && !(s->sflags & S_PERC)) {
		x -= s->shac[m] * cur_scale;
		a2b(" ");
		putx(x);
		if (s->as.flags & ABC_F_GRACE)
			a2b("gsc ");
		else
			a2b("y ");
		draw_acc(i, s->as.u.note.microscale);
		if (s->as.flags & ABC_F_GRACE)
			a2b(" grestore");
	}
}

/* -- draw a note or a chord -- */
/* (the staves are defined) */
static void draw_note(float x,
		      struct SYMBOL *s,
		      int fl)
{
	int i, m, ma, y;
	float staffb, slen, shhd;
	char c, *hltype;
	signed char y_tb[MAXHD];

	if (s->dots)
		setdoty(s, y_tb);
	if (s->head >= H_OVAL)
		x += 1;
	staffb = staff_tb[s->staff].y;

	/* output the ledger lines */
	if (!(s->as.flags & ABC_F_INVIS)) {
		if (s->as.flags & ABC_F_GRACE) {
			hltype = "ghl";
		} else {
			switch (s->head) {
			default:
				hltype = "hl";
				break;
			case H_OVAL:
				hltype = "hl1";
				break;
			case H_SQUARE:
				hltype = "hl2";
				break;
			}
		}
		shhd = (s->stem > 0 ? s->shhd[0] : s->shhd[s->nhd])
			* cur_scale;
		y = 3 * (s->pits[0] - 18);	/* lower ledger lines */
		switch (staff_tb[s->staff].clef.stafflines) {
		case 0:
		case 1: i = 6; break;
		case 2:
		case 3: i = 0; break;
		default: i = -6; break;
		}
		for ( ; i >= y; i -= 6) {
			putxy(x + shhd, i + staffb);
			a2b("%s ", hltype);
		}
		y = 3 * (s->pits[s->nhd] - 18);	/* upper ledger lines */
		switch (staff_tb[s->staff].clef.stafflines) {
		case 0:
		case 1:
		case 2: i = 18; break;
		case 3: i = 24; break;
		default: i = staff_tb[s->staff].clef.stafflines * 6; break;
		}
		for ( ; i <= y; i += 6) {
			putxy(x + shhd, i + staffb);
			a2b("%s ", hltype);
		}
	}

	/* draw the master note, first or last one */
	if (cfmt.setdefl)
		set_defl(s->stem >= 0 ? DEF_STEMUP : 0);
	ma = s->stem >= 0 ? 0 : s->nhd;

	draw_basic_note(x, s, ma, y_tb);

	/* add stem and flags */
	if (!(s->as.flags & (ABC_F_INVIS | ABC_F_STEMLESS))) {
		char c2;

		c = s->stem >= 0 ? 'u' : 'd';
		slen = (s->ys - s->y) / voice_tb[s->voice].scale;
		if (!fl || s->nflags - s->u <= 0) {	/* stem only */
			c2 = (s->as.flags & ABC_F_GRACE) ? 'g' : 's';
			if (s->nflags > 0) {	/* (fix for PS low resolution) */
				if (s->stem >= 0)
					slen -= 1;
				else
					slen += 1;
			}
			a2b(" %.1f %c%c", slen, c2, c);
		} else {				/* stem and flags */
			if (cfmt.straightflags)
				c = 's';		/* straight flag */
			c2 = (s->as.flags & ABC_F_GRACE) ? 'g' : 'f';
			a2b(" %d %.1f s%c%c", s->nflags - s->u, slen, c2, c);
		}
	} else if (s->sflags & S_XSTEM) {	/* cross-staff stem */
		struct SYMBOL *s2;

		s2 = s->ts_prev;
		if (s2->stem > 0)
			slen = s2->y - s->y;
		else
			slen = s2->ys - s->y;
		slen += staff_tb[s2->staff].y - staffb;
/*fixme:KO when different scales*/
		slen /= voice_tb[s->voice].scale;
		a2b(" %.1f su", slen);
	}

	/* draw the tremolo bars */
	if (!(s->as.flags & ABC_F_INVIS)
	 && fl
	 && (s->sflags & S_TREM1)) {
		float x1;

		x1 = x;
		if (s->stem > 0)
			slen = 3 * (s->pits[s->nhd] - 18);
		else
			slen = 3 * (s->pits[0] - 18);
		if (s->head >= H_OVAL) {
			if (s->stem > 0)
				slen = slen + 5 + 5.4 * s->u;
			else
				slen = slen - 5 - 5.4;
		} else {
			x1 += ((s->as.flags & ABC_F_GRACE)
					? GSTEM_XOFF : STEM_XOFF)
							* s->stem;
			if (s->stem > 0)
				slen = slen + 6 + 5.4 * s->u;
			else
				slen = slen - 6 - 5.4;
		}
		slen /= voice_tb[s->voice].scale;
		a2b(" %d ", s->u);
		putxy(x1, staffb + slen);
		a2b("trem");
	}

	/* draw the other note heads */
	for (m = 0; m <= s->nhd; m++) {
		if (m == ma)
			continue;
		a2b(" ");
		draw_basic_note(x, s, m, y_tb);
	}
	a2b("\n");
}

/* -- find where to terminate/start a slur -- */
static struct SYMBOL *next_scut(struct SYMBOL *s)
{
	struct SYMBOL *prev;

	prev = s;
	for (s = s->next; s; s = s->next) {
		if (s->type == BAR
		 && ((s->sflags & S_RRBAR)
			|| s->as.u.bar.type == B_THIN_THICK
			|| s->as.u.bar.type == B_THICK_THIN
			|| (s->as.u.bar.repeat_bar
			 && s->as.text
			 && s->as.text[0] != '1')))
			return s;
		prev = s;
	}
	/*fixme: KO when no note for this voice at end of staff */
	return prev;
}

static struct SYMBOL *prev_scut(struct SYMBOL *s)
{
	struct SYMBOL *sym;
	int voice;
	float x;

	voice = s->voice;
	for (s = s->prev ; s; s = s->prev) {
		if (s->type == BAR
		 && ((s->sflags & S_RRBAR)
		  || s->as.u.bar.type == B_THIN_THICK
		  || s->as.u.bar.type == B_THICK_THIN
		  || (s->as.u.bar.repeat_bar
		   && s->as.text
		   && s->as.text[0] != '1')))
			return s;
	}

	/* return sym before first note/rest/bar */
	sym = voice_tb[voice].sym;
	for (s = sym->next; s; s = s->next) {
		switch (s->as.type) {
		case ABC_T_NOTE:
		case ABC_T_REST:
		case ABC_T_BAR:
			x = s->x;
			do {
				s = s->prev;
			} while (s->x == x);
			return s;
		}
	}
	return sym;
}

/* -- decide whether a slur goes up or down -- */
static int slur_direction(struct SYMBOL *k1,
			  struct SYMBOL *k2)
{
	struct SYMBOL *s;
	int some_upstem, low;

	some_upstem = low = 0;
	for (s = k1; ; s = s->next) {
		if (s->as.type == ABC_T_NOTE) {
			if (!(s->as.flags & ABC_F_STEMLESS)) {
				if (s->stem < 0)
					return 1;
				some_upstem = 1;
			}
			if (s->pits[0] < 22)	/* if under middle staff */
				low = 1;
		}
		if (s == k2)
			break;
	}
	if (!some_upstem && !low)
		return 1;
	return -1;
}

/* -- output a slur / tie -- */
static void slur_out(float x1,
		     float y1,
		     float x2,
		     float y2,
		     int s,
		     float height,
		     int dotted,
		     int staff)	/* if < 0, the staves are defined */
{
	float alfa, beta, mx, my, xx1, yy1, xx2, yy2, dx, dy, dz;
	float scale_y;

	alfa = .3;
	beta = .45;

	/* for wide flat slurs, make shape more square */
	dy = y2 - y1;
	if (dy < 0)
		dy = -dy;
	dx = x2 - x1;
	if (dx > 40. && dy / dx < .7) {
		alfa = .3 + .002 * (dx - 40.);
		if (alfa > .7)
			alfa = .7;
	}

	/* alfa, beta, and height determine Bezier control points pp1,pp2
	 *
	 *           X====alfa===|===alfa=====X
	 *	    /		 |	       \
	 *	  pp1		 |	        pp2
	 *	  /	       height		 \
	 *	beta		 |		 beta
	 *      /		 |		   \
	 *    p1		 m		     p2
	 *
	 */

	mx = .5 * (x1 + x2);
	my = .5 * (y1 + y2);

	xx1 = mx + alfa * (x1 - mx);
	yy1 = my + alfa * (y1 - my) + height;
	xx1 = x1 + beta * (xx1 - x1);
	yy1 = y1 + beta * (yy1 - y1);

	xx2 = mx + alfa * (x2 - mx);
	yy2 = my + alfa * (y2 - my) + height;
	xx2 = x2 + beta * (xx2 - x2);
	yy2 = y2 + beta * (yy2 - y2);

	dx = .03 * (x2 - x1);
//	if (dx > 10.)
//		dx = 10.;
//	dy = 1.6 * s;
	dy = 2 * s;
	dz = .2 + .001 * (x2 - x1);
	if (dz > .6)
		dz = .6;
	dz *= s;
	
	scale_y = scale_voice ? cur_scale : 1;
	if (!dotted)
		a2b("%.2f %.2f %.2f %.2f %.2f %.2f 0 %.2f ",
			(xx2 - dx - x2) / cur_scale,
				(yy2 + dy - y2 - dz) / scale_y,
			(xx1 + dx - x2) / cur_scale,
				(yy1 + dy - y2 - dz) / scale_y,
			(x1 - x2) / cur_scale,
				(y1 - y2 - dz) / scale_y,
				dz);
	a2b("%.2f %.2f %.2f %.2f %.2f %.2f ",
		(xx1 - x1) / cur_scale, (yy1 - y1) / scale_y,
		(xx2 - x1) / cur_scale, (yy2 - y1) / scale_y,
		(x2 - x1) / cur_scale, (y2 - y1) / scale_y);
	putxy(x1, y1);
	if (staff >= 0)
		a2b("y%d ", staff);
	a2b(dotted ? "dSL\n" : "SL\n");
}

/* -- check if slur sequence in a multi-voice staff -- */
static int slur_multi(struct SYMBOL *k1,
		      struct SYMBOL *k2)
{
	for (;;) {
		if (k1->multi != 0)	/* if multi voice */
			/*fixme: may change*/
			return k1->multi;
		if (k1 == k2)
			break;
		k1 = k1->next;
	}
	return 0;
}

/* -- draw a phrasing slur between two symbols -- */
/* (the staves are not yet defined) */
/* (not a pretty routine, this) */
static int draw_slur(struct SYMBOL *k1,
		     struct SYMBOL *k2,
		     int m1,
		     int m2,
		     int slur_type)
{
	struct SYMBOL *k;
	float x1, y1, x2, y2, height, addy;
	float a, y, z, h, dx, dy;
	int s, nn, upstaff, two_staves;

/*fixme: if two staves, may have upper or lower slur*/
	switch (slur_type & 0x03) {	/* (ignore dot bit) */
	case SL_ABOVE: s = 1; break;
	case SL_BELOW: s = -1; break;
	default:
		if ((s = slur_multi(k1, k2)) == 0)
			s = slur_direction(k1, k2);
		break;
	}

	nn = 1;
	upstaff = k1->staff;
	two_staves = 0;
	if (k1 != k2)
	    for (k = k1->next; k; k = k->next) {
		if (k->type == NOTEREST) {
			nn++;
			if (k->staff != upstaff) {
				two_staves = 1;
				if (k->staff < upstaff)
					upstaff = k->staff;
			}
		}
		if (k == k2)
			break;
	}
/*fixme: KO when two staves*/
if (two_staves) error(0, k1, "*** multi-staves slurs not treated yet");

	/* fix endpoints */
	x1 = k1->x + k1->xmx;		/* take the max right side */
	if (k1 != k2) {
		x2 = k2->x;
	} else {		/* (the slur starts on last note of the line) */
		for (k = k2->ts_next; k; k = k->ts_next)
			if (k->type == STAVES)
				break;
		if (!k)
			x2 = realwidth;
		else
			x2 = k->x;
	}
	y1 = (float) (s > 0 ? k1->ymx + 2 : k1->ymn - 2);
	y2 = (float) (s > 0 ? k2->ymx + 2 : k2->ymn - 2);

	if (k1->as.type == ABC_T_NOTE) {
		if (s > 0) {
			if (k1->stem > 0) {
				x1 += 5;
				if ((k1->sflags & S_BEAM_END)
				 && k1->nflags >= -1	/* if with a stem */
//fixme: check if at end of tuplet
				 && (!(k1->sflags & S_IN_TUPLET))) {
//				  || k1->ys > y1 - 3)) {
					if (k1->nflags > 0) {
						x1 += 2;
						y1 = k1->ys - 3;
					} else {
						y1 = k1->ys - 6;
					}
				} else {
					y1 = k1->ys + 3;
				}
			} else {
				y1 = k1->y + 8;
			}
		} else {
			if (k1->stem < 0) {
				x1 -= 1;
				if ((k1->sflags & S_BEAM_END)
				 && k1->nflags >= -1
				 && (!(k1->sflags & S_IN_TUPLET)
				  || k1->ys < y1 + 3)) {
					if (k1->nflags > 0) {
						x1 += 2;
						y1 = k1->ys + 3;
					} else {
						y1 = k1->ys + 6;
					}
				} else {
					y1 = k1->ys - 3;
				}
			} else {
				y1 = k1->y - 8;
			}
		}
	}

	if (k2->as.type == ABC_T_NOTE) {
		if (s > 0) {
			if (k2->stem > 0) {
				x2 += 1;
				if ((k2->sflags & S_BEAM_ST)
				 && k2->nflags >= -1
				 && (!(k2->sflags & S_IN_TUPLET)))
//					|| k2->ys > y2 - 3))
					y2 = k2->ys - 6;
				else
					y2 = k2->ys + 3;
			} else {
				y2 = k2->y + 8;
			}
		} else {
			if (k2->stem < 0) {
				x2 -= 5;
				if ((k2->sflags & S_BEAM_ST)
				 && k2->nflags >= -1
				 && (!(k2->sflags & S_IN_TUPLET)))
//					|| k2->ys < y2 + 3))
					y2 = k2->ys + 6;
				else
					y2 = k2->ys - 3;
			} else {
				y2 = k2->y - 8;
			}
		}
	}

	if (k1->as.type != ABC_T_NOTE) {
		y1 = y2 + 1.2 * s;
		x1 = k1->x + k1->wr * .5;
		if (x1 > x2 - 12)
			x1 = x2 - 12;
	}

	if (k2->as.type != ABC_T_NOTE) {
		if (k1->as.type == ABC_T_NOTE)
			y2 = y1 + 1.2 * s;
		else
			y2 = y1;
		if (k1 != k2)
			x2 = k2->x - k2->wl * .3;
	}

	if (nn >= 3) {
		if (k1->next->type != BAR
		 && k1->next->x < x1 + 48) {
			if (s > 0) {
				y = k1->next->ymx - 2;
				if (y1 < y)
					y1 = y;
			} else {
				y = k1->next->ymn + 2;
				if (y1 > y)
					y1 = y;
			}
		}
		if (k2->prev->type != BAR
		 && k2->prev->x > x2 - 48) {
			if (s > 0) {
				y = k2->prev->ymx - 2;
				if (y2 < y)
					y2 = y;
			} else {
				y = k2->prev->ymn + 2;
				if (y2 > y)
					y2 = y;
			}
		}
	}

#if 0
	/* shift endpoints */
	addx = .04 * (x2 - x1);
	if (addx > 3.0)
		addx = 3.0;
	addy = .01 * (x2 - x1);
	if (addy > 3.0)
		addy = 3.0;
	x1 += addx;
	x2 -= addx;

/*fixme: to simplify*/
	if (k1->staff == upstaff)
		y1 += s * addy;
	else
		y1 = -6;
	if (k2->staff == upstaff)
		y2 += s * addy;
	else
		y2 = -6;
#endif

	a = (y2 - y1) / (x2 - x1);		/* slur steepness */
	if (a > SLUR_SLOPE || a < -SLUR_SLOPE) {
		if (a > SLUR_SLOPE)
			a = SLUR_SLOPE;
		else
			a = -SLUR_SLOPE;
		if (a * s > 0)
			y1 = y2 - a * (x2 - x1);
		else
			y2 = y1 + a * (x2 - x1);
	}

	/* for big vertical jump, shift endpoints */
	y = y2 - y1;
	if (y > 8)
		y = 8;
	else if (y < -8)
		y = -8;
	z = y;
	if (z < 0)
		z = -z;
	dx = .5 * z;
	dy = .3 * y;
	if (y * s > 0) {
		x2 -= dx;
		y2 -= dy;
	} else {
		x1 += dx;
		y1 += dy;
	}

	/* special case for grace notes */
	if (k1->as.flags & ABC_F_GRACE)
		x1 = k1->x - GSTEM_XOFF * .5;
	if (k2->as.flags & ABC_F_GRACE)
		x2 = k2->x + GSTEM_XOFF * 1.5;

	h = 0;
	a = (y2 - y1) / (x2 - x1);
	if (k1 != k2) {
	    addy = y1 - a * x1;
	    for (k = k1->next; k != k2 ; k = k->next) {
		if (k->staff != upstaff)
			continue;
		switch (k->type) {
		case NOTEREST:
			if (s > 0) {
				y = 3 * (k->pits[k->nhd] - 18) + 6;
				if (y < k->ymx)
					y = k->ymx;
				y -= a * k->x + addy;
				if (y > h)
					h = y;
			} else {
				y = 3 * (k->pits[0] - 18) - 6;
				if (y > k->ymn)
					y = k->ymn;
				y -= a * k->x + addy;
				if (y < h)
					h = y;
			}
			break;
		case GRACE: {
			struct SYMBOL *g;

			for (g = k->extra; g; g = g->next) {
#if 1
				if (s > 0) {
					y = 3 * (g->pits[g->nhd] - 18) + 6;
					if (y < g->ymx)
						y = g->ymx;
					y -= a * g->x + addy;
					if (y > h)
						h = y;
				} else {
					y = 3 * (g->pits[0] - 18) - 6;
					if (y > g->ymn)
						y = g->ymn;
					y -= a * g->x + addy;
					if (y < h)
						h = y;
				}
#else
				y = g->y - a * k->x - addy;
				if (s > 0) {
					y += GSTEM + 2;
					if (y > h)
						h = y;
				} else {
					y -= 2;
					if (y < h)
						h = y;
				}
#endif
			}
			break;
		    }
		}
	    }
	    y1 += .45 * h;
	    y2 += .45 * h;
	    h *= .65;
	}

	if (nn > 3)
		height = (.08 * (x2 - x1) + 12) * s;
	else
		height = (.03 * (x2 - x1) + 8) * s;
	if (s > 0) {
		if (height < 3 * h)
			height = 3 * h;
		if (height > 40)
			height = 40;
	} else {
		if (height > 3 * h)
			height = 3 * h;
		if (height < -40)
			height = -40;
	}

	y = y2 - y1;
	if (y < 0)
		y = -y;
	if (s > 0) {
		if (height < .8 * y)
			height = .8 * y;
	} else {
		if (height > -.8 * y)
			height = -.8 * y;
	}
	height *= cfmt.slurheight;

/*fixme: ugly!*/
	if (m1 >= 0)
		y1 = (float) (3 * (k1->pits[m1] - 18) + 5 * s);
	if (m2 >= 0)
		y2 = (float) (3 * (k2->pits[m2] - 18) + 5 * s);

	slur_out(x1, y1, x2, y2, s, height, slur_type & SL_DOTTED, upstaff);

	/* have room for other symbols */
	dx = x2 - x1;
	a = (y2 - y1) / dx;
/*fixme: it seems to work with .4, but why?*/
	addy = y1 - a * x1 + .4 * height;
	for (k = k1; k != k2; k = k->next) {
		if (k->staff != upstaff)
			continue;
		y = a * k->x + addy;
		if (k->ymx < y)
			k->ymx = y;
		else if (k->ymn > y)
			k->ymn = y;
		if (k->next == k2) {
			dx = x2;
			if (k2->sflags & S_SL1)
				dx -= 5;
		} else {
			dx = k->next->x;
		}
		if (k != k1)
			x1 = k->x;
		dx -= x1;
		y_set(upstaff, s > 0, x1, dx, y);
	}
	return (s > 0 ? SL_ABOVE : SL_BELOW) | (slur_type & SL_DOTTED);
}

/* -- draw the slurs between 2 symbols --*/
static void draw_slurs(struct SYMBOL *first,
		       struct SYMBOL *last)
{
	struct SYMBOL *s, *s1, *k, *gr1, *gr2;
	int i, m1, m2, gr1_out, slur_type, cont;

	gr1 = gr2 = NULL;
	s = first;
	for (;;) {
		if (!s || s == last) {
			if (!gr1
			 || !(s = gr1->next)
			 || s == last)
				break;
			gr1 = NULL;
		}
		if (s->type == GRACE) {
			gr1 = s;
			s = s->extra;
			continue;
		}
		if ((s->type != NOTEREST && s->type != SPACE)
		 || (s->as.u.note.slur_st == 0
			&& !(s->sflags & S_SL1))) {
			s = s->next;
			continue;
		}
		k = NULL;		/* find matching slur end */
		s1 = s->next;
		gr1_out = 0;
		for (;;) {
			if (!s1) {
				if (gr2) {
					s1 = gr2->next;
					gr2 = NULL;
					continue;
				}
				if (!gr1 || gr1_out)
					break;
				s1 = gr1->next;
				gr1_out = 1;
				continue;
			}
			if (s1->type == GRACE) {
				gr2 = s1;
				s1 = s1->extra;
				continue;
			}
			if (s1->type == BAR
			 && ((s1->sflags & S_RRBAR)
			  || s1->as.u.bar.type == B_THIN_THICK
			  || s1->as.u.bar.type == B_THICK_THIN
			  || (s1->as.u.bar.repeat_bar
			   && s1->as.text
			   && s1->as.text[0] != '1'))) {
				k = s1;
				break;
			}
			if (s1->type != NOTEREST && s1->type != SPACE) {
				s1 = s1->next;
				continue;
			}
			if (s1->as.u.note.slur_end
			 || (s1->sflags & S_SL2)) {
				k = s1;
				break;
			}
			if (s1->as.u.note.slur_st
			 || (s1->sflags & S_SL1)) {
				if (gr2) {	/* if in grace note sequence */
					for (k = s1; k->next; k = k->next)
						;
					k->next = gr2->next;
					if (gr2->next)
						gr2->next->prev = k;
//					gr2->as.u.note.slur_st = SL_AUTO;
					k = NULL;
				}
				draw_slurs(s1, last);
				if (gr2
				 && gr2->next) {
					gr2->next->prev->next = NULL;
					gr2->next->prev = gr2;
				}
			}
			if (s1 == last)
				break;
			s1 = s1->next;
		}
		if (!s1) {
			k = next_scut(s);
		} else if (!k) {
			s = s1;
			if (s == last)
				break;
			continue;
		}

		/* if slur in grace note sequence, change the linkages */
		if (gr1) {
			for (s1 = s; s1->next; s1 = s1->next)
				;
			s1->next = gr1->next;
			if (gr1->next)
				gr1->next->prev = s1;
			gr1->as.u.note.slur_st = SL_AUTO;
		}
		if (gr2) {
			gr2->prev->next = gr2->extra;
			gr2->extra->prev = gr2->prev;
			gr2->as.u.note.slur_st = SL_AUTO;
		}
		if (s->as.u.note.slur_st) {
			slur_type = s->as.u.note.slur_st & 0x07;
			s->as.u.note.slur_st >>= 3;
			m1 = -1;
		} else {
			for (m1 = 0; m1 <= s->nhd; m1++)
				if (s->as.u.note.sl1[m1])
					break;
			slur_type = s->as.u.note.sl1[m1] & 0x07;
			s->as.u.note.sl1[m1] >>= 3;
			if (s->as.u.note.sl1[m1] == 0) {
				for (i = m1 + 1; i <= s->nhd; i++)
					if (s->as.u.note.sl1[i])
						break;
				if (i > s->nhd)
					s->sflags &= ~S_SL1;
			}
		}
		m2 = -1;
		cont = 0;
		if ((k->type == NOTEREST || k->type == SPACE)
		  && (k->as.u.note.slur_end
		   || (k->sflags & S_SL2))) {
			if (k->as.u.note.slur_end) {
				k->as.u.note.slur_end--;
			} else {
				for (m2 = 0; m2 <= k->nhd; m2++)
					if (k->as.u.note.sl2[m2])
						break;
				k->as.u.note.sl2[m2]--;
				if (k->as.u.note.sl2[m2] == 0) {
					for (i = m2 + 1; i <= k->nhd; i++)
						if (k->as.u.note.sl2[i])
							break;
					if (i > k->nhd)
						k->sflags &= ~S_SL2;
				}
			}
		} else {
			if (k->type != BAR
			 || (!(k->sflags & S_RRBAR)
			  && k->as.u.bar.type != B_THIN_THICK
			  && k->as.u.bar.type != B_THICK_THIN
			  && (!k->as.u.bar.repeat_bar
			   || !k->as.text
			   || k->as.text[0] == '1')))
				cont = 1;
		}
		slur_type = draw_slur(s, k, m1, m2, slur_type);
		if (cont) {
/*fixme: the slur types are inverted*/
			voice_tb[k->voice].slur_st <<= 3;
			voice_tb[k->voice].slur_st += slur_type;
		}

		/* if slur in grace note sequence, restore the linkages */
		if (gr1
		 && gr1->next) {
			gr1->next->prev->next = NULL;
			gr1->next->prev = gr1;
		}
		if (gr2) {
			gr2->prev->next = gr2;
			gr2->extra->prev = NULL;
		}

		if (s->as.u.note.slur_st
		 || (s->sflags & S_SL1))
			continue;
		if (s == last)
			break;
		s = s->next;
	}
}

/* -- draw a tuplet -- */
/* (the staves are not yet defined) */
/* See 'tuplets' in format.txt about the value of 'u' */
static struct SYMBOL *draw_tuplet(struct SYMBOL *t,	/* tuplet in extra */
				  struct SYMBOL *s)	/* main note */
{
	struct SYMBOL *s1, *s2, *sy, *next, *g;
	int r, upstaff, nb_only, some_slur;
	float x1, x2, y1, y2, xm, ym, a, s0, yy, yx, dy;

	next = s;
	if ((t->u & 0x0f00) == 0x100)		/* if 'when' == never */
		return next;

	/* treat the nested tuplets starting on this symbol */
	for (g = t->next; g; g = g->next) {
		if (g->type == TUPLET) {
			sy = draw_tuplet(g, s);
			if (sy->time > next->time)
				next = sy;
		}
	}

	/* search the first and last notes/rests of the tuplet */
	r = t->as.u.tuplet.r_plet;
	s1 = NULL;
	some_slur = 0;
	upstaff = s->staff;
	for (s2 = s; s2; s2 = s2->next) {
		if (s2 != s) {
			for (g = s2->extra; g; g = g->next) {
				if (g->type == TUPLET) {
					sy = draw_tuplet(g, s2);
					if (sy->time > next->time)
						next = sy;
				}
			}
		}
		if (s2->type != NOTEREST) {
			if (s2->type == GRACE) {
				for (g = s2->extra; g; g = g->next) {
					if (g->type != NOTEREST)
						continue;
					if (g->as.u.note.slur_st
					 || (g->sflags & S_SL1))
						some_slur = 1;
				}
			}
			continue;
		}
		if (s2->as.u.note.slur_st	/* if slur start/end */
		 || s2->as.u.note.slur_end
		 || (s2->sflags & (S_SL1 | S_SL2)))
			some_slur = 1;
		if (s2->staff < upstaff)
			upstaff = s2->staff;
		if (!s1)
			s1 = s2;
		if (--r <= 0)
			break;
	}
	if (!s2)
		return next;			/* no solution... */
	if (s2->time > next->time)
		next = s2;

#if 0
	/* draw the slurs when inside the tuplet */
	if (some_slur) {
		draw_slurs(s1, s2);
		if (s1->as.u.note.slur_st
		 || (s1->sflags & S_SL1))
			return next;
		for (sy = s1->next; sy != s2; sy = sy->next) {
			if (sy->as.u.note.slur_st	/* if slur start/end */
			 || sy->as.u.note.slur_end
			 || (sy->sflags & (S_SL1 | S_SL2)))
				return next;		/* don't draw now */
		}
		if (s2->as.u.note.slur_end
		 || (s2->sflags & S_SL2))
			return next;
	}
#endif

	if (s1 == s2) {				/* tuplet with 1 note (!) */
		nb_only = 1;
	} else if ((t->u & 0x0f0) == 0x10) {	/* 'what' == slur */
		nb_only = 1;
		draw_slur(s1, s2, -1, -1, 
			  s1->stem > 0 ? SL_ABOVE : SL_BELOW);
	} else {

		/* search if a bracket is needed */
		if ((t->u & 0x0f00) == 0x200	/* if 'when' == always */
		 || s1->as.type != ABC_T_NOTE || s2->as.type != ABC_T_NOTE) {
			nb_only = 0;
		} else {
			nb_only = 1;
			for (sy = s1; ; sy = sy->next) {
				if (sy->type != NOTEREST) {
					if (sy->type == GRACE
					 || sy->type == SPACE)
						continue;
					nb_only = 0;
					break;
				}
				if (sy == s2)
					break;
				if (sy->sflags & S_BEAM_END) {
					nb_only = 0;
					break;
				}
			}
			if (nb_only
			 && !(s1->sflags & (S_BEAM_ST | S_BEAM_BR1 | S_BEAM_BR2))) {
				for (sy = s1->prev; sy; sy = sy->prev) {
					if (sy->type == NOTEREST) {
						if (sy->nflags >= s1->nflags)
							nb_only = 0;
						break;
					}
				}
			}
			if (nb_only && !(s2->sflags & S_BEAM_END)) {
				for (sy = s2->next; sy; sy = sy->next) {
					if (sy->type == NOTEREST) {
						if (!(sy->sflags & (S_BEAM_BR1 | S_BEAM_BR2))
						 && sy->nflags >= s2->nflags)
							nb_only = 0;
						break;
					}
				}
			}
		}
	}

	/* if number only, draw it */
	if (nb_only) {
		float a, b;

		if ((t->u & 0x0f) == 1)		/* if 'value' == none */
			return next;
		xm = (s2->x + s1->x) * .5;
		if (s1 == s2)			/* tuplet with 1 note */
			a = 0;
		else
			a = (s2->ys - s1->ys) / (s2->x - s1->x);
		b = s1->ys - a * s1->x;
		yy = a * xm + b;
		if (s1->stem > 0) {
			ym = y_get(s1->staff, 1, xm - 3, 6);
			if (ym > yy)
				b += ym - yy;
			b += 4;
		} else {
			ym = y_get(s1->staff, 0, xm - 3, 6);
			if (ym < yy)
				b += ym - yy;
			b -= 12;
		}
		for (sy = s1; ; sy = sy->next) {
			if (sy->x >= xm)
				break;
		}
		if (s1->stem * s2->stem > 0) {
			if (s1->stem > 0)
				xm += GSTEM_XOFF;
			else
				xm -= GSTEM_XOFF;
		}
		ym = a * xm + b;
		if ((t->u & 0x0f) == 0)		/* if 'value' == number */
			a2b("(%d)", t->as.u.tuplet.p_plet);
		else
			a2b("(%d:%d)", t->as.u.tuplet.p_plet,
			     t->as.u.tuplet.q_plet);
		putxy(xm, ym);
		a2b("y%d bnum\n", s1->staff);

		if (s1->stem > 0) {
			ym += 8;
			if (sy->ymx < ym)
				sy->ymx = (short) ym;
			y_set(s1->staff, 1, xm - 3, 6, ym);
		} else {
			if (sy->ymn > ym)
				sy->ymn = (short) ym;
			y_set(s1->staff, 0, xm - 3, 6, ym);
		}
		s->sflags &= ~S_IN_TUPLET;		/* the tuplet is drawn */
		return next;
	}

#if 1
	/* draw the slurs when inside the tuplet */
	if (some_slur) {
		draw_slurs(s1, s2);
		if (s1->as.u.note.slur_st
		 || (s1->sflags & S_SL1))
			return next;
		for (sy = s1->next; sy != s2; sy = sy->next) {
			if (sy->as.u.note.slur_st	/* if slur start/end */
			 || sy->as.u.note.slur_end
			 || (sy->sflags & (S_SL1 | S_SL2)))
				return next;		/* don't draw now */
		}

		/* don't draw the tuplet when a slur ends on the last note */
		if (s2->as.u.note.slur_end
		 || (s2->sflags & S_SL2))
			return next;
	}
#endif
	if ((t->u & 0x0f0) != 0)	/* if 'what' != square */
		fprintf(stderr, "'what' value of %%%%tuplets not yet coded\n");

/*fixme: two staves not treated*/
/*fixme: to optimize*/
    if (s1->multi >= 0) {

	/* sole or upper voice: the bracket is above the staff */
	x1 = s1->x - 4;
	y1 = 24;
	if (s1->staff == upstaff) {
		sy = s1;
		if (sy->as.type != ABC_T_NOTE) {
			for (sy = sy->next; sy != s2; sy = sy->next)
				if (sy->as.type == ABC_T_NOTE)
					break;
		}
		ym = y_get(upstaff, 1, sy->x, 0);
		if (ym > y1)
			y1 = ym;
		if (s1->stem > 0)
			x1 += 3;
	}
	y2 = 24;
	if (s2->staff == upstaff) {
		sy = s2;
		if (sy->as.type != ABC_T_NOTE) {
			for (sy = sy->prev; sy != s1; sy = sy->prev)
				if (sy->as.type == ABC_T_NOTE)
					break;
		}
		ym = y_get(upstaff, 1, sy->x, 0);
		if (ym > y2)
			y2 = ym;
	}

	/* end the backet according to the last note duration */
#if 1
	if (s2->dur > s2->prev->dur) {
		if (s2->next)
			x2 = s2->next->x - s2->next->wl - 5;
		else
			x2 = realwidth - 6;
	} else {
		x2 = s2->x + 4;
		r = s2->stem >= 0 ? 0 : s2->nhd;
		if (s2->shhd[r] > 0)
			x2 += s2->shhd[r];
		if (s2->staff == upstaff
		 && s2->stem > 0)
			x2 += 3.5;
	}
#else
	if (s2->next)
		x2 += (s2->next->x - s2->next->wl - s2->x - s2->wr) * 0.5;
	else
		x2 += (realwidth - s2->x) * 0.5;
#endif

	xm = .5 * (x1 + x2);
	ym = .5 * (y1 + y2);

	a = (y2 - y1) / (x2 - x1);
	s0 = 3 * (s2->pits[s2->nhd] - s1->pits[s1->nhd]) / (x2 - x1);
	if (s0 > 0) {
		if (a < 0)
			a = 0;
		else if (a > s0)
			a = s0;
	} else {
		if (a > 0)
			a = 0;
		else if (a < s0)
			a = s0;
	}
	if (a * a < .1 * .1)
		a = 0;

	/* shift up bracket if needed */
	dy = 0;
	for (sy = s1; ; sy = sy->next) {
		if (sy->dur == 0	/* not a note or a rest */
		 || sy->staff != upstaff) {
			if (sy == s2)
				break;
			continue;
		}
		yy = ym + (sy->x - xm) * a;
		yx = y_get(upstaff, 1, sy->x, 0);
		if (yx - yy > dy)
			dy = yx - yy;
		if (sy == s2)
			break;
	}

	ym += dy + 4;
	y1 = ym + a * (x1 - xm);
	y2 = ym + a * (x2 - xm);
	putxy(x2 - x1, y2 - y1);
	putxy(x1, y1 + 4);
	a2b("y%d tubr", upstaff);

	/* shift the slurs / decorations */
	ym += 8;
	for (sy = s1; ; sy = sy->next) {
		if (sy->staff == upstaff) {
			yy = ym + (sy->x - xm) * a;
			if (sy->ymx < yy)
				sy->ymx = yy;
			if (sy == s2)
				break;
			y_set(upstaff, 1, sy->x, sy->next->x - sy->x, yy);
		} else if (sy == s2) {
			break;
		}
	}

    } else {	/* lower voice of the staff: the bracket is below the staff */
/*fixme: think to all that again..*/
	x1 = s1->x - 7;

#if 1
	if (s2->dur > s2->prev->dur) {
		if (s2->next)
			x2 = s2->next->x - s2->next->wl - 8;
		else
			x2 = realwidth - 6;
	} else {
		x2 = s2->x + 2;
		if (s2->shhd[s2->nhd] > 0)
			x2 += s2->shhd[s2->nhd];
	}
#else
	if (s2->next)
		x2 += (s2->next->x - s2->next->wl - s2->x - s2->wr) * 0.5;
	else
		x2 += (realwidth - s2->x) * 0.5;
#endif

	if (s1->staff == upstaff) {
		sy = s1;
		if (sy->as.type != ABC_T_NOTE) {
			for (sy = sy->next; sy != s2; sy = sy->next)
				if (sy->as.type == ABC_T_NOTE)
					break;
		}
		y1 = y_get(upstaff, 0, sy->x, 0);
	} else {
		y1 = 0;
	}
	if (s2->staff == upstaff) {
		sy = s2;
		if (sy->as.type != ABC_T_NOTE) {
			for (sy = sy->prev; sy != s1; sy = sy->prev)
				if (sy->as.type == ABC_T_NOTE)
					break;
		}
		y2 = y_get(upstaff, 0, sy->x, 0);
	} else {
		y2 = 0;
	}

	xm = .5 * (x1 + x2);
	ym = .5 * (y1 + y2);

	a = (y2 - y1) / (x2 - x1);
	s0 = 3 * (s2->pits[0] - s1->pits[0]) / (x2 - x1);
	if (s0 > 0) {
		if (a < 0)
			a = 0;
		else if (a > s0)
			a = s0;
	} else {
		if (a > 0)
			a = 0;
		else if (a < s0)
			a = s0;
	}
	if (a * a < .1 * .1)
		a = 0;

	/* shift down bracket if needed */
	dy = 0;
	for (sy = s1; ; sy = sy->next) {
		if (sy->dur == 0	/* not a note nor a rest */
		 || sy->staff != upstaff) {
			if (sy == s2)
				break;
			continue;
		}
		yy = ym + (sy->x - xm) * a;
		yx = y_get(upstaff, 0, sy->x, 0);
		if (yx - yy < dy)
			dy = yx - yy;
		if (sy == s2)
			break;
	}

	ym += dy - 12;
	y1 = ym + a * (x1 - xm);
	y2 = ym + a * (x2 - xm);
	putxy(x2 - x1, y2 - y1);
	putxy(x1, y1 + 4);
	a2b("y%d tubrl",upstaff);

	/* shift the slurs / decorations */
	ym -= 8;
	for (sy = s1; ; sy = sy->next) {
		if (sy->staff == upstaff) {
			if (sy == s2)
				break;
			yy = ym + (sy->x - xm) * a;
			if (sy->ymn > yy)
				sy->ymn = (short) yy;
			y_set(upstaff, 0, sy->x, sy->next->x - sy->x, yy);
		}
		if (sy == s2)
			break;
	}
    } /* lower voice */

	if ((t->u & 0x0f) == 1) {	/* if 'value' == none */
		s->sflags &= ~S_IN_TUPLET;
		return next;
	}
	yy = .5 * (y1 + y2);
	if ((t->u & 0x0f) == 0)		/* if 'value' == number */
		a2b("(%d)", t->as.u.tuplet.p_plet);
	else
		a2b("(%d:%d)", t->as.u.tuplet.p_plet,
		     t->as.u.tuplet.q_plet);
	putxy(xm, yy);
	a2b("y%d bnumb\n", upstaff);
	s->sflags &= ~S_IN_TUPLET;
	return next;
}

/* -- draw the ties between two notes/chords -- */
static void draw_note_ties(struct SYMBOL *k1,
			   struct SYMBOL *k2,
			   int ntie,
			   int *mhead1,
			   int *mhead2,
			   int job)
{
	int i, s, m1, m2, p, p1, p2, y, staff;
	float x1, x2, h, sh;

	for (i = 0; i < ntie; i++) {
		m1 = mhead1[i];
		p1 = k1->pits[m1];
		m2 = mhead2[i];
		p2 = k2->pits[m2];
		s = (k1->as.u.note.ti1[m1] & 0x03) == SL_ABOVE ? 1 : -1;

		x1 = k1->x;
		sh = k1->shhd[m1];		/* head shift */
		if (s > 0) {
			if (m1 < k1->nhd && p1 + 1 == k1->pits[m1 + 1])
				if (k1->shhd[m1 + 1] > sh)
					sh = k1->shhd[m1 + 1];
		} else {
			if (m1 > 0 && p1 == k1->pits[m1 - 1] + 1)
				if (k1->shhd[m1 - 1] > sh)
					sh = k1->shhd[m1 - 1];
		}
//		x1 += sh;
		x1 += sh * 0.6;

		x2 = k2->x;
		sh = k2->shhd[m2];
		if (s > 0) {
			if (m2 < k2->nhd && p2 + 1 == k2->pits[m2 + 1])
				if (k2->shhd[m2 + 1] < sh)
					sh = k2->shhd[m2 + 1];
		} else {
			if (m2 > 0 && p2 == k2->pits[m2 - 1] + 1)
				if (k2->shhd[m2 - 1] < sh)
					sh = k2->shhd[m2 - 1];
		}
//		x2 += sh;
		x2 += sh * 0.6;

		staff = k1->staff;
		switch (job) {
		case 0:
			if (p1 == p2 || (p1 & 1))
				p = p1;
			else
				p = p2;
			break;
		case 1:				/* no starting note */
		case 3:				/* clef or staff change */
			x1 = k1->x;
			if (x1 > x2 - 20)
				x1 = x2 - 20;
			p = p2;
			staff = k2->staff;
			if (job == 3)
				s = -s;
			break;
/*		case 2:				 * no ending note */
		default:
			if (k1 != k2) {
				x2 -= k2->wl;
			} else {
				struct SYMBOL *k;

				for (k = k2->ts_next; k; k = k->ts_next)
					if (k->type == STAVES)
						break;
				if (!k)
					x2 = realwidth;
				else
					x2 = k->x;
			}
			if (x2 < x1 + 16)
				x2 = x1 + 16;
			p = p1;
			break;
		}
		if (x2 - x1 > 20) {
			x1 += 3.5;
			x2 -= 3.5;
		}

		y = 3 * (p - 18);
		if (job != 1 && job != 3) {
			if (p & 1)
				y += 2 * s;
			if (s > 0) {
//				if (k1->nflags > -2 && k1->stem > 0
//				 && k1->nhd == 0)
//					x1 += 4.5;
				if (!(p & 1) && k1->dots > 0)
					y = 3 * (p - 18) + 6;
			}
		}
//		if (job != 2) {
		 else {
			if (p & 1)
				y += 2 * s;
//			if (s < 0) {
//				if (k2->nflags > -2 && k2->stem < 0
//				 && k2->nhd == 0)
//					x2 -= 4.5;
//			}
//			if (job != 0)
//				y1 = y2;
//		} else {
//			if (k1 == k2) {		/* if continuation on next line */
//				k1->as.u.note.ti1[m1] &= SL_DOTTED;
//				k1->as.u.note.ti1[m1] +=
//					s > 0 ? SL_ABOVE : SL_BELOW;
//			}
		}

		h = (.04 * (x2 - x1) + 10) * s;
		slur_out(x1, staff_tb[staff].y + y,
			 x2, staff_tb[staff].y + y,
			 s, h, k1->as.u.note.ti1[m1] & SL_DOTTED, -1);
	}
}

/* -- draw ties between neighboring notes/chords -- */
static void draw_ties(struct SYMBOL *k1,
		      struct SYMBOL *k2,
		      int job)		/* 0: normal
					 * 1: no starting note
					 * 2: no ending note
					 * 3: no start for clef or staff change */
{
	struct SYMBOL *k3;
	int i, m1, nh1, pit, ntie, tie2, ntie3, time;
	int mhead1[MAXHD], mhead2[MAXHD], mhead3[MAXHD];

	/* special cases for ties to/from a grace note */
	if (k1->type == GRACE) {
		k3 = k1->extra;
		while (k3) {
			if (k3->type == NOTEREST)
				k1 = k3;	/* last grace note */
			k3 = k3->next;
		}
	}
	if (k2->type == GRACE) {
		k3 = k2->extra;
		while (k3) {
			if (k3->type == NOTEREST) {
				k2 = k3;	/* first grace note */
				break;
			}
			k3 = k3->next;
		}
	}

	ntie = ntie3 = 0;
	nh1 = k1->nhd;
	time = k1->time + k1->dur;

	/* half ties from last note in line or before new repeat */
	if (job == 2) {
		for (i = 0; i <= nh1; i++) {
			if (k1->as.u.note.ti1[i])
				mhead3[ntie3++] = i;
		}
		draw_note_ties(k1, k2, ntie3, mhead3, mhead3, job);
		return;
	}

	/* set up list of ties to draw */
	for (i = 0; i <= nh1; i++) {
		if (k1->as.u.note.ti1[i] == 0)
			continue;
		tie2 = -1;
		pit = k1->as.u.note.pits[i];
		for (m1 = k2->nhd; m1 >= 0; m1--) {
			switch (k2->as.u.note.pits[m1] - pit) {
			case 1:			/* maybe ^c - _d */
			case -1:		/* _d - ^c */
				if (k1->as.u.note.accs[i] != k2->as.u.note.accs[m1])
					tie2 = m1;
				break;
			case 0:
				mhead1[ntie] = i;
				mhead2[ntie++] = m1;
				goto found;
			}
		}
		if (tie2 >= 0) {		/* second choice */
			mhead1[ntie] = i;
			mhead2[ntie++] = tie2;
		} else {
			mhead3[ntie3++] = i;	/* no match */
		}
found:
		;
	}

	/* draw the ties */
	draw_note_ties(k1, k2, ntie, mhead1, mhead2, job);

	/* if any bad tie, try an other voice of the same staff */
	if (ntie3 == 0)
		return;				/* no bad tie */
	k3 = k1->ts_next;
	while (k3 && k3->time < time)
		k3 = k3->ts_next;
	while (k3 && k3->time == time) {
		if (k3->as.type != ABC_T_NOTE
		 || k3->staff != k1->staff) {
			k3 = k3->ts_next;
			continue;
		}
		ntie = 0;
		for (i = ntie3; --i >= 0; ) {
			pit = k1->as.u.note.pits[mhead3[i]];
			for (m1 = k3->nhd; m1 >= 0; m1--) {
				if (k3->as.u.note.pits[m1] == pit) {
					mhead1[ntie] = mhead3[i];
					mhead2[ntie++] = m1;
					ntie3--;
					mhead3[i] = mhead3[ntie3];
					break;
				}
			}
		}
		if (ntie > 0) {
			draw_note_ties(k1, k3,
					ntie, mhead1, mhead2,
					job == 1 ? 1 : 0);
			if (ntie3 == 0)
				return;
		}
		k3 = k3->ts_next;
	}

	if (ntie3 != 0)
		error(1, k1, "Bad tie");
}

/* -- draw all ties between neighboring notes -- */
static void draw_all_ties(struct VOICE_S *p_voice)
{
	struct SYMBOL *s1, *s2, *rtie;
	struct SYMBOL tie;
	int clef_chg;

	for (s1 = p_voice->sym->next; s1; s1 = s1->next)
		if (s1->type != KEYSIG && s1->type != TIMESIG)
			break;
	rtie = p_voice->rtie;			/* tie from 1st repeat bar */
	for (s2 = s1; s2; s2 = s2->next) {
		if (s2->as.type == ABC_T_NOTE
		 || s2->type == GRACE)
			break;
		if (s2->type != BAR
		 || !s2->as.u.bar.repeat_bar
		 || !s2->as.text)
			continue;
		if (s2->as.text[0] == '1')	/* 1st repeat bar */
			rtie = p_voice->tie;
		else
			p_voice->tie = rtie;
	}
	if (!s2)
		return;
	if (p_voice->tie) {			/* tie from previous line */
		p_voice->tie->x = s1->x + s1->wr;
		s1 = p_voice->tie;
		p_voice->tie = NULL;
		s1->staff = s2->staff;
		s1->ts_next = tsfirst->next;	/* (for tie to other voice) */
		s1->time = s2->time - s1->dur;	/* (if after repeat sequence) */
		draw_ties(s1, s2, 1);		/* tie to 1st note */
	}

	/* search the start of ties */
	clef_chg = 0;
	for (;;) {
		for (s1 = s2; s1; s1 = s1->next) {
			if (s1->sflags & S_TI1)
				break;
			if (!rtie)
				continue;
			if (s1->type != BAR
			 || !s1->as.u.bar.repeat_bar
			 || !s1->as.text)
				continue;
			if (s1->as.text[0] == '1') {	/* 1st repeat bar */
				rtie = NULL;
				continue;
			}
			for (s2 = s1->next; s2; s2 = s2->next)
				if (s2->as.type == ABC_T_NOTE)
					break;
			if (!s2) {
				s1 = NULL;
				break;
			}
			memcpy(&tie, rtie, sizeof tie);
			tie.x = s1->x + s1->wr;
			tie.next = s2;
			tie.staff = s2->staff;
			tie.time = s2->time - tie.dur;
			draw_ties(&tie, s2, 1);
		}
		if (!s1)
			break;

		/* search the end of the tie
		 * and notice the clef changes (may occur in an other voice) */
		for (s2 = s1->ts_next; s2; s2 = s2->ts_next) {
			if (s2->staff != s1->staff
			 && s2->voice != s1->voice)
				continue;
			if (s2->type == CLEF) {
				clef_chg = 1;
				continue;
			}
			if (s2->voice != s1->voice)
				continue;
			if (s2->as.type == ABC_T_NOTE) {
				if (s2->time != s1->time + s1->dur)
					s2 = NULL;	/* %%combinevoices */
				break;
			}
			if (s2->type == GRACE)
				break;
			if (s2->type == BAR) {
				if ((s2->sflags & S_RRBAR)
				 || s2->as.u.bar.type == B_THIN_THICK
				 || s2->as.u.bar.type == B_THICK_THIN)
					break;
				if (!s2->as.u.bar.repeat_bar
				 || !s2->as.text)
					continue;
				if (s2->as.text[0] != '1')
					break;
				rtie = s1;		/* 1st repeat bar */
			}
		}
		if (!s2) {
			struct SYMBOL *s3;

			/* special case: tie to a combined chord */
			if (s1->ts_prev && s1->ts_prev->next) {
				int time;

				s3 = s1->ts_prev->next;	/* previous voice */
				time = s1->time + s1->dur;
				if (s3->time == time) {
					while (s3 && s3->time == time
					    && s3->as.type != ABC_T_NOTE)
						s3 = s3->next;
					if (s3
					 && s3->time == time
					 && s3->as.type == ABC_T_NOTE) {
						draw_ties(s1, s3, 1);
						break;
					}
				}
			}
			draw_ties(s1, s1, 2);
			p_voice->tie = s1;
			break;
		}

		/* ties with clef or staff change */
		if (clef_chg || s1->staff != s2->staff) {
			float x, dx;

			clef_chg = 0;
			dx = (s2->x - s1->x) * 0.4;
			x = s2->x;
			s2->x -= dx;
			if (s2->x > s1->x + 32.)
				s2->x = s1->x + 32.;
			draw_ties(s1, s2, 2);
			s2->x = x;
			x = s1->x;
			s1->x += dx;
			if (s1->x < s2->x - 24.)
				s1->x = s2->x - 24.;
			draw_ties(s1, s2, 3);
			s1->x = x;
			continue;
		}
		draw_ties(s1, s2, s2->as.type == ABC_T_NOTE ? 0 : 2);
	}
	p_voice->rtie = rtie;
}

/* -- draw all phrasing slurs for one staff -- */
/* (the staves are not yet defined) */
static void draw_all_slurs(struct VOICE_S *p_voice)
{
	struct SYMBOL *s, *k;
	int i, m2, slur_type;
	unsigned char slur_st;

	s = p_voice->sym->next;
	if (!s)
		return;
	slur_type = p_voice->slur_st;
	p_voice->slur_st = 0;

	/* the starting slur types are inverted */
	slur_st = 0;
	while (slur_type != 0) {
		slur_st <<= 3;
		slur_st |= (slur_type & 0x07);
		slur_type >>= 3;
	}

	/* draw the slurs inside the music line */
	draw_slurs(s, NULL);

	/* do unbalanced slurs still left over */
	for ( ; s; s = s->next) {
		if (s->type != NOTEREST && s->type != SPACE)
			continue;
		while (s->as.u.note.slur_end
		    || (s->sflags & S_SL2)) {
			if (s->as.u.note.slur_end) {
				s->as.u.note.slur_end--;
				m2 = -1;
			} else {
				for (m2 = 0; m2 <= s->nhd; m2++)
					if (s->as.u.note.sl2[m2])
						break;
				s->as.u.note.sl2[m2]--;
				if (s->as.u.note.sl2[m2] == 0) {
					for (i = m2 + 1; i <= s->nhd; i++)
						if (s->as.u.note.sl2[i])
							break;
					if (i > s->nhd)
						s->sflags &= ~S_SL2;
				}
			}
			slur_type = slur_st & 0x07;
			k = prev_scut(s);
			draw_slur(k, s, -1, m2, slur_type);
			if (k->type != BAR
			 || (!(k->sflags & S_RRBAR)
			  && k->as.u.bar.type != B_THIN_THICK
			  && k->as.u.bar.type != B_THICK_THIN
			  && (!k->as.u.bar.repeat_bar
			   || !k->as.text
			   || k->as.text[0] == '1')))
				slur_st >>= 3;
		}
	}
	s = p_voice->sym->next;
	while (slur_st != 0) {
		slur_type = slur_st & 0x07;
		slur_st >>= 3;
		k = next_scut(s);
		draw_slur(s, k, -1, -1, slur_type);
		if (k->type != BAR
		 || (!(k->sflags & S_RRBAR)
		  && k->as.u.bar.type != B_THIN_THICK
		  && k->as.u.bar.type != B_THICK_THIN
		  && (!k->as.u.bar.repeat_bar
		   || !k->as.text
		   || k->as.text[0] == '1'))) {
/*fixme: the slur types are inverted again*/
			p_voice->slur_st <<= 3;
			p_voice->slur_st += slur_type;
		}
	}
}

/* -- work out accidentals to be applied to each note -- */
static void setmap(int sf,	/* number of sharps/flats in key sig (-7 to +7) */
		   unsigned char *map)	/* for 7 notes only */
{
	int j;

	for (j = 7; --j >= 0; )
		map[j] = A_NULL;
	switch (sf) {
	case 7: map[6] = A_SH;
	case 6: map[2] = A_SH;
	case 5: map[5] = A_SH;
	case 4: map[1] = A_SH;
	case 3: map[4] = A_SH;
	case 2: map[0] = A_SH;
	case 1: map[3] = A_SH;
		break;
	case -7: map[3] = A_FT;
	case -6: map[0] = A_FT;
	case -5: map[4] = A_FT;
	case -4: map[1] = A_FT;
	case -3: map[5] = A_FT;
	case -2: map[2] = A_FT;
	case -1: map[6] = A_FT;
		break;
	}
}

/* output a tablature string escaping the parenthesis */
static void tbl_out(char *s, float x, int j, char *f)
{
	char *p;

	a2b("(");
	p = s;
	for (;;) {
		while (*p != '\0' && *p != '(' && *p != ')' )
			p++;
		if (p != s) {
			a2b("%.*s", (int) (p - s), s);
			s = p;
		}
		if (*p == '\0')
			break;
		a2b("\\");
		p++;
	}
	a2b(")%.1f y %d %s ", x, j, f);
}

/* -- draw the tablature with w: -- */
static void draw_tblt_w(struct VOICE_S *p_voice,
			int nly,
			float y,
			struct tblt_s *tblt)
{
	struct SYMBOL *s;
	struct lyrics *ly;
	struct lyl *lyl;
	char *p;
	int j, l;

	a2b("/y{%.1f y%d}def ", y, p_voice->staff);
	set_font(VOCALFONT);
	a2b("%.1f 0 y %d %s\n", realwidth, nly, tblt->head);
	for (j = 0; j < nly ; j++) {
		for (s = p_voice->sym->next; s; s = s->next) {
			ly = s->ly;
			if (!ly
			 || (lyl = ly->lyl[j]) == NULL) {
				if (s->type == BAR) {
					if (!tblt->bar)
						continue;
					p = &tex_buf[16];
					*p-- = '\0';
					l = bar_cnv(s->as.u.bar.type);
					while (l != 0) {
						*p-- = "?|[]:???"[l & 0x07];
						l >>= 4;
					}
					p++;
					tbl_out(p, s->x, j, tblt->bar);
				}
				continue;
			}
			tbl_out(lyl->t, s->x, j, tblt->note);
		}
		a2b("\n");
	}
}

/* -- draw the tablature with automatic pitch -- */
static void draw_tblt_p(struct VOICE_S *p_voice,
			float y,
			struct tblt_s *tblt)
{
	struct SYMBOL *s;
	int j, pitch, octave, sf, tied, acc;
	unsigned char workmap[70];	/* sharps/flats - base: lowest 'C' */
	unsigned char basemap[7];
	static int scale[7] = {0, 2, 4, 5, 7, 9, 11};	/* index = natural note */
	static int acc_pitch[6] = {0, 1, 0, -1, 2, -2};	/* index = enum accidentals */

	sf = p_voice->key.sf;
	setmap(sf, basemap);
	for (j = 0; j < 10; j++)
		memcpy(&workmap[7 * j], basemap, 7);
	a2b("gsave 0 %.1f y%d T(%.2s)%s\n",
		y, p_voice->staff,
		tblt->instr, tblt->head);
	tied = 0;
	for (s = p_voice->sym; s; s = s->next) {
		switch (s->type) {
		case NOTEREST:
			if (s->as.type == ABC_T_REST)
				continue;
			if (tied) {
				tied = s->as.u.note.ti1[0];
				continue;
			}
			break;
		case KEYSIG:
			sf = s->as.u.key.sf;
			setmap(sf, basemap);
			for (j = 0; j < 10; j++)
				memcpy(&workmap[7 * j], basemap, 7);
			continue;
		case BAR:
			if (s->as.flags & ABC_F_INVIS)
				continue;
			for (j = 0; j < 10; j++)
				memcpy(&workmap[7 * j], basemap, 7);
			continue;
		default:
			continue;
		}
		pitch = s->as.u.note.pits[0] + 19;
		acc = s->as.u.note.accs[0];
		if (acc != 0) {
			workmap[pitch] = acc == A_NT
				? A_NULL
				: (acc & 0x07);
		}
		pitch = scale[pitch % 7]
			+ acc_pitch[workmap[pitch]]
			+ 12 * (pitch / 7)
			- tblt->pitch;
		octave = 0;
		while (pitch < 0) {
			pitch += 12;
			octave--;
		}
		while (pitch >= 36) {
			pitch -= 12;
			octave++;
		}
		if ((acc & 0xf8) == 0) {
			a2b("%d %d %.2f %s\n", octave, pitch, s->x, tblt->note);
		} else {
			int n, d;
			float micro_p;

			n = micro_tb[acc >> 3];
			d = (n & 0xff) + 1;
			n = (n >> 8) + 1;
			switch (acc & 0x07) {
			case A_FT:
			case A_DF:
				n = -n;
				break;
			}
			micro_p = (float) pitch + (float) n / d;
			a2b("%d %.3f %.2f %s\n", octave, micro_p, s->x, tblt->note);
		}
		tied = s->as.u.note.ti1[0];
	}
	a2b("grestore\n");
}

/* -- draw the lyrics under (or above) notes -- */
/* !! this routine is tied to set_width() !! */
static float draw_lyrics(struct VOICE_S *p_voice,
			 int nly,
			 float y,
			 int incr)	/* 1: below, -1: above */
{
	int hyflag, l, j, lflag;
	char *p;
	float lastx, w, lskip, desc;
	struct SYMBOL *s;
	struct FONTSPEC *f;
	struct lyrics *ly;
	struct lyl *lyl;

	/* check if the lyrics contain tablatures */
	if (p_voice->tblts[0]) {
		if (p_voice->tblts[0]->pitch == 0)
			return y;		/* yes */
		if (p_voice->tblts[1]
		 && p_voice->tblts[1]->pitch == 0)
			return y;		/* yes */
	}

	outft = -1;				/* force font output */
	lskip = 0;				/* (compiler warning) */
	f = NULL;				/* (force new font) */
	if (incr > 0) {				/* under the staff */
		j = 0;
/*fixme: may not be the current font*/
		y -= cfmt.font_tb[VOCALFONT].size;
		if (y > -cfmt.vocalspace)
			y = -cfmt.vocalspace;
	} else {
		int top;

		top = staff_tb[p_voice->staff].topbar;
		j = nly - 1;
		nly = -1;
		if (y < top + cfmt.vocalspace - cfmt.font_tb[VOCALFONT].size)
			y = top + cfmt.vocalspace - cfmt.font_tb[VOCALFONT].size;
	}
/*fixme: may not be the current font*/
	desc = cfmt.font_tb[VOCALFONT].size * .25;	/* descent */
	for (; j != nly ; j += incr) {
		float x0, shift;

		a2b("/y{%.1f y%d}! ", y + desc, p_voice->staff);
		hyflag = lflag = 0;
		if (p_voice->hy_st & (1 << j)) {
			hyflag = 1;
			p_voice->hy_st &= ~(1 << j);
		}
		for (s = p_voice->sym; /*s*/; s = s->next)
			if (s->type != CLEF
			 && s->type != KEYSIG && s->type != TIMESIG)
				break;
		if (s->prev)
			lastx = s->prev->x;
		else
			lastx = 0;
		x0 = 0;
		if (f != 0)
			lskip = f->size * 1.1;
		for ( ; s; s = s->next) {
			ly = s->ly;
			if (!ly
			 || (lyl = ly->lyl[j]) == NULL) {
				switch (s->type) {
				case NOTEREST:
					if (s->as.type == ABC_T_NOTE)
						break;
					/* fall thru */
				case MREST:
					if (lflag) {
						putx(x0 - lastx);
						putx(lastx + 3);
						a2b("y wln ");
						lflag = 0;
						lastx = s->x + s->wr;
					}
				}
				continue;
			}
			if (lyl->f != f) {		/* font change */
				f = lyl->f;
				str_font(f - cfmt.font_tb);
				if (lskip < f->size * 1.1)
					lskip = f->size * 1.1;
			}
			p = lyl->t;
			w = lyl->w;
			shift = lyl->s;
			if (hyflag) {
				if (*p == LY_UNDER) {		/* '_' */
					*p = LY_HYPH;
				} else if (*p != LY_HYPH) {	/* not '-' */
					putx(s->x - shift - lastx);
					putx(lastx);
					a2b("y hyph ");
					hyflag = 0;
					lastx = s->x + s->wr;
				}
			}
			if (lflag
			 && *p != LY_UNDER) {		/* not '_' */
				putx(x0 - lastx + 3);
				putx(lastx + 3);
				a2b("y wln ");
				lflag = 0;
				lastx = s->x + s->wr;
			}
			if (*p == LY_HYPH			/* '-' */
			 || *p == LY_UNDER) {		/* '_' */
				if (x0 == 0 && lastx > s->x - 18)
					lastx = s->x - 18;
				if (*p == LY_HYPH)
					hyflag = 1;
				else
					lflag = 1;
				x0 = s->x - shift;
				continue;
			}
			x0 = s->x - shift;
			l = strlen(p) - 1;
			if (p[l] == LY_HYPH) {		/* '-' at end */
				p[l] = '\0';
				hyflag = 1;
			}
			putx(x0);
			a2b("y M ");
			put_str(p, A_LYRIC);
			lastx = x0 + w;
		}
		if (hyflag) {
			x0 = realwidth - 10;
			if (x0 < lastx + 10)
				x0 = lastx + 10;
			putx(x0 - lastx);
			putx(lastx);
			a2b("y hyph ");
			if (cfmt.hyphencont)
				p_voice->hy_st |= (1 << j);
		}

		/* see if any underscore in the next line */
		for (s = tsnext; s; s = s->ts_next)
			if (s->voice == p_voice - voice_tb)
				break;
		for ( ; s; s = s->next) {
			if (s->as.type == ABC_T_NOTE) {
				if (s->ly && s->ly->lyl[j] != 0
				 && s->ly->lyl[j]->t[0] == LY_UNDER) {
					lflag = 1;
					x0 = realwidth - 15;
					if (x0 < lastx + 12)
						x0 = lastx + 12;
				}
				break;
			}
		}
		if (lflag) {
			putx(x0 - lastx + 3);
			putx(lastx + 3);
			a2b("y wln");
		}
		a2b("\n");
		if (incr > 0)
			y -= lskip;
		else
			y += lskip;
	}
	if (incr > 0)
		y += lskip;
	return y;
}

/* -- draw all the lyrics and the tablatures -- */
/* (the staves are not yet defined) */
static void draw_all_lyrics(void)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *s;
	int staff, voice, nly, i;
	struct {
		short a, b;
		float top, bot;
	} lyst_tb[MAXSTAFF];
	char nly_tb[MAXVOICE];
	char above_tb[MAXVOICE];
	char rv_tb[MAXVOICE];
	float top, bot, y;

	/* check if any lyric */
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		if (p_voice->have_ly
		 || p_voice->tblts[0])
			break;
	}
	if (!p_voice)
		return;

	/* compute the number of lyrics per voice - staff
	 * and their y offset on the staff */
	memset(above_tb, 0, sizeof above_tb);
	memset(nly_tb, 0, sizeof nly_tb);
	memset(lyst_tb, 0, sizeof lyst_tb);
	staff = -1;
	top = bot = 0;
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		if (!p_voice->sym)
			continue;
		voice = p_voice - voice_tb;
		if (p_voice->staff != staff) {
			top = 0;
			bot = 0;
			staff = p_voice->staff;
		}
		nly = 0;
		if (p_voice->have_ly) {
			for (s = p_voice->sym; s; s = s->next) {
				struct lyrics *ly;
				float x, w;

				ly = s->ly;
				if (!ly)
					continue;
/*fixme:should get the real width*/
				x = s->x;
				if (ly->lyl[0] != 0) {
					x -= ly->lyl[0]->s;
					w = ly->lyl[0]->w;
				} else {
					w = 10;
				}
				y = y_get(p_voice->staff, 1, x, w);
				if (top < y)
					top = y;
				y = y_get(p_voice->staff, 0, x, w);
				if (bot > y)
					bot = y;
				for (i = MAXLY; --i >= 0; )
					if (ly->lyl[i] != 0)
						break;
				i++;
				if (i > nly)
					nly = i;
			}
		} else {
			y = y_get(p_voice->staff, 1, 0, realwidth);
			if (top < y)
				top = y;
			y = y_get(p_voice->staff, 0, 0, realwidth);
			if (bot > y)
				bot = y;
		}
		lyst_tb[staff].top = top;
		lyst_tb[staff].bot = bot;
		if (nly == 0)
			continue;
		nly_tb[voice] = nly;
		if (p_voice->posit.voc != 0)
			above_tb[voice] = p_voice->posit.voc == SL_ABOVE;
		else if (p_voice->next
/*fixme:%%staves:KO - find an other way..*/
		      && p_voice->next->staff == staff
		      && p_voice->next->have_ly)
			above_tb[voice] = 1;
		if (above_tb[voice])
			lyst_tb[staff].a = 1;
		else
			lyst_tb[staff].b = 1;
	}

	/* draw the lyrics under the staves */
	i = 0;
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		struct tblt_s *tblt;

		if (!p_voice->sym)
			continue;
		if (!p_voice->have_ly
		 && !p_voice->tblts[0])
			continue;
		voice = p_voice - voice_tb;
		if (above_tb[voice]) {
			rv_tb[i++] = voice;
			continue;
		}
		staff = p_voice->staff;
		set_sscale(staff);
		if (nly_tb[voice] > 0)
			lyst_tb[staff].bot = draw_lyrics(p_voice, nly_tb[voice],
							 lyst_tb[staff].bot, 1);
		for (nly = 0; nly < 2; nly++) {
			if ((tblt = p_voice->tblts[nly]) == NULL)
				break;
			if (tblt->hu > 0) {
				lyst_tb[staff].bot -= tblt->hu;
				lyst_tb[staff].b = 1;
			}
			if (tblt->pitch == 0)
				draw_tblt_w(p_voice, nly_tb[voice],
					lyst_tb[staff].bot, tblt);
			else
				draw_tblt_p(p_voice, lyst_tb[staff].bot,
					tblt);
			if (tblt->ha != 0) {
				lyst_tb[staff].top += tblt->ha;
				lyst_tb[staff].a = 1;
			}
		}
	}

	/* draw the lyrics above the staff */
	while (--i >= 0) {
		voice = rv_tb[i];
		p_voice = &voice_tb[voice];
		staff = p_voice->staff;
		set_sscale(staff);
		lyst_tb[staff].top = draw_lyrics(p_voice, nly_tb[voice],
						 lyst_tb[staff].top, -1);
	}

	/* set the max y offsets of all symbols */
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		if (!p_voice->sym)
			continue;
		staff = p_voice->staff;
		set_sscale(staff);
		if (lyst_tb[staff].a) {
			top = lyst_tb[staff].top + 2;
			for (s = p_voice->sym->next; s; s = s->next) {
/*fixme: may have lyrics crossing a next symbol*/
				if (s->ly) {
/*fixme:should set the real width*/
					y_set(staff, 1, s->x - 2, 10, top);
				}
			}
		}
		if (lyst_tb[staff].b) {
			bot = lyst_tb[staff].bot - 2;
			if (nly_tb[p_voice - voice_tb] > 0) {
				for (s = p_voice->sym->next; s; s = s->next) {
					if (s->ly) {
/*fixme:should set the real width*/
						y_set(staff, 0, s->x - 2, 10, bot);
					}
				}
			} else {
				y_set(staff, 0, 0, realwidth, bot);
			}
		}
	}
}

/* -- draw the symbols near the notes -- */
/* (the staves are not yet defined) */
/* order:
 * - beams
 * - decorations near the notes
 * - measure bar numbers
 * - n-plets
 * - decorations tied to the notes
 * - slurs
 * - guitar chords
 * - then remaining decorations
 * The buffer output is delayed until the definition of the staff system,
 * so, global variables must be saved (see music.c delayed_output()).
 */
void draw_sym_near(void)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *s;

	/* calculate the beams but don't draw them (the staves are not yet defined) */
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		struct BEAM bm;
		int first_note = 1;

		for (s = p_voice->sym; s; s = s->next) {
			if (s->as.type != ABC_T_NOTE)
				continue;
			if (((s->sflags & S_BEAM_ST) && !(s->sflags & S_BEAM_END))
			 || (first_note && !(s->sflags & S_BEAM_ST))) {
				first_note = 0;
				calculate_beam(&bm, s);
			}
		}
	}

	/* initialize the y offsets */
	{
		int i, staff;

		for (staff = 0; staff <= nstaff; staff++) {
			for (i = 0; i < YSTEP; i++) {
				staff_tb[staff].top[i] = 0;
				staff_tb[staff].bot[i] = 24;
			}
		}
	}

	set_tie_room();
	draw_deco_near();

	/* set the min/max vertical offsets */
	for (s = tsfirst; s; s = s->ts_next) {
		int y;
		struct SYMBOL *g;

//		if (!s->prev)
//			continue;		/* skip the clefs */
		if (s->as.flags & ABC_F_INVIS)
			continue;
		if (s->type == GRACE) {
			g = s->extra;
			for ( ; g; g = g->next) {
				y_set(s->staff, 1, g->x - g->wl, g->wl + g->wr,
						g->ymx + 1);
				y_set(s->staff, 0, g->x - g->wl, g->wl + g->wr,
						g->ymn - 1);
			}
			continue;
		}
		if (s->type != MREST) {
			y_set(s->staff, 1, s->x - s->wl, s->wl + s->wr, s->ymx + 2);
			y_set(s->staff, 0, s->x - s->wl, s->wl + s->wr, s->ymn - 2);
		} else {
			y_set(s->staff, 1, s->x - 16, 32, s->ymx + 2);
		}
		if (s->as.type != ABC_T_NOTE)
			continue;

		/* have room for the accidentals */
		if (s->as.u.note.accs[s->nhd]) {
			y = s->y + 8;
			if (s->ymx < y)
				s->ymx = y;
			y_set(s->staff, 1, s->x, 0., y);
		}
		if (s->as.u.note.accs[0]) {
			y = s->y;
			if ((s->as.u.note.accs[0] & 0x07) == A_SH
			 || s->as.u.note.accs[0] == A_NT)
				y -= 7;
			else
				y -= 5;
			if (s->ymn > y)
				s->ymn = y;
			y_set(s->staff, 0, s->x, 0., y);
		}
	}

	if (cfmt.measurenb >= 0)
		draw_measnb();

	draw_deco_note();

	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		s = p_voice->sym;
		if (!s)
			continue;
		set_sscale(cursys->voice[p_voice - voice_tb].staff);

		/* draw the tuplets near the notes */
		for (s = s->next; s; s = s->next) {
			struct SYMBOL *g;

			if ((s->sflags & S_IN_TUPLET)
			 && (g = s->extra) != NULL) {
				for ( ; g; g = g->next) {
					if (g->type == TUPLET) {
						s = draw_tuplet(g, s);
						break;
					}
				}
			}
		}
		draw_all_slurs(p_voice);

		/* draw the tuplets over the slurs */
		for (s = p_voice->sym->next; s; s = s->next) {
			struct SYMBOL *g;

			if ((s->sflags & S_IN_TUPLET)
			 && (g = s->extra) != NULL) {
				for ( ; g; g = g->next) {
					if (g->type == TUPLET) {
						s = draw_tuplet(g, s);
						break;
					}
				}
			}
		}
	}

	/* set the top and bottom for all symbols to be out of the staves */
	{
		int top, bot, i, staff;

		for (staff = 0; staff <= nstaff; staff++) {
			top = staff_tb[staff].topbar + 2;
			bot = staff_tb[staff].botbar - 2;
/*fixme:should handle stafflines changes*/
			for (i = 0; i < YSTEP; i++) {
				if (top > staff_tb[staff].top[i])
					staff_tb[staff].top[i] = (float) top;
				if (bot < staff_tb[staff].bot[i])
					staff_tb[staff].bot[i] = (float) bot;
			}
		}
	}
	draw_all_lyrics();
	draw_deco_staff();
	set_sscale(-1);		/* restore the scale parameters */
}

/* -- draw the name/subname of the voices -- */
static void draw_vname(float indent)
{
	struct VOICE_S *p_voice;
	int n, staff;
	struct {
		int nl;
		char *v[8];
	} staff_d[MAXSTAFF], *staff_p;
	char *p, *q;
	float y;

	for (staff = cursys->nstaff; staff >= 0; staff--) {
		if (!cursys->staff[staff].empty)
			break;
	}
	if (staff < 0)
		return;

	memset(staff_d, 0, sizeof staff_d);
	n = 0;
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		if (!p_voice->sym)
			continue;
		staff = cursys->voice[p_voice - voice_tb].staff;
		if (cursys->staff[staff].empty)
			continue;
		if (p_voice->new_name) {
			p_voice->new_name = 0;
			p = p_voice->nm;
		} else {
			p = p_voice->snm;
		}
		if (!p)
			continue;
		if (cursys->staff[staff].flags & CLOSE_BRACE2) {
			while (!(cursys->staff[staff].flags & OPEN_BRACE2))
				staff--;
		} else if (cursys->staff[staff].flags & CLOSE_BRACE) {
			while (!(cursys->staff[staff].flags & OPEN_BRACE))
				staff--;
		}
		staff_p = &staff_d[staff];
		for (;;) {
			staff_p->v[staff_p->nl++] = p;
			p = strstr(p, "\\n");
			if (!p
			 || staff_p->nl >= MAXSTAFF)
				break;
			p += 2;
		}
		n++;
	}
	if (n == 0)
		return;
	str_font(VOICEFONT);
	indent = -indent * .5;			/* center */
	for (staff = nstaff; staff >= 0; staff--) {
		staff_p = &staff_d[staff];
		if (staff_p->nl == 0)
			continue;
		y = staff_tb[staff].y
			+ staff_tb[staff].topbar * .5
				* staff_tb[staff].clef.staffscale
			+ 9 * (staff_p->nl - 1)
			- cfmt.font_tb[VOICEFONT].size * .3;
		n = staff;
		if (cursys->staff[staff].flags & OPEN_BRACE2) {
			while (!(cursys->staff[n].flags & CLOSE_BRACE2))
				n++;
		} else if (cursys->staff[staff].flags & OPEN_BRACE) {
			while (!(cursys->staff[n].flags & CLOSE_BRACE))
				n++;
		}
		if (n != staff)
			y -= (staff_tb[staff].y - staff_tb[n].y) * .5;
		for (n = 0; n < staff_p->nl; n++) {
			p = staff_p->v[n];
			q = strstr(p, "\\n");
			if (q)
				*q = '\0';
			a2b("%.1f %.1f M ", indent, y);
			put_str(p, A_CENTER);
			y -= 18.;
			if (q)
				*q = '\\';
		}
	}
}

/* -- adjust the empty flag in a staff system -- */
static void set_empty(struct SYSTEM *sy)
{
	int staff;

	/* if a system brace has empty and non empty staves, keep all staves */
	for (staff = 0; staff <= nstaff; staff++) {
		int i, empty_fl;

		if (!(sy->staff[staff].flags & (OPEN_BRACE | OPEN_BRACE2)))
			continue;
		empty_fl = 0;
		i = staff;
		while (staff <= nstaff) {
			if (sy->staff[staff].empty)
				empty_fl |= 1;
			else
				empty_fl |= 2;
			if (cursys->staff[staff].flags & (CLOSE_BRACE | CLOSE_BRACE2))
				break;
			staff++;
		}
		if (empty_fl == 3) {	/* if empty and not empty staves */
/*fixme: add measure bars on empty main voices*/
			while (i <= staff)
				sy->staff[i++].empty = 0;
		}
	}
}

/* -- set the y offset of the staves and return the whole height -- */
static float set_staff(void)
{
	struct SYSTEM *sy;
	struct SYMBOL *s;
	int i, staff, prev_staff;
	float y, staffsep, dy, maxsep, mbot, v;
	char empty[MAXSTAFF];

	/* search the empty staves in each parts */
	memset(empty, 1, sizeof empty);
	for (staff = 0; staff <= nstaff; staff++)
		staff_tb[staff].empty = 0;
	sy = cursys;
	set_empty(sy);
	for (staff = 0; staff <= nstaff; staff++) {
		if (!sy->staff[staff].empty)
			empty[staff] = 0;
	}
	for (s = tsfirst; s; s = s->ts_next) {
		if (s->type != STAVES)
			continue;
		sy = sy->next;
		set_empty(sy);
		for (staff = 0; staff <= nstaff; staff++) {
			if (!sy->staff[staff].empty)
				empty[staff] = 0;
		}
	}

	/* output the scale of the voices */
	{
		struct VOICE_S *p_voice;

		for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
			if (p_voice->scale != 1)
				a2b("/scvo%d{gsave %.2f dup scale}!\n",
				     (int) (p_voice - voice_tb),
				     p_voice->scale);
		}
	}

	/* set the vertical offset of the 1st staff */
	for (staff = 0; staff <= nstaff; staff++) {
		if (!empty[staff])
			break;
		staff_tb[staff].empty = 1;
	}
	if (staff > nstaff)
		staff--;			/* one staff, empty */

	y = 0;
	for (i = 0; i < YSTEP; i++) {
		v = staff_tb[staff].top[i];
		if (y < v)
			y = v;
	}

	/* draw the parts and tempo indications if any */
	y += draw_partempo(staff, y);

	staffsep = cfmt.staffsep * 0.5 +
			staff_tb[staff].topbar * staff_tb[staff].clef.staffscale;
	if (y < staffsep)
		y = staffsep;
	staff_tb[staff].y = -y;

	/* set the offset of the other staves */
	prev_staff = staff;
	for (staff++; staff <= nstaff; staff++) {
		if (empty[staff]) {
			staff_tb[staff].empty = 1;
			continue;
		}
		if (sy->staff[prev_staff].sep != 0)
			staffsep = sy->staff[prev_staff].sep;
		else
			staffsep = cfmt.sysstaffsep;
		if (sy->staff[prev_staff].maxsep != 0)
			maxsep = sy->staff[prev_staff].maxsep;
		else
			maxsep = cfmt.maxsysstaffsep;

		dy = 0;
		if (staff_tb[staff].clef.staffscale
				== staff_tb[prev_staff].clef.staffscale) {
			for (i = 0; i < YSTEP; i++) {
				v = staff_tb[staff].top[i]
				  - staff_tb[prev_staff].bot[i];
				if (dy < v)
					dy = v;
			}
			dy *= staff_tb[staff].clef.staffscale;
		} else {
			for (i = 0; i < YSTEP; i++) {
				v = staff_tb[staff].top[i]
					* staff_tb[staff].clef.staffscale
				  - staff_tb[prev_staff].bot[i]
					* staff_tb[prev_staff].clef.staffscale;
				if (dy < v)
					dy = v;
			}
		}
		staffsep += staff_tb[staff].topbar
				* staff_tb[staff].clef.staffscale;
		if (dy < staffsep)
			dy = staffsep;
		maxsep += staff_tb[staff].topbar
				* staff_tb[staff].clef.staffscale;
		if (dy > maxsep)
			dy = maxsep;
		y += dy;
		staff_tb[staff].y = -y;

		prev_staff = staff;
	}
	mbot = 0;
	for (i = 0; i < YSTEP; i++) {
		v = staff_tb[prev_staff].bot[i];
		if (mbot > v)
			mbot = v;
	}
	mbot *= staff_tb[prev_staff].clef.staffscale;

	/* output the staff offsets */
	for (staff = nstaff; staff >= 0; staff--) {
		dy = staff_tb[staff].y;
		if (staff_tb[staff].clef.staffscale != 1
		 && staff_tb[staff].clef.staffscale != 0) {
			a2b("/scst%d{gsave 0 %.2f T %.2f dup scale}!\n",
			     staff, dy, staff_tb[staff].clef.staffscale);
			a2b("/y%d{}!\n", staff);
		} else {
			a2b("/y%d{%.1f add}!\n", staff, dy);
		}
	}

	if (mbot == 0) {
		for (staff = nstaff; staff >= 0; staff--) {
			if (!empty[staff])
				break;
		}
		if (staff < 0)		/* no symbol in this system ! */
			return y;
	}
	dy = -mbot;
	staffsep = cfmt.staffsep * 0.5;
	if (dy < staffsep)
		dy = staffsep;
	maxsep = cfmt.maxstaffsep * 0.5;
	if (dy > maxsep)
		dy = maxsep;
	y += dy;
	if (y > cfmt.maxstaffsep)
		y = cfmt.maxstaffsep;

	/* return the whole staff system height */
	return y;
}

/* -- set the bottom and height of the measure bars -- */
static void bar_set(float *bar_bot, float *bar_height)
{
	int staff, nlines;
	float dy, staffscale;
			/* !! max number of staff lines !! */
	static const char top[10] = {18, 18, 12, 18, 18, 24, 30, 36, 42, 48};
	static const char bot[10] = { 6,  6,  6,  6,  0,  0,  0,  0,  0,  0};

	dy = 0;
	for (staff = 0; staff <= nstaff; staff++) {
		nlines = cursys->staff[staff].clef.stafflines;
		staffscale = cursys->staff[staff].clef.staffscale;
		if (cursys->staff[staff].empty) {
			bar_bot[staff] = bar_height[staff] = 0;
			continue;
		}
		if (dy == 0)
			dy = staff_tb[staff].y + top[nlines] * staffscale;
		bar_height[staff] = dy
				- staff_tb[staff].y - bot[nlines] * staffscale;

		bar_bot[staff] = staff_tb[staff].y + bot[nlines] * staffscale;

		if (cursys->staff[staff].flags & STOP_BAR)
			dy = 0;
		else
			dy = bar_bot[staff];
	}
}

/* -- draw the staff systems and the measure bars -- */
float draw_systems(float indent)
{
	struct SYSTEM *next_sy;
	struct SYMBOL *s, *s2;
	int staff;
	float xstaff[MAXSTAFF], bar_bot[MAXSTAFF], bar_height[MAXSTAFF];
	float x, x2;
	float line_height;

	line_height = set_staff();
	draw_vname(indent);

	/* draw the staff, skipping the staff breaks */
	for (staff = 0; staff <= nstaff; staff++)
		xstaff[staff] = cursys->staff[staff].empty ? -1 : 0;
	bar_set(bar_bot, bar_height);
	draw_lstaff(0);
	for (s = tsfirst; s; s = s->ts_next) {
		staff = s->staff;
		switch (s->type) {
		case STAVES:
			next_sy = cursys->next;
			for (staff = 0; staff <= nstaff; staff++) {
				if (next_sy->staff[staff].empty
						== cursys->staff[staff].empty
				 && next_sy->staff[staff].clef.stafflines
						== cursys->staff[staff].clef.stafflines)
					continue;
				x2 = s->x;
				if ((x = xstaff[staff]) >= 0) {
					if (s->ts_prev->type == BAR)
						x2 = s->ts_prev->x;
					draw_staff(staff, x, x2);
				}
				if (next_sy->staff[staff].empty) {
					xstaff[staff] = -1;
				} else if (xstaff[staff] < 0) {
					if (s->ts_next->type != BAR)
						xstaff[staff] = x2;
					else
						xstaff[staff] = s->ts_next->x;
				} else {
					xstaff[staff] = x2;
				}
			}
			cursys = next_sy;
			bar_set(bar_bot, bar_height);
			break;
		case BAR:
			if ((s->sflags & S_SECOND)
			 || cursys->staff[staff].empty)
				s->as.flags |= ABC_F_INVIS;
			if (s->as.flags & ABC_F_INVIS)
				break;
			draw_bar(s, bar_bot[staff], bar_height[staff]);
			if (annotate)
				anno_out(s, 'B');
			break;
		case STBRK:
			if (cursys->voice[s->voice].range == 0) {
				if (s->next
				 && s->next->type == STAVES)
					s->next->x = s->x;
				if ( s->xmx > .5 CM) {
					int i, nvoice;

					/* draw the left system if stbrk in all voices */
					nvoice = 0;
					for (i = 0; i < MAXVOICE; i++) {
						if (cursys->voice[i].range > 0)
							nvoice++;
					}
					for (s2 = s->ts_next; s2; s2 = s2->ts_next) {
						if (s2->type != STBRK)
							break;
						nvoice--;
					}
					if (nvoice == 0)
						draw_lstaff(s->x);
				}
			}
			s2 = s->prev;
			if (!s2)
				break;
			if (s2->type == STAVES)
				s2 = s2->prev;
			x2 = s2->x;
			if (s2->type != BAR)
				x2 += s2->wr;
			staff = s->staff;
			x = xstaff[staff];
			if (x >= 0) {
				if (x >= x2)
					continue;
				draw_staff(staff, x, x2);
			}
			xstaff[staff] = s->x;
			break;
		default:
//fixme:does not work for "%%staves K: M: $" */
//removed for K:/M: in empty staves
//			if (cursys->staff[staff].empty)
//				s->as.flags |= ABC_F_INVIS;
			break;
		}
	}
	for (staff = 0; staff <= nstaff; staff++) {
		if ((x = xstaff[staff]) < 0
		 || x >= realwidth - 8)
			continue;
		draw_staff(staff, x, realwidth);
	}
	set_sscale(-1);
	return line_height;
}

/* -- output PostScript sequences -- */
void output_ps(struct SYMBOL *s, int state)
{
	struct SYMBOL *g, *g2;

	g = s->extra;
	g2 = NULL;
	for (;;) {
		if (g->type == FMTCHG
		 && (g->u == PSSEQ || g->u == SVGSEQ)
		 && g->as.state <= state) {
			if (g->u == SVGSEQ)
				a2b("%%svg %s\n", g->as.text);
			else
				a2b("%s\n", g->as.text);
			if (!g2)
				s->extra = g->next;
			else
				g2->next = g->next;
		} else {
			g2 = g;
		}
		g = g->next;
		if (!g)
			break;
	}
}

/* -- draw remaining symbols when the staves are defined -- */
static void draw_symbols(struct VOICE_S *p_voice)
{
	struct BEAM bm;
	struct SYMBOL *s;
	float x, y;
	int staff, first_note;

	/* output the PostScript code at start of line */
	for (s = p_voice->sym; s; s = s->next) {
		if (s->extra)
			output_ps(s, 127);
		switch (s->type) {
		case CLEF:
		case KEYSIG:
		case TIMESIG:
		case BAR:
			continue;	/* skip the symbols added by init_music_line() */
		}
		break;
	}

	bm.s2 = NULL;
	first_note = 1;
	for (s = p_voice->sym; s; s = s->next) {
		if (s->extra)
			output_ps(s, 127);
		if ((s->as.flags & ABC_F_INVIS)
		 && s->type != NOTEREST && s->type != GRACE)
			continue;
		x = s->x;
		switch (s->type) {
		case NOTEREST:
			set_scale(s);
			if (s->as.type == ABC_T_NOTE) {
				if ((s->sflags & (S_BEAM_ST | S_BEAM_END)) == S_BEAM_ST
				 || (first_note && !(s->sflags & S_BEAM_ST))) {
					first_note = 0;
					if (calculate_beam(&bm, s)) {
						if (annotate)
							anno_out(s, 'b');
						draw_beams(&bm);
					}
				}
				draw_note(x, s, bm.s2 == NULL);
				if (annotate)
					anno_out(s, 'N');
				if (s == bm.s2)
					bm.s2 = NULL;
				if (annotate
				 && (s->sflags & (S_BEAM_ST | S_BEAM_END))
							== S_BEAM_END)
					anno_out(s, 'e');
				break;
			}
			draw_rest(s);
			if (annotate)
				anno_out(s, 'R');
			break;
		case BAR:
			break;			/* drawn in draw_systems */
		case CLEF:
			staff = s->staff;
			if (s->sflags & S_SECOND)
/*			 || p_voice->staff != staff)	*/
				break;		/* only one clef per staff */
			if ((s->as.flags & ABC_F_INVIS)
			 || staff_tb[staff].empty)
				break;
			set_sscale(staff);
			y = staff_tb[staff].y;
			x -= 10;	/* clef shift - see set_width() */
			putxy(x, y + s->y);
			if (s->as.u.clef.name)
				a2b("%s\n", s->as.u.clef.name);
			else
				a2b("%c%cclef\n",
				     s->u ? 's' : ' ',
				     "tcbp"[(unsigned) s->as.u.clef.type]);
			if (s->as.u.clef.octave != 0) {
/*fixme:break the compatibility and avoid strange numbers*/
				if (s->as.u.clef.octave > 0)
					y += s->ymx - 12;
				else
					y += s->ymn + 2;
				putxy(x, y);
				a2b("oct%c\n",
				     s->as.u.clef.octave > 0 ? 'u' : 'l');
			}
			if (annotate)
				anno_out(s, 'c');
			break;
		case TIMESIG:
			memcpy(&p_voice->meter, &s->as.u.meter,
			       sizeof p_voice->meter);
			if ((s->sflags & S_SECOND)
			 || staff_tb[s->staff].empty)
				break;
			if (cfmt.alignbars && s->staff != 0)
				break;
			set_sscale(s->staff);
			draw_timesig(x, s);
			if (annotate)
				anno_out(s, 'M');
			break;
		case KEYSIG:
			memcpy(&p_voice->key, &s->as.u.key,
			       sizeof p_voice->key);
			if ((s->sflags & S_SECOND)
			 || staff_tb[s->staff].empty)
				break;
			set_sscale(s->staff);
			draw_keysig(p_voice, x, s);
			if (annotate)
				anno_out(s, 'K');
			break;
		case MREST:
			set_scale(s);
			a2b("(%d)", s->as.u.bar.len);
			putxy(x, staff_tb[s->staff].y);
			a2b("mrest\n");
			break;
		case GRACE:
			set_scale(s);
			draw_gracenotes(s);
			break;
		case SPACE:
		case STAVES:
		case STBRK:
		case FMTCHG:
			break;			/* nothing */
		case CUSTOS:
			set_scale(s);
			s->sflags |= ABC_F_STEMLESS;
			draw_note(x, s, 0);
			break;
		default:
			bug("Symbol not drawn", 1);
		}
	}
	set_scale(p_voice->sym);
	draw_all_ties(p_voice);
}

/* -- draw all symbols -- */
void draw_all_symb(void)
{
	struct VOICE_S *p_voice;

	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
#if 0 /* no: did display the rests when "%%staffnonote 0" */
		if (!p_voice->sym)
#else
		if (!p_voice->sym
		 || staff_tb[p_voice->staff].empty)
#endif
			continue;
		draw_symbols(p_voice);
	}
}

/* -- output a floating value, and x and y according to the current scale -- */
void putf(float v)
{
	a2b("%.1f ", v);
}

void putx(float x)
{
	putf(x / cur_scale);
}

void puty(float y)
{
	putf(scale_voice ?
		y / cur_scale :		/* scaled voice */
		y - cur_trans);		/* scaled staff */
}

void putxy(float x, float y)
{
	if (scale_voice)
		a2b("%.1f %.1f ",
		     x / cur_scale, y / cur_scale);	/* scaled voice */
	else
		a2b("%.1f %.1f ",
		     x / cur_scale, y - cur_trans);	/* scaled staff */
}

/* -- set the voice or staff scale -- */
void set_scale(struct SYMBOL *s)
{
	int staff;
	float scale, trans;

	staff = -1;
	scale = voice_tb[s->voice].scale;
	if (scale == 1) {
		staff = s->staff;
		scale = staff_tb[staff].clef.staffscale;
	}
/*fixme: KO when both staff and voice are scaled */
	if (staff >= 0 && scale != 1) {
		trans = staff_tb[staff].y;
		scale_voice = 0;
		if (staff != cur_staff && cur_scale != 1)
			cur_scale = 0;
	} else {
		trans = 0;
		scale_voice = 1;
	}
	if (scale == cur_scale && trans == cur_trans)
		return;
	if (cur_scale != 1)
		a2b("grestore ");
	cur_scale = scale;
	cur_trans = trans;
	if (scale != 1) {
		if (scale_voice) {
			a2b("scvo%d ", s->voice);
		} else {
			a2b("scst%d ", staff);
			cur_staff = staff;
		}
	}
}

/* -- set the staff scale (only) -- */
void set_sscale(int staff)
{
	float scale, trans;

	scale_voice = 0;
	if (staff != cur_staff && cur_scale != 1)
		cur_scale = 0;
	if (staff >= 0)
		scale = staff_tb[staff].clef.staffscale;
	else
		scale = 1;
	if (staff >= 0 && scale != 1)
		trans = staff_tb[staff].y;
	else
		trans = 0;
	if (scale == cur_scale && trans == cur_trans)
		return;
	if (cur_scale != 1)
		a2b("grestore ");
	cur_scale = scale;
	cur_trans = trans;
	if (scale != 1) {
		a2b("scst%d ", staff);
		cur_staff = staff;
	}
}

/* -- set the tie directions for one voice -- */
static void set_tie_dir(struct SYMBOL *sym)
{
	struct SYMBOL *s;
	int i, ntie, dir, sec, pit, ti;

	for (s = sym; s; s = s->next) {
		if (!(s->sflags & S_TI1))
			continue;

		/* if other voice, set the ties in opposite direction */
		if (s->multi != 0) {
/*			struct SYMBOL *s2;

			s2 = s->ts_next;
			if (s2->time == s->time && s2->staff == s->staff) { */
				dir = s->multi > 0 ? SL_ABOVE : SL_BELOW;
				for (i = 0; i <= s->nhd; i++) {
					ti = s->as.u.note.ti1[i];
					if (!((ti & 0x03) == SL_AUTO))
						continue;
					s->as.u.note.ti1[i] = (ti & SL_DOTTED) | dir;
				}
				continue;
/*			} */
		}

		/* if one note, set the direction according to the stem */
		sec = ntie = 0;
		pit = 128;
		for (i = 0; i <= s->nhd; i++) {
			if (s->as.u.note.ti1[i]) {
				ntie++;
				if (pit < 128
				 && s->as.u.note.pits[i] <= pit + 1)
					sec++;
				pit = s->as.u.note.pits[i];
			}
		}
		if (ntie <= 1) {
			dir = s->stem < 0 ? SL_ABOVE : SL_BELOW;
			for (i = 0; i <= s->nhd; i++) {
				ti = s->as.u.note.ti1[i];
				if (ti != 0) {
					if ((ti & 0x03) == SL_AUTO)
						s->as.u.note.ti1[i] =
							(ti & SL_DOTTED) | dir;
					break;
				}
			}
			continue;
		}
		if (sec == 0) {
			if (ntie & 1) {
/* in chords with an odd number of notes, the outer noteheads are paired off
 * center notes are tied according to their position in relation to the
 * center line */
				ntie = ntie / 2;
				dir = SL_BELOW;
				for (i = 0; i <= s->nhd; i++) {
					ti = s->as.u.note.ti1[i];
					if (ti == 0)
						continue;
					if (ntie == 0) {	/* central tie */
						if (s->pits[i] >= 22)
							dir = SL_ABOVE;
					}
					if ((ti & 0x03) == SL_AUTO)
						s->as.u.note.ti1[i] =
							(ti & SL_DOTTED) | dir;
					if (ntie-- == 0)
						dir = SL_ABOVE;
				}
				continue;
			} else {
/* even number of notes, ties divided in opposite directions */
				ntie /= 2;
				dir = SL_BELOW;
				for (i = 0; i <= s->nhd; i++) {
					ti = s->as.u.note.ti1[i];
					if (ti == 0)
						continue;
					if ((ti & 0x03) == SL_AUTO)
						s->as.u.note.ti1[i] =
							(ti & SL_DOTTED) | dir;
					if (--ntie == 0)
						dir = SL_ABOVE;
				}
				continue;
			}
		}
/*fixme: treat more than one second */
/*		if (nsec == 1) {	*/
/* When a chord contains the interval of a second, tie those two notes in
 * opposition; then fill in the remaining notes of the chord accordingly */
			pit = 128;
			for (i = 0; i <= s->nhd; i++) {
				if (s->as.u.note.ti1[i]) {
					if (pit < 128
					 && s->as.u.note.pits[i] <= pit + 1) {
						ntie = i;
						break;
					}
					pit = s->as.u.note.pits[i];
				}
			}
			dir = SL_BELOW;
			for (i = 0; i <= s->nhd; i++) {
				ti = s->as.u.note.ti1[i];
				if (ti == 0)
					continue;
				if (ntie == i)
					dir = SL_ABOVE;
				if ((ti & 0x03) == SL_AUTO)
					s->as.u.note.ti1[i] =
							(ti & SL_DOTTED) | dir;
			}
/*fixme..
			continue;
		}
..*/
/* if a chord contains more than one pair of seconds, the pair farthest
 * from the center line receives the ties drawn in opposition */
	}
}

/* -- have room for the ties out of the staves -- */
static void set_tie_room(void)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *s, *s2;

	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		s = p_voice->sym;
		if (!s)
			continue;
		s = s->next;
		if (!s)
			continue;
		set_tie_dir(s);
		for ( ; s; s = s->next) {
			float dx, y, dy;

			if (!(s->sflags & S_TI1))
				continue;
			if (s->pits[0] < 20 && s->as.u.note.ti1[0] == SL_BELOW)
				;
			else if (s->pits[s->nhd] > 24
			      && s->as.u.note.ti1[s->nhd] == SL_ABOVE)
				;
			else
				continue;
			s2 = s->next;
			while (s2 && s2->as.type != ABC_T_NOTE)
				s2 = s2->next;
			if (s2) {
				if (s2->staff != s->staff)
					continue;
				dx = s2->x - s->x - 10;
			} else {
				dx = realwidth - s->x - 10;
			}
			if (dx < 100)
				dy = 9;
			else if (dx < 300)
				dy = 12;
			else
				dy = 16;
			if (s->pits[s->nhd] > 24) {
				y = 3 * (s->pits[s->nhd] - 18) + dy;
				if (s->ymx < y)
					s->ymx = y;
				if (s2 && s2->ymx < y)
					s2->ymx = y;
				y_set(s->staff, 1, s->x + 5, dx, y);
			}
			if (s->pits[0] < 20) {
				y = 3 * (s->pits[0] - 18) - dy;
				if (s->ymn > y)
					s->ymn = y;
				if (s2 && s2->ymn > y)
					s2->ymn = y;
				y_set(s->staff, 0, s->x + 5, dx, y);
			}
		}
	}
}
abcm2ps-7.8.13/features.txt0000644000175000017500000002743012314503276013623 0ustar  jefjef	Features of abcm2ps 7.6.9 (J.F. Moine, January 2014)
	====================================================

abcm2ps tries to follow the ABC standard version 2.1 (december 2011):

	http://abcnotation.com/wiki/abc:standard:v2.1

Here are listed only the differences from the standard.


Features not implemented.
========================

Information fields.

	- The continuation field ('+:') is implemented for w: only.

	- The charsets iso-8859-5 .. iso-8859-8 are not implemented.

Tune body.

	- The following decorations are not implemented:
		!dacoda!, !dacapo!

	- 'U:' fields cannot contain guitar chord nor annotations.

	- The values assigned by the 'U:' field are always global (they
	  are not restored at end of tune).

	- Multiple measure overlay (as '&&') is not implemented.
	  Use the '(& .. & .. & .. &) extension instead.

Text strings.

	- The HTML sequences are not implemented.

	- The unicode '\Uxxxxxxxx' 32 bits character is not implemented.
	  Use the UTF-16 surrogates instead.


Features that work differently.
===============================

File structure.

	- The T: header field may be omitted when 'X:' is present.

	- There is no notion of 'file header': any valid ABC field
	  found outside the tunes is considered as global, and applies
	  to the remaining tunes.

Information fields.

	- In a tune body, the lines beginning with a letter in range A-G
	  or a-g and immediately followed by a colon are interpreted as
	  information fields.

	- When the %%abc-version is different from '2.0', the field 'A:' is
	  'Area', and not 'Author of lyrics'. It is displayed only when
	  'infoline' is set.

	- In 'K:' fields, the list of accidentals may be 'none' (for
	  no accidental).

	- In 'U:' fields, the character may be
	  '\ ' (back-slash - space) to redefine the character space, or
	  '\t' (back-slash - t) to redefine the character tabulation.
	  The default value of these characters is !beambreak! (see below).

Tune body.

	- The decorations on notes inside chords cannot be standard ones
	  because their offset is relative to the note they are attached to,
	  and not to the chord. They must be explicitly defined by %%deco
	  and %%postscript.

	- '@' in annotations must be followed by the <x> and <y> offsets
	  of the text from the note position (in points). The <x> and <y>
	  values are separated by a comma, and <y> may be followed by a
	  space (usefull if the text begins with a digit, a dot or the
	  letters 'E' or 'e' - see sample3.abc for an example).

	- Grace notes may appear before any symbol and may contain
	  chords. Their note lengths are handled. The unit note length
	  is not tied to L: (or M:). Instead, for compatibility, it is:
		- a quaver for a single note and
		  a semi-quaver for many notes in standard tunes,
		- a demi-semi-quaver in bagpipe tunes.
	  Grace notes greater than crotchets are drawn as crotchets.

	- Tuplets values may be greater than 9.

	- Tuplets may be nested.

Clefs.

	- When 'clef=' is present, the clef name may be one of
	  'G' (treble clef), 'C' (alto clef) or 'F' (bass clef).
	  The two following definitions are equivalent:
		K: clef=F
		K: bass

	- The suffixes "^8" and "_8" do an octave transposition
	  (while "+8" and "-8" don't do it).

Multiple voices.

	- When the voices are synchronized, a 'P:' field is set in the first
	  voice, without changing the current voice.
	  This fixes the common error:
		P:A
		V:1
		..
		V:2
		..
		P:B		% misplaced P: (in voice 2)
		V:1
		%		should be here
		..
		V:2
		%		and normally repeated here
		..

ABC Stylesheet specification.

	- The star ('*' = floating voice) is not treated in '%%score'.

	- '%%staves' coexists with '%%score'.
	  The differences of '%%staves' are:
		- measure bars are drawn between staves when there is
		  no '|' between the voice names (this feature is inverted
		  in %%score).
		- A floating voice may be only the second one in a
		  3 voices brace.

	- Some formatting directives are not implemented, and some other
	  ones are defined. See the file 'format.txt' for details.


Extensions.
==========

File structure.

	- Lines starting with '\' (back-slash) are ignored (abc2mtex
	  compatibility).

Information fields.

	- The field 'L:' may contain 'auto' in which case the duration of
	  each note is adjusted to fulfill the measures.
	  This value works when the measures are regular (fixed duration).
	  'L:auto' may be used in each case the measure is regular in a
	  compatible way.
	  For instance, the three following lines give a same result:
	  - standard ABC:
		L:1/4
		cccd | e2d2 | cedd | c4 |
	  - auto L:
		M:C				% required
		L:auto
		cccd | ed | cedd | c |
	  - compatible
		M:C				% required
		L:auto
		cccd | e2d2 | cedd | c4 |

	- The field 'M:' may specify more complex meters with a
	  combination of digits, parenthesis, slashes and blanks.
	  It may also specify ancient meters as 'M:2' or 'M:3',
	  and also 'M:o' (perfect minor), 'M:o.' (perfect major),
	  'M:c' (imperfect minor) and 'M:c.' (imperfect major).
	  An explicit measure duration may be specified putting its
	  value after an '=' sign (ex: 'M:C|=2/1').

	- 'microscale=<d>' in 'K:' or 'V:' fields defines the
	  denominator to use in microtonal accidentals (see 'microtone'
	  pitches below).

	- The field 'd:' is the same as 's:' (symbol line).

	- In 'U:' fields, !ignore! defines the character as ignored.
	  This is the default value for the character '`' (back-quote).

	- In 'U:' fields, !beambreak! defines the character as stopping
	  note beaming. This is the default value for the characters
	  '\ ' (space) and '\t' (tabulation).

Tune body.

	- Microtone pitches are indicated by a number or a fraction after
	  an accidental (and before the note).

	  There are two ways to define microtone pitches:

	  - old method (default)
		The pitches are indicated by a fraction of semitone as
		"^3/4c" (3/4 of a sharp).
		When omitted, the numerator defaults to 1 and the
		denominator to 2 ("^/c" is the same as "^1/2c").
		Support exists for 1/2 and 3/2 sharps and flats. For other
		values, PostScript functions must be defined (%%postscript
		or %%beginps - see below).

	  - new method
		The pitches are indicated by a fraction of tone
		(! not semitone !) when "microscale=<denominator>"
		is set in K: or V: information fields.
		With this method, only the numerator is to be set after the
		accidental as "^3c".

	  For instance, the two declarations
		- without microscale:	^3/2c
		- with microscale=4:	^3c
	  give a same result.

	  Note: the numerator and denominator cannot be greater than 255.

	  There are also two ways to implement the accidental drawing
	  function:

	  - old method 
		When neither "microscale=" nor "%%micronewps" are set,
		the name of the PostScript function which draws
		a microtone accidental is:
			<accidental_type><micro_value>
		where:
			- <accidental_type> is "sh" (sharp) or "ft" (flat)
				(may be also "nt", "dsh" or "dft" !)
			- <micro_value> is computed from the fraction as:
				(<numerator> - 1) * 256 + <denominator> - 1
		and it is called with <x> and <y>.

	  - new method
		When either "microscale=" or "%%micronewps" is set,
		the name of the PostScript function is:
			<accidental_type><fraction of tone>
		and it is called with <x> <y> <numerator>.
		Note that the <fraction of tone> is two times the pitch
		denominator when "microscale=" is not set.

	- A note length starting with '0' (zero') indicates a stemless
	  note.

	- A space ('y') may be followed by a width in points.
	  The default width is 20 pts.

	- '[]' is the same as '[|]' (invisible bar).

	- ':' (colon alone) is the same as '.|' (dotted bar).

	- ']' alone is not a bar. It stops a repeat bracket.

	- Repeat bars may contain a set of digits, '-' (hyphen),
	  ',' (comma) or '.' (dot), or even a free string. Ex:
		|: ... [1,3 ... :|2,4-6 ... :|["last time" ...
	  (note that a '[' is needed before the string - this one may
	   be empty).

	- There may be slurs from notes to grace notes and reverse.

	- Opening slurs ("(") may be followed by "'" or "," to force their
	  direction (above or below).

	- The tie character ("-") may be followed by "'" or "," to force
	  the tie direction (above or below).

	- The following decorations are added:
		!beamon!	do not break beaming (on a measure bar)
		!beambr1! and !beambr2!
				let only 1 or 2 beams from the previous note
		!gmark!		grace mark ('~' like sign)
		!invisible!	prevent a symbol to be displayed
		!rbstop!	stop here the current repeat bracket
		!trem1! .. !trem4!
				tremolo (on the second of a couple of notes
				- see sample4.abc for example)
		!xstem!		draw a stem up to the note on the previous
				staff
		!/! .. !///!	tremolo on one note
		!beam-accel! and !beam-rall!
				feathered beam

	- There may be decorations on grace notes.

	- Multiple lines of guitar chord / annotation may also be
	  indicated by '\n' or ';' in which case, the lines are of
	  the same type (gchord or annotation).
	  The 3 next notations are equivalent:
		"_ann1" "_ann2" "G3" "4"
		"_ann1;ann2" "G3;4"
		"_ann1\nann2" "G3\n4"
	  (annotation on 2 lines and guitar chord on 2 lines)
	  The two next notations are NOT equivalent:
		"_ann1" "G"
		"_ann1;G"
	  (in the 1st line, 'G' is a guitar chord,
	   in the 2nd one, it is the 2nd line of the annotation)
	  A new annotation type may be indicated after a ';' as:
		"^above;_below"

Clefs.

	- the clef definition should not be in K: or V: information fields.
	  Better use the %%clef pseudo-comment (see format.txt)

	- 'clef=P' is the same as 'perc'.

	- When the clef name is 'perc' (or 'P'), accidentals change the
	  note head glyph. By default, sharp notes are drawn as a 'x'
	  and flat notes as a circled 'x'. This behaviour may be changed
	  redefineding the PostScript functions 'pshhd' and 'pfthd', or
	  defining 'pnthd' (natural), 'pdshhd' (double sharp) and
	  'pdfthd' (double flat).

	- When no clef is specified, clef changes are automatically
	  inserted when needed ('bass' or 'treble').

	- The clef name may be enclosed by double quotes in which case
	  it is the name of the PostScript function which draws the
	  clef. The arguments of this function are the x and y offsets.

Multiple voices.

	- 'stem=auto' in a V: field re-enables the automatic computation
	  of the direction of the stems (default).

	- For compatibility with previous abcm2ps versions, the V: fields may
	  contain:
		- 'gchord=up' (default) and 'gchord=down'
		  which forces the display of guitar chords above or
		  below the staff (see 'gchord' in format.txt).

		- 'gstem=up' or 'gstem=down'
		  which forces the direction of the stems of the grace notes
		  (see 'gstemdir' in format.txt).

		- 'dyn=up', 'dyn=down' or 'dyn=auto'
		  which forces the place of the dynamic marks (above
		  or below the staff - default is 'auto' -
		  see 'dynamic' in format.txt)

		- 'lyrics=up', 'lyrics=down' or 'lyrics=auto'
		  which forces the place of the lyrics (above or below
		  the staff - default is 'auto' - see 'vocal' in format.txt).
	  (use pseudo comments instead - see format.txt)

	- 'merge' in a V: field makes the voice to go on the same staff
	  as the previous voice (BarFly compatibility).

	- The BarFly voice switch in tune ('V:x <notes>', i.e.
	  voice + notes on the same line) may work.

	- The operator '(&...&...&)' permits voice overlay on many
	  measures. See sample3.abc for an example.

Text strings.

	- The guitar chords and annotations may contain '\#', '\b' and '\='
	  to display accidentals.

	- The strings may contain characters from '\001' to '\005' to display
	  accidentals. For compatibility, the values '\201' to '\205' are
	  handled the same way.

	- In quoted string, the '%' does not need to be escaped.

	- The strings may contain XML character references like "&#xe9;"
	  or "&#x1d15f;"

Deprecated ABC syntax.

	- Most of the deprecated ABC syntax is supported.

	- Some incompatible syntaxes are handled according to the ABC version
	  of the file as the ABC 2.0 line continuation mechanism.
abcm2ps-7.8.13/flute.fmt0000644000175000017500000002032312055357464013075 0ustar  jefjef% format file for flute tablatures - this file is part of abcm2ps
%
% Tin whistle by Guido Gonzato
% Galoubet and Pipe-Tabor by Michel Bellon
%
% tw_   : tin whistle
% gbl_  : galoubet (3 holes pipe from Provence)
% gblc_ : galoubet (digit only )
% pt_   : pipe and tabor (3 holes pipe from England)
% xi_   : txistu (3 holes pipe from Euskadi)
%
% you may try it running:
%	abcm2ps sample -e1 -F flute.fmt -T1 -T3

beginps
% -- whistle drawing functions --
%
% start of line 
%	string tw_head
/tw_head{/Helvetica 8 selectfont
	0 15 M 90 rotate(WHISTLE)show -90 rotate
	/Helvetica-Bold 36 selectfont
	0 15 M show .5 SLW newpath}!
/tw_under{
	-2.5 6.5 M 2.5 -2.5 RL 2.5 2.5 RL
	-2.5 -2.5 RM 0 6 RL stroke}!
/tw_over{
	-2.5 7.5 M 2.5 2.5 RL 2.5 -2.5 RL
	-2.5 2.5 RM 0 -6 RL stroke}!
/tw_p{-3 0 M 6 0 RL -3 -3 RM 0 6 RL stroke}!
/tw_pp{-3 0 M 6 0 RL
	-1.5 -1.5 RM 0 3 RL
	-3 0 RM 0 -3 RL stroke}!
% holes
/tw_0{0 0 3 0 360 arc stroke}!
/tw_1{0 0 3 90 270 arc fill 0 0 3 270 90 arc stroke}!
/tw_2{0 0 3 0 360 arc fill}!
% hole table - from C to B
/tw_holes
	[8#222222 8#222221 8#222220 8#222210 8#222200 8#222000
	 8#221000 8#220000 8#210000 8#200000 8#022000 8#000000]
	def
% draw a note
%	octave pitch x tw_note
/tw_note{gsave
	7 T			% oct pit
	cvi			% (if microtone)
	dup 12 idiv		% oct pit pit/12
	dup 0 eq{pop}
		{1 eq{tw_p}
		     {tw_pp}ifelse
	}ifelse
	dup 12 eq{
		pop 8#022222	% (special case)
	}{
		12 mod tw_holes exch get
	}ifelse			% oct holes
	0 1 5{pop
		0 7 T
		dup 8#3 and dup 0 eq{pop tw_0}
				    {1 eq{tw_1}
					 {tw_2}ifelse
		}ifelse
		-3 bitshift
	}for
	pop			% oct
	dup 0 gt{pop tw_over}
		 {0 lt{tw_under}if
	}ifelse
	grestore
}!
% -- galoubet en Do --
%
% début de ligne
%	string gbl_head
/gbl_tete{/Helvetica 7 selectfont
	0 10 M 90 rotate(GALOUBET)show -90 rotate
	/Helvetica-Bold 24 selectfont
	0 10 M show .5 SLW newpath}!
/gbl_c{/Helvetica-utf8 14 selectfont
	-5 10 M show .5 SLW newpath}!
/gbl_doux{-3.5 0 M 7 0 RL stroke}!
/gbl_fort{-3.5 0 M 7 0 RL -3.5 -3.5 RM 0 7 RL stroke}!
/gbl_tres_fort{-5 0 M 10 0 RL
	-2.5 -3 RM 0 6 RL
	-5 0 RM 0 -6 RL stroke}!
% trous
/gbl_0{0 0 3.5 0 360 arc stroke}!
/gbl_1{0 0 3.5 90 270 arc fill 0 0 3.5 270 90 arc stroke}!
/gbl_2{0 0 3.5 0 360 arc fill}!
% table des trous - de E à d'
/gbl_trous
	[8#22210
% F.. B
	 8#22200 8#22100 8#22000 8#21000 8#20000 8#10000 8#00000
% c .. e
	 8#22201 8#22101 8#22001 8#21001 8#20001
% f ..b
	 8#22202 8#00002 8#22002 8#21002 8#20002 8#10202 8#00202
% c' .. d'
	 8#22203 8#22103 8#22003]
	def
% table des doigtés chiffrés
/gbl_dgt
	[(3Þ)
	(3) (2Þ) (2) (1Þ) (1) (Þ) (0)
	(3) (2Þ) (2) (1Þ) (1)
	(3) (0) (2) (1Þ) (1) (ÞF) (F)
	(3) (2Þ) (2)]
	def
% dessin d'une note
%	octave pitch x gbl_note
/gbl_note{gsave
	8 T			% oct pit
	cvi			% (if microtone)
	4 sub			% oct pit/'E'
	exch			% pit/E oct
	0 eq			% (1ere octave seulement)
	1 index 0 ge and	% (pitch = 0 .. 22 = E .. d')
	1 index 23 lt and{
		dup gbl_dgt exch get
		0 30 T gbl_c	0 -35 T		
		gbl_trous exch get
		dup 8#3 and 
			dup 0 eq{pop gbl_doux}
				{dup 1 eq{pop}
					{2 eq{gbl_fort}
					     {gbl_tres_fort}ifelse
				}ifelse
			}ifelse
		-3 bitshift
		0 9 T
		dup 8#3 and 1 eq{gbl_1}if
		-3 bitshift
		0 1 2{pop
			0 9 T
			dup 8#3 and dup 0 eq{pop gbl_0}
					    {1 eq{gbl_1}
						 {gbl_2}ifelse
			}ifelse
			-3 bitshift
		}for
	}if
	pop grestore
}!
% -- galoubet en Do Tablature chiffrée--
%
% début de ligne
%	string gbl_head
/gblc_tete{/Helvetica 7 selectfont
	0 10 M 90 rotate(GALOUBET)show -90 rotate
	/Helvetica-Bold 24 selectfont
	0 10 M show .5 SLW newpath}!
/gblc_c{/Helvetica-utf8 18 selectfont
	-5 10 M show .5 SLW newpath}!
/gblc_doux{-3.5 0 M 7 0 RL stroke}!
/gblc_fort{-3.5 0 M 7 0 RL -3.5 -3.5 RM 0 7 RL stroke}!
/gblc_tres_fort{-5 0 M 10 0 RL
	-2.5 -3 RM 0 6 RL
	-5 0 RM 0 -6 RL stroke}!
% trous
/gblc_0{0 0 3.5 0 360 arc stroke}!
/gblc_1{0 0 3.5 90 270 arc fill 0 0 3.5 270 90 arc stroke}!
/gblc_2{0 0 3.5 0 360 arc fill}!
% table des trous - de E à d'
/gblc_trous
	[8#22210
% F.. B
	 8#22200 8#22100 8#22000 8#21000 8#20000 8#10000 8#00000
% c .. e
	 8#22201 8#22101 8#22001 8#21001 8#20001
% f ..b
	 8#22202 8#00002 8#22002 8#21002 8#20002 8#10202 8#00202
% c' .. d'
	 8#22203 8#22103 8#22003]
	def
% table des doigtés chiffrés
/gblc_dgt
	[(3Þ)
	(3) (2Þ) (2) (1Þ) (1) (Þ) (0)
	(3) (2Þ) (2) (1Þ) (1)
	(3) (0) (2) (1Þ) (1) (ÞF) (F)
	(3) (2Þ) (2)]
	def
% dessin d'une note
%	octave pitch x gblc_note
/gblc_note{gsave
	8 T			% oct pit
	cvi			% (if microtone)
	4 sub			% oct pit/'E'
	exch			% pit/E oct
	0 eq			% (1ere octave seulement)
	1 index 0 ge and	% (pitch = 0 .. 22 = E .. d')
	1 index 23 lt and{
		dup gblc_dgt exch get
		0 10 T gblc_c	0 0 T		
		gblc_trous exch get
		dup 8#3 and 
			dup 0 eq{pop gblc_doux}
				{dup 1 eq{pop}
					{2 eq{gblc_fort}
					     {gblc_tres_fort}ifelse
				}ifelse
			}ifelse
		-3 bitshift
%		0 9 T
%		dup 8#3 and 1 eq{gblc_1}if
%		-3 bitshift
%		0 1 2{pop
%			0 9 T
%			dup 8#3 and dup 0 eq{pop gblc_0}
%					    {1 eq{gblc_1}
%						 {gblc_2}ifelse
%			}ifelse
%			-3 bitshift
%		}for
	}if
	pop grestore
}!
% -- Pipe-Tabor en Do --
%
% début de ligne
%	string pt_head
/pt_tete{/Helvetica 7 selectfont
	0 10 M 90 rotate(PIPE-TABOR)show -90 rotate
	/Helvetica-Bold 24 selectfont
	0 10 M show .5 SLW newpath}!
/pt_doux{-3.5 0 M 7 0 RL stroke}!
/pt_fort{-3.5 0 M 7 0 RL -3.5 -3.5 RM 0 7 RL stroke}!
/pt_tres_fort{-5 0 M 10 0 RL
	-2.5 -3 RM 0 6 RL
	-5 0 RM 0 -6 RL stroke}!
% trous
/pt_0{0 0 3.5 0 360 arc stroke}!
/pt_1{0 0 3.5 90 270 arc fill 0 0 3.5 270 90 arc stroke}!
/pt_2{0 0 3.5 0 360 arc fill}!
% table des trous - de E à d'
/pt_trous
	[8#22210
% F.. B
	 8#22200 8#22100 8#22000 8#20200 8#20000 8#00000 8#22211
% c .. e
	 8#22201 8#22101 8#22001 8#21001 8#20001
% f ..b
	 8#22202 8#22102 8#22002 8#21002 8#20202 8#00202 8#22002
% c' .. d'
	 8#22203 8#22103 8#00203]
	def
% dessin d'une note
%	octave pitch x pt_note
/pt_note{gsave
	8 T			% oct pit
	cvi			% (if microtone)
	11 sub			% oct pit/'E'
	exch			% pit/E oct
	0 eq			% (1ere octave seulement)
	1 index 0 ge and	% (pitch = 0 .. 22 = E .. d')
	1 index 23 lt and{
		pt_trous exch get
		dup 8#3 and 
			dup 0 eq{pop pt_doux}
				{dup 1 eq{pop}
					{2 eq{pt_fort}
					     {pt_tres_fort}ifelse
				}ifelse
			}ifelse
		-3 bitshift
		0 9 T
		dup 8#3 and 1 eq{pt_1}if
		-3 bitshift
		0 1 2{pop
			0 9 T
			dup 8#3 and dup 0 eq{pop pt_0}
					    {1 eq{pt_1}
						 {pt_2}ifelse
			}ifelse
			-3 bitshift
		}for
	}if
	pop grestore
}!
% -- Galoubet en dièze ou Txistu --
%
% début de ligne
%	string xi_head
/xi_tete{/Helvetica 7 selectfont
	0 10 M 90 rotate(TXISTU)show -90 rotate
	/Helvetica-Bold 24 selectfont
	0 10 M show .5 SLW newpath}!
/xi_doux{-3.5 0 M 7 0 RL stroke}!
/xi_fort{-3.5 0 M 7 0 RL -3.5 -3.5 RM 0 7 RL stroke}!
/xi_tres_fort{-5 0 M 10 0 RL
	-2.5 -3 RM 0 6 RL
	-5 0 RM 0 -6 RL stroke}!
% trous
/xi_0{0 0 3.5 0 360 arc stroke}!
/xi_1{0 0 3.5 90 270 arc fill 0 0 3.5 270 90 arc stroke}!
/xi_2{0 0 3.5 0 360 arc fill}!
% table des trous - de E à d'
/xi_trous
	[8#22210
% E.. _B
	 8#22200 8#22100 8#22000 8#20000 8#02200 8#00200 8#22210
% B .. ^d
	 8#22201 8#22101 8#22001 8#20001 8#02001
% e ..g
	 8#22202 8#22102 8#22002 8#20002 
% c' .. d'
	 8#22203 8#00203 8#22213 8#22203 8#22103 8#22003]
	def
% dessin d'une note
%	octave pitch xi tw_note
/xi_note{gsave
	8 T			% oct pit
	cvi			% (if microtone)
	11 sub			% oct pit/'E'
	exch			% pit/E oct
	0 eq			% (1ere octave seulement)
	1 index 0 ge and	% (pitch = 0 .. 22 = E .. d')
	1 index 23 lt and{
		xi_trous exch get
		dup 8#3 and 
			dup 0 eq{pop xi_doux}
				{dup 1 eq{pop}
					{2 eq{xi_fort}
					     {xi_tres_fort}ifelse
				}ifelse
			}ifelse
		-3 bitshift
		0 9 T
		dup 8#3 and 1 eq{xi_1}if
		-3 bitshift
		0 1 2{pop
			0 9 T
			dup 8#3 and dup 0 eq{pop xi_0}
					    {1 eq{xi_1}
						 {xi_2}ifelse
			}ifelse
			-3 bitshift
		}for
	}if
	pop grestore
}!
endps

% all tin whistle transpositions
tablature #1 pitch=D 35 0 63 tw_head tw_note
tablature #2 pitch=C 35 0 63 tw_head tw_note
tablature #3 pitch=Eb 60 0 63 tw_head tw_note
%tablature #4 pitch=Bb, 60 0 63 tw_head tw_note
%tablature #5 pitch=F, 35 0 63 tw_head tw_note
%tablature #6 pitch=G, 35 0 63 tw_head tw_note
%tablature #7 pitch=A, 35 0 63 tw_head tw_note

% galoubet
%tablature #3 pitch=C 30 0 60 gbl_tete gbl_note
tablature #4 pitch=B,b 50 0 60 gbl_tete gbl_note
tablature #5 pitch=G, 30 0 54 pt_tete pt_note
tablature #6 pitch=C 30 0 46 gblc_tete gblc_note
abcm2ps-7.8.13/format.c0000644000175000017500000010124612424375452012703 0ustar  jefjef/*
 * Formatting functions.
 *
 * This file is part of abcm2ps.
 *
 * Copyright (C) 1998-2014 Jean-François Moine
 * Adapted from abc2ps, Copyright (C) 1996,1997 Michael Methfessel
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 */

#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "abc2ps.h"

struct FORMAT cfmt;		/* current format for output */

char *fontnames[MAXFONTS];		/* list of font names */
static char font_enc[MAXFONTS];		/* font encoding */
static char def_font_enc[MAXFONTS];	/* default font encoding */
static char used_font[MAXFONTS];	/* used fonts */
static float swfac_font[MAXFONTS];	/* width scale */
static int nfontnames;
static float staffwidth;

/* format table */
static struct format {
	char *name;
	void *v;
	char type;
#define FORMAT_I 0	/* int */
#define FORMAT_R 1	/* float */
#define FORMAT_F 2	/* font spec */
#define FORMAT_U 3	/* float with unit */
#define FORMAT_B 4	/* boolean */
#define FORMAT_S 5	/* string */
	char subtype;		/* special cases - see code */
	short lock;
} format_tb[] = {
	{"abc2pscompat", &cfmt.abc2pscompat, FORMAT_B, 3},
	{"alignbars", &cfmt.alignbars, FORMAT_I, 0},
	{"aligncomposer", &cfmt.aligncomposer, FORMAT_I, 0},
	{"autoclef", &cfmt.autoclef, FORMAT_B, 0},
	{"annotationfont", &cfmt.font_tb[ANNOTATIONFONT], FORMAT_F, 0},
	{"barsperstaff", &cfmt.barsperstaff, FORMAT_I, 0},
	{"bgcolor", &cfmt.bgcolor, FORMAT_S, 0},
	{"botmargin", &cfmt.botmargin, FORMAT_U, 0},
	{"breaklimit", &cfmt.breaklimit, FORMAT_R, 3},
	{"breakoneoln", &cfmt.breakoneoln, FORMAT_B, 0},
	{"bstemdown", &cfmt.bstemdown, FORMAT_B, 0},
	{"cancelkey", &cfmt.cancelkey, FORMAT_B, 0},
	{"combinevoices", &cfmt.combinevoices, FORMAT_I, 0},
	{"composerfont", &cfmt.font_tb[COMPOSERFONT], FORMAT_F, 0},
	{"composerspace", &cfmt.composerspace, FORMAT_U, 0},
	{"contbarnb", &cfmt.contbarnb, FORMAT_B, 0},
	{"continueall", &cfmt.continueall, FORMAT_B, 0},
	{"custos", &cfmt.custos, FORMAT_B, 0},
	{"dateformat", &cfmt.dateformat, FORMAT_S, 0},
	{"dblrepbar", &cfmt.dblrepbar, FORMAT_I, 2},
	{"dynalign", &cfmt.dynalign, FORMAT_B, 0},
	{"footer", &cfmt.footer, FORMAT_S, 0},
	{"footerfont", &cfmt.font_tb[FOOTERFONT], FORMAT_F, 0},
	{"flatbeams", &cfmt.flatbeams, FORMAT_B, 0},
	{"gchordbox", &cfmt.gchordbox, FORMAT_B, 0},
	{"gchordfont", &cfmt.font_tb[GCHORDFONT], FORMAT_F, 3},
	{"graceslurs", &cfmt.graceslurs, FORMAT_B, 0},
	{"gracespace", &cfmt.gracespace, FORMAT_I, 5},
	{"header", &cfmt.header, FORMAT_S, 0},
	{"headerfont", &cfmt.font_tb[HEADERFONT], FORMAT_F, 0},
	{"historyfont", &cfmt.font_tb[HISTORYFONT], FORMAT_F, 0},
	{"hyphencont", &cfmt.hyphencont, FORMAT_B, 0},
	{"indent", &cfmt.indent, FORMAT_U, 0},
	{"infofont", &cfmt.font_tb[INFOFONT], FORMAT_F, 0},
	{"infoline", &cfmt.infoline, FORMAT_B, 0},
	{"infospace", &cfmt.infospace, FORMAT_U, 0},
	{"keywarn", &cfmt.keywarn, FORMAT_B, 0},
	{"landscape", &cfmt.landscape, FORMAT_B, 0},
	{"leftmargin", &cfmt.leftmargin, FORMAT_U, 0},
	{"lineskipfac", &cfmt.lineskipfac, FORMAT_R, 0},
	{"linewarn", &cfmt.linewarn, FORMAT_B, 0},
	{"maxshrink", &cfmt.maxshrink, FORMAT_R, 2},
	{"maxstaffsep", &cfmt.maxstaffsep, FORMAT_U, 0},
	{"maxsysstaffsep", &cfmt.maxsysstaffsep, FORMAT_U, 0},
	{"measurebox", &cfmt.measurebox, FORMAT_B, 0},
	{"measurefirst", &cfmt.measurefirst, FORMAT_I, 0},
	{"measurefont", &cfmt.font_tb[MEASUREFONT], FORMAT_F, 2},
	{"measurenb", &cfmt.measurenb, FORMAT_I, 0},
	{"micronewps", &cfmt.micronewps, FORMAT_B, 0},
	{"microscale", &cfmt.microscale, FORMAT_I, 0},
	{"musicspace", &cfmt.musicspace, FORMAT_U, 0},
	{"notespacingfactor", &cfmt.notespacingfactor, FORMAT_R, 1},
	{"oneperpage", &cfmt.oneperpage, FORMAT_B, 0},
	{"pageheight", &cfmt.pageheight, FORMAT_U, 0},
	{"pagewidth", &cfmt.pagewidth, FORMAT_U, 0},
#ifdef HAVE_PANGO
	{"pango", &cfmt.pango, FORMAT_B, 2},
#endif
	{"parskipfac", &cfmt.parskipfac, FORMAT_R, 0},
	{"partsbox", &cfmt.partsbox, FORMAT_B, 0},
	{"partsfont", &cfmt.font_tb[PARTSFONT], FORMAT_F, 1},
	{"partsspace", &cfmt.partsspace, FORMAT_U, 0},
	{"pdfmark", &cfmt.pdfmark, FORMAT_I, 0},
	{"repeatfont", &cfmt.font_tb[REPEATFONT], FORMAT_F, 0},
	{"rightmargin", &cfmt.rightmargin, FORMAT_U, 0},
	{"scale", &cfmt.scale, FORMAT_R, 0},
	{"setdefl", &cfmt.setdefl, FORMAT_B, 0},
	{"setfont-1", &cfmt.font_tb[1], FORMAT_F, 0},
	{"setfont-2", &cfmt.font_tb[2], FORMAT_F, 0},
	{"setfont-3", &cfmt.font_tb[3], FORMAT_F, 0},
	{"setfont-4", &cfmt.font_tb[4], FORMAT_F, 0},
#if FONT_UMAX!=5
#	error Bad number of user fonts
#endif
//	{"shifthnote", &cfmt.shiftunison, FORMAT_B, 0},	/*to remove*/
	{"shiftunison", &cfmt.shiftunison, FORMAT_I, 0},
	{"shiftunisson", &cfmt.shiftunison, FORMAT_I, 0}, /*to remove*/
	{"slurheight", &cfmt.slurheight, FORMAT_R, 0},
	{"splittune", &cfmt.splittune, FORMAT_B, 0},
	{"squarebreve", &cfmt.squarebreve, FORMAT_B, 0},
	{"staffnonote", &cfmt.staffnonote, FORMAT_I, 0},
	{"staffsep", &cfmt.staffsep, FORMAT_U, 0},
	{"staffwidth", &staffwidth, FORMAT_U, 1},
	{"stemheight", &cfmt.stemheight, FORMAT_R, 0},
	{"straightflags", &cfmt.straightflags, FORMAT_B, 0},
	{"stretchlast", &cfmt.stretchlast, FORMAT_R, 2},
	{"stretchstaff", &cfmt.stretchstaff, FORMAT_B, 0},
	{"subtitlefont", &cfmt.font_tb[SUBTITLEFONT], FORMAT_F, 0},
	{"subtitlespace", &cfmt.subtitlespace, FORMAT_U, 0},
	{"sysstaffsep", &cfmt.sysstaffsep, FORMAT_U, 0},
	{"tempofont", &cfmt.font_tb[TEMPOFONT], FORMAT_F, 0},
	{"textfont", &cfmt.font_tb[TEXTFONT], FORMAT_F, 0},
	{"textoption", &cfmt.textoption, FORMAT_I, 4},
	{"textspace", &cfmt.textspace, FORMAT_U, 0},
	{"titlecaps", &cfmt.titlecaps, FORMAT_B, 0},
	{"titlefont", &cfmt.font_tb[TITLEFONT], FORMAT_F, 0},
	{"titleformat", &cfmt.titleformat, FORMAT_S, 0},
	{"titleleft", &cfmt.titleleft, FORMAT_B, 0},
	{"titlespace", &cfmt.titlespace, FORMAT_U, 0},
	{"titletrim", &cfmt.titletrim, FORMAT_B, 0},
	{"timewarn", &cfmt.timewarn, FORMAT_B, 0},
	{"topmargin", &cfmt.topmargin, FORMAT_U, 0},
	{"topspace", &cfmt.topspace, FORMAT_U, 0},
	{"transpose", &cfmt.transpose, FORMAT_I, 1},
	{"tuplets", &cfmt.tuplets, FORMAT_I, 3},
	{"vocalfont", &cfmt.font_tb[VOCALFONT], FORMAT_F, 0},
	{"vocalspace", &cfmt.vocalspace, FORMAT_U, 0},
	{"voicefont", &cfmt.font_tb[VOICEFONT], FORMAT_F, 0},
	{"wordsfont", &cfmt.font_tb[WORDSFONT], FORMAT_F, 0},
	{"wordsspace", &cfmt.wordsspace, FORMAT_U, 0},
	{"writefields", &cfmt.fields, FORMAT_B, 1},
	{0, 0, 0, 0}		/* end of table */
};

/* -- search a font and add it if not yet defined -- */
static int get_font(char *fname, int encoding)
{
	int fnum;

	/* get or set the default encoding */
	for (fnum = nfontnames; --fnum >= 0; )
		if (strcmp(fname, fontnames[fnum]) == 0) {
			if (encoding < 0)
				encoding = def_font_enc[fnum];
			if (encoding == font_enc[fnum])
				return fnum;		/* font found */
			break;
		}
	while (--fnum >= 0) {
		if (strcmp(fname, fontnames[fnum]) == 0
		 && encoding == font_enc[fnum])
			return fnum;
	}

	/* add the font */
	if (nfontnames >= MAXFONTS) {
		error(1, NULL, "Too many fonts");
		return 0;
	}
	if (file_initialized> 0
	 && (epsf <= 1 && !svg))
		error(1, NULL,
		      "Cannot have a new font when the output file is opened");
	fnum = nfontnames++;
	fontnames[fnum] = strdup(fname);
	if (encoding < 0)
		encoding = 0;
	font_enc[fnum] = encoding;
	return fnum;
}

/* -- set a dynamic font -- */
static int dfont_set(struct FONTSPEC *f)
{
	int i;

	for (i = FONT_DYN; i < cfmt.ndfont; i++) {
		if (cfmt.font_tb[i].fnum == f->fnum
		    && cfmt.font_tb[i].size == f->size)
			return i;
	}
	if (i >= FONT_MAX - 1) {
		error(1, NULL, "Too many dynamic fonts");
		return FONT_MAX - 1;
	}
	memcpy(&cfmt.font_tb[i], f, sizeof cfmt.font_tb[0]);
	cfmt.ndfont = i + 1;
	return i;
}

/* -- define a font -- */
static void fontspec(struct FONTSPEC *f,
		     char *name,
		     int encoding,
		     float size)
{
	if (name)
		f->fnum = get_font(name, encoding);
	else
		name = fontnames[f->fnum];
	f->size = size;
	f->swfac = size;
	if (swfac_font[f->fnum] != 0) {
		f->swfac *= swfac_font[f->fnum];
	} else if (strncmp(name, "Times", 5) == 0) {
		if (strcmp(name, "Times-Bold") == 0)
			f->swfac *= 1.05;
	} else if (strcmp(name, "Helvetica-Bold") == 0) {
		f->swfac *= 1.15;
	} else if (strncmp(name, "Helvetica", 9) == 0
		|| strncmp(name, "Palatino", 8) == 0) {
		f->swfac *= 1.10;
	} else if (strncmp(name, "Courier", 7) == 0) {
		f->swfac *= 1.35;
	} else {
		f->swfac *= 1.2;		/* unknown font */
	}
	if (f == &cfmt.font_tb[GCHORDFONT])
		cfmt.gcf = dfont_set(f);
	else if (f == &cfmt.font_tb[ANNOTATIONFONT])
		cfmt.anf = dfont_set(f);
	else if (f == &cfmt.font_tb[VOCALFONT])
		cfmt.vof = dfont_set(f);
}

/* -- output the font definitions with their encodings -- */
/* This output must occurs after user PostScript definitions because
 * these ones may change the default behaviour */
void define_fonts(void)
{
	int i;
	static char *mkfont =
	"/mkfont{findfont dup length 1 add dict begin\n"
	"	{1 index/FID ne{def}{pop pop}ifelse}forall\n"
	"	CharStrings/double_sharp known not{\n"
	"	    /CharStrings CharStrings dup length dict copy def\n"
	"	    FontMatrix 0 get 1 eq{\n"
	"		CharStrings/sharp{pop .46 0 setcharwidth .001 dup scale usharp ufill}bind put\n"
	"		CharStrings/flat{pop .46 0 setcharwidth .001 dup scale uflat ufill}bind put\n"
	"		CharStrings/natural{pop .40 0 setcharwidth .001 dup scale unat ufill}bind put\n"
	"		CharStrings/double_sharp{pop .46 0 setcharwidth .001 dup scale udblesharp ufill}bind put\n"
	"		CharStrings/double_flat{pop .50 0 setcharwidth .001 dup scale udbleflat ufill}bind put\n"
	"	    }{\n"
	"		CharStrings/sharp{pop 460 0 setcharwidth usharp ufill}bind put\n"
	"		CharStrings/flat{pop 460 0 setcharwidth uflat ufill}bind put\n"
	"		CharStrings/natural{pop 400 0 setcharwidth unat ufill}bind put\n"
	"		CharStrings/double_sharp{pop 460 0 setcharwidth udblesharp ufill}bind put\n"
	"		CharStrings/double_flat{pop 500 0 setcharwidth udbleflat ufill}bind put\n"
	"	    }ifelse\n"
	"	}if currentdict definefont pop end}!\n";

	fputs(mkfont, fout);
	make_font_list();
	for (i = 0; i < nfontnames; i++) {
		if (used_font[i])
			define_font(fontnames[i], i, font_enc[i]);
	}
}

/* -- mark the used fonts -- */
void make_font_list(void)
{
	struct FORMAT *f;
	int i;

	f = &cfmt;
	for (i = FONT_UMAX; i < FONT_DYN; i++)
		used_font[f->font_tb[i].fnum] = 1;
}

/* -- set the name of an information header type -- */
/* the argument is
 *	<letter> [ <possibly quoted string> ]
 * this information is kept in the 'I' information */
static void set_infoname(char *p)
{
	struct SYMBOL *s, *prev;

	if (*p == 'I')
		return;
	s = info['I' - 'A'];
	prev = NULL;
	while (s) {
		if (s->as.text[0] == *p)
			break;
		prev = s;
		s = s->next;
	}
	if (p[1] == '\0') {		/* if delete */
		if (s) {
			if (!prev)
				info['I' - 'A'] = s->next;
			else if ((prev->next = s->next) != 0)
				prev->next->prev = prev;
		}
		return;
	}
	if (!s) {
		s = (struct SYMBOL *) getarena(sizeof *s);
		memset(s, 0, sizeof *s);
		if (!prev)
			info['I' - 'A'] = s;
		else {
			prev->next = s;
			s->prev = prev;
		}
	}
	s->as.text = (char *) getarena(strlen(p) + 1);
	strcpy(s->as.text, p);
}

/* -- set the default format -- */
/* this function is called only once, at abcm2ps startup time */
void set_format(void)
{
	struct FORMAT *f;

	f = &cfmt;
	memset(f, 0, sizeof *f);
	f->pageheight = PAGEHEIGHT;
	f->pagewidth = PAGEWIDTH;
	f->leftmargin = MARGIN;
	f->rightmargin = MARGIN;
	f->topmargin = 1.0 CM;
	f->botmargin = 1.0 CM;
	f->topspace = 0.8 CM;
	f->titlespace = 0.2 CM;
	f->subtitlespace = 0.1 CM;
	f->composerspace = 0.2 CM;
	f->musicspace = 0.2 CM;
	f->partsspace = 0.3 CM;
	f->staffsep = 46.0 PT;
	f->sysstaffsep = 34.0 PT;
	f->maxstaffsep = 2000.0 PT;
	f->maxsysstaffsep = 2000.0 PT;
	f->vocalspace = 23.0 PT;
	f->textspace = 0.5 CM;
	f->scale = 0.75;
	f->slurheight = 1.0;
	f->maxshrink = 0.65;
	f->breaklimit = 0.7;
	f->stretchlast = 0.2;
	f->stretchstaff = 1;
	f->graceslurs = 1;
	f->hyphencont = 1;
	f->lineskipfac = 1.1;
	f->parskipfac = 0.4;
	f->measurenb = -1;
	f->measurefirst = 1;
	f->autoclef = 1;
	f->breakoneoln = 1;
	f->dblrepbar = (B_COL << 12) + (B_CBRA << 8) + (B_OBRA << 4) + B_COL;
	f->dynalign = 1;
	f->keywarn = 1;
	f->linewarn = 1;
#ifdef HAVE_PANGO
	if (!svg && epsf <= 1)
		f->pango = 1;
	else
		lock_fmt(&cfmt.pango);	/* SVG output does not use panga */
#endif
	f->staffnonote = 1;
	f->titletrim = 1;
	f->aligncomposer = A_RIGHT;
	f->notespacingfactor = 1.414;
	f->stemheight = STEM;
#ifndef WIN32
	f->dateformat = strdup("%b %e, %Y %H:%M");
#else
	f->dateformat = strdup("%b %#d, %Y %H:%M");
#endif
	f->gracespace = (65 << 16) | (80 << 8) | 120;	/* left-inside-right - unit 1/10 pt */
	f->textoption = T_LEFT;
	f->ndfont = FONT_DYN;
	fontspec(&f->font_tb[ANNOTATIONFONT], "Helvetica", 0, 12.0);
	fontspec(&f->font_tb[COMPOSERFONT], "Times-Italic", 0, 14.0);
	fontspec(&f->font_tb[FOOTERFONT], "Times-Roman", 0, 12.0); /* not scaled */
	fontspec(&f->font_tb[GCHORDFONT], "Helvetica", 0, 12.0);
	fontspec(&f->font_tb[HEADERFONT], "Times-Roman", 0, 12.0); /* not scaled */
	fontspec(&f->font_tb[HISTORYFONT], "Times-Roman", 0, 16.0);
	fontspec(&f->font_tb[INFOFONT],	"Times-Italic", 0, 14.0); /* same as composer by default */
	fontspec(&f->font_tb[MEASUREFONT], "Times-Italic", 0, 14.0);
	fontspec(&f->font_tb[PARTSFONT], "Times-Roman", 0, 15.0);
	fontspec(&f->font_tb[REPEATFONT], "Times-Roman", 0, 13.0);
	fontspec(&f->font_tb[SUBTITLEFONT], "Times-Roman", 0, 16.0);
	fontspec(&f->font_tb[TEMPOFONT], "Times-Bold", 0, 15.0);
	fontspec(&f->font_tb[TEXTFONT],	"Times-Roman", 0, 16.0);
	fontspec(&f->font_tb[TITLEFONT], "Times-Roman", 0, 20.0);
	fontspec(&f->font_tb[VOCALFONT], "Times-Bold", 0, 13.0);
	fontspec(&f->font_tb[VOICEFONT], "Times-Bold", 0, 13.0);
	fontspec(&f->font_tb[WORDSFONT], "Times-Roman", 0, 16.0);
	f->fields[0] = (1 << ('C' - 'A'))
		| (1 << ('M' - 'A'))
		| (1 << ('O' - 'A'))
		| (1 << ('P' - 'A'))
		| (1 << ('Q' - 'A'))
		| (1 << ('T' - 'A'))
		| (1 << ('W' - 'A'));
	f->fields[1] = (1 << ('w' - 'a'));
	set_infoname("R \"Rhythm: \"");
	set_infoname("B \"Book: \"");
	set_infoname("S \"Source: \"");
	set_infoname("D \"Discography: \"");
	set_infoname("N \"Notes: \"");
	set_infoname("Z \"Transcription: \"");
	set_infoname("H \"History: \"");
}

/* -- print the current format -- */
void print_format(void)
{
	struct format *fd;
static char *yn[2] = {"no","yes"};

	for (fd = format_tb; fd->name; fd++) {
		printf("%-15s ", fd->name);
		switch (fd->type) {
		case FORMAT_B:
			switch (fd->subtype) {
#ifdef HAVE_PANGO
			case 2:				/* pango = 0, 1 or 2 */
				if (cfmt.pango == 2) {
					printf("2\n");
					break;
				}
				/* fall thru */
#endif
			default:
			case 0:
				printf("%s\n", yn[*((int *) fd->v)]);
				break;
			case 1: {			/* writefields */
				int i;

				for (i = 0; i < 32; i++) {
					if (cfmt.fields[0] & (1 << i))
						printf("%c", (char) ('A' + i));
					if (cfmt.fields[1] & (1 << i))
						printf("%c", (char) ('a' + i));
				}
				printf("\n");
				break;
			    }
			}
			break;
		case FORMAT_I:
			switch (fd->subtype) {
			default:
				printf("%d\n", *((int *) fd->v));
				break;
			case 1: {		/* transpose */
				int t;

				t = *((int *) fd->v);
				if (t >= 0)
					putchar('+');
				printf("%d", t / 3);
				switch ((t + 240) % 3) {
				case 1:
					putchar('#');
					break;
				case 2:
					putchar('b');
					break;
				}
				putchar('\n');
				break;
			    }
			case 2: {		/* dblrepbar */
				int v;
				char tmp[16], *p;

				p = &tmp[sizeof tmp - 1];
				*p = '\0';
				for (v = cfmt.dblrepbar; v != 0; v >>= 4) {
					switch (v & 0x0f) {
					case B_BAR:
						*--p = '|';
						break;
					case B_OBRA:
						*--p = '[';
						break;
					case B_CBRA:
						*--p = ']';
						break;
					default:
//					case B_COL:
						*--p = ':';
						break;
					}
				}
				printf("%s\n", p);
				break;
			    }
			case 3:			/* tuplets */
				printf("%d %d %d\n",
					cfmt.tuplets >> 8,
					(cfmt.tuplets >> 4) & 0x0f,
					cfmt.tuplets & 0x0f);
				break;
//			case 4:			/* textoption */
//				break;
			case 5:			/* gracespace */
				printf("%d.%d %d.%d %d.%d\n",
					(cfmt.gracespace >> 16) / 10,
					(cfmt.gracespace >> 16) % 10,
					((cfmt.gracespace >> 8) & 0xff) / 10,
					((cfmt.gracespace >> 8) & 0xff) % 10,
					(cfmt.gracespace & 0xff) / 10,
					(cfmt.gracespace & 0xff) % 10);
				break;
			}
			break;
		case FORMAT_R:
			printf("%.2f\n", *((float *) fd->v));
			break;
		case FORMAT_F: {
			struct FONTSPEC *s;

			s = (struct FONTSPEC *) fd->v;
			printf("%s", fontnames[s->fnum]);
			printf(" %s", font_enc[s->fnum] ? "native" : "utf-8");
			printf(" %.1f", s->size);
			if ((fd->subtype == 1 && cfmt.partsbox)
			 || (fd->subtype == 2 && cfmt.measurebox)
			 || (fd->subtype == 3 && cfmt.gchordbox))
				printf(" box");
			printf("\n");
			break;
		}
		case FORMAT_U:
			if (fd->subtype == 0)
				printf("%.2fcm\n", *((float *) fd->v) / (1 CM));
			else
				printf("%.2fcm\n",
					(cfmt.pagewidth
						- cfmt.leftmargin
						- cfmt.rightmargin)
					/ (1 CM));
			break;
		case FORMAT_S:
			printf("\"%s\"\n",
				*((char **) fd->v) != 0 ? *((char **) fd->v) : "");
			break;
		}
	}
}

/* -- get an encoding -- */
static int parse_encoding(char *p)
{
	return strncasecmp(p, "native", 6) == 0;
}

/* -- get a position -- */
static int get_posit(char *p)
{
	if (strcmp(p, "up") == 0
	 || strcmp(p, "above") == 0)
		return SL_ABOVE;
	if (strcmp(p, "down") == 0
	 || strcmp(p, "below") == 0)
		return SL_BELOW;
	if (strcmp(p, "hidden") == 0
	 || strcmp(p, "opposite") == 0)
		return SL_HIDDEN;
	return 0;			/* auto (!= SL_AUTO) */
}

/* -- get the option for text -- */
int get_textopt(char *p)
{
	if (*p == '\0'
	 || strncmp(p, "obeylines", 9) == 0)
		return T_LEFT;
	if (strncmp(p, "align", 5) == 0
	 || strncmp(p, "justify", 7) == 0)
		return T_JUSTIFY;
	if (strncmp(p, "ragged", 6) == 0
	 || strncmp(p, "fill", 4) == 0)
		return T_FILL;
	if (strncmp(p, "center", 6) == 0)
		return T_CENTER;
	if (strncmp(p, "skip", 4) == 0)
		return T_SKIP;
	if (strncmp(p, "right", 5) == 0)
		return T_RIGHT;
	return -1;
}

/* -- get the double repeat bar -- */
static int get_dblrepbar(char *p)
{
	int bar_type;

	bar_type = 0;
	for (;;) {
		switch (*p++) {
		case '|':
			bar_type <<= 4;
			bar_type |= B_BAR;
			continue;
		case '[':
			bar_type <<= 4;
			bar_type |= B_OBRA;
			continue;
		case ']':
			bar_type <<= 4;
			bar_type |= B_CBRA;
			continue;
		case ':':
			bar_type <<= 4;
			bar_type |= B_COL;
			continue;
		default:
			break;
		}
		break;
	}
	return bar_type;
}

/* -- get a boolean value -- */
static int g_logv(char *p)
{
	switch (*p) {
	case '\0':
	case '1':
	case 'y':
	case 'Y':
	case 't':
	case 'T':
		return 1;
	case '0':
	case 'n':
	case 'N':
	case 'f':
	case 'F':
		break;
	default:
		error(0, NULL, "Unknown logical '%s' - false assumed", p);
		break;
	}
	return 0;
}

/* -- get a font specifier -- */
static void g_fspc(char *p,
		   struct FONTSPEC *f)
{
	char fname[80];
	int encoding;
	float fsize;

	p = get_str(fname, p, sizeof fname);
	if (isalpha((unsigned char) *p) || *p == '*') {
		if (*p == '*')
			encoding = font_enc[f->fnum];
		else
			encoding = parse_encoding(p);
		while (*p != '\0' && !isspace((unsigned char) *p))
			p++;
		while (isspace((unsigned char) *p))
			p++;
	} else {
		encoding = -1;
	}
	fsize = f->size;
	if (*p != '\0' && *p != '*') {
		char *q;
		float v;

		v = strtod(p, &q);
		if (v <= 0 || (*q != '\0' && *q != ' '))
			error(1, NULL, "Bad font size '%s'", p);
		else
			fsize = v;
	}
	fontspec(f,
		 strcmp(fname, "*") != 0 ? fname : 0,
		 encoding,
		 fsize);
	if (file_initialized <= 0)
		used_font[f->fnum] = 1;
	if (f - cfmt.font_tb == outft)
		outft = -1;
#ifdef HAVE_PANGO
	pg_reset_font();
#endif
}

/* -- parse a 'tablature' definition -- */
/* %%tablature
 *	[#<nunmber (1..MAXTBLT)>]
 *	[pitch=<instrument pitch (<note> # | b)>]
 *	[[<head width>]
 *	 <height above>]
 *	<height under>
 *	<head function>
 *	<note function>
 *	[<bar function>]
 */
struct tblt_s *tblt_parse(char *p)
{
	struct tblt_s *tblt;
	int n;
	char *q;
	static char notes_tb[] = "CDEFGABcdefgab";
	static char pitch_tb[14] = {60, 62, 64, 65, 67, 69, 71,
				    72, 74, 76, 77, 79, 81, 83};

	/* number */
	if (*p == '#') {
		p++;
		n = *p++ - '0' - 1;
		if ((unsigned) n >= MAXTBLT
		 || (*p != '\0' && *p != ' ')) {
			error(1, NULL, "Invalid number in %%%%tablature");
			return 0;
		}
		if (*p == '\0')
			return tblts[n];
		while (isspace((unsigned char) *p))
			p++;
	} else {
		n = -1;
	}

	/* pitch */
	tblt = malloc(sizeof *tblt);
	memset(tblt, 0, sizeof *tblt);
	if (strncmp(p, "pitch=", 6) == 0) {
		p += 6;
		if (*p == '^' || *p == '_') {
			if (*p == '^') {
				tblt->pitch++;
				tblt->instr[1] = '#';
			} else {
				tblt->pitch--;
				tblt->instr[1] = 'b';
			}
			p++;
		}
		if (*p == '\0' || (q = strchr(notes_tb, *p)) == NULL) {
			error(1, NULL, "Invalid pitch in %%%%tablature");
			return 0;
		}
		tblt->pitch += pitch_tb[q - notes_tb];
		tblt->instr[0] = toupper(*p++);
		while (*p == '\'' || *p == ',') {
			if (*p++ == '\'')
				tblt->pitch += 12;
			else
				tblt->pitch -= 12;
		}
		if (*p == '#' || *p == 'b') {
			if (*p == '#')
				tblt->pitch++;
			else
				tblt->pitch--;
			tblt->instr[1] = *p++;
		}
		while (*p == '\'' || *p == ',') {
			if (*p++ == '\'')
				tblt->pitch += 12;
			else
				tblt->pitch -= 12;
		}
		while (isspace((unsigned char) *p))
			p++;
	}

	/* width and heights */
	if (!isdigit(*p)) {
		error(1, NULL, "Invalid width/height in %%%%tablature");
		return 0;
	}
	tblt->hu = scan_u(p);
	while (*p != '\0' && !isspace((unsigned char) *p))
		p++;
	while (isspace((unsigned char) *p))
		p++;
	if (isdigit(*p)) {
		tblt->ha = tblt->hu;
		tblt->hu = scan_u(p);
		while (*p != '\0' && !isspace((unsigned char) *p))
			p++;
		while (isspace((unsigned char) *p))
			p++;
		if (isdigit(*p)) {
			tblt->wh = tblt->ha;
			tblt->ha = tblt->hu;
			tblt->hu = scan_u(p);
			while (*p != '\0' && !isspace((unsigned char) *p))
				p++;
			while (isspace((unsigned char) *p))
				p++;
		}
	}
	if (*p == '\0')
		goto err;

	/* PS functions */
	p = strdup(p);
	tblt->head = p;
	while (*p != '\0' && !isspace((unsigned char) *p))
		p++;
	if (*p == '\0')
		goto err;
	*p++ = '\0';
	while (isspace((unsigned char) *p))
		p++;
	tblt->note = p;
	while (*p != '\0' && !isspace((unsigned char) *p))
		p++;
	if (*p != '\0') {
		*p++ = '\0';
		while (isspace((unsigned char) *p))
			p++;
		tblt->bar = p;
		while (*p != '\0' && !isspace((unsigned char) *p))
			p++;
		if (*p != '\0')
			goto err;
	}

	/* memorize the definition */
	if (n >= 0)
		tblts[n] = tblt;
	return tblt;
err:
	error(1, NULL, "Wrong values in %%%%tablature");
	return 0;
}

/* functions to set a voice parameter */
#define F_SET_PAR(param) \
static void set_ ## param(struct VOICE_S *p_voice, int val)\
{\
	p_voice->posit.param = val;\
}
F_SET_PAR(dyn)
F_SET_PAR(gch)
F_SET_PAR(orn)
F_SET_PAR(voc)
F_SET_PAR(vol)
F_SET_PAR(std)
F_SET_PAR(gsd)

struct vpar {
	char *name;
	void (*f)(struct VOICE_S *p_voice, int val);
	int max;
};
static const struct vpar vpar_tb[] = {
	{"dynamic", set_dyn, 3},	/* 0 */
	{"gchord", set_gch, 3},		/* 1 */
	{"gstemdir", set_gsd, 3},	/* 2 */
	{"ornament", set_orn, 3},	/* 3 */
	{"stemdir", set_std, 2},	/* 4 */
	{"vocal", set_voc, 3},		/* 5 */
	{"volume", set_vol, 3},		/* 6 */
	{}
};
/* -- set a voice parameter -- */
void set_voice_param(struct VOICE_S *p_voice,	/* current voice */
			int state,		/* tune state */
			char *w,		/* keyword */
			char *p)		/* argument */
{
	const struct vpar *vpar, *vpar2 = NULL;
	int i, val;

	for (vpar = vpar_tb; vpar->name; vpar++) {
		if (strcmp(w, vpar->name))
			continue;
		if (!isdigit(*p))
			val = get_posit(p);
		else
			val = strtod(p, 0);
		if ((unsigned) val > vpar->max)
			goto err;
		break;
	}
	if (!vpar->name) {	/* compatibility with previous versions */
		val = -1;
		switch (*w) {
		case 'e':
			if (strcmp(w, "exprabove") == 0) {
				vpar = &vpar[0];	/* dyn */
				vpar2 = &vpar[6];	/* vol */
				if (g_logv(p))
					val = SL_ABOVE;
				else
					val = SL_BELOW;
				break;
			}
			if (strcmp(w, "exprbelow") == 0) {
				vpar = &vpar[0];	/* dyn */
				vpar2 = &vpar[6];	/* vol */
				if (g_logv(p))
					val = SL_BELOW;
				else
					val = SL_ABOVE;
				break;
			}
			break;
		case 'v':
			if (strcmp(w, "vocalabove") == 0) {	/* compatibility */
				vpar = &vpar[5];	/* voc */
				if (g_logv(p))
					val = SL_ABOVE;
				else
					val = SL_BELOW;
				break;
			}
			break;
		}
		if (val < 0)
			goto err;
	}
	if (state == ABC_S_TUNE) {
		vpar->f(p_voice, val);
		if (vpar2)
			vpar2->f(p_voice, val);
		return;
	}
	for (i = MAXVOICE, p_voice = voice_tb;	/* global */
	     --i >= 0;
	     p_voice++) {
		vpar->f(p_voice, val);
		if (vpar2)
			vpar2->f(p_voice, val);
	}
	cfmt.posit = voice_tb[0].posit;
	return;
err:
	error(1, NULL, "Bad value %%%%%s %s", w, p);
}

/* -- parse a format line -- */
void interpret_fmt_line(char *w,		/* keyword */
			char *p,		/* argument */
			int lock)
{
	struct format *fd;

	switch (*w) {
	case 'b':
		if (strcmp(w, "barnumbers") == 0)	/* compatibility */
			w = "measurenb";
		break;
	case 'c':
		if (strcmp(w, "comball") == 0) {	/* compatibility */
			cfmt.combinevoices = 2;
			return;
		}
		break;
	case 'f':
		if (strcmp(w, "font") == 0) {
			int i, fnum, encoding;
			float swfac;
			char fname[80];

			if (file_initialized > 0
			 && !svg && epsf <= 1) {	/* PS */
				error(1, NULL,
				      "Cannot define a font when the output file is opened");
				return;
			}
			p = get_str(fname, p, sizeof fname);
			swfac = 0;			/* defaults to 1.2 */
			encoding = 0;
			if (*p != '\0') {
				if (isalpha((unsigned char) *p)) {
					encoding = parse_encoding(p);
					while (*p != '\0'
					    && !isspace((unsigned char) *p))
						p++;
					while (isspace((unsigned char) *p))
						p++;
				}
				if (isdigit((unsigned char) *p)) {
					char *q;
					float v;

					v = strtod(p, &q);
					if (v > 2 || (*q != '\0' && *q != '\0'))
						goto bad;
					swfac = v;
				}
			}
			fnum = get_font(fname, encoding);
			def_font_enc[fnum] = encoding;
			swfac_font[fnum] = swfac;
			used_font[fnum] = 1;
			for (i = FONT_UMAX; i < FONT_MAX; i++) {
				if (cfmt.font_tb[i].fnum == fnum)
					cfmt.font_tb[i].swfac = cfmt.font_tb[i].size
									* swfac;
			}
			return;
		}
		break;
	case 'i':
		if (strcmp(w, "infoname") == 0) {
			if (*p < 'A' || *p > 'Z')
				goto bad;
			set_infoname(p);
			return;
		}
		break;
	case 'm':
		if (strcmp(w, "musiconly") == 0) {	/* compatibility */
			if (g_logv(p))
				cfmt.fields[1] &= ~(1 << ('w' - 'a'));
			else
				cfmt.fields[1] |= (1 << ('w' - 'a'));
			return;
		}
		break;
	case 'p':
		if (strcmp(w, "printparts") == 0) {	/* compatibility */
			if (g_logv(p))
				cfmt.fields[0] |= (1 << ('P' - 'A'));
			else
				cfmt.fields[0] &= ~(1 << ('P' - 'A'));
			return;
		}
		if (strcmp(w, "printtempo") == 0) {	/* compatibility */
			if (g_logv(p))
				cfmt.fields[0] |= (1 << ('Q' - 'A'));
			else
				cfmt.fields[0] &= ~(1 << ('Q' - 'A'));
			return;
		}
		break;
	case 'w':
		if (strcmp(w, "withxrefs") == 0) {	/* compatibility */
			if (g_logv(p))
				cfmt.fields[0] |= (1 << ('X' - 'A'));
			else
				cfmt.fields[0] &= ~(1 << ('X' - 'A'));
			return;
		}
		if (strcmp(w, "writehistory") == 0) {	/* compatibility */
			struct SYMBOL *s;
			int bool;
			unsigned u;

			bool = g_logv(p);
			for (s = info['I' - 'A']; s != 0; s = s->next) {
				u = s->as.text[0] - 'A';
				if (bool)
					cfmt.fields[0] |= (1 << u);
				else
					cfmt.fields[0] &= ~(1 << u);
			}
			return;
		}
		break;
	}
	for (fd = format_tb; fd->name; fd++)
		if (strcmp(w, fd->name) == 0)
			break;
	if (fd->name == 0)
		return;

	{
		int l;

		l = strlen(p);
		if (strcmp(p + l - 5, " lock") == 0) {
			p[l - 5] = '\0';
			lock = 1;
		}
	}
	if (lock)
		fd->lock = 1;
	else if (fd->lock)
		return;

	switch (fd->type) {
	case FORMAT_B:
		switch (fd->subtype) {
#ifdef HAVE_PANGO
		case 2:				/* %%pango = 0, 1 or 2 */
			if (*p == '2') {
				cfmt.pango = 2;
				break;
			}
			/* fall thru */
#endif
		default:
		case 0:
		case 3:				/* %%abc2pscompat */
			*((int *) fd->v) = g_logv(p);
			if (fd->subtype == 3) {
				if (cfmt.abc2pscompat)
					deco['M'] = deco_define("tenuto");
				else
					deco['M'] = deco_define("lowermordent");
			}
			break;
		case 1:	{			/* %%writefields */
			char *q;
			int bool, i;
			unsigned u;

			q = p;
			while (*p != '\0' && !isspace((unsigned char) *p))
				p++;
			while (isspace((unsigned char) *p))
				p++;
			bool = g_logv(p);
			while (*q != '\0' && !isspace((unsigned char) *q)) {
				u = *q - 'A';
				if (u < 26) {
					i = 0;
				} else {
					u = *q - 'a';
					if (u < 26)
						i = 1;
					else
						break;	/*fixme: error */
				}
				if (bool)
					cfmt.fields[i] |= (1 << u);
				else
					cfmt.fields[i] &= ~(1 << u);
				q++;
			}
			break;
		    }
		}
		break;
	case FORMAT_I:
		if (fd->subtype == 3) {		/* tuplets */
			unsigned i1, i2, i3;

			if (sscanf(p, "%d %d %d", &i1, &i2, &i3) != 3
			 || i1 > 2 || i2 > 2 || i3 > 2)
				goto bad;
			cfmt.tuplets = (i1 << 8) | (i2 << 4) | i3;
			break;
		}
		if (fd->subtype == 5) {		/* gracespace */
			unsigned i1, i2, i3;
			float f1, f2, f3;

			if (sscanf(p, "%f %f %f", &f1, &f2, &f3) != 3
			 || f1 > 256 || f2 > 256 || f3 > 256)
				goto bad;
			i1 = f2 * 10;
			i2 = f2 * 10;
			i3 = f3 * 10;
			cfmt.gracespace = (i1 << 16) | (i2 << 8) | i3;
			break;
		}
		if (fd->subtype == 4 && !isdigit(*p))	/* textoption */
			cfmt.textoption = get_textopt(p);
		else if (fd->subtype == 2)		/* dblrepbar */
			cfmt.dblrepbar = get_dblrepbar(p);
		else if (isdigit(*p) || *p == '-' || *p == '+')
			sscanf(p, "%d", (int *) fd->v);
		else
			*((int *) fd->v) = g_logv(p);
		switch (fd->subtype) {
		case 1:					/* transpose */
			cfmt.transpose *= 3;
			if (p[strlen(p) - 1] == '#') {
				if (cfmt.transpose > 0)
					cfmt.transpose++;
				else
					cfmt.transpose -= 2;
			} else if (p[strlen(p) - 1] == 'b') {
				if (cfmt.transpose > 0)
					cfmt.transpose += 2;
				else
					cfmt.transpose--;
			}
			break;
//		case 2:				/* (free) */
//			break;
		case 4:				/* textoption */
			if (cfmt.textoption < 0)
				goto bad;
			break;
		}
		break;
	case FORMAT_R: {
		char *q;
		int i;
		float v;

		v = strtod(p, &q);
		if (*q != '\0' && *q != ' ')
			goto bad;
		switch (fd->subtype) {
		default:
			if (v <= 0)
				goto bad;
			break;
		case 1: {			/* note spacing factor */
			float v2;

			if (v < 1 || v > 2)
				goto bad;
			i = C_XFLAGS;		/* crotchet index */
			v2 = space_tb[i];
			for ( ; --i >= 0; ) {
				v2 /= v;
				space_tb[i] = v2;
			}
			i = C_XFLAGS;
			v2 = space_tb[i];
			for ( ; ++i < NFLAGS_SZ; ) {
				v2 *= v;
				space_tb[i] = v2;
			}
			break;
		    }
		case 2:				/* maxshrink / stretchlast */
			if (v < 0 || v > 1)
				goto bad;
			break;
		case 3:				/* breaklimit */
			if (v < 0.5 || v > 1)
				goto bad;
			break;
		}
		*((float *) fd->v) = v;
		break;
	    }
	case FORMAT_F: {
		int b;

		g_fspc(p, (struct FONTSPEC *) fd->v);
		b = strstr(p, "box") != NULL;
		switch (fd->subtype) {
		case 1:
			cfmt.partsbox = b;
			break;
		case 2:
			cfmt.measurebox = b;
			break;
		case 3:
			cfmt.gchordbox = b;
			break;
		}
		break;
	    }
	case FORMAT_U:
		*((float *) fd->v) = scan_u(p);
		if (fd->subtype == 1) {
			float rmargin;

			rmargin = (cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth)
					- staffwidth - cfmt.leftmargin;
			if (rmargin < 0)
				error(1, NULL, "'staffwidth' too big\n");
			cfmt.rightmargin = rmargin;
		}
		break;
	case FORMAT_S: {
		int l;

		l = strlen(p) + 1;
		*((char **) fd->v) = getarena(l);
		if (*p == '"')
			get_str(*((char **) fd->v), p, l);
		else
			strcpy(*((char **) fd->v), p);
		break;
	    }
	}
	return;
bad:
	error(1, NULL, "Bad value '%s' for '%s' - ignored", p, w);
}

/* -- lock a format -- */
void lock_fmt(void *fmt)
{
	struct format *fd;

	for (fd = format_tb; fd->name; fd++)
		if (fd->v == fmt)
			break;
	if (fd->name == 0)
		return;
	fd->lock = 1;
}

/* -- start a new font -- */
void set_font(int ft)
{
	int fnum;
	struct FONTSPEC *f, *f2;

	if (ft == outft)
		return;
	f = &cfmt.font_tb[ft];
	if (outft >= 0) {
		f2 = &cfmt.font_tb[outft];
		outft = ft;
		fnum = f->fnum;
		if (fnum == f2->fnum && f->size == f2->size)
			return;
	} else {
		outft = ft;
		fnum = f->fnum;
	}
	if (!used_font[fnum]
	 && epsf <= 1 && !svg) {	/* (not usefull for svg output) */
		if (file_initialized <= 0) {
			used_font[fnum] = 1;
		} else {
			error(1, NULL,
			      "Font '%s' not predefined; using first in list",
			      fontnames[fnum]);
			fnum = 0;
		}
	}
	if (f->size == 0) {
		error(0, NULL, "Font '%s' with a null size - set to 8",
		      fontnames[fnum]);
		f->size = 8;
	}
	a2b("%.1f F%d ", f->size, fnum);
}

/* -- get the encoding of a font -- */
int get_font_encoding(int ft)
{
	return font_enc[ft];
}
abcm2ps-7.8.13/format.txt0000644000175000017500000016316412314503276013302 0ustar  jefjef			Format parameters
			=================

Note: This file will be soon removed from the abcm2ps distribution.
====  The format parameters documentation is now online:
	http://moinejf.free.fr/abcm2ps-doc/index.html

The general layout of the printed scores may be changed in many ways.

For example, when running the program, one or more format files may
be specified as program arguments using the command line option -F
(see the file options.txt).
A format file contains a sequence of lines where empty and lines
beginning with a '%' are ignored.
Each line contains a pair consisting of the  parameter name
(without the "%%") and the associated value(s).

Alternatively one or more format parameters may be specified directly
as run time argument pairs using the following syntax.
The first argument is the format parameter name preceded by two dashes
(eg. --vocalfont) and the second argument is the new value.
If the value contains spaces, it should be enclosed by quotes when
the program is run from a shell. For example, the following
command will run abcm2ps on the file myfile.abc changing the format
parameter vocalfont to 'Arial 13'.
 
	abcm2ps --vocalfont 'Arial 13' myfile.abc

Format parameters may be specified inside an ABC tune in one of two
ways. Pseudo-comments are specified by beginning a line with '%%'.
The syntax is simply:

	%%parameter_name new_value

Alternatively, a parameter change may be indicated inside the body of
the tune using the I: information field. For example:

	CDEF | [I:annotationfont Arial 13] "^bla" GABc |

The keyword "lock" may appear at the end of a parameter value.
After such a keyword has been found, the parameter will not be changed
anymore unless "lock" appears again.
It is implicitly appended in the command line arguments so that these
parameters take precedence and override any other changes.

example:
	abcm2ps --vocalfont 'Arial 13' myfile.abc
in myfile.abc:
	%%vocalfont Times-Roman *		% <- ignored
	%%vocalfont Helvetica * lock		% <- vocalfont = 'Helvetica 13'


Scope
-----

This section describes the meaning of the 'Scope:' found in the following
command descriptions. This concept is tied to the way the music is
generated.

All the commands appearing in the program arguments (including those in
format files) are inserted as pseudo-comments at the head of the ABC file
to be processed. Then, the whole source is parsed. The music is generated
as ABC music elements are processed, but it is not directly written to the
output file. Instead, it is buffered until some event occurs. This may be
either the end of a tune, the end of a page (page full, %%newpage or new tune
with %%splittune), or some specific music element or command (see 'restart'
below). At this moment, if the output file was still empty, the global output
parameters are written (PostScript global definitions), and then the buffered
music is written.

Here are the possible values of 'Scope:':

- 'page'
	Each output page has specific information (dimensions,
	header/footer, ...) which needs to be known at the time a new page
	is opened in the output file. As the exact moment of writing
	the buffered music may not be known, the commands of scope 'page'
	should be set near the beginning of the ABC file or at least
	immediately after a 'newpage' command is issued.

- 'tune'
	Commands with the scope 'tune' have to do with the tune headers
	(title, composer, tempo...) and footers (lyrics after tune and
	notes).
	They behave either globally or locally depending on their placement.

	When they appear outside a tune, they apply to the tunes which are
	yet to be processed. The parameter values are said to be 'global'.

	When they appear inside a tune, they apply locally to only this
	tune, the remaining tunes assume the global values again.
	In this case, since the exact write moment is not known, such
	commands should appear in the tune header or immediately after
	the first K:.

- 'generation'
	As explained above, the generation of the music is done element
	by element, independently of the buffering and file output.
	It starts at the beginning of a tune and stops naturally at the end
	of this tune, but it may be interrupted and restarted when
	encountering some specific information field (T: only) or command
	(see 'restart' below).
	The commands with a scope 'generation' are globally applied to each
	generation sequence (between start and stop). In other words, when
	a parameter is changed many times in a generation sequence, only the
	last value is used. This value remains for the next generation
	phases. They have the same global and local behaviour as the 'tune'
	commands, i.e. when starting the generation a new tune, all
	parameters have the global value.

- 'immediate'
	Such commands are executed as they are found in the source file.
	Their effects are immediate and apply to the next music elements.
	Some of them may do a generation restart (see 'restart' below).

- 'voice'
	Commands with this scope may appear only inside tunes and apply
	to the current voice only. Their main scope type may be
	'generation' or 'immediate'. There is no associated global value.

- 'restart'
	This information indicates that the execution of the command
	is preceded by a stop of the generation (see 'generation' above)..


Common value types
------------------

A <boolean> value may be:
	- 'true', 'yes', '1' or (empty)
	- 'false', 'no' or '0'
Only the first character is checked.

<int> is a whole number, usually positive.

<encoding> may be either 'native' or any other string in which case
'utf-8' is assumed (default value).
It is used only for PostScript output without pango.
When the <encoding> is not 'native', the utf-8 characters are replaced by
the name of their glyphs as they appear in the font files. This is done
thanks to an internal table which contains the ASCII and most Latin
characters. This table may be extended by the command %%glyph to handle more
characters (see the addition of '...'  ellipsis - in the file sample.abc).

<float> is a number which may have a decimal point number (eg. 0.5).

<size> is used in font definitions. It is expressed in graphic points
(see <unit>).

<unit> is a dimension of which the unit is defined by the suffix:
- 'pt' or no suffix: graphic points,
- 'in': inches, or
- 'cm': centimeters.
The height of a 5 lines staff is always 24pt.

<font>, <encoding> and <size> appear in font definitions.
They may be specified as '*' (asterisk), in which case their values
remain unchanged.
<encoding> may be omitted, in which case its value defaults to 'utf-8'
for the first declaration of the font or it remains unchanged.
When <size> is omitted, it remains unchanged.
Examples:
%%vocalfont Arial 12		% Arial utf-8 12pt
%%vocalfont Times-Roman		% Times-Roman utf-8 12pt
%%vocalfont * 13		% Times-Roman utf-8 13pt
%%vocalfont UKaiCN-UTF8-H native % UKaiCN-UTF8-H native 13pt


List of the format parameters
-----------------------------

  abc2pscompat <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Handle old abc2ps tunes.

		When set, 'M' becomes the !tenuto! decoration and a pitch
		translation may be done for the bass and alto clefs
		(respectively, 2 and 1 octaves down).

		It is preferable to rewrite the old tunes to comply with
		the current standard rather than using this parameter.
		For example, you could include in the tune,
			U: M = !tenuto!
		and/or:
			K:C clef=bass octave=-2
		and the old tune would be interpreted correctly.

  abcm2ps <char> [<char>]*
	Default: %
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		Change the pseudo-comment prefix(es).

		By default, pseudo-comments are lines starting with two percent
		signs ("%%"). This command redefines a list of possible second
		characters of these commands (up to 3 different characters).
		This permits to avoid conflicts with pseudo-comments of other
		programs and also to have a simple conditional generation.
		Example 1:

			%%abcm2ps *
			%*voice Mib	% the voices which name contains "Mib"
			%*transpose -3	% are transposed a minor third lower
			%*voice end
			%*abcm2ps %	% restore standard pseudo-comments

		Example 2:
		   - tune.abc:
			X:1
			...
			K:C
			%			% default 4 staves
			%Fstaves [(S A) (T B)]	% 2 staves
			%Sstaves S		% Soprano only
			%Astaves A		% Alto only
			V:S
			...
			V:A
			...
			V:T
			...
			V:B
			...
		   - command line:
			abcm2ps --abcm2ps %A tune.abc	# generate alto only

  alignbars <int>
	Default: 0
	Compilation: none
	Command line: none
	Scope: immediate, restart and restart after <int> music lines
	Description:
		Align the bars of the next <int> music lines.
		Such an alignment works only when there is only one
		voice (i.e. no V:, %%staves or %%score are permitted).

  aligncomposer <int>
	Default: 1
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		This parameter specifies where the composer field
		is displayed.

		A negative value means 'on the left', 0 means 'center',
		and a positive value means 'on the right'.

  annotationfont <font> [<encoding>] [<size>]
	Default: Helvetica 12
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		Set the annotation font.

  autoclef <bool>
	Default: 1
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		When this parameter is false, the voices which don't contain
		a 'clef=' in K: or V: use the treble clef, according to the
		ABC standard.
		When true, the clefs and possibly the clef changes for these
		voices are determined from the note pitches and inserted
		automatically.

  barsperstaff <int>
	Default: 0
	Compilation: none
	Command line: -B<int>
	Scope: generation
	Description:
		Try to typeset with <int> bars on each line.

  beginps ["nosvg"]
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		This command introduces a PostScript sequence that
		ends with '%%endps' and which will be included in the
		PostScript output file.

		Such a sequence cannot be greater than 128 Kb.

		When the output file format is SVG (command options '-g',
		'-v' or '-X'), the PostScript code is executed by the
		small abcm2ps PS interpreter. Sequences which cannot
		be executed (as font redefinitions) must be skipped
		checking the presence of the symbol 'svg':

		/svg where {pop} {
		.. PostScript code which cannot be executed by abcm2ps ..
		} ifelse

		When the option "nosvg" is present, the sequence is not
		executed on SVG output.

  beginsvg
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		This command introduces a SVG sequence that ends with
		'%%endsvg' and which will be included in the SVG output file.

		It allows adding a CSS to the generated SVG files.

		The sequence is ignored when the SVG output file has begun
		to be written (for example if it is found after the first
		K: information field).

  begintext [<option>]
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate, restart
	Description:
		Start printing the free text of the followng lines up to
		%%endtext.

		When a line of text starts with '%%', these characters are
		removed.

		When a sequence %%begintext .. %%endtext appears inside a
		tune, blank lines must be replaced with '%%' to prevent
		them from being confused with the end of the tune marker.

		<option> may be:
		    'obeylines':	  keep lines as they are (default)
		    'align' or 'justify': justify the lines
		    'ragged' or 'fill':	  fill the lines
		    'center':		  center the lines
		    'skip':		  don't print the lines
							(same as comments)
		    'right':		  align at the right side
		When <option> is omitted, it defaults to the %%textoption
		value.

		Inside the free text, an empty line starts a new paragraph.
		Page breaks (start of new pages) cannot occur in the middle
		of a paragraph.

  bgcolor <color>
	Default: none
	Compilation: none
	Command line: none
	Scope: page
	Description:
		This parameter defines the background color of SVG images.
		The <color> may be a color name (like 'white') or
		a hexadecimal RGB color (like '#faf0e6').
		When not set, the SVG images are transparent.

  botmargin <unit>
	Default: 1cm
	Compilation: none
	Command line: none
	Scope: page
	Description:
		Set the page bottom margin.

  breaklimit <float>
	Default: 0.7
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		This parameter is used with 'maxshrink' to adjust the
		place where automatic music line breaks may occur.

		To know how many music symbols will be in a music line,
		the width of each symbol is computed by:
			width = minimal_space * 'maxshrink'
				+ natural_space * (1 - 'maxshrink')
		When the sum of all the symbol widths is greater than
			(paper width - margins) * 'breaklimit'
		and smaller than (paper width - margins), a line break
		may occur.

		The value <float> is limited between 0.5 (line breaks may
		occur when the line is 50% full) and 1 (the music line is
		split at the exact computed symbol).

  breakoneoln <bool>
	Default: 1
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		When set, a space (beam break) is inserted after each end of
		(ABC source) line.
		This prevents a beam from being continued between two music
		lines.
		(don't confuse this parameter with %%continueall or
		%%linebreak)

  bstemdown <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: immediate, voice
	Description:
		When set, the stem of the note in the middle of the
		staff goes downwards. Otherwise, it goes upwards
		or downwards according to either the previous or
		following note.

  cancelkey <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		When set, the accidentals associated with the last key
		signature are cancelled using naturals prior to
		introducing the new key signature.

  center <line of text>
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate, restart
	Description:
		Print one line of centered text.

  clef <clef_name>[<clef_line>][<octave_indication>]
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate, voice
	Description:
		Insert a clef change.

		<clef_name> may be:
			treble (same as G2)
			alto (same as C3)
			tenor (same as C4)
			bass (same as F4)
			perc (same as P2)
			G
			C
			F
			P
			none (to avoid clefs on the next music lines)
			"<user_clef_name>" (<user_clef_name> is the name of
				a PostScript function which  draws the clef
				glyph)

		<clef_line> gives the number of the line on which the note of
		the clef is defined. When omitted, it defaults according to
		the clef name: line #3 for "C", line #4 for "F" and line #2
		for the other clefs.

		<octave_indication> is either
		- "+8" or "-8", in which case a '8' is drawn above or below
		  the clef without octave transposition.
		- "^8" or "_8", in which case a '8' is drawn above or below
		  the clef with octave transposition.

		There should be no space in the %%clef value.
		Example:
			%%clef bass	% same as K: clef=bass

  combinevoices <int>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Define how notes of different voices in a same staff
		may be combined.
		<int> may be:
			- < 0: the voices are displayed as written
			- 0: the rests of same duration are displayed
				as one rest
			- 1: the notes of same duration are combined
				to chords except when there could be
				a second, a unison or a voice inversion
			- > 1: the notes of same duration are always combined
				to chords

  composerfont <font> [<encoding>] [<size>]
	Default: Times-Italic 14
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the composer font.

  composerspace <unit>
	Default: 0.2cm
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the vertical space above the composer.

  contbarnb <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		If not set, the bar number of the second repeat(s) is reset to
		the number of the first repeat.
		If set, the bars are sequentially numbered.

  continueall <bool>
	Default: 0
	Compilation: none
	Command line: -c
	Scope: generation
	Description:
		When true, all line breaks of the tune are ignored.
		This parameter is deprecated in favour of '%%linebreak <none>'
		plus 'linewarn 0'.

  custos <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		When set, a custos is added at the end of each music line.
		This parameter works with single voice tunes only.

  dateformat <text>
	Default: "%b %e, %Y %H:%M"
	Compilation: none
	Command line: none
	Scope: page
	Description:
		Define the format of the date and time.
		The possible values of this parameter are described in the
		manual pages of date(1) and strftime(3).
		Note: the '%'s must be escaped as '\%' if the is not enclosed
		in double quotes (otherwise it is taken as the start of a
		comment).

  deco <name> <c_func> <ps_func> <h> <wl> <wr> [<str>]
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		Define a decoration.
		This command assumes a good knowledge of the abcm2ps internals.
		The arguments are:
		<name>: name of the decoration. If it is the name of an
			existing decoration, this one is redefined.
		<c_func>: index of a C function (defined in deco.c).
			The possible values are:
			0, 1, 2: the decoration goes near the note, possibly
					inside the staff.
				0: 'dot' and 'tenuto'
				1: 'slide'
				2: 'arpeggio'
			3, 4, 5: the decoration goes near the note but outside
					the staff. It is usually printed above
					the staff.
				3: general
				4: below the staff
				5: long 'trill' (with start and stop)
			6, 7: the decoration is tied to the staff (dynamic
					marks). It is generally printed below
					the staff.
				6: general
				7: long dynamic (with start and stop)
		<ps_func>: postscript function name or '-' for the start
			of a long decoration.
		<h>: decoration height.
			It is the minimum height for +arpeggio+.
		<wl> and <wr>: left and right widths.
			These values are actually used for general dynamic
			marks only.
		<str>: text to display (for some postscript functions
			- see code).
		The decorations, which names begin with 'head-', prevent the
		note head(s) to be drawn.
		See deco.abc for examples.

  decoration <character>
	Default: !
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		Define the decoration separator.
		It may be set only to '!' (default) or '+' (for compatibility
		with the ABC standard 2.0).

  dblrepbar <bar>
	Default: :][:
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Define how the double repeat bars (::, :|: :||:) are drawn.

  dynalign <bool>
	Default: 1
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		When true, the dynamic marks are horizontally aligned.

  dynamic <int>
	Default: 0
	Compilation: none
	Command line: none
	Scope: immediate, voice
	Description:
		Set the position of the dynamic informations (crescendo,
		diminuendo..).
		<int> may be:
			0 or 'auto' for automatic position (it depends on
				the presence and position of lyrics)
			1 or 'above' above the staff
			2 or 'below' below the staff
			3 or 'hidden' don't print
		When this parameter appears outside a tune or inside a tune
		header, it applies to all voices. When it appears inside
		a tune body, it applies to the current voice only.

  EPS <eps_file>
	Default: 0
	Compilation: none
	Command line: -f
	Scope: immediate, restart
	Description:
		Include the file <eps_file> (Encapsulated PostScript).

		The file content is left or right aligned, or centered
		according to the current value of '%%textoption'.

  flatbeams <bool>
	Default: 0
	Compilation: none
	Command line: -f
	Scope: generation
	Description:
		Draw flat beams.

  font <font> [[<encoding>] <scale>]
	Default: none
	Compilation: none
	Command line: none
	Scope: page
	Description:
		Define a font and its encoding.

		This parameter is required with PostScript output when
		specific fonts are defined later in ABC files/tunes.

		<scale> is the width factor to apply to the Time-Roman
		character width. It is needed to adjust the string width
		when the computation using the default scale gives
		erroneous values:
			- if the strings collide with other elements,
			  set <scale> to a value lower than 1.0.
			- if there is too much space between elements
			  because of the strings, set it to a value
			  greater than 1.0.
		Note that the <scale> is not applied immediately: it will
		used only in further font assignment.

  footer <text>
	Default: none
	Compilation: none
	Command line: none
	Scope: page
	Description:
		Specify the text to be printed at the bottom of each page.
		There may be one or two lines in the footer.
		To specify 2 lines, put the 2 characters "\n" (not
		a real 'newline') as a separator in the command.
		In each line, 3 areas may be defined: left, center and
		right.
		These areas are separated by tabulations (real TABs,
		not "\t") and may be empty (if the left area is empty,
		double quote the string - see sample3.abc for example).
		The prefix '$' introduces variable substitution:
			- '$d' is the date and time of the last modification
			   of the current ABC input file,
			- '$D' is the current date and time,
			- '$F' is the current input file name,
			- '$Ix' is any header information type ('x' is a
			   letter range 'A' to 'Z').
			- '$P' is the current page number,
			- '$P0' and '$P1' are also the page number, but apply
			   only to the even ('0') or odd ('1') page numbers,
			- '$T' is the current tune title,
			- '$V' is 'abcm2ps-' followed by the program version.
		For example, the command line option '-N3' is the same
		as:
			%%header "$P0		$P1"
		(note the 2 TABs).
		If the footer (or header) begins with '-' (hyphen/minus),
		it is not printed on the first page.

  footerfont <font> [<encoding>] [<size>]
	Default: Times-Roman 12
	Compilation: none
	Command line: none
	Scope: page
	Description:
		Set the footer font.
		Note that the footer is not scaled.

  format <filename>
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		Load the format (or PostScript) file <filename>.
		When found in the command line, this parameter is
		equivalent to '-F'.

  gchord <int>
	Default: 0
	Compilation: none
	Command line: none
	Scope: immediate, voice
	Description:
		Set the position of the guitar chords.
		<int> may be:
			0 or 'auto' for automatic position (usually
				above the staff)
			1 or 'above' above the staff
			2 or 'below' below the staff
			3 or 'hidden' don't print
		When this parameter appears outside a tune or inside a tune
		header, it applies to all voices. When inside a tune body,
		it applies to the current voice only.

  gchordbox <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Draw a box around the guitar chords.
		This value may be set to 'true' by the option "box"
		in %%gchordfont.

  gchordfont <font> [<encoding>] <size> ["box"]
	Default: Helvetica 12
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		Set the guitar chord font.
		If "box" is present, a box is drawn around the guitar chords.

  glyph <unicode> <glyph_name>
	Default: none
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the name of a unicode glyph.

		This command is useful for PostScript output without pango.
		<unicode> is a hexadecimal value, and <name> is the name of
		the associated glyph in the font files.

  graceslurs <bool>
	Default: 1
	Compilation: none
	Command line: -G
	Scope: generation
	Description:
		Draw slurs on grace notes.

  gracespace <float> <float> <float>
	Default: 6.5 8.0 12.0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Define the space before, inside and after the grace notes.

  gstemdir <int>
	Default: 0
	Compilation: none
	Command line: none
	Scope: immediate, voice
	Description:
		Set the direction of the stems of the grace notes.
		<int> may be:
			0 or 'auto' for automatic position
			1 or 'up' stem up
			2 or 'down' stem down
			3 or 'opposite' opposite direction of the next note
		When this parameter appears outside a tune or inside a tune
		header, it applies to all voices. When inside a tune body,
		it applies to the current voice only.

  header <text>
	Default: none
	Compilation: none
	Command line: none
	Scope: page
	Description:
		Set the text printed at the top of each page.
		See 'footer' above for the header syntax.

  headerfont <font> [<encoding>] [<size>]
	Default: Times-Roman 12
	Compilation: none
	Command line: none
	Scope: page
	Description:
		Set the header font.
		Note that the header is not scaled by %%scale.

  historyfont <font> [<encoding>] [<size>]
	Default: Times-Roman 16
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the history font.

  hyphencont <bool>
	Default: 1
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		If set, when a word of lyric under staff ends with a hyphen,
		put a hyphen in the next line.

  indent <unit>
	Default: 0
	Compilation: none
	Command line: -I<unit>
	Scope: tune
	Description:
		Indent the first line of the tune by <unit>.

  infofont <font> [<encoding>] [<size>]
	Default: Times-Italic 14
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the infoline font.

  infoline <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Display the rhythm (R:) and area (A:) on a same line
		before the first music line:
			Rhythm (Area)

  infoname <uppercase letter> [<information name>]
	Default:
		R "Rhythm: "
		B "Book: "
		S "Source: "
		D "Discography: "
		N "Notes: "
		Z "Transcription: "
		H "History: "
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Define the name of the information fields which may be
		printed after the tunes.
		Note: For being printed, a field must be set to 'on' in a
		%%writefields parameter and have an information name.
		When <information name> is not present, the field name is
		removed. This is usefull to change the field order.
		Examples:

		%%infoname G "Group: "	% display the group
		%%writefields G 1

		%%infoname N		% notes after the other fields
		%%infoname N "Notes: "

  infospace <unit>
	Default: 0
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the vertical space above the infoline.

  keywarn <bool>
	Default: 1
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		When set, if a key signature change occurs at the
		beginning of a music line, a cautionary key signature
		is added at the end of the previous line.

  landscape <bool>
	Default: 0
	Compilation: none
	Command line: -l
	Scope: page
	Description:
		Set the page orientation to landscape.

  leftmargin <unit>
	Default: 1.8cm
	Compilation: none
	Command line: -m<unit>
	Scope: page, restart
	Description:
		Set the page left margin.

  linebreak <list of linebreak separators>
	Default: <EOL>
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		Define the character(s) which break(s) the music lines.
		The <list of linebreak separators> is a blank separated
		list of none, one or more of:
			<EOL> (End Of Line of any system)
			$
			!
			<none>
		For compatibility, when <EOL> is in the list, the character
		'!' does a linebreak if it does not introduce a decoration.
		If the value '<none>' occurs alone or if the list is empty,
		the program computes the linebreaks automatically. This
		replaces the deprecated '%%continueall 1'.

  lineskipfac <float>
	Default: 1.1
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the factor for spacing between lines of text.

  linewarn <bool>
	Default: 1
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		When set, raise a warning when there are too few or
		too many elements in a music line.

  maxshrink <float>
	Default: 0.65
	Compilation: none
	Command line: -a<float>
	Scope: generation
	Description:
		Set how much to compress horizontally when music line breaks
		are automatic.
		<float> must be between 0 (natural spacing)
		and 1 (max shrinking).

  maxstaffsep <unit>
	Default: 2000pt
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the maximum staff system separation.

  maxsysstaffsep <unit>
	Default: 2000pt
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the maximum staves separation inside a system.
		This values applies to all staves when global or in
		the tune header. Otherwise, it defines the maximum
		vertical offset of the next staff.

  measurebox <bool>
	Default: 0
	Compilation: none
	Command line: trailing 'b' at end of -j or -k - see measurenb.
	Scope: generation
	Description:
		Draw a box around the measure numbers.
		This value may be set to 'true' by the option "box"
		in %%measurefont.

  measurefirst <int>
	Default: 1
	Compilation: none
	Command line: -b<int>
	Scope: tune
	Description:
		Start numbering the measures of the tune from <int>.
		This parameter is obsolete and should be replaced by
		'%%setbarnb' in the tune header.

  measurefont <font> [<encoding>] <size> ["box"]
	Default: Times-Italic 14
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the measure font.
		If "box" is present, a box is drawn around the measure
		numbers.

  measurenb <int>
	Default: -1
	Compilation: none
	Command line: -j<int>[b] or -k<int>[b]
	Scope: generation
	Description:
		If positive, draw the measure number every <int> bars.
		If <int> = 0, the measure number appears only on the
		left of the staff systems.
		On the command line only, if a trailing 'b' is present,
		a box is also drawn around the measure numbers.

  micronewps <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: page
	Description:
		If set, use the new PostScript function to draw the microtonal
		accidentals.
		(see "Microtone" in features.txt for more information)

  multicol <command>
	Default: 0
	Compilation: none
	Command line: none
	Scope: immediate, restart
	Description:
		Define multicolumn printing.

		<command> may be:
		    'start':	save the current vertical position and the
				left and right margins. Then, these margins
				may be changed to print music or text.
		    'new':	reset the vertical offset at the place of
				the previous '%%multicol start', and restore
				the left and right margins.
		    'end':	restore the left and right margins, and skip
				down to a safe place.
		(see 'sample3.abc' for an example).
		This command may also be used to group some tunes and text in
		a same page.

  musiconly <bool>
	Default: 0
	Compilation: none
	Command line: -M
	Scope: generation
	Description:
		If true, don't output the lyrics under staff.

  musicspace <unit>
	Default: 0.2cm
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the vertical space above the first staff.

  newpage [<int>]
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate, restart
	Description:
		Continue printing on a new page and optionally restart page
		numbering from <int>.

  notespacingfactor <float>
	Default: 1.414
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the note spacing factor to <float> (range 1..2).

		This value is used to compute the natural spacing of
		the notes. The base spacing of the crotchet is always
		40 pts. When the duration of a note type is twice the
		duration of an other note type, its spacing is multiplied
		by this factor.
		The default value causes the note spacing to be multiplied
		by 2 when its duration is multiplied by 4, i.e. the
		space of the semibreve is 80 pts and the space of the
		semiquaver is 20 pts.
		Setting this value to 1 sets all note spacing to 40 pts.

  oneperpage <bool>
	Default: 0
	Compilation: none
	Command line: -1
	Scope: page
	Description:
		Output one tune per page.

  ornament <int>
	Default: 0
	Compilation: none
	Command line: none
	Scope: immediate, voice
	Description:
		Set the position of the ornaments (mordent, trill..).
		<int> may be:
			0 or 'auto' for automatic positioning (usually above
				the staff)
			1 or 'above' above the staff
			2 or 'below' below the staff
			3 or 'hidden' don't print
		When this parameter appears outside a tune or inside a tune
		header, it applies to all voices. When it is inside a tune
		body, it applies to the current voice only.

  pageheight <unit>
	Default: PAGEHEIGHT
	Compilation: PAGEHEIGHT= (A4: 29.7cm - US: 11in)
	Command line: none
	Scope: page
	Description:
		Set the page height.

  pagewidth <unit>
	Default: PAGEWIDTH
	Compilation: PAGEWIDTH= (A4: 21.0cm - US: 8.5in)
	Command line: none
	Scope: page
	Description:
		Set the page width.

  pango <bool>
	Default: 1
	Compilation: HAVE_PANGO
	Command line: none
	Scope: generation
	Description:
		Enable or disable PostScript output with pango.

		This command works only when abcm2ps is compiled with
		pango/freetype support.
		By default, pango is used for texts containing characters
		that are not ASCII nor Latin. Its advantage is that it
		searches for a replacement font when a character does not
		exist in the current font.
		Trick: this parameter may be set to '2' to force pango
		to be used for all texts.

  parskipfac <float>
	Default: 0.4
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the factor for spacing between text paragraphs.

  partsbox <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Draw a box around the part names.
		This value may be set to 'true' by the option "box"
		in %%partsfont.

  partsfont <font> [<encoding>] <size> ["box"]
	Default: Times-Roman 15
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the part font.
		If "box" is present, a box is drawn around the part names.

  partsspace <unit>
	Default: 0.3cm
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the vertical space above a new part.

  pdfmark <int>
	Default: 0
	Compilation: none
	Command line: none
	Scope: page
	Description:
		When set to a non null value, the PostScript output file
		contains marks which may be used by the PS to PDF translators
		to create a PDF index of the tunes.
		If <int> is greater than 1, generate pdfmarks for titles and
		subtitles, otherwise, if <int> is 1, generate pdfmarks
		for the main titles only.

  postscript <text>
  ps <text>
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		Define a line to be included in the PostScript output
		file.
		This parameter may be used to override any PostScript
		function or to define new functions for use in a 'deco'
		format.
		See 'beginps' above.

  repbra <bool>
	Default: 1
	Compilation: none
	Command line: none
	Scope: generation, voice
	Description:
		The repeat brackets are normally displayed as they are found
		in a voice. %%repbra 0' prevents displaying them for the
		current voice.

  repeat [<n> [k]]
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		Try to replace a sequence by one or many repeat signs.

		When placed after a bar, <n> indicates the number of measures
		to be repeated (it may be only one or two). <k> indicates how
		many times the previous measure is to be repeated.

		When placed after a note or rest, <n> indicates the number of
		notes and rests to be repeated, and <k> how many times this
		repetition occurs.

		When omitted, <n> and <k> default to 1.
		No check is done on the equality of the sequences.
		See 'sample5.abc' for examples.

  repeatfont <font> [<encoding>] [<size>]
	Default: Times-Roman 13
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the repeat number/text font.

  rightmargin <unit>
	Default: 1.8cm
	Compilation: none
	Command line: none
	Scope: page, restart
	Description:
		Set the page right margin.

  scale <float>
	Default: 0.75
	Compilation: none
	Command line: -s<float>
	Scope: generation, restart
	Description:
		Set the page scale factor.
		Note that the header and footer are not scaled.

  score <definition>
	Description:
		Controls the layout of multivoiced tunes.
		See the ABC standard version 2.1 for description.

  sep [<h1> <h2> <len>]
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate, restart
	Description:
		Print a separator (centered line) of length <len> with
		space <h1> above and space <h2> below
		(defaults: h1 = h2 = 0.5cm,len = 3.0cm).

  setbarnb <int>
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		Set the number of the next measure.

		When this command appears at the beginning of the tune
		(after K:), only the 2nd measure will have the new number.
		It must appear in the tune header to set the first measure.

  setdefl <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		When true, output some indications about the note, chord
		and/or decorations for customization purpose. These
		indications are stored in the PostScript variable 'defl'.

  setfont-1 <font> [<encoding>] <size>
  setfont-2 <font> [<encoding>] <size>
  setfont-3 <font> [<encoding>] <size>
  setfont-4 <font> [<encoding>] <size>
	Default: Times-Roman 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the alternate fonts for strings.
		In most strings, the current font may be changed
		by "$n" (n = 0, 1 .. 4 - "$0" resets the font to
		its default value).
		Note: <size> is mandatory at the first definition.

  shiftunison <int>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the way voice unison is displayed.
		<int> may be:
		'0': for one note head if possible
		'1': for two shifted notes when one note is dotted
		     and the other one is not,
		'2': also for two shifted notes when one note is a
		     minim (half note) and the other one has some flags,
		'3': for two shifted notes on all unison cases.

  slurheight <float>
	Default: 1.0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the slur height factor.

  splittune <bool>
	Default: 0
	Compilation: none
	Command line: -0
	Scope: page
	Description:
		If false, a tune starts on a new page when it does not
		fit in the current one. If true, there is no page
		check, and the tune may be splitted.

  squarebreve <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Display the breve notes in square format.

  staff <["+" | "-"] int>
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate, voice
	Description:
		Put the next symbols of the current voice on the staff <int>
		(1..n - see sample4.abc for example), or on the <+int>th or
		<-int>th staff.

  staffbreak [<unit>] ["f"]
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate, voice
	Description:
		Set a break in the current staff.

		<unit> gives the width of the break (in points, inches or cm)
		and defaults to 0.5 cm.
		As a side effect, when the width exceeds 0.5 cm and when all
		the voices have the same staffbreak, the left side of the
		staff system is redrawn.
		When "f" is not present, the staff break is removed if it
		occurs at the start or end of the music line.

  stafflines <int>
	Default: 5
	Compilation: none
	Command line: none
	Scope: generation, voice
	Description:
		Set the number of lines of the staff of the current voice.

  staffnonote <int>
	Default: 1
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		This parameter is used to decide if a staff must be displayed
		when it contains no visible note.
		The possible values are:
		- 0: don't display the staff when it contains only
		     invisible rests and notes,
		- 1: don't display the staff when it contains only
		     rests and invisible notes,
		- 2: always display the staff.

  staffscale <float>
	Default: 1
	Compilation: none
	Command line: none
	Scope: generation, voice
	Description:
		Set the scale of the staff of the current voice.

  staffsep <unit>
	Default: 46pt
	Compilation: none
	Command line: -d<unit>
	Scope: generation
	Description:
		Do not put a staff system closer than <unit> from the
		previous system.

  staffwidth <unit>
	Default: none
	Compilation: none
	Command line: -w<unit>
	Scope: page
	Description:
		Adjust the page right margin so that the staff width
		is <unit>.

  staves <definition>
	Description:
		This command is deprecated. Use %%score instead.
		See 'features.txt' for description.

  stemdir <int>
	Default: 0
	Compilation: none
	Command line: none
	Scope: immediate, voice
	Description:
		Set the direction of the stems.
		<int> may be:
			0 or 'auto' for automatic positioning
			1 or 'up' stem up
			2 or 'down' stem down
		When this parameter appears outside a tune or inside a tune
		header, it applies to all voices. When inside a tune body,
		it applies to the current voice only.
		This parameter may also be set using the parameter 'stem='
		in the K: and V: information fields.

  stemheight <float>
	Default: 20.0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the stem height.

  straightflags <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Have straight flags on the stems for bagpipe tunes.

  stretchlast <float>
	Default: 0.8
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Stretch the last music line of a tune when it exceeds
		the <float> fraction of the page width.
		<float> range is 0.0 to 1.0.

  stretchstaff <bool>
	Default: 1
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Stretch underfull music lines inside a tune.

  subtitlefont <font> [<encoding>] [<size>]
	Default: Times-Roman 16
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the subtitle font.

  subtitlespace <unit>
	Default: 0.1cm
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the vertical space above the subtitle.

  sysstaffsep <unit>
	Default: 36pt
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Do not place the staves closer than <unit> inside a system.
		This values applies to all staves when global or in
		the tune header. Otherwise, it defines the minimum
		vertical offset of the next staff.

  tablature [#<int>] [pitch=<pitch>] [[<unit-1>] <unit-2>] <unit-3> \
			<head-func> <note-func> [<bar-func>]
	Default: none
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Define a tablature for the current voice.

		<int> gives the tablature number (from 1 to 8, default=1).
		<pitch> is the pitch of the instrument. It looks like a
			normal ABC note. When present, the pitch of each
			note is given as argument to the note function.
			When absent, the information about the note(s)
			is given by one or many lyrics (w:).
		<unit-1> specifies the width of the header (left side of
			the music line).
		<unit-2> specifies the tablature height above the staff.
		<unit-3> specifies the tablature height under the staff.
		<head-func> is the PostScript function called at start
			of a new music line.
		<note-func> is the PostScript function called at each note.
		<bar-func> is the PostScript function called at each bar.

		The arguments of the PostScript functions depend on the
		presence of the pitch.
		When the pitch is absent, the stack contains:
			- head function:
				- the music line width,
				- the x and y offsets,
				- the number of w: lines.
			- note function:
				- the string as defined by the 'w:' line.
				- the x and y offsets.
				- the w: line number (0 .. n-1).
			- bar function:
				- the ABC bar as a string.
				- the x and y offsets.
				- the w: line number (0 .. n-1).
		Otherwise (pitch present), the PS origins are translated to
		the tablature area and the stack contains:
			- head function:
				- the instrument pitch with a single
				  uppercase letter and a sharp or flat.
			- note function:
				- the octave (0 is 'C') letting pitch >= 0
				  and < 36
				- the pitch in 12th of octave on 3 octaves
				  (0..35 - it may be not a whole number with
				  microtone)
				- the x offset
			- the bar function is never called.

		For examples of tablatures without pitch, see:
			'accordion.abc'
			'http://moinejf.free.fr/abc/banjo.abc',
			'http://moinejf.free.fr/abc/bataille.abc'
			'http://moinejf.free.fr/abc/tabyf1.abc'
		For examples of tablatures with pitch, look at
			flute.fmt
		and try:
			abcm2ps sample.abc -e1 -F flute.fmt -T1 -T3

  tempofont <font> [<encoding>] [<size>]
	Default: Times-Bold 15
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the tempo font.

  text <text>
	Default: none
	Compilation: none
	Command line: none
	Scope: immediate, restart
	Description:
		Print one line of text using the current value of
		'%%textoption'.

  textfont <font> [<encoding>] [<size>]
	Default: Times-Roman 16
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the text font.

  textoption <int>
	Default: 0 (obeylines)
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the default text option.
		This option is used for the text between '%%begintext' and
		'%%endtext', '%%text' and '%%EPS'.
		<int> may be an integer or a keyword. The values are:
			0: obeylines
			1: justify
			2: fill
			3: center
			4: skip
			5: right
		When <int> is 4 (skip), there is no output of texts
		(%%text, %%center, %%begintext..%%endtext...) and %%EPS.

  textspace <unit>
	Default: 0.5cm
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the vertical space above the history.

  timewarn <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		When set, if a time signature change occurs at the
		beginning of a music line, a cautionary time signature
		is added at the end of the previous line.

  titlecaps <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		When set, print the titles in uppercase letters.

  titlefont <font> [<encoding>] [<size>]
	Default: Times-Roman 20
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the title font.

  titleformat <text>
	Default: none
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Define the format of the tune title.
		This format overrides the standard way to display the
		tune title. Then, parameters as %%titleleft, %%infoline
		and also  %%writefields are not used.
		The format is a set of letters, numbers, commas and
		plus and minus signs. Unrecognized characters are ignored.

		A letter gives the ABC header information type. It may be any
		type range 'A' to 'Z', but 'I', 'L', 'M', 'U' and 'V'.

		Alignment is defined by a number and/or a minus sign
		following the letter. It may be:
			'0' for 'center',
			'1' for 'right align'
			'-1' (or '-') for 'left align'.
		When absent, alignment defaults to center ('0').

		A plus sign ('+') may appear between two fields
		in which case these fields are concatenated (this works
		only with fields of the same type and same alignment).

		A comma defines a box edge. In each box, the fields are
		vertically added in their alignment zones.

		Example:
			%%titleformat R-1 P-1 Q-1 T C1 O1 , T + T N1
		displays:
		- in the 1st box:
		    - on the left: the rhythm, part and tempo
		    - in the middle: the main title (only)
		    - on the right: the composer and origin
		- in the 2nd box:
		    - in the middle: the concatenated subtitles
		    - on the right: the notes

		When <text> is empty, the default standard tune format is
		set back.

  titleleft <bool>
	Default: 0
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Output the title on the left (instead of centered).

  titlespace <unit>
	Default: 0.2cm
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the vertical space above the title.

  titletrim <bool>
	Default: 1
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		When set, if the last word of a title starts with a capital
		letter and is preceded by a comma and a space, this word is
		moved at the head. For example: the title
			T:Clair de la lune, Au
		is printed as
			Au Clair de la lune
			
  topmargin <unit>
	Default: 1cm
	Compilation: none
	Command line: none
	Scope: page
	Description:
		Set the page top margin.

  topspace <unit>
	Default: 0.8cm
	Compilation: none
	Command line: none
	Scope: page
	Description:
		Set the vertical space above the tunes and on the top of
		the continuation pages.

  transpose <int> [ "#" | "b" ]
	Default: 0
	Compilation: none
	Command line: none
	Scope: immediate - see below
	Description:
		Transpose the music.

		<int> is a signed number of semitones.
		When "#" or "b" is present, the new key signature(s) will have
		sharps or flats in case of enharmonic keys.

		When this command appears in a global definition (format file
		or file header), it applies to all voices of all the following
		tunes.
		When it appears in a tune header, it applies to all voices.
		When inside a tune body, it applies to the current voice only.

		Note 1: Transposition of key signatures with explicit or
			added accidental list does not work.
		Note 2: The transposition is always relative to the ABC source
			(it does not depend on a previous %%transpose command).

  tuplets <int> <int> <int>
	Default: 0 0 0
	Compilation: none
	Command line: none
	Scope: immediate
	Description:
		Define how to draw the tuplets.
		The first <int> tells when to draw:
			0: auto (draw when no beam on some note of the tuplet)
			1: never
			2: always
		The second <int> tells what to draw:
			0: a square bracket
			1: a slur
			2: do beam extension on rests (does not work yet)
		The third <int> tells which value to print:
			0: a simple number (value of 'p')
			1: no value
			2: a ratio ('p':'q')

  user <char> [ = ] <decoration>
	Default: none
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Define a user decoration.
		This parameter is the same as the information field U:.
		In may be used in format files to change default decorations.

  vocal <int>
	Default: 0
	Compilation: none
	Command line: none
	Scope: immediate, voice
	Description:
		Set the position of the lyrics.
		<int> may be:
			0 or 'auto' for automatic position (usually above
				the staff)
			1 or 'above' above the staff
			2 or 'below' below the staff
			3 or 'hidden' don't print
		When this command appears outside a tune or inside a tune
		header, it applies to all voices. When inside a tune body,
		it applies to the current voice only.

  vocalabove <bool>
	Default: 0
	Compilation: none
	Command line: none
	Description:
		Force the vocals to be above the staff.
		This command is obsolete. Use "%%vocal above' instead.

  vocalfont <font> [<encoding>] [<size>]
	Default: Times-Bold 13
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the font of the lyrics under staves.

  vocalspace <unit>
	Default: 23pt
	Compilation: none
	Command line: none
	Scope: generation
	Description:
		Set the vertical space above the lyrics under the staves.

  voicefont <font> [<encoding>] [<size>]
	Default: Times-Bold 13
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the font of the voice names.

  voicescale <float>
	Default: 1
	Compilation: none
	Command line: none
	Scope: generation, voice
	Description:
		Set the scale of
		- all voices when in the tune header,
		- the current voice when found in the tune body.
		The <float> value must be in the range [0.6 .. 1.5].

  volume <int>
	Default: 0
	Compilation: none
	Command line: none
	Scope: immediate, voice
	Description:
		Set the position of the volume decorations (!p!, !fff!...).
		<int> may be:
			0 or 'auto' for automatic position (usually below
				the staff)
			1 or 'above' above the staff
			2 or 'below' below the staff
			3 or 'hidden' don't print
		When this parameter appears outside a tune or inside a tune
		header, it applies to all voices. When inside a tune body,
		it applies to the current voice only.

  vskip <unit>
	Default: Times-Roman 16
	Compilation: none
	Command line: none
	Scope: immediate, restart
	Description:
		Skip vertical space of height <unit>.

  wordsfont <font> [<encoding>] [<size>]
	Default: Times-Roman 16
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the font of the lyrics at end of tune.

  wordsspace <unit>
	Default: 0cm
	Compilation: none
	Command line: none
	Scope: tune
	Description:
		Set the vertical space above the lyrics at the end of
		the tune.

  writefields <list> <bool>
	Default: COPQTWw 1
	Compilation: none
	Command line: -M, -x
	Scope: generation

	Description:
		<list> is an unsorted list of ASCII letters, each being
		the type of an information field.
		<bool> indicates whether the information field(s) is to be
		displayed or not.


Pseudo-commands used for external formatting
--------------------------------------------

  break <symbol selection> [ [ "," | " " ] <symbol selection> ]*
	Insert a music line break after the selected symbol(s).

	This command may appear only in the tune header or in a %%tune
	sequence.
	There may be many %%break commands in a %%tune sequence.

  clip [ <start symbol> ]  "-" [ <end symbol> ]
	Define the subset of the tune(s) to be printed.

	<start symbol> and <end symbol> are <symbol selection>s (see below).
	The starting and ending symbols are included in the clip.
	This command may appear only in a %%tune sequence.
	There may be only one %%clip command in a %%tune sequence.

  select [ <tune index list> ] [ <regular expression> ]
	Select a subset of tunes in an ABC file to be printed.

	<tune index list> is a comma separated list of tune numbers.
	Each selector applies to the current ABC file.
	A tune number may be:
	- a single index value as indicated in the 'X:' field,
	- a range of such values.
	  A range is indicated as <first_index> "-" [ <last_index> ].
	  The last index may be omitted meaning 'last tune of file'.
	The <regular expression> applies to the tune headers on their whole.
	An empty %%select selects all the tunes of the next ABC files.

	Command line examples:
		abcm2ps voices.abc -e 1,3-5 newfeatures.abc -e5-
		abcm2ps sample2.abc -eclefs voices.abc -e 'K:C\s'

	ABC file example:
		%%select C:.*Bach
		%%abc-include voices.abc
		%%abc-include sample5.abc

	Note: Such selections may give strange results when there are global
	definitions in the ABC files (before and between the tunes).

  tune [ <regular expression> ]
	Select the tune(s) to which the following options will be applied.

	The options are pseudo-comments (starting with %%), up to an other
	'%%tune' command. The command "%%tune end" may be used to mark the
	end of the options.

	The options are inserted at start of the tunes (after the first K:)
	whose header matches the <regular expression>.
	When an option is %%score or %%staves, it replaces a %%score or
	%%staves of the tune. There may be many such options, each one
	replacing one %%staves/score of the tune.
	%%tune may appear only in a global definition (command line,
	format file or file header).
	When the <regular expression> is the same as the one of a previous
	%%tune, all the previous tune options for this regular expression
	are removed.
	When the <regular expression> is absent, all the tune options of
	all tunes are removed.
	ABC file example:
	  Remove the 'ossia' part from sample5.abc of the abcm2ps package

		%%tune Bach
		%%leftmargin 1cm lock
		%%rightmargin 1cm lock
		%%scale 0.7
		%%staves {(1 2) (3 4)}
		%%staves {(1 2) (3 4)}
		%%staves {(1 2) (3 4)}
		%%abc-include sample5.abc

  voice [ <regular expression> ]
	Select the voice(s) to which the following options will be applied.

	The options are pseudo-comments (starting with %%), up to an other
	'%%voice', '%%tune' or %%score/%%staves command.
	The command "%%voice end" may be used to mark the end of the options
	for the last voice.

	The commands are inserted before the first symbol of each voice which
	identifier or full name match the <regular expression>.
	%%voice may appear only in a global definition (command line,
	format file,r file header or %%tune option list).
	When the <regular expression> is the same as the one of a previous
	%%voice, all the previous voice options for this regular expression
	are removed.
	When the <regular expression> is absent, all the global or tune
	related voice options are removed.
	ABC file example:
	  Print 'Tridal a ra va c'halon' with 4 staves, lyrics at the top
	  and with a 'tenor' clef.

		%%select Tridal
		%%tune Tridal
		%%staves S A T B
		%%voice S
		%%vocal up
		%%voice T
		%%clef G,-8
		%%abc-include voices.abc

  <symbol selection>
	The <symbol selection> used in %%break and %%clip permits the
	localisation of a music symbol (note, rest or bar - only).
	It has the following format:

		<measure number> [ ":" <time numerator> "/" <time denominator> ]

	<measure_number> is the measure number as it is displayed with
	"%%measurenb 1"	or '-j1'.
	Note that this number may change when changing the %%contbarnb value.
	In the case %%contbarnb is not set, the repeat sequences may be
	identified by a letter after the measure number as "10b" (second
	repeat sequence).

	<time numerator> and <time denominator> define the fraction of a
	whole note which gives the time offset of the symbol in the selected
	measure.
	The numerator is numbered starting from 0. The value 0 (default)
	selects the measure bar. To select the first note of a measure,
	set the fraction to a small value as "5:1/64".

  <regular expression>
	  Such expressions are a subset of Perl regular expressions:
		^	match beginning of the string
		$	match end of the string
		|	start an alternate sequence
		()	grouping
		.	match any character
		[...]	match any character from set
		[^...]	match any character but ones from set
		\s	match whitespace
		\S	match non-whitespace
		\d	match decimal digit
		+	match one or more times
		*	match zero or more times
		?	match zero or once
		\xDD	match byte with hex value 0xDD
		\meta	match one of the meta character: ^$().[*+?\

  Examples:
	- transpose up by two semitones all the voices which names contain
	  the characters "Bb":

		abcm2ps tune1.abc --voice Bb --transpose 2 --voice end

	- display only the 2 first measures of the tunes which titles start
	  with "Gloria":

		abcm2ps tune2.abc --tune 'T:Gloria' --clip -3 --tune end

	  (note: "-3" means "include the bar starting the measure 3")
abcm2ps-7.8.13/front.c0000644000175000017500000005061312457404635012546 0ustar  jefjef/*
 * ABC front-end parser
 *
 * This file is part of abcm2ps.
 *
 * Copyright (C) 2011-2014 Jean-François Moine (http://moinejf.free.fr)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#ifdef WIN32
#define strncasecmp strnicmp
#endif

#include "front.h"
#include "slre.h"

static unsigned char *dst;
static int offset, size, keep_comments;
static void (*include_f)(unsigned char *fn);
static unsigned char *selection;
static int latin, skip;
static char prefix[4] = {'%'};

/*
 * translation table from the ABC draft version 2
 *	` grave
 *	' acute
 *	^ circumflex
 *	, cedilla
 *	" umlaut
 *	~ tilde
 *	o ring
 *	= macron or stroke
 *	/ slash
 *	; ogonek
 *	v caron
 *	u breve
 *	: long Hungarian umlaut
 *	. dot / dotless
 * else, ligatures
 *	ae ss ng
 */
/* !! each table item is 3 bytes: 1 char, 1 UTF-8 char on 2 bytes */
static unsigned char grave[] = "AÀEÈIÌOÒUÙaàeèiìoòuù";
static unsigned char acute[] = "AÁEÉIÍOÓUÚYÝaáeéiíoóuúyýSŚZŹsśzźRŔLĹCĆNŃrŕlĺcćnń";
static unsigned char circumflex[] = "AÂEÊIÎOÔUÛaâeêiîoôuûHĤJĴhĥjĵCĈGĜSŜcĉgĝsŝ";
static unsigned char cedilla[] = "CÇcçSŞsşTŢtţRŖLĻGĢrŗlļgģNŅKĶnņkķ";
static unsigned char umlaut[] = "AÄEËIÏOÖUÜYŸaäeëiïoöuüyÿ";
static unsigned char tilde[] = "AÃNÑOÕaãnñoõIĨiĩUŨuũ";
static unsigned char ring[] = "AÅaåUŮuů";
static unsigned char macron[] = "AĀDĐEĒHĦIĪOŌTŦUŪaādđeēhħiīoōtŧuū"; /* and stroke! */
static unsigned char slash[] = "OØoøDĐdđLŁlł";
static unsigned char ogonek[] = "AĄEĘIĮUŲaąeęiįuų";
static unsigned char caron[] = "LĽSŠTŤZŽlľsštťzžCČEĚDĎNŇRŘcčeědďnňrř";
static unsigned char breve[] = "AĂaăEĔeĕGĞgğIĬiĭOŎoŏUŬuŭ";
static unsigned char hungumlaut[] = "OŐUŰoőuű";
static unsigned char dot[] = "ZŻzżIİiıCĊcċGĠgġEĖeė";
/* the items of this table are 4 bytes long */
static unsigned char ligature[] = "AAÅaaåAEÆaeæccçcCÇDHÐdhðngŋOEŒoeœssßTHÞthþ";

/* latin conversion tables - range 0xa0 .. 0xff */
static unsigned char latin2[] = {
	" Ą˘Ł¤ĽŚ§¨ŠŞŤŹ­ŽŻ°ą˛ł´ľśˇ¸šşťź˝žż"
	"ŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢß"
	"ŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙"
};
static unsigned char latin3[] = {
	" Ħ˘£¤  Ĥ§¨İŞĞĴ­  ݰħ²³´µĥ·¸ışğĵ½  ż"
	"ÀÁÂ  ÄĊĈÇÈÉÊËÌÍÎÏ  ÑÒÓÔĠÖ×ĜÙÚÛÜŬŜß"
	"àáâ  äċĉçèéêëìíîï  ñòóôġö÷ĝùúûüŭŝ˙"
};
static unsigned char latin4[] = {
	" ĄĸŖ¤Ĩϧ¨ŠĒĢŦ­Ž¯°ą˛ŗ´ĩšēģŧŊžŋ"
	"ĀÁÂÃÄÅÆĮČÉĘËĖÍÎĪĐŅŌĶÔÕÖרŲÚÛÜŨŪß"
	"āáâãäåæįčéęëėíîīđņōķôõö÷øųúûüũū˙"
};
static unsigned char latin5[] = {
	" ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿"
	"ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖרÙÚÛÜİŞß"
	"àáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ"
};
static unsigned char latin6[] = {
	" ĄĒĢĪĨͧĻĐŠŦŽ­ŪŊ°ąēģīĩķ·ļđšŧž―ūŋ"
	"ĀÁÂÃÄÅÆĮČÉĘËĖÍÎÏÐŅŌÓÔÕÖŨØŲÚÛÜÝÞß"
	"āáâãäåæįčéęëėíîïðņōóôõöũøųúûüýþĸ"
};
static unsigned char *latin_tb[5] = {
	latin2, latin3, latin4, latin5, latin6
};

/* add text to the output buffer */
static void txt_add(unsigned char *s, int sz)
{
	if (skip)
		return;
	if (offset + sz > size) {
		size = (offset + sz + 8191) / 8192 * 8192;
		if (dst == 0)
			dst = malloc(size);
		else
			dst = realloc(dst, size);
		if (dst == 0) {
			fprintf(stderr, "Out of memory - abort\n");
			exit(EXIT_FAILURE);
		}
	}
	memcpy(dst + offset, s, sz);
	offset += sz;
}

/* add text to the output buffer translating
 * the escape sequences and the non utf-8 characters */
static void txt_add_cnv(unsigned char *s, int sz)
{
	unsigned char *p, c, tmp[4];

	p = s;
	while (sz > 0) {
		if (*p == '\\') {
			if (sz >= 4			/* \ooo */
			 && p[1] >= '0' && p[1] <= '3'
			 && p[2] >= '0' && p[2] <= '7'
			 && p[3] >= '0' && p[3] <= '7') {
				c = ((p[1] - '0') << 6)
					+ ((p[2] - '0') << 3)
					+ p[3] - '0';
				if (p != s)
					txt_add(s, (int) (p - s));
				p += 4;
				s = p;
				sz -= 4;
				switch (c) {	/* convert the accidentals */
				case 0x01:
				case 0x81:
					tmp[0] = 0xe2;
					tmp[1] = 0x99;
					tmp[2] = 0xaf;
					txt_add(tmp, 3);
					continue;
				case 0x02:
				case 0x82:
					tmp[0] = 0xe2;
					tmp[1] = 0x99;
					tmp[2] = 0xad;
					txt_add(tmp, 3);
					continue;
				case 0x03:
				case 0x83:
					tmp[0] = 0xe2;
					tmp[1] = 0x99;
					tmp[2] = 0xae;
					txt_add(tmp, 3);
					continue;
				case 0x04:
				case 0x84:
					tmp[0] = 0xf0;
					tmp[1] = 0x9d;
					tmp[2] = 0x84;
					tmp[3] = 0xaa;
					txt_add(tmp, 4);
					continue;
				case 0x05:
				case 0x85:
					tmp[0] = 0xf0;
					tmp[1] = 0x9d;
					tmp[2] = 0x84;
					tmp[3] = 0xab;
					txt_add(tmp, 4);
					continue;
				}
				if (c >= 0x80 && latin > 0)
					goto latin;
				tmp[0] = c;
				txt_add(tmp, 1);
				continue;
			}
			if (sz >= 6		/* \uxxxx */
			 && p[1] == 'u'
			 && isxdigit(p[2])
			 && isxdigit(p[3])
			 && isxdigit(p[4])
			 && isxdigit(p[5])) {
				int i, v;

				v = 0;
				for (i = 2; i < 6; i++) {
					v <<= 4;
					c = p[i];
					if (c <= '9')
						v += c - '0';
					else if (c <= 'F')
						v += c - 'A' + 10;
					else
						v += c - 'a' + 10;
				}
				if (p != s)
					txt_add(s, (int) (p - s));
				p += 6;
				sz -= 6;
				if ((v & 0xdc00) == 0xd800	/* surrogates */
				 && sz >= 6
				 && *p == '\\'
				 && p[1] == 'u'
				 && isxdigit(p[2])
				 && isxdigit(p[3])
				 && isxdigit(p[4])
				 && isxdigit(p[5])) {
					int v2;

					v = (v - 0xd7c0) << 10;
					v2 = 0;
					for (i = 2; i < 6; i++) {
						v2 <<= 4;
						c = p[i];
						if (c <= '9')
							v2 += c - '0';
						else if (c <= 'F')
							v2 += c - 'A' + 10;
						else
							v2 += c - 'a' + 10;
					}
					v2 -= 0xdc00;
					v += v2;
					p += 6;
					sz -= 6;
				}
//fixme: else error
				s = p;
				if (v < 0x80) {	/* convert to UTF-8 */
					tmp[0] = v;
					i = 1;
				} else if (v < 0x800) {
					tmp[0] = 0xc0 | (v >> 6);
					tmp[1] = 0x80 | (v & 0x3f);
					i = 2;
				} else if (v < 0x10000) {
					tmp[0] = 0xe0 | (v >> 12);
					tmp[1] = 0x80 | ((v >> 6) & 0x3f);
					tmp[2] = 0x80 | (v & 0x3f);
					i = 3;
				} else {
					tmp[0] = 0xf0 | (v >> 18);
					tmp[1] = 0x80 | ((v >> 12) & 0x3f);
					tmp[2] = 0x80 | ((v >> 6) & 0x3f);
					tmp[3] = 0x80 | (v & 0x3f);
					i = 4;
				}
				txt_add(tmp, i);
				continue;
			}
			if (sz >= 3) {
				unsigned char *q;

				switch (p[1]) {
				case '`': q = grave; break;
				case '\'': q = acute; break;
				case '^': q = circumflex; break;
				case ',': q = cedilla; break;
				case '"': q = umlaut; break;
				case '~': q = tilde; break;
				case 'o': q = ring; break;
				case '=': q = macron; break;
				case '/': q = slash; break;
				case ';': q = ogonek; break;
				case 'v': q = caron; break;
				case 'u': q = breve; break;
				case 'H':
				case ':': q = hungumlaut; break;
				case '.': q = dot; break;
				default:
					q = ligature;
					do {
						if (*q == p[1]
						 && q[1] == p[2])
							break;
						q += 4;
					} while (*q != '\0');
					if (*q != '\0') {
						if (p != s)
							txt_add(s, (int) (p - s));
						txt_add(q + 2, 2);
						p += 3;
						sz -= 3;
						s = p;
						continue;
					}
					q = 0;
					break;
				}
				if (q != 0) {
					do {
						if (*q == p[2])
							break;
						q += 3;
					} while (*q != '\0');
					if (*q != '\0') {
						if (p != s)
							txt_add(s, (int) (p - s));
						txt_add(q + 1, 2);
						p += 3;
						sz -= 3;
						s = p;
						continue;
					}
				}
			}
			p++;
			sz--;
			if (*p == '\\') {
				p++;
				sz--;
			}
			continue;
		}
		if (*p >= 0x80 && latin > 0) {
			if (p != s)
				txt_add(s, (int) (p - s));
			c = *p++;
			s = p;
			sz--;
latin:
			if (c < 0xa0 || latin == 1) {
				tmp[0] = 0xc0 | ((c >> 6) & 0x03);
				tmp[1] = 0x80 | (c & 0x3f);
				txt_add(tmp, 2);
			} else {
				unsigned char *q;

				q = latin_tb[latin - 2];
				txt_add(q + (c - 0xa0) * 2, 2);
			}
			continue;
		}
		p++;
		sz--;
	}
	if (p != s)
		txt_add(s, (int) (p - s));
}

static const unsigned char eol_chars[2] = {'\r', '\n'};
static void eol0(void)
{
	txt_add((unsigned char *) &eol_chars[1], 1);
}
static void eol1(void)
{
	txt_add((unsigned char *) &eol_chars[0], 1);
}
static void eol2(void)
{
	txt_add((unsigned char *) &eol_chars[0], 2);
}
static void (*eol_tb[3])(void) = {eol0, eol1, eol2};
static void (*txt_add_eol)(void);

/* add the line number */
static void add_lnum(int nline)
{
	unsigned char tmp[16];

	sprintf((char *) tmp, "%%@%d", nline);
	txt_add(tmp, strlen((char *) tmp));
}

/* check if the current tune is to be selected */
static int tune_select(unsigned char *s)
{
	struct slre slre;
	unsigned char *p, *sel;

	/* if there is a list of tune indexes,
	 * check the tune index */
	sel = selection;
	if (isdigit(*sel)) {
		int tune_number, cur_sel, end_sel, n;

		/* get the tune number ('s' points to X:) */
		tune_number = strtod((char *) s + 2, 0);

		/* search it in the number list */
		for (;;) {
			if (sscanf((char *) sel, "%d%n", &cur_sel, &n) != 1)
				break;
			sel += n;
			if (*sel == '-') {
				sel++;
				if (sscanf((char *) sel, "%d%n", &end_sel, &n) != 1)
					end_sel = ~0u >> 1;
				else
					sel += n;
			} else {
				end_sel = cur_sel;
			}
			if (tune_number >= cur_sel && tune_number <= end_sel)
				return 1;
			if (*sel != ',')
				break;
			sel++;
		}
		if (*sel == '\0')
			return 0;
	}

	for (p = s + 2; ; p++) {
		switch (*p) {
		case '\0':
			return 0;
		default:
			continue;
		case '\n':
		case '\r':
			break;
		}
		if (p[1] != 'K' || p[2] != ':')
			continue;
		p += 3;
		while (*p != '\n' && *p != '\r' && *p != '\0')
			p++;
		if (*p != '\0')
			p++;		/* keep the EOL for RE with '\s' */
		break;
	}
//fixme: should compile only one time
	if (!slre_compile(&slre, (char *) sel))
		return 0;
	return slre_match(&slre, (char *) s, p - s, 0);
}

/* -- init the front-end -- */
void front_init(int edit,	/* for edition - keep comments */
		int eol,	/* 0: \n, 1: \r, 2: \r\n */
		void include_api(unsigned char *fn))
{
	keep_comments = edit;
	txt_add_eol = eol_tb[eol];
	include_f = include_api;
	dst = 0;
	offset = 0;
	size = 0;
}

/* -- front end parser -- */
unsigned char *frontend(unsigned char *s,
			int ftype)
{
	unsigned char *p, *q, c, *begin_end;
	int i, l, state, str_cnv_p, histo, end_len, nline;
	char prefix_sav[4];
	int latin_sav = 0;		/* have C compiler hppy */

	begin_end = 0;
	end_len = 0;
	histo = 0;
	state = 0;
	nline = 0;
	if (dst != 0)			/* if continuation */
		offset--;		/* restart before the EOL */

	add_lnum(0);
	txt_add_eol();

	/* if unknown encoding, check if latin1 or utf-8 */
	if (ftype == FE_ABC
	 && strncmp((char *) s, "%abc-2.1", 8) == 0) {
		latin = 0;
	} else {
		for (p = s; *p != '\0'; p++) {
			c = *p;
			if (c == '\\') {
				if (p[1] == '2') {
					if (p[2] == '0')	/* accidental */
						continue;
					c = 0x80;
				} else if (p[1] == '3') {
					c = 0xc0;
				}
			}
			if (c < 0x80)
				continue;
//fixme: problem when two octal values give a UTF-8 character
			if (c >= 0xc0) {
				if ((p[1] & 0xc0) == 0x80
				 || (p[1] == '\\' && p[2] == '2')) {
					latin = 0;
					break;
				 }
			}
			latin = 1;
			break;
		}
	}

	/* scan the file */
	skip = 0;
	while (*s != '\0') {

		/* get a line */
		str_cnv_p = 0;
		p = s;
		while (*p != '\0'
		    && *p != '\r'
		    && *p != '\n') {
			if (*p == '\\'
			 || (latin > 0 && *p >= 0x80))
				str_cnv_p = 1;
			p++;
		}
		l = p - s;
		if (*p != '\0') {
			p++;
			if (p[-1] == '\r' && *p == '\n')	/* (DOS) */
				p++;
		}
		nline++;

		if (begin_end) {
			if (ftype == FE_FMT) {
				if (strncmp((char *) s, "end", 3) == 0
				 && strncmp((char *) s + 3,
						(char *) begin_end, end_len) == 0) {
					begin_end = 0;
					txt_add((unsigned char *) "%%", 2);
					goto next;
				}
				if (*s == '%')
					goto next_eol;		/* comment */
				goto next;
			}
			if (*s == '%' && strchr(prefix, s[1])) {
				q = s + 2;
				while (*q == ' ' || *q == '\t')
					q++;
				if (strncmp((char *) q, "end", 3) == 0
				 && strncmp((char *) q + 3,
						(char *) begin_end, end_len) == 0) {
					begin_end = 0;
					txt_add((unsigned char *) "%%", 2);
					l -= q - s;
					s = q;
					goto next;
				}
			}
			if (strncmp("ps", (char *) begin_end, end_len) == 0) {
				if (*s == '%')
					goto next_eol;		/* comment */
			} else {
				if (*s == '%' && strchr(prefix, s[1])) {
					s += 2;
					l -= 2;
				}
			}
			goto next;
		}

		if (skip) {
			if (l != 0)
				goto next_eol;
			skip = 0;
			txt_add_eol();
			add_lnum(nline);
		}

		if (l == 0) {			/* empty line */
			switch (state) {
			case 1:
				fprintf(stderr,
					"Line %d: Empty line in tune header - K:C added\n",
					nline);
				txt_add((unsigned char *) "K:C", 3);
				txt_add_eol();
				txt_add_eol();
				add_lnum(nline);
				/* fall thru */
			case 2:
				state = 0;
				strcpy(prefix, prefix_sav);
				latin = latin_sav;
				break;
			}
			goto next_eol;
		}
		if (histo) {			/* H: continuation */
			if ((s[1] == ':'
			  && (isalpha(*s) || *s == '+'))
			 || (*s == '%' && strchr(prefix, s[1]))) {
				histo = 0;
			} else {
				txt_add((unsigned char *) "H:", 2);
				goto next;
			}
		}

		/* special case 'space* "%" ' */
		if (*s == ' ' || *s == '\t') {
			q = s;
			do {
				q++;
			} while (*q == ' ' || *q == '\t');
			if (*q == '%') {
				if (keep_comments)
					txt_add(q, l - (q - s));
				else if (state != 0)	/* inside tune */
					txt_add(q, 1);	/* keep a single '%' */
				goto next_eol;
			}
		}

		if (ftype == FE_PS) {
			if (*s == '%')
				goto next_eol;
			goto next;
		}

		/* treat the pseudo-comments */
		if (ftype == FE_FMT) {
			if (*s == '%')
				goto next_eol;
			goto pscom;
		}
		if (*s == 'I' && s[1] == ':') {
			s += 2;
			l -= 2;
			while (*s == ' ' || *s == '\t') {
				s++;
				l--;
			}
			txt_add((unsigned char *) "%%", 2);
			goto info;
		}
		if (*s == '%') {
			if (!strchr(prefix, s[1])) {		/* pure comment */
				if (keep_comments
				 || strncmp((char *) s, "%abc", 4) == 0)
					txt_add(s, l);
				else if (state != 0)		/* if not global */
					txt_add(s, 1);
				goto next_eol;
			}
			s += 2;
			l -= 2;
			if (strncmp((char *) s, "abcm2ps ", 8) == 0) {
				s += 8;
				l -= 8;
				while (*s == ' ' || *s == '\t') {
					s++;
					l--;
				}
				for (i = 0; i < sizeof prefix - 1; i++) {
					if (*s == ' ' || *s == '\t'
					 || --l < 0)
						break;
					prefix[i] = *s++;
				}
				if (i == 0)
					prefix[i++] = '%';
				prefix[i] = '\0';
				txt_add((unsigned char *) "%", 1);
				goto next_eol;
			}
pscom:
			while (*s == ' ' || *s == '\t') {
				s++;
				l--;
			}
			txt_add((unsigned char *) "%%", 2);
			if (strncmp((char *) s, "begin", 5) == 0) {
				q = begin_end = s + 5;
				while (!isspace(*q))
					q++;
				end_len = q - begin_end;
				goto next;
			}
info:
			if (strncmp((char *) s, "encoding ", 9) == 0
			 || strncmp((char *) s, "abc-charset ", 12) == 0) {
				if (*s == 'e')
					q = s + 9;
				else
					q = s + 12;
				while (*q == ' ' || *q == '\t')
					q++;
				if (strncasecmp((char *) q, "latin", 5) == 0) {
					q += 5;
				} else if (strncasecmp((char *) q, "iso-8859-", 9) == 0) {
					q += 9;
				} else if (strncasecmp((char *) q, "utf-8", 5) == 0
					|| strncasecmp((char *) q, "native", 6) == 0) {
					latin = 0;
					goto next;
				} else if (!isdigit(*q)) {
					goto next;	/* unknown charset */
				}
				switch (*q) {
				case '1':
					if (q[1] == '0')
						latin = 6;
					else
						latin = 1;
					break;
				case '2': latin = 2; break;
				case '3': latin = 3; break;
				case '4': latin = 4; break;
				case '5':
					if (q[-1] != '-')
						latin = 5;
					break;
				case '6':
					if (q[-1] != '-')
						latin = 6;
					break;
/*fixme: iso-8859 5..8 not treated */
				case '9': latin = 5; break;
				}
				goto next;
			}
			if (include_f
			 && (strncmp((char *) s, "format ", 7) == 0
			  || strncmp((char *) s, "abc-include ", 12) == 0)) {
				unsigned char sep;
				int skip_sav;

				if (*s == 'f')
					s += 7;
				else
					s += 12;
				while (*s == ' ' || *s == '\t')
					s++;
				q = s;
				while (*q != '\0'
				    && *q != '%'
				    && *q != '\n'
				    && *q != '\r')
					q++;
				while (q[-1] == ' ')
					q--;
				sep = *q;
				*q = '\0';
				offset--;		/* remove one % */
				dst[offset - 1] = '\0';	/* replace the other % by EOS */
				skip_sav = skip;
				include_f(s);
				skip = skip_sav;
				offset--;		/* remove the EOS */
				*q = sep;
				add_lnum(nline);
				goto next_eol;
			}
			if (strncmp((char *) s, "select", 6) == 0) {
				s += 6;
				if (*s == '\n') {	/* select clear */
					q = s;
				} else if (*s != ' ' && *s != '\t') {
					goto next;
				} else {
					while (*s == ' ' || *s == '\t')
						s++;
					q = s;
					while (*q != '\0'
					    && *q != '%'
					    && *q != '\n'
					    && *q != '\r')
						q++;
					while (q[-1] == ' ' || q[-1] == '\t')
						q--;
					if (strncmp((char *) q - 5, " lock", 5) == 0)
						q -= 5;
				}
				if (selection) {
					free(selection);
					selection = NULL;
				}
				if (q != s) {
					unsigned char sep;

					sep = *q;
					*q = '\0';
					selection = (unsigned char *) strdup((char *) s);
					*q = sep;
				}
				offset--;		/* remove one % */
				goto next_eol;
			}
			goto next;
		}
		if (begin_end)
			goto next;

		/* treat the information fields */
		if (s[1] == ':' && (isalpha(*s) || *s == '+')) {
			c = *s;
			switch (c) {
			case 'I':		/* treat as a pseudo-comment */
				s += 2;
				l -= 2;
				goto pscom;
			case 'X':
				switch (state) {
				case 1:
					fprintf(stderr,
						"Line %d: X: found in tune header - K:C added\n",
						nline);
					txt_add((unsigned char *) "K:C", 3);
					txt_add_eol();
					txt_add_eol();	/* empty line */
					add_lnum(nline);
					txt_add_eol();
					break;
				case 2:
					txt_add_eol();	/* no empty line - minor error */
					break;
				}
				if (selection)
					skip = !tune_select(s);
				if (!skip) {
					state = 1;
					strcpy(prefix_sav, prefix);
					latin_sav = latin;
				}
				break;
			case 'U':
				break;
			case 'H':
				histo = 1;
				break;
			default:
				if (state == 0			/* if global */
				 && strchr("dKPQsVWw", *s) != 0) {
					if (keep_comments)
						txt_add(s, l);
					goto next_eol;		/* ignore */
				}
				if (*s == 'K')
					state = 2;
				break;
			}
			txt_add(s, 2);
			s += 2;
			l -= 2;
			while (*s == ' ' || *s == '\t') {
				s++;
				l--;
			}
			str_cnv_p = 1;
			goto next;
		}

		/* treat the music lines */
		if (state == 0)				/* if not in tune */
			goto next_eol;			/* ignore */
		if (!str_cnv_p)
			goto next;
		str_cnv_p = 0;
		for (i = 0; i < l; i++) {
			if (s[i] != '"')
				continue;
			i++;
			txt_add(s, i);
			s += i;
			l -= i;
			for (i = 0; i < l; i++) {
				if (s[i] == '"' && s[i - 1] != '\\')
					break;
			}
//fixme: if i == l, no end of string - error
			txt_add_cnv(s, i);
			s += i;
			l -= i;
			i = 0;
		}
next:
		if (str_cnv_p)
			txt_add_cnv(s, l);
		else
			txt_add(s, l);
next_eol:
		txt_add_eol();
		s = p;
	}
	txt_add((unsigned char *) "", 1);			/* EOS */
	return dst;
}

#ifdef MAIN
static void usage(void)
{
	printf("ABC frontend\n"
		"Usage: abcmfe file\n");
	exit(EXIT_SUCCESS);
}

int main(int argc, char **argv)
{
	char *p, *file, *result;
	char *fname = 0;
	FILE *fin;
	size_t fsize;

	while (--argc > 0) {
		argv++;
		p = *argv;
		if (*p == '-')
			continue;
		fname = p;
	}
	if (fname == 0)
		usage();

	if ((fin = fopen(fname, "rb")) == 0) {
		fprintf(stderr, "Cannot open '%s'\n", fname);
		exit(EXIT_FAILURE);
	}

	if (fseek(fin, 0L, SEEK_END) < 0) {
		fclose(fin);
		return 0;
	}
	fsize = ftell(fin);
	rewind(fin);
	if ((file = malloc(fsize + 2)) == 0) {
		fclose(fin);
		return 0;
	}

	if (fread(file, 1, fsize, fin) != fsize) {
		fclose(fin);
		free(file);
		return 0;
	}
	file[fsize] = '\0';
	fclose(fin);

	front_init(0, 0, 0);
	result = (char *) frontend((unsigned char *) file, 0);

	fputs(result, stdout);
	return EXIT_SUCCESS;
}
#endif
abcm2ps-7.8.13/front.h0000644000175000017500000000035112314506337012537 0ustar  jefjef/* declarations for front.c */

/* file types */
#define FE_ABC 0
#define FE_FMT 1
#define FE_PS 2
void front_init(int edit,
		int eol,
		void include_api(unsigned char *fn));
unsigned char *frontend(unsigned char *s,
			int ftype);
abcm2ps-7.8.13/glyph.c0000644000175000017500000002074012353471443012533 0ustar  jefjef/*
 * utf-8 to glyph translation
 *
 * This file is part of abcm2ps.
 *
 * Copyright (C) 2011-2014 Jean-François Moine (http://moinejf.free.fr)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "abc2ps.h"

static char *c2[64] = {
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	"nbspace",	"exclamdown",	"cent",		"sterling",
	"currency",	"yen",		"brokenbar",	"section",
	"dieresis",	"copyright",	"ordfeminine",	"guillemotleft",
	"logicalnot",	"sfthyphen",	"registered",	"macron",
	"degree",	"plusminus",	"twosuperior",	"threesuperior",
	"acute",	"mu",		"paragraph",	"periodcentered",
	"cedilla",	"onesuperior",	"ordmasculine",	"guillemotright",
	"onequarter",	"onehalf",	"threequarters","questiondown"
};
static char *c3[64] = {
	"Agrave",	"Aacute",	"Acircumflex",	"Atilde",
	"Adieresis",	"Aring",	"AE",		"Ccedilla",
	"Egrave",	"Eacute",	"Ecircumflex",	"Edieresis",
	"Igrave",	"Iacute",	"Icircumflex",	"Idieresis",
	"Eth",		"Ntilde",	"Ograve",	"Oacute",
	"Ocircumflex",	"Otilde",	"Odieresis",	"multiply",
	"Oslash",	"Ugrave",	"Uacute",	"Ucircumflex",
	"Udieresis",	"Yacute",	"Thorn",	"germandbls",
	"agrave",	"aacute",	"acircumflex",	"atilde",
	"adieresis",	"aring",	"ae",		"ccedilla",
	"egrave",	"eacute",	"ecircumflex",	"edieresis",
	"igrave",	"iacute",	"icircumflex",	"idieresis",
	"eth",		"ntilde",	"ograve",	"oacute",
	"ocircumflex",	"otilde",	"odieresis",	"divide",
	"oslash",	"ugrave",	"uacute",	"ucircumflex",
	"udieresis",	"yacute",	"thorn",	"ydieresis"
};
static char *c4[64] = {
	"Amacron",	"amacron",	"Abreve",	"abreve",
	"Aogonek",	"aogonek",	"Cacute",	"cacute",
	"Ccircumflex",	"ccircumflex",	"Cdotaccent",	"cdotaccent",
	"Ccaron",	"ccaron",	"Dcaron",	"dcaron",
	"Dcroat",	"dcroat",	"Emacron",	"emacron",
	"Ebreve",	"ebreve",	"Edotaccent",	"edotaccent",
	"Eogonek",	"eogonek",	"Ecaron",	"ecaron",
	"Gcircumflex",	"gcircumflex",	"Gbreve",	"gbreve",
	"Gdotaccent",	"gdotaccent",	"Gcommaaccent",	"gcommaaccent",
	"Hcircumflex",	"hcircumflex",	"Hbar",		"hbar",
	"Itilde",	"itilde",	"Imacron",	"imacron",
	"Ibreve",	"ibreve",	"Iogonek",	"iogonek",
	"Idotaccent",	"dotlessi",	"IJ",		"ij",
	"Jcircumflex",	"jcircumflex",	"Kcedilla",	"kcedilla",
	"kgreenlandic",	"Lacute",	"lacute",	"Lcedilla",
	"lcedilla",	"Lcaron",	"lcaron",	"Ldot"
};
static char *c5[64] = {
	"ldot",		"Lslash",	"lslash",	"Nacute",
	"nacute",	"Ncedilla",	"ncedilla",	"tmacron",
	"ncaron",	"napostrophe",	"Eng",		"eng",
	"Omacron",	"omacron",	"Obreve",	"obreve",
	"Ohungarumlaut","ohungarumlaut","OE",		"oe",
	"Racute",	"racute",	"Rcommaaccent",	"rcommaaccent",
	"Rcaron",	"rcaron",	"Sacute",	"sacute",
	"Scircumflex",	"scircumflex",	"Scedilla",	"scedilla",
	"Scaron",	"scaron",	"Tcedilla",	"tcedilla",
	"Tcaron",	"tcaron",	"Tbar",		"tbar",
	"Utilde",	"utilde",	"Umacron",	"umacron",
	"Ubreve",	"ubreve",	"Uring",	"uring",
	"Uhungarumlaut","uhungarumlaut","Uogonek",	"uogonek",
	"Wcircumflex",	"wcircumflex",	"Ycircumflex",	"ycircumflex",
	"Ydieresis",	"Zacute",	"zacute",	"Zdotaccent",
	"zdotaccent",	"Zcaron",	"zcaron",	"longs"
};

static char *ce[64] = {
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, "Delta", NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};

static char *e299[64] = {
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
//	NULL, NULL, NULL, NULL, NULL, "uni266D", "uni266E", "uni266F",
	NULL, NULL, NULL, NULL, NULL, "flat", "natural", "sharp",
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static char **e2[64] = {
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, e299, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};

static char *f09d84[64] = {
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
//	NULL, NULL, "u1D12A", "u1D12B",
	NULL, NULL, "double_sharp", "double_flat",
					NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static char **f09d[64] = {
	NULL, NULL, NULL, NULL, f09d84, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static char ***f0[64] = {
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, f09d, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};

/* 1st character - c2..ff */
static char **utf_1[62] = {
			c2,	c3,	c4,	c5,	NULL,	NULL,
	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	ce,	NULL,
	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,
	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,
	NULL,	NULL,	(char **) e2, NULL,
					NULL,	NULL,	NULL,	NULL,
	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,
	(char **) f0, NULL, NULL, NULL,	NULL,	NULL,	NULL,	NULL,
	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,
};

/* output the glyph of a utf-8 character */
/* return the next character */
char *glyph_out(char *p)
{
	int i1, i2, i3, i4;
	char **g, *q;

	g = NULL;
	i1 = (unsigned char) *p++ - 0xc2;
	i2 = (unsigned char) *p++ - 0x80;
	if (i1 >= 0xe0 - 0xc2) {
		i3 = (unsigned char) *p++ - 0x80;
		if (i1 >= 0xf0 - 0xc2)
			i4 = (unsigned char) *p++ - 0x80;
		else
			i4 = -1;
	} else {
		i3 = -1;
		i4 = -1;
	}
	if (i1 >= 0 && i2 >= 0) {
		g = (char **) utf_1[i1];
		if (g) {
			g = (char **) g[i2];
			if (i3 >= 0 && g) {
				g = (char **) g[i3];
				if (i4 >= 0 && g)
					g = (char **) g[i4];
			}
		}
		q = (char *) g;
	} else {
		q = NULL;
	}
	if (!q)
		q = ".notdef";
	a2b("/%s", q);
	return p;
}

/* -- add a glyph -- */
/* %%glyph hex_value glyph_name */
void glyph_add(char *p)
{
	int val, i1, i2, i3, i4;
	char **g, **g1, *q;

	val = strtoul(p, &q, 16);	/* unicode value */
	if (val < 0x80
	 || val >= 0x100000) {
		 error(1, 0, "Bad unicode value '%s'", p);
		 return;
	}
	p = q;
	while (isspace(*p))
		p++;
	i3 = i4 = -1;
	if (val < 0x0400) {
		i1 = (val >> 6) - 2;
		i2 = val & 0x3f;
	} else if (val < 0x10000) {
		i1 = (val >> 12) + 0x20 - 2;
		i2 = (val >> 6) & 0x3f;
		i3 = val & 0x3f;
	} else {
		i1 = (val >> 18) + 0x30 - 2;
		i2 = (val >> 12) & 0x3f;
		i3 = (val >> 6) & 0x3f;
		i4 = val & 0x3f;
	}
	g1 = utf_1[i1];
	if (!g1) {
		g1 = calloc(64, sizeof(char **));
		utf_1[i1] = g1;
	}
	if (i3 < 0) {
		g1[i2] = strdup(p);
		return;
	}
	g = (char **) g1[i2];
	if (!g) {
		g = calloc(64, sizeof(char **));
		g1[i2] = (char *) g;
	}
	if (i4 < 0) {
		g[i3] = strdup(p);
		return;
	}
	g1 = (char **) g[i3];
	if (!g1) {
		g1 = calloc(64, sizeof(char **));
		g[i3] = (char *) g1;
	}
	g1[i4] = strdup(p);
}
abcm2ps-7.8.13/install.sh0000755000175000017500000001124407234347534013255 0ustar  jefjef#! /bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
#


# set DOITPROG to echo to test this script

# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"


# put in absolute paths if you don't have them in your path; or use env. vars.

mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"

tranformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""

while [ x"$1" != x ]; do
    case $1 in
	-c) instcmd="$cpprog"
	    shift
	    continue;;

	-d) dir_arg=true
	    shift
	    continue;;

	-m) chmodcmd="$chmodprog $2"
	    shift
	    shift
	    continue;;

	-o) chowncmd="$chownprog $2"
	    shift
	    shift
	    continue;;

	-g) chgrpcmd="$chgrpprog $2"
	    shift
	    shift
	    continue;;

	-s) stripcmd="$stripprog"
	    shift
	    continue;;

	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
	    shift
	    continue;;

	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
	    shift
	    continue;;

	*)  if [ x"$src" = x ]
	    then
		src=$1
	    else
		# this colon is to work around a 386BSD /bin/sh bug
		:
		dst=$1
	    fi
	    shift
	    continue;;
    esac
done

if [ x"$src" = x ]
then
	echo "install:	no input file specified"
	exit 1
else
	true
fi

if [ x"$dir_arg" != x ]; then
	dst=$src
	src=""
	
	if [ -d $dst ]; then
		instcmd=:
	else
		instcmd=mkdir
	fi
else

# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad 
# if $src (and thus $dsttmp) contains '*'.

	if [ -f $src -o -d $src ]
	then
		true
	else
		echo "install:  $src does not exist"
		exit 1
	fi
	
	if [ x"$dst" = x ]
	then
		echo "install:	no destination specified"
		exit 1
	else
		true
	fi

# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic

	if [ -d $dst ]
	then
		dst="$dst"/`basename $src`
	else
		true
	fi
fi

## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`

# Make sure that the destination directory exists.
#  this part is taken from Noah Friedman's mkinstalldirs script

# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='	
'
IFS="${IFS-${defaultIFS}}"

oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"

pathcomp=''

while [ $# -ne 0 ] ; do
	pathcomp="${pathcomp}${1}"
	shift

	if [ ! -d "${pathcomp}" ] ;
        then
		$mkdirprog "${pathcomp}"
	else
		true
	fi

	pathcomp="${pathcomp}/"
done
fi

if [ x"$dir_arg" != x ]
then
	$doit $instcmd $dst &&

	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else

# If we're going to rename the final executable, determine the name now.

	if [ x"$transformarg" = x ] 
	then
		dstfile=`basename $dst`
	else
		dstfile=`basename $dst $transformbasename | 
			sed $transformarg`$transformbasename
	fi

# don't allow the sed command to completely eliminate the filename

	if [ x"$dstfile" = x ] 
	then
		dstfile=`basename $dst`
	else
		true
	fi

# Make a temp file name in the proper directory.

	dsttmp=$dstdir/#inst.$$#

# Move or copy the file name to the temp name

	$doit $instcmd $src $dsttmp &&

	trap "rm -f ${dsttmp}" 0 &&

# and set any options; do chmod last to preserve setuid bits

# If any of these fail, we abort the whole thing.  If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.

	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&

# Now rename the file to the real destination.

	$doit $rmcmd -f $dstdir/$dstfile &&
	$doit $mvcmd $dsttmp $dstdir/$dstfile 

fi &&


exit 0
abcm2ps-7.8.13/landscape.fmt0000644000175000017500000000022307337660472013710 0ustar  jefjef
% format for wide output in landscape mode

   landscape 1

   titleleft  yes
   titlefont Palatino-Bold 22
   composerspace 0.6cm
   staffsep 60
abcm2ps-7.8.13/music.c0000644000175000017500000033451012436546572012543 0ustar  jefjef/*
 * Music generator.
 *
 * This file is part of abcm2ps.
 *
 * Copyright (C) 1998-2014 Jean-François Moine
 * Adapted from abc2ps, Copyright (C) 1996,1997 Michael Methfessel
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 */

#include <string.h>
#include <ctype.h>

#include "abc2ps.h"

struct SYMBOL *tsnext;		/* next line when cut */
float realwidth;		/* real staff width while generating */

static int insert_meter;	/* insert time signature (1) and indent 1st line (2) */
static float alfa_last, beta_last;	/* for last short short line.. */

#define AT_LEAST(a,b)  do { float tmp = b; if(a<tmp) a=tmp; } while (0)

/* width of notes indexed by log2(note_length) */
float space_tb[NFLAGS_SZ] = {
	7, 10, 14.15, 20, 28.3,
	40,				/* crotchet */
	56.6, 80, 113, 150
};
static int smallest_duration;

/* upper and lower space needed by rests */
static struct {
	char u, l;
} rest_sp[NFLAGS_SZ] = {
	{16, 31},
	{16, 25},
	{16, 19},
	{10, 19},
	{10, 13},
	{10, 13},			/* crotchet */
	{7, 7},
	{10, 4},
	{10, 7},
	{10, 13}
};

/* -- decide whether to shift heads to other side of stem on chords -- */
/* also position accidentals to avoid too much overlap */
/* this routine is called only once per tune */
static void set_head_directions(struct SYMBOL *s)
{
	int i, i1, i2, i3, n, sig, d, shift;
	int p1, p2, p3, ps, m, nac;
	float dx, dx1, dx2, dx3, shmin, shmax;
	unsigned char ax_tb[MAXHD], ac_tb[MAXHD];
	static float dx_tb[4] = {
		9, 10, 12, 14
	};
	/* distance for no overlap - index: [prev acc][cur acc] */
	static char dt_tb[4][4] = {
		{5, 5, 5, 5},		/* dble sharp */
		{5, 6, 6, 6},		/* sharp */
		{5, 6, 5, 6},		/* natural */
		{5, 5, 5, 5}		/* flat */
	};

	/* special case when single note */
	n = s->nhd;
	if (n == 0) {
		if (s->as.u.note.accs[0] != 0) {
			dx = dx_tb[s->head];
			if (s->as.flags & ABC_F_GRACE)
				dx *= 0.7;
			s->shac[0] = dx;
		}
		return;
	}

	/* set the head shifts */
	dx = dx_tb[s->head] * 0.78;
	if (s->as.flags & ABC_F_GRACE)
		dx *= 0.5;
	i1 = 1;
	i2 = n + 1;
	sig = s->stem;
	if (sig < 0) {
		dx = -dx;
		i1 = n - 1;
		i2 = -1;
	}
	shift = 0;
	nac = 0;
	for (i = i1; i != i2; i += sig) {
		d = s->pits[i] - s->pits[i - sig];
		if (d == 0 && shift) {		/* unison on shifted note */
			s->shhd[i] = s->shhd[i - sig] + dx;
			continue;
		}
		if (d < 0)
			d = -d;
		if (d > 3 || (d >= 2 && s->head < H_SQUARE)) {
			shift = 0;
		} else {
			shift = !shift;
			if (shift) {
				s->shhd[i] = dx;
				nac++;
			}
		}
	}
	if (nac != 0 && sig > 0)
		s->xmx = dx;		/* shift the dots */

	/* set the accidental shifts */
	nac = 0;
	for (i = n; i >= 0; i--) {	/* from top to bottom */
		if ((i1 = s->as.u.note.accs[i]) != 0) {
			ax_tb[nac++] = i;
			if (i1 & 0xf8)
				i1 = A_SH;	/* micro-tone same as sharp */
			else if (i1 == A_DF)
				i1 = A_FT;	/* dble flat same as flat */
			else if (i1 == A_DS)
				i1 = 0;		/* (max -> 0) */
			ac_tb[i] = i1;
		}
	}
	if (nac == 0)			/* no accidental */
		return;
	dx = dx_tb[s->head];
	m = n;
	p2 = i2 = 0;			/* (compiler warning) */
	dx2 = 0;
	ps = 255;
	for (i = 0; i < nac; i++) {
		i1 = ax_tb[i];
		p1 = s->pits[i1];
		if (m >= 0) {		/* see if any head shift */
			if (ps - s->pits[i1] >= 4) {
				for (m--; m >= 0; m--) {
					if (s->shhd[m] < 0) {
						ps = s->pits[m];
						break;
					}
				}
			}
		}
		dx1 = dx;
		if (m >= 0 && s->shhd[m] < 0
		 && ps - p1 < 4 && ps - p1 > -4)
			dx1 -= s->shhd[m];
		if (s->as.flags & ABC_F_GRACE)
			dx1 *= 0.7;
		if (i == 0) {	/* no other shift for the 1st accidental */
			s->shac[i1] = dx1;
			i2 = i1;
			p2 = p1;
			dx2 = dx1;
			continue;
		}
		d = dt_tb[ac_tb[i2]][ac_tb[i1]];
		if (p2 - p1 < d) {		/* if possible overlap */
			if (s->as.u.note.accs[i1] & 0xf8) { /* microtonal */
				shmin = 6.5;
				shmax = 9;
			} else {
				shmin = 4.5;
				shmax = 7;
			}
			if (s->as.flags & ABC_F_GRACE) {
				shmin *= 0.7;
				shmax *= 0.7;
			}
			if (i >= 2) {
				i3 = ax_tb[i - 2];
				p3 = s->pits[i3];
				d = dt_tb[ac_tb[i3]][ac_tb[i1]];
				if (p3 - p1 < d) {
					dx3 = s->shac[i3];
					if (p3 - p1 >= 4
					 && (ac_tb[i3] != A_SH || ac_tb[i1] != A_SH)) {
						if (dx1 > dx3 - shmin && dx1
									< dx3 + shmin)
							dx1 = dx3 + shmin;
					} else {
						if (dx1 > dx3 - shmax && dx1
									< dx3 + shmax)
							dx1 = dx3 + shmax;
					}
				}
			}
			if (p2 - p1 >= 4
			 && (ac_tb[i2] != A_SH || ac_tb[i1] != A_SH)) {
				if (dx1 > dx2 - shmin && dx1 < dx2 + shmin) {
					if (dx1 + shmin < dx2 + shmin)
						s->shac[i2] = dx1 + shmin;
					else
						dx1 = dx2 + shmin;
				}
			} else {
				if (dx1 > dx2 - shmax && dx1 < dx2 + shmax) {
					if (dx1 + shmax < dx2 + shmax)
						s->shac[i2] = dx1 + shmax;
					else
						dx1 = dx2 + shmax;
				}
			}
		}
		s->shac[i1] = dx1;
		i2 = i1;
		p2 = p1;
		dx2 = dx1;
	}
}

/* -- unlink a symbol -- */
void unlksym(struct SYMBOL *s)
{
	if (!s->next) {
		if (s->extra) {
			s->type = FMTCHG;
			s->u = -1;
			return;
		}
	} else {
		s->next->prev = s->prev;
//		if (s->type == NOTEREST
//		 && !(s->sflags & S_BEAM_END))
//			s->next->sflags |= S_BEAM_ST;
		if (s->extra) {
			struct SYMBOL *g;

			g = s->next->extra;
			if (!g) {
				s->next->extra = s->extra;
			} else {
				for (; g->next; g = g->next)
					;
				g->next = s->extra;
			}
		}
	}
	if (s->prev)
		s->prev->next = s->next;
	else
		voice_tb[s->voice].sym = s->next;
	if (s->ts_next) {
		if ((s->sflags & S_SEQST)
		 && !(s->ts_next->sflags & S_SEQST)) {
			s->ts_next->sflags |= S_SEQST;
			s->ts_next->shrink = s->shrink;
			s->ts_next->space = s->space;
		}
		s->ts_next->ts_prev = s->ts_prev;
	}
	if (s->ts_prev)
		s->ts_prev->ts_next = s->ts_next;
	if (tsfirst == s)
		tsfirst = s->ts_next;
	if (tsnext == s)
		tsnext = s->ts_next;
}

/* -- check if voice combine may occur -- */
static int may_combine(struct SYMBOL *s)
{
	struct SYMBOL *s2;
	int nhd2;

	s2 = s->ts_next;
	if (!s2 || s2->type != NOTEREST)
		return 0;
	if (s2->voice == s->voice
	 || s2->staff != s->staff
	 || s2->time != s->time
	 || s2->dur != s->dur)
		return 0;
	if (cfmt.combinevoices <= 0
	 && s2->as.type != s->as.type)
		return 0;
	if (s2->as.u.note.dc.n != 0) {
		if (s2->as.u.note.dc.h != s2->as.u.note.dc.h
		 || memcmp(&s->as.u.note.dc, &s2->as.u.note.dc,
				sizeof s->as.u.note.dc) != 0)
			return 0;
	}
	if (s->gch && s2->gch)
		return 0;
	if (s->as.type == ABC_T_REST) {
		if (s2->as.type  == ABC_T_REST
		 && (s->as.flags & ABC_F_INVIS) && !(s2->as.flags & ABC_F_INVIS))
			return 0;
		return 1;
	}
	if (s2->ly
	 || (s2->sflags & (S_SL1 | S_SL2))
	 || s2->as.u.note.slur_st != 0
	 || s2->as.u.note.slur_end != 0)
		return 0;
	if ((s2->sflags ^ s->sflags) & (S_BEAM_ST | S_BEAM_END))
		return 0;
	nhd2 = s2->nhd;
	if (s->nhd + nhd2 + 1 >= MAXHD)
		return 0;
	if (cfmt.combinevoices <= 1 && s->pits[0] <= s2->pits[nhd2] + 1)
		return 0;
	return 1;
}

/* -- combine 2 voices -- */
static void do_combine(struct SYMBOL *s)
{
	struct SYMBOL *s2;
	int nhd, nhd2, type;

again:
	nhd = s->nhd;
	s2 = s->ts_next;
	nhd2 = s2->nhd;
	s2->extra = NULL;
	if (s->as.type != s2->as.type) {	/* if note and rest */
		if (s2->as.type == ABC_T_REST)
			goto delsym2;
#if 1
		s2 = s;
		s = s2->ts_next;
		goto delsym2;
#else
		s->as.type = ABC_T_NOTE;	/* copy the note into the rest */
		nhd = -1;
//		s->pits[0] = 127;
		s->sflags |= s2->sflags & (S_BEAM_BR1 | S_BEAM_BR2 |
					S_OTHER_HEAD |
					S_TREM1 | S_TREM2 | S_XSTEM |
					S_BEAM_ON |
					S_SL1 | S_SL2 | S_TI1 |
					S_PERC | S_RBSTOP |
					S_FEATHERED_BEAM |
					S_SHIFTUNISON_1 | S_SHIFTUNISON_2);
#endif
	} else if (s->as.type == ABC_T_REST) {
		if ((s->as.flags & ABC_F_INVIS)
		 && !(s2->as.flags & ABC_F_INVIS))
			s->as.flags &= ~ABC_F_INVIS;
		goto delsym2;
	}

	/* combine the voices */
	memcpy(&s->pits[nhd + 1], s2->pits,
		sizeof s->pits[0] * (nhd2 + 1));
#define COMBINEV(f)\
    memcpy(&s->as.u.note.f[nhd + 1], s2->as.u.note.f,\
	sizeof s->as.u.note.f[0] * (nhd2 + 1));\

		COMBINEV(pits);
		COMBINEV(lens);
		COMBINEV(accs);
		COMBINEV(sl1);
		COMBINEV(sl2);
		COMBINEV(ti1);
		COMBINEV(decs);
#undef COMBINEV
	nhd += nhd2 + 1;
	s->nhd = nhd;
	sort_pitch(s, 1);		/* sort the notes by pitch */
	s->ymx = 3 * (s->pits[nhd] - 18) + 4;
	s->ymn = 3 * (s->pits[0] - 18) - 4;
	s->yav = (s->ymx + s->ymn) / 2;

	/* force the tie directions */
	type = s->as.u.note.ti1[0];
	if ((type & 0x03) == SL_AUTO)
		s->as.u.note.ti1[0] = SL_BELOW | (type & ~SL_DOTTED);
	type = s->as.u.note.ti1[nhd];
	if ((type & 0x03) == SL_AUTO)
		s->as.u.note.ti1[nhd] = SL_ABOVE | (type & ~SL_DOTTED);
delsym2:
	if (s2->as.text && !s->as.text) {
		s->as.text = s2->as.text;
		s->gch = s2->gch;
	}
	unlksym(s2);			/* remove the next symbol */

	/* there may be more voices */
	if (!(s->sflags & S_IN_TUPLET) && may_combine(s))
		goto again;
}

/* -- try to combine voices */
static void combine_voices(void)
{
	struct SYMBOL *s, *s2, *g;
	int i, r;

	for (s = tsfirst; s->ts_next; s = s->ts_next) {
		if (cfmt.combinevoices == 0
		 && s->as.type != ABC_T_REST)
			continue;
		if (s->sflags & S_IN_TUPLET) {
			g = s->extra;
			if (!g)
				continue;	/* tuplet already treated */
			r = 0;
			for ( ; g; g = g->next) {
				if (g->type == TUPLET
				 && g->as.u.tuplet.r_plet > r)
					r = g->as.u.tuplet.r_plet;
			}
			if (r == 0)
				continue;
			i = r;
			for (s2 = s; s2; s2 = s2->next) {
				if (!s2->ts_next)
					break;
				if (s2->type != NOTEREST)
					continue;
				if (!may_combine(s2))
					break;
				if (--i <= 0)
					break;
			}
			if (i > 0)
				continue;
			for (s2 = s; /*s2*/; s2 = s2->next) {
				if (s2->type != NOTEREST)
					continue;
				do_combine(s2);
				if (--r <= 0)
					break;
			}
			continue;
			
		}
		if (s->type != NOTEREST)
			continue;

		if (s->as.type == ABC_T_NOTE) {
			if (!(s->sflags & S_BEAM_ST))
				continue;
			if (s->sflags & S_BEAM_END) {
				if (may_combine(s))
					do_combine(s);
				continue;
			}
		} else {
			if (may_combine(s))
				do_combine(s);
			continue;
		}
		s2 = s;
		for (;;) {
			if (!may_combine(s2)) {
				s2 = 0;
				break;
			}
#if 1
//fixme: may have rests in beam
			if (s2->sflags & S_BEAM_END)
#else
			if (s2->as.type == ABC_T_REST
			 || (s2->sflags & S_BEAM_END))
#endif
				break;
			do {
				s2 = s2->next;
			} while (s2->type != NOTEREST);
		}
		if (!s2)
			continue;
		s2 = s;
		for (;;) {
			do_combine(s2);
#if 1
//fixme: may have rests in beam
			if (s2->sflags & S_BEAM_END)
#else
			if (s2->as.type == ABC_T_REST
			 || (s2->sflags & S_BEAM_END))
#endif
				break;
			do {
				s2 = s2->next;
			} while (s2->type != NOTEREST);
		}
	}
}

/* -- insert a clef change (treble or bass) before a symbol -- */
static void insert_clef(struct SYMBOL *s,
			int clef_type)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *new_s;

	/* don't insert the clef between two bars */
	if (s->type == BAR && s->prev && s->prev->type == BAR
/*	 && s->time == s->prev->time */
			)
		s = s->prev;

	/* create the symbol */
	p_voice = &voice_tb[s->voice];
	p_voice->last_sym = s->prev;
	if (!p_voice->last_sym)
		p_voice->sym = NULL;
	p_voice->time = s->time;
	new_s = sym_add(p_voice, CLEF);
	new_s->next = s;
	s->prev = new_s;

	new_s->as.u.clef.type = clef_type;
	new_s->as.u.clef.line = clef_type == TREBLE ? 2 : 4;
	new_s->staff = s->staff;
	new_s->u = 1;			/* small clef */
	new_s->sflags &= ~S_SECOND;

	/* link in time */
	while (!(s->sflags & S_SEQST))
		s = s->ts_prev;
	if (s->type == STAVES) {
		s = s->ts_next;
		s->sflags |= S_SEQST;
	} else if (!s->ts_prev || s->ts_prev->type != CLEF) {
		new_s->sflags |= S_SEQST;
	}
	new_s->ts_prev = s->ts_prev;
	if (new_s->ts_prev)
		new_s->ts_prev->ts_next = new_s;
	else
		tsfirst = new_s;
	new_s->ts_next = s;
	s->ts_prev = new_s;
}

/* -- define the clef for a staff with no explicit clef -- */
/* this function is called only once for the whole tune */
static void set_clef(int staff)
{
	struct SYSTEM *sy;
	struct SYMBOL *s, *last_chg;
	int clef_type, min, max, time;

	/* get the max and min pitches */
	min = max = 16;			/* 'C' */
	for (s = tsfirst; s; s = s->ts_next) {
		if (s->staff != staff || s->as.type != ABC_T_NOTE)
			continue;
		if (s->pits[0] < min)
			min = s->pits[0];
		else if (s->pits[s->nhd] > max)
			max = s->pits[s->nhd];
	}

	sy = cursys;
	if (min >= 13)			/* all upper than 'G,' --> treble clef */
		return;
	if (max <= 19) {		/* all lower than 'F' --> bass clef */
		do {
			sy->staff[staff].clef.type = BASS;
			sy->staff[staff].clef.line = 4;
			sy = sy->next;
		} while (sy);
		return;
	}

	/* set clef changes */
	clef_type = TREBLE;
	sy->staff[staff].clef.type = clef_type;
	sy->staff[staff].clef.line = clef_type == TREBLE ? 2 : 4;
	last_chg = NULL;
	for (s = tsfirst; s; s = s->ts_next) {
		struct SYMBOL *s2, *s3, *s4;

		if (s->staff != staff || s->as.type != ABC_T_NOTE) {
			if (s->type == STAVES) {
				sy = sy->next;	/* keep the starting clef */
				sy->staff[staff].clef.type = clef_type;
				sy->staff[staff].clef.line = clef_type == TREBLE ? 2 : 4;
				last_chg = s;
			}
			continue;
		}

		/* check if a clef change may occur */
		time = s->time;
		if (clef_type == TREBLE) {
			if (s->pits[0] > 12		/* F, */
			 || s->pits[s->nhd] > 20)	/* G */
				continue;
			s2 = s->ts_prev;
			if (s2
			 && s2->time == time
			 && s2->staff == staff
			 && s2->as.type == ABC_T_NOTE
			 && s2->pits[0] >= 19)	/* F */
				continue;
			s2 = s->ts_next;
			if (s2
			 && s2->staff == staff
			 && s2->time == time
			 && s2->as.type == ABC_T_NOTE
			 && s2->pits[0] >= 19)	/* F */
				continue;
		} else {
			if (s->pits[0] < 12		/* F, */
			 || s->pits[s->nhd] < 20)	/* G */
				continue;
			s2 = s->ts_prev;
			if (s2
			 && s2->time == time
			 && s2->staff == staff
			 && s2->as.type == ABC_T_NOTE
			 && s2->pits[0] <= 13)	/* G, */
				continue;
			s2 = s->ts_next;
			if (s2
			 && s2->staff == staff
			 && s2->time == time
			 && s2->as.type == ABC_T_NOTE
			 && s2->pits[0] <= 13)	/* G, */
				continue;
		}

		/* go backwards and search where to insert a clef change */
#if 1 /*fixme:test*/
		s3 = s;
#else
		if (!voice_tb[s->voice].second
		 && voice_tb[s->voice].staff == staff)
			s3 = s;
		else
			s3 = NULL;
#endif
#if 0
		time = !last_chg ? -1 : last_chg->time;
#endif
		for (s2 = s->ts_prev; s2 != last_chg; s2 = s2->ts_prev) {
#if 0
			if (s2->time <= time)
				break;
#endif
			if (s2->staff != staff)
				continue;
			if (s2->type == BAR
			 && s2->voice == s->voice) {
#if 0 /*fixme:test*/
				if (voice_tb[s2->voice].second
				 || voice_tb[s2->voice].staff != staff)
					continue;
#endif
				s3 = s2;
				break;
			}
#if 1
			if (s2->as.type != ABC_T_NOTE)
#else
			if (s2->type != NOTEREST)	/* neither note nor rest */
#endif
				continue;

			/* exit loop if a clef change cannot occur */
//			if (s2->as.type == ABC_T_NOTE) {
				if (clef_type == TREBLE) {
					if (s2->pits[0] >= 19)		/* F */
						break;
				} else {
					if (s2->pits[s2->nhd] <= 13)	/* G, */
						break;
				}
//			}

#if 1 /*fixme:test*/
			/* have a 2nd choice on beam start */
#if 1
#if 1
#if 1 /* double clef pb - clef change on 2nd voice */
			if ((s2->sflags & S_BEAM_ST)
			 && !voice_tb[s2->voice].second)
#else
			if (s2->sflags & S_BEAM_ST)
#endif
				s3 = s2;
#else
			if ((s3->sflags & S_BEAM_ST) == 0)
				s3 = s2;
#endif
#else
			if ((s2->sflags & S_BEAM_ST)
			 || (s3->sflags & S_BEAM_ST) == 0)
				s3 = s2;
#endif
#else
			/* have a 2nd choice if word starts on the main voice */
			if (!voice_tb[s2->voice].second
			 && voice_tb[s2->voice].staff == staff) {
				if ((s2->sflags & S_BEAM_ST)
				 || !s3
				 || !(s3->sflags & S_BEAM_ST))
					s3 = s2;
			}
#endif
		}
		s2 = last_chg;
		last_chg = s;

		/* if first change, see if any note before */
		if (!s2 || s2->type == STAVES) {
#if 1 /*fixme:test*/
			s4 = s3;
#else
			if ((s4 = s3) == NULL)
				s4 = s;
#endif
			for (s4 = s4->ts_prev; s4 != s2; s4 = s4->ts_prev) {
				if (s4->staff != staff)
					continue;
				if (s4->as.type == ABC_T_NOTE)
					break;
			}

			/* if no note, change the clef of the staff */
			if (s4 == s2) {
				if (clef_type == TREBLE) {
					clef_type = BASS;
					sy->staff[staff].clef.line = 4;
				} else {
					clef_type = TREBLE;
					sy->staff[staff].clef.line = 2;
				}
				sy->staff[staff].clef.type = clef_type;
				continue;
			}
		}

		/* no change possible if no insert point */
#if 1 /*fixme:test*/
		    else if (s3->time == s2->time)
#else
		if (!s3 || s3 == s2)
#endif
			continue;

		/* insert a clef change */
		clef_type = clef_type == TREBLE ? BASS : TREBLE;
		insert_clef(s3, clef_type);
		s3->prev->staff = staff;
	}

	/* keep the starting clef of the next staff systems */
	while ((sy = sy->next) != 0) {
		sy->staff[staff].clef.type = clef_type;
		sy->staff[staff].clef.line = clef_type == TREBLE ? 2 : 4;
	}
}

/* -- set the staff of the floating voices -- */
/* this function is called only once per tune */
static void set_float(void)
{
	struct VOICE_S *p_voice;
	int staff, staff_chg;
	struct SYMBOL *s, *s1;

	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		if (!p_voice->floating)
			continue;
		staff_chg = 0;
		staff = p_voice->staff;
		for (s = p_voice->sym; s; s = s->next) {
			signed char up, down;

			if (s->as.type != ABC_T_NOTE) {
				if (staff_chg)
					s->staff++;
				continue;
			}
			if (!(s->sflags & S_FLOATING)) {
				staff_chg = 0;
				continue;
			}
			if (s->pits[0] >= 19) {		/* F */
				staff_chg = 0;
				continue;
			}
			if (s->pits[s->nhd] <= 12) {	/* F, */
				staff_chg = 1;
				s->staff++;
				continue;
			}
			up = 127;
			for (s1 = s->ts_prev; s1; s1 = s1->ts_prev) {
				if (s1->staff != staff
				 || s1->voice == s->voice)
					break;
#if 1
/*fixme:test again*/
				if (s1->as.type == ABC_T_NOTE)
#endif
				    if (s1->pits[0] < up)
					up = s1->pits[0];
			}
			if (up == 127) {
				if (staff_chg)
					s->staff++;
				continue;
			}
			if (s->pits[s->nhd] > up - 3) {
				staff_chg = 0;
				continue;
			}
			down = -127;
			for (s1 = s->ts_next; s1; s1 = s1->ts_next) {
				if (s1->staff != staff + 1
				 || s1->voice == s->voice)
					break;
#if 1
/*fixme:test again*/
				if (s1->as.type == ABC_T_NOTE)
#endif
				    if (s1->pits[s1->nhd] > down)
					down = s1->pits[s1->nhd];
			}
			if (down == -127) {
				if (staff_chg)
					s->staff++;
				continue;
			}
			if (s->pits[0] < down + 3) {
				staff_chg = 1;
				s->staff++;
				continue;
			}
			up -= s->pits[s->nhd];
			down = s->pits[0] - down;
			if (!staff_chg) {
				if (up < down + 3)
					continue;
				staff_chg = 1;
			} else {
				if (up < down - 3) {
					staff_chg = 0;
					continue;
				}
			}
			s->staff++;
		}
	}
}

/* -- set the x offset of the grace notes -- */
static float set_graceoffs(struct SYMBOL *s)
{
	struct SYMBOL *g, *next;
	int m;
	float xx, gspleft, gspinside, gspright;

	gspleft = (cfmt.gracespace >> 16) * 0.1;
	gspinside = ((cfmt.gracespace >> 8) & 0xff) * 0.1;
	gspright = (cfmt.gracespace & 0xff) * 0.1;
	xx = 0;
	for (g = s->extra; ; g = g->next) {
		if (g->type == NOTEREST)
			break;
	}
	g->sflags |= S_BEAM_ST;
	for ( ; ; g = g->next) {
		if (g->type != NOTEREST) {
			if (!g->next)
				break;
			continue;
		}
		set_head_directions(g);
		for (m = g->nhd; m >= 0; m--) {
			if (g->as.u.note.accs[m]) {
				xx += 5;
				if (g->as.u.note.accs[m] & 0xf8)
					xx += 2;
				break;
			}
		}
		g->x = xx;

		if (g->nflags <= 0)
			g->sflags |= S_BEAM_ST | S_BEAM_END;
		next = g->next;
		if (!next) {
			g->sflags |= S_BEAM_END;
			break;
		}
		if (next->nflags <= 0 || (next->as.flags & ABC_F_SPACE))
			g->sflags |= S_BEAM_END;
		if (g->sflags & S_BEAM_END) {
			next->sflags |= S_BEAM_ST;
			xx += gspinside / 4;
		}
		if (g->nflags <= 0)
			xx += gspinside / 4;
		if (g->y > next->y + 8)
			xx -= 1.5;
		xx += gspinside;
	}

	xx += gspleft + gspright;
	next = s->next;
	if (next
	 && next->as.type == ABC_T_NOTE) {	/* if before a note */
		if (g->y >= (float) (3 * (next->pits[next->nhd] - 18)))
			xx -= 1;		/* above, a bit closer */
		else if ((g->sflags & S_BEAM_ST)
		      && g->y < (float) (3 * (next->pits[0] - 18) - 7))
			xx += 2;	/* below with flag, a bit further */
	}

	/* return the whole width */
	return xx;
}

/* -- compute the width needed by the guitar chords / annotations -- */
static float gchord_width(struct SYMBOL *s,
			  float wlnote,
			  float wlw)
{
	struct SYMBOL *s2;
	struct gch *gch;
	int ix;
	float lspc, rspc, w;

	lspc = rspc = 0;
	for (ix = 0, gch = s->gch; ix < MAXGCH; ix++, gch++) {
		if (gch->type == '\0')
			break;
		switch (gch->type) {
		default: {		/* default = above */
			float wl;

			wl = -gch->x;
			if (wl > lspc)
				lspc = wl;
			w = gch->w - wl;
			if (w > rspc)
				rspc = w;
			break;
		    }
		case '<':		/* left */
			w = gch->w + wlnote;
			if (w > lspc)
				lspc = w;
			break;
		case '>':		/* right */
			w = gch->w + s->wr;
			if (w > rspc)
				rspc = w;
			break;
		}
	}
#if 1
	/* adjust width for no clash */
	s2 = s->prev;
	if (s2 && s2->gch) {
		for (s2 = s->ts_prev; ; s2 = s2->ts_prev) {
			if (s2 == s->prev) {
				AT_LEAST(wlw, lspc);
				break;
			}
			if (s2->sflags & S_SEQST)
				lspc -= s2->shrink;
		}
	}
	s2 = s->next;
	if (s2 && s2->gch) {
		for (s2 = s->ts_next; ; s2 = s2->ts_next) {
			if (s2 == s->next) {
				AT_LEAST(s->wr, rspc);
				break;
			}
			if (s2->sflags & S_SEQST)
				rspc -= 8;
		}
	}
#else
	s2 = s->prev;
	if (s2 && s2->gch) {
		AT_LEAST(wlw, lspc);
/*fixme: pb when ">" only*/
	for (s2 = s->next; s2; s2 = s2->next) {
		switch (s2->type) {
		default:
			continue;
		case NOTEREST:
		case SPACE:
		case BAR:
			if (s2->as.text)
				AT_LEAST(s->wr, rspc);
			break;
		}
		break;
	}
#endif
	return wlw;
}

/* -- set the width needed by the lyrics -- */
static float ly_width(struct SYMBOL *s, float wlw)
{
	struct SYMBOL *k;
	struct lyrics *ly = s->ly;
	struct lyl *lyl;
	struct tblt_s *tblt;
	float align, xx, w;
	int i;

	/* check if the lyrics contain tablature definition */
	for (i = 0; i < 2; i++) {
		tblt = voice_tb[s->voice].tblts[i];
		if (!tblt)
			continue;
		if (tblt->pitch == 0) {		/* yes, no width */
			for (i = 0; i < MAXLY; i++) {
				if ((lyl = ly->lyl[i]) == 0)
					continue;
				lyl->s = 0;
			}
			return wlw;
		}
	}

	align = 0;
	for (i = 0; i < MAXLY; i++) {
		float swfac, shift;
		char *p;

		if ((lyl = ly->lyl[i]) == 0)
			continue;
		p = lyl->t;
		w = lyl->w;
		swfac = lyl->f->swfac;
		xx = w + 2 * cwid(' ') * swfac;
		if (isdigit((unsigned char) *p)
		 || p[1] == ':'
//		 || p[1] == '(' || p[1] == ')') {
		 || *p == '(' || *p == ')') {
			float sz;

//			if (p[1] == '(')
			if (*p == '(') {
//				sz = cwid((unsigned char) p[1]);
				sz = cwid((unsigned char) *p);
			} else {
				sz = 0;
				while (*p != '\0') {
/*fixme: KO when '\ooo'*/
					if (*p == '\\') {
						p++;
						continue;
					}
					sz += cwid((unsigned char) *p);
					if (*p == ' ')
						break;
					p++;
				}
			}
			sz *= swfac;
			shift = (w - sz + 2 * cwid(' ') * swfac)
				* VOCPRE;
			if (shift > 20)
				shift = 20;
			shift += sz;
			if (isdigit((unsigned char) lyl->t[0])) {
				if (shift > align)
					align = shift;
			}
		} else if (*p == LY_HYPH || *p == LY_UNDER) {
			shift = 0;
		} else {
			shift = xx * VOCPRE;
			if (shift > 20)
				shift = 20;
		}
		lyl->s = shift;
		AT_LEAST(wlw, shift);
		xx -= shift;
		shift = 2 * cwid(' ') * swfac;
		for (k = s->next; k; k = k->next) {
			switch (k->type) {
			case NOTEREST:
				if (!k->ly
				 || !k->ly->lyl[i])
					xx -= 9;
				else if (k->ly->lyl[i]->t[0] == LY_HYPH
				      || k->ly->lyl[i]->t[0] == LY_UNDER)
					xx -= shift;
				else
					break;
				if (xx <= 0)
					break;
				continue;
			case CLEF:
			case TIMESIG:
			case KEYSIG:
				xx -= 10;
				continue;
			default:
				xx -= 5;
				break;
			}
			break;
		}
		if (xx > s->wr)
			s->wr = xx;
		}
	if (align > 0) {
		for (i = 0; i < MAXLY; i++) {
			if ((lyl = ly->lyl[i]) == 0)
				continue;
			if (isdigit((unsigned char) lyl->t[0]))
				lyl->s = align;
		}
	}
	return wlw;
}

/* -- set the width of a symbol -- */
/* This routine sets the minimal left and right widths wl,wr
 * so that successive symbols are still separated when
 * no extra glue is put between them */
static void set_width(struct SYMBOL *s)
{
	struct SYMBOL *s2;
	int i, m;
	float xx, w, wlnote, wlw;

	switch (s->type) {
	case NOTEREST:

		/* set the note widths */
		switch (s->head) {
		case H_SQUARE:
			wlnote = 8;
			break;
		case H_OVAL:
			wlnote = 6;
			break;
		case H_EMPTY:
			wlnote = 5;
			break;
		default:
			wlnote = 4.5;
			break;
		}
		s->wr = wlnote;

		/* room for shifted heads and accidental signs */
		if (s->xmx > 0)
			s->wr += s->xmx + 4;
		s2 = s->prev;
		if (s2) {
			switch (s2->type) {
			case BAR:
			case CLEF:
			case KEYSIG:
			case TIMESIG:
				wlnote += 3;
				break;
			}
		}
		for (m = 0; m <= s->nhd; m++) {
			xx = s->shhd[m];
			if (xx < 0)
				AT_LEAST(wlnote, -xx + 5);
			if (s->as.u.note.accs[m]) {
				AT_LEAST(wlnote, s->shac[m]
					 + ((s->as.u.note.accs[m] & 0xf8)
					    ? 6.5 : 4.5));
			}
		}
		if (s2) {
			switch (s2->type) {
			case BAR:
			case CLEF:
			case KEYSIG:
			case TIMESIG:
				wlnote -= 3;
				break;
			}
		}

		/* room for the decorations */
		if (s->as.u.note.dc.n > 0)
			wlnote += deco_width(s);

		/* space for flag if stem goes up on standalone note */
		if ((s->sflags & (S_BEAM_ST | S_BEAM_END)) == (S_BEAM_ST | S_BEAM_END)
		 && s->stem > 0 && s->nflags > 0)
			AT_LEAST(s->wr, s->xmx + 12);

		/* leave room for dots and set their offset */
		if (s->dots > 0) {

			/* standalone with up-stem and flags */
			if (s->nflags > 0 && s->stem > 0
			 && s->xmx == 0 && s->doty == 0
			 && (s->sflags & (S_BEAM_ST | S_BEAM_END))
					== (S_BEAM_ST | S_BEAM_END)
			 && !(s->y % 6))
				s->xmx = DOTSHIFT;
			switch (s->head) {
			case H_SQUARE:
			case H_OVAL:
				s->xmx += 2;
				break;
			case H_EMPTY:
				s->xmx += 1;
				break;
			}
			AT_LEAST(s->wr, s->xmx + 12);
			if (s->dots >= 2)
				s->wr += 3.5 * (s->dots - 1);
		}

		/* if a tremolo on 2 notes, have space for the small beam(s) */
		if ((s->sflags & (S_TREM2 | S_BEAM_END)) == (S_TREM2 | S_BEAM_END))
			AT_LEAST(wlnote, 20);

		wlw = wlnote;

		if (s2) {
			switch (s2->type) {
			case NOTEREST:	/* extra space when up stem - down stem */
				if (s2->as.type == ABC_T_REST)
					break;
				if (s2->stem > 0 && s->stem < 0)
					AT_LEAST(wlw, 7);

				/* make sure helper lines don't overlap */
				if ((s->y > 27 && s2->y > 27)
				 || (s->y < -3 && s2->y < -3))
					AT_LEAST(wlw, 6);

				/* have ties wide enough */
				if (s2->sflags & S_TI1)
					AT_LEAST(wlw, 14);
				break;
			case CLEF:		/* extra space at start of line */
				if ((s2->sflags & S_SECOND)
				 || s2->u)
					break;
				wlw += 8;
				break;
			case KEYSIG:
/*			case TIMESIG:	*/
				wlw += 4;
				break;
			}
		}

		/* leave room for guitar chord */
		if (s->gch)
			wlw = gchord_width(s, wlnote, wlw);

		/* leave room for vocals under note */
		/* related to draw_lyrics() */
		if (s->ly)
			wlw = ly_width(s, wlw);
#if 0
/*new fixme*/
		/* reduce right space when not followed by a note */
		for (k = s->next; k; k = k->next) {
			switch (k->type) {
			default:
				s->pr *= 0.8;
				break;
			case NOTEREST:
				break;
			}
			break;
		}

		/* squeeze notes a bit if big jump in pitch */
		if (s->as.type == ABC_T_NOTE
		 && s2->as.type == ABC_T_NOTE) {
			int dy;
			float fac;

			dy = s->y - s2->y;
			if (dy < 0)
				dy =- dy;
			fac = 1. - 0.01 * dy;
			if (fac < 0.9)
				fac = 0.9;
			s2->pr *= fac;

			/* stretch / shrink when opposite stem directions */
			if (s2->stem > 0 && s->stem < 0)
				s2->pr *= 1.1;
			else if (s2->stem < 0 && s->stem > 0)
				s2->pr *= 0.9;
		}
#endif
		/* if preceeded by a grace note sequence, adjust */
		if (s2 && s2->type == GRACE)
			s->wl = wlnote - 4.5;
		else
			s->wl = wlw;
		break;
	case SPACE:
		if (s->as.u.note.lens[1] < 0)
			xx = 10;
		else
			xx = (float) s->as.u.note.lens[1] * 0.5;
		s->wr = xx;
		if (s->gch)
			xx = gchord_width(s, xx, xx);
		if (s->as.u.note.dc.n > 0)
			xx += deco_width(s);
		s->wl = xx;
		break;
	case BAR:
		if (s->sflags & S_NOREPBRA)
			break;
		if (!(s->as.flags & ABC_F_INVIS)) {
			int bar_type;

			w = 5;
			bar_type = s->as.u.bar.type;
			switch (bar_type) {
			case (B_BAR << 4) + B_COL:
			case (B_COL << 4) + B_BAR:
				w += 3 + 3 + 5;
				break;
			case (B_COL << 4) + B_COL:
				w += 5 + 3 + 3 + 3 + 5;
				break;
			default:
				for (;;) {
					switch (bar_type & 0x07) {
					case B_OBRA:
					case B_CBRA:
						w += 3;
						break;
					case B_COL:
						w += 2;
						break;
					}
					bar_type >>= 4;
					if (bar_type == 0)
						break;
					w += 3;
				}
				break;
			}
			s->wl = w;
			if (s->next
			 && s->next->type != TIMESIG)
				s->wr = 8;
			else
				s->wr = 5;
			s->shhd[0] = (w - 5) * -0.5;
		}
		if (s->as.u.bar.dc.n > 0)
			s->wl += deco_width(s);

		/* have room for the repeat numbers / guitar chord */
		if (s->gch
		 && strlen(s->as.text) < 4)
			s->wl = gchord_width(s, s->wl, s->wl);
		break;
	case CLEF:
		/* shift the clef to the left - see draw_symbols() */
		if (!(s->as.flags & ABC_F_INVIS)) {
			s->wl = 12 + 10;
			s->wr = (s->u ? 10 : 12) - 10;
		}
		break;
	case KEYSIG: {
		int n1, n2, esp;

		s->wl = 3;
		esp = 4;
		if (s->as.u.key.nacc == 0) {
			n1 = s->as.u.key.sf;	/* new key sig */
			if (cfmt.cancelkey || n1 == 0)
				n2 = s->u;	/* old key */
			else
				n2 = 0;
			if (n1 * n2 >= 0) {	/* if no natural */
				if (n1 < 0)
					n1 = -n1;
				if (n2 < 0)
					n2 = -n2;
				if (n2 > n1)
					n1 = n2;
			} else {
				n1 -= n2;
				if (n1 < 0)
					n1 = -n1;
				esp += 3;	/* see extra space in draw_keysig() */
			}
		} else {
			int last_acc;

			n1 = n2 = s->as.u.key.nacc;
			last_acc = s->as.u.key.accs[0];
			for (i = 1; i < n2; i++) {
				if (s->as.u.key.accs[i] != last_acc) {
					last_acc = s->as.u.key.accs[i];
					esp += 3;
				}
				if (s->as.u.key.pits[i] == s->as.u.key.pits[i - 1] + 7
				 || s->as.u.key.pits[i] == s->as.u.key.pits[i - 1] - 7)
					n1--;		/* octave */
			}
		}
		s->wr = (float) (5.5 * n1 + esp);
		break;
	    }
	case TIMESIG:
		/* !!tied to draw_timesig()!! */
		w = 0;
		for (i = 0; i < s->as.u.meter.nmeter; i++) {
			int l;

			l = sizeof s->as.u.meter.meter[i].top;
			if (s->as.u.meter.meter[i].top[l - 1] == '\0') {
				l = strlen(s->as.u.meter.meter[i].top);
				if (s->as.u.meter.meter[i].top[1] == '|'
				 || s->as.u.meter.meter[i].top[1] == '.')
					l--;		/* 'C|' */
			}
			if (s->as.u.meter.meter[i].bot[0] != '\0') {
				int l2;

				l2 = sizeof s->as.u.meter.meter[i].bot;
				if (s->as.u.meter.meter[i].bot[l2 - 1] == '\0')
					l2 = strlen(s->as.u.meter.meter[i].bot);
				if (l2 > l)
					l = l2;
			}
			w += 6.5 * l;
		}
		s->wl = w;
		s->wr = w + 7;
		break;
	case MREST:
		s->wl = 40 / 2 + 16;
		s->wr = 40 / 2 + 16;
		break;
	case GRACE:
		s->wl = set_graceoffs(s);
		break;
	case STBRK:
		if (s->next && s->next->type == CLEF) {
			s->wr = 2;
			s->next->u = 0;	/* big clef */
		} else {
			s->wr = 8;
		}
		s->wl = s->xmx;
		break;
#if 0
	case TEMPO:
	case PART:
	case TUPLET:
	case CUSTOS:
#endif
	case FMTCHG:
	case STAVES:		/* no space */
		break;
	default:
		bug("Cannot set width for symbol", 1);
	}
}

/* -- set the natural space -- */
static float set_space(struct SYMBOL *s)
{
	struct SYMBOL *s2;
	int i, len, l, stemdir, prev_time;
	float space;

	prev_time = !s->ts_prev ? s->time : s->ts_prev->time;
	len = s->time - prev_time;		/* time skip */
	if (len == 0) {
		switch (s->type) {
		case MREST:
			return s->wl + 16;
/*fixme:do same thing at start of line*/
		case NOTEREST:
			if (s->ts_prev->type == BAR) {
				i = 2;
				if (s->nflags < -2)
					i = 0;
				return space_tb[i];
			}
			break;
		}
		return 0;
	}
	if (s->prev && s->prev->type == MREST)
		return s->prev->wr + 16;
	if (smallest_duration >= MINIM) {
		if (smallest_duration >= SEMIBREVE)
			len /= 4;
		else
			len /= 2;
	}
	if (len >= CROTCHET) {
		if (len < MINIM)
			i = 5;
		else if (len < SEMIBREVE)
			i = 6;
		else if (len < BREVE)
			i = 7;
		else if (len < BREVE * 2)
			i = 8;
		else
			i = 9;
	} else {
		if (len >= QUAVER)
			i = 4;
		else if (len >= SEMIQUAVER)
			i = 3;
		else if (len >= SEMIQUAVER / 2)
			i = 2;
		else if (len >= SEMIQUAVER / 4)
			i = 1;
		else
			i = 0;
	}
	l = len - ((SEMIQUAVER / 8) << i);
	space = space_tb[i];
	if (l != 0) {
		if (l < 0) {
			space = space_tb[0] * len / (SEMIQUAVER / 8);
		} else {
			if (i >= 9)
				i = 8;
			space += (space_tb[i + 1] - space_tb[i])
				* l / len;
		}
	}
	if (s->dur == 0) {
		if (s->type == BAR) {
			if (s->as.u.bar.type & 0xf)
				space *= 0.8;	/* complex bar */
			else
				space *= 0.7;
		}
		return space;
	}

	/* reduce spacing within a beam */
	if (!(s->sflags & S_BEAM_ST))
		space *= fnnp;

	/* decrease spacing when stem down followed by stem up */
/*fixme:to be done later, after x computed in sym_glue*/
	if (s->as.type == ABC_T_NOTE && s->nflags >= -1
	 && s->stem > 0) {
		stemdir = 1;
		for (s2 = s->ts_prev;
		     s2 && s2->time == prev_time;
		     s2 = s2->ts_prev) {
			if (s2->nflags < -1 || s2->stem > 0) {
				stemdir = 0;
				break;
			}
		}
		if (stemdir) {
			for (s2 = s->ts_next;
			     s2 && s2->time == s->time;
			     s2 = s2->ts_next) {
				if (s2->nflags < -1 || s2->stem < 0) {
					stemdir = 0;
					break;
				}
			}
			if (stemdir)
				space *= 0.9;
		}
	}
	return space;
}

/* -- set the width and space of all symbols -- */
/* this function is called once for the whole tune
 * then, once per music line up to the first sequence */
static void set_allsymwidth(struct SYMBOL *last_s)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *s, *s2, *s3;
	struct tblt_s *tblt;
	int i;
	float new_val, shrink, space;

	/* set the space of the starting symbols */
	new_val = 0;
	s = tsfirst;
	for (;;) {
		set_width(s);
		if (new_val < s->wl)
			new_val = s->wl;
		s = s->ts_next;
		if (!s || (s->sflags & S_SEQST))
			break;
	}
	tsfirst->shrink = new_val;

	/* loop on all remaining symbols */
//	for (;;) {
	while (s != last_s) {
		s2 = s;
		shrink = space = 0;
		do {
			int ymx1, ymn1, ymx2, ymn2;
			float wl;

			/* set the minimum space before and after the symbol */
			set_width(s2);

			/* calculate the minimum space before the symbol,
			 * looping in the previous time sequence */
			if (s2->type == BAR) {
				ymx1 = 50;
				ymn1 = -50;
			} else {
				ymx1 = s2->ymx;
				ymn1 = s2->ymn;
			}
			wl = s2->wl;
			new_val = 0;
			for (s3 = s->ts_prev; s3; s3 = s3->ts_prev) {
				if (new_val < s3->wr
				 && s3->type == NOTEREST
				 && s2->type == NOTEREST)
					new_val = s3->wr;
				if (s3->staff == s2->staff
				 && (!(s3->as.flags & ABC_F_INVIS)
				  || s3->voice == s2->voice)
				 && new_val < s3->wr + wl) {
					switch (s3->type) {
					case NOTEREST:
						if (s2->type == NOTEREST) {
							new_val = s3->wr + wl;
							break;
						}
						/* fall thru */
					default:
						ymx2 = s3->ymx;
						ymn2 = s3->ymn;
						if (ymn1 > ymx2
						 || ymx1 < ymn2)
							break;
						/* fall thru */
					case SPACE:
					case BAR:
					case CLEF:
					case TIMESIG:
					case KEYSIG:
						new_val = s3->wr + wl;
						break;
					}
				}
				if (s3->sflags & S_SEQST) {
					if (new_val != 0)
						break;
					wl -= s3->shrink;
					if (wl < 0)
						break;
				}
			}
			if (shrink < new_val)
				shrink = new_val;
			new_val = set_space(s2);
			if (space < new_val)
				space = new_val;
			if ((s2 = s2->ts_next) == last_s)
				break;
		} while (!(s2->sflags & S_SEQST));

		/* set the spaces at start of sequence */
		if (shrink == 0 && space == 0 && s->type == CLEF) {
			s->sflags &= ~S_SEQST;		/* no space */
			s->time = s->ts_prev->time;
		} else {
			s->shrink = shrink;
			s->space = space;
		}
//		if ((s = s2) == last_s)
//			break;
		s = s2;
	}

	/* have room for the tablature header */
	space = 0;
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		for (i = 0; i < 2; i++) {
			if ((tblt = p_voice->tblts[i]) == NULL)
				continue;
			if (tblt->wh > space)
				space = tblt->wh;
		}
	}
	if (space == 0)
		return;
	shrink = 0;
	for (s = tsfirst; s != last_s; s = s->ts_next) {
		if (s->shrink != 0)
			shrink += s->shrink;
		if (s->as.type == ABC_T_NOTE)
			break;
	}
	if (s != last_s && shrink < space) {
		while (!(s->sflags & S_SEQST))
			s = s->ts_prev;
		s->shrink += space - shrink;
	}
}

/* change a symbol into a rest */
static void to_rest(struct SYMBOL *s)
{
	s->type = NOTEREST;
	s->as.type = ABC_T_REST;
	s->sflags &= S_NL | S_SEQST;
	s->doty = -1;
	s->as.u.note.dc.n = 0;
	s->gch = NULL;
	s->extra = NULL;
	s->as.u.note.slur_st = s->as.u.note.slur_end = 0;
/*fixme: should set many parameters for set_width*/
//	set_width(s);
}

/* -- set the repeat sequences / measures -- */
static void set_repeat(struct SYMBOL *g,	/* repeat format */
			struct SYMBOL *s)	/* first note */
{
	struct SYMBOL *s2, *s3;
	int i, j, n, dur, staff, voice;

	staff = s->staff;
	voice = s->voice;

	/* treat the sequence repeat */
	if ((n = g->doty) < 0) {		/* number of notes / measures */
		n = -n;
		i = n;				/* number of notes to repeat */
		for (s3 = s->prev; s3; s3 = s3->prev) {
			if (s3->dur == 0) {
				if (s3->type == BAR) {
					error(0, s3, "Bar in sequence to repeat");
					goto delrep;
				}
				continue;
			}
			if (--i <= 0)
				break;
		}
		if (!s3) {
			error(0, s, "Not enough symbols to repeat");
			goto delrep;
		}

		i = g->nohdix * n;	/* number of notes/rests to repeat */
		for (s2 = s; s2; s2 = s2->next) {
			if (s2->dur == 0) {
				if (s2->type == BAR) {
					error(0, s2, "Bar in repeat sequence");
					goto delrep;
				}
				continue;
			}
			if (--i <= 0)
				break;
		}
		if (!s2
		 || !s2->next) {		/* should have some symbol */
			error(0, s, "Not enough symbols after repeat sequence");
			goto delrep;
		}
		for (s2 = s->prev; s2 != s3; s2 = s2->prev) {
			if (s2->as.type == ABC_T_NOTE) {
				s2->sflags |= S_BEAM_END;
				break;
			}
		}
		s3 = s;
		for (j = g->nohdix; --j >= 0; ) {
			i = n;			/* number of notes/rests */
			if (s3->dur != 0)
				i--;
			s2 = s3->ts_next;
			while (i > 0) {
				if (s2->staff != staff)
					continue;
				if (s2->voice == voice
				 && s2->dur != 0)
					i--;
				s2->extra = NULL;
				unlksym(s2);
				s2 = s2->ts_next;
			}
			to_rest(s3);
			s3->dur = s3->as.u.note.lens[0]
				= s2->time - s3->time;
//			s3->sflags |= S_REPEAT | S_BEAM_ST;
			s3->sflags |= S_REPEAT;
			set_width(s3);
			if (s3->sflags & S_SEQST)
				s3->space = set_space(s3);
			s3->head = H_SQUARE;
			s3 = s2;
		}
		goto delrep;			/* done */
	}

	/* check the measure repeat */
	i = n;				/* number of measures to repeat */
	for (s2 = s->prev->prev ; s2; s2 = s2->prev) {
		if (s2->type == BAR
		 || s2->time == tsfirst->time) {
			if (--i <= 0)
				break;
		}
	}
	if (!s2) {
		error(0, s, "Not enough measures to repeat");
		goto delrep;
	}

	dur = s->time - s2->time;	/* repeat duration */

	if (n == 1)
		i = g->nohdix;		/* repeat number */
	else
		i = n;			/* check only 2 measures */
	for (s2 = s; s2; s2 = s2->next) {
		if (s2->type == BAR) {
			if (--i <= 0)
				break;
		}
	}
	if (!s2) {
		error(0, s, "Not enough bars after repeat measure");
		goto delrep;
	}

	/* if many 'repeat 2 measures'
	 * insert a new %%repeat after the next bar */
	i = g->nohdix;		/* repeat number */
	if (n == 2 && i > 1) {
		s2 = s2->next;
		if (!s2) {
			error(0, s, "Not enough bars after repeat measure");
			goto delrep;
		}
		g->nohdix = 1;
		s = (struct SYMBOL *) getarena(sizeof *s);
		memcpy(s, g, sizeof *s);
		s->next = s2->extra;
		if (s->next)
			s->next->prev = s;
		s->prev = NULL;
		s2->extra = s;
		s->nohdix = --i;
	}

	/* replace */
	dur /= n;
	if (n == 2) {			/* repeat 2 measures (once) */
		s3 = s;
		for (s2 = s->ts_next; ;s2 = s2->ts_next) {
			if (s2->staff != staff)
				continue;
			if (s2->voice == voice
			 && s2->type == BAR)
				break;
			s2->extra = NULL;
			unlksym(s2);
		}
		to_rest(s3);
		s3->dur = s3->as.u.note.lens[0] = dur;
		s3->as.flags = ABC_F_INVIS;
		if (s3->sflags & S_SEQST)
			s3->space = set_space(s3);
		s2->as.u.bar.len = 2;
		if (s2->sflags & S_SEQST)
			s2->space = set_space(s2);
		s3 = s2->next;
		s2 = s3->next;
		for (;;) {
			if (s2->type == BAR || s2->type == CLEF)
				break;
			s2->extra = NULL;
			unlksym(s2);
			s2 = s2->next;
		}
		to_rest(s3);
		s3->dur = s3->as.u.note.lens[0] = dur;
		s3->as.flags = ABC_F_INVIS;
		set_width(s3);
		if (s3->sflags & S_SEQST)
			s3->space = set_space(s3);
		if (s2->sflags & S_SEQST)
			s2->space = set_space(s2);
		return;
	}

	/* repeat 1 measure */
	s3 = s;
	for (j = g->nohdix; --j >= 0; ) {
		for (s2 = s3->ts_next; ; s2 = s2->ts_next) {
			if (s2->staff != staff)
				continue;
			if (s2->voice == voice
			 && s2->type == BAR)
				break;
			s2->extra = NULL;
			unlksym(s2);
		}
		to_rest(s3);
		s3->dur = s3->as.u.note.lens[0] = dur;
//		s3->sflags |= S_REPEAT | S_BEAM_ST;
		s3->sflags |= S_REPEAT;
		if (s3->sflags & S_SEQST)
			s3->space = set_space(s3);
		if (s2->sflags & S_SEQST)
			s2->space = set_space(s2);
		if (g->nohdix == 1) {
			s3->doty = 1;
			break;
		}
		s3->doty = g->nohdix - j + 1;	/* number to print above the repeat rest */
		s3 = s2->next;
	}
	return;

delrep:					/* remove the %%repeat */
	g->type = FMTCHG;
	g->u = -1;
}

/* add a custos before the symbol of the next line */
static void custos_add(struct SYMBOL *s)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *new_s, *s2;
	int i;

	s2 = s;
	for (;;) {
		if (!s2)
			return;
		if (s2->as.type == ABC_T_NOTE)
			break;
		s2 = s2->next;
	}

	p_voice = &voice_tb[s->voice];
	p_voice->last_sym = s->prev;
	if (!p_voice->last_sym)
		p_voice->sym = NULL;
	p_voice->time = s->time;
	new_s = sym_add(p_voice, CUSTOS);
	new_s->next = s;
	s->prev = new_s;
	new_s->ts_prev = s->ts_prev;
	new_s->ts_prev->ts_next = new_s;
	new_s->ts_next = s;
	s->ts_prev = new_s;

	new_s->sflags |= S_SEQST;
	new_s->wl = 8;
	new_s->wr = 4;
	new_s->shrink = 8 + 4;

	new_s->nhd = s2->nhd;
//	memcpy(new_s->as.u.note.lens, s2->as.u.note.lens,
//			sizeof new_s->as.u.note.lens);
	memcpy(new_s->pits, s2->pits, sizeof new_s->pits);
	for (i = 0; i <= new_s->nhd; i++)
		new_s->as.u.note.lens[i] = CROTCHET;
	new_s->as.flags = ABC_F_STEMLESS;
}

/* -- define the beginning of a new music line -- */
static struct SYMBOL *set_nl(struct SYMBOL *s)
{
	struct SYMBOL *s2, *extra, *staves;
	struct VOICE_S *p_voice;
	int done;

	/* if explicit EOLN, cut on the next symbol */
	if ((s->sflags & S_EOLN) && !cfmt.keywarn && !cfmt.timewarn) {
		s = s->next;
		if (!s)
			return s;
		while (!(s->sflags & S_SEQST))
			s = s->ts_prev;
		goto setnl;
	}

	/* if normal symbol, cut here */
	switch (s->type) {
	case CLEF:
	case BAR:
		break;
	case KEYSIG:
		if (cfmt.keywarn)
			break;
		goto normal;
	case TIMESIG:
		if (cfmt.timewarn)
			break;
		goto normal;
	case GRACE:			/* don't cut on a grace note */
		s = s->next;
		if (!s)
			return s;
		/* fall thru */
	default:
normal:
		/* cut on the next symbol */
		s = s->next;
		if (!s)
			return s;
		while (!(s->sflags & S_SEQST))
			s = s->ts_prev;
#if 1
		goto setnl;
#else
		switch (s->type) {
		case NOTEREST:
		case GRACE:
		case SPACE:
			goto setnl;
		}
		break;
#endif
	}

	/* go back to handle the staff breaks at end of line */
	for (; s; s = s->ts_prev) {
		if (!(s->sflags & S_SEQST))
			continue;
		switch (s->type) {
		case CLEF:
		case KEYSIG:
		case TIMESIG:
			continue;
		}
		break;
	}
	done = 0;
	staves = extra = NULL;
	for ( ; ; s = s->ts_next) {
		if (!s)
			return NULL;
		if (!(s->sflags & S_SEQST))
			continue;
		if (done < 0)
			break;
		if (s->type == STAVES) {	/* case "| $ %%staves K: M:" */
			if (!s->ts_next)
				return NULL;
			staves = s;
			s = s->ts_next;
		}
		switch (s->type) {
		case BAR:
			if (done
			 || (s->u == 0		/* incomplete measure */
			  && s->next		/* not at end of tune */
			  && (s->as.u.bar.type & 0x0f) == B_COL
			  && !(s->sflags & S_RRBAR)))
						/* 'xx:' (not ':xx:') */
				goto cut_here;
			done = 1;
			break;
		case STBRK:
			if (s->doty == 0) {	/* if not forced */
				unlksym(s);	/* remove */
				break;
			}
			done = -1;	/* keep the next symbols on the next line */
			break;
		case TIMESIG:
			if (!cfmt.timewarn)
				goto cut_here;
			break;
		case CLEF:
			if (done)
				goto cut_here;
			break;
		case KEYSIG:
			if (!cfmt.keywarn)
				goto cut_here;
			break;
		default:
			if (!done || (s->prev && s->prev->type == GRACE))
				break;
			goto cut_here;
		}
		if (s->extra) {
			if (!extra)
				extra = s;
			else
				error(0, s, "abcm2ps problem: "
					"Extra symbol may be misplaced");
		}
	}
cut_here:
	if (extra			/* extra symbol(s) to be moved */
	 && extra != s) {
		s2 = extra->extra;
		while (s2->next)
			s2 = s2->next;
		s2->next = s->extra;
		s->extra = extra->extra;
		extra->extra = NULL;
	}
	if (staves) {			/* move the %%staves to the next line */
		if (s != staves->ts_next) {
			unlksym(staves);
			staves->prev = s->prev;
			if (s->prev)
				staves->prev->next = staves;
			s->prev = staves;
			staves->next = s;
			staves->ts_prev = s->ts_prev;
			staves->ts_prev->ts_next = staves;
			s->ts_prev = staves;
			staves->ts_next = s;
			s->sflags &= ~S_SEQST;
		}
		s = staves;
	}
setnl:
	if (cfmt.custos && !first_voice->next) {
		custos_add(s);
	} else {
		switch (s->ts_prev->type) {
		case BAR:
		case FMTCHG:
		case CLEF:
		case KEYSIG:
		case TIMESIG:
			break;
		default:			/* add an extra symbol at eol */
			p_voice = &voice_tb[s->voice];
			p_voice->last_sym = s->prev;
//			if (!p_voice->last_sym)
//				p_voice->sym = NULL;
			p_voice->time = s->time;
			extra = sym_add(p_voice, FMTCHG);
			extra->next = s;
			s->prev = extra;
			extra->ts_prev = s->ts_prev;
			extra->ts_prev->ts_next = extra;
			extra->ts_next = s;
			s->ts_prev = extra;
			if (s->x != 0) {	/* auto break */
				for (s2 = s->ts_next; ; s2 = s2->ts_next) {
					if (s2->x != 0) {
						extra->x = s2->x - 1;
						break;
					}
				}
			}
			extra->u = -1;
			extra->sflags |= S_SEQST;
			extra->wl = 6;
			extra->shrink = extra->prev->wr + 6;
			extra->space = extra->prev->space;
			break;
		}
	}
	s->sflags |= S_NL;
	return s;
}

/* -- search where to cut the lines according to the staff width -- */
static struct SYMBOL *set_lines(struct SYMBOL *first,	/* first symbol */
				struct SYMBOL *last,	/* last symbol / 0 */
				float lwidth,		/* w - (clef & key sig) */
				float indent)		/* for start of tune */
{
	struct SYMBOL *s, *s2;
	float x, xmin, xmax, wwidth, shrink, space;
	int nlines, beam, bar_time;

	/* calculate the whole size of the piece of tune */
	wwidth = indent;
	for (s = first; s != last; s = s->ts_next) {
		if (!(s->sflags & S_SEQST))
			continue;
		s->x = wwidth;
		shrink = s->shrink;
		if ((space = s->space) < shrink)
			wwidth += shrink;
		else
			wwidth += shrink * cfmt.maxshrink
				+ space * (1 - cfmt.maxshrink);
	}

	/* loop on cutting the tune into music lines */
	s = first;
	for (;;) {
		nlines = wwidth / lwidth + 0.999;
		if (nlines <= 1) {
			if (last)
				last = set_nl(last);
			return last;
		}

		/* try to cut on a measure bar */
		s2 = first = s;
		xmin = s->x + wwidth / nlines * cfmt.breaklimit;
		xmax = s->x + lwidth;
		for ( ; s != last; s = s->ts_next) {
			x = s->x;
			if (x == 0)
				continue;
			if (x > xmax)
				break;
			if (s->type != BAR)
				continue;
			if (x > xmin)
				goto cut_here;
			s2 = s;			// keep the last bar
		}

#if 1
		bar_time = s2->time;

		/* try to cut on a crotchet */
		if (s) {
		    for (;;) {			/* go back */
			s = s->ts_prev;
			x = s->x;
			if (x == 0)
				continue;
			if ((s->time - bar_time) % CROTCHET == 0) {
				for (s = s->ts_prev ; ; s = s->ts_prev) {
					if (s->x != 0)
						break;
				}
				goto cut_here;
			}
			if (s->x < xmin)
				break;
		    }
		}

		/* try to avoid to cut a beam */
		s = s2;				/* restart from the last bar */
		beam = 0;
		for ( ; s != last; s = s->ts_next) {
			if ((s->sflags & (S_BEAM_ST | S_BEAM_END))
						== S_BEAM_ST) {
				beam++;
				continue;
			}
			if ((s->sflags & (S_BEAM_ST | S_BEAM_END))
						== S_BEAM_END)
				beam--;
			if (beam != 0)
				continue;
			x = s->x;
			if (x != 0 && x >= xmin) {
				if (x > xmax)
					break;
				for (s = s->ts_prev ; ; s = s->ts_prev) {
					if (s->x != 0)
						break;
				}
				goto cut_here;
			}
		}

		/* no good place, cut here */
		for (s = s->ts_prev ; ; s = s->ts_prev) {
//			if (!s)
//				return s;
			if (s->x != 0)
				break;
		}
#else
		/* try to avoid to cut a beam */
		beam = 0;
		bar_time = s2->time;
		s = s2;				/* restart on the last bar */
		s2 = NULL;
		for ( ; s != last; s = s->ts_next) {
			x = s->x;
			if (x != 0 && x >= xmin) {
				if (x > xmax)
					break;
				if (!s2)
					s2 = s;
			}
			if ((s->sflags & (S_BEAM_ST | S_BEAM_END))
						== S_BEAM_ST)
				beam++;
			else if ((s->sflags & (S_BEAM_ST | S_BEAM_END))
						== S_BEAM_END)
				beam--;
		}
		if (s2 && beam <= 0) {
			s = s2;
			goto cut_here;
		}

		/* cut on a crotchet */
		s = s2;
		if (!s) {
//fixme:test - this should not occur very often
			fprintf(stderr, "*** cut_tune limit 1!\n");
			s = s2 = first->ts_next;
		}
		for ( ; s != last; s = s->ts_next) {
			x = s->x;
			if (x == 0)
				continue;
			if ((s->time - bar_time) % CROTCHET == 0) {
				for (s = s->ts_prev ; ; s = s->ts_prev) {
					if (!s)
						return s;
					if (s->x != 0)
						break;
				}
				goto cut_here;
			}
			if (x > xmax)
				break;
		}
//fixme:test - may occur when symbol width > line width
		fprintf(stderr, "*** cut_tune limit 2!\n");
		s = s->next;
		if (!s)
			return s;
#endif
cut_here:
		if (s->sflags & S_NL) {		/* already set here - advance */
			error(0, s, "Line split problem - "
					"adjust maxshrink and/or breaklimit");
			nlines = 2;
			for (s = s->ts_next; s != last; s = s->ts_next) {
				if (s->x == 0)
					continue;
				if (--nlines <= 0)
					break;
			}
		}
		s = set_nl(s);
		if (!s
		 || (last && s->time >= last->time))
			break;
		wwidth -= s->x - first->x;
	}
	return s;
}

/* -- cut the tune into music lines -- */
static void cut_tune(float lwidth, float indent)
{
	struct SYMBOL *s, *s2;
	int i;
	float xmin;

	/* adjust the line width according to the starting clef
	 * and key signature */
/*fixme: may change in the tune*/
#if 1
	struct VOICE_S *p_voice;

	s = tsfirst;
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		i = p_voice - voice_tb;
		if (cursys->voice[i].range >= 0)
			break;
	}
	lwidth -= 12 + 10			// clef.wl
		+ 12 - 10			// clef.wr
		+ 3				// key.wl
		+ p_voice->key.sf * 5.5;	// key.wr
#else
	for (s = tsfirst; s; s = s->ts_next) {
		if (s->shrink == 0)
			continue;
		if (s->type != CLEF && s->type != KEYSIG)
			break;
		lwidth -= s->shrink;
	}
#endif
	if (cfmt.custos && !first_voice->next)
		lwidth -= 12;
	if (cfmt.continueall) {
		set_lines(s, 0, lwidth, indent);
		return;
	}

	/* if asked, count the measures and set the EOLNs */
	if ((i = cfmt.barsperstaff) != 0) {
		s2 = s;
		for ( ; s; s = s->ts_next) {
			if (s->type != BAR
			 || s->u == 0)
				continue;
			if (--i > 0)
				continue;
			s->sflags |= S_EOLN;
			i = cfmt.barsperstaff;
		}
		s = s2;
	}

	/* cut at explicit end of line, checking the line width */
	xmin = indent;
	s2 = s;
	for ( ; s; s = s->ts_next) {
		if (!(s->sflags & (S_SEQST | S_EOLN)))
			continue;
		xmin += s->shrink;
		if (xmin > lwidth) {
			if (cfmt.linewarn)
				error(0, s, "Line overfull (%.0fpt of %.0fpt)",
					xmin, lwidth);
			for (s = s->ts_next; s; s = s->ts_next) {
				if (s->sflags & S_EOLN)
					break;
			}
			s = s2 = set_lines(s2, s, lwidth, indent);
			if (!s)
				break;
			xmin = s->shrink;
			indent = 0;
		}
		if (!(s->sflags & S_EOLN))
			continue;
		s2 = set_nl(s);
		s->sflags &= ~S_EOLN;
		s = s2;
		if (!s)
			break;
		xmin = s->shrink;
		indent = 0;
	}
}

/* -- set the y values of some symbols -- */
static void set_yval(struct SYMBOL *s)
{
	int top, bot;

	top = staff_tb[s->staff].topbar;
	bot = staff_tb[s->staff].botbar;
	switch (s->type) {
	case CLEF:
		if ((s->sflags & S_SECOND)
		 || (s->as.flags & ABC_F_INVIS)) {
			s->ymx = s->ymn = (top + bot) / 2;
			break;
		}
		switch (s->as.u.clef.type) {
		default:			/* treble / perc */
			s->y = -2 * 6;
			s->ymx = 24 + 15;
			s->ymn = -11;
			break;
		case ALTO:
			s->y = -3 * 6;
			s->ymx = 24 + 6;
			s->ymn = -3;
			break;
		case BASS:
			s->y = -4 * 6;
			s->ymx = 24 + 6;
			s->ymn = -3;
			break;
		}
		if (s->u) {
			s->ymx -= 2;
			s->ymn += 2;
		}
		s->y += s->as.u.clef.line * 6;
		if (s->y > 0)
			s->ymx += s->y;
		else if (s->y < 0)
			s->ymn += s->y;
		if (s->as.u.clef.octave > 0)
			s->ymx += 9;
		else if (s->as.u.clef.octave < 0)
			s->ymn -= 9;
		break;
	case KEYSIG:
		if (s->as.u.key.sf > 2)
			s->ymx = 24 + 10;
		else if (s->as.u.key.sf > 0)
			s->ymx = 24 + 6;
		else
			s->ymx = 24 + 2;
		s->ymn = -2;
		break;
	default:
		s->ymx = top + 2;
		s->ymn = -2;
		break;
	}
}

/* -- set the pitch of the notes according to the clefs -- */
/* also set the vertical offset of the symbols */
/* this function is called only once per tune
 * then, once per music line up to the old sequence */
static void set_pitch(struct SYMBOL *last_s)
{
	struct SYSTEM *sy;
	struct SYMBOL *s;
	int staff, delta, dur;
	signed char staff_clef[MAXSTAFF];
	static signed char delta_tb[4] = {
		0 - 2 * 2,
		6 - 3 * 2,
		12 - 4 * 2,
		0 - 2 * 2
	};

	sy = cursys;
	for (staff = 0; staff <= sy->nstaff; staff++) {
		staff_clef[staff] = delta_tb[sy->staff[staff].clef.type]
				+ sy->staff[staff].clef.transpose
				+ sy->staff[staff].clef.line * 2;
	}
	dur = BASE_LEN;
	for (s = tsfirst; s != last_s; s = s->ts_next) {
		struct SYMBOL *g;
		int np, m;

		for (g = s->extra ; g; g = g->next) {
			if (g->type == FMTCHG && g->u == REPEAT) {
				set_repeat(g, s);
				break;
			}
		}
		staff = s->staff;
		switch (s->type) {
		case CLEF:
			if (s->sflags & S_SECOND) {
/*fixme:%%staves:can this happen?*/
				if (!s->prev)
					break;
				unlksym(s);
				break;
			}
			set_yval(s);
			staff_clef[staff] = delta_tb[s->as.u.clef.type]
						+ s->as.u.clef.transpose
						+ s->as.u.clef.line * 2;
			break;
		case STAVES:
			sy = sy->next;
			for (staff = 0; staff <= sy->nstaff; staff++) {
				staff_clef[staff] = delta_tb[sy->staff[staff].clef.type]
						+ sy->staff[staff].clef.transpose
						+ sy->staff[staff].clef.line * 2;
			}
			break;
		case GRACE:
			for (g = s->extra; g; g = g->next) {
				if (g->type != NOTEREST)
					continue;
				delta = staff_clef[g->staff];
				if (delta != 0) {
					for (m = g->nhd; m >= 0; m--)
						g->pits[m] += delta;
				}
				g->ymn = 3 * (g->pits[0] - 18) - 2;
				g->ymx = 3 * (g->pits[g->nhd] - 18) + 2;
			}
			set_yval(s);
			break;
		case KEYSIG:
			s->pits[0] = staff_clef[staff];	/* keep the current clef */
//			s->ymx = 24 + 10;
//			s->ymn = -2;
//			break;
			/* fall thru */
		default:
			set_yval(s);
			break;
		case MREST:
			if (s->as.flags & ABC_F_INVIS)
				break;
			s->ymx = 24 + 15;
			s->ymn = -2;
			break;
		case NOTEREST:
#if 1 /* test rest offset */
			if (s->as.type != ABC_T_NOTE
			 && !first_voice->next) {
#else
			if (s->as.type != ABC_T_NOTE) {
#endif
				s->y = 12;		/* rest */
				s->ymx = 12 + 8;
				s->ymn = 12 - 8;
				break;
			}
			np = s->nhd;
			delta = staff_clef[staff];
			if (delta != 0) {
				for (m = np; m >= 0; m--)
					s->pits[m] += delta;
			}
//			pav = 0;
//			for (m = np; m >= 0; m--)
//				pav += s->pits[m];
//			s->yav = 3 * pav / (np + 1) - 3 * 18;
			s->ymx = 3 * (s->pits[np] - 18) + 4;
			s->ymn = 3 * (s->pits[0] - 18) - 4;
			s->yav = (s->ymx + s->ymn) / 2;
// test rest offset
			if (s->as.type != ABC_T_NOTE)
				s->y = s->yav / 6 * 6;
			if (s->dur < dur)
				dur = s->dur;
			break;
		}
	}
	smallest_duration = dur;
}

/* -- set the stem direction when multi-voices -- */
/* this function is called only once per tune */
static void set_stem_dir(void)
{
	struct SYSTEM *sy;
	struct SYMBOL *s, *t, *u;
	int i, staff, nst, rvoice, voice;
	struct {
		int nvoice;
		struct {
			int voice;
			short ymn;
			short ymx;
		} st[4];		/* (no more than 4 voices per staff) */
	} stb[MAXSTAFF];
	struct {
		signed char st1, st2;	/* (a voice cannot be on more than 2 staves) */
	} vtb[MAXVOICE];

	s = tsfirst;
	sy = cursys;
	nst = sy->nstaff;
	while (s) {
		for (staff = nst; staff >= 0; staff--) {
			stb[staff].nvoice = -1;
			for (i = 4; --i >= 0; ) {
				stb[staff].st[i].voice = -1;
				stb[staff].st[i].ymx = 0;
				stb[staff].st[i].ymn = 24;
			}
		}
		for (i = 0; i < MAXVOICE; i++)
			vtb[i].st1 = vtb[i].st2 = -1;

		/* get the max/min offsets in the delta time */
/*fixme: the stem height is not calculated yet*/
		for (u = s;
		     u && u->type != BAR && u->type != STAVES;
		     u = u->ts_next) {
			if (u->type != NOTEREST
			 || (u->as.flags & ABC_F_INVIS))
				continue;
			staff = u->staff;
#if 1
/*fixme:test*/
if (staff > nst) {
	bug("set_stem_dir(): bad staff number\n", 1);
}
#endif
			voice = u->voice;
			if (vtb[voice].st1 < 0) {
				vtb[voice].st1 = staff;
			} else if (vtb[voice].st1 != staff) {
				if (staff > vtb[voice].st1) {
					if (staff > vtb[voice].st2)
						vtb[voice].st2 = staff;
				} else {
					if (vtb[voice].st1 > vtb[voice].st2)
						vtb[voice].st2 = vtb[voice].st1;
					vtb[voice].st1 = staff;
				}
			}
			rvoice = sy->voice[voice].range;
			for (i = stb[staff].nvoice; i >= 0; i--) {
				if (stb[staff].st[i].voice == rvoice)
					break;
			}
			if (i < 0) {
				if (++stb[staff].nvoice >= 4)
					bug("Too many voices per staff", 1);
				for (i = 0; i < stb[staff].nvoice; i++) {
					if (rvoice < stb[staff].st[i].voice) {
						memmove(&stb[staff].st[i + 1],
							&stb[staff].st[i],
							sizeof stb[staff].st[i]
								* (stb[staff].nvoice - i));
						stb[staff].st[i].ymx = 0;
						stb[staff].st[i].ymn = 24;
						break;
					}
				}
				stb[staff].st[i].voice = rvoice;
			}

			if (u->as.type != ABC_T_NOTE)
				continue;
			if (u->ymx > stb[staff].st[i].ymx)
				stb[staff].st[i].ymx = u->ymx;
			if (u->ymn < stb[staff].st[i].ymn)
				stb[staff].st[i].ymn = u->ymn;
			if (u->sflags & S_XSTEM) {
				if (u->ts_prev->staff != staff - 1
				 || u->ts_prev->as.type != ABC_T_NOTE) {
					error(1, s, "Bad +xstem+");
					u->sflags &= ~S_XSTEM;
/*fixme:nflags KO*/
				} else {
					u->ts_prev->multi = 1;
					u->multi = 1;
					u->as.flags |= ABC_F_STEMLESS;
				}
			}
		}

		for ( ; s != u; s = s->ts_next) {
			if (s->type != NOTEREST		/* if not note nor rest */
			 && s->type != GRACE)
				continue;
			staff = s->staff;
			voice = s->voice;
			if (!s->multi && vtb[voice].st2 >= 0) {
				if (staff == vtb[voice].st1)
					s->multi = -1;
				else if (staff == vtb[voice].st2)
					s->multi = 1;
			}
			if (stb[staff].nvoice <= 0) { /* voice alone on the staff */
				if (s->multi)
					continue;
/*fixme:could be done in set_float()*/
				if (s->sflags & S_FLOATING) {
					if (staff == voice_tb[voice].staff)
						s->multi = -1;
					else
						s->multi = 1;
				}
				continue;
			}
			rvoice = sy->voice[voice].range;
			for (i = stb[staff].nvoice; i >= 0; i--) {
				if (stb[staff].st[i].voice == rvoice)
					break;
			}
			if (i < 0)
				continue;		/* voice ignored */
			if (!s->multi) {
				if (i == stb[staff].nvoice) {
					s->multi = -1;	/* last voice */
				} else {
					s->multi = 1;	/* first voice(s) */

					/* if 3 voices, and vertical space enough,
					 * have stems down for the middle voice */
					if (i != 0
					 && i + 1 == stb[staff].nvoice) {
						if (stb[staff].st[i].ymn - cfmt.stemheight
						    > stb[staff].st[i + 1].ymx)
							s->multi = -1;

						/* special case for unison */
						if (s->ts_prev
						 && s->ts_prev->time == s->time
						 && s->ts_prev->staff == s->staff
						 && s->pits[s->nhd] == s->ts_prev->pits[0]
						 && (s->sflags & (S_BEAM_ST | S_BEAM_END))
								== (S_BEAM_ST | S_BEAM_END)
						 && ((t = s->ts_next) == 0
						  || t->staff != s->staff
						  || t->time != s->time))
							s->multi = -1;
					}
				}
			}
		}

		while (s) {
			switch (s->type) {
			case STAVES:
				sy = sy->next;
				for (staff = nst + 1; staff <= sy->nstaff; staff++) {
					stb[staff].nvoice = -1;
					for (i = 4; --i >= 0; ) {
						stb[staff].st[i].voice = -1;
						stb[staff].st[i].ymx = 0;
						stb[staff].st[i].ymn = 24;
					}
				}
				nst = sy->nstaff;
				/*fall thru*/
			case BAR:
				s = s->ts_next;
				continue;
			}
			break;
		}
	}
}

/* -- shift a rest vertically or horizontally -- */
static void shift_rest(struct SYMBOL *s,	/* rest */
			struct SYMBOL *s2,	/* other note/rest */
			struct SYSTEM *sy)
{
	int y, us, ls, ymx, ymn;

	us = rest_sp[C_XFLAGS - s->nflags].u;
	ls = rest_sp[C_XFLAGS - s->nflags].l;

	/* check if clash */
	ymx = s->y + us;
	ymn = s->y - ls;
	if (ymx < s2->ymn
	 || ymn > s2->ymx)
		return;			/* no */

	/* decide to move the rest upper or lower
	 * according to the voice ranges */
	if (sy->voice[s->voice].range > sy->voice[s2->voice].range)
		ymx = s2->ymn;			/* lower */
	else
		ymx = s2->ymx;			/* upper */

	/* change the rest vertical offset */
	if (ymx >= s2->ymx) {
		y = (s2->ymx + ls + 3) / 6 * 6;
		if (y < 12)
			y = 12;
		if (s->y < y)
			s->y = y;
	} else {
		y = (s2->ymn - us - 3) / 6 * 6;
		if (y > 12)
			y = 12;
		if (s->y > y)
			s->y = y;
	}
	s->ymx = s->y + us;
	s->ymn = s->y - ls;
}

/* -- adjust the offset of the rests when many voices -- */
/* this function is called only once per tune */
static void set_rest_offset(void)
{
#if 1 // 7.6.8
	struct SYSTEM *sy;
	struct SYMBOL *s, *s2, *prev;
	int nvoice, voice, end_time, not_alone;
	struct {
		struct SYMBOL *s;
		int staff;
		int end_time;
	} vtb[MAXVOICE], *v;

	memset(vtb, 0, sizeof vtb);
	
	sy = cursys;
	nvoice = 0;
	for (s = tsfirst; s; s = s->ts_next) {
		v = &vtb[s->voice];
		if (s->as.flags & ABC_F_INVIS)
			continue;
		switch (s->type) {
		case STAVES:
			sy = sy->next;
		default:
			continue;
		case NOTEREST:
			break;
		}
		if (s->voice > nvoice)
			nvoice = s->voice;
		v->s = s;
		v->staff = s->staff;
		v->end_time = s->time + s->dur;
		if (s->as.type != ABC_T_REST)
			continue;

		/* check if clash with previous symbols */
		not_alone = 0;
		prev = NULL;
		for (voice = 0, v = vtb; voice <= nvoice; voice++, v++) {
			if (!v->s
			 || v->staff != s->staff
			 || voice == s->voice)
				continue;
			if (v->end_time <= s->time)
				continue;
			not_alone++;
			shift_rest(s, v->s, sy);
			if (voice < s->voice && v->s->time == s->time)
				prev = v->s;
		}

		/* check if clash with next symbols */
		end_time = s->time + s->dur;
		for (s2 = s->ts_next; s2; s2 = s2->ts_next) {
			if (s2->time >= end_time)
				break;
			if (s2->staff != s->staff
			 || s2->type != NOTEREST
			 || (s2->as.flags & ABC_F_INVIS))
				continue;
			not_alone++;
			if (s2->as.type != ABC_T_REST) {
				shift_rest(s, s2, sy);

				/* shift to the right if same time and clash */
				if (prev
				 && s2->time == s->time
				 && (s2->ymx > s->ymn
				  || prev->ymn < s->ymx)) {
					int y;

					s->shhd[0] = 10;
					s->xmx = 10;
					y = (prev->ymn + s2->ymx) / 2;
					if (y < 12)
						y += 5;
					s->y = y / 6 * 6;
					s->ymx = s->y + 8;
					s->ymn = s->y - 8;
				}
			}
		}
		if (!not_alone) {
			s->y = 12;
			s->ymx = 12 + 8;
			s->ymn = 12 - 8;
		}
	}
#else
	struct SYSTEM *sy;
	struct SYMBOL *s, *s2, *s3, *s4;
	int i, j, staff, nstaff, rvoice, voice;
	int next_time, delta_time;
	struct {
		int nvoice;
		struct {
			int voice;
			short ymn;
			short ymx;
		} st[4];		/* (no more than 4 voices per staff) */
	} stb[MAXSTAFF];
	struct {
		signed char st1, st2;	/* (a voice cannot be on more than 2 staves) */
	} vtb[MAXVOICE];

	s = tsfirst;
	sy = cursys;
	nstaff = sy->nstaff;
	delta_time = BASE_LEN / 4;	/* crotchet */
	if (voice_tb[cursys->top_voice].meter.wmeasure > BASE_LEN)
		delta_time *= 2;	/* measure longer than 4/4 */
	while (s) {

		/* skip to the next visible note/rest */
		for ( ; s; s = s->ts_next) {
			if (s->type == NOTEREST
			 && !(s->as.flags & ABC_F_INVIS))
				break;
		}
		if (!s)
			break;

		for (staff = nstaff; staff >= 0; staff--) {
			stb[staff].nvoice = -1;
			for (i = 4; --i >= 0; ) {
				stb[staff].st[i].voice = -1;
				stb[staff].st[i].ymx = 0;
				stb[staff].st[i].ymn = 24;
			}
		}
		for (i = 0; i < MAXVOICE; i++)
			vtb[i].st1 = vtb[i].st2 = -1;

		/* get the max/min offsets in the sequence */
/*fixme: the stem height is not calculated yet*/
		next_time = s->time + delta_time;
		for (s2 = s;
		     s2 && s2->time < next_time
			&& s2->type != BAR && s2->type != STAVES;
		     s2 = s2->ts_next) {
			if (s2->type != NOTEREST
			 || (s2->as.flags & ABC_F_INVIS))
				continue;
			if (s2->time + s2->dur > next_time)
				next_time = s2->time + s2->dur;
			staff = s2->staff;
#if 1
/*fixme:test*/
if (staff > nstaff) {
	bug("set_rest_offset(): bad staff number\n", 1);
}
#endif
			voice = s2->voice;
			if (vtb[voice].st1 < 0) {
				vtb[voice].st1 = staff;
			} else if (vtb[voice].st1 != staff) {
				if (staff > vtb[voice].st1) {
					if (staff > vtb[voice].st2)
						vtb[voice].st2 = staff;
				} else {
					if (vtb[voice].st1 > vtb[voice].st2)
						vtb[voice].st2 = vtb[voice].st1;
					vtb[voice].st1 = staff;
				}
			}
			rvoice = sy->voice[voice].range;
			for (i = stb[staff].nvoice; i >= 0; i--) {
				if (stb[staff].st[i].voice == rvoice)
					break;
			}
			if (i < 0) {
				if (++stb[staff].nvoice >= 4)
					bug("Too many voices per staff", 1);
				for (i = 0; i < stb[staff].nvoice; i++) {
					if (rvoice < stb[staff].st[i].voice) {
						memmove(&stb[staff].st[i + 1],
							&stb[staff].st[i],
							sizeof stb[staff].st[i] *
								(stb[staff].nvoice - i));
						stb[staff].st[i].ymx = 0;
						stb[staff].st[i].ymn = 24;
						break;
					}
				}
				stb[staff].st[i].voice = rvoice;
			}

			if (s2->as.type != ABC_T_NOTE) {

				/* avoid clash of rest on a whole measure */
				if (s2->next && s2->next->type == BAR
				 && s2->next->time > next_time)
					next_time = s2->next->time;
				continue;
			}

			if (s2->ymx > stb[staff].st[i].ymx)
				stb[staff].st[i].ymx = s2->ymx;
			if (s2->ymn < stb[staff].st[i].ymn)
				stb[staff].st[i].ymn = s2->ymn;

			/* if beamed notes, continue to the next note */
			if (!(s2->sflags & S_BEAM_END)) {
				if (s2->time + s2->dur + s2->next->dur > next_time)
					next_time = s2->time + s2->dur + s2->next->dur;
			}
		}

		for ( ; s != s2; s = s->ts_next) {
			int us, ls, not_alone, y;

			if (s->as.type != ABC_T_REST)
				continue;
			staff = s->staff;
			voice = s->voice;
			if (stb[staff].nvoice <= 0) {	/* voice alone on the staff */
				s->y = 12;
				s->ymx = 12 + 8;
				s->ymn = 12 - 8;
				continue;
			}
			rvoice = sy->voice[voice].range;
			for (i = stb[staff].nvoice; i >= 0; i--) {
				if (stb[staff].st[i].voice == rvoice)
					break;
			}
			if (i < 0)
				continue;		/* voice ignored */
/*fixme:do this later because the stem heights are not yet calculated */

			/* if one visible rest and only invisible ones
			 * or (rests only and combinevoices == 0)
			 * at the same time on the same staff,
			 * set as if one rest only */
			if (i == 0) {		/* check the 1st rest only */
				not_alone = stb[staff].nvoice + 1;
				if (cfmt.combinevoices >= 0)
					not_alone += 31;
				s4 = NULL;
				for (s3 = s; s3 != s2; s3 = s3->ts_next) {
					if (s3->staff != staff
					 || s3->time != s->time)
						break;
					if (s3->as.type != ABC_T_REST
//??					 || s3->dur < s->dur) {
					 || s3->dur != s->dur) {
						not_alone = 127;
						break;
					}
					if (!(s3->as.flags & ABC_F_INVIS)
					 && cfmt.combinevoices >= 0) {
						s4 = s3;
						not_alone -= 32;
						continue;
					}
//??
//					rvoice = sy->voice[s3->voice].range;
//					for (j = stb[staff].nvoice; j >= 0; j--) {
//						if (stb[staff].st[j].voice == rvoice) {
//							not_alone--;
//							break;
//						}
//					}
					not_alone--;
				}
				if (not_alone == 0) {
					if (!s4) {	/* combinevoices < 0 */
						for (s4 = s->ts_next;
						     s4 != s3;
						     s4 = s4->ts_next)
							s4->as.flags |= ABC_F_INVIS;
						s4 = s;
						s4->as.flags &= ~ABC_F_INVIS;
					}
					s4->y = 12;
					s4->ymx = 12 + 8;
					s4->ymn = 12 - 8;
					s = s3->ts_prev;	/* skip the rests */
					continue;
				}
			}
			if (s->as.flags & ABC_F_INVIS)
				continue;

			/* set the rest vertical offset */
			us = rest_sp[C_XFLAGS - s->nflags].u;
			ls = rest_sp[C_XFLAGS - s->nflags].l;

			if (i == 0) {			/* first voice */
				if (stb[staff].st[0].ymx < stb[staff].st[0].ymn
				 || stb[staff].st[0].ymx >= stb[staff].st[1].ymn) {
					y = stb[staff].st[1].ymx;
					for (j = 2; j <= stb[staff].nvoice; j++) {
						if (y < stb[staff].st[j].ymx)
							y = stb[staff].st[j].ymx;
					}
					y = (y + ls + 3) / 6 * 6;
					if (y < 12)
						y = 12;
					if (y > s->y)
						s->y = y;
				} else {		/* voices inverted */
					y = (stb[staff].st[0].ymx
						+ stb[staff].st[0].ymn) / 2;
					y = (y - us) / 6 * 6;
					if (y > 12)
						y = 12;
					if (y < s->y)
						s->y = y;
				}
			} else if (i == stb[staff].nvoice) { /* last voice */
				if (stb[staff].st[i].ymx < stb[staff].st[i].ymn
				 || stb[staff].st[i].ymn <= stb[staff].st[i - 1].ymx) {
					y = stb[staff].st[i - 1].ymn;
					for (j = i - 2; j >= 0; j--) {
						if (y > stb[staff].st[j].ymn)
							y = stb[staff].st[j].ymn;
					}
					y = (y - us) / 6 * 6;
					if (y > 12)
						y = 12;
					if (y < s->y)
						s->y = y;
				} else {		/* voices inverted */
					y = (stb[staff].st[i].ymx
						+ stb[staff].st[i].ymn) / 2;
					y = (y + ls) / 6 * 6;
					if (y < 12)
						y = 12;
					if (y > s->y)
						s->y = y;
				}
			} else {			/* middle voice */
/*fixme: may be too high*/
				y = (stb[staff].st[i - 1].ymn
						+ stb[staff].st[i + 1].ymx)
					/ 12 * 6;
				s->y = y;
				s3 = s->ts_next;
				if ((s3
				  && s3->staff == staff
				  && s3->time == s->time
				  && s3->dur != 0
				  && !(s3->as.flags & ABC_F_INVIS)
				  && s3->ymx > s->y - ls)
				 || (s->ts_prev->staff == staff
				  && s->ts_prev->time == s->time
				  && s->ts_prev->dur != 0
				  && !(s->ts_prev->as.flags & ABC_F_INVIS)
				  && s->ts_prev->ymn < s->y + us)) {
					s->shhd[0] = 10;
					s->xmx = 10;
				}
			}
			s->ymx = s->y + us;
			if (s->ymx > stb[staff].st[i].ymx)
				stb[staff].st[i].ymx = s->ymx;
			s->ymn = s->y - ls;
			if (s->ymn < stb[staff].st[i].ymn)
				stb[staff].st[i].ymn = s->ymn;
		}

		while (s) {
			switch (s->type) {
			case STAVES:
				sy = sy->next;
//				for (staff = nstaff + 1; staff <= sy->nstaff; staff++) {
//					stb[staff].nvoice = -1;
//					for (i = 4; --i >= 0; ) {
//						stb[staff].st[i].voice = -1;
//						stb[staff].st[i].ymx = 0;
//						stb[staff].st[i].ymn = 24;
//					}
//				}
				nstaff = sy->nstaff;
				/*fall thru*/
			case BAR:
				s = s->ts_next;
				continue;
			}
			break;
		}
	}
#endif
}

/* -- create a starting symbol -- */
static struct SYMBOL *sym_new(int type,
				struct VOICE_S *p_voice,
				struct SYMBOL *last_s)	/* same time */
{
	struct SYMBOL *s;

	s = (struct SYMBOL *) getarena(sizeof *s);
	memset(s, 0, sizeof *s);
	s->type = type;
	s->voice = p_voice - voice_tb;
	s->staff = p_voice->staff;
	s->time = last_s->time;

	s->next = p_voice->last_sym->next;
	if (s->next)
		s->next->prev = s;
	p_voice->last_sym->next = s;
	s->prev = p_voice->last_sym;
	p_voice->last_sym = s;

	s->ts_next = last_s;
	s->ts_prev = last_s->ts_prev;
	s->ts_prev->ts_next = s;
	if (s->ts_prev->type != type)
		s->sflags |= S_SEQST;
	last_s->ts_prev = s;
	if (last_s->type == type && s->voice != last_s->voice) {
		last_s->sflags &= ~S_SEQST;
		last_s->shrink = 0;
	}
	s->as.fn = last_s->as.fn;
	s->as.linenum = last_s->as.linenum;
	s->as.colnum = last_s->as.colnum;
	return s;
}

/* -- init the symbols at start of a music line -- */
/* this routine is called starting a tune generation,
 * and it is called later for each new music line */
static void init_music_line(void)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *s, *last_s;
	int voice, staff;

	/* initialize the voices */
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		voice = p_voice - voice_tb;
		if (cursys->voice[voice].range < 0)
			continue;
		p_voice->second = cursys->voice[voice].second;
		staff = cursys->voice[voice].staff;
		while (staff < nstaff && cursys->staff[staff].empty)
			staff++;
		p_voice->staff = staff;
		s = p_voice->sym;
		if (!s)
			continue;
		if (s->type == CLEF) {		/* move the clefs and keysig's */
			if (!p_voice->second) {
				cursys->staff[staff].clef.type
					= s->as.u.clef.type;
				cursys->staff[staff].clef.line
					= s->as.u.clef.line;
				cursys->staff[staff].clef.octave
					= s->as.u.clef.octave;
				cursys->staff[staff].clef.invis
					= s->as.u.clef.invis;
			}
			s = s->next;
			if (!s)
				continue;
		}
		if (s->type == KEYSIG)
			memcpy(&p_voice->key, &s->as.u.key,
				sizeof s->as.u.key);
	}

	/* add a clef at start of each voice */
	last_s = tsfirst;
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		voice = p_voice - voice_tb;
		if (cursys->voice[voice].range < 0)
			continue;
		staff = cursys->voice[voice].staff;
		if (last_s->voice == voice && last_s->type == CLEF) {
			last_s->u = 0;		/* normal clef */
#if 0
			if (cursys->staff[staff].clef.invis)
				s->as.flags |= ABC_F_INVIS;
#endif
			p_voice->last_sym = last_s;
			last_s = last_s->ts_next;
		} else {
			s = (struct SYMBOL *) getarena(sizeof *s);
			memset(s, 0, sizeof *s);
			s->type = CLEF;
			s->voice = voice;
			s->staff = staff;
			s->time = last_s->time;
			s->next = p_voice->sym;
			if (s->next) {
				s->next->prev = s;
				s->as.fn = s->next->as.fn;
				s->as.linenum = s->next->as.linenum;
				s->as.colnum = s->next->as.colnum;
			}
			p_voice->sym = s;
			p_voice->last_sym = s;
			s->ts_next = last_s;
			s->ts_prev = last_s->ts_prev;
			if (!s->ts_prev) {
				tsfirst = s;
				s->sflags |= S_SEQST;
			} else {
				s->ts_prev->ts_next = s;
			}
			last_s->ts_prev = s;
			if (last_s->type == CLEF)
				last_s->sflags &= ~S_SEQST;
			memcpy(&s->as.u.clef,
				&cursys->staff[staff].clef,
				sizeof s->as.u.clef);
			if (cursys->voice[voice].second)
				s->sflags |= S_SECOND;
			if (cursys->staff[staff].clef.invis
			 || cursys->staff[staff].empty)
				s->as.flags |= ABC_F_INVIS;
			set_yval(s);
		}
	}

	/* add keysig */
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		voice = p_voice - voice_tb;
		if (cursys->voice[voice].range < 0
		 || cursys->voice[voice].second
		 || cursys->staff[cursys->voice[voice].staff].empty)
			continue;
		if (last_s->voice == voice && last_s->type == KEYSIG) {
			p_voice->last_sym = last_s;
			last_s = last_s->ts_next;
			continue;
		}
		if (p_voice->key.sf != 0 || p_voice->key.nacc != 0) {
			s = sym_new(KEYSIG, p_voice, last_s);
			memcpy(&s->as.u.key, &p_voice->key, sizeof s->as.u.key);
			if (s->as.u.key.mode == BAGPIPE + 1)
				s->u = 3;	/* K:Hp --> G natural */
			set_yval(s);
		}
	}

	/* add time signature if needed */
	if (insert_meter & 1) {
		for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
			voice = p_voice - voice_tb;
			if (cursys->voice[voice].range < 0
			 || cursys->voice[voice].second
			 || cursys->staff[cursys->voice[voice].staff].empty
			 || p_voice->meter.nmeter == 0)		/* M:none */
				continue;
			if (last_s->voice == voice && last_s->type == TIMESIG) {
				p_voice->last_sym = last_s;
				last_s = last_s->ts_next;
				continue;
			}
			s = sym_new(TIMESIG, p_voice, last_s);
			memcpy(&s->as.u.meter, &p_voice->meter,
			       sizeof s->as.u.meter);
			set_yval(s);
		}
	}

	/* add bar if needed */
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		int i;

		voice = p_voice - voice_tb;
		if (cursys->voice[voice].range < 0
		 || cursys->voice[voice].second
		 || cursys->staff[cursys->voice[voice].staff].empty
		 || p_voice->bar_start == 0)
			continue;
		i = 2;
		if (!p_voice->bar_text		/* if repeat continuation */
		 && p_voice->bar_start == B_OBRA) {
			for (s = p_voice->last_sym;
			     s;
			     s = s->next) {	/* search the end of repeat */
				if (s->sflags & S_RBSTOP) {
					i = -1;
					break;
				}
				if (s->type != BAR)
					continue;
				if ((s->as.u.bar.type & 0xf0)	/* if complex bar */
				 || s->as.u.bar.type == B_CBRA
				 || s->as.u.bar.repeat_bar)
					break;
				if (--i < 0)
					break;
			}
			if (!s)
				i = -1;
			if (i >= 0 && p_voice->last_sym->time == s->time)
				i = -1;		/* no note */
		}
		if (i >= 0) {
			s = sym_new(BAR, p_voice, last_s);
			s->as.u.bar.type = p_voice->bar_start & 0x3fff;
			if (p_voice->bar_start & 0x8000)
				s->as.flags |= ABC_F_INVIS;
			if (p_voice->bar_start & 0x4000)
				s->sflags |= S_NOREPBRA;
			s->as.text = p_voice->bar_text;
			s->gch = p_voice->bar_gch;
			s->as.u.bar.repeat_bar = p_voice->bar_repeat;
			set_yval(s);
		}
		p_voice->bar_start = 0;
		p_voice->bar_repeat = 0;
		p_voice->bar_text = 0;
		p_voice->bar_gch = 0;
	}

	/* if initialization of a new music line, compute the spacing,
	 * including the first (old) sequence */
//	if (tsnext) {		/* (if called from cut_symbols()) */
		set_pitch(last_s);
		s = last_s;
		if (s) {
			for ( ; s; s = s->ts_next)
				if (s->sflags & S_SEQST)
					break;
			if (s)
			    for (s = s->ts_next; s; s = s->ts_next)
				if (s->sflags & S_SEQST)
					break;
		}
		set_allsymwidth(s);	/* set the width of the added symbols */
//	}
}

/* -- initialize the generator -- */
/* this function is called only once per tune  */
static void set_global(void)
{
	struct SYSTEM *sy;
	struct SYMBOL *s;
	struct VOICE_S *p_voice;
	int staff;
	static const signed char delpit[4] = {0, -7, -14, 0};

	/* get the max number of staves */
	sy = cursys;
	staff = cursys->nstaff;
	while ((sy = sy->next) != 0) {
		if (sy->nstaff > staff)
			staff = sy->nstaff;
	}
	nstaff = staff;

	/* adjust the pitches if old abc2ps behaviour of clef definition */
	if (cfmt.abc2pscompat) {
		int i;

		for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
			int delta;
			struct SYMBOL *g;

			if (!p_voice->forced_clef
			 || p_voice->octave != 0)
				continue;
#if 1
			/* (the clefs in the voice table are not yet initialized) */
			i = p_voice->staff;
			i = cursys->staff[i].clef.type;
#else
			i = p_voice->clef.type;
#endif
			if (i == PERC)
				continue;
			delta = delpit[i];
			for (s = p_voice->sym; s; s = s->next) {
				switch (s->type) {
				case CLEF:
					i = s->as.u.clef.type;
					if (!s->as.u.clef.check_pitch)
						i = 0;
					delta = delpit[i];
					break;
				case NOTEREST:
					if (delta == 0)
						break;
					if (s->as.type == ABC_T_REST)
						break;
					for (i = s->nhd; i >= 0; i--)
						s->pits[i] += delta;
					break;
				case GRACE:
					if (delta == 0)
						break;
					for (g = s->extra; g; g = g->next) {
						if (g->type != NOTEREST)
							continue;
						for (i = g->nhd; i >= 0; i--)
							g->pits[i] += delta;
					}
					break;
				}
			}
		}
	}

	/* set a pitch for all symbols and the start/stop of words (beams) */
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		int pitch, start_flag;
		struct SYMBOL *sym, *lastnote;

		sym = p_voice->sym;
		for (s = sym; s; s = s->next) {
			if (s->as.type == ABC_T_NOTE) {
				pitch = s->pits[0];
				break;
			}
		}
		if (!s)
			pitch = 127;			/* no note */
		start_flag = 1;
		lastnote = 0;
		for (s = sym; s; s = s->next) {
			switch (s->type) {
			default:
				if (s->as.flags & ABC_F_SPACE)
					start_flag = 1;
				break;
			case MREST:
				start_flag = 1;
				break;
			case BAR:
				if (!(s->sflags & S_BEAM_ON))
					start_flag = 1;
				if (!s->next && s->prev
				 && s->prev->as.type == ABC_T_NOTE
				 && s->prev->dur >= BREVE)
					s->prev->head = H_SQUARE;
				break;
			case NOTEREST:
				if (s->sflags & S_TREM2)
					break;
				if (s->as.flags & ABC_F_SPACE)
					start_flag = 1;
				if (start_flag
				 || s->nflags - s->u <= 0) {
					if (lastnote) {
						lastnote->sflags |= S_BEAM_END;
						lastnote = NULL;
					}
					if (s->nflags - s->u <= 0) {
						s->sflags |= (S_BEAM_ST | S_BEAM_END);
					} else if (s->as.type == ABC_T_NOTE) {
						s->sflags |= S_BEAM_ST;
						start_flag = 0;
					}
				}
				if (s->sflags & S_BEAM_END)
					start_flag = 1;
				if (s->as.type == ABC_T_NOTE)
					lastnote = s;
				break;
			}
			if (s->as.type == ABC_T_NOTE) {
				pitch = s->pits[0];
				if (s->prev
				 && s->prev->as.type != ABC_T_NOTE) {
					s->prev->pits[0] = (s->prev->pits[0]
							    + pitch) / 2;
				}
			} else {
				s->pits[0] = pitch;
			}
		}
		if (lastnote)
			lastnote->sflags |= S_BEAM_END;
	}

	/* set the staff of the floating voices */
	set_float();

	/* set the clefs */
	if (cfmt.autoclef) {
		for (p_voice = first_voice; p_voice; p_voice = p_voice->next)
			if (p_voice->forced_clef)
				staff_tb[p_voice->staff].forced_clef = 1;
		for (staff = 0; staff <= nstaff; staff++) {
			if (!staff_tb[staff].forced_clef)
				set_clef(staff);
		}
	}

	/* set a pitch to the symbols of voices with no note */
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		int pitch;
		struct SYMBOL *sym;

		sym = p_voice->sym;
		if (!sym || sym->pits[0] != 127)
			continue;
		switch (cursys->staff[sym->staff].clef.type) {
		default:
		case TREBLE:
			pitch = 22;		/* 'B' */
			break;
		case ALTO:
			pitch = 16;		/* 'C' */
			break;
		case BASS:
			pitch = 10;		/* 'D,' */
			break;
		}
		for (s = sym; s; s = s->next)
			s->pits[0] = pitch;
	}


//fixme:initmusic_line
//	init_music_line();
//	insert_meter &= ~1;		/* keep the 'first line' flag */
	set_pitch(NULL);		/* adjust the note pitches */
}

/* -- return the left indentation of the staves -- */
static float set_indent(int keep)
{
	int staff, voice;
	float w, maxw;
	struct VOICE_S *p_voice;
	char *p, *q;

	maxw = 0;
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		voice = p_voice - voice_tb;
		if (cursys->voice[voice].range < 0)
			continue;
		staff = cursys->voice[voice].staff;
		if (cursys->staff[staff].empty)
			continue;
		if ((p = p_voice->new_name ? p_voice->nm : p_voice->snm) == NULL)
			continue;
		str_font(VOICEFONT);
		for (;;) {
			if ((q = strstr(p, "\\n")) != NULL)
				*q = '\0';
			w = tex_str(p);
			if (w > maxw)
				maxw = w;
			if (!q)
				break;
			*q = '\\';
			p = q + 2;
		}
	}

	if (maxw != 0) {
		w = 0;
		for (staff = 0; staff <= nstaff; staff++) {
			if (cursys->staff[staff].flags
					& (OPEN_BRACE2 | OPEN_BRACKET2)) {
				w = 20;
				break;
			}
			if ((cursys->staff[staff].flags
					& (OPEN_BRACE | OPEN_BRACKET))
			 && w == 0)
				w = 10;
		}
		maxw += 4 * cwid(' ') * cfmt.font_tb[VOICEFONT].swfac + w;
	}
	if (insert_meter & 2) {			/* if indent */
		maxw += cfmt.indent;
//		if (!keep)
//			insert_meter &= ~2;
	}
	return maxw;
}

/* -- decide on beams and on stem directions -- */
/* this routine is called only once per tune */
static void set_beams(struct SYMBOL *sym)
{
	struct SYMBOL *s, *t, *g, *s_opp;
	int beam, laststem, lasty;

	beam = 0;
	laststem = -1;
	lasty = 0;
	s_opp = NULL;
	for (s = sym; s; s = s->next) {
		if (s->as.type != ABC_T_NOTE) {
			if (s->type != GRACE)
				continue;
			g = s->extra;
			while (g->as.type != ABC_T_NOTE)
				g = g->next;
			if (g->stem == 2) {	/* opposite gstem direction */
				s_opp = s;
				continue;
			}
			if (s->stem == 0
			 && (s->stem = s->multi) == 0)
				s->stem = 1;
			for (; g; g = g->next) {
				g->stem = s->stem;
				g->multi = s->multi;
			}
			continue;
		}

		if (s->stem == 0		/* if not explicitly set */
		 && (s->stem = s->multi) == 0) { /* and alone on the staff */

			/* notes in a beam have the same stem direction */
			if (beam) {
				s->stem = laststem;
			} else if ((s->sflags & (S_BEAM_ST | S_BEAM_END))
					== S_BEAM_ST) { /* start of beam */
				int avg, n;

				avg = s->yav;
				n = 12;
				for (t = s->next; t; t = t->next) {
					if (t->as.type == ABC_T_NOTE) {
						if (t->multi) {
							avg = n - t->multi;
							break;
						}
						avg += t->yav;
						n += 12;
					}
					if (t->sflags & S_BEAM_END)
						break;
				}
				if (avg < n)
					laststem = 1;
				else if (avg > n || cfmt.bstemdown)
					laststem = -1;
				beam = 1;
				s->stem = laststem;
			} else {
				s->stem = s->yav >= 12 ? -1 : 1;
				if (s->yav == 12	/* note on middle line */
				 && !cfmt.bstemdown) {
					int dy;

					if (!s->prev || s->prev->type == BAR) {
						for (t = s->next; t; t = t->next) {
							if (t->as.type == ABC_T_NOTE
							 || t->type == BAR)
								break;
						}
						if (t && t->as.type == ABC_T_NOTE
						 && t->yav < 12)
							s->stem = 1;
					} else {
						dy = s->yav - lasty;
						if (dy > -7 && dy < 7)
							s->stem = laststem;
					}
				}
			}
		} else {			/* stem set by set_stem_dir */
			if ((s->sflags & (S_BEAM_ST | S_BEAM_END))
					== S_BEAM_ST) /* start of beam */
				beam = 1;
		}
		if (s->sflags & S_BEAM_END)
			beam = 0;
		laststem = s->stem;
		lasty = s->yav;

		if (s_opp) {			/* opposite gstem direction */
			for (g = s_opp->extra; g; g = g->next)
				g->stem = -laststem;
			s_opp->stem = -laststem;
			s_opp = NULL;
		}
	}
}

/* -- shift the notes horizontally when voices overlap -- */
/* this routine is called only once per tune */
static void set_overlap(void)
{
	struct SYMBOL *s, *s1, *s2;
	int d, i1, i2, m, sd1, sd2, t;
	float d1, d2, dy1, dy2, noteshift;

	for (s = tsfirst; s; s = s->ts_next) {
		if (s->as.type != ABC_T_NOTE
		 || (s->as.flags & ABC_F_INVIS))
			continue;

		/* treat the stem on two staves with different directions */
		if ((s->sflags & S_XSTEM)
		 && s->ts_prev->stem < 0) {
			s2 = s->ts_prev;
			for (m = 0; m <= s2->nhd; m++) {
				s2->shhd[m] += STEM_XOFF * 2;
				s2->shac[m] -= STEM_XOFF * 2;
			}
			s2->xmx += STEM_XOFF * 2;
		}

		/* search the next note at the same time on the same staff */
		s2 = s;
		for (;;) {
			s2 = s2->ts_next;
			if (!s2)
				break;
			if (s2->time != s->time) {
				s2 = NULL;
				break;
			}
			if (s2->as.type == ABC_T_NOTE
			 && !(s2->as.flags & ABC_F_INVIS)
			 && s2->staff == s->staff)
				break;
		}
		if (!s2)
			continue;

		sd1 = sd2 = 0;
		d1 = d2 = dy1 = dy2 = 0;
		s1 = s;

		/* set the smallest interval type */
		t = 0;		/* t: interval types
				 *	0: >= 4
				 *	1: third or fourth
				 *	2: second
				 *	4: unison
				 *	-1: unison and different accidentals */
		{
			int dp;

			i1 = s1->nhd;
			i2 = s2->nhd;
			for (;;) {
				dp = s1->pits[i1] - s2->pits[i2];
				switch (dp) {
				case 0:
					if (s1->as.u.note.accs[i1] != s2->as.u.note.accs[i2])
						t = -1;
					else
						t |= 4;
					break;
				case 1:
				case -1:
					t |= 2;
					break;
				case 2:
				case -2:
				case 3:
				case -3:
					t |= 1;
					break;
				}
				if (t < 0)
					break;
				if (dp >= 0) {
					i1--;
					if (i1 < 0)
						break;
				}
				if (dp <= 0) {
					i2--;
					if (i2 < 0)
						break;
				}
			}
		}
		if (s1->dur >= BREVE || s2->dur >= BREVE) {
			noteshift = 13;
		} else {

			/* if the 2nd voice is far enough, don't shift it */
			if (t == 0 && s1->pits[0] > s2->pits[s2->nhd]
			 && s1->stem > 0 && s2->stem < 0)
				continue;
			if (s1->dur >= SEMIBREVE || s2->dur >= SEMIBREVE) {
				noteshift = 10;
			} else {
				if (t == 1 && s1->pits[0] > s2->pits[s2->nhd]
				 && s1->stem > 0 &&  s2->stem < 0) {
					if (s1->shac[0] < 8)
						s1->shac[0] += 5;
					if (s1->as.u.note.accs[0] != 0
					 && s2->as.u.note.accs[s2->nhd] != 0)
						s2->shac[s2->nhd] += 10;
					continue;
				}
				noteshift = 7.8;
			}
		}

		/* if unison and different accidentals */
		if (t < 0) {
			if (s2->as.u.note.accs[i2] == 0) {
				d1 = noteshift + s2->xmx + s1->shac[i1];
				if (s1->as.u.note.accs[i1] & 0xf8)
					d1 += 2;
				if (s2->dots)
					d1 += 6;
				for (m = 0; m <= s1->nhd; m++) {
					s1->shhd[m] += d1;
					s1->shac[m] -= d1;
				}
				s1->xmx += d1;
			} else {
				d2 = noteshift + s1->xmx + s2->shac[i2];
				if (s2->as.u.note.accs[i2] & 0xf8)
					d2 += 2;
				if (s1->dots)
					d2 += 6;
				for (m = 0; m <= s2->nhd; m++) {
					s2->shhd[m] += d2;
					s2->shac[m] -= d2;
				}
				s2->xmx += d2;
			}
			s2->doty = -3;
			continue;
		}

		if (s1->stem * s2->stem > 0) {	/* if same stem direction */
			d2 = noteshift + 2;	/* shift the 2nd voice */
			if (s1->dur < CROTCHET
			 && (s1->sflags & (S_BEAM_ST | S_BEAM_END))
					== (S_BEAM_ST | S_BEAM_END)) { /* if a flag */
				if (s1->stem > 0) {
					if (3 * (s1->pits[s1->nhd] - 18) > s2->ymx) {
						d2 *= 0.5;
						sd1 = -1;
					} else if (s1->pits[s1->nhd] <= s2->pits[s2->nhd]) {
						d2 += noteshift;
					}
				}
			} else {			/* no flag */
				if (s1->pits[0] > s2->pits[s2->nhd] + 1) {
					d2 *= 0.5;
					sd1 = -1;
				}
			}
		} else if (s->stem < 0) {	/* if stem inverted, */
			s1 = s2;		/* invert the voices */
			s2 = s;
		}

		d = s1->pits[0] - s2->pits[s2->nhd];
		if (d >= 0)
			dy2 = -3;	/* the dot of the 2nd voice shall be lower */

		if (s1->head == H_SQUARE || s2->head == H_SQUARE) {
			if (s1->ymn >= s2->ymx + 4
			 || s1->ymx <= s2->ymn - 4) {
				d2 = 0;
				goto do_shift;
			}
			if (s1->stem * s2->stem > 0)	/* if same stem direction */
				goto do_shift;
		} else {
			if (s1->ymn >= s2->ymx - 2
			 || s1->ymx <= s2->ymn + 2) {
				d2 = 0;
				goto do_shift;
			}
			if (s1->stem * s2->stem > 0)	/* if same stem direction */
				goto do_shift;
			if (d >= 2)
				goto do_shift;
		}
		/* (here, voice 1 stem up and voice 2 stem down) */

		/* if unison */
		if (t >= 4) {
			int l1, l2;

			if ((s1->sflags & (S_SHIFTUNISON_1 | S_SHIFTUNISON_2))
					== (S_SHIFTUNISON_1 | S_SHIFTUNISON_2))
				goto uni_shift;
			if ((l1 = s1->dur) >= SEMIBREVE)
				goto uni_shift;
			if ((l2 = s2->dur) >= SEMIBREVE)
				goto uni_shift;
			if (s1->as.flags & s2->as.flags & ABC_F_STEMLESS)
				goto uni_shift;
			if (s1->dots != s2->dots) {
				if ((s1->sflags & (S_SHIFTUNISON_1 | S_SHIFTUNISON_2))
				 || s1->dots * s2->dots != 0)
					goto uni_shift;
			}
			i2 = 0;
			while (i2 <= s2->nhd && s2->pits[i2] != s1->pits[0])
				i2++;
			if (i2 > s2->nhd)
				goto uni_shift;
			i1 = 0;
			while (i1 < s1->nhd && i1 + i2 < s2->nhd
			    && s2->pits[i1 + i2 + 1] == s1->pits[i1 + 1])
				i1++;
			if (i1 + i2 != s2->nhd)
				goto uni_shift;
			if (l1 == l2)
				goto same_head;
			if (l1 < l2) {
				l1 = l2;
				l2 = s1->dur;
			}
			if (l1 < MINIM) {
				if (s2->dots > 0) {
					dy2 = -3;
					goto head_2;
				}
				if (s1->dots > 0)
					goto head_1;
				goto same_head;
			}
			if (l2 < CROTCHET) {	/* (l1 >= MINIM) */
				if ((s1->sflags & S_SHIFTUNISON_2)
				 || s1->dots != s2->dots)
					goto uni_shift;
				if (s2->dur >= MINIM) {
					dy2 = -3;
					goto head_2;
				}
				goto head_1;
			}
			goto uni_shift;
		same_head:
			if (voice_tb[s1->voice].scale < voice_tb[s2->voice].scale)
				goto head_2;
		head_1:
			s2->nohdix = i2;	/* keep heads of 1st voice */
			for (; i2 <= s2->nhd; i2++)
				s2->as.u.note.accs[i2] = 0;
			goto do_shift;
		head_2:
			s1->nohdix = i1;	/* keep heads of 2nd voice */
			for (; i1 >= 0; i1--)
				s1->as.u.note.accs[i1] = 0;
			goto do_shift;
		}

		if (d == -1
		 && (s1->nhd == 0 || s1->pits[1] > s2->pits[s2->nhd])
		 && (s2->nhd == 0 || s1->pits[0] > s2->pits[s2->nhd - 1])) {
			if (!(s->as.flags & ABC_F_STEMLESS)) {
				d1 = noteshift;
				if (s2->dots && s1->dots == s2->dots) {
					sd2 = 1;
					dy1 = -3;
				}
			} else {
				d2 = noteshift;
			}
			goto do_shift;
		}

		if (t == 1) {			/* if third or fourth only */
			if (s1->head != H_SQUARE
			 && s2->head != H_SQUARE)
				t = 0;
		}
		if (t == 0) {			/* if small overlap */
			if (s1->dur < SEMIBREVE
			 && s2->dur < SEMIBREVE) {
				if (s2->dur < CROTCHET
				 && (s2->sflags & (S_BEAM_ST | S_BEAM_END))
						== (S_BEAM_ST | S_BEAM_END) /* if flag */
				 && s1->pits[0] < s2->pits[0]
				 && 3 * (s1->pits[s1->nhd] - 18) > s2->ymn)
					d1 = noteshift;
				else
					d1 = noteshift * 0.3;	// (was 0.6)
				if (s2->dots)
					sd2 = 1;
			} else {
				d2 = noteshift + 1.5;
				if (s1->dots)
					sd1 = 1;
			}
			goto do_shift;
		}

	uni_shift:
		if (t >= 2) {				/* if close or unison */
			if (s1->dots != s2->dots) {
				if (s1->dots > s2->dots) /* shift the voice with more dots */
					d1 = noteshift;
				else
					d2 = noteshift;
/*fixme:if second, see if dots may be distinguished?*/
			} else if (d == 1) {
				d2 = noteshift;
				if (s1->dots)
					sd1 = 1;
			} else {
				if (t >= 4		/* if unison */
				 && s1->stem >= 0)
					d2 = noteshift;
				else
					d1 = noteshift;
			}
			if (t >= 4) {			/* if unison */
				if (d1 != 0)
					d1 += 1.5;
				else
					d2 += 1.5;
			}
			goto do_shift;
		}

		/* if the upper note is SEMIBREVE or higher, shift it */
		if (s1->dur >= SEMIBREVE
		 && s1->dur > s2->dur) {
			d1 = noteshift;

		/* else shift the 2nd voice */
		} else {
			d2 = noteshift;
			if (s1->dots > 0
			 && (d != 1 || (s1->pits[0] & 1)))
/*fixme: d always != 1 ?*/
				sd1 = 1;	/* and the dot of the 1st voice */
		}

		/* do the shift, and update the width */
	do_shift:

		/* shift the accidentals */
		for (i1 = 0; i1 <= s1->nhd; i1++) {
			int dp;
			float shft;

			if (s1->as.u.note.accs[i1] == 0)
				continue;
			for (i2 = 0; i2 <= s2->nhd; i2++) {
				dp = s1->pits[i1] - s2->pits[i2];
				if (dp > 5 || dp < -5)
					continue;
				if (s2->as.u.note.accs[i2] == 0) {
					if (s2->shhd[i2] < 0
					 && dp == 3) {
						s1->shac[i1] = 9 + 7;
					}
					continue;
				}
				if (dp == 0) {
					s2->as.u.note.accs[i2] = 0;
					continue;
				}
				shft = (dp <= -4 || dp >= 4) ? 4.5 : 7;
				if (dp > 0) {
					if (s1->as.u.note.accs[i1] & 0xf8)
						shft += 2;
					if (s2->shac[i2] < s1->shac[i1] + shft
					 && s2->shac[i2] > s1->shac[i1] - shft)
						s2->shac[i2] = s1->shac[i1] + shft;
				} else {
					if (s2->as.u.note.accs[i2] & 0xf8)
						shft += 2;
					if (s1->shac[i1] < s2->shac[i2] + shft
					 && s1->shac[i1] > s2->shac[i2] - shft)
						s1->shac[i1] = s2->shac[i2] + shft;
				}
			}
		}

		/* handle the previous shift */
		m = s1->stem >= 0 ? 0 : s1->nhd;
		d1 -= s1->shhd[m];
		d2 += s1->shhd[m];
		m = s2->stem >= 0 ? 0 : s2->nhd;
		d1 += s2->shhd[m];
		d2 -= s2->shhd[m];

		if (d1 > 0) {			/* shift the 1st voice */
			if (s2->dots && sd2 == 0)	/* room for the dots */
				d1 += 8 + 3.5 * (s2->dots - 1);
			for (m = s1->nhd; m >= 0; m--)
				s1->shhd[m] += d1;
			s1->xmx += d1;
			if (sd2 != 0)
				s2->xmx = s1->xmx;
		}
		if (d2 > 0) {			/* shift the 2nd voice */
			if (s1->dots && sd1 == 0)	/* room for the dots */
				d2 += 8 + 3.5 * (s1->dots - 1);
			for (m = s2->nhd; m >= 0; m--) {
				s2->shhd[m] += d2;
				if (s2->as.u.note.accs[m] != 0
				 && s2->pits[m] < s1->pits[0] - 4)
					s2->shac[m] -= d2;
			}
			s2->xmx += d2;
			if (sd1 > 0)
				s1->xmx = s2->xmx;
		}
		s1->doty = dy1;
		s2->doty = dy2;
	}
}

/* -- set the stem lengths -- */
/* this routine is called only once per tune */
static void set_stems(void)
{
	struct SYMBOL *s, *s2, *g;
	float slen, scale;
	int ymn, ymx, nflags;

	for (s = tsfirst; s; s = s->ts_next) {
		if (s->as.type != ABC_T_NOTE) {
			int ymin, ymax;

			if (s->type != GRACE)
				continue;
			ymin = ymax = 12;
			for (g = s->extra; g; g = g->next) {
				if (g->type != NOTEREST)
					continue;
				slen = GSTEM;
				if (g->nflags > 1)
					slen += 1.2 * (g->nflags - 1);
				ymn = 3 * (g->pits[0] - 18);
				ymx = 3 * (g->pits[g->nhd] - 18);
				if (s->stem >= 0) {
					g->y = ymn;
					g->ys = ymx + slen;
					ymx = (int) (g->ys + 0.5);
				} else {
					g->y = ymx;
					g->ys = ymn - slen;
					ymn = (int) (g->ys - 0.5);
				}
				ymx += 2;
				ymn -= 2;
				if (ymn < ymin)
					ymin = ymn;
				else if (ymx > ymax)
					ymax = ymx;
				g->ymx = ymx;
				g->ymn = ymn;
			}
			s->ymx = ymax;
			s->ymn = ymin;
			continue;
		}

		/* shift notes in chords (need stem direction to do this) */
		set_head_directions(s);

		/* if start or end of beam, adjust the number of flags
		 * with the other end */
		nflags = s->nflags;
		if ((s->sflags & (S_BEAM_ST | S_BEAM_END)) == S_BEAM_ST) {
			if (s->sflags & S_FEATHERED_BEAM)
				nflags = ++s->nflags;
			for (s2 = s->next; /*s2*/; s2 = s2->next) {
				if (s2->as.type == ABC_T_NOTE) {
					if (s->sflags & S_FEATHERED_BEAM)
						s2->nflags++;
					if (s2->sflags & S_BEAM_END)
						break;
				}
			}
/*			if (s2) */
			    if (s2->nflags > nflags)
				nflags = s2->nflags;
		} else if ((s->sflags & (S_BEAM_ST | S_BEAM_END)) == S_BEAM_END) {
			for (s2 = s->prev; /*s2*/; s2 = s2->prev) {
				if (s2->sflags & S_BEAM_ST)
					break;
			}
/*			if (s2) */
			    if (s2->nflags > nflags)
				nflags = s2->nflags;
		}

		/* set height of stem end */
		slen = cfmt.stemheight;
		switch (nflags) {
		case 2: slen += 2; break;
		case 3:	slen += 5; break;
		case 4:	slen += 10; break;
		case 5:	slen += 16; break;
		}
		if ((scale = voice_tb[s->voice].scale) != 1)
			slen *= (scale + 1) * 0.5;
		ymn = 3 * (s->pits[0] - 18);
		if (s->nhd > 0) {
			slen -= 2;
			ymx = 3 * (s->pits[s->nhd] - 18);
		} else {
			ymx = ymn;
		}
		if (s->u != 0)
			slen += 2 * s->u;		/* tremolo */
		if (s->as.flags & ABC_F_STEMLESS) {
			if (s->stem >= 0) {
				s->y = ymn;
				s->ys = (float) ymx;
			} else {
				s->ys = (float) ymn;
				s->y = ymx;
			}
			if (nflags == -4)		/* if longa */
				ymn -= 6;
			s->ymx = ymx + 4;
			s->ymn = ymn - 4;
		} else if (s->stem >= 0) {
			if (nflags >= 2)
				slen -= 1;
			if (s->pits[s->nhd] > 26
			 && (nflags <= 0
			  || (s->sflags & (S_BEAM_ST | S_BEAM_END))
					!= (S_BEAM_ST | S_BEAM_END))) {
				slen -= 2;
				if (s->pits[s->nhd] > 28)
					slen -= 2;
			}
			s->y = ymn;
			if (s->as.u.note.ti1[0] != 0)
/*fixme
 *			 || s->as.u.note.ti2[0] != 0) */
				ymn -= 3;
			s->ymn = ymn - 4;
			s->ys = ymx + slen;
			if (s->ys < 12)
				s->ys = 12;
			s->ymx = (int) (s->ys + 2.5);
		} else {			/* stem down */
			if (s->pits[0] < 18
			 && (nflags <= 0
			  || (s->sflags & (S_BEAM_ST | S_BEAM_END))
					!= (S_BEAM_ST | S_BEAM_END))) {
				slen -= 2;
				if (s->pits[0] < 16)
					slen -= 2;
			}
			s->ys = ymn - slen;
			if (s->ys > 12)
				s->ys = 12;
			s->ymn = (int) (s->ys - 2.5);
			s->y = ymx;
/*fixme:the tie may be lower*/
			if (s->as.u.note.ti1[s->nhd] != 0)
/*fixme
 *			 || s->as.u.note.ti2[s->nhd] != 0)*/
				ymx += 3;
			s->ymx = ymx + 4;
		}
	}
}

/* -- split up unsuitable bars at end of staff -- */
static void check_bar(struct SYMBOL *s)
{
	struct VOICE_S *p_voice;
	int bar_type, i;

	p_voice = &voice_tb[s->voice];

	/* search the last bar */
	while (s->type == CLEF || s->type == KEYSIG || s->type == TIMESIG) {
		if (s->type == TIMESIG
		 && s->time > p_voice->sym->time)	/* if not empty voice */
			insert_meter |= 1;	/* meter in the next line */
		if ((s = s->prev) == 0)
			return;
	}
	if (s->type != BAR)
		return;

	if (s->as.u.bar.repeat_bar) {
		p_voice->bar_start = B_OBRA;
		p_voice->bar_text = s->as.text;
		p_voice->bar_gch = s->gch;
		p_voice->bar_repeat = 1;
		s->as.text = NULL;
		s->gch = NULL;
		s->as.u.bar.repeat_bar = 0;
		if (s->as.flags & ABC_F_INVIS)
			p_voice->bar_start |= 0x8000;
		if (s->sflags & S_NOREPBRA)
			p_voice->bar_start |= 0x4000;
	}
	bar_type = s->as.u.bar.type;
	if (bar_type == B_COL)			/* ':' */
		return;
	if ((bar_type & 0x0f) != B_COL)		/* if not left repeat bar */
		return;
	if (!(s->sflags & S_RRBAR)) {		/* 'xx:' (not ':xx:') */
		p_voice->bar_start = bar_type & 0x3fff;
		if (s->as.flags & ABC_F_INVIS)
			p_voice->bar_start |= 0x8000;
		if (s->sflags & S_NOREPBRA)
			p_voice->bar_start |= 0x4000;
		if (s->prev && s->prev->type == BAR)
			unlksym(s);
		else
			s->as.u.bar.type = B_BAR;
		return;
	}
	if (bar_type == B_DREP) {		/* '::' */
		s->as.u.bar.type = B_RREP;
		p_voice->bar_start = B_LREP;
		if (s->as.flags & ABC_F_INVIS)
			p_voice->bar_start |= 0x8000;
		if (s->sflags & S_NOREPBRA)
			p_voice->bar_start |= 0x4000;
		return;
	}
	for (i = 0; bar_type != 0; i++)
		bar_type >>= 4;
	bar_type = s->as.u.bar.type;
	s->as.u.bar.type = bar_type >> ((i / 2) * 4);
	i = ((i + 1) / 2 * 4);
	bar_type &= 0x3fff;
	p_voice->bar_start = bar_type & ((1 << i) - 1);
	if (s->as.flags & ABC_F_INVIS)
		p_voice->bar_start |= 0x8000;
	if (s->sflags & S_NOREPBRA)
		p_voice->bar_start |= 0x4000;
}

/* -- move the symbols of an empty staff to the next one -- */
static void sym_staff_move(int staff,
			struct SYMBOL *s,
			struct SYSTEM *sy)
{
	for (;;) {
		if (s->staff == staff
		 && s->type != CLEF) {
			s->staff++;
			s->as.flags |= ABC_F_INVIS;
		}
		s = s->ts_next;
		if (s == tsnext || s->type == STAVES)
			break;
	}
}

/* -- define the start and end of a piece of tune -- */
/* tsnext becomes the beginning of the next line */
static void set_piece(void)
{
	struct SYSTEM *sy;
	struct SYMBOL *s;
	struct VOICE_S *p_voice;
	struct STAFF_S *p_staff;
	int staff;
	char empty[MAXSTAFF];

	/* reset the staves */
	sy = cursys;
	for (staff = 0; staff <= nstaff; staff++) {
		p_staff = &staff_tb[staff];
		p_staff->y = 0;		/* staff system not computed */
		p_staff->clef.stafflines = sy->staff[staff].clef.stafflines;
		if (sy->staff[staff].clef.staffscale != 0)
			p_staff->clef.staffscale = sy->staff[staff].clef.staffscale;
	}

	/* search the next end of line,
	 * set the repeat measures, (remove some dble bars?)
	 * and flag the empty staves
	 */
	memset(empty, 1, sizeof empty);
	for (s = tsfirst; s; s = s->ts_next) {
		if (s->sflags & S_NL)
			break;
		switch (s->type) {
		case STAVES:
			for (staff = 0; staff <= nstaff; staff++) {
				sy->staff[staff].empty = empty[staff];
				empty[staff] = 1;
			}
			sy = sy->next;
			for (staff = 0; staff <= sy->nstaff; staff++) {
				p_staff = &staff_tb[staff];
				if (sy->staff[staff].clef.stafflines >= 0)
					p_staff->clef.stafflines = sy->staff[staff].clef.stafflines;
				if (sy->staff[staff].clef.staffscale != 0)
					p_staff->clef.staffscale = sy->staff[staff].clef.staffscale;
			}
			break;
		case GRACE:
			empty[s->staff] = 0;
			break;
		case NOTEREST:
		case SPACE:
		case MREST:
			if (cfmt.staffnonote > 1) {
				empty[s->staff] = 0;
			} else if (!(s->as.flags & ABC_F_INVIS)) {
				if (s->as.type == ABC_T_NOTE
				 || cfmt.staffnonote != 0)
					empty[s->staff] = 0;
			}
			break;
		}
	}
	tsnext = s;

	/* set the last empty staves and
	 * define the offsets of the measure bars */
	for (staff = 0; staff <= nstaff; staff++) {
		sy->staff[staff].empty = empty[staff];
		if (empty[staff])
			continue;

		p_staff = &staff_tb[staff];
		p_staff->botbar = p_staff->clef.stafflines <= 3 ? 6 : 0;
		switch (p_staff->clef.stafflines) {
		case 0:
		case 1:
		case 3:	p_staff->topbar = 18; break;
		case 2:	p_staff->topbar = 12; break;
		default:
			p_staff->topbar = 6 * (p_staff->clef.stafflines - 1);
			break;
		}
	}

	/* move the symbols of the empty staves to the next staff */
	sy = cursys;
	for (staff = 0; staff < nstaff; staff++) {
		if (sy->staff[staff].empty)
			sym_staff_move(staff, tsfirst, sy);
	}
	for (s = tsfirst; s; s = s->ts_next) {
		if (s->type == STAVES) {
			sy = sy->next;
			for (staff = 0; staff < nstaff; staff++) {
				if (sy->staff[staff].empty)
					sym_staff_move(staff, s, sy);
			}
		}
	}

//	/* let the last empty staff have a full height */
//	if (empty[nstaff])
//		staff_tb[nstaff].topbar = 0;

	/* initialize the music line */
	init_music_line();
//	if (!empty[nstaff])
	if (!empty[cursys->nstaff])
		insert_meter &= ~1;	// no more meter

	/* if last music line, nothing more to do */
	if (!tsnext)
		return;

	s = tsnext;
	s->sflags &= ~S_NL;
	s = s->ts_prev;
	s->ts_next = NULL;

	/* set the end of the voices */
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		int voice;

		voice = p_voice - voice_tb;
		for (s = tsnext->ts_prev; s; s = s->ts_prev) {
			if (s->voice == voice) {
				s->next = NULL;
				check_bar(s);
				break;
			}
		}
		if (!s)
			p_voice->sym = NULL;
	}
}

/* -- position the symbols along the staff -- */
static void set_sym_glue(float width)
{
	struct SYMBOL *s;
	float beta0, alfa, beta;
	int some_grace;
	float xmin, x, xmax, spafac;

	/* calculate the whole space of the symbols */
	some_grace = 0;
	s = tsfirst;
	xmin = x = xmax = 0;
	for (;;) {
		if (s->type == GRACE)
			some_grace = 1;
		if (s->sflags & S_SEQST) {
			float space;

			xmin += s->shrink;
			if ((space = s->space) < s->shrink)
				space = s->shrink;
			x += space;
			if (cfmt.stretchstaff)
				space *= 1.8;
			xmax += space;
		}
		if (!s->ts_next)
			break;
		s = s->ts_next;
	}
#if 0
	if (s->type == FMTCHG		/* if PS/SVG sequence at end of line */
	 && (s->u == PSSEQ || s-> == SVGSEQ)) {
		s->sflags &= ~S_SEQST;
		s->shrink = 0;
	}
#endif

	/* set max shrink and stretch */
	if (!cfmt.continueall)
		beta0 = BETA_X;
	else
		beta0 = BETA_C;

	/* memorize the glue for the last music line */
	if (tsnext) {
		if (x - width >= 0) {
			alfa_last = (x - width) / (x - xmin);	/* shrink */
			beta_last = 0;
		} else {
			alfa_last = 0;
			beta_last = (width - x) / (xmax - x);	/* stretch */
			if (beta_last > beta0) {
				if (cfmt.stretchstaff) {
					if (!cfmt.continueall
					 && cfmt.linewarn) {
						error(0, s,
						      "Line underfull (%.0fpt of %.0fpt)",
							beta0 * xmax + (1 - beta0) * x,
							width);
					}
				} else {
					width = x;
					beta_last = 0;
				}
			}
		}
	} else {			/* if last music line */
		if (x < width) {
			beta = (width - x) / (xmax - x);	/* stretch */
			if (beta >= beta_last) {
				beta = beta_last * xmax + (1 - beta_last) * x;

				/* shrink underfull last line same as previous */
				if (beta < width * (1. - cfmt.stretchlast))
					width = beta;
			}
		}
	}

	spafac = width / x;			/* space expansion factor */

	/* define the x offsets of all starting symbols */
	x = xmax = 0;
	s = tsfirst;
	for (;;) {
		if (s->sflags & S_SEQST) {
			float new_space;

			new_space = s->shrink;
			if (s->space != 0) {
				if (new_space < s->space * spafac)
					new_space = s->space * spafac;
				xmax += s->space * spafac * 1.8;
			}
			x += new_space;
			xmax += new_space;
			s->x = x;
			s->xmax = xmax;
		}
		if (!s->ts_next)
			break;
		s = s->ts_next;
	}

	/* if the last symbol is not a bar, add some extra space */
	switch (s->type) {
	case BAR:
	case FMTCHG:
		break;
	default: {
		float min;

		min = s->wr;
		while (!(s->sflags & S_SEQST)) {
			s = s->ts_prev;
			if (s->wr > min)
				min = s->wr;
		}
		xmin += min + 3;
		if (tsnext && tsnext->space * 0.8 > s->wr + 4) {
			x += tsnext->space * 0.8 * spafac;
			xmax += tsnext->space * 0.8 * spafac * 1.8;
		} else {
#if 1
			x += min + 4;
			xmax += min + 4;
#else
/*fixme:should calculate the space according to the last symbol duration */
			x += (min + 4) * spafac;
			xmax += (min + 4) * spafac * 1.8;
#endif
		}
		break;
	    }
	}

	/* calculate the exact glue */
	if (x >= width) {
		beta = 0;
		if (x == xmin) {
			alfa = 1;
		} else {
			alfa = (x - width) / (x - xmin);	/* shrink */
			if (alfa > 1) {
				error(0, s,
				      "Line too much shrunk (%.0f/%0.fpt of %.0fpt)",
					xmin, x, width);
// uncomment for staff greater than music line
//				alfa = 1;
			}
		}
		realwidth = xmin * alfa + x * (1 - alfa);
	} else {
		alfa = 0;
		if (xmax > x)
			beta = (width - x) / (xmax - x);	/* stretch */
		else
			beta = 1;				/* (no note) */
		if (beta > beta0) {
			if (!cfmt.stretchstaff)
				beta = 0;
		}
		realwidth = xmax * beta + x * (1 - beta);
	}

	/* set the final x offsets */
	s = tsfirst;
	if (alfa != 0) {
		if (alfa < 1) {
			x = xmin = 0;
			for (; s; s = s->ts_next) {
				if (s->sflags & S_SEQST) {
					xmin += s->shrink * alfa;
					x = xmin + s->x * (1 - alfa);
				}
				s->x = x;
			}
		} else {
			alfa = realwidth / x;
			x = 0;
			for (; s; s = s->ts_next) {
				if (s->sflags & S_SEQST)
					x = s->x * alfa;
				s->x = x;
			}
		}
	} else {
		x = 0;
		for (; s; s = s->ts_next) {
			if (s->sflags & S_SEQST)
				x = s->xmax * beta + s->x * (1 - beta);
			s->x = x;
		}
	}

	/* set the x offsets of the grace notes */
	if (some_grace) {
		for (s = tsfirst; s; s = s->ts_next) {
			struct SYMBOL *g;

			if (s->type != GRACE)
				continue;
			x = s->x - s->wl + (cfmt.gracespace >> 16) * 0.1;
			for (g = s->extra; g; g = g->next)
				if (g->type == NOTEREST)
					g->x += x;
		}
	}
}

/* -- initialize a new music line -- */
static void new_music_line(void)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *s;
	int voice;

	/* set the first symbol of each voice */
	tsfirst->ts_prev = NULL;
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		p_voice->sym = NULL;		/* may have no symbol */
		voice = p_voice - voice_tb;
		for (s = tsfirst; s; s = s->ts_next) {
			if (s->voice == voice) {
				p_voice->sym = s;
				s->prev = NULL;
				break;
			}
		}
	}

//fixme:initmusic_line
//	init_music_line();	/* add the first symbols of the line */
//	insert_meter = 0;	/* not first line */
}
/* -- initialize the start of generation / new music line -- */
static void gen_init(void)
{
	struct SYMBOL *s;

	for (s = tsfirst ; s; s = s->ts_next) {
		if (s->extra)
			output_ps(s, ABC_S_HEAD);
		switch (s->type) {
		case CLEF:
		case KEYSIG:
		case TIMESIG:
			continue;
		case FMTCHG:
			if (s->extra)
				output_ps(s, 127);
			if (!s->extra) {
				unlksym(s);
				if (!tsfirst)
					return;
			}
//			continue;
			break;		/* may be Q: */
		case STAVES:
			cursys = cursys->next;
			unlksym(s);
			if (!tsfirst)
				return;
			continue;	/* fix %%staves - %%vskip */
//			break;
		}
		return;
	}
	tsfirst = NULL;			/* no more notes */
}

/* -- update the clefs at start of line -- */
static void update_clefs(void)
{
	struct SYMBOL *s;
	int staff;

	s = tsfirst;
	while (s && s->type == CLEF)
		s = s->ts_next;
	for ( ; s; s = s->ts_next) {
		if (s->type != CLEF)
			continue;
		staff = s->staff;
		cursys->staff[staff].clef.type = s->as.u.clef.type;
		cursys->staff[staff].clef.line = s->as.u.clef.line;
		cursys->staff[staff].clef.octave = s->as.u.clef.octave;
		cursys->staff[staff].clef.invis = s->as.u.clef.invis;
	}
}

/* -- show the errors -- */
static void error_show(void)
{
	struct SYMBOL *s;

	for (s = tsfirst; s; s = s->ts_next) {
		if (s->as.flags & ABC_F_ERROR) {
			putxy(s->x, staff_tb[s->staff].y + s->y);
			a2b("showerror\n");
		}
	}
}

/* -- delay output until the staves are defined (by draw_systems) -- */
static float delayed_output(float indent)
{
	float line_height;
	char *outbuf_sav, *mbf_sav, tmpbuf[20 * 1024];

	outbuf_sav = outbuf;
	mbf_sav = mbf;
	mbf = outbuf = tmpbuf;
	*outbuf = '\0';
	outft = -1;
	draw_sym_near();
	outbuf = outbuf_sav;
	mbf = mbf_sav;
	outft = -1;
	line_height = draw_systems(indent);
	a2b("%s", tmpbuf);
	return line_height;
}

/* -- generate the music -- */
void output_music(void)
{
	struct VOICE_S *p_voice;
	float lwidth, indent;

	/* set the staff system if any STAVES at start of the next line */
	gen_init();
	if (!tsfirst)
		return;
	check_buffer();
	set_global();			/* initialize the generator */
	if (first_voice->next) {	/* if many voices */
		if (cfmt.combinevoices >= 0)
			combine_voices();
		set_stem_dir();		/* set the stems direction in 'multi' */
	}
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next)
		set_beams(p_voice->sym);	/* decide on beams */
	set_stems();			/* set the stem lengths */
	if (first_voice->next) {		/* when multi-voices */
		set_rest_offset();	/* set the vertical offset of rests */
		set_overlap();		/* shift the notes on voice overlap */
	}
	set_allsymwidth(NULL);		/* set the width of all symbols */

	lwidth = ((cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth)
		- cfmt.leftmargin - cfmt.rightmargin)
			/ cfmt.scale;
	if (lwidth < 50) {
		error(1, 0, "Bad page width %.1f", lwidth);
		lwidth = 10 CM;
	}
	indent = set_indent(1);		/* (keep the indentation flag) */
	cut_tune(lwidth, indent);
	alfa_last = 0.1;
	beta_last = 0;
	for (;;) {			/* loop per music line */
		float line_height;

//fixme:initmusic_line			<- pb repeat bars...
//	init_music_line();
		set_piece();
		indent = set_indent(0);
//		set_piece();		<- pb new voice after %%staves
//fixme:initmusic_line			<- pb repeat bars...
//		init_music_line();

//fixme:initmusic_line
//	insert_meter = 0;
		set_sym_glue(lwidth - indent);
		if (indent != 0)
			a2b("%.2f 0 T\n", indent); /* do indentation */
		line_height = delayed_output(indent);
		draw_all_symb();
		draw_all_deco();
		if (showerror)
			error_show();
		bskip(line_height);
		if (indent != 0) {
			a2b("%.2f 0 T\n", -indent);
			insert_meter &= ~2;	// no more indentation
		}
		update_clefs();
		tsfirst = tsnext;
		gen_init();
		if (!tsfirst)
			break;
		buffer_eob();
		new_music_line();
	}
	outft = -1;
}

/* -- reset the generator -- */
void reset_gen(void)
{
	if (cfmt.fields[0] & (1 << ('M' - 'A')))
		insert_meter = 3;	/* insert meter and indent */
	else
		insert_meter = 2;	/* indent only */
}
abcm2ps-7.8.13/musicfont.fmt0000644000175000017500000000215011662672701013760 0ustar  jefjef% example of musical symbols by font

% --- SVG definitions ---
beginsvg
<style type="text/css">
	@font-face {
	    font-family: 'MusicFont';
	    src: local(FreeSerif);
	    font-weight: normal;
	    font-style: normal;
	}
</style>
endsvg

beginps svg
/tclef{/MusicFont 35 selectfont M -12 0 RM(\ud834\udd1e)show}!
/bclef{/MusicFont 35 selectfont M -12 -3 RM(\ud834\udd22)show}!
/csig{/MusicFont 32 selectfont M -7 0 RM(\ud834\udd34)show}!
% the brace does not work with Opera
/brace{/MusicFont 35 selectfont
	gsave
		T -8 0 M -.04 mul 1 exch scale
		(\ud834\udd14)show
	grestore}!
endps

% --- PostScript definitions ---
beginps nosvg
% with FreeSerif
/tclef{/FreeSerif 35 selectfont M -12 0 RM/g_clef glyphshow}!
/bclef{/FreeSerif 35 selectfont M -12 -3 RM/f_clef glyphshow}!
/csig{/FreeSerif 32 selectfont M -8 0 RM/common_time glyphshow}!
/brace{/FreeSerif 35 selectfont 
	gsave
		T -8 0 M -.04 mul 1 exch scale
		/brace glyphshow
	grestore}!

% with PMW-Music (use "GS_FONTPATH=/usr/local/src/pmw-4.21/psfonts/ gs Out.ps")
%/tclef{/PMW-Music 15 selectfont M -10 0 RM(!)show}!
% I let your search the other symbols..
endps
abcm2ps-7.8.13/newfeatures.abc0000644000175000017500000000615312147345672014252 0ustar  jefjef%%textfont Helvetica-Bold 21
%%center Examples for new features in abc2ps-1.2.5
%%textfont * 16
%%center Oct. 5 1997
%%textfont Times-Roman 16

X:1
T:Scale with Treble Clef
M:C
%%freegchord 1	% abcm2ps: don't print 'b' as a flat sign
K:C treble	% abcm2ps: must be forced because too low at the beginning
L: 1/4
 "C,"C,"D,"D,"E,"E,"F,"F,  "G,"G,"A,"A,"B,"B,\
| "C"C"D"D"E"E"F"F  "G"G"A"A"B"B| "c"c "d"d"e"e"f"f  "g"g"a"a"b"b"c'"c' |

X:2
T:Scale with Bass and Alto Clef
M:C
K:C bass	% abcm2ps: no transposition
L: 1/4
P:Bass
 "C,,,"C,,,"D,,,"D,,,"E,,,"E,,,"F,,,"F,,,  "G,,,"G,,,"A,,,"A,,,"B,,,"B,,,|\
 "C,,"C,,"D,,"D,,"E,,"E,,"F,,"F,,  "G,,"G,,"A,,"A,,"B,,"B,,|\
 "C,"C, "D,"D,"E,"E,"F,"F,  "G,"G,"A,"A,"B,"B,"C"C |
P:Alto
%abcm2ps: don't have a new key signature
%K:C alto
K: clef=alto
 "C,,"C,,"D,,"D,,"E,,"E,,"F,,"F,,  "G,,"G,,"A,,"A,,"B,,"B,,\
| "C,"C,"D,"D,"E,"E,"F,"F,  "G,"G,"A,"A,"B,"B,| "C"C "D"D"E"E"F"F  "G"G"A"A"B"B"c"c |

X:3
T:Clef Changes Within Tune
T:In-Line Info Fields by [..]
% text moved out of tune header - change in abcm2ps-7.x.x
M:C
L: 1/8
K:C
%%begintext align
Here is an example for a block of text which is associated with a specific
tune. It will only be printed if this tune (number 3) is selected.
The text should be placed after the "T:" field and before the
block is terminated by a blank line.
Text which is outside a block is
always printed; for example, the title at the top of the page.
%%endtext
cdef gabc' [K:bass] | C,D,E,F, G,A,B,C [K:D treble] | cdef gabc' |  
%%sep
%%text Note: this line and the separator above are also associated with this tune. 

X:4
T:Vocals
T:Note also the trill
C:Music: Trad.
C:Text: Anonymous
M:C
K:C
L: 1/4
e>e ez || edTc2 | ed(c2 | e2 c2- | Hc4) |]
w: *** 1.~~Three blind mice, three blind mice.___
w: *** 2.~~See how~they run, see how~they ru-uuu-un._

X:6
T:Invisible Rests Using X
M:C
K:C
L: 1/4
"F"z4|"F"x4|"F"z4|"F"x4|"Bb"z4|"Bb"x4|"F"z4|"F"x4|"C"z4|"Bb"x4|"F"z4|"F"x4||

%%leftmargin 3cm

X:5
T:Scotland The Brave
T:Demonstrating the Bagpipe Mode and Output Formatting
%%titleleft
%%titlefont Helvetica-Bold 24
%%subtitlefont Helvetica-Bold 16
%%composerspace 0.4cm
%%composerfont Helvetica 13
%%staffwidth 5.5in
%%scale 0.75
%%staffsep 55
C:Trad.
C:from PS file by Alan S. Watt
P:March
L:1/8
M:4/4
K:HP
e|{g}A2 {GdGe}A>B {gcd}c{e}A {gcd}ce| {ag}a2{g}a2 {GdG}ae {gcd}c{e}A|
   {Gdc}d2 {g}f>d {gcd}ce {gcd}c{e}A|{GdG}B2{gef}e2{A}e>f {g}e/>d/{g}c/>B/|
{g}A2 {GdGe}A>B {gcd}c{e}A {gcd}ce| {ag}a2{g}a2 {GdG}ae {gcd}c{e}A|
   {Gdc}d2 {g}f>d {gcd}ce {gcd}c{e}A|{GdG}B2{g}A>B {G}A2 {gcd}ce||

%%vskip 1cm
%%textfont Times-Roman 16
%%begintext
Summary of changes:

- Bass and alto clefs.
- Vocals.
- In-line info fields can be coded using [...].
- Subtitles now printed without "or:".
- Can be more than one composer field.
- Predefined formats: standard, pretty, pretty2 (flag -p, -P).
- Format page layout by .fmt file selected with flag -F.
- Format page layout by %%-pseudocomments in abc file.
- Other pseudocomments: %%sep, %%vskip, %%newpage.
- Text output using %%text, %%center, and %%begintext .. %%endtext.
- "x" functions like a rest but is invisible on the page.
- Bagpipe mode for K:HP.
%%endtext
abcm2ps-7.8.13/options.txt0000644000175000017500000001251312314511765013476 0ustar  jefjef		abcm2ps command line options
		============================

The list of the command line options may be known running:
	'abcm2ps -h'

The options may be grouped when they have no argument, but the
last one (ex: "-lnGI20").

The options may be disabled when starting with '+' or ending with '-'
(ex: "+MT1" is the same as "-MT1-").

The general output format is the last found in the command line.
It may be:
	"-E" for Encapsulated PostScript, one file per tune
	"-g" for SVG, one file per tune
	"-v" for SVG, one file per page
	"-X" for XHTML+SVG
	(none) for PostScript
(see below for more information)

List of the options
-------------------

  -
	Read the abc file from stdin.

  --<format> <value>
	Set the format parameter to <value>. See format.txt.

  -a <float>
	See: format.txt - maxshrink <float>

  -A
	Annotate.
	This option inserts reference elements in the PostScript
	or SVG output.

  -B <int>, +B
	See: format.txt - barsperstaff <int>

  -b <int>
	See: format.txt - measurefirst <int>

  -c, +c
	See: format.txt - continueall <bool>

  -D <dir>
	Search the format files in the directory <dir>.

  -d <unit>
	See: format.txt - staffsep <unit>

  -E
	Produce EPS output instead of simple PS.
	In this mode, each tune goes to a different file which
	name is '<name>nnn.eps' or <title>.eps (see option '-O'
	- 'nnn' is a sequence number incremented at each tune
	- output to stdout is forbidden).
	EPS files are normally embedded into Postscript documents,
	but they may be a way to generate graphical images. For
	example, using GhostScript:
		abcm2ps voices -Ee7
		gs -sDEVICE=pngmono -r80 -g590x174 \
			-dBATCH -dNOPAUSE \
			-sOutputFile=quitolis.png Out001.eps
	(the values for -g are the values of the bounding box in
	 the .eps, multiplied by (80 / 72), where 80 is the value
	 for -r, and 72 is the default resolution)

  -e [ <tune index list> ] [ <regular expression> ]
	See: format.txt - select [ <tune index list> ] [ <regular expression> ]

  -F <file>, +F
	Read the format (or PostScript) file <file>.
	When omitted, the default type of a format file is '.fmt'.
	In the form '+F', the default format file ('default.fmt') is not
	read.

  -f
	See: format.txt - flatbeams <bool>

  -G, +G
	See: format.txt - graceslurs <bool>

  -g
	Produce SVG output instead of EPS.
	In this mode each tune goes to a different file which name
	is 'Outnnn.svg' (see option '-O').
	If the output is stdout (option '-O-'), all the SVG images
	are output without XML header.

  -H
	Display the current format values.

  -h
	Quick help, equivalent to "abcm2ps" without any arguments.
	This also shows the default settings for some parameters.

  -I <unit>
	See: format.txt - indent <unit>

  -i, +i
	Insert a red cercle around the errors in the PostScript output.

  -j <int>[b], +j
	See: format.txt - measurenb <int>

  -k <int>
	Set the size of the PostScript output buffer in Kibytes.
	Setting this value to a higher value permits the
	generation of big tunes with -E or -g.
	The default value is 64.

  -l, +l
	See: format.txt - landscape <bool>

  -M, +M
	See: format.txt - writefields w <bool>

  -m <unit>
	See: format.txt - leftmargin <unit>

  -N <int>, +N
	Number the pages.
	<int> indicates the mode:
		0  no page numbers
		1  at top left
		2  at top right
		3  at top left on even pages, top right on odd pages
		4  at top right on even pages, top left on odd pages
	For compatibility with previous versions, '+N' is the same as
	'-N0', and '-N' is the same as '-N2'.
	If a header is defined ('%%header'), this option is ignored.

  -n, +n
	See: format.txt - writehistory <bool>

  -O [ <directory> ] [ <name> ], +O
	Define the output file directory and/or name.
	The directory must end with the directory separator
	('/' for unix/windows, '\' for mac).
	By default, the output file goes to the current directory
	with the name:
		'Out.ps' for PS,
		'Outnnn.eps' for EPS (see option '-E'),
		'Outnnn.svg' for SVG (see options '-g' and '-v') or
		'Out.xhtml' for XHTML+SVG (see option '-X').
	'nnn' being a sequence number.
	When <name> is present, it is the name of the file, or it
	replaces 'Out' in the file name.
	If <name> is '=', it is replaced by the name of the ABC
	source file.
	If <name> is '-', the result is output to stdout (not for EPS).
	'+O' resets the output file directory and name to their defaults.

  -q
	Quiet mode.
	When present, only the errors are shown.

  -s <float>
	See: format.txt - scale <float>

  -S
	Secure mode.
	When present, file inclusion (%%format and %%EPS) and PostScript
	injection (%%beginps and %%postscript) are disabled.

  -T <int> [ <voice> ], +T [ <int> [<voice> ] ]
	Activate or deactivate tablature drawing.
	<int> is the tablature number as defined in %%tablature.
		There may be only 8 different tablatures.
	<voice> is the voice name, full name or subname as found in V:.
		When absent, apply to all voices.
	Up to 4 such commands may be defined.
	Ex: '-T1flute +T2'
	See: format.txt - tablature

  -V
	Show the version number.

  -v
	Produce SVG output instead of simple PS.
	In this mode each page goes to a different file which name
	is 'Outnnn.svg' (see option '-O').

  -w <unit>
	See: format.txt - staffwidth <unit>

  -X
	Produce XML + SVG output instead of simple PS.
	The default file name is 'Out.xhtml' (see option '-O').

  -x, +x
	See: format.txt - writefields X <bool>

  -0, +0
	See: format.txt - splittune <bool>

  -1, +1
	See: format.txt - oneperpage <bool>
abcm2ps-7.8.13/parse.c0000644000175000017500000034364612461214640012531 0ustar  jefjef/*
 * Parsing functions.
 *
 * This file is part of abcm2ps.
 *
 * Copyright (C) 1998-2015 Jean-François Moine
 * Adapted from abc2ps, Copyright (C) 1996,1997 Michael Methfessel
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>

#include "abc2ps.h"
#include "slre.h"

/* options = external formatting */
struct symsel_s {			/* symbol selection */
	short bar;
	short time;
	char seq;
};
struct brk_s {				/* music line break */
	struct brk_s *next;
	struct symsel_s symsel;
};
struct voice_opt_s {			/* voice options */
	struct voice_opt_s *next;
	struct SYMBOL *s;		/* list of options (%%xxx) */
};
struct tune_opt_s {			/* tune options */
	struct tune_opt_s *next;
	struct voice_opt_s *voice_opts;
	struct SYMBOL *s;		/* list of options (%%xxx) */
};

struct STAFF_S staff_tb[MAXSTAFF];	/* staff table */
int nstaff;				/* (0..MAXSTAFF-1) */
struct SYMBOL *tsfirst;			/* first symbol in the time sorted list */

struct VOICE_S voice_tb[MAXVOICE];	/* voice table */
static struct VOICE_S *curvoice;	/* current voice while parsing */
struct VOICE_S *first_voice;		/* first voice */
struct SYSTEM *cursys;			/* current system */
static struct SYSTEM *parsys;		/* current system while parsing */

struct FORMAT dfmt;			/* current global format */
unsigned short *micro_tb;		/* ptr to the microtone table of the tune */
int nbar;				/* current measure number */

static struct voice_opt_s *voice_opts, *tune_voice_opts;
static struct tune_opt_s *tune_opts, *cur_tune_opts;
static struct brk_s *brks;
static struct symsel_s clip_start, clip_end;


static INFO info_glob;			/* global info definitions */
static unsigned char deco_glob[256];	/* global decoration table */

static int over_time;			/* voice overlay start time */
static int over_mxtime;			/* voice overlay max time */
static short over_bar;			/* voice overlay in a measure */
static short over_voice;		/* main voice in voice overlay */
static int staves_found;		/* time of the last %%staves */
static int abc2win;

float multicol_start;			/* (for multicol) */
static float multicol_max;
static float lmarg, rmarg;
static int mc_in_tune;			/* multicol started in tune */

static void get_clef(struct SYMBOL *s);
static struct abcsym *get_info(struct abcsym *as,
		     struct abctune *t);
static void get_key(struct SYMBOL *s);
static void get_meter(struct SYMBOL *s);
static void get_voice(struct SYMBOL *s);
static void get_note(struct SYMBOL *s);
static struct abcsym *process_pscomment(struct abcsym *as);
static void set_tblt(struct VOICE_S *p_voice);
static void set_tuplet(struct SYMBOL *s);
static void sym_link(struct SYMBOL *s, int type);

/* -- weight of the symbols -- */
static signed char w_tb[NSYMTYPES] = {	/* !! index = symbol type !! */
	0,
	9,	/* 1- note / rest */
	3,	/* 2- space */
	2,	/* 3- bar */
	1,	/* 4- clef */
	5,	/* 5- timesig */
	4,	/* 6- keysig */
	0,	/* 7- tempo */
	0,	/* 8- staves */
	9,	/* 9- mrest */
	0,	/* 10- part */
	3,	/* 11- grace */
	0,	/* 12- fmtchg */
	7,	/* 13- tuplet */
	6,	/* 14- stbrk */
	6	/* 15- custos */
};

/* key signature transposition tables */
static signed char cde2fcg[7] = {0, 2, 4, -1, 1, 3, 5};
static char cgd2cde[7] = {0, 4, 1, 5, 2, 6, 3};

/* -- expand a multi-rest into single rests and measure bars -- */
static void mrest_expand(struct SYMBOL *s)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *s2, *next;
	struct deco dc;
	int nb, dt;

	nb = s->as.u.bar.len;
	dt = s->dur / nb;

	/* change the multi-rest (type bar) to a single rest */
	memcpy(&dc, &s->as.u.bar.dc, sizeof dc);
	memset(&s->as.u.note, 0, sizeof s->as.u.note);
	s->type = NOTEREST;
	s->as.type = ABC_T_REST;
	s->as.u.note.nhd = 0;
	s->dur = s->as.u.note.lens[0] = dt;
	s->head = H_FULL;
	s->nflags = -2;

	/* add the bar(s) and rest(s) */
	next = s->next;
	p_voice = &voice_tb[s->voice];
	p_voice->last_sym = s;
	p_voice->time = s->time + dt;
	p_voice->cstaff = s->staff;
	s2 = s;
	while (--nb > 0) {
		s2 = sym_add(p_voice, BAR);
		s2->as.type = ABC_T_BAR;
		s2->as.u.bar.type = B_SINGLE;
		s2 = sym_add(p_voice, NOTEREST);
		s2->as.type = ABC_T_REST;
		s2->as.flags = s->as.flags;
		s2->dur = s2->as.u.note.lens[0] = dt;
		s2->head = H_FULL;
		s2->nflags = -2;
		p_voice->time += dt;
	}
	s2->next = next;
	if (next)
		next->prev = s2;

	/* copy the mrest decorations to the last rest */
	memcpy(&s2->as.u.note.dc, &dc, sizeof s2->as.u.note.dc);
}

/* -- sort all symbols by time and vertical sequence -- */
static void sort_all(void)
{
	struct SYSTEM *sy;
	struct SYMBOL *s, *prev, *s2;
	struct VOICE_S *p_voice;
	int fl, voice, time, w, wmin, multi, mrest_time;
	int nv, nb, r, sysadv;
	struct SYMBOL *vtb[MAXVOICE];
	signed char vn[MAXVOICE];	/* voice indexed by range */

/*	memset(vtb, 0, sizeof vtb); */
	mrest_time = -1;
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next)
		vtb[p_voice - voice_tb] = p_voice->sym;

	/* initialize the voice order */
	sy = cursys;
	sysadv = 1;
	prev = NULL;
	fl = 1;				/* set start of sequence */
	multi = -1;			/* (have gcc happy) */
	for (;;) {
		if (sysadv) {
			sysadv = 0;
			memset(vn, -1, sizeof vn);
			multi = -1;
			for (p_voice = first_voice;
			     p_voice;
			     p_voice = p_voice->next) {
				voice = p_voice - voice_tb;
				r = sy->voice[voice].range;
				if (r < 0)
					continue;
				vn[r] = voice;
				multi++;
			}
		}

		/* search the min time and symbol weight */
		wmin = time = (unsigned) ~0 >> 1;	/* max int */
		nv = nb = 0;
		for (r = 0; r < MAXVOICE; r++) {
			voice = vn[r];
			if (voice < 0)
				break;
			s = vtb[voice];
			if (!s || s->time > time)
				continue;
			w = w_tb[s->type];
			if (s->time < time) {
				time = s->time;
				wmin = w;
				nb = 0;
			} else if (w < wmin) {
				wmin = w;
				nb = 0;
			}
			if (!(s->sflags & S_SECOND)) {
				nv++;
				if (s->type == BAR)
					nb++;
			}
			if (s->type == MREST) {
				if (s->as.u.bar.len == 1)
					mrest_expand(s);
				else if (multi)
					mrest_time = time;
			}
		}
		if (wmin > 127)
			break;			/* done */

#if 0
		/* align the measure bars */
		if (nb != 0 && nb != nv) {	/* if other symbol than bars */
			wmin = (unsigned) ~0 >> 1;
			for (r = 0; r < MAXVOICE; r++) {
				voice = vn[r];
				if (voice < 0)
					break;
				s = vtb[voice];
				if (!s || s->time > time
				 || s->type == BAR)
					continue;
				w = w_tb[s->type];
				if (w < wmin)
					wmin = w;
			}
			if (wmin > 127)
				wmin = w_tb[BAR];
		}
#endif

		/* if some multi-rest and many voices, expand */
		if (time == mrest_time) {
			nb = 0;
			for (r = 0; r < MAXVOICE; r++) {
				voice = vn[r];
				if (voice < 0)
					break;
				s = vtb[voice];
				if (!s || s->time != time)
					continue;
				w = w_tb[s->type];
				if (w != wmin)
					continue;
				if (s->type != MREST) {
					mrest_time = -1;	/* some note or rest */
					break;
				}
				if (nb == 0) {
					nb = s->as.u.bar.len;
				} else if (nb != s->as.u.bar.len) {
					mrest_time = -1;	/* different duration */
					break;
				}
			}
			if (mrest_time < 0) {
				for (r = 0; r < MAXVOICE; r++) {
					voice = vn[r];
					if (voice < 0)
						break;
					s = vtb[voice];
					if (s && s->type == MREST)
						mrest_expand(s);
				}
			}
		}

		/* link the vertical sequence */
		for (r = 0; r < MAXVOICE; r++) {
			voice = vn[r];
			if (voice < 0)
				break;
			s = vtb[voice];
			if (!s || s->time != time)
				continue;
			w = w_tb[s->type];
			if (w != wmin)
				continue;
			if (fl) {
				fl = 0;
				s->sflags |= S_SEQST;
			}
			s->ts_prev = prev;
			if (prev) {
				prev->ts_next = s;
				if (s->type == BAR
				 && (s->sflags & S_SECOND)
				 && prev->type != BAR
				 && !(s->as.flags & ABC_F_INVIS))
					error(1, s, "Bad measure bar");
			} else {
				tsfirst = s;
			}
			prev = s;
			vtb[voice] = s->next;
			if (s->type == STAVES) {
				sy = sy->next;
				sysadv = 1;
			}
		}
		fl = wmin;	/* start a new sequence if some space */
	}

	if (!prev)
		return;

	/* if no bar or format_change at end of tune, add a dummy symbol */
	if (prev->type != BAR && prev->type != FMTCHG) {
		p_voice = &voice_tb[prev->voice];
		p_voice->last_sym = prev;
		s = sym_add(p_voice, FMTCHG);
		s->u = -1;
		s->time = prev->time + prev->dur;
		s->sflags = S_SEQST;
		prev->ts_next = s;
		s->ts_prev = prev;
		for (;;) {
			prev->sflags &= ~S_EOLN;
			if (prev->sflags & S_SEQST)
				break;
			prev = prev->ts_prev;
		}
	}

	/* if Q: from tune header, put it at start of the music */
	s2 = info['Q' - 'A'];
	if (!s2)
		return;
	info['Q' - 'A'] = NULL;
	s = tsfirst->extra;
	if (s) {
		do {
			if (s->type == TEMPO)
				return;		/* already a tempo */
			s = s->next;
		} while (s);
	}
	s = tsfirst;
	s2->type = TEMPO;
	s2->voice = s->voice;
	s2->staff = s->staff;
	s2->time = s->time;
	if (s->extra) {
		s2->next = s->extra;
		s2->next->prev = s2;
	}
	s->extra = s2;
}

/* -- move the symbols with no width to the next symbol -- */
static void voice_compress(void)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *s, *s2, *ns;
//	int sflags;

	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		if (p_voice->ignore)
			continue;
		for (s = p_voice->sym; s; s = s->next) {
			if (s->time >= staves_found)
				break;
		}
		ns = NULL;
//		sflags = 0;
		for ( ; s; s = s->next) {
			switch (s->type) {
			case KEYSIG:	/* remove the empty key signatures */
				if (s->as.u.key.empty) {
					if (s->prev)
						s->prev->next = s->next;
					else
						p_voice->sym = s->next;
					if (s->next)
						s->next->prev = s->prev;
					continue;
				}
				break;
			case FMTCHG:
				s2 = s->extra;
				if (s2) {	/* dummy format */
					if (!ns)
						ns = s2;
					if (s->prev) {
						s->prev->next = s2;
						s2->prev = s->prev;
					}
					if (!s->next) {
						ns = NULL;
						break;
					}
					while (s2->next)
						s2 = s2->next;
					s->next->prev = s2;
					s2->next = s->next;
				}
				/* fall thru */
			case TEMPO:
			case PART:
			case TUPLET:
				if (!ns)
					ns = s;
//				sflags |= s->sflags;
				continue;
			case MREST:		/* don't shift P: and Q: */
				if (!ns)
					continue;
				s2 = (struct SYMBOL *) getarena(sizeof *s);
				memset(s2, 0, sizeof *s2);
				s2->type = SPACE;
				s2->as.u.note.lens[1] = -1;
				s2->as.flags = ABC_F_INVIS;
				s2->voice = s->voice;
				s2->staff = s->staff;
				s2->time = s->time;
				s2->sflags = s->sflags;
				s2->next = s;
				s2->prev = s->prev;
				s2->prev->next = s2;
				s->prev = s2;
				s = s2;
				break;
			}
			if (s->as.flags & ABC_F_GRACE) {
				if (!ns)
					ns = s;
				while (!(s->as.flags & ABC_F_GR_END))
					s = s->next;
				s2 = (struct SYMBOL *) getarena(sizeof *s);
				memcpy(s2, s, sizeof *s2);
				s2->as.type = 0;
				s2->type = GRACE;
				s2->dur = 0;
				s2->next = s->next;
				if (s2->next)
					s2->next->prev = s2;
				else
					p_voice->last_sym = s2;
				s2->prev = s;
				s->next = s2;
				s = s2;
			}
			if (!ns)
				continue;
			s->extra = ns;
//			s->sflags |= (sflags & S_EOLN);
//			sflags = 0;
			s->prev->next = NULL;
			s->prev = ns->prev;
			if (s->prev)
				s->prev->next = s;
			else
				p_voice->sym = s;
			ns->prev = NULL;
			ns = NULL;
		}

		/* when symbols with no space at end of tune,
		 * add a dummy format */
		if (ns) {
			s = sym_add(p_voice, FMTCHG);
			s->u = -1;		/* nothing */
			s->extra = ns;
			s->prev->next = NULL;	/* unlink */
			s->prev = ns->prev;
			if (s->prev)
				s->prev->next = s;
			else
				p_voice->sym = s;
			ns->prev = NULL;
		}
	}
}

/* -- duplicate the voices as required -- */
static void voice_dup(void)
{
	struct VOICE_S *p_voice, *p_voice2;
	struct SYMBOL *s, *s2, *g, *g2;
	int voice;

	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		if ((voice = p_voice->clone) < 0)
			continue;
		p_voice->clone = -1;
		p_voice2 = &voice_tb[voice];
		for (s = p_voice->sym; s; s = s->next) {
//fixme: there may be other symbols before the %%staves at this same time
			if (s->time >= staves_found)
				break;
		}
		for ( ; s; s = s->next) {
			s2 = (struct SYMBOL *) getarena(sizeof *s2);
			memcpy(s2, s, sizeof *s2);
			s2->prev = p_voice2->last_sym;
			s2->next = NULL;
			if (p_voice2->sym)
				p_voice2->last_sym->next = s2;
			else
				p_voice2->sym = s2;
			p_voice2->last_sym = s2;
			s2->voice = voice;
			s2->staff = p_voice2->staff;
			if (p_voice2->second)
				s2->sflags |= S_SECOND;
			else
				s2->sflags &= ~S_SECOND;
			if (p_voice2->floating)
				s2->sflags |= S_FLOATING;
			else
				s2->sflags &= ~S_FLOATING;
			s2->ly = NULL;
			g = s2->extra;
			if (!g)
				continue;
			g2 = (struct SYMBOL *) getarena(sizeof *g2);
			memcpy(g2, g, sizeof *g2);
			s2->extra = g2;
			s2 = g2;
			s2->voice = voice;
			s2->staff = p_voice2->staff;
			for (g = g->next; g; g = g->next) {
				g2 = (struct SYMBOL *) getarena(sizeof *g2);
				memcpy(g2, g, sizeof *g2);
				s2->next = g2;
				g2->prev = s2;
				s2 = g2;
				s2->voice = voice;
				s2->staff = p_voice2->staff;
			}
		}
	}
}

/* -- create a new staff system -- */
static void system_new(void)
{
	struct SYSTEM *new_sy;
	int staff, voice;

	new_sy = (struct SYSTEM *) getarena(sizeof *new_sy);
	if (!parsys) {
		memset(new_sy, 0, sizeof *new_sy);
		for (voice = 0; voice < MAXVOICE; voice++) {
			new_sy->voice[voice].range = -1;
			new_sy->voice[voice].clef.line = 2;
			new_sy->voice[voice].clef.stafflines = 5;
			new_sy->voice[voice].clef.staffscale = 1;
		}
		cursys = new_sy;
	} else {
		for (voice = 0; voice < MAXVOICE; voice++) {
			if (parsys->voice[voice].range < 0
			 || parsys->voice[voice].second)
				continue;
			staff = parsys->voice[voice].staff;
			memcpy(&parsys->staff[staff].clef,
				&parsys->voice[voice].clef,
				sizeof parsys->staff[staff].clef);
		}
		memcpy(new_sy, parsys, sizeof *new_sy);
		for (voice = 0; voice < MAXVOICE; voice++) {
			new_sy->voice[voice].range = -1;
			new_sy->voice[voice].second = 0;
		}
		for (staff = 0; staff < MAXSTAFF; staff++)
			new_sy->staff[staff].flags = 0;
		parsys->next = new_sy;
	}
	parsys = new_sy;
}

/* -- set the staves -- */
static void staves_init(void)
{
	struct SYSTEM *sy, *new_sy;
	struct SYMBOL *s, *staves;
	int staff, voice;

	sy = cursys;
	for (voice = 0; voice < MAXVOICE; voice++) {
		if (sy->voice[voice].range < 0
		 || sy->voice[voice].second)
			continue;
		staff = sy->voice[voice].staff;
		memcpy(&sy->staff[staff].clef,
			&sy->voice[voice].clef,
			sizeof (struct clef_s));
		sy->staff[staff].sep = sy->voice[voice].sep;
		sy->staff[staff].maxsep = sy->voice[voice].maxsep;
	}
	staves = NULL;
	for (s = tsfirst; s; s = s->ts_next) {
		switch (s->type) {
		case STAVES:
			sy = sy->next;
			for (voice = 0; voice < MAXVOICE; voice++) {
				if (sy->voice[voice].range < 0
				 || sy->voice[voice].second)
					continue;
				staff = sy->voice[voice].staff;
				memcpy(&sy->staff[staff].clef,
					&sy->voice[voice].clef,
					sizeof (struct clef_s));
				sy->staff[staff].sep = sy->voice[voice].sep;
				sy->staff[staff].maxsep = sy->voice[voice].maxsep;
			}
			staves = s;
			continue;
		case CLEF:
			if (s->as.u.clef.type < 0)
				break;
			{
				int scale, lines;

				scale = sy->voice[s->voice].clef.staffscale;
				lines = sy->voice[s->voice].clef.stafflines;
				sy->voice[s->voice].clef = s->as.u.clef;
				sy->voice[s->voice].clef.staffscale = scale;
				sy->voice[s->voice].clef.stafflines = lines;
			}
			continue;	/* normal clef change */
		case KEYSIG:
		case TIMESIG:
		case TEMPO:
		case PART:
		case FMTCHG:
			continue;
		default:
			staves = NULL;
			continue;
		}

		/* CLEF with change of #lines or scale of staff */
		voice = s->voice;
		if (!staves) {
			staves = s;	/* create a new staff system */
			new_sy = (struct SYSTEM *) getarena(sizeof *new_sy);
			memcpy(new_sy, sy, sizeof *new_sy);
			for (voice = 0; voice < MAXVOICE; voice++) {
				if (new_sy->voice[voice].range < 0
				 || new_sy->voice[voice].second)
					continue;
				staff = new_sy->voice[voice].staff;
				memcpy(&new_sy->staff[staff].clef,
					&new_sy->voice[voice].clef,
					sizeof (struct clef_s));
			}
			new_sy->next = sy->next;
			sy->next = new_sy;
			sy = new_sy;
			s->type = STAVES;	/* and set the marker */
		} else {		/* remove the CLEF */
			if (s->prev)
				s->prev->next = s->next;
			else
				voice_tb[voice].sym = s->next;
			if (s->ts_next) {
				s->ts_next->ts_prev = s->ts_prev;
				if (s->sflags & S_SEQST)
					s->ts_next->sflags |= S_SEQST;
			}
			if (s->ts_prev)
				s->ts_prev->ts_next = s->ts_next;
			else
				tsfirst = s->ts_next;
			if (s->next)
				s->next->prev = s->prev;
		}
		staff = sy->voice[voice].staff;
		if (s->as.u.clef.stafflines >= 0)
			sy->voice[voice].clef.stafflines
				= sy->staff[staff].clef.stafflines
				= s->as.u.clef.stafflines;
		if (s->as.u.clef.staffscale != 0)
			sy->voice[voice].clef.staffscale
				= sy->staff[staff].clef.staffscale
				= s->as.u.clef.staffscale;
	}
}

/* -- initialize the voices and staves -- */
/* this routine is called when starting the generation */
static void system_init(void)
{
	voice_compress();
	voice_dup();
	sort_all();			/* define the time / vertical sequences */
	if (!tsfirst)
		return;
	parsys->nstaff = nstaff;	/* save the number of staves */
	staves_init();
}

/* go to a global (measure + time) */
static struct SYMBOL *go_global_time(struct SYMBOL *s,
				struct symsel_s *symsel)
{
	struct SYMBOL *s2;
	int bar_time;

	if (symsel->bar <= 1) {		/* special case: there is no measure 0/1 */
//	 && nbar == -1) {		/* see set_bar_num */
		if (symsel->bar == 0)
			goto chk_time;
		for (s2 = s; s2; s2 = s2->ts_next) {
			if (s2->type == BAR
			 && s2->time != 0)
				break;
		}
		if (s2->time < voice_tb[cursys->top_voice].meter.wmeasure)
			s = s2;
		goto chk_time;
	}
	for ( ; s; s = s->ts_next) {
		if (s->type == BAR
		 && s->u >= symsel->bar)
			break;
	}
	if (!s)
		return NULL;
	if (symsel->seq != 0) {
		int seq;

		seq = symsel->seq;
		for (s = s->ts_next; s; s = s->ts_next) {
			if (s->type == BAR
			 && s->u == symsel->bar) {
				if (--seq == 0)
					break;
			}
		}
		if (!s)
			return NULL;
	}

chk_time:
	if (symsel->time == 0)
		return s;
	bar_time = s->time + symsel->time;
	while (s->time < bar_time) {
		s = s->ts_next;
		if (!s)
			return s;
	}
	do {
		s = s->ts_prev;		/* go back to the previous sequence */
	} while (!(s->sflags & S_SEQST));
	return s;
}

/* treat %%clip */
static void do_clip(void)
{
	struct SYMBOL *s, *s2;
	struct SYSTEM *sy;
	struct VOICE_S *p_voice;
	int voice;

	/* remove the beginning of the tune */
	s = tsfirst;
	if (clip_start.bar > 0
	 || clip_start.time > 0) {
		s = go_global_time(s, &clip_start);
		if (!s) {
			tsfirst = NULL;
			return;
		}

		/* update the start of voices */
		sy = cursys;
		for (s2 = tsfirst; s2 != s; s2 = s2->ts_next) {
			switch (s2->type) {
			case STAVES:
				sy = sy->next;
				break;
			case CLEF:
				memcpy(&voice_tb[s2->voice].clef, &s2->as.u.clef,
					sizeof voice_tb[0].clef);
				break;
			case KEYSIG:
				memcpy(&voice_tb[s2->voice].key, &s2->as.u.key,
					sizeof voice_tb[0].key);
				break;
			case TIMESIG:
				memcpy(&voice_tb[s2->voice].meter, &s2->as.u.meter,
					sizeof voice_tb[0].meter);
				break;
			}
		}
		cursys = sy;
		for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
			voice = p_voice - voice_tb;
			for (s2 = s; s2; s2 = s2->ts_next) {
				if (s2->voice == voice) {
					s2->prev = NULL;
					break;
				}
			}
			p_voice->sym = s2;
		}
		tsfirst = s;
		s->ts_prev = NULL;
	}

	/* remove the end of the tune */
	s = go_global_time(s, &clip_end);
	if (!s)
		return;

	/* keep the current sequence */
	do {
		s = s->ts_next;
		if (!s)
			return;
	} while (!(s->sflags & S_SEQST));

	/* cut the voices */
	for (p_voice = first_voice; p_voice; p_voice = p_voice->next) {
		voice = p_voice - voice_tb;
		for (s2 = s->ts_prev; s2; s2 = s2->ts_prev) {
			if (s2->voice == voice) {
				s2->next = NULL;
				break;
			}
		}
		if (!s2)
			p_voice->sym = NULL;
	}
	s->ts_prev->ts_next = NULL;
}

/* -- set the bar numbers and treat %%clip / %%break -- */
static void set_bar_num(void)
{
	struct SYMBOL *s;
	int bar_time, wmeasure;
	int bar_num, bar_rep;

	wmeasure = voice_tb[cursys->top_voice].meter.wmeasure;
	if (wmeasure == 0)				/* if M:none */
		wmeasure = 1;
	bar_rep = nbar;

	/* don't count a bar at start of line */
	for (s = tsfirst; ; s = s->ts_next) {
		if (!s)
			return;
		switch (s->type) {
		case TIMESIG:
		case CLEF:
		case KEYSIG:
		case FMTCHG:
		case STBRK:
			continue;
		case BAR:
			if (s->u != 0) {
				nbar = s->u;		/* (%%setbarnb) */
				break;
			}
			if (s->as.u.bar.repeat_bar
			 && s->as.text
			 && !cfmt.contbarnb) {
				if (s->as.text[0] == '1') {
					bar_rep = nbar;
				} else {
					nbar = bar_rep; /* restart bar numbering */
					s->u = nbar;
				}
			}
			break;
		}
		break;
	}

	/* set the measure number on the top bars */
	bar_time = s->time + wmeasure;	/* for incomplete measure at start of tune */
	bar_num = nbar;
	for ( ; s; s = s->ts_next) {
		switch (s->type) {
		case TIMESIG:
			wmeasure = s->as.u.meter.wmeasure;
			if (wmeasure == 0)
				wmeasure = 1;
			if (s->time < bar_time)
				bar_time = s->time + wmeasure;
			break;
		case MREST:
			bar_num += s->as.u.bar.len - 1;
			while (s->ts_next
			    && s->ts_next->type != BAR)
				s = s->ts_next;
			break;
		case BAR: {
			struct SYMBOL *s2;
			int tim;

//			if (s->as.flags & ABC_F_INVIS)
//				break;
			if (s->u != 0) {
				bar_num = s->u;		/* (%%setbarnb) */
				if (s->time < bar_time) {
					s->u = 0;
					break;
				}
			} else {
				if (s->time < bar_time)	/* incomplete measure */
					break;
				bar_num++;
			}

			/* check if any repeat bar at this time */
			tim = s->time;
			s2 = s;
			do {
				if (s2->type == BAR
				 && s2->as.u.bar.repeat_bar
				 && s2->as.text
				 && !cfmt.contbarnb) {
					if (s2->as.text[0] == '1')
						bar_rep = bar_num;
					else		/* restart bar numbering */
						bar_num = bar_rep;
					break;
				}
				s2 = s2->next;
			} while (s2 && s2->time == tim);
			s->u = bar_num;
			bar_time = s->time + wmeasure;
			break;
		}
	    }
	}

	/* do the %%clip stuff */
	if (clip_start.bar >= 0) {
		if (bar_num <= clip_start.bar
		 || nbar > clip_end.bar) {
			tsfirst = NULL;
			return;
		}
		do_clip();
	}

	/* do the %%break stuff */
	{
		struct brk_s *brk;
		int nbar_min;

//		if (nbar == 1)
//			nbar = -1;	/* see go_global_time */
		nbar_min = nbar;
		if (nbar_min == 1)
			nbar_min = -1;
		for (brk = brks; brk; brk = brk->next) {
			if (brk->symsel.bar <= nbar_min
			 || brk->symsel.bar > bar_num)
				continue;
			s = go_global_time(tsfirst, &brk->symsel);
			if (s)
				s->sflags |= S_EOLN;
		}
	}
	if (cfmt.measurenb < 0)		/* if no display of measure bar */
		nbar = bar_num;		/* update in case of more music to come */
}

/* -- generate a piece of tune -- */
static void generate(void)
{
	int voice;
	int old_lvl;

	system_init();
	if (!tsfirst)
		return;				/* no symbol */
	set_bar_num();
	if (!tsfirst)
		return;				/* no more symbol */
	old_lvl = lvlarena(2);
	output_music();
	clrarena(2);				/* clear generation */
	lvlarena(old_lvl);

	/* reset the parser */
	for (voice = 0; voice < MAXVOICE; voice++) {
		voice_tb[voice].sym = voice_tb[voice].last_sym = NULL;
		voice_tb[voice].time = 0;
		voice_tb[voice].have_ly = 0;
		voice_tb[voice].staff = cursys->voice[voice].staff;
		voice_tb[voice].second = cursys->voice[voice].second;
	}
	staves_found = 0;
}

/* -- output the music and lyrics after tune -- */
static void gen_ly(int eob)
{
	generate();
	if (info['W' - 'A']) {
		put_words(info['W' - 'A']);
		info['W' - 'A'] = NULL;
	}
	if (eob)
		buffer_eob();
}

/* for transpose purpose, check if a pitch is already in the measure
 * in the current voice and return its accidental or (-1) */
static int acc_same_pitch(int pitch)
{
	struct SYMBOL *s;
	int i;

	for (s = curvoice->last_sym; s; s = s->prev) {
		switch (s->as.type) {
		case ABC_T_BAR:
			return -1;	/* no same pitch */
		default:
			continue;
		case ABC_T_NOTE:
			break;
		}

		for (i = 0; i <= s->nhd; i++) {
			if (s->as.u.note.pits[i] == pitch)
				return s->as.u.note.accs[i];
		}
	}
	return -1;
}

/* transpose a note / chord */
static void note_transpose(struct SYMBOL *s)
{
	int i, j, m, n, d, a, dp, i1, i2, i3, i4, sf_old;
	static signed char acc1[6] = {0, 1, 0, -1, 2, -2};
	static char acc2[5] = {A_DF, A_FT, A_NT, A_SH, A_DS};

	m = s->as.u.note.nhd;
	sf_old = curvoice->okey.sf;
	i2 = curvoice->ckey.sf - sf_old;
	dp = cgd2cde[(i2 + 4 * 7) % 7];
	if (curvoice->transpose < 0
	 && dp != 0)
		dp -= 7;
	dp += curvoice->transpose / 3 / 12 * 7;
	for (i = 0; i <= m; i++) {
		n = s->as.u.note.pits[i];
		s->as.u.note.pits[i] += dp;
		i1 = cde2fcg[(n + 5 + 16 * 7) % 7];	/* fcgdaeb */
		a = s->as.u.note.accs[i] & 0x07;
		if (a == 0) {
			if (curvoice->okey.nacc == 0) {
				if (sf_old > 0) {
					if (i1 < sf_old - 1)
						a = A_SH;
				} else if (sf_old < 0) {
					if (i1 >= sf_old + 6)
						a = A_FT;
				}
			} else {
				for (j = 0; j < curvoice->okey.nacc; j++) {
					if ((n + 16 * 7 - curvoice->okey.pits[j]) % 7
								== 0) {
						a = curvoice->okey.accs[j];
						break;
					}
				}
			}
		}
		i3 = i1 + i2 + acc1[a] * 7;

		/* accidental */
		i1 = ((i3 + 1 + 21) / 7 + 2 - 3 + 32 * 5) % 5;
		a = acc2[(unsigned) i1];
		if (curvoice->ckey.empty != 0) {	/* key none */
			int other_acc;

			other_acc = acc_same_pitch(s->as.u.note.pits[i]);
			switch (s->as.u.note.accs[i]) {
			case 0:
				if (other_acc >= 0 || a == A_NT)
					continue;
				break;
			case A_NT:
				break;
			default:
				if (other_acc < 0) {
					if (a == A_NT)
						a = 0;
				} else {
					if (a == other_acc)
						a = 0;
				}
				break;
			}
		} else if (s->as.u.note.accs[i] != 0) {
			;
		} else if (curvoice->ckey.nacc > 0) {	/* acc list */
			i4 = cgd2cde[(unsigned) ((i3 + 16 * 7) % 7)];
			for (j = 0; j < curvoice->ckey.nacc; j++) {
				if ((i4 + 16 * 7 - curvoice->ckey.pits[j]) % 7
							== 0)
					break;
			}
			if (j < curvoice->ckey.nacc)
				continue;
		} else {
			continue;
		}
		i1 = s->as.u.note.accs[i] & 0x07;
		i4 = s->as.u.note.accs[i] >> 3;
		if (i4 != 0				/* microtone */
		 && i1 != a) {				/* different accidental type */
			n = micro_tb[i4];
			d = (n & 0xff) + 1;
			n = (n >> 8) + 1;
			if (a == A_NT) {
/*fixme:should treat the double sharps/flats*/
				if (n >= d) {
					n -= d;
					a = i1;
				} else {
					n = d - n;
					if (i1 == A_SH)
						a = A_FT;
					else
						a = A_SH;
				}
			}
			d--;
			d += (n - 1) << 8;
			for (i4 = 1; i4 < MAXMICRO; i4++) {
				if (micro_tb[i4] == d)
					break;
				if (micro_tb[i4] == 0) {
					micro_tb[i4] = d;
					break;
				}
			}
			if (i4 == MAXMICRO) {
				error(1, s, "Too many microtone accidentals");
				i4 = 0;
			}
		}
		s->as.u.note.accs[i] = (i4 << 3) | a;
	}
}

/* transpose a guitar chord */
static void gch_transpose(struct SYMBOL *s)
{
	char *p, *q, *new_txt;
	int l, latin;
	int n, a, i1, i2, i3, i4;
	static const char note_names[] = "CDEFGAB";
	static const char *latin_names[7] =
			{ "Do", "Ré", "Mi", "Fa", "Sol", "La", "Si" };
	static const char *acc_name[5] = {"bb", "b", "", "#", "##"};

	p = s->as.text;

	/* skip the annotations */
	for (;;) {
		if (!strchr("^_<>@", *p))
			break;
		while (*p != '\0' && *p != '\n')
			p++;
		if (*p == '\0')
			return;
		p++;
	}

	/* main chord */
	q = p + 1;
	latin = 0;
	switch (*p) {
	case 'A':
	case 'B':
		n = *p - 'A' + 5;
		break;
	case 'C':
	case 'E':
	case 'G':
		n = *p - 'C';
		break;
	case 'D':
		if (p[1] == 'o') {
			latin = 1;
			n = 0;		/* Do */
			break;
		}
		n = 1;
		break;
	case 'F':
		if (p[1] == 'a')
			latin = 1;	/* Fa */
		n = 3;
		break;
	case 'L':
		latin = 1;		/* La */
		n = 5;
		break;
	case 'M':
		latin = 1;		/* Mi */
		n = 2;
		break;
	case 'R':
		latin = 1;
		if (p[1] != 'e')
			latin++;	/* Ré */
		n = 1;			/* Re */
		break;
	case 'S':
		latin = 1;
		if (p[1] == 'o') {
			latin++;
			n = 4;		/* Sol */
		} else {
			n = 6;		/* Si */
		}
		break;
	default:
		return;
	}
	q += latin;

	/* allocate a new string */
	new_txt = getarena(strlen(s->as.text) + 6);
	l = p - s->as.text;
	memcpy(new_txt, s->as.text, l);
	s->as.text = new_txt;
	new_txt += l;
	p = q;

	i2 = curvoice->ckey.sf - curvoice->okey.sf;
	i1 = cde2fcg[n];			/* fcgdaeb */
	a = 0;
	if (*p == '#') {
		a++;
		p++;
		if (*p == '#') {
			a++;
			p++;
		}
	} else if (*p == 'b') {
		a--;
		p++;
		if (*p == 'b') {
			a--;
			p++;
		}
	} else if (*p == '=') {
		p++;
	}
	i3 = i1 + i2 + a * 7;
	i4 = cgd2cde[(unsigned) ((i3 + 16 * 7) % 7)];
	if (!latin)
		*new_txt++ = note_names[i4];
	else
		new_txt += sprintf(new_txt, "%s", latin_names[i4]);
	i1 = ((i3 + 1 + 21) / 7 + 2 - 3 + 32 * 5) % 5;
						/* accidental */
	new_txt += sprintf(new_txt, "%s", acc_name[i1]);

	/* bass */
	while (*p != '\0' && *p != '\n' && *p != '/')
		*new_txt++ = *p++;
	if (*p == '/') {
		*new_txt++ = *p++;
//fixme: latin names not treated
		q = strchr(note_names, *p);
		if (q) {
			p++;
			n = q - note_names;
			i1 = cde2fcg[n];	/* fcgdaeb */
			if (*p == '#') {
				a = 1;
				p++;
			} else if (*p == 'b') {
				a = -1;
				p++;
			} else {
				a = 0;
			}
			i3 = i1 + i2 + a * 7;
			i4 = cgd2cde[(unsigned) ((i3 + 16 * 7) % 7)];
			*new_txt++ = note_names[i4];
			i1 = ((i3 + 1 + 21) / 7 + 2 - 3 + 32 * 5) % 5;
			new_txt += sprintf(new_txt, "%s", acc_name[i1]);
		}
	}
	strcpy(new_txt, p);
}

/* -- build the guitar chords / annotations -- */
static void gch_build(struct SYMBOL *s)
{
	struct gch *gch;
	char *p, *q, antype, sep;
	float w, h_ann, h_gch, y_above, y_below, y_left, y_right;
	float xspc;
	int l, ix, box, gch_place;

	if (s->posit.gch == SL_HIDDEN)
		return;
	s->gch = getarena(sizeof *s->gch * MAXGCH);
	memset(s->gch, 0, sizeof *s->gch * MAXGCH);

	if (curvoice->transpose != 0)
		gch_transpose(s);

	/* split the guitar chords / annotations
	 * and initialize their vertical offsets */
	gch_place = s->posit.gch == SL_BELOW ? -1 : 1;
	h_gch = cfmt.font_tb[cfmt.gcf].size;
	h_ann = cfmt.font_tb[cfmt.anf].size;
	y_above = y_below = y_left = y_right = 0;
	box = cfmt.gchordbox;
	p = s->as.text;
	gch = s->gch;
	sep = '\n';
	antype = 'g';			/* (compiler warning) */
	for (;;) {
		if (sep != 'n' && strchr("^_<>@", *p)) {
			gch->font = cfmt.anf;
			antype = *p++;
			if (antype == '@') {
				int n;
				float xo, yo;

				if (sscanf(p, "%f,%f%n", &xo, &yo, &n) != 2) {
					error(1, s, "Error in annotation \"@\"");
				} else {
					p += n;
					if (*p == ' ')
						p++;
					gch->x = xo;
					gch->y = yo;
				}
			}
		} else if (sep == '\n') {
			gch->font = cfmt.gcf;
			gch->box = box;
			antype = 'g';
		} else {
			gch->font = (gch - 1)->font;
			gch->box = (gch - 1)->box;
		}
		gch->type = antype;
		switch (antype) {
		default:				/* guitar chord */
			if (gch_place < 0)
				break;			/* below */
			y_above += h_gch;
			if (box)
				y_above += 2;
			break;
		case '^':				/* above */
			y_above += h_ann;
			break;
		case '_':				/* below */
			break;
		case '<':				/* left */
			y_left += h_ann * 0.5;
			break;
		case '>':				/* right */
			y_right += h_ann * 0.5;
			break;
		case '@':				/* absolute */
			if (gch->x == 0 && gch->y == 0
			 && gch != s->gch) {		/* if not 1st line */
				gch->x = (gch - 1)->x;
				gch->y = (gch - 1)->y - h_ann;
			}
			break;
		}
		gch->idx = p - s->as.text;
		for (;;) {
			switch (*p) {
			default:
				p++;
				continue;
			case '\\':
				p++;
				if (*p == 'n') {
					p[-1] = '\0';
					break;		/* sep = 'n' */
				}
				p++;
				continue;
			case '\0':
			case ';':
			case '\n':
				break;
			}
			break;
		}
		sep = *p;
		if (sep == '\0')
			break;
		*p++ = '\0';
		gch++;
		if (gch - s->gch >= MAXGCH) {
			error(1, s, "Too many guitar chords / annotations");
			break;
		}
	}

	/* change the accidentals in the guitar chords */
	for (ix = 0, gch = s->gch; ix < MAXGCH; ix++, gch++) {
		if (gch->type == '\0')
			break;
		if (gch->type != 'g')
			continue;
		p = s->as.text + gch->idx;
		q = p;
		for (; *p != '\0'; p++) {
			switch (*p) {
			case '#':
			case 'b':
			case '=':
				if (p == q)	/* 1st char or after a slash */
					break;

				/* set the accidentals as unused utf-8 values
				 * (see subs.c) */
				switch (*p) {
				case '#':
					*p = 0x01;
					break;
				case 'b':
					*p = 0x02;
					break;
				default:
/*				case '=': */
					*p = 0x03;
					break;
				}
				break;
			case '\\':
				p++;
				switch (*p) {
				case '#':
					p[-1] = 0x01;
					goto move;
				case 'b':
					p[-1] = 0x02;
					goto move;
				case '=':
					p[-1] = 0x03;
				move:
					l = strlen(p);
					memmove(p, p + 1, l);
					p--;
					break;
				}
				break;
			case ' ':
				if (p != q)		//??
					break;
				/* fall thru */
			case '/':
				q = p + 1;
				break;
			}
		}
	}

	/* set the offsets and widths */
/*fixme:utf8*/
	for (ix = 0, gch = s->gch; ix < MAXGCH; ix++, gch++) {
		if (gch->type == '\0')
			break;
		if (gch->type == '@')
			continue;		/* no width */
		p = s->as.text + gch->idx;
		str_font(gch->font);
		w = tex_str(p);
		gch->w = w + 4;
		switch (gch->type) {
		case '_':			/* below */
			xspc = w * GCHPRE;
			if (xspc > 8)
				xspc = 8;
			gch->x = -xspc;
			y_below -= h_ann;
			gch->y = y_below;
			break;
		case '^':			/* above */
			xspc = w * GCHPRE;
			if (xspc > 8)
				xspc = 8;
			gch->x = -xspc;
			y_above -= h_ann;
			gch->y = y_above;
			break;
		default:			/* guitar chord */
			xspc = w * GCHPRE;
			if (xspc > 8)
				xspc = 8;
			gch->x = -xspc;
			if (gch_place < 0) {	/* below */
				y_below -= h_gch;
				gch->y = y_below;
				if (box) {
					y_below -= 2;
					gch->y -= 1;
				}
			} else {
				y_above -= h_gch;
				gch->y = y_above;
				if (box) {
					y_above -= 2;
					gch->y -= 1;
				}
			}
			break;
		case '<':		/* left */
			gch->x = -(w + 6);
			y_left -= h_ann;
			gch->y = y_left;
			break;
		case '>':		/* right */
			gch->x = 6;
			y_right -= h_ann;
			gch->y = y_right;
			break;
		}
	}
}

/* get the note which will receive a lyric word */
static struct SYMBOL *next_lyric_note(struct SYMBOL *s)
{
	while (s
	    && (s->as.type != ABC_T_NOTE
	     || (s->as.flags & ABC_F_GRACE)))
		s = s->next;
	return s;
}

/* -- parse lyric (vocal) lines (w:) -- */
static struct abcsym *get_lyric(struct abcsym *as)
{
	struct SYMBOL *s, *s2;
	char word[128], *p, *q;
	int ln, cont;
	struct FONTSPEC *f;

	curvoice->have_ly = curvoice->posit.voc != SL_HIDDEN;

	f = &cfmt.font_tb[cfmt.vof];
	str_font(cfmt.vof);			/* (for tex_str) */

	if (curvoice->ignore) {
		for (;;) {
			if (!as->next)
				return as;
			switch (as->next->type) {
			case ABC_T_PSCOM:
				as = process_pscomment(as->next);
				f = &cfmt.font_tb[cfmt.vof];	/* may have changed */
				str_font(cfmt.vof);
				continue;
			case ABC_T_INFO:
				if (as->next->text[0] == 'w'
				 || as->next->text[0] == '+') {
					as = as->next;
					continue;
				}
				break;
			}
			return as;
		}
	}

	/* treat all w: lines */
	cont = 0;
	ln = -1;
	s2 = s = NULL;				// have gcc happy
	for (;;) {
		if (!cont) {
			if (ln >= MAXLY) {
				error(1, s, "Too many lyric lines");
				ln--;
			}
			ln++;
			s2 = s;
			s = curvoice->lyric_start;
			if (!s)
				s = curvoice->sym;
			else
				s = s->next;
			if (!s) {
				error(1, (struct SYMBOL *) as, "w: without music");
				return as;
			}
		} else {
			cont = 0;
		}

		/* scan the lyric line */
		p = &as->text[2];
		while (*p != '\0') {
			while (isspace((unsigned char) *p))
				p++;
			if (*p == '\0')
				break;
			if (*p == '\\' && p[1] == '\0') {
				cont = 1;
				break;
			}
			switch (*p) {
			case '|':
				while (s && s->type != BAR) {
					s2 = s;
					s = s->next;
				}
				if (!s) {
					error(1, s2,
						"Not enough bar lines for lyric line");
					goto ly_next;
				}
				s2 = s;
				s = s->next;
				p++;
				continue;
			case '-':
				word[0] = LY_HYPH;
				word[1] = '\0';
				p++;
				break;
			case '_':
				word[0] = LY_UNDER;
				word[1] = '\0';
				p++;
				break;
			case '*':
				word[0] = *p++;
				word[1] = '\0';
				break;
			default:
				q = word;
				for (;;) {
					unsigned char c;

					c = *p;
					switch (c) {
					case '\0':
					case ' ':
					case '\t':
					case '_':
					case '*':
					case '|':
						break;
					case '~':
						c = ' ';
						goto addch;
					case '-':
						c = LY_HYPH;
						goto addch;
					case '\\':
						if (p[1] == '\0')
							break;
						switch (p[1]) {
						case '~':
						case '_':
						case '*':
						case '|':
						case '-':
						case ' ':
						case '\\':
							c = *++p;
							break;
						}
						/* fall thru */
					default:
					addch:
						if (q < &word[sizeof word - 1])
							*q++ = c;
						p++;
						if (c == LY_HYPH)
							break;
						continue;
					}
					break;
				}
				*q = '\0';
				break;
			}

			/* store the word in the next note */
			if (s) {				/* for error */
				s2 = s;
				s = next_lyric_note(s);
			}
			if (!s) {
				error(1, s2, "Too many words in lyric line");
				goto ly_next;
			}
			if (word[0] != '*'
			 && s->posit.voc != SL_HIDDEN) {
				struct lyl *lyl;
				float w;

				if (!s->ly) {
					s->ly = (struct lyrics *) getarena(sizeof (struct lyrics));
					memset(s->ly, 0, sizeof (struct lyrics));
				}
				w = tex_str(word);

				/* handle the font change at start of text */
				q = tex_buf;
				if (*q == '$' && isdigit((unsigned char) q[1])
				 && (unsigned) (q[1] - '0') < FONT_UMAX) {
					int ft;

					ft = q[1] - '0';
					if (ft == 0)
						ft = cfmt.vof;
					f = &cfmt.font_tb[ft];
					str_font(ft);
					q += 2;
				}
				lyl = (struct lyl *) getarena(sizeof *s->ly->lyl[0]
							    + strlen(q));
				s->ly->lyl[ln] = lyl;
				lyl->f = f;
				lyl->w = w;
				strcpy(lyl->t, q);

				/* handle the font changes inside the text */
				while (*q != '\0') {
					if (*q == '$' && isdigit((unsigned char) q[1])
					 && (unsigned) (q[1] - '0') < FONT_UMAX) {
						int ft;

						q++;
						ft = *q - '0';
						if (ft == 0)
							ft = cfmt.vof;
						f = &cfmt.font_tb[ft];
						str_font(ft);
					}
					q++;
				}
			}
			s2 = s;
			s = s->next;
		}

		/* loop if more lyrics */
ly_next:
		for (;;) {
			if (!as->next)
				goto ly_upd;
			switch (as->next->type) {
			case ABC_T_PSCOM:
				as = process_pscomment(as->next);
				f = &cfmt.font_tb[cfmt.vof];	/* may have changed */
				str_font(cfmt.vof);
				continue;
			case ABC_T_INFO:
				if (as->next->text[0] != 'w'
				 && as->next->text[0] != '+')
					goto ly_upd;
				as = as->next;
				if (as->text[0] == '+')
					cont = 1;
				if (!cont) {
					s = next_lyric_note(s);
					if (s) {
						error(1, s,
							"Not enough words for lyric line");
					}
				}
				break;			/* more lyric */
			default:
				goto ly_upd;
			}
			break;
		}
	}

	/* the next lyrics will go into the next notes */
ly_upd:
//fixme: no error with abc-2.1
	if (next_lyric_note(s))
		error(0, s, "Not enough words for lyric line");
	// fill the w: with 'blank syllabes'
	curvoice->lyric_start = curvoice->last_sym;
	return as;
}

/* -- add a voice in the linked list -- */
static void voice_link(struct VOICE_S *p_voice)
{
	struct VOICE_S *p_voice2;

	p_voice2 = first_voice;
	for (;;) {
		if (p_voice2 == p_voice)
			return;
		if (!p_voice2->next)
			break;
		p_voice2 = p_voice2->next;
	}
	p_voice2->next = p_voice;
}

/* -- get a voice overlay -- */
static void get_over(struct SYMBOL *s)
{
	struct VOICE_S *p_voice, *p_voice2, *p_voice3;
	int range, voice, voice2, voice3;
static char tx_wrong_dur[] = "Wrong duration in voice overlay";

	/* treat the end of overlay */
	p_voice = curvoice;
	if (p_voice->ignore)
		return;
	if (s->as.type == ABC_T_BAR
	 || s->as.u.v_over.type == V_OVER_E)  {
		p_voice->last_sym->sflags |= S_BEAM_END;
		over_bar = 0;
		if (over_time < 0) {
			error(1, s, "Erroneous end of voice overlap");
			return;
		}
		if (p_voice->time != over_mxtime)
			error(1, s, tx_wrong_dur);
		curvoice = &voice_tb[over_voice];
		over_voice = -1;
		over_time = -1;
		return;
	}

	/* treat the full overlay start */
	if (s->as.u.v_over.type == V_OVER_S) {
		over_time = p_voice->time;
		return;
	}

	/* (here is treated a new overlay - '&') */
	/* create the extra voice if not done yet */
	p_voice->last_sym->sflags |= S_BEAM_END;
	voice2 = s->as.u.v_over.voice;
	p_voice2 = &voice_tb[voice2];
	if (parsys->voice[voice2].range < 0) {
		int clone;

		if (cfmt.abc2pscompat) {
			error(1, s, "Cannot have %%%%abc2pscompat");
			cfmt.abc2pscompat = 0;
		}
		clone = p_voice->clone >= 0;
		p_voice2->id[0] = '&';
		p_voice2->id[1] = '\0';
		p_voice2->second = 1;
		parsys->voice[voice2].second = 1;
		p_voice2->scale = p_voice->scale;
		p_voice2->octave = p_voice->octave;
		p_voice2->transpose = p_voice->transpose;
		memcpy(&p_voice2->key, &p_voice->key,
					sizeof p_voice2->key);
		memcpy(&p_voice2->ckey, &p_voice->ckey,
					sizeof p_voice2->ckey);
		memcpy(&p_voice2->okey, &p_voice->okey,
					sizeof p_voice2->okey);
		p_voice2->posit = p_voice->posit;
		range = parsys->voice[p_voice - voice_tb].range;
		for (voice = 0; voice < MAXVOICE; voice++) {
			if (parsys->voice[voice].range > range)
				parsys->voice[voice].range += clone + 1;
		}
		parsys->voice[voice2].range = range + 1;
		voice_link(p_voice2);
		if (clone) {
			for (voice3 = MAXVOICE; --voice3 >= 0; ) {
				if (parsys->voice[voice3].range < 0)
					break;
			}
			if (voice3 > 0) {
				p_voice3 = &voice_tb[voice3];
				strcpy(p_voice3->id, p_voice2->id);
				p_voice3->second = 1;
				parsys->voice[voice3].second = 1;
				p_voice3->scale = voice_tb[p_voice->clone].scale;
				parsys->voice[voice3].range = range + 2;
				voice_link(p_voice3);
				p_voice2->clone = voice3;
			} else {
				error(1, s,
				      "Too many voices for overlay cloning");
			}
		}
	}
	voice = p_voice - voice_tb;
	p_voice2->cstaff = p_voice2->staff = parsys->voice[voice2].staff
			= parsys->voice[voice].staff;
	if ((voice3 = p_voice2->clone) >= 0) {
		p_voice3 = &voice_tb[voice3];
		p_voice3->cstaff = p_voice3->staff
				= parsys->voice[voice3].staff
				= parsys->voice[p_voice->clone].staff;
	}

	if (over_time < 0) {			/* first '&' in a measure */
		int time;

		over_bar = 1;
		over_mxtime = p_voice->time;
		over_voice = voice;
		time = p_voice2->time;
		for (s = p_voice->last_sym; /*s*/; s = s->prev) {
			if (s->type == BAR
			 || s->time <= time)	/* (if start of tune) */
				break;
		}
		over_time = s->time;
	} else {
		if (over_voice < 0) {
			over_mxtime = p_voice->time;
			over_voice = voice;
		} else if (p_voice->time != over_mxtime)
			error(1, s, tx_wrong_dur);
	}
	p_voice2->time = over_time;
	curvoice = p_voice2;
}

struct staff_s {
	short voice;
	short flags;
};

/* -- parse %%staves / %%score -- */
static void parse_staves(struct SYMBOL *s,
			struct staff_s *staves)
{
	char *p;
	int voice, flags_st, brace, bracket, parenth, err;
	short flags;
	struct staff_s *p_staff;

	/* define the voices */
	err = 0;
	flags = 0;
	brace = bracket = parenth = 0;
	flags_st = 0;
	voice = 0;
	p = s->as.text + 7;
	while (*p != '\0' && !isspace((unsigned char) *p))
		p++;
	while (*p != '\0') {
		switch (*p) {
		case ' ':
		case '\t':
			break;
		case '[':
			if (parenth || brace + bracket >= 2) {
				error(1, s, "Misplaced '[' in %%%%staves");
				err = 1;
				break;
			}
			if (brace + bracket == 0)
				flags |= OPEN_BRACKET;
			else
				flags |= OPEN_BRACKET2;
			bracket++;
			flags_st <<= 8;
			flags_st |= OPEN_BRACKET;
			break;
		case '{':
			if (parenth || brace || bracket >= 2) {
				error(1, s, "Misplaced '{' in %%%%staves");
				err = 1;
				break;
			}
			if (bracket == 0)
				flags |= OPEN_BRACE;
			else
				flags |= OPEN_BRACE2;
			brace++;
			flags_st <<= 8;
			flags_st |= OPEN_BRACE;
			break;
		case '(':
			if (parenth) {
				error(1, s, "Misplaced '(' in %%%%staves");
				err = 1;
				break;
			}
			flags |= OPEN_PARENTH;
			parenth++;
			flags_st <<= 8;
			flags_st |= OPEN_PARENTH;
			break;
		case '*':
			if (brace && !parenth && !(flags & (OPEN_BRACE | OPEN_BRACE2)))
				flags |= FL_VOICE;
			break;
		default:
			if (!isalnum((unsigned char) *p) && *p != '_') {
				error(1, s, "Bad voice ID in %%%%staves");
				err = 1;
				break;
			}
			if (voice >= MAXVOICE) {
				error(1, s, "Too many voices in %%%%staves");
				err = 1;
				break;
			}
			{
				int i, v;
				char sep, *q;

				q = p;
				while (isalnum((unsigned char) *p) || *p == '_')
					p++;
				sep = *p;
				*p = '\0';

				/* search the voice in the voice table */
				v = -1;
				for (i = 0; i < MAXVOICE; i++) {
					if (strcmp(q, voice_tb[i].id) == 0) {
						v = i;
						break;
					}
				}
				if (v < 0) {
					error(1, s,
						"Voice '%s' of %%%%staves has no symbol",
						q);
					err = 1;
//					break;
					p_staff = staves;
				} else {
					p_staff = staves + voice++;
					p_staff->voice = v;
				}
				*p = sep;
			}
			for (;;) {
				switch (*p) {
				case ' ':
				case '\t':
					p++;
					continue;
				case ']':
					if (!(flags_st & OPEN_BRACKET)) {
						error(1, s,
							"Misplaced ']' in %%%%staves");
						err = 1;
						break;
					}
					bracket--;
					if (brace + bracket == 0)
						flags |= CLOSE_BRACKET;
					else
						flags |= CLOSE_BRACKET2;
					flags_st >>= 8;
					p++;
					continue;
				case '}':
					if (!(flags_st & OPEN_BRACE)) {
						error(1, s,
							"Misplaced '}' in %%%%staves");
						err = 1;
						break;
					}
					brace--;
					if (bracket == 0)
						flags |= CLOSE_BRACE;
					else
						flags |= CLOSE_BRACE2;
					flags &= ~FL_VOICE;
					flags_st >>= 8;
					p++;
					continue;
				case ')':
					if (!(flags_st & OPEN_PARENTH)) {
						error(1, s,
							"Misplaced ')' in %%%%staves");
						err = 1;
						break;
					}
					parenth--;
					flags |= CLOSE_PARENTH;
					flags_st >>= 8;
					p++;
					continue;
				case '|':
					flags |= STOP_BAR;
					p++;
					continue;
				}
				break;
			}
			p_staff->flags = flags;
			flags = 0;
			if (*p == '\0')
				break;
			continue;
		}
		if (*p == '\0')
			break;
		p++;
	}
	if (flags_st != 0) {
		error(1, s, "'}', ')' or ']' missing in %%%%staves");
		err = 1;
	}
	if (err) {
		int i;

		for (i = 0; i < voice; i++)
			staves[i].flags = 0;
	}
	if (voice < MAXVOICE)
		staves[voice].voice = -1;
}

/* -- get staves definition (%%staves / %%score) -- */
static void get_staves(struct SYMBOL *s)
{
	struct VOICE_S *p_voice, *p_voice2;
	struct staff_s *p_staff, staves[MAXVOICE];
	int i, flags, voice, staff, range, dup_voice, maxtime;

	voice_compress();
	voice_dup();

	/* create a new staff system */
	curvoice = p_voice = first_voice;
	maxtime = p_voice->time;
	flags = p_voice->sym != NULL;
	for (p_voice = p_voice->next; p_voice; p_voice = p_voice->next) {
		if (p_voice->time > maxtime)
			maxtime = p_voice->time;
		if (p_voice->sym)
			flags = 1;
	}
	if (flags == 0			/* if first %%staves */
	 || (maxtime == 0 && staves_found < 0)) {
		for (voice = 0; voice < MAXVOICE; voice++)
			parsys->voice[voice].range = -1;
	} else {

		/*
		 * create a new staff system and
		 * link the staves in a voice which is seen from
		 * the previous system - see sort_all
		 */
		p_voice = curvoice;
		if (parsys->voice[p_voice - voice_tb].range < 0) {
			for (voice = 0; voice < MAXVOICE; voice++) {
				if (parsys->voice[voice].range >= 0) {
					curvoice = &voice_tb[voice];
					break;
				}
			}
/*fixme: should check if voice < MAXVOICE*/
		}
		curvoice->time = maxtime;
		sym_link(s, STAVES);	/* link the staves in the current voice */
		s->as.state = ABC_S_HEAD; /* (output PS sequences immediately) */
		parsys->nstaff = nstaff;
		system_new();
	}
	staves_found = maxtime;

	memset(staves, 0, sizeof staves);
	parse_staves(s, staves);

	/* initialize the voices */
	for (voice = 0, p_voice = voice_tb;
	     voice < MAXVOICE;
	     voice++, p_voice++) {
		p_voice->second = 0;
		p_voice->floating = 0;
		p_voice->ignore = 0;
		p_voice->time = maxtime;
	}
	dup_voice = MAXVOICE;
	range = 0;
	p_staff = staves;
	parsys->top_voice = p_staff->voice;
	for (i = 0;
	     i < MAXVOICE && p_staff->voice >= 0;
	     i++, p_staff++) {
		voice = p_staff->voice;
		p_voice = &voice_tb[voice];
		if (parsys->voice[voice].range >= 0) {
			if (parsys->voice[dup_voice - 1].range >= 0) {
				error(1, s, "Too many voices for cloning");
				continue;
			}
			voice = --dup_voice;	/* duplicate the voice */
			p_voice2 = &voice_tb[voice];
			memcpy(p_voice2, p_voice, sizeof *p_voice2);
			p_voice2->next = NULL;
			p_voice2->sym = p_voice2->last_sym = NULL;
			p_voice2->tblts[0] = p_voice2->tblts[1] = NULL;
			p_voice2->clone = -1;
			while (p_voice->clone > 0)
				p_voice = &voice_tb[p_voice->clone];
			p_voice->clone = voice;
			p_voice = p_voice2;
			p_staff->voice = voice;
		}
		parsys->voice[voice].range = range++;
		voice_link(p_voice);
	}

	/* change the behavior from %%staves to %%score */
	if (s->as.text[3] == 't') {		/* if %%staves */
		for (i = 0, p_staff = staves;
		     i < MAXVOICE - 2 && p_staff->voice >= 0;
		     i++, p_staff++) {
			flags = p_staff->flags;
			if (!(flags & (OPEN_BRACE | OPEN_BRACE2)))
				continue;
			if ((flags & (OPEN_BRACE | CLOSE_BRACE))
					== (OPEN_BRACE | CLOSE_BRACE)
			 || (flags & (OPEN_BRACE2 | CLOSE_BRACE2))
					== (OPEN_BRACE2 | CLOSE_BRACE2))
				continue;
			if (p_staff[1].flags != 0)
				continue;
			if ((flags & OPEN_PARENTH)
			 || (p_staff[2].flags & OPEN_PARENTH))
				continue;

			/* {a b c} --> {a *b c} */
			if (p_staff[2].flags & (CLOSE_BRACE | CLOSE_BRACE2)) {
				p_staff[1].flags |= FL_VOICE;

			/* {a b c d} --> {(a b) (c d)} */
			} else if (p_staff[2].flags == 0
				 && (p_staff[3].flags & (CLOSE_BRACE | CLOSE_BRACE2))) {
				p_staff->flags |= OPEN_PARENTH;
				p_staff[1].flags |= CLOSE_PARENTH;
				p_staff[2].flags |= OPEN_PARENTH;
				p_staff[3].flags |= CLOSE_PARENTH;
			}
		}
	}

	/* set the staff system */
	staff = -1;
	for (i = 0, p_staff = staves;
	     i < MAXVOICE && p_staff->voice >= 0;
	     i++, p_staff++) {
		flags = p_staff->flags;
		if ((flags & (OPEN_PARENTH | CLOSE_PARENTH))
				== (OPEN_PARENTH | CLOSE_PARENTH)) {
			flags &= ~(OPEN_PARENTH | CLOSE_PARENTH);
			p_staff->flags = flags;
		}
		voice = p_staff->voice;
		p_voice = &voice_tb[voice];
		if (flags & FL_VOICE) {
			p_voice->floating = 1;
			p_voice->second = 1;
		} else {
#if MAXSTAFF < MAXVOICE
			if (staff >= MAXSTAFF - 1) {
				error(1, s, "Too many staves");
			} else
#endif
				staff++;
			parsys->staff[staff].flags = 0;
		}
		p_voice->staff = p_voice->cstaff
				= parsys->voice[voice].staff = staff;
		parsys->staff[staff].flags |= flags;
		if (flags & OPEN_PARENTH) {
			while (i < MAXVOICE) {
				i++;
				p_staff++;
				voice = p_staff->voice;
				p_voice = &voice_tb[voice];
				p_voice->second = 1;
				p_voice->staff = p_voice->cstaff
						= parsys->voice[voice].staff
						= staff;
				if (p_staff->flags & CLOSE_PARENTH)
					break;
			}
			parsys->staff[staff].flags |= p_staff->flags;
		}
	}
	if (staff < 0)
		staff = 0;
	nstaff = staff;

	/* change the behaviour of '|' in %%score */
	if (s->as.text[3] == 'c') {		/* if %%score */
		for (staff = 0; staff <= nstaff; staff++)
			parsys->staff[staff].flags ^= STOP_BAR;
	}

	for (voice = 0; voice < MAXVOICE; voice++) {
		p_voice = &voice_tb[voice];
		parsys->voice[voice].second = p_voice->second;
		staff = p_voice->staff;
		if (staff > 0)
			p_voice->norepbra
				= !(parsys->staff[staff - 1].flags & STOP_BAR);
	}
}

/* -- re-initialize all potential voices -- */
static void voice_init(void)
{
	struct VOICE_S *p_voice;
	int i;

	for (i = 0, p_voice = voice_tb;
	     i < MAXVOICE;
	     i++, p_voice++) {
		p_voice->sym = p_voice->last_sym = NULL;
		p_voice->lyric_start = NULL;
		p_voice->bar_start = 0;
		p_voice->time = 0;
		p_voice->slur_st = 0;
		p_voice->hy_st = 0;
		p_voice->tie = 0;
		p_voice->rtie = 0;
	}
}

/* output a pdf mark */
static void put_pdfmark(char *p)
{
	unsigned char c, *q;
	int u;

	p = trim_title(p, 0);

	/* check if pure ASCII without '\', '(' nor ')'*/
	for (q = (unsigned char *) p; *q != '\0'; q++) {
		switch (*q) {
		case '\\':
		case '(':
		case ')':
			break;
		default:
			if (*q >= 0x80)
				break;
			continue;
		}
		break;
	}
	if (*q == '\0') {
		a2b("[/Title(%s)/OUT pdfmark\n", p);
		return;
	}

	/* build utf-8 mark */
	a2b("[/Title<FEFF");
	q = (unsigned char *) p;
	u = -1;
	while (*q != '\0') {
		c = *q++;
		if (c < 0x80) {
			if (u >= 0) {
				a2b("%04X", u);
				u = -1;
			}
			a2b("%04X", (int) c);
			continue;
		}
		if (c < 0xc0) {
			u = (u << 6) | (c & 0x3f);
			continue;
		}
		if (u >= 0) {
			a2b("%04X", u);
			u = -1;
		}
		if (c < 0xe0)
			u = c & 0x1f;
		else if (c < 0xf0)
			u = c & 0x0f;
		else
			u = c & 0x07;
	}
	if (u >= 0) {
		a2b("%04X", u);
		u = -1;
	}
	a2b(">/OUT pdfmark\n");
}

/* rebuild a tune header for %%tune filter */
static char *tune_header_rebuild(struct abcsym *as)
{
	struct abcsym *as2;
	char *header, *p;
	int len;

	len = 0;
	as2 = as;
	for (;;) {
		if (as2->type == ABC_T_INFO) {
			len += strlen(as2->text) + 1;
			if (as2->text[0] == 'K')
				break;
		}
		as2 = as2->next;
	}
	header = malloc(len + 1);
	p = header;
	for (;;) {
		if (as->type == ABC_T_INFO) {
			strcpy(p, as->text);
			p += strlen(p);
			*p++ = '\n';
			if (as->text[0] == 'K')
				break;
		}
		as = as->next;
	}
	*p++ = '\0';
	return header;
}

/* apply the options to the current tune */
static void tune_filter(struct abcsym *as)
{
	struct tune_opt_s *opt;
	struct SYMBOL *s, *s2;
	struct slre slre;
	char *header, *p;

	header = tune_header_rebuild(as);
	for (opt = tune_opts; opt; opt = opt->next) {
		struct abcsym *last_staves;

		p = &opt->s->as.text[2 + 5];	/* "%%tune RE" */
		while (isspace((unsigned char) *p))
			p++;
		if (!slre_compile(&slre, p))
			continue;
		if (!slre_match(&slre, header, strlen(header), 0))
			continue;

		/* apply the options */
		cur_tune_opts = opt;
		last_staves = as->next;
		for (s = opt->s->next; s; s = s->next) {
			struct abcsym *as2;

			/* replace the next %%staves/%%score */
			as2 = (struct abcsym *) s;
			if (as2->type == ABC_T_PSCOM
			 && (strncmp(&as2->text[2], "staves", 6) == 0
			  || strncmp(&as2->text[2], "score", 5) == 0)) {
				while (last_staves) {
					if (last_staves->type == ABC_T_PSCOM
					 && (strncmp(&last_staves->text[2],
								"staves", 6) == 0
					  || strncmp(&last_staves->text[2],
								 "score", 5) == 0)) {
						last_staves->text = as2->text;
						last_staves = last_staves->next;
						break;
					}
					last_staves = last_staves->next;
				}
				continue;
			}
			s2 = (struct SYMBOL *) getarena(sizeof *s2);
			memcpy(s2, s, sizeof *s2);
			process_pscomment((struct abcsym *) s2);
		}
		cur_tune_opts = NULL;
		tune_voice_opts = opt->voice_opts;	// for %%voice
//fixme: what if many %%tune's with %%voice inside?
	}
	free(header);
}

/* apply the options of the current voice */
static void voice_filter(void)
{
	struct voice_opt_s *opt;
	struct SYMBOL *s;
	struct slre slre;
	int pass;
	char *p;

	/* scan the global, then the tune options */
	pass = 0;
	opt = voice_opts;
	for (;;) {
		if (!opt) {
			if (pass != 0)
				break;
			opt = tune_voice_opts;
			if (!opt)
				break;
			pass++;
		}
		p = &opt->s->as.text[2 + 6];	/* "%%voice RE" */
		while (isspace((unsigned char) *p))
			p++;
		if (!slre_compile(&slre, p))
			goto next_voice;
		if (!slre_match(&slre, curvoice->id, strlen(curvoice->id), 0)
		 && (curvoice->nm == 0
		  || !slre_match(&slre, curvoice->nm, strlen(curvoice->nm), 0)))
			goto next_voice;

		/* apply the options */
		for (s = opt->s->next; s; s = s->next) {
			struct SYMBOL *s2;

			s2 = (struct SYMBOL *) getarena(sizeof *s2);
			memcpy(s2, s, sizeof *s2);
			process_pscomment((struct abcsym *) s2);
		}
next_voice:
		opt = opt->next;
	}
}

/* -- check if a pseudo-comment may be in the tune header -- */
static int check_header(struct abcsym *as)
{
	switch (as->text[2]) {
	case 'E':
		if (strncmp(as->text + 3, "PS", 2) == 0)
			return 0;
		break;
	case 'm':
		if (strncmp(as->text + 3, "ulticol", 7) == 0)
			return 0;
		break;
	}
	return 1;
}

/* -- set the global definitions after the first K: or middle-tune T:'s -- */
static void set_global_def(void)
{
	struct VOICE_S *p_voice;
	int i;

	for (i = MAXVOICE, p_voice = voice_tb;
	     --i >= 0;
	     p_voice++) {
		if (p_voice->key.mode >= BAGPIPE
		 && p_voice->posit.std == 0)
			p_voice->posit.std = SL_BELOW;
		p_voice->transpose = cfmt.transpose;
		if (p_voice->key.empty)
			p_voice->key.sf = 0;
	}

	/* switch to the 1st voice */
	curvoice = &voice_tb[parsys->top_voice];
}

/* -- get the global definitions after the first K: or middle-tune T:'s -- */
static struct abcsym *get_global_def(struct abcsym *as,
				     struct abctune *t)
{
	struct abcsym *as2;

	for (;;) {
		as2 = as->next;
		if (!as2)
			break;
		switch (as2->type) {
		case ABC_T_INFO:
			switch (as2->text[0]) {
			case 'K':
				as = as2;
				as->state = ABC_S_HEAD;
				get_key((struct SYMBOL *) as);
				continue;
			case 'I':
			case 'M':
			case 'Q':
				as = as2;
				as->state = ABC_S_HEAD;
				as = get_info(as, t);
				continue;
			}
			break;
		case ABC_T_PSCOM:
			if (!check_header(as2))
				break;
			as = as2;
			as->state = ABC_S_HEAD;
			as = process_pscomment(as);
			continue;
		}
		break;
	}
	set_global_def();
	return as;
}

/* -- identify info line, store in proper place	-- */
static struct abcsym *get_info(struct abcsym *as,
		     struct abctune *t)
{
	struct SYMBOL *s, *s2;
	struct VOICE_S *p_voice;
	char *p;
	char info_type;
	int old_lvl;
	static char *state_txt[] = {"global", "header", "tune"};

	/* change arena to global or tune */
	old_lvl = lvlarena(as->state != ABC_S_GLOBAL);

	s = (struct SYMBOL *) as;
	info_type = as->text[0];
	switch (info_type) {
	case 'd':
		break;
	case 'I':
		as = process_pscomment(as);	/* same as pseudo-comment */
		break;
	case 'K':
		get_key(s);
		if (as->state != ABC_S_HEAD)
			break;
		info['K' - 'A'] = s;		/* first K:, end of tune header */
		tunenum++;

		if (!epsf) {
			if (!cfmt.oneperpage)
				use_buffer = !cfmt.splittune;
			bskip(cfmt.topspace);
		}
		write_heading(t);
		block_put();

		/* information for index
		 * (pdfmark must be after title show for Adobe Distiller) */
		s2 = info['T' - 'A'];
		p = &s2->as.text[2];
		if (*p != '\0') {
			a2b("%% --- font ");
			outft = -1;
			set_font(TITLEFONT);		/* font in comment */
			a2b("\n");
			outft = -1;
		}
		if (cfmt.pdfmark) {
			if (*p != '\0')
				put_pdfmark(p);
			if (cfmt.pdfmark > 1) {
				for (s2 = s2->next; s2; s2 = s2->next) {
					p = &s2->as.text[2];
					if (*p != '\0')
						put_pdfmark(p);
				}
			}
		}

		nbar = cfmt.measurefirst;	/* measure numbering */
		over_voice = -1;
		over_time = -1;
		over_bar = 0;
		reset_gen();

		as = get_global_def(as, t);

		if (!(cfmt.fields[0] & (1 << ('Q' - 'A'))))
			info['Q' - 'A'] = NULL;

		/* apply the filter for the voice '1' */
		voice_filter();

		/* activate the default tablature if not yet done */
		if (!first_voice->tblts[0])
			set_tblt(first_voice);
		break;
	case 'L':
		switch (as->state) {
		case ABC_S_HEAD: {
			int i, auto_len;

			auto_len = as->u.length.base_length < 0;

			for (i = MAXVOICE, p_voice = voice_tb;
			     --i >= 0;
			     p_voice++)
				p_voice->auto_len = auto_len;
			break;
		    }
		case ABC_S_TUNE:
			curvoice->auto_len = as->u.length.base_length < 0;
			break;
		}
		break;
	case 'M':
		get_meter(s);
		break;
	case 'P': {
		struct VOICE_S *curvoice_sav;

		if (as->state != ABC_S_TUNE) {
			info['P' - 'A'] = s;
			break;
		}

		if (!(cfmt.fields[0] & (1 << ('P' - 'A'))))
			break;
		p_voice = &voice_tb[parsys->top_voice];

		/* if not main voice and if voices are synchronized
		 * then, misplaced P: goes in the main voice */ 
		if (curvoice != p_voice
		 && curvoice->time == p_voice->time) {
			curvoice_sav = curvoice;
			curvoice = p_voice;
			sym_link(s, PART);
			curvoice = curvoice_sav;
			break;
		}
		sym_link(s, PART);
		break;
	    }
	case 'Q':
		if (!(cfmt.fields[0] & (1 << ('Q' - 'A'))))
			break;
		if (as->state != ABC_S_TUNE) {
			info['Q' - 'A'] = s;
			break;
		}
		if (curvoice != &voice_tb[parsys->top_voice])
			break;		/* tempo only for first voice */
		s2 = curvoice->last_sym;
		if (s2) {			/* keep last Q: */
			int tim;

			tim = s2->time;
			do {
				if (s2->type == TEMPO) {
					if (!s2->next)
						curvoice->last_sym = s2->prev;
					else
						s2->next->prev = s2->prev;
					if (!s2->prev)
						curvoice->sym = s2->next;
					else
						s2->prev->next = s2->next;
					break;
				}
				s2 = s2->prev;
			} while (s2 && s2->time == tim);
		}
		sym_link(s, TEMPO);
		break;
	case 'r':
	case 's':
		break;
	case 'T':
		if (as->state == ABC_S_GLOBAL)
			break;
		if (as->state == ABC_S_HEAD)		/* in tune header */
			goto addinfo;
		gen_ly(1);				/* in tune */
		p = &as->text[2];
		if (*p != '\0') {
			write_title(s);
			a2b("%% --- + (%s) ---\n", p);
			if (cfmt.pdfmark)
				put_pdfmark(p);
		}
		voice_init();
		reset_gen();		/* (display the time signature) */
		as = get_global_def(as, t);
		break;
	case 'U':
		deco[as->u.user.symbol] = deco_intern(as->u.user.value);
		break;
	case 'u':
		break;
	case 'V':
		get_voice(s);

		/* handle here the possible clef which could be replaced
		 * in case of filter */
		if (as->next && as->next->type == ABC_T_CLEF) {
			as = as->next;
			get_clef((struct SYMBOL *) as);
		}
		if (as->state == ABC_S_TUNE
		 && !curvoice->last_sym
		 && curvoice->time == 0)
			voice_filter();
		break;
	case 'w':
		if (as->state != ABC_S_TUNE)
			break;
		if (!(cfmt.fields[1] & (1 << ('w' - 'a')))) {
			while (as->next) {
				if (as->next->type != ABC_T_INFO
				 || as->next->text[0] != '+')
					break;
				as = as->next;
			}
			break;
		}
		as = get_lyric(as);
		break;
	case 'W':
		if (as->state == ABC_S_GLOBAL)
			break;
		goto addinfo;
	case 'X':
		if (!epsf) {
			buffer_eob();	/* flush stuff left from %% lines */
			write_buffer();
		}
		memcpy(&dfmt, &cfmt, sizeof dfmt); /* save global values */
		memcpy(&info_glob, &info, sizeof info_glob);
		memcpy(deco_glob, deco, sizeof deco_glob);
		info['X' - 'A'] = s;
		if (tune_opts)
			tune_filter(as);
		break;
	default:
		if (info_type >= 'A' && info_type <= 'Z') {
			struct SYMBOL *prev;

addinfo:
			if (!(cfmt.fields[0] & (1 << (info_type - 'A')))
			 && as->state != ABC_S_GLOBAL
			 && as->state != ABC_S_HEAD)
				break;
			prev = info[info_type - 'A'];
			if (!prev
			 || (prev->as.state == ABC_S_GLOBAL
			  && as->state != ABC_S_GLOBAL)) {
				info[info_type - 'A'] = s;
				break;
			}
			while (prev->next)
				prev = prev->next;
			prev->next = s;
			s->prev = prev;
			break;
		}
		if (as->state != ABC_S_GLOBAL)
			error(1, s, "%s info '%c:' not treated",
				state_txt[(int) as->state], info_type);
		break;
	}
	lvlarena(old_lvl);
	return as;
}

/* -- set head type, dots, flags for note -- */
void identify_note(struct SYMBOL *s,
		   int dur,
		   int *p_head,
		   int *p_dots,
		   int *p_flags)
{
	int head, dots, flags;

	if (dur % 12 != 0)
		error(1, s, "Invalid note duration");
	dur /= 12;			/* see BASE_LEN for values */
	if (dur == 0)
		error(1, s, "Note too short");
	for (flags = 5; dur != 0; dur >>= 1, flags--) {
		if (dur & 1)
			break;
	}
	dur >>= 1;
	switch (dur) {
	case 0: dots = 0; break;
	case 1: dots = 1; break;
	case 3: dots = 2; break;
	case 7: dots = 3; break;
	default:
		error(1, s, "Note too much dotted");
		dots = 3;
		break;
	}
	flags -= dots;
	if (flags >= 0) {
		head = H_FULL;
	} else switch (flags) {
	default:
		error(1, s, "Note too long");
		flags = -4;
		/* fall thru */
	case -4:
		head = H_SQUARE;
		break;
	case -3:
		head = cfmt.squarebreve ? H_SQUARE : H_OVAL;
		break;
	case -2:
		head = H_OVAL;
		break;
	case -1:
		head = H_EMPTY;
		break;
	}
	*p_head = head;
	*p_flags = flags;
	*p_dots = dots;
}

/* -- adjust the duration and time of symbols in a measure when L:auto -- */
static void adjust_dur(struct SYMBOL *s)
{
	struct SYMBOL *s2;
	int time, auto_time;

	/* search the start of the measure */
	s2 = curvoice->last_sym;
	if (!s2)
		return;

	/* the bar time is correct if there is multi-rests */
	if (s2->type == MREST
	 || s2->type == BAR)		/* in second voice */
		return;
	while (s2->type != BAR && s2->prev)
		s2 = s2->prev;
	time = s2->time;
	auto_time = curvoice->time - time;

	/* remove the invisible rest at start of tune */
	if (time == 0) {
		while (s2 && s2->dur == 0)
			s2 = s2->next;
		if (s2 && s2->as.type == ABC_T_REST
		 && (s2->as.flags & ABC_F_INVIS)) {
			time += s2->dur * curvoice->wmeasure / auto_time;
			if (s2->prev)
				s2->prev->next = s2->next;
			else
				curvoice->sym = s2->next;
			if (s2->next)
				s2->next->prev = s2->prev;
			s2 = s2->next;
		}
	}
	if (curvoice->wmeasure == auto_time)
		return;				/* already good duration */

	for (; s2; s2 = s2->next) {
		int i, head, dots, nflags;

		s2->time = time;
		if (s2->dur == 0
		 || (s2->as.flags & ABC_F_GRACE))
			continue;
		s2->dur = s2->dur * curvoice->wmeasure / auto_time;
		time += s2->dur;
		if (s2->type != NOTEREST)
			continue;
		for (i = 0; i <= s2->nhd; i++)
			s2->as.u.note.lens[i] = s2->as.u.note.lens[i]
					 * curvoice->wmeasure / auto_time;
		identify_note(s2, s2->as.u.note.lens[0],
				&head, &dots, &nflags);
		s2->head = head;
		s2->dots = dots;
		s2->nflags = nflags;
		if (s2->nflags <= -2)
			s2->as.flags |= ABC_F_STEMLESS;
		else
			s2->as.flags &= ~ABC_F_STEMLESS;
	}
	curvoice->time = s->time = time;
}

/* -- measure bar -- */
static void get_bar(struct SYMBOL *s)
{
	int bar_type;
	struct SYMBOL *s2, *s3;

	if (curvoice->norepbra && s->as.u.bar.repeat_bar)
		s->sflags |= S_NOREPBRA;
	if (curvoice->auto_len)
		adjust_dur(s);

	bar_type = s->as.u.bar.type;
	s3 = NULL;
	s2 = curvoice->last_sym;
	if (s2) {

		/* remove the invisible repeat bars when no shift is needed */
		if (bar_type == B_OBRA
		 && (curvoice == &voice_tb[parsys->top_voice]
		  || (parsys->staff[curvoice->staff - 1].flags & STOP_BAR)
		  || (s->sflags & S_NOREPBRA))) {
			if (s2->type == BAR && !s2->as.text) {
				s2->as.text = s->as.text;
				s2->as.u.bar.repeat_bar = s->as.u.bar.repeat_bar;
				s2->sflags |= (s->sflags & S_NOREPBRA);
				s = s2;
				goto gch_build;
			}
		}

		/* merge back-to-back repeat bars */
		if (bar_type == B_LREP && !s->as.text) {
			if (s2->type == BAR
			 && s2->as.u.bar.type == B_RREP) {
				s2->as.u.bar.type = B_DREP;
				return;
			}
		}
	}

	/* link the bar in the voice */
	if (s3) {
		s2 = curvoice->last_sym;
		curvoice->last_sym = s3->prev;
		sym_link(s, BAR);
		s->next = s3;
		s3->prev = s;
		curvoice->last_sym = s2;
	} else {
		sym_link(s, BAR);
	}
	s->staff = curvoice->staff;	/* original staff */

	/* set some flags */
	switch (bar_type) {
	case B_OBRA:
/*	case B_CBRA:			thick bar or end of repeat braket */
	case (B_OBRA << 4) + B_CBRA:
		s->as.flags |= ABC_F_INVIS;
		break;
	case (B_COL << 8) + (B_BAR << 4) + B_COL:
	case (B_COL << 12) + (B_BAR << 8) + (B_BAR << 4) + B_COL:
		bar_type = (B_COL << 4) + B_COL;	/* :|: and :||: -> :: */
		s->as.u.bar.type = bar_type;
		break;
	}
	if ((bar_type & 0xf0) != 0) {
		do {
			bar_type >>= 4;
		} while ((bar_type & 0xf0) != 0);
		if (bar_type == B_COL)
			s->sflags |= S_RRBAR;
	}
	if (s->as.u.bar.dc.n > 0)
		deco_cnv(&s->as.u.bar.dc, s, 0); /* convert the decorations */

	/* build the gch */
gch_build:
	if (s->as.text) {
		if (!s->as.u.bar.repeat_bar) {
			gch_build(s);	/* build the guitar chords */
		} else {
			s->gch = getarena(sizeof *s->gch * 2);
			memset(s->gch, 0, sizeof *s->gch * 2);
			s->gch->type = 'r';
			s->gch->font = REPEATFONT;
			str_font(REPEATFONT);
			s->gch->w = tex_str(s->as.text);
			s->gch->x = 4 + 4;
		}
	}
}

/* -- activate the tablature from the command line '-T' -- */
static void set_tblt(struct VOICE_S *p_voice)
{
	struct tblt_s *tblt;
	int i;

	for (i = 0; i < ncmdtblt; i++) {
		if (!cmdtblts[i].active)
			continue;
		if (cmdtblts[i].vn[0] != '\0') {
			if (strcmp(cmdtblts[i].vn, p_voice->id) != 0
			 && (p_voice->nm == 0
			  || strcmp(cmdtblts[i].vn, p_voice->nm) != 0)
			 && (p_voice->snm == 0
			  || strcmp(cmdtblts[i].vn, p_voice->snm) != 0))
				continue;
		}
		tblt = tblts[cmdtblts[i].index];
		if (p_voice->tblts[0] == tblt
		 || p_voice->tblts[1] == tblt)
			continue;
		if (p_voice->tblts[0] == 0)
			p_voice->tblts[0] = tblt;
		else
			p_voice->tblts[1] = tblt;
	}
}

/* -- do a tune -- */
void do_tune(struct abctune *t)
{
	struct abcsym *as;
	struct SYMBOL *s, *s2;
	int i;

	/* initialize */
	lvlarena(0);
	nstaff = 0;
	staves_found = -1;
	memset(staff_tb, 0, sizeof staff_tb);
	memset(voice_tb, 0, sizeof voice_tb);
	for (i = 0; i < MAXVOICE; i++) {
		voice_tb[i].clef.line = 2;	/* treble clef on 2nd line */
		voice_tb[i].clef.stafflines = 5;
		voice_tb[i].clef.staffscale = 1;
		voice_tb[i].meter.nmeter = 1;
		voice_tb[i].meter.wmeasure = BASE_LEN;
		voice_tb[i].meter.meter[0].top[0] = '4';
		voice_tb[i].meter.meter[0].bot[0] = '4';
		voice_tb[i].wmeasure = BASE_LEN;
		voice_tb[i].scale = 1;
		voice_tb[i].clone = -1;
		voice_tb[i].over = -1;
		voice_tb[i].posit = cfmt.posit;
	}
	curvoice = first_voice = voice_tb;
	micro_tb = t->micro_tb;		/* microtone values */
	abc2win = 0;
	clip_start.bar = -1;
	clip_end.bar = (short unsigned) ~0 >> 1;

	parsys = NULL;
	system_new();			/* create the 1st staff system */
	parsys->top_voice = parsys->voice[0].range = 0;	/* implicit voice */

	if (!epsf) {
		if (cfmt.oneperpage) {
			use_buffer = 0;
			close_page();
		} else {
			use_buffer = !cfmt.splittune;

		}
	} else {
		use_buffer = 1;
		marg_init();
	}

	/* set the duration of all notes/rests
	 *	(this is needed for tuplets and the feathered beams)
	 * and get the voice IDs */
	for (as = t->first_sym; as; as = as->next) {
		switch (as->type) {
		case ABC_T_EOLN:
			if (as->u.eoln.type == 2)
				abc2win = 1;
			break;
		case ABC_T_NOTE:
		case ABC_T_REST:
			s = (struct SYMBOL *) as;
			s->dur = s->as.u.note.lens[0];
			break;
		case ABC_T_INFO:
			if (as->text[0] == 'V') {
				int v;

				v = as->u.voice.voice;
				if (voice_tb[v].id[0] == '\0')
					strcpy(voice_tb[v].id, as->u.voice.id);
			}
			break;
		}
	}

	if (voice_tb[0].id[0] == '\0') {	/* single voice */
		voice_tb[0].id[0] = '1';	/* implicit V:1 */
		voice_tb[0].id[1] = '\0';
	}

	/* scan the tune */
	for (as = t->first_sym; as; as = as->next) {
		s = (struct SYMBOL *) as;
		if (as->flags & ABC_F_LYRIC_START)
			curvoice->lyric_start = curvoice->last_sym;
		switch (as->type) {
		case ABC_T_INFO:
			as = get_info(as, t);
			break;
		case ABC_T_PSCOM:
			as = process_pscomment(as);
			break;
		case ABC_T_NOTE:
		case ABC_T_REST:
			if (curvoice->space) {
				curvoice->space = 0;
				s->as.flags |= ABC_F_SPACE;
			}
			get_note(s);
			break;
		case ABC_T_BAR:
			if (over_bar)
				get_over(s);
			get_bar(s);
			break;
		case ABC_T_CLEF:
			get_clef(s);
			break;
		case ABC_T_EOLN:
			if (cfmt.breakoneoln
			 || (as->flags & ABC_F_SPACE))
				curvoice->space = 1;
			if (cfmt.continueall || cfmt.barsperstaff
			 || as->u.eoln.type == 1)	/* if '\' */
				continue;
			if (as->u.eoln.type == 0	/* if normal eoln */
			 && abc2win
			 && t->abc_vers != (2 << 16))
				continue;
			if (parsys->voice[curvoice - voice_tb].range == 0
			 && curvoice->last_sym)
				curvoice->last_sym->sflags |= S_EOLN;
			if (!cfmt.alignbars)
				continue;
			while (as->next) {		/* treat the lyrics */
				if (as->next->type != ABC_T_INFO)
					break;
				switch (as->next->text[0]) {
				case 'w':
					as = get_info(as->next, t);
					s = (struct SYMBOL *) as;
					continue;
				case 'd':
				case 's':
					as = as->next;
					s = (struct SYMBOL *) as;
					continue;
				}
				break;
			}
			i = (curvoice - voice_tb) + 1;
			if (i < cfmt.alignbars) {
				curvoice = &voice_tb[i];
				continue;
			}
			generate();
			buffer_eob();
			curvoice = &voice_tb[0];
			continue;
		case ABC_T_MREST: {
			int dur;

			dur = curvoice->wmeasure * as->u.bar.len;
			if (curvoice->second) {
				curvoice->time += dur;
				break;
			}
			sym_link(s, MREST);
			s->dur = dur;
			curvoice->time += dur;
			if (s->as.text)
				gch_build(s);	/* build the guitar chords */
			if (s->as.u.bar.dc.n > 0)
				deco_cnv(&s->as.u.bar.dc, s, 0);
			break;
		    }
		case ABC_T_MREP: {
			int n;

			if (!as->next || as->next->type != ABC_T_BAR) {
				error(1, s,
				      "Measure repeat not followed by a bar");
				break;
			}
			if (curvoice->ignore)
				break;
			n = as->u.bar.len;
			if (curvoice->second) {
				curvoice->time += curvoice->wmeasure * n;
				break;
			}
			s2 = sym_add(curvoice, NOTEREST);
			s2->as.type = ABC_T_REST;
			s2->as.flags |= ABC_F_INVIS;
			s2->dur = curvoice->wmeasure;
			curvoice->time += s2->dur;
			if (n == 1) {
				as->next->u.bar.len = n; /* <n> in the next bar */
				break;
			}
			while (--n > 0) {
				s2 = sym_add(curvoice, BAR);
				s2->as.u.bar.type = B_SINGLE;
				if (n == as->u.bar.len - 1)
					s2->as.u.bar.len = as->u.bar.len;
				s2 = sym_add(curvoice, NOTEREST);
				s2->as.type = ABC_T_REST;
				s2->as.flags |= ABC_F_INVIS;
				s2->dur = curvoice->wmeasure;
				curvoice->time += s2->dur;
			}
			break;
		    }
		case ABC_T_V_OVER:
			get_over(s);
			continue;
		case ABC_T_TUPLET:
			set_tuplet(s);
			break;
		default:
			continue;
		}
		if (s->type == 0)
			continue;
		if (curvoice->second)
			s->sflags |= S_SECOND;
		if (curvoice->floating)
			s->sflags |= S_FLOATING;
	}

	gen_ly(0);
	put_history();
	buffer_eob();
	if (epsf)
		write_eps();
	else
		write_buffer();

	if (info['X' - 'A']) {
		memcpy(&cfmt, &dfmt, sizeof cfmt); /* restore global values */
		memcpy(&info, &info_glob, sizeof info);
		memcpy(deco, deco_glob, sizeof deco);
		info['X' - 'A'] = NULL;
	}

	/* free the parsing resources */
	{
		struct brk_s *brk, *brk2;

		brk = brks;
		while (brk) {
			brk2 = brk->next;
			free(brk);
			brk = brk2;
		}
		brks = brk;		/* (NULL) */
	}
//	clrarena(2);			/* clear generation */
}

/* check if a K: or M: may go to the tune key and time signatures */
static int is_tune_sig(void)
{
	struct SYMBOL *s;

	if (curvoice->time != 0)
		return 0;		/* not at start of tune */
	for (s = curvoice->sym; s; s = s->next) {
		switch (s->type) {
		case TEMPO:
		case PART:
		case FMTCHG:
			break;
		default:
			return 0;
		}
	}
	return 1;
}

/* -- get a clef definition (in K: or V:) -- */
static void get_clef(struct SYMBOL *s)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *s2;
	int stafflines, voice;
	float staffscale;

	p_voice = curvoice;
	if (s->as.prev->type == ABC_T_INFO) {
		switch (s->as.prev->text[0]) {
		case 'K':
			if (s->as.prev->state != ABC_S_HEAD)
				break;
			if (s->as.u.clef.type >= 0) {
				for (voice = 0; voice < MAXVOICE; voice++) {
					stafflines = parsys->voice[voice].clef.stafflines;
					staffscale = parsys->voice[voice].clef.staffscale;
					memcpy(&parsys->voice[voice].clef, &s->as.u.clef,
					       sizeof parsys->voice[voice].clef);
					parsys->voice[voice].clef.stafflines = stafflines;
					parsys->voice[voice].clef.staffscale = staffscale;
					voice_tb[voice].forced_clef = 1;
					if (s->as.u.clef.type == PERC)
						voice_tb[voice].perc = 1;
				}
			}
			if ((stafflines = s->as.u.clef.stafflines) >= 0) {
				for (voice = 0; voice < MAXVOICE; voice++)
					parsys->voice[voice].clef.stafflines = stafflines;
			}
			if ((staffscale = s->as.u.clef.staffscale) != 0) {
				for (voice = 0; voice < MAXVOICE; voice++)
					parsys->voice[voice].clef.staffscale = staffscale;
			}
			return;
		case 'V':	/* clef relative to a voice definition in the header */
			p_voice = &voice_tb[(int) s->as.prev->u.voice.voice];
			break;
		}
	}
	voice = p_voice - voice_tb;

	if (is_tune_sig()) {
		if ((stafflines = s->as.u.clef.stafflines) < 0)
			stafflines = parsys->voice[voice].clef.stafflines;
		if ((staffscale = s->as.u.clef.staffscale) == 0)
			staffscale = parsys->voice[voice].clef.staffscale;
		if (s->as.u.clef.type >= 0)
			memcpy(&parsys->voice[voice].clef,
				&s->as.u.clef,
				sizeof parsys->voice[voice].clef);
		parsys->voice[voice].clef.stafflines = stafflines;
		parsys->voice[voice].clef.staffscale = staffscale;
	} else {				/* clef change */
		if (s->as.u.clef.type < 0) {	/* if stafflines or staffscale only */
			sym_link(s, CLEF);	/* (will be changed to STAVES in staves_init) */
			return;
		}

		/* the clef must appear before a key signature or a bar */
		s2 = curvoice->last_sym;
		if (s2 && s2->prev
		 && (s2->type == KEYSIG || s2->type == BAR)) {
			struct SYMBOL *s3;

			for (s3 = s2; s3->prev; s3 = s3->prev) {
				switch (s3->prev->type) {
				case KEYSIG:
				case BAR:
					continue;
				}
				break;
			}
			curvoice->last_sym = s3->prev;
			sym_link(s, CLEF);
			s->next = s3;
			s3->prev = s;
			curvoice->last_sym = s2;
		} else {
			sym_link(s, CLEF);
		}
		s->u = 1;			/* small clef */

		/* if #lines or scale, add a clef which will be changed to STAVES
		 * in staves_init */
		if (s->as.u.clef.stafflines >= 0
		 || s->as.u.clef.staffscale != 0) {
			s2 = sym_add(curvoice, CLEF);
			s2->as.u.clef.type = -1;
			s2->as.u.clef.stafflines = s->as.u.clef.stafflines;
			s2->as.u.clef.staffscale = s->as.u.clef.staffscale;
		}
	}
	if (s->as.u.clef.type >= 0) {
		p_voice->forced_clef = 1;	/* don't change */
		p_voice->perc = s->as.u.clef.type == PERC;
	}
}

/* -- treat %%clef -- */
static void clef_def(struct SYMBOL *s)
{
	char *p;
	int clef, clef_line;
	char str[80];

	clef = -1;
	clef_line = 2;
	p = &s->as.text[2 + 5];		/* skip %%clef */
	while (isspace((unsigned char) *p))
		p++;

	/* clef name */
	switch (*p) {
	case '\"':			/* user clef name */
		p = get_str(str, p, sizeof str);
		s->as.u.clef.name = (char *) getarena(strlen(str) + 1);
		strcpy(s->as.u.clef.name, str);
		clef = TREBLE;
		break;
	case 'G':
		clef = TREBLE;
		p++;
		break;
	case 'F':
		clef = BASS;
		clef_line = 4;
		p++;
		break;
	case 'C':
		clef = ALTO;
		clef_line = 3;
		p++;
		break;
	case 'P':
		clef = PERC;
		p++;
		break;
	case 't':
		if (strncmp(p, "treble", 6) == 0) {
			clef = TREBLE;
			p += 6;
		}
		if (strncmp(p, "tenor", 5) == 0) {
			clef = ALTO;
			clef_line = 4;
			p += 5;
		}
		break;
	case 'a':
		if (strncmp(p, "alto", 4) == 0) {
			clef = ALTO;
			clef_line = 3;
			p += 4;
		}
		break;
	case 'b':
		if (strncmp(p, "bass", 4) == 0) {
			clef = BASS;
			clef_line = 4;
			p += 4;
		}
		break;
	case 'p':
		if (strncmp(p, "perc", 4) == 0) {
			clef = PERC;
			p += 4;
		}
		break;
	case 'n':
		if (strncmp(p, "none", 4) == 0) {
			clef = TREBLE;
			s->as.u.clef.invis = 1;
			s->as.flags |= ABC_F_INVIS;
			p += 4;
		}
		break;
	}
	if (clef < 0) {
		error(1, s, "Unknown clef '%s'", p);
		return;
	}

	/* clef line */
	switch (*p) {
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
		clef_line = *p++ - '0';
		break;
	}

	/* +/-/^/_8 */
	if (p[1] == '8') {
		switch (*p) {
		case '^':
			s->as.u.clef.transpose = -7;
		case '+':
			s->as.u.clef.octave = 1;
			break;
		case '_':
			s->as.u.clef.transpose = 7;
		case '-':
			s->as.u.clef.octave = -1;
			break;
		}
	}

	/* handle the clef */
	s->as.type = ABC_T_CLEF;
	s->as.u.clef.type = clef;
	s->as.u.clef.line = clef_line;
	s->as.u.clef.stafflines = -1;
	s->as.u.clef.staffscale = 0;
	get_clef(s);
}

/* transpose a key */
static void key_transpose(struct key_s *key)
{
	int t, sf;

	t = curvoice->transpose / 3;
	sf = (t & ~1) + (t & 1) * 7 + key->sf;
	switch ((curvoice->transpose + 210) % 3) {
	case 1:
		sf = (sf + 4 + 12 * 4) % 12 - 4;	/* more sharps */
		break;
	case 2:
		sf = (sf + 7 + 12 * 4) % 12 - 7;	/* more flats */
		break;
	default:
		sf = (sf + 5 + 12 * 4) % 12 - 5;	/* Db, F# or B */
		break;
	}
	key->sf = sf;
}

/* -- set the accidentals when K: with modified accidentals -- */
static void set_acc(struct SYMBOL *s)
{
	int i, j, nacc;
	char accs[8], pits[8];
	static char sharp_tb[8] = {26, 23, 27, 24, 21, 25, 22};
	static char flat_tb[8] = {22, 25, 21, 24, 20, 23, 26};

	if (s->as.u.key.sf > 0) {
		for (nacc = 0; nacc < s->as.u.key.sf; nacc++) {
			accs[nacc] = A_SH;
			pits[nacc] = sharp_tb[nacc];
		}
	} else {
		for (nacc = 0; nacc < -s->as.u.key.sf; nacc++) {
			accs[nacc] = A_FT;
			pits[nacc] = flat_tb[nacc];
		}
	}
	for (i = 0; i < s->as.u.key.nacc; i++) {
		for (j = 0; j < nacc; j++) {
			if ((pits[j] - s->as.u.key.pits[i]) % 7 == 0) {
				accs[j] = s->as.u.key.accs[i];
				break;
			}
		}
		if (j == nacc) {
			accs[j] = s->as.u.key.accs[i];
			pits[j] = s->as.u.key.pits[i];
			nacc++;		/* cannot overflow */
		}
	}
	for (i = 0; i < nacc; i++) {
		s->as.u.key.accs[i] = accs[i];
		s->as.u.key.pits[i] = pits[i];
	}
	s->as.u.key.nacc = nacc;
}

/* -- get a key signature definition (K:) -- */
static void get_key(struct SYMBOL *s)
{
	struct VOICE_S *p_voice;
	struct SYMBOL *s2;
	struct key_s okey;			/* original key */
	int i;

	if (s->as.u.key.octave != NO_OCTAVE)
		curvoice->octave = s->as.u.key.octave;
	if (s->as.u.key.empty == 1)		/* clef only */
		return;

	if (s->as.u.key.sf != 0
	 && !s->as.u.key.exp
	 && s->as.u.key.nacc != 0)
		set_acc(s);

	memcpy(&okey, &s->as.u.key, sizeof okey);
	if (s->as.state == ABC_S_HEAD)		/* if first K: (start of tune) */
		curvoice->transpose = cfmt.transpose;
	if (curvoice->transpose != 0) {
		key_transpose(&s->as.u.key);

#if 0
		/* transpose explicit accidentals */
//fixme: not correct - transpose adds or removes accidentals...
		if (s->as.u.key.nacc > 0) {
			struct VOICE_S voice, *voice_sav;
			struct SYMBOL note;

			memset(&voice, 0, sizeof voice);
			voice.transpose = curvoice->transpose;
			memcpy(&voice.ckey, &s->as.u.key, sizeof voice.ckey);
			voice.ckey.empty = 2;
			voice.ckey.nacc = 0;
			memset(&note, 0, sizeof note);
			memcpy(note.as.u.note.pits, voice.ckey.pits,
					sizeof note.as.u.note.pits);
			memcpy(note.as.u.note.accs, voice.ckey.accs,
					sizeof note.as.u.note.accs);
			note.as.u.note.nhd = s->as.u.key.nacc;
			voice_sav = curvoice;
			curvoice = &voice;
			note_transpose(&note);
			memcpy(s->as.u.key.pits, note.as.u.note.pits,
					sizeof s->as.u.key.pits);
			memcpy(s->as.u.key.accs, note.as.u.note.accs,
					sizeof s->as.u.key.accs);
			curvoice = voice_sav;
		}
#endif
	}

	if (s->as.state == ABC_S_HEAD) {	/* start of tune */
		for (i = MAXVOICE, p_voice = voice_tb;
		     --i >= 0;
		     p_voice++) {
			memcpy(&p_voice->key, &s->as.u.key,
						sizeof p_voice->key);
			memcpy(&p_voice->ckey, &s->as.u.key,
						sizeof p_voice->ckey);
			memcpy(&p_voice->okey, &okey,
						sizeof p_voice->okey);
			if (s->as.u.key.octave != NO_OCTAVE)
				p_voice->octave = s->as.u.key.octave;
		}
		return;
	}

	/* ABC_S_TUNE (K: cannot be ABC_S_GLOBAL) */
	if (is_tune_sig()) {

		/* define the starting key signature */
		memcpy(&curvoice->key, &s->as.u.key,
					sizeof curvoice->key);
		memcpy(&curvoice->ckey, &s->as.u.key,
					sizeof curvoice->ckey);
		memcpy(&curvoice->okey, &okey,
					sizeof curvoice->okey);
		if (curvoice->key.mode >= BAGPIPE
		 && curvoice->posit.std == 0)
			curvoice->posit.std = SL_BELOW;
		curvoice->transpose = cfmt.transpose;
		if (curvoice->key.empty)
			curvoice->key.sf = 0;
		return;
	}

	/* key signature change */
	if ((!s->as.next
	  || s->as.next->type != ABC_T_CLEF)	/* if not explicit clef */
	 && curvoice->ckey.sf == s->as.u.key.sf	/* and same key */
	 && curvoice->ckey.nacc == 0
	 && s->as.u.key.nacc == 0
	 && curvoice->ckey.empty == s->as.u.key.empty
	 && cfmt.keywarn)			/* (if not key warning,
						 *  keep all key signatures) */
		return;				/* ignore */

	if (!curvoice->ckey.empty)
		s->u = curvoice->ckey.sf;	/* previous key signature */
	memcpy(&curvoice->ckey, &s->as.u.key,
				sizeof curvoice->ckey);
	memcpy(&curvoice->okey, &okey,
				sizeof curvoice->okey);
	if (s->as.u.key.empty)
		s->as.u.key.sf = 0;

	/* the key signature must appear before a time signature */
	s2 = curvoice->last_sym;
	if (s2 && s2->type == TIMESIG) {
		curvoice->last_sym = s2->prev;
		if (!curvoice->last_sym)
			curvoice->sym = NULL;
		sym_link(s, KEYSIG);
		s->next = s2;
		s2->prev = s;
		curvoice->last_sym = s2;
	} else {
		sym_link(s, KEYSIG);
	}
}

/* -- set meter from M: -- */
static void get_meter(struct SYMBOL *s)
{
	struct VOICE_S *p_voice;
	int i;

	switch (s->as.state) {
	case ABC_S_GLOBAL:
		/*fixme: keep the values and apply to all tunes?? */
		break;
	case ABC_S_HEAD:
		for (i = MAXVOICE, p_voice = voice_tb;
		     --i >= 0;
		     p_voice++) {
			memcpy(&p_voice->meter, &s->as.u.meter,
			       sizeof p_voice->meter);
			p_voice->wmeasure = s->as.u.meter.wmeasure;
		}
		break;
	case ABC_S_TUNE:
		curvoice->wmeasure = s->as.u.meter.wmeasure;
		if (is_tune_sig()) {
			memcpy(&curvoice->meter, &s->as.u.meter,
				       sizeof curvoice->meter);
			reset_gen();	/* (display the time signature) */
			break;
		}
		if (s->as.u.meter.nmeter == 0)
			break;		/* M:none */
		sym_link(s, TIMESIG);
		break;
	}
}

/* -- treat a 'V:' -- */
static void get_voice(struct SYMBOL *s)
{
	struct VOICE_S *p_voice;
	int voice;

	voice = s->as.u.voice.voice;
	p_voice = &voice_tb[voice];
	if (parsys->voice[voice].range < 0) {
		if (cfmt.alignbars) {
			error(1, s, "V: does not work with %%%%alignbars");
		}
		if (staves_found < 0) {
			if (!s->as.u.voice.merge) {
#if MAXSTAFF < MAXVOICE
				if (nstaff >= MAXSTAFF - 1) {
					error(1, s, "Too many staves");
					return;
				}
#endif
				nstaff++;
			} else {
				p_voice->second = 1;
				parsys->voice[voice].second = 1;
			}
			p_voice->staff = p_voice->cstaff = nstaff;
			parsys->voice[voice].staff = nstaff;
			{
				int range, i;

				range = 0;
				for (i = 0; i < MAXVOICE; i++) {
					if (parsys->voice[i].range > range)
						range = parsys->voice[i].range;
				}
				parsys->voice[voice].range = range + 1;
				voice_link(p_voice);
			}
		} else {
			p_voice->ignore = 1;
			p_voice->staff = p_voice->cstaff = nstaff + 1;
		}
	}

	/* if something has changed, update */
	if (s->as.u.voice.octave != NO_OCTAVE)
		p_voice->octave = s->as.u.voice.octave;
	if (s->as.u.voice.fname != 0) {
		p_voice->nm = s->as.u.voice.fname;
		p_voice->new_name = 1;
	}
	if (s->as.u.voice.nname != 0)
		p_voice->snm = s->as.u.voice.nname;
	switch (s->as.u.voice.dyn) {
	case 1:
		p_voice->posit.dyn = SL_ABOVE;
		p_voice->posit.vol = SL_ABOVE;
		break;
	case -1:
		p_voice->posit.dyn = SL_BELOW;
		p_voice->posit.vol = SL_BELOW;
		break;
	}
	switch (s->as.u.voice.lyrics) {
	case 1:
		p_voice->posit.voc = SL_ABOVE;
		break;
	case -1:
		p_voice->posit.voc = SL_BELOW;
		break;
	}
	switch (s->as.u.voice.gchord) {
	case 1:
		p_voice->posit.gch = SL_ABOVE;
		break;
	case -1:
		p_voice->posit.gch = SL_BELOW;
		break;
	}
	switch (s->as.u.voice.stem) {
	case 1:
		p_voice->posit.std = SL_ABOVE;
		break;
	case -1:
		p_voice->posit.std = SL_BELOW;
		break;
	case 2:
		p_voice->posit.std = 0;		/* auto */
		break;
	}
	switch (s->as.u.voice.gstem) {
	case 1:
		p_voice->posit.gsd = SL_ABOVE;
		break;
	case -1:
		p_voice->posit.gsd = SL_BELOW;
		break;
	case 2:
		p_voice->posit.gsd = 0;		/* auto */
		break;
	}
	if (s->as.u.voice.scale != 0)
		p_voice->scale = s->as.u.voice.scale;

	set_tblt(p_voice);

	/* if in tune, switch to this voice */
	if (s->as.state == ABC_S_TUNE)
		curvoice = p_voice;
}

/* sort the notes of the chord by pitch (lowest first) */
void sort_pitch(struct SYMBOL *s, int combine)
{
	int i, nx, k;
	for (;;) {
		nx = 0;
		for (i = 1; i <= s->nhd; i++) {
			if (s->as.u.note.pits[i] >= s->as.u.note.pits[i-1])
				continue;
#define xch(f) \
	k = s->as.u.note.f[i]; \
	s->as.u.note.f[i] = s->as.u.note.f[i-1]; \
	s->as.u.note.f[i-1] = k
			xch(pits);
			xch(lens);
			xch(accs);
			xch(sl1);
			xch(sl2);
			xch(ti1);
			xch(decs);
#undef xch
			if (combine) {
				k = s->pits[i];
				s->pits[i] = s->pits[i-1];
				s->pits[i-1] = k;
			}
			nx++;
		}
		if (nx == 0)
			break;
	}
}

/* -- note or rest -- */
static void get_note(struct SYMBOL *s)
{
	struct SYMBOL *prev;
	int i, m;

	prev = curvoice->last_sym;
	s->nhd = m = s->as.u.note.nhd;

	if (curvoice->octave != 0) {
		for (i = 0; i <= m; i++)
			s->as.u.note.pits[i] += curvoice->octave * 7;
	}

	if (curvoice->perc)
		s->sflags |= S_PERC;
	else if (s->as.type == ABC_T_NOTE
	      && curvoice->transpose != 0)
		note_transpose(s);

	if (!(s->as.flags & ABC_F_GRACE)) {
		switch (curvoice->posit.std) {
		case SL_ABOVE: s->stem = 1; break;
		case SL_BELOW: s->stem = -1; break;
		}
	} else {			/* grace note - adjust its duration */
		int div;

		if (curvoice->key.mode < BAGPIPE) {
			div = 2;
			if (!prev
			 || !(prev->as.flags & ABC_F_GRACE)) {
				if (s->as.flags & ABC_F_GR_END)
					div = 1;	/* one grace note */
			}
		} else {
			div = 4;
		}
		for (i = 0; i <= m; i++)
			s->as.u.note.lens[i] /= div;
		s->dur /= div;
		switch (curvoice->posit.gsd) {
		case SL_ABOVE: s->stem = 1; break;
		case SL_BELOW: s->stem = -1; break;
		case SL_HIDDEN:	s->stem = 2; break;	/* opposite */
		}
	}

	/* convert the decorations
	 * (!beam-accel! and !beam-rall! may change the note duration) */
	if (s->as.u.note.dc.n > 0)
		deco_cnv(&s->as.u.note.dc, s, prev);

	/* insert the note/rest in the voice */
	sym_link(s,  s->as.u.note.lens[0] != 0 ? NOTEREST : SPACE);
	if (!(s->as.flags & ABC_F_GRACE))
		curvoice->time += s->dur;
	s->nohdix = -1;

	/* change the figure of whole measure rests */
	if (s->as.type == ABC_T_REST) {
		if (s->dur == curvoice->wmeasure) {
			if (s->dur < BASE_LEN * 2)
				s->as.u.note.lens[0] = BASE_LEN;
			else if (s->dur < BASE_LEN * 4)
				s->as.u.note.lens[0] = BASE_LEN * 2;
			else
				s->as.u.note.lens[0] = BASE_LEN * 4;
		}
	} else {

		/* sort the notes of the chord by pitch (lowest first) */
		sort_pitch(s, 0);
	}

	memcpy(s->pits, s->as.u.note.pits, sizeof s->pits);

	/* get the max head type, number of dots and number of flags */
	{
		int head, dots, nflags, l;

		if ((l = s->as.u.note.lens[0]) != 0) {
			identify_note(s, l, &head, &dots, &nflags);
			s->head = head;
			s->dots = dots;
			s->nflags = nflags;
			for (i = 1; i <= m; i++) {
				if (s->as.u.note.lens[i] == l)
					continue;
				identify_note(s, s->as.u.note.lens[i],
						&head, &dots, &nflags);
				if (head > s->head)
					s->head = head;
				if (dots > s->dots)
					s->dots = dots;
				if (nflags > s->nflags)
					s->nflags = nflags;
			}
			if (s->sflags & S_XSTEM)
				s->nflags = 0;		/* word start+end */
		}
	}
	if (s->nflags <= -2)
		s->as.flags |= ABC_F_STEMLESS;

	if (s->sflags & (S_TREM1 | S_TREM2)) {
		if (s->nflags > 0)
			s->nflags += s->u;
		else
			s->nflags = s->u;
		if ((s->sflags & S_TREM2)
		 && (s->sflags & S_BEAM_END)) {		/* if 2nd note - see deco.c */
			prev->head = s->head;
			prev->u = s->u;
			prev->nflags = s->nflags;
			prev->as.flags |= (s->as.flags & ABC_F_STEMLESS);
		}
	}

	for (i = 0; i <= m; i++) {
		if (s->as.u.note.sl1[i] != 0)
			s->sflags |= S_SL1;
		if (s->as.u.note.sl2[i] != 0)
			s->sflags |= S_SL2;
		if (s->as.u.note.ti1[i] != 0)
			s->sflags |= S_TI1;
	}

	switch (cfmt.shiftunison) {
	case 0:
		break;
	case 1:
		s->sflags |= S_SHIFTUNISON_1;
		break;
	case 2:
		s->sflags |= S_SHIFTUNISON_2;
		break;
	default:
		s->sflags |= S_SHIFTUNISON_1 | S_SHIFTUNISON_2;
		break;
	}

	/* build the guitar chords */
	if (s->as.text)
		gch_build(s);
}

/* -- treat a postscript definition -- */
static void ps_def(struct SYMBOL *s,
			char *p,
			char use)	/* cf user_ps_add() */
{
	if (!svg && epsf != 2) {	/* if PS output */
		if (secure
		 || use == 'g'
		 || use == 's')
			return;
	} else {			/* if SVG output */
		if (use == 'p'
		 || (use == 'g' && file_initialized))
			return;
	}
	if (s->as.prev)
		s->as.state = s->as.prev->state;
	if (s->as.state == ABC_S_TUNE) {
		if (use == 'g')
			return;
		sym_link(s, FMTCHG);
		s->u = PSSEQ;
		s->as.text = p;
		s->as.flags |= ABC_F_INVIS;
		return;
	}
	if (file_initialized || mbf != outbuf)
		a2b("%s\n", p);
	else
		user_ps_add(p, use);
}

/* get a symbol selection */
/* measure_number [ ":" time_numerator "/" time_denominator ] */
static char *get_symsel(struct symsel_s *symsel, char *p)
{
	char *q;
	int tn, td, n;

	symsel->bar = strtod(p, &q);
	if (*q >= 'a' && *q <= 'z')
		symsel->seq = *q++ - 'a';
	else
		symsel->seq = 0;
	if (*q == ':') {
		if (sscanf(q + 1, "%d/%d%n", &tn, &td, &n) != 2
		 || td <= 0)
			return 0;
		symsel->time = BASE_LEN * tn / td;
		q += 1 + n;
	} else {
		symsel->time = 0;
	}
	return q;
}

/* free the voice options */
static void free_voice_opt(struct voice_opt_s *opt)
{
	struct voice_opt_s *opt2;

	while (opt) {
		opt2 = opt->next;
		free(opt);
		opt = opt2;
	}
}

/* -- process a pseudo-comment (%% or I:) -- */
static struct abcsym *process_pscomment(struct abcsym *as)
{
	char w[32], *p, *q;
	int lock;
	float h1;
	struct SYMBOL *s = (struct SYMBOL *) as;

	p = as->text + 2;		/* skip '%%' */
	q = p + strlen(p) - 5;
	lock = strncmp(q, " lock", 5) == 0;
	if (lock)
		*q = '\0'; 
	p = get_str(w, p, sizeof w);
	if (as->state == ABC_S_HEAD
	 && !check_header(as)) {
		error(1, s, "Cannot have %%%%%s in tune header", w);
		return as;
	}
	switch (w[0]) {
	case 'b':
		if (strcmp(w, "beginps") == 0
		 || strcmp(w, "beginsvg") == 0) {
			char use;

			if (w[5] == 'p') {
				if (strncmp(p, "svg", 3) == 0)
					use = 's';
				else if (strncmp(p, "nosvg", 5) == 0)
					use = 'p';
				else
					use = 'b';
			} else {
				use = 'g';
			}
			p = as->text + 2 + 7;
			while (*p != '\0' && *p != '\n')
				p++;
			if (*p == '\0')
				return as;		/* empty */
			ps_def(s, p + 1, use);
			return as;
		}
		if (strcmp(w, "begintext") == 0) {
			int job;

			if (as->state == ABC_S_TUNE) {
				gen_ly(1);
			} else if (as->state == ABC_S_GLOBAL) {
				if (epsf || in_fname == 0)
					return as;
			}
			p = as->text + 2 + 9;
			while (*p == ' ' || *p == '\t')
				p++;
			if (*p != '\n') {
				job = get_textopt(p);
				if (job < 0) {
					error(1, s,
						"Bad argument for begintext: %s", p);
					job = T_LEFT;
				}
				while (*p != '\0' && *p != '\n')
					p++;
				if (*p == '\0')
					return as;	/* empty */
			} else {
				job = cfmt.textoption;
			}
			if (job != T_SKIP) {
				p++;
				write_text(w, p, job);
			}
			return as;
		}
		if (strcmp(w, "break") == 0) {
			struct brk_s *brk;

			if (as->state != ABC_S_HEAD) {
				error(1, s, "%%%%%s ignored", w);
				return as;
			}
			if (*p == '\0')
				return as;
			for (;;) {
				brk = malloc(sizeof *brk);
				p = get_symsel(&brk->symsel, p);
				if (!p) {
					error(1, s, "Bad selection in %%%%%s", w);
					return as;
				}
				brk->next = brks;
				brks = brk;
				if (*p != ',' && *p != ' ')
					break;
				p++;
			}
			return as;
		}
		break;
	case 'c':
		if (strcmp(w, "center") == 0)
			goto center;
		if (strcmp(w, "clef") == 0) {
			if (as->state != ABC_S_GLOBAL)
				clef_def(s);
			return as;
		}
		if (strcmp(w, "clip") == 0) {
			if (!cur_tune_opts) {
				error(1, s, "%%%%%s not in %%%%tune sequence", w);
				return as;
			}

			/* %%clip <symbol selection> "-" <symbol selection> */
			if (*p != '-') {
				p = get_symsel(&clip_start, p);
				if (!p) {
					error(1, s, "Bad start in %%%%%s", w);
					return as;
				}
				if (*p != '-') {
					error(1, s, "Lack of '-' in %%%%%s", w);
					return as;
				}
			}
			p++;
			p = get_symsel(&clip_end, p);
			if (!p) {
				error(1, s, "Bad end in %%%%%s", w);
				return as;
			}
			if (clip_start.bar < 0)
				clip_start.bar = 0;
			if (clip_end.bar < clip_start.bar
			 || (clip_end.bar == clip_start.bar
			  && clip_end.time <= clip_start.time)) {
				clip_end.bar = (short unsigned) ~0 >> 1;
			}
			return as;
		}
		break;
	case 'd':
		if (strcmp(w, "deco") == 0) {
			deco_add(p);
			return as;
		}
		if (strcmp(w, "dynamic") == 0) {
			set_voice_param(curvoice, as->state, w, p);
			return as;
		}
		break;
	case 'E':
		if (strcmp(w, "EPS") == 0) {
			float x1, y1, x2, y2;
			FILE *fp;
			char fn[STRL1], line[STRL1];

			gen_ly(1);
			if (secure
			 || cfmt.textoption == T_SKIP)
				return as;
			get_str(line, p, sizeof line);
			if ((fp = open_file(line, "eps", fn)) == NULL) {
				error(1, s, "No such file: %s", line);
				return as;
			}

			/* get the bounding box */
			x1 = x2 = 0;
			while (fgets(line, sizeof line, fp)) {
				if (strncmp(line, "%%BoundingBox:", 14) == 0) {
					if (sscanf(&line[14], "%f %f %f %f",
						   &x1, &y1, &x2, &y2) == 4)
						break;
				}
			}
			fclose(fp);
			if (x1 == x2) {
				error(1, s,
				      "No bounding box in '%s'", fn);
				return as;
			}
			if (cfmt.textoption == T_CENTER
			 || cfmt.textoption == T_RIGHT) {
				float lw;

				lw = ((cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth)
					- cfmt.leftmargin - cfmt.rightmargin) / cfmt.scale;
				if (cfmt.textoption == T_CENTER)
					x1 += (lw - (x2 - x1)) * 0.5;
				else
					x1 += lw - (x2 - x1);
			}
			a2b("\001");	/* include file (must be the first after eob) */
			bskip(y2 - y1);
			a2b("%.2f %.2f%%%s\n", x1, -y1, fn);
			buffer_eob();
			return as;
		}
		break;
	case 'g':
		if (strcmp(w, "gchord") == 0
		 || strcmp(w, "gstemdir") == 0) {
			set_voice_param(curvoice, as->state, w, p);
			return as;
		}
		if (strcmp(w, "glyph") == 0) {
			glyph_add(p);
			return as;
		}
		break;
	case 'm':
		if (strcmp(w, "maxsysstaffsep") == 0) {
			if (as->state != ABC_S_TUNE)
				break;
			parsys->voice[curvoice - voice_tb].maxsep = scan_u(p);
			return as;
		}
		if (strcmp(w, "measrep") == 0)
			goto irepeat;
		if (strcmp(w, "multicol") == 0) {
			float bposy;

			generate();
			if (strncmp(p, "start", 5) == 0) {
				if (!in_page)
					a2b("%%\n");	/* initialize the output */
				buffer_eob();
				bposy = get_bposy();
				multicol_max = multicol_start = bposy;
				lmarg = cfmt.leftmargin;
				rmarg = cfmt.rightmargin;
				mc_in_tune = info['X' - 'A'] != 0;
			} else if (strncmp(p, "new", 3) == 0) {
				if (multicol_start == 0) {
					error(1, s,
					      "%%%s new without start", w);
				} else {
					buffer_eob();
					bposy = get_bposy();
					if (bposy < multicol_start)
						bskip((bposy - multicol_start)
								/ cfmt.scale);
					if (bposy < multicol_max)
						multicol_max = bposy;
					cfmt.leftmargin = lmarg;
					cfmt.rightmargin = rmarg;
				}
			} else if (strncmp(p, "end", 3) == 0) {
				if (multicol_start == 0) {
					error(1, s,
					      "%%%s end without start", w);
				} else {
					buffer_eob();
					bposy = get_bposy();
					if (bposy > multicol_max)
						bskip((bposy - multicol_max)
								/ cfmt.scale);
					else
						a2b("%%\n");	/* force write_buffer */
					cfmt.leftmargin = lmarg;
					cfmt.rightmargin = rmarg;
					multicol_start = 0;
					buffer_eob();
					if (!info['X' - 'A']
					 && !epsf)
						write_buffer();
				}
			} else {
				error(1, s,
				      "Unknown keyword '%s' in %%%s", p, w);
			}
			return as;
		}
		break;
	case 'n':
		if (strcmp(w, "newpage") == 0) {
			if (epsf || in_fname == 0)
				return as;
			if (as->state == ABC_S_TUNE)
				generate();
			buffer_eob();
			write_buffer();
			use_buffer = 0;
			if (isdigit((unsigned char) *p))
				pagenum = atoi(p);
			close_page();
			return as;
		}
		break;
	case 'p':
		if (strcmp(w, "ps") == 0
		 || strcmp(w, "postscript") == 0) {
			ps_def(s, p, 'b');
			return as;
		}
		break;
	case 'o':
		if (strcmp(w, "ornament") == 0) {
			set_voice_param(curvoice, as->state, w, p);
			return as;
		}
		break;
	case 'r':
		if (strcmp(w, "repbra") == 0) {
			if (as->state != ABC_S_TUNE)
				return as;
			curvoice->norepbra = strchr("0FfNn", *p)
						|| *p == '\0';
			return as;
		}
		if (strcmp(w, "repeat") == 0) {
			int n, k;

irepeat:
			if (as->state != ABC_S_TUNE)
				return as;
			if (!curvoice->last_sym) {
				error(1, s,
				      "%%%s cannot start a tune", w);
				return as;
			}
			if (*p == '\0') {
				n = 1;
				k = 1;
			} else {
				n = atoi(p);
				if (n < 1
				 || (curvoice->last_sym->type == BAR
					&& n > 2)) {
					error(1, s,
					      "Incorrect 1st value in %%%s", w);
					return as;
				}
				while (*p != '\0' && !isspace((unsigned char) *p))
					p++;
				while (isspace((unsigned char) *p))
					p++;
				if (*p == '\0') {
					k = 1;
				} else {
					k = atoi(p);
					if (k < 1) {
//					 || (curvoice->last_sym->type == BAR
//					  && n == 2
//					  && k > 1)) {
						error(1, s,
						      "Incorrect 2nd value in %%%s", w);
						return as;
					}
				}
			}
			s->u = REPEAT;
			if (curvoice->last_sym->type == BAR)
				s->doty = n;
			else
				s->doty = -n;
			sym_link(s, FMTCHG);
			s->nohdix = k;
			as->text = NULL;
			return as;
		}
		break;
	case 's':
		if (strcmp(w, "setbarnb") == 0) {
			if (as->state == ABC_S_TUNE) {
				struct abcsym *as2;
				int n;

				n = atoi(p);
				for (as2 = as->next; as2; as2 = as2->next) {
					if (as2->type == ABC_T_BAR) {
						s = (struct SYMBOL *) as2;
						s->u = n;
						break;
					}
				}
				return as;
			}
			strcpy(w, "measurefirst");
			break;
		}
		if (strcmp(w, "sep") == 0) {
			float h2, len, lwidth;

			if (as->state == ABC_S_TUNE) {
				gen_ly(0);
			} else if (as->state == ABC_S_GLOBAL) {
				if (epsf || in_fname == 0)
					return as;
			}
			lwidth = (cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth)
				- cfmt.leftmargin - cfmt.rightmargin;
			h1 = h2 = len = 0;
			if (*p != '\0') {
				h1 = scan_u(p);
				while (*p != '\0' && !isspace((unsigned char) *p))
					p++;
				while (isspace((unsigned char) *p))
					p++;
			}
			if (*p != '\0') {
				h2 = scan_u(p);
				while (*p != '\0' && !isspace((unsigned char) *p))
					p++;
				while (isspace((unsigned char) *p))
					p++;
			}
			if (*p != '\0')
				len = scan_u(p);
			if (h1 < 1)
				h1 = 0.5 CM;
			if (h2 < 1)
				h2 = h1;
			if (len < 1)
				len = 3.0 CM;
			bskip(h1);
			a2b("%.1f %.1f sep0\n",
			     len / cfmt.scale,
			     (lwidth - len) * 0.5 / cfmt.scale);
			bskip(h2);
			buffer_eob();
			return as;
		}
		if (strcmp(w, "staff") == 0) {
			int staff;

			if (as->state != ABC_S_TUNE)
				return as;
			if (*p == '+')
				staff = curvoice->cstaff + atoi(p + 1);
			else if (*p == '-')
				staff = curvoice->cstaff - atoi(p + 1);
			else
				staff = atoi(p) - 1;
			if ((unsigned) staff > (unsigned) nstaff) {
				error(1, s, "Bad staff in %%%s", w);
				return as;
			}
			curvoice->floating = 0;
			curvoice->cstaff = staff;
			return as;
		}
		if (strcmp(w, "staffbreak") == 0) {
			if (as->state != ABC_S_TUNE)
				return as;
			if (isdigit(*p)) {
				s->xmx = scan_u(p);
				if (s->xmx < 0) {
					error(1, s, "Bad value in %%%s", w);
					return as;
				}
				if (p[strlen(p) - 1] == 'f')
					s->doty = 1;
			} else {
				s->xmx = 0.5 CM;
				if (*p == 'f')
					s->doty = 1;
			}
			sym_link(s, STBRK);
			return as;
		}
		if (strcmp(w, "stafflines") == 0) {
			int voice, lines;

			lines = atoi(p);
			if ((unsigned) lines >= 10) {
				error(1, s, "Bad value in %%%s", w);
				return as;
			}
			if (as->state != ABC_S_TUNE) {
				for (voice = 0; voice < MAXVOICE; voice++)
					parsys->voice[voice].clef.stafflines = lines;
			} else {
				voice = curvoice - voice_tb;
				parsys->voice[voice].clef.stafflines = lines;
			}
			return as;
		}
		if (strcmp(w, "staffscale") == 0) {
			int voice;
			char *q;
			float scale;

			scale = strtod(p, &q);
			if (scale <= 0.5 || scale > 2
			 || (*q != '\0' && *q != ' ')) {
				error(1, s, "Bad value in %%%s", w);
				return as;
			}
			if (as->state != ABC_S_TUNE) {
				for (voice = 0; voice < MAXVOICE; voice++)
					parsys->voice[voice].clef.staffscale = scale;
			} else {
				voice = curvoice - voice_tb;
				parsys->voice[voice].clef.staffscale = scale;
			}
			return as;
		}
		if (strcmp(w, "staves") == 0
		 || strcmp(w, "score") == 0) {
			if (as->state == ABC_S_GLOBAL)
				return as;
			get_staves(s);
			return as;
		}
		if (strcmp(w, "stemdir") == 0) {
			set_voice_param(curvoice, as->state, w, p);
			return as;
		}
		if (strcmp(w, "sysstaffsep") == 0) {
			if (as->state != ABC_S_TUNE)
				break;
			parsys->voice[curvoice - voice_tb].sep = scan_u(p);
			return as;
		}
		break;
	case 't':
		if (strcmp(w, "text") == 0) {
			int job;

center:
			if (as->state == ABC_S_TUNE) {
				gen_ly(1);
			} else if (as->state == ABC_S_GLOBAL) {
				if (epsf || in_fname == 0)
					return as;
			}
			if (w[0] == 'c') {
				job = T_CENTER;
			} else {
				job = cfmt.textoption;
				switch(job) {
				case T_SKIP:
					return as;
				case T_LEFT:
				case T_RIGHT:
				case T_CENTER:
					break;
				default:
					job = T_LEFT;
					break;
				}
			}
			write_text(w, p, job);
			return as;
		}
		if (strcmp(w, "tablature") == 0) {
			struct tblt_s *tblt;
			int i, j;

			tblt = tblt_parse(p);
			if (tblt == 0)
				return as;

			switch (as->state) {
			case ABC_S_TUNE:
			case ABC_S_HEAD:
				for (i = 0; i < ncmdtblt; i++) {
					if (cmdtblts[i].active)
						continue;
					j = cmdtblts[i].index;
					if (j < 0 || tblts[j] == tblt)
						return as;
				}
				/* !! 2 tblts per voice !! */
				if (curvoice->tblts[0] == tblt
				 || curvoice->tblts[1] == tblt)
					break;
				if (curvoice->tblts[1]) {
					error(1, s,
						"Too many tablatures for voice %s",
						curvoice->id);
					break;
				}
				if (!curvoice->tblts[0])
					curvoice->tblts[0] = tblt;
				else
					curvoice->tblts[1] = tblt;
				break;
			}
			return as;
		}
		if (strcmp(w, "transpose") == 0) {
			struct SYMBOL *s2;

			interpret_fmt_line(w, p, 0);
			switch (as->state) {
			case ABC_S_GLOBAL:
				return as;
			case ABC_S_HEAD: {
				struct VOICE_S *p_voice;
				int i;

				for (i = MAXVOICE, p_voice = voice_tb;
				     --i >= 0;
				     p_voice++) {
					p_voice->transpose = cfmt.transpose;
					memcpy(&p_voice->key, &p_voice->okey,
						sizeof p_voice->key);
					key_transpose(&p_voice->key);
					memcpy(&p_voice->ckey, &p_voice->key,
						sizeof p_voice->ckey);
					if (p_voice->key.empty)
						p_voice->key.sf = 0;
				}
				return as;
			    }
			}
			curvoice->transpose = cfmt.transpose;
			s2 = curvoice->sym;
			if (!s2) {
				memcpy(&curvoice->key, &curvoice->okey,
					sizeof curvoice->key);
				key_transpose(&curvoice->key);
				memcpy(&curvoice->ckey, &curvoice->key,
					sizeof curvoice->ckey);
				if (curvoice->key.empty)
					curvoice->key.sf = 0;
				return as;
			}
			for ( ; s2; s2 = s2->prev)
				if (s2->type == KEYSIG)
					break;
			if (!s2 || s2->time != curvoice->time) {
				s = sym_add(curvoice, KEYSIG);
				s->as.type = ABC_T_INFO;
				s->as.text = (char *) getarena(2);
				s->as.text[0] = 'K';
				s->as.text[1] = '\0';
				s->u = curvoice->ckey.sf;
				s2 = s;
			}
			memcpy(&s2->as.u.key, &curvoice->okey,
						sizeof s2->as.u.key);
			key_transpose(&s2->as.u.key);
			memcpy(&curvoice->ckey, &s2->as.u.key,
						sizeof curvoice->ckey);
			if (curvoice->key.empty)
				curvoice->key.sf = 0;
			return as;
		}
		if (strcmp(w, "tune") == 0) {
			struct abcsym *as2, *as3;
			struct tune_opt_s *opt, *opt2;

			if (as->state != ABC_S_GLOBAL) {
				error(1, s, "%%%%%s ignored", w);
				return as;
			}

			/* if void %%tune, remove all tune options */
			if (*p == '\0') {
				opt = tune_opts;
				while (opt) {
					free_voice_opt(opt->voice_opts);
					opt2 = opt->next;
					free(opt);
					opt = opt2;
				}
				tune_opts = NULL;
				return as;
			}

			if (strcmp(p, "end") == 0)
				return as;	/* end of previous %%tune */

			/* search the end of the tune options */
			as2 = as;
			for (;;) {
				as3 = as2->next;
				if (!as3)
					break;
				if (as3->type != ABC_T_NULL
				 && (as3->type != ABC_T_PSCOM
				  || strncmp(&as3->text[2], "tune ", 5) == 0))
					break;
				as2 = as3;
			}

			/* search if already a same %%tune */
			opt2 = NULL;
			for (opt = tune_opts; opt; opt = opt->next) {
				if (strcmp(opt->s->as.text, as->text) == 0)
					break;
				opt2 = opt;
			}

			if (opt) {
				free_voice_opt(opt->voice_opts);
				if (as2 == as) {	/* no option */
					if (!opt2)
						tune_opts = opt->next;
					else
						opt2->next = opt->next;
					free(opt);
					return as;
				}
				opt->voice_opts = NULL;
			} else {
				if (as2 == as)		/* no option */
					return as;
				opt = malloc(sizeof *opt);
				memset(opt, 0, sizeof *opt);
				opt->next = tune_opts;
				tune_opts = opt;
			}

			/* link the options */
			opt->s = s;
			cur_tune_opts = opt;
			as = as->next;
			for (;;) {
				if (as->type != ABC_T_PSCOM)
					continue;
				if (strncmp(&as->text[2], "voice ", 6) == 0) {
					as = process_pscomment(as);
				} else {
					as->state = ABC_S_HEAD;

					/* !! no reverse link !! */
					s->next = (struct SYMBOL *) as;
					s = s->next;
				}
				if (as == as2)
					break;
				as = as->next;
			}
			cur_tune_opts = NULL;
			return as;
		}
		break;
	case 'u':
		if (strcmp(w, "user") == 0) {
			deco[as->u.user.symbol] = deco_intern(as->u.user.value);
			return as;
		}
		break;
	case 'v':
		if (strcmp(w, "vocal") == 0) {
			set_voice_param(curvoice, as->state, w, p);
			return as;
		}
		if (strcmp(w, "voice") == 0) {
			struct abcsym *as2;
			struct voice_opt_s *opt, *opt2;

			if (as->state != ABC_S_GLOBAL) {
				error(1, s, "%%%%voice ignored");
				return as;
			}

			/* if void %%voice, free all voice options */
			if (*p == '\0') {
				if (cur_tune_opts) {
					free_voice_opt(cur_tune_opts->voice_opts);
					cur_tune_opts->voice_opts = NULL;
				} else {
					free_voice_opt(voice_opts);
					voice_opts = NULL;
				}
				return as;
			}

			if (strcmp(p, "end") == 0)
				return as;	/* end of previous %%voice */

			if (cur_tune_opts)
				opt = cur_tune_opts->voice_opts;
			else
				opt = voice_opts;

			/* search the end of the voice options */
			as2 = as;
			for (;;) {
				struct abcsym *as3;

				as3 = as2->next;
				if (!as3)
					break;
				if (as3->type != ABC_T_NULL
				 && (as3->type != ABC_T_PSCOM
				  || strncmp(&as3->text[2], "score ", 6) == 0
				  || strncmp(&as3->text[2], "staves ", 7) == 0
				  || strncmp(&as3->text[2], "tune ", 5) == 0
				  || strncmp(&as3->text[2], "voice ", 6) == 0))
					break;
				as2 = as3;
			}

			/* if already the same %%voice
			 * remove the options */
			opt2 = NULL;
			for ( ; opt; opt = opt->next) {
				if (strcmp(opt->s->as.text, as->text) == 0) {
					if (!opt2) {
						if (cur_tune_opts)
							cur_tune_opts->voice_opts = NULL;
						else
							voice_opts = NULL;
					} else {
						opt2->next = opt->next;
					}
					free(opt);
					break;
				}
				opt2 = opt;
			}
			if (as2 == as)		/* no option */
				return as;
			opt = malloc(sizeof *opt + strlen(p));
			memset(opt, 0, sizeof *opt);
			if (cur_tune_opts) {
				opt->next = cur_tune_opts->voice_opts;
				cur_tune_opts->voice_opts = opt;
			} else {
				opt->next = voice_opts;
				voice_opts = opt;
			}

			/* link the options */
			opt->s = s;
			for ( ; as != as2; as = as->next) {
				if (as->next->type != ABC_T_PSCOM)
					continue;
				as->next->state = ABC_S_TUNE;
				s->next = (struct SYMBOL *) as->next;
				s = s->next;
			}
			return as;
		}
		if (strcmp(w, "voicescale") == 0) {
			int voice;
			char *q;
			float scale;

			scale = strtod(p, &q);
			if (scale < 0.6 || scale > 1.5
			 || (*q != '\0' && *q != ' ')) {
				error(1, s, "Bad %%%%voicescale value");
				return as;
			}
			if (as->state != ABC_S_TUNE) {
				for (voice = 0; voice < MAXVOICE; voice++)
					voice_tb[voice].scale = scale;
			} else {
				curvoice->scale = scale;
			}
			return as;
		}
		if (strcmp(w, "volume") == 0) {
			set_voice_param(curvoice, as->state, w, p);
			return as;
		}
		if (strcmp(w, "vskip") == 0) {
			if (as->state == ABC_S_TUNE) {
				gen_ly(0);
			} else if (as->state == ABC_S_GLOBAL) {
				if (epsf || in_fname == 0)
					return as;
			}
			h1 = scan_u(p);
			bskip(h1);
			buffer_eob();
			return as;
		}
		break;
	}
	if (as->state == ABC_S_TUNE) {
		if (strcmp(w, "leftmargin") == 0
		 || strcmp(w, "rightmargin") == 0
		 || strcmp(w, "scale") == 0) {
			generate();
			block_put();
		}
	}
	interpret_fmt_line(w, p, lock);
	if (cfmt.alignbars && strcmp(w, "alignbars") == 0) {
		int i;

		generate();
		if ((unsigned) cfmt.alignbars > MAXSTAFF) {
			error(1, s, "Too big value in %%%%alignbars");
			cfmt.alignbars = MAXSTAFF;
		}
		if (staves_found >= 0)		/* (compatibility) */
			cfmt.alignbars = nstaff + 1;
		first_voice = curvoice = voice_tb;
		for (i = 0; i < cfmt.alignbars; i++) {
			voice_tb[i].staff = voice_tb[i].cstaff = i;
			voice_tb[i].next = &voice_tb[i + 1];
			parsys->staff[i].flags |= STOP_BAR;
			parsys->voice[i].staff = i;
			parsys->voice[i].range = i;
		}
		i--;
		voice_tb[i].next = NULL;
		nstaff = i;
	}
	return as;
}

/* -- set the duration of notes/rests in a tuplet -- */
/*fixme: KO if voice change*/
/*fixme: KO if in a grace sequence*/
static void set_tuplet(struct SYMBOL *t)
{
	struct abcsym *as;
	struct SYMBOL *s;
	int l, r, lplet, grace;

	r = t->as.u.tuplet.r_plet;
	grace = t->as.flags & ABC_F_GRACE;

	l = 0;
	for (as = t->as.next; as; as = as->next) {
		if (as->type == ABC_T_TUPLET) {
			struct abcsym *as2;
			int l2, r2;

			r2 = as->u.tuplet.r_plet;
			l2 = 0;
			for (as2 = as->next; as2; as2 = as2->next) {
				switch (as2->type) {
				case ABC_T_NOTE:
				case ABC_T_REST:
					break;
				case ABC_T_EOLN:
					if (as2->u.eoln.type != 1) {
						error(1, t,
							"End of line found inside a nested tuplet");
						return;
					}
					continue;
				default:
					continue;
				}
				if (as2->u.note.lens[0] == 0)
					continue;
				if (grace ^ (as2->flags & ABC_F_GRACE))
					continue;
				s = (struct SYMBOL *) as2;
				l2 += s->dur;
				if (--r2 <= 0)
					break;
			}
			l2 = l2 * as->u.tuplet.q_plet
					/ as->u.tuplet.p_plet;
			((struct SYMBOL *) as)->u = l2;
			l += l2;
			r -= as->u.tuplet.r_plet;
			if (r == 0)
				break;
			if (r < 0) {
				error(1, t, "Bad nested tuplet");
				break;
			}
			as = as2;
			continue;
		}
		switch (as->type) {
		case ABC_T_NOTE:
		case ABC_T_REST:
			break;
		case ABC_T_EOLN:
			if (as->u.eoln.type != 1) {
				error(1, t, "End of line found inside a tuplet");
				return;
			}
			continue;
		default:
			continue;
		}
		if (as->u.note.lens[0] == 0)	/* space ('y') */
			continue;
		if (grace ^ (as->flags & ABC_F_GRACE))
			continue;
		s = (struct SYMBOL *) as;
		l += s->dur;
		if (--r <= 0)
			break;
	}
	if (!as) {
		error(1, t, "End of tune found inside a tuplet");
		return;
	}
	if (t->u != 0)		/* if nested tuplet */
		lplet = t->u;
	else
		lplet = (l * t->as.u.tuplet.q_plet) / t->as.u.tuplet.p_plet;
	r = t->as.u.tuplet.r_plet;
	for (as = t->as.next; as; as = as->next) {
		int olddur;

		if (as->type == ABC_T_TUPLET) {
			int r2;

			r2 = as->u.tuplet.r_plet;
			s = (struct SYMBOL *) as;
			olddur = s->u;
			s->u = (olddur * lplet) / l;
			l -= olddur;
			lplet -= s->u;
			r -= r2;
			for (;;) {
				as = as->next;
				if (as->type != ABC_T_NOTE
				 && as->type != ABC_T_REST)
					continue;
				if (as->u.note.lens[0] == 0)
					continue;
				if (grace ^ (as->flags & ABC_F_GRACE))
					continue;
				if (--r2 <= 0)
					break;
			}
			if (r <= 0)
				goto done;
			continue;
		}
		if (as->type != ABC_T_NOTE && as->type != ABC_T_REST)
			continue;
		if (as->u.note.lens[0] == 0)
			continue;
		if (grace ^ (as->flags & ABC_F_GRACE))
			continue;
		s = (struct SYMBOL *) as;
		s->sflags |= S_IN_TUPLET;
		olddur = s->dur;
		s->dur = (olddur * lplet) / l;
		if (--r <= 0)
			break;
		l -= olddur;
		lplet -= s->dur;
	}
done:
	if (grace) {
		error(1, t, "Tuplets in grace note sequence not yet treated");
	} else {
		sym_link(t, TUPLET);
		t->u = cfmt.tuplets;
	}
}

/* -- add a new symbol in a voice -- */
struct SYMBOL *sym_add(struct VOICE_S *p_voice, int type)
{
	struct SYMBOL *s;
	struct VOICE_S *p_voice2;

	s = (struct SYMBOL *) getarena(sizeof *s);
	memset(s, 0, sizeof *s);
	p_voice2 = curvoice;
	curvoice = p_voice;
	sym_link(s, type);
	curvoice = p_voice2;
	if (p_voice->second)
		s->sflags |= S_SECOND;
	if (p_voice->floating)
		s->sflags |= S_FLOATING;
	if (s->prev) {
		s->as.fn = s->prev->as.fn;
		s->as.linenum = s->prev->as.linenum;
		s->as.colnum = s->prev->as.colnum;
	}
	return s;
}

/* -- link a ABC symbol into the current voice -- */
static void sym_link(struct SYMBOL *s, int type)
{
	struct VOICE_S *p_voice = curvoice;

/*	memset((&s->as) + 1, 0, sizeof (struct SYMBOL) - sizeof (struct abcsym)); */
	if (!p_voice->ignore) {
		s->prev = p_voice->last_sym;
		if (s->prev)
			p_voice->last_sym->next = s;
		else
			p_voice->sym = s;
		p_voice->last_sym = s;
//fixme:test bug
//	} else {
//		if (p_voice->sym)
//			p_voice->last_sym = p_voice->sym = s;
	}

	s->type = type;
	s->voice = p_voice - voice_tb;
	s->staff = p_voice->cstaff;
	s->time = p_voice->time;
	s->posit = p_voice->posit;
}
abcm2ps-7.8.13/sample.abc0000644000175000017500000000666312204130373013171 0ustar  jefjef% Sample file to test various features of abc2ps

U: M = !tenuto!		% abcm2ps: default M is lowermordent

% abcm2ps >= 7.6.0 - definition of '...' (ellipsis) for PostScript
%%glyph 2026 ellipsis

X:1
T:Scale
T:Second Title
T:Third Title
M:C
%K:C		% abcm2ps: automatic clef processing gives a bass clef
K:C treble
L: 1/4
 "C,"C,"D,"D,"E,"E,"F,"F,  "G,"G,"A,"A,"B,"B,\
| "C"C"D"D"E"E"F"F  "G"G"A"A"B"B| "c"c "d"d"e"e"f"f  "g"g"a"a"b"b"c'"c' |

X:3
T:Short and Long Notes, Beams and Tuplets
C:Trad
M:C
K:C
L: 1/8
 c8| d4 e2 fg | C c C/ c/ d/e/ d// C// C/D/E/F/ | d>e d>>e e<fe (3CDE (4fgab |

X:4
T:Key signature, Accidentals and Decorations
M:C
K:A
L: 1/4
 ^C=C_C ^G=G_G | .F/.G/.A/ Ma/Mg/Mf/ Jc J^c J[c^f] J[c^g]  |\
 {f}e {C}D {cd}c {E^c}a2 {dedc}d|    
 uc vc'-c'/Mb/Mc'/Ma/ | (b4 | b/).a/.b/.c'/ | ~A ~g \
% RA Rg MA Mg | .A .g vf/-g/ (u.a/.b/)  | uR~M.c2  Hg4 || % abcm2ps: '-' is not a slur
 RA Rg MA Mg | .A .g (vf/g/) (u.a/.b/)  | uR~M.c2  Hg4 ||

X:5
T:Bars and Rests
M:6/8
L: 1/4
K:D
[| z4 |] z2 |: z z/z// :| z2> :: z2 z>z | f>z g>z ||

X:6
T:Chords, Unions, First and Second Endings
M:9/8
K:D
L: 1/4
%|: [D2FA] ~+d2fa+ | [c2e][df][eg]|\	% abcm2ps: '+' is no more handled
|: [D2F2A2] ~[d2f2a2] | [c2e2][df][eg]|\
 [cc] [dd] [F/A][G/B][D/F]>[C/E] [G/e][A/e] [G/e]>.[A/e][B/e]>.[c/e]\
|1 (3[A//df][A//ef][A//cg] [G3Ce] :|2 (3[A//=df][^A//dg][_A//_c^g] [e3gc] |]

X:7
T:Slurs and Ties
T: Title with funny chars like \005 Çéñô Àçäßö © …
M:C|
K:Ebm
[| (CDEF) ((3efg) ((3gag)| (C2 EF) (ef(ga)) | ((c2 (3(d)ef) e2)\
 A2-|A4 c4-|(c4(e4)|a8) |]

X:8
T:Changing Time or Key Signatures, Guitar Chords
M: 6/8
K: G
 "Em"ABc def |\
M: 9/8
% abcm2ps: '\' is no more handled
%"Am7"A,CC DFF GBB |\M:4/4\"G"a,2b,2"D"c2d2 ||\L:1/4\\K:Bb\"Eb"e4|
"Am7"A,CC DFF GBB |[M:4/4]"G"a,2b,2"D"c2d2 ||[L:1/4][K:Bb]"Eb"e4-|
K: Gb
M: 6/8
L:1/8		% abcm2ps: basic length is not reset on M:
%| -"Gb"ede edc | def fed |1 "A"efg "D"gfe | e6 \ % abcm2ps: cannot have '-' before a note
| "Gb"ede edc | def fed |1 "A"efg "D"gfe | e6 \
:|2 "G"gag "F"f"Em"e"D7"d | "C"c6 |]

X:9
T:Strange tuplet cases
M:C
K:C
L: 1/8
 (3cde c(3d/e/f/ |(3zcd (3z/c/d/ (3czc c(4d/e/f/z/ d2-(3def | \
   (3::2 c4d2  (3::4 cde/f/ (3gfe |
 (3z2G,2A,2 (3C2E2G2 |e-(5e//f//g//f//g// de- (5e//f//g//f//g// |\
  (6z/c/e/g/e/c/ (6z/c/e/g/e/c/ | (3d/e/f/g-(3g/f/e/d || 

X:10
T:Chords with many accidentals
M: 6/8
K: G
[^c^d] [^c^e] [^c^f] [^c^g] [^c^a] [^c^b] |\
[^C^D] [^C^E] [^C^F] [^C^G] [^C^A] [^C^B] |\
[^c^d^e] [^c^d^f] [^c^f^g] [^c^f^a] [^c=d=f^g_a_b]  |]
[^c^f^a] [^c^f^b] [^c^f^c'] [^c^f^d'] [^c^f^e'] |\
[^c^e^f] [^c^f^g] [^c^g^a] [^c^g^b] |\
 [^c^d^c'] [^c^e^c'] [^A^e^c']   [^G^e^c']   \
 [^c_e^g][^c^f^g][^c^g^a][^c^d^g][^G^e^c']   ||

X:11
T:Horizontal beams
M:9/8
K:C
L: 1/8
 c,d,c, d,e,d, e,f,e, b,cb,  | c,/d,/c,/ d,/e,/d,/ e,/f,/e,/ |\
   c,//d,//c,// d,//e,//d,// e,//f,//e,// |
 cdc ded efe b,a,b,| c/d/c/ d/e/d/ e/f/e/ | c//d//c// d//e//d// e//f//e// |
 c'd'c' d'e'd' e'f'e' f'g'f' | c'/d'/c'/ d'/e'/d'/ e'/f'/e'/ |\ 
   c'//d'//c'// d'//e'//d'// e'//f'//e'// |

X:12
T:Gracenotes
L:1/8
M:C
K:D
FA{c}AF DF{^dc}A f{A}df f{AGA}df |{B}D2 {A}D2 {G}D2 {F}D2 {E}D2 |\
 {E}c2 {F}c2 {G}c2 {A}c2 {B}c2 | 
   {A}^c2 {gcd}c2 {gAGAG}A2{g}c<{GdG}e {Gdc}d>c {gBd}B<{e}G |\ 
  {G}[G4e4] {FGAB}[^c4A4] {ef}[e4c4] {d'c'bagfedcB_AcBFGC}D4| 

X: 13
T: Vocals
M: C|
K: F
L: 1/4
BA |: "Gm"G2AB|"C7"cd2e|"F"f2fe|"Dm"dA2d|
w: Close your eyes and I'll kiss you, to-mor-row I'll miss you; re-
"Bb"d2dc|"Gm"B2GF|"Eb"G4-|G2 z2|
w:mem-ber I'll al-ways be true._ 
abcm2ps-7.8.13/sample2.abc0000644000175000017500000000571612150576471013266 0ustar  jefjef% Sample file to test various features of abcm2ps
%%footer abcm2ps - sample2

U: N = !tenuto!

X:1
T:All clefs
M:C
L:1/4
K:C bass
"^bass"G,CEG|[K:bass3]"^bass3"G,CEG|[K:alto4]"^alto4"G,CEG|[K:alto]"^alto"G,CEG|
[K:alto2]"^alto2"G,CEG|[K:alto1]"^alto1"G,CEG|[K:treble]"^treble"G,CEG|
[K:treble1]"^treble1"G,CEG|[K:treble-8]"^treble-8"G,CEG|[K:treble+8]"^treble+8"G,CEG|

X:2
T:Key signature change
T:and multi-measure rest
M:2
L:1/4
K:C
Z4|"C"CEGc|[K:A]"A"Acea|[K:B]"B"Bdfb|[K:A]"A"Acea|
[K:Eb]"Eb"EGBe|[K:Cb]"Cb"CEGc|[K:C]"C"CEGc|

X:3
T:All clefs with max signatures
M:C
L:1/4
K:C# bass
C,E,G,C|[K:Cb]C,E,G,C|[K:C# bass3]C,E,G,C|
[K:Cb]C,E,G,C|[K:C# alto4]G,CEG|[K:Cb]G,CEG|
[K:C# alto]G,CEG|[K:Cb]G,CEG|[K:C# alto2]CEGc|
[K:Cb]CEGc|[K:C# alto1]CEGc|[K:Cb]CEGc|
[K:C# treble]CEGc|[K:Cb]CEGc|[K:C]CEGc|

X:4
T:Guitar chords - annotations
M:none
L:1/4
K:C
"^no time""^signature"CD"gchord""^on bar"|EF\
"^appogiattura"{B}c "^acciaccatura"{/B}c \
"^three;annot;lines"G "^and""^four""^annot""^lines!"c| \
"^Fa#"^F "^Sib"_B "^Fa="=F \
"F#"^F "Bb"_B||

X:5
T:Standard decorations
M:none
L:1/8
K:C
~C.D JENF HCRD TEuF vcLB MAPG ScOB|
w: \~ . J N H R T u v L M P S O
w: grace dot slide tenuto fermata roll trill upbow downbow \
w: emphasis lmordent umordent segno coda

X:6
T:All decorations
M:none
L:1/8
K:C
!0!C!1!D !2!E!3!F !4!G!5!A !+!B!accent!c|\
w:~0 ~1 ~2 ~3 ~4 ~5 ~+ accent
!breath!C!crescendo(!D !crescendo)!E!D.C.!F !diminuendo(!G!diminuendo)!A !f!B!ffff!c|
w:breath crescendo( crescendo) D.C. diminuendo( diminuendo) ~f ffff
!fine!C!invertedfermata!D !longphrase!E !mediumphrase!F !mf!G!open!A !p!B!pppp!c|
w:fine invertedfermata longphrase mediumphrase mf open ~p pppp
!pralltriller!C!sfz!D !shortphrase!E !snap!F !thumb!G!turn!A!wedge!B!D.S.!c|
w:pralltriller sfz shortphrase snap thumb turn wedge D.S.

X:7
T:Non standard decorations
C:Composer
O:Origin
R:Rhythm
M:none
L:1/8
K:C
!turnx!G!invertedturn!A !invertedturnx!B !arpeggio![EGc]|\
w:turnx invertedturn invertedturnx arpeggio
!trill(!c4-|!trill)!c3|
w:trill( trill)

X:8
T:Decorations on two voices
T:(also in 'd:' lines)
%%infoline 1
C:Composer
O:Origin
R:Rhythm
M:C
%%staves (1 2)
K:C
V:1
  ~c.dJeNf cdef|aabc' gabc'|!coda!cdef gfec||
d: * * * * HRTu|!mf!       |!sfz!  *** ***!D.S.!
V:2
   CDEF    CDEF|ffga   efga|C  D  EF   [EG]FEC||
d: ~.JN    HRTu|~.JN   HRTu|!5!!4!M*   !5! M
d:             |           |*  P  !3!  !4!

X:9
T:Beams
L:1/16
M:4/4
K:C
(3CDE(3FGA B/c/d/e/d/c/B/A/ (3zDE(3FGz z/c/d/e/d/c/B/z/|(3CDz(3zGA B/c/d/z/z/c/B/A/ G8|

X:10
T:Voice overlap
T:invisible and dashed bars
M:2/4
L:1/8
%%staves (1 2)
K:C
V:1
FEDC:GGGG|G2 G2|c4[|]GABc|
V:2
GABc:FEDC|GD G>D|cBAG[|]G4|

X:11
T:Clef transpositions
M:C
L:1/4
K:C
%%titleleft 1
T:No transposition
"^clef=treble""A,"A,"B,"B,"C"C"D"D|\
[K:alto]"^alto""A,"A,"B,"B,"C"C"D"D|\
[K:bass]"^bass""A,"A,"B,"B,"C"C"D"D|
T:abc2ps compatible clef transposition
%%abc2pscompat 1
[K:treble]"^treble""A,"A,"B,"B,"C"C"D"D|\
[K:alto]"^alto""A"A"B"B"c"c"d"d|\
[K:bass]"^bass""a"a"b"b"c'"c'"d'"d'|
%%titleleft 0
abcm2ps-7.8.13/sample3.abc0000644000175000017500000000414212150576703013255 0ustar  jefjef%%deco alcoda 3 dacs 20 0 0 Al Coda
%%header "		$T\n		Page $P"
%%footer "	$F"

X:1
T:abcm2ps version 3 features
M:2/4 3/4
K:C
C2D2 E2F2G2{FG}|G4-G6|1.2[M:5/4 (2/4 3/4)]G4{AB}z6:|["last time"A2B2 c6||
%%multicol start
%%rightmargin 11.5cm
[M:2/4]C2G2|C4|
%%multicol new
%%leftmargin 11.5cm
%%begintext

Multi column text on the right after a blank line.
%%endtext
%%multicol end
%%multicol start
%%rightmargin 11.5cm
%%begintext
         And now at the left side.
Here, there are spaces to align
                the text on the right.
%%endtext
%%multicol new
%%leftmargin 11.5cm
CD EF|GA Bc|
%%multicol end
%
%%center Scale change inside the tune
%%scale 0.6
%%leftmargin 7cm
%%rightmargin 11cm
CD EF|
%%scale 1.2
%%leftmargin 11cm
%%rightmargin 4cm
CD EF|
%%leftmargin 5cm
%%scale 1
%%EPS sample3.eps
%%scale 0.75		% set the scale back to default
% restore the left and right margins
%%leftmargin 1.78cm
%%rightmargin 1.78cm
%%center Is this centered?

X:2
T:Staff break
M:none
L:1/8
K:G exp ^F ^F, clef=C
%%staffbreak 0.2cm
[K:G clef=treble][M:C]SDE FG|AG !alcoda!FEO|DE FES||\
%%staffbreak 2cm
[K:G clef=treble]OC2D2||

X:3
T:Staff break multi-staves
M:none
L:1/8
%%staves {1 2}
K:G
V:1
[K:G exp ^F ^F, clef=C]
%%staffbreak 0.2cm
V:2 bass
%%staffbreak 0.2cm
V:1
[K:G clef=treble][M:C]SDE FG|AG !alcoda!FEO|DE FES||\
V:2
[K:G clef=bass][M:C]D,4|A,4|D,4||\
V:1
%%staffbreak 2cm
[K:G clef=treble]OC2D2||
V:2
%%staffbreak 2cm
[K:G clef=bass]A,,2D,,2||

X:4
T:Voice overlay and chords
M:C
L:1/4
K:C
[C2G]A[B3/G2]c/|cdef&ABcd|GA{[FA]}[GB][Ac]|defg&Bcde|
GABc|efga&FGAB&CDEF|GA(&Bc|de&FG|AB&)cd|

X:5
T:Annotations and guitar chords
M:C
L:1/8
%%gchordbox 1
K:C
"^annotation""gchord in box"CD"_below"EG "<left"cd">right"ec|\
"@20,-50anywhere"gf"<("">)"ed (c4y)||

X:6
T:Grace notes
M:C
L:1/4
%%graceslurs 0
K:C
V:1 name="voice name\non\nthree lines"
{B2}A{B}A{B/}A{B//}A|{c4B4}A{c2B2}A{cB}A{c/B/}A|
{a2g2f2 e2d2c2B4}A4|\
	{(AB)}c{(AB}c){(GA)B}c{G(AB}c)|\
	(c2{BA)G}{(G/A/B/) (G/A/B/)}c2||

X:7
T:Drum
M:C
L:1/8
%%staves (1 2)
K:C clef=perc
V:1
^a^f[c^f]^f ^f^f[c^f]^f|^a^f[c^f]^f ^f/c/^f c/^a3/||
V:2
FF/F/ z3/F/ zF/F/ z/F3/|FF/F/ z3/F/ z3/F/ z/F3/||
abcm2ps-7.8.13/sample3.eps0000644000175000017500000000030107612251066013307 0ustar  jefjef%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 50 40
%%Pages: 0
%%EndProlog
0 0 moveto 25 40 rlineto 25 -40 rlineto -50 0 rlineto fill
1.0 setgray /Times-Roman 14 selectfont 13 8 moveto (EPS) show
abcm2ps-7.8.13/sample4.abc0000644000175000017500000000601112277212023013243 0ustar  jefjef% sample4.abc - this file is part of abcm2ps

% definitions for tablature
%%beginps
/hn{	currentgray 1.0 setgray 1 SLW
	2 index 2 sub 2 index M 8 0 RL stroke setgray
	3 sub M /Helvetica-Bold 8 selectfont show}!
%%endps
%%deco head-3 3 hn 0 0 0 3
%%deco head-4 3 hn 0 0 0 4
%%deco head-5 3 hn 0 0 0 5
U:i=!invisible!
U:j=!head-3!
U:k=!head-4!
U:l=!head-5!

X:1
%%abc-version 2.0
T:ABC-2.0 new fea\	% strange continuation line
tures
M:C
L:1/4
%%measurenb 1
K:C
CDEF | GABc | FEDC [I:setbarnb 10] | [CEG]4 |]
s:"^annotation;in 's:' line"**+1+|||H|

X:2
T:abcm2ps-4.x.x new features
%%graceslurs 0
%%breakoneoln 0		% needed with abcm2ps-5.x.x
M:C
L:1/4
Q:1/4=ca. 80
K:none
"^slur above.."('FG) "^..below"(,FG)|\
"^dashed tie.."A.-A "^..slur".(ce/)d/"^beam;crossing;a bar"!beamon!|\
c/B/ "^chord slur"{(,G}[CA)]3||
"^standard tuplet"(3A/A/A/ "^no bracket"[I:tuplets 1 0 0](3A/A/A/ \
"^forced bracket"[I:tuplets 2 0 0](3A/A/A/ "^ratio"[I:tuplets 0 0 2](3A/A/A/| \
"^nested tuplets"[I:tuplets 2 0 2](7:8:8(3A/A/A/ A/A/A/A/A/|
"^1/4 tone;sharp"^/G  ^G "^3/4 tone;sharp"^3/2G ^^G |\
"^1/4 tone;flat"_/G _G "^3/4 tone;flat"_3/2G __G|"^deco on;grace note"{.A4.B4}c4||
% tremolo: note the position of the decorations and the note lengths
"^tremolo"C/c/C/c/ C!trem1!c | C2!trem1!c2 | \
C//[Gc]//C//[Gc]// C//[Gc]//C//[Gc]// C!trem2![Gc] | C2!trem2![Gc]2 ||
%
C///D///E///F///G///F///E///D///\
C///D///E///F///G///F///E///D/// \
"^beam break"C///D///E///F///!beambr2!G///F///E///D///\
!beambr1!C///D///E///F///!beambr2!G///F///E///D///||
T:		% needed with abcm2ps-5.x.x
%%staves 1 2
%%rightmargin 12cm
V:1
"^cross staff stems"cc//c//c//c//c2 | [CEGc]2[CEGc]2||
V:2 bass
!xstem!C,C,//!xstem!C,//C,//!xstem!C,//!xstem!C,2 | !xstem![C,,C,]2[C,,C,]2||

X:3
T:Yesterday
T:(extract)
M:4/4
L:1/8
%%staves (melody1 chords melody2)
K:F
V:melody1
%%stemdir down
e3/d/ d6 | z2 d/d3/ cB/A/- AG |
w: far a-way, | Now it looks as though_ they're |
V:chords
"Dm"x4 "Dm/C"x4 | "Bb"x4  "C7"x4 |
V:melody2
%%stemdir up
%%voicescale 0.8
ie3/id/ id6 | x2 d/dc/.- c/B3/ AG |
w: used to be, | There's a shad-_ow hang-ing |

X:4
T:Fantaisie
C:Camille Saint-Saëns
M:C
L:1/8
%%staves [recit GO pos ped]
K:Eb
V:recit name="Récit"
z8|z8|z8|
V:GO treble name="Grand\nOrgue"
z2[G,B,E][I:staff 3][G,B,E] \
 [I:staff 2][A,CF][I:staff 3][A,CF] [I:staff 2][CEA][I:staff 3][CEA]| \
[I:staff 2][A,CF][I:staff 3][A,CF] [I:staff 2][B,DG][I:staff 3][B,DG] \
 [I:staff 2][CEA][I:staff 3][CEA] [I:staff 2][DAc][I:staff 3][DAc]| \
[I:staff 2][EGB][I:staff 3][EGB] [I:staff 2][GBe][I:staff 3][GBe] \
 [I:staff 2][EGB][I:staff 3][EGB] [I:staff 2][DFA][I:staff 3][DFA]|
V:pos treble name=Positif
z2x6|x8|x8|
V:ped name="Pédale"
E,,8-|E,,8-|E,,2G,,2B,,2=B,,2|

X:5
T:Special staves
M:9/8
L:1/8
%%staves [1 2] | (3 4)
K:Cm
V:1 stem=up
[CGceg]6[C-,G-,ceg]3-|[CGceg]3[CGceg]6|
% tablature
V:2 clef=none
%%stafflines 6
%%staffscale 1.6
%%staffnonote 2
[K:none][M:none]i[jGlBldkfja]6i[jGlBldkfja]3|iA3i[jGlBldkfja]6|
% percussion
V:3 clef=perc
%%stafflines 1
[K:none]^c3^c3^c^c^c|^c3^c3^c^c^c|
V:4 clef=perc stafflines=1
[K:none]A3A3A3|A6A3|
abcm2ps-7.8.13/sample5.abc0000644000175000017500000000364112061346473013262 0ustar  jefjef% sample5.abc - this file is part of abcm2ps

%%writefields NF 1
%%infoname F "This file is part of the "
F:abcm2ps sources at http://moinejf.free.fr/

X:1
%%titleformat T,TTQ-1C1A1
T:New features in abcm2ps-5.x.x
T:Subtitle one
T:Subtitle two
C:This is the composer field
A:This is the Area/Author field
N:Here are some notes (N:)
N:on two lines
M:c. C=4/4
L:1/4
Q:"Tempo in the tune header"
K:C
Q:"Tempo in the tune body"
"C"C"Dm	G"D2"C"C"^<- guitar chords between symbols"|\
	C//E//G//E// \
	[I:repeat 4 3]C//E//G//E// "^sequence repeat"C//E//G//E// C//E//G//E//|
"^measure repeat"GABc|[I:repeat 1 2]GABc|GABc|\
	G2d2|B2d2|[I:repeat 2]G2d2|B2d2|c4||
"^tremolo 2 notes"\
	z/ C//!trem1!c// C/!trem1!c/ C!trem1!c | C2!trem1!c2 | \
	z/ C//!trem2!c// C/!trem2!c/ C!trem2!c | C2!trem2!c2 |
"^tremolo 1 note"\
	z C//!/!c// c//!/!C// C/!/!c/ c/!/!C/ | \
	z C//!//!c// c//!//!C// C/!//!c/ c/!//!C/ |
	z !/!C/ !/!c/ !/!C !/!c | !/!C2 !/!c2 | \
	z !//!C/ !//!c/ !//!C !//!c | !//!C2 !//!c2 ||
	!/!C4 | !/!c4 | !//!C4 | !//!c4 |

%%writefields F 0
X:2
T:Romance sans paroles
C:F.B. Mendelssohn
M:12/8
L:1/8
K:Eb
%%staves {M A1 A2}
V:M	% Melody
x6z2z(B3|\
V:A1
%%voicescale 0.8
z(G,[B,E]) z(G,[B,E]) z(G,[B,E]) z(G,[B,E])|\
V:A2
%%staffscale 0.8
E,,3G,,3B,,3G,,3|\
%%staves M
A2GF2EE3)E3|(E3c6)(B2A|G3F3B3F3)|

X:3
T:Fugue II
T:(extract from the well-tempered clavichord II)
C:J.S. Bach
M:none
L:1/8
K:Cm
%%rightmargin 0.5cm
%%leftmargin 0.5cm
%%staves 1s 3s | {(1 2) 3}
V:1s name="Ossia"
%%staffscale 0.8
V:3s
%%staffscale 0.8
%%clef bass
V:1
gc fe/d/ e>e d=e\
V:2
B_A/G/ c/[I:staff +1]C/[I:staff -1]G- G/G/=A B/cD/\
V:3
B,/G,/ C=A,=B, CF, _B,_A,/G,/\
%%staves (1s 2) 3s | {(1 2) 3}
V:1s
|fB _e_d/c/ dG\
V:3s
|_A,_D- D/C/F/E/ D/C/D-\
V:1
|fB _ed/c/ dG\
V:2
|z/c/B/_A/ G=A BG\
V:3
|=A,=D- D/C/F/E/ D/C/_D-\
%%staves 1s 3s | {(1 2) (3 4)}
V:1
 e2-|e/e/d- d/c/=B cg de/f/|
V:2
 _AG/F/|G>F ED CeA2|
V:3
 D/C/B,/_A,/|B,=B,CD G,/C/B,/C/- C/B,/C-|
V:4
 x2|z2G,2E,2F,2|
abcm2ps-7.8.13/slre.c0000644000175000017500000003370312314503212012343 0ustar  jefjef/*
 * Super Light Regular Expression library
 *
 * Copyright (c) 2012 Jean-François Moine (http://moinejf.free.fr)
 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
 * All rights reserved
 *
 * "THE BEER-WARE LICENSE" (Revision 42):
 * Sergey Lyubka wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.
 */

#ifdef SLRE_TEST
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#else
#define assert(x) do {} while (0)
#endif
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include "slre.h"

enum {END, BRANCH, ANY, EXACT, ANYOF, ANYBUT, OPEN, CLOSE, BOL, EOL,
	STAR, PLUS, STARQ, PLUSQ, QUEST, SPACE, NONSPACE, DIGIT};

/*
 * Commands and operands are all unsigned char (1 byte long). All code offsets
 * are relative to current address, and positive (always point forward). Data
 * offsets are absolute. Commands with operands:
 *
 * BRANCH offset1 offset2
 *	Try to match the code block that follows the BRANCH instruction
 *	(code block ends with END). If no match, try to match code block that
 *	starts at offset1. If either of these match, jump to offset2.
 *
 * EXACT data_offset data_length
 *	Try to match exact string. String is recorded in data section from
 *	data_offset, and has length data_length.
 *
 * OPEN capture_number
 * CLOSE capture_number
 *	If the user have passed 'struct cap' array for captures, OPEN
 *	records the beginning of the matched substring (cap->ptr), CLOSE
 *	sets the length (cap->len) for respective capture_number.
 *
 * STAR code_offset
 * PLUS code_offset
 * QUEST code_offset
 *	*, +, ?, respectively. Try to gobble as much as possible from the
 *	matched buffer, until code block that follows these instructions
 *	matches. When the longest possible string is matched,
 *	jump to code_offset
 *
 * STARQ, PLUSQ are non-greedy versions of STAR and PLUS.
 */

static const char *meta_chars = "|.^$*+?()[\\";

#ifdef SLRE_TEST
static struct {
	const char	*name;
	int		narg;
	const char	*flags;	
} opcodes[] = {
	{"END",		0, ""},		/* End of code block or program	*/
	{"BRANCH",	2, "oo"},	/* Alternative operator, "|"	*/
	{"ANY",		0, ""},		/* Match any character, "."	*/
	{"EXACT",	2, "d"},	/* Match exact string		*/
	{"ANYOF",	2, "D"},	/* Match any from set, "[]"	*/
	{"ANYBUT",	2, "D"},	/* Match any but from set, "[^]"*/
	{"OPEN ",	1, "i"},	/* Capture start, "("		*/
	{"CLOSE",	1, "i"},	/* Capture end, ")"		*/
	{"BOL",		0, ""},		/* Beginning of string, "^"	*/
	{"EOL",		0, ""},		/* End of string, "$"		*/
	{"STAR",	1, "o"},	/* Match zero or more times "*"	*/
	{"PLUS",	1, "o"},	/* Match one or more times, "+"	*/
	{"STARQ",	1, "o"},	/* Non-greedy STAR,  "*?"	*/
	{"PLUSQ",	1, "o"},	/* Non-greedy PLUS, "+?"	*/
	{"QUEST",	1, "o"},	/* Match zero or one time, "?"	*/
	{"SPACE",	0, ""},		/* Match whitespace, "\s"	*/
	{"NONSPACE",	0, ""},		/* Match non-space, "\S"	*/
	{"DIGIT",	0, ""}		/* Match digit, "\d"		*/
};

static void
print_character_set(FILE *fp, const unsigned char *p, int len)
{
	int	i;

	for (i = 0; i < len; i++) {
		if (i > 0)
			fputc(',', fp);
		if (p[i] == 0) {
			i++;
			if (p[i] == 0)
				fprintf(fp, "\\x%02x", p[i]);
			else
				fprintf(fp, "%s", opcodes[p[i]].name);
		} else if (isprint(p[i])) {
			fputc(p[i], fp);
		} else {
			fprintf(fp,"\\x%02x", p[i]);
		}
	}
}

void
slre_dump(const struct slre *r, FILE *fp)
{
	int	i, j, ch, op, pc;

	for (pc = 0; pc < r->code_size; pc++) {

		op = r->code[pc];
		fprintf(fp, "%3d %s ", pc, opcodes[op].name);

		for (i = 0; opcodes[op].flags[i] != '\0'; i++)
			switch (opcodes[op].flags[i]) {
			case 'i':
				fprintf(fp, "%d ", r->code[pc + 1]);
				pc++;
				break;
			case 'o':
				fprintf(fp, "%d ",
					pc + r->code[pc + 1] - i);
				pc++;
				break;
			case 'D':
				print_character_set(fp, r->data +
					r->code[pc + 1], r->code[pc + 2]);
				pc += 2;
				break;
			case 'd':
				fputc('"', fp);
				for (j = 0; j < r->code[pc + 2]; j++) {
					ch = r->data[r->code[pc + 1] + j];
					if (isprint(ch))
						fputc(ch, fp);
					else
						fprintf(fp,"\\x%02x",ch);
				}
				fputc('"', fp);
				pc += 2;
				break;
			}

		fputc('\n', fp);
	}
}
#endif /* SLRE_TEST */

static void
set_jump_offset(struct slre *r, int pc, int offset)
{
	assert(offset < r->code_size);

#if 0
	if (r->code_size - offset > 0xff)
		r->err_str = "Jump offset is too big";
	else
#endif
		r->code[pc] = (unsigned char) (r->code_size - offset);
}

static void
emit(struct slre *r, int code)
{
#if 0
	if (r->code_size >= (int) (sizeof(r->code) / sizeof(r->code[0])))
		r->err_str = "RE is too long (code overflow)";
	else
#endif
		r->code[r->code_size++] = (unsigned char) code;
}

static void
store_char_in_data(struct slre *r, int ch)
{
#if 0
	if (r->data_size >= (int) sizeof(r->data))
		r->err_str = "RE is too long (data overflow)";
	else
#endif
		r->data[r->data_size++] = ch;
}

static const char *
exact(struct slre *r, const char *re)
{
	int	old_data_size = r->data_size;

	while (*re != '\0' && strchr(meta_chars, *re) == NULL)
		store_char_in_data(r, *re++);

	emit(r, EXACT);
	emit(r, old_data_size);
	emit(r, r->data_size - old_data_size);
	return re;
}

static int
get_escape_char(char c)
{
	int	res;

	switch (c) {
	case 'n':	res = '\n';		break;
	case 'r':	res = '\r';		break;
	case 't':	res = '\t';		break;
	case '0':	res = 0;		break;
	case 'S':	res = NONSPACE << 8;	break;
	case 's':	res = SPACE << 8;	break;
	case 'd':	res = DIGIT << 8;	break;
	default:	res = c;		break;
	}

	return res;
}

static const char *
anyof(struct slre *r, const char *re)
{
	int	esc, old_data_size = r->data_size, op = ANYOF;

	if (*re == '^') {
		op = ANYBUT;
		re++;
	}

	while (*re != '\0')

		switch (*re++) {
		case ']':
			emit(r, op);
			emit(r, old_data_size);
			emit(r, r->data_size - old_data_size);
			return re;
		case '\\':
			esc = get_escape_char(*re++);
			if ((esc & 0xff) == 0) {
				store_char_in_data(r, 0);
				store_char_in_data(r, esc >> 8);
			} else {
				store_char_in_data(r, esc);
			}
			break;
		default:
			store_char_in_data(r, re[-1]);
			break;
		}

	r->err_str = "No closing ']' bracket";
	return re;
}

static void
relocate(struct slre *r, int begin, int shift)
{
	emit(r, END);
	memmove(r->code + begin + shift, r->code + begin, r->code_size - begin);
	r->code_size += shift;
}

static void
quantifier(struct slre *r, int prev, int op)
{
	if (r->code[prev] == OPEN) {
		r->err_str = "No character before *, + or ?";
		return;
	}
	if (r->code[prev] == EXACT && r->code[prev + 2] > 1) {
		r->code[prev + 2]--;
		emit(r, EXACT);
		emit(r, r->code[prev + 1] + r->code[prev + 2]);
		emit(r, 1);
		prev = r->code_size - 3;
	}
	relocate(r, prev, 2);
	r->code[prev] = op;
	set_jump_offset(r, prev + 1, prev);
}

static void
exact_one_char(struct slre *r, int ch)
{
	emit(r, EXACT);
	emit(r, r->data_size);
	emit(r, 1);
	store_char_in_data(r, ch);
}

static void
fixup_branch(struct slre *r, int fixup)
{
	if (fixup > 0) {
		emit(r, END);
		set_jump_offset(r, fixup, fixup - 2);
	}
}

static const char *
compile(struct slre *r, const char *re)
{
	int	op, esc, branch_start, last_op, fixup, cap_no, level;

	fixup = 0;
	level = r->num_caps;
	branch_start = r->code_size;
	last_op = branch_start - 2;	/* points to OPEN */

	for (;;) {
		switch (*re++) {
		case '\0':
			re--;
			return re;
		case '^':
			emit(r, BOL);
			break;
		case '$':
			emit(r, EOL);
			break;
		case '.':
			last_op = r->code_size;
			emit(r, ANY);
			break;
		case '[':
			last_op = r->code_size;
			re = anyof(r, re);
			break;
		case '\\':
			last_op = r->code_size;
			esc = get_escape_char(*re++);
			if (esc & 0xff00)
				emit(r, esc >> 8);
			else
				exact_one_char(r, esc);
			break;
		case '(':
			last_op = r->code_size;
			cap_no = ++r->num_caps;
			emit(r, OPEN);
			emit(r, cap_no);

			re = compile(r, re);
			if (*re++ != ')') {
				r->err_str = "No closing bracket";
				return re;
			}

			emit(r, CLOSE);
			emit(r, cap_no);
			break;
		case ')':
			re--;
			fixup_branch(r, fixup);
			if (level == 0)
				r->err_str = "Unbalanced brackets";
			return re;
		case '+':
		case '*':
			op = re[-1] == '*' ? STAR: PLUS;
			if (*re == '?') {
				re++;
				op = op == STAR ? STARQ : PLUSQ;
			}
			quantifier(r, last_op, op);
			break;
		case '?':
			quantifier(r, last_op, QUEST);
			break;
		case '|':
			fixup_branch(r, fixup);
			relocate(r, branch_start, 3);
			r->code[branch_start] = BRANCH;
			set_jump_offset(r, branch_start + 1, branch_start);
			fixup = branch_start + 2;
			r->code[fixup] = 0xff;
			break;
		default:
			re--;
			last_op = r->code_size;
			re = exact(r, re);
			break;
		}
	}
	return re;
}

int
slre_compile(struct slre *r, const char *re)
{
	r->err_str = NULL;
	r->code_size = r->data_size = r->num_caps = r->anchored = 0;

	if (*re == '^')
		r->anchored++;

	emit(r, OPEN);	/* This will capture what matches full RE */
	emit(r, 0);

//fixme
//	while (*re != '\0')
		compile(r, re);

	if (r->code[2] == BRANCH)
		fixup_branch(r, 4);

	emit(r, CLOSE);
	emit(r, 0);
	emit(r, END);

	return r->err_str == NULL ? 1 : 0;
}

static int match(const struct slre *, int,
		const char *, int, int *, struct cap *);

static void
loop_greedy(const struct slre *r, int pc, const char *s, int len, int *ofs)
{
	int	saved_offset, matched_offset;

	saved_offset = matched_offset = *ofs;

	while (match(r, pc + 2, s, len, ofs, NULL)) {
		saved_offset = *ofs;
		if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL))
			matched_offset = saved_offset;
		*ofs = saved_offset;
	}

	*ofs = matched_offset;
}

static void
loop_non_greedy(const struct slre *r, int pc, const char *s,int len, int *ofs)
{
	int	saved_offset = *ofs;

	while (match(r, pc + 2, s, len, ofs, NULL)) {
		saved_offset = *ofs;
		if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL))
			break;
	}

	*ofs = saved_offset;
}

static int
is_any_of(const unsigned char *p, int len, const char *s, int *ofs)
{
	int	i, ch;

	ch = s[*ofs];

	for (i = 0; i < len; i++)
		if (p[i] == ch) {
			(*ofs)++;
			return 1;
		}

	return 0;
}

static int
is_any_but(const unsigned char *p, int len, const char *s, int *ofs)
{
	int	i, ch;

	ch = s[*ofs];

	for (i = 0; i < len; i++) {
		if (p[i] == ch)
			return 0;
	}

	(*ofs)++;
	return 1;
}

static int
match(const struct slre *r, int pc, const char *s, int len,
		int *ofs, struct cap *caps)
{
	int	n, saved_offset, res = 1;

	while (res && r->code[pc] != END) {

		assert(pc < r->code_size);
		assert(pc < (int) (sizeof(r->code) / sizeof(r->code[0])));

		switch (r->code[pc]) {
		case BRANCH:
			saved_offset = *ofs;
			res = match(r, pc + 3, s, len, ofs, caps);
			if (res == 0) {
				*ofs = saved_offset;
				res = match(r, pc + r->code[pc + 1],
						s, len, ofs, caps);
			}
			pc += r->code[pc + 2]; 
			break;
		case EXACT:
			res = 0;
			n = r->code[pc + 2];	/* String length */
			if (n <= len - *ofs
			 && !memcmp(s + *ofs, r->data + r->code[pc + 1], n)) {
				(*ofs) += n;
				res = 1;
			}
			pc += 3;
			break;
		case QUEST:
			res = 1;
			saved_offset = *ofs;
			if (!match(r, pc + 2, s, len, ofs, caps))
				*ofs = saved_offset;
			pc += r->code[pc + 1];
			break;
		case STAR:
			res = 1;
			loop_greedy(r, pc, s, len, ofs);
			pc += r->code[pc + 1];
			break;
		case STARQ:
			res = 1;
			loop_non_greedy(r, pc, s, len, ofs);
			pc += r->code[pc + 1];
			break;
		case PLUS:
			res = match(r, pc + 2, s, len, ofs, caps);
			if (res == 0)
				break;

			loop_greedy(r, pc, s, len, ofs);
			pc += r->code[pc + 1];
			break;
		case PLUSQ:
			res = match(r, pc + 2, s, len, ofs, caps);
			if (res == 0)
				break;

			loop_non_greedy(r, pc, s, len, ofs);
			pc += r->code[pc + 1];
			break;
		case SPACE:
			res = 0;
			if (*ofs < len && isspace(((unsigned char *) s)[*ofs])) {
				(*ofs)++;
				res = 1;
			}
			pc++;
			break;
		case NONSPACE:
			res = 0;
			if (*ofs <len && !isspace(((unsigned char *) s)[*ofs])) {
				(*ofs)++;
				res = 1;
			}
			pc++;
			break;
		case DIGIT:
			res = 0;
			if (*ofs < len && isdigit(((unsigned char *)s)[*ofs])) {
				(*ofs)++;
				res = 1;
			}
			pc++;
			break;
		case ANY:
			res = 0;
			if (*ofs < len) {
				(*ofs)++;
				res = 1;
			}
			pc++;
			break;
		case ANYOF:
			res = 0;
			if (*ofs < len)
				res = is_any_of(r->data + r->code[pc + 1],
					r->code[pc + 2], s, ofs);
			pc += 3;
			break;
		case ANYBUT:
			res = 0;
			if (*ofs < len)
				res = is_any_but(r->data + r->code[pc + 1],
					r->code[pc + 2], s, ofs);
			pc += 3;
			break;
		case BOL:
			res = *ofs == 0 ? 1 : 0;
			pc++;
			break;
		case EOL:
			res = *ofs == len ? 1 : 0;
			pc++;
			break;
		case OPEN:
			if (caps != NULL)
				caps[r->code[pc + 1]].ptr = s + *ofs;
			pc += 2;
			break;
		case CLOSE:
			if (caps != NULL)
				caps[r->code[pc + 1]].len = (s + *ofs) -
				    caps[r->code[pc + 1]].ptr;
			pc += 2;
			break;
		case END:
			pc++;
			break;
		default:
			fprintf(stderr,
				"slre: Unknown cmd (%d) at %d\n", r->code[pc], pc);
			assert(0);
			break;
		}
	}

	return res;
}

int
slre_match(const struct slre *r, const char *buf, int len,
		struct cap *caps)
{
	int	i, ofs = 0, res = 0;

	if (r->anchored) {
		res = match(r, 0, buf, len, &ofs, caps);
	} else {
		for (i = 0; i < len && res == 0; i++) {
			ofs = i;
			res = match(r, 0, buf, len, &ofs, caps);
		}
	}

	return res;
}

#ifdef SLRE_TEST
int main(int argc, char *argv[])
{
	struct slre	slre;
	struct cap	caps[20];
	char		data[128 * 1024];
	FILE		*fp;
	int		i, count, res, len;

	if (argc < 3) {
		printf("Usage: %s 'slre' <file> [count]\n", argv[0]);
		return 1;
	}
	if (!slre_compile(&slre, argv[1])) {
		printf("Error compiling slre: %s\n", slre.err_str);
		return 1;
	}
	fp = fopen(argv[2], "rb");
	if (fp == NULL) {
		printf("Error: cannot open %s:%s\n",
			argv[2], strerror(errno));
		return 1;
	}
	slre_dump(&slre, stderr);

	memset(caps, 0, sizeof(caps));

	/* Read first 128K of file */
	len = fread(data, 1, sizeof(data), fp);
	fclose(fp);

	res = 0;
	count = argc > 3 ? atoi(argv[3]) : 1;
	for (i = 0; i < count; i++)
		res = slre_match(&slre, data, len, caps);

	printf("Result: %d\n", res);

	for (i = 0; i < 20; i++) {
		if (caps[i].len > 0)
			printf("Substring %d: [%.*s]\n", i,
				caps[i].len, caps[i].ptr);
	}

	return 0;
}
#endif /* SLRE_TEST */
abcm2ps-7.8.13/slre.h0000644000175000017500000000551012314503216012347 0ustar  jefjef/*
 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
 * All rights reserved
 *
 * "THE BEER-WARE LICENSE" (Revision 42):
 * Sergey Lyubka wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.
 */

/*
 * This is a regular expression library that implements a subset of Perl RE.
 * Please refer to http://slre.sourceforge.net for detailed description.
 *
 * Usage example (parsing HTTP request):
 *
 * struct slre	slre;
 * struct cap	captures[4 + 1];  // Number of braket pairs + 1
 * ...
 *
 * slre_compile(&slre,"^(GET|POST) (\S+) HTTP/(\S+?)\r\n");
 *
 * if (slre_match(&slre, buf, len, captures)) {
 *	printf("Request line length: %d\n", captures[0].len);
 *	printf("Method: %.*s\n", captures[1].len, captures[1].ptr);
 *	printf("URI: %.*s\n", captures[2].len, captures[2].ptr);
 * }
 *
 * Supported syntax:
 *	^		Match beginning of a buffer
 *	$		Match end of a buffer
 *	()		Grouping and substring capturing
 *	[...]		Match any character from set
 *	[^...]		Match any character but ones from set
 *	\s		Match whitespace
 *	\S		Match non-whitespace
 *	\d		Match decimal digit
 *	\r		Match carriage return
 *	\n		Match newline
 *	+		Match one or more times (greedy)
 *	+?		Match one or more times (non-greedy)
 *	*		Match zero or more times (greedy)
 *	*?		Match zero or more times (non-greedy)
 *	?		Match zero or once
 *	\xDD		Match byte with hex value 0xDD
 *	\meta		Match one of the meta character: ^$().[*+?\
 */

#ifndef SLRE_HEADER_DEFINED
#define	SLRE_HEADER_DEFINED

/*
 * Compiled regular expression
 */
struct slre {
	unsigned char	code[256];
	unsigned char	data[256];
	unsigned char	code_size;
	unsigned char	data_size;
	unsigned char	num_caps;	/* Number of bracket pairs	*/
	unsigned char	anchored;	/* Must match from string start	*/
	const char	*err_str;	/* Error string			*/
};

/*
 * Captured substring
 */
struct cap {
	const char	*ptr;		/* Pointer to the substring	*/
	int		len;		/* Substring length		*/
};

/*
 * Compile regular expression. If success, 1 is returned.
 * If error, 0 is returned and slre.err_str points to the error message. 
 */
int slre_compile(struct slre *, const char *re);

/*
 * Return 1 if match, 0 if no match. 
 * If `captured_substrings' array is not NULL, then it is filled with the
 * values of captured substrings. captured_substrings[0] element is always
 * a full matched substring. The round bracket captures start from
 * captured_substrings[1].
 * It is assumed that the size of captured_substrings array is enough to
 * hold all captures. The caller function must make sure it is! So, the
 * array_size = number_of_round_bracket_pairs + 1
 */
int slre_match(const struct slre *, const char *buf, int buf_len,
	struct cap *captured_substrings);

#endif /* SLRE_HEADER_DEFINED */
abcm2ps-7.8.13/subs.c0000644000175000017500000011621312366212017012357 0ustar  jefjef/*
 * Low-level utilities.
 *
 * This file is part of abcm2ps.
 *
 * Copyright (C) 1998-2014 Jean-François Moine
 * Adapted from abc2ps, Copyright (C) 1996,1997 Michael Methfessel
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 */

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#ifdef HAVE_PANGO
#include <pango/pangocairo.h>
#include <pango/pangofc-font.h>
#endif

#include "abc2ps.h" 

char tex_buf[TEX_BUF_SZ];	/* result of tex_str() */
int outft = -1;			/* last font in the output file */

static char *strop;		/* current string output operation */
static float strlw;		/* line width */
static int curft;		/* current (wanted) font */
static int defft;		/* default font */
static char strtx;		/* PostScript text outputing (bits) */
#define TX_STR 1			/* string started */
#define TX_ARR 2			/* glyph/string array started */
#define TX_EXT 4			/* glyph/string array needed */

/* width of characters according to the encoding */
/* these are the widths for Times-Roman, extracted from the 'a2ps' package */
/*fixme-hack: set 500 to control characters for utf-8*/
static short cw_tb[] = {
	500,500,500,500,500,500,500,500,
	500,500,500,500,500,500,500,500,
	500,500,500,500,500,500,500,500,
	500,500,500,500,500,500,500,500,
	250,333,408,500,500,833,778,333,
	333,333,500,564,250,564,250,278,
	500,500,500,500,500,500,500,500,
	500,500,278,278,564,564,564,444,
	921,722,667,667,722,611,556,722,
	722,333,389,722,611,889,722,722,
	556,722,667,556,611,722,722,944,
	722,722,611,333,278,333,469,500,
	333,444,500,444,500,444,333,500,
	500,278,278,500,278,778,500,500,
	500,500,333,389,278,500,500,722,
	500,500,444,480,200,480,541,500,
	500,500,500,500,500,500,500,500,
	500,500,500,500,500,500,500,500,
	500,500,500,500,500,500,500,500,
	500,500,500,500,500,500,500,500,
	250,333,500,500,500,500,200,500,
	333,760,276,500,564,333,760,333,
	400,564,300,300,333,500,453,350,
	333,278,310,500,750,750,750,444,
	722,722,722,722,722,722,889,667,
	611,611,611,611,333,333,333,333,
	722,722,722,722,722,722,722,564,
	722,722,722,722,722,722,556,500,
	444,444,444,444,444,444,667,444,
	444,444,444,444,278,278,278,278,
	500,500,500,500,500,500,500,564,
	500,500,500,500,500,500,500,500,
};

static struct u_ps {
	struct u_ps *next;
	char text[2];
} *user_ps;

/* -- print message for internal error and maybe stop -- */
void bug(char *msg, int fatal)
{
	error(1, NULL, "Internal error: %s.", msg);
	if (fatal) {
		fprintf(stderr, "Emergency stop.\n\n");
		exit(EXIT_FAILURE);
	}
	fprintf(stderr, "Trying to continue...\n");
}

/* -- print an error message -- */
void error(int sev,	/* 0: warning, 1: error */
	   struct SYMBOL *s,
	   char *fmt, ...)
{
	va_list args;
static struct SYMBOL *t;

	if (t != info['T' - 'A']) {
		char *p;

		t = info['T' - 'A'];
		p = &t->as.text[2];
		while (isspace((unsigned char) *p))
			p++;
		fprintf(stderr, "   - In tune '%s':\n", p);
	}
	fprintf(stderr, sev == 0 ? "Warning " : "Error ");
	if (s) {
		fprintf(stderr, "in line %d.%d",
			s->as.linenum, s->as.colnum);
		s->as.flags |= ABC_F_ERROR;
	}
	fprintf(stderr, ": ");
	va_start(args, fmt);
	vfprintf(stderr, fmt, args);
	va_end(args);
	fprintf(stderr, "\n");
	if (sev > severity)
		severity = sev;
}

/* -- read a number with a unit -- */
float scan_u(char *str)
{
	float a;
	int nch;

	if (sscanf(str, "%f%n", &a, &nch) == 1) {
		if (str[nch] == '\0' || str[nch] == ' ')
			return a PT;
		if (!strncasecmp(str + nch, "cm", 2))
			return a CM;
		if (!strncasecmp(str + nch, "in", 2))
			return a IN;
		if (!strncasecmp(str + nch, "pt", 2))
			return a PT;
	}
	error(1, NULL, "Unknown unit value \"%s\"", str);
	return 20 PT;
}

/* -- capitalize a string -- */
static void cap_str(char *p)
{
	while (*p != '\0') {
#if 1
/* pb with toupper - works with ASCII and some latin characters only */
		unsigned char c;

		c = (unsigned char) *p;
		if (c >= 'a' && c <= 'z') {
			*p = c & ~0x20;
		} else if (c == 0xc3) {
			p++;
			c = *p;
			if (c >= 0xa0 && c <= 0xbe && c != 0xb7)
				*p = c & ~0x20;
		} else if (c == 0xc4) {
			p++;
			c = *p;
			if (c >= 0x81 && c <= 0xb7 && (c & 0x01))
				(*p)--;
		}
#else
		*p = toupper((unsigned char) *p);
#endif
		p++;
	}
}

/* -- return the character width -- */
float cwid(unsigned short c)
{
	if (c > sizeof cw_tb / sizeof cw_tb[0])
		c = 'a';
	return (float) cw_tb[c] / 1000.;
}

/* -- change string taking care of some tex-style codes -- */
/* Return an estimated width of the string. */
float tex_str(char *s)
{
	char *d;
	signed char c1;
	unsigned maxlen, i;
	float w, swfac;

	w = 0;
	d = tex_buf;
	maxlen = sizeof tex_buf - 1;		/* have room for EOS */
	if ((i = curft) <= 0)
		i = defft;
	swfac = cfmt.font_tb[i].swfac;
	while ((c1 = *s++) != '\0') {
		switch (c1) {
		case '\\':
			c1 = *s++;
			if (c1 == '\0') {
				*d = '\0';
				return w;
			}
			switch (c1) {
			case 'n':
				c1 = '\n';
				break;
			case 't':
				c1 = '\t';
				break;
			}
			break;
		case '$':
			if (isdigit((unsigned char) *s)
			 && (unsigned) (*s - '0') < FONT_UMAX) {
				i = *s - '0';
				if (i == 0)
					i = defft;
				swfac = cfmt.font_tb[i].swfac;
				if (--maxlen <= 0)
					break;
				*d++ = c1;
				c1 = *s++;
				goto addchar_nowidth;
			}
			if (*s == '$') {
				if (--maxlen <= 0)
					break;
				*d++ = c1;
				s++;
			}
			break;
		case '&':
			if (*s == '#' && !svg && epsf != 2) {	/* XML char ref */
				int j;
				long v;

				if (s[1] == 'x')
					i = sscanf(s, "#x%lx;%n", &v, &j);
				else
					i = sscanf(s, "#%ld;%n", &v, &j);
				if (i != 1) {
					error(0, NULL, "Bad XML char reference");
					break;
				}
				if (v < 0x80) {	/* convert to UTF-8 */
					*d++ = v;
				} else if (v < 0x800) {
					*d++ = 0xc0 | (v >> 6);
					*d++ = 0x80 | (v & 0x3f);
				} else if (v < 0x10000) {
					*d++ = 0xe0 | (v >> 12);
					*d++ = 0x80 | ((v >> 6) & 0x3f);
					*d++ = 0x80 | (v & 0x3f);
				} else {
					*d++ = 0xf0 | (v >> 18);
					*d++ = 0x80 | ((v >> 12) & 0x3f);
					*d++ = 0x80 | ((v >> 6) & 0x3f);
					*d++ = 0x80 | (v & 0x3f);
				}
				s += j;
				continue;
			}
			break;
		}
		if (c1 < 0) {
			if ((c1 & 0xc0) == 0x80) {
				unsigned short unicode;

/*fixme: does not work with utf-8 on 3 characters*/
				unicode = ((d[-1] & 0x0f) << 6) | (c1 & 0x3f);
				w += cwid(unicode) * swfac;
			}
		} else if (c1 <= 5) {		/* accidentals from gchord */
			if (--maxlen < 4)
				break;
			switch (c1) {
			case 1:
				*d++ = 0xe2;
				*d++ = 0x99;
				*d++ = 0xaf;
				break;
			case 2:
				*d++ = 0xe2;
				*d++ = 0x99;
				*d++ = 0xad;
				break;
			case 3:
				*d++ = 0xe2;
				*d++ = 0x99;
				*d++ = 0xae;
				break;
			case 4:
				*d++ = 0xf0;
				*d++ = 0x9d;
				*d++ = 0x84;
				*d++ = 0xaa;
				break;
			case 5:
				*d++ = 0xf0;
				*d++ = 0x9d;
				*d++ = 0x84;
				*d++ = 0xab;
				break;
			}
			w += cwid('a') * swfac;
			continue;
		} else {
			w += cwid((unsigned short) c1) * swfac;
		}
	addchar_nowidth:
		if (--maxlen <= 0)
			break;
		*d++ = c1;
	}
	*d = '\0';
	if (maxlen <= 0)
		error(0, NULL, "Text too large - ignored part: '%s'", s);
	return w;
}

#ifdef HAVE_PANGO
#define PG_SCALE (PANGO_SCALE * 72 / 96)	/* 96 DPI */

static PangoFontDescription *desc_tb[MAXFONTS];
static PangoLayout *layout = (PangoLayout *) -1;
static PangoAttrList *attrs;
static int out_pg_ft = -1;		/* current pango font */
static GString *pg_str;

/* -- initialize the pango mechanism -- */
void pg_init(void)
{
	static PangoContext *context;

	context = pango_font_map_create_context(
			pango_cairo_font_map_get_default());
	if (context)
		layout = pango_layout_new(context);
	if (!layout) {
		error(0, NULL, "pango disabled\n");
		cfmt.pango = 0;
	} else {
		pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
//		pango_layout_set_spacing(layout, 0);
		pg_str = g_string_sized_new(256);
	}
}
void pg_reset_font(void)
{
	out_pg_ft = -1;
}

static void desc_font(int fnum)
{
	char font_name[128], *p;

	if (desc_tb[fnum] == 0) {
		p = font_name;
		sprintf(p, "%s 10", fontnames[fnum]);
		while (*p != '\0') {
			if (*p == '-')
				*p = ' ';
			p++;
		}
		desc_tb[fnum] = pango_font_description_from_string(font_name);
	}
}

/* output a line */
static void pg_line_output(PangoLayoutLine *line)
{
	GSList *runs_list;
	PangoGlyphInfo *glyph_info;
	char tmp[256];
	const char *fontname = NULL;
	int ret, glypharray;

	outft = -1;
	glypharray = 0;
	for (runs_list = line->runs; runs_list; runs_list = runs_list->next) {
		PangoLayoutRun *run = runs_list->data;
		PangoItem *item = run->item;
		PangoGlyphString *glyphs = run->glyphs;
		PangoAnalysis *analysis = &item->analysis;
		PangoFont *font = analysis->font;
		PangoFcFont *fc_font = PANGO_FC_FONT(font);
		FT_Face face = pango_fc_font_lock_face(fc_font);
		PangoFontDescription *ftdesc =
				pango_font_describe(font);
		int wi = pango_font_description_get_size(ftdesc);
		int i, c;

		if (pango_font_description_get_size(ftdesc) != wi) {
			wi = pango_font_description_get_size(ftdesc);
			fontname = NULL;
		}
		for (i = 0; i < glyphs->num_glyphs; i++) {
			glyph_info = &glyphs->glyphs[i];
			c = glyph_info->glyph;
			if (c == PANGO_GLYPH_EMPTY)
				continue;
			if (c & PANGO_GLYPH_UNKNOWN_FLAG) {
				c &= ~PANGO_GLYPH_UNKNOWN_FLAG;
				error(0, NULL, "char %04x not treated\n", c);
				continue;
			}

			ret = FT_Load_Glyph(face,
					c,		// PangoGlyph = index
					FT_LOAD_NO_SCALE);
			if (ret != 0) {
				error(0, NULL, "freetype error %d\n", ret);
			} else if (FT_HAS_GLYPH_NAMES(face)) {
				if (FT_Get_Postscript_Name(face) != fontname) {
					fontname = FT_Get_Postscript_Name(face);
					if (glypharray)
						a2b("]glypharray");
						a2b("\n");
					a2b("/%s %.1f selectfont[",
						fontname,
						(float) wi / PG_SCALE);
					glypharray = 1;
				}
				FT_Get_Glyph_Name((FT_FaceRec *) face, c,
						tmp, sizeof tmp);
				a2b("/%s", tmp);
			} else {
				a2b("%% glyph: %s %d\n",
					FT_Get_Postscript_Name(face), c);
			}
		}
		pango_fc_font_unlock_face(fc_font);
	}
	if (glypharray)
		a2b("]glypharray");
}

static void str_font_change(int start,
			int end)
{
	struct FONTSPEC *f;
	int fnum;
	PangoAttribute *attr1, *attr2;

	f = &cfmt.font_tb[curft];
	fnum = f->fnum;
	if (f->size == 0) {
		error(0, NULL, "Font \"%s\" with a null size - set to 8",
			fontnames[fnum]);
		f->size = 8;
	}
	desc_font(fnum);
	
	attr1 = pango_attr_font_desc_new(desc_tb[fnum]);
	attr1->start_index = start;
	attr1->end_index = end;
	pango_attr_list_insert(attrs, attr1);
	attr2 = pango_attr_size_new((int) (f->size * PG_SCALE));
	attr2->start_index = start;
	attr2->end_index = end;
	pango_attr_list_insert(attrs, attr2);
}

static void str_set_font(char *p)
{
	GString *str;
	char *q;
	int start;

	str = pg_str;
	start = str->len;
	q = p;
	while (*p != '\0') {
		switch (*p) {
		case '$':
			if (isdigit((unsigned char) p[1])
			 && (unsigned) (p[1] - '0') < FONT_UMAX) {
				if (p > q)
					str = g_string_append_len(str, q, p - q);
				if (curft != p[1] - '0') {
					str_font_change(start, str->len);
					start = str->len;
					curft = p[1] - '0';
					if (curft == 0)
						curft = defft;
				}
				p += 2;
				q = p;
				continue;
			}
			if (p[1] == '$') {
				str = g_string_append_len(str, q, p - q);
				q = ++p;
			}
			break;
		}
		p++;
	}
	if (p > q) {
		str = g_string_append_len(str, q, p - q);
		str_font_change(start, str->len);
	}
	pg_str = str;
}

/* -- output a string using the pango and freetype libraries -- */
static void str_pg_out(char *p, int action)
{
	PangoLayoutLine *line;
	int wi;
	float w;

//fixme: test
//a2b("\n%% t: '%s'\n", p);
	if (out_pg_ft != curft)
		out_pg_ft = -1;

	/* guitar chord with TABs */
	if (action == A_GCHEXP) {
		char *q;

		/* get the inter TAB width (see draw_gchord) */
		q = mbf - 1;
		while (q[-1] != ' ')
			q--;
		mbf = q;
		w = atof(q);
		for (;;) {
			q = strchr(p, '\t');
			if (!q)
				break;
			*q = '\0';
			str_pg_out(p, A_LEFT);
			a2b(" %.1f 0 RM ", w);
			p = q + 1;
		}
	}

	attrs = pango_attr_list_new();
	str_set_font(p);

	pango_layout_set_text(layout, pg_str->str, pg_str->len);
	pango_layout_set_attributes(layout, attrs);

	/* only one line */
	line = pango_layout_get_line_readonly(layout, 0);
	switch (action) {
	case A_CENTER:
	case A_RIGHT:
		pango_layout_get_size(layout, &wi, NULL);
		if (action == A_CENTER)
			wi /= 2;
//		w = (float) wi / PG_SCALE;
		w = (float) wi / PANGO_SCALE;
		a2b("-%.1f 0 RM ", w);
		break;
	}
	pg_line_output(line);
	pango_layout_set_attributes(layout, NULL);
	pg_str = g_string_truncate(pg_str, 0);
	pango_attr_list_unref(attrs);
}

/* output a justified or filled paragraph */
static void pg_para_output(int job)
{
	GSList *lines, *runs_list;
	PangoLayoutLine *line;
	PangoGlyphInfo *glyph_info;
	char tmp[256];
	const char *fontname = NULL;
	int ret, glypharray;
	int wi;
	float y;

	pango_layout_set_text(layout, pg_str->str,
			pg_str->len - 1);	/* remove the last space */
	pango_layout_set_attributes(layout, attrs);
	outft = -1;
	glypharray = 0;
	wi = 0;
	y = 0;
	lines = pango_layout_get_lines_readonly(layout);

	for (; lines; lines = lines->next) {
		PangoRectangle pos;

		line = lines->data;
		pango_layout_line_get_extents(line, NULL, &pos);
		y += (float) pos.height
				* .87		/* magic! */
				/ PANGO_SCALE;

		for (runs_list = line->runs; runs_list; runs_list = runs_list->next) {
			PangoLayoutRun *run = runs_list->data;
			PangoItem *item = run->item;
			PangoGlyphString *glyphs = run->glyphs;
			PangoAnalysis *analysis = &item->analysis;
			PangoFont *font = analysis->font;
			PangoFcFont *fc_font = PANGO_FC_FONT(font);
			FT_Face face = pango_fc_font_lock_face(fc_font);
			PangoFontDescription *ftdesc =
					pango_font_describe(font);
			int i, g, set_move, x;

			if (pango_font_description_get_size(ftdesc) != wi) {
				wi = pango_font_description_get_size(ftdesc);
				fontname = NULL;
			}
//printf("font size: %.2f\n", (float) wi / PG_SCALE);

			pango_layout_index_to_pos(layout, item->offset, &pos);
			x = pos.x;
			set_move = 1;
			for (i = 0; i < glyphs->num_glyphs; i++) {
				glyph_info = &glyphs->glyphs[i];
				g = glyph_info->glyph;
				if (g == PANGO_GLYPH_EMPTY)
					continue;
				if (set_move) {
					set_move = 0;
					if (glypharray) {
						a2b("]glypharray");
						glypharray = 0;
					}
					a2b("\n");
					a2b("%.2f %.2f M ",
						(float) x / PANGO_SCALE, -y);
				}
				x += glyph_info->geometry.width;
				if (g & PANGO_GLYPH_UNKNOWN_FLAG) {
					g &= ~PANGO_GLYPH_UNKNOWN_FLAG;
					error(0, NULL, "char %04x not treated\n", g);
					continue;
				}

				ret = FT_Load_Glyph(face,
						g,		// PangoGlyph = index
						FT_LOAD_NO_SCALE);
				if (ret != 0) {
					fprintf(stdout, "%%%% freetype error %d\n", ret);
				} else if (FT_HAS_GLYPH_NAMES(face)) {
					if (FT_Get_Postscript_Name(face) != fontname) {
						fontname = FT_Get_Postscript_Name(face);
						if (glypharray)
							a2b("]glypharray");
						a2b("\n/%s %.1f selectfont[",
							fontname,
							(float) wi / PG_SCALE);
						glypharray = 1;
					}
					FT_Get_Glyph_Name((FT_FaceRec *) face, g,
							tmp, sizeof tmp);
					if (job == T_JUSTIFY
					 && strcmp(tmp, "space") == 0) {
						set_move = 1;
						continue;
					}
					if (!glypharray) {
						a2b("[");
						glypharray = 1;
					}
					a2b("/%s", tmp);
				} else {
					a2b("%% glyph: %s %d\n",
						FT_Get_Postscript_Name(face), g);
				}
			}
			pango_fc_font_unlock_face(fc_font);
			if (glypharray) {
				a2b("]glypharray\n");
				glypharray = 0;
			}
		}
		if (glypharray) {
			a2b("]glypharray\n");
			glypharray = 0;
		}
	}
	bskip(y);
	pango_layout_set_attributes(layout, NULL);
	pg_str = g_string_truncate(pg_str, 0);
}

/* output of filled / justified text */
static void pg_write_text(char *s, int job, float parskip)
{
	char *p;

	curft = defft;
	pango_layout_set_width(layout, strlw * PANGO_SCALE);
	pango_layout_set_justify(layout, job == T_JUSTIFY);
	attrs = pango_attr_list_new();

	p = s;
	while (*p != '\0') {
		if (*p++ != '\n')
			continue;
		if (*p == '\n') {		/* if empty line */
			p[-1] = '\0';
			tex_str(s);
			str_set_font(tex_buf);
			if (pg_str->len > 0)
				pg_para_output(job);
			bskip(parskip);
			buffer_eob();
			s = ++p;
			continue;
		}
//fixme: maybe not useful
		p [-1] = ' ';
	}
	tex_str(s);
	str_set_font(tex_buf);
	if (pg_str->len)
		pg_para_output(job);
	pango_attr_list_unref(attrs);
}

/* check if pango is needed */
static int is_latin(unsigned char *p)
{
	while (*p != '\0') {
		if (*p >= 0xc6) {
			if (*p == 0xe2) {
				if (p[1] != 0x99
				 || p[2] < 0xad || p[2] > 0xaf)
					return 0;
				p += 2;
			} else if (*p == 0xf0) {
				if (p[1] != 0x9d
				 || p[2] != 0x84
				 || p[3] < 0xaa || p[3] > 0xab)
					return 0;
			} else {
				return 0;
			}
		}
		p++;
	}
	return 1;
}
#endif /* HAVE_PANGO */

/* -- set the default font of a string -- */
void str_font(int ft)
{
	curft = defft = ft;
}

/* -- get the current and default fonts -- */
void get_str_font(int *cft, int *dft)
{
	*cft = curft;
	*dft = defft;
}

/* -- set the current and default fonts -- */
void set_str_font(int cft, int dft)
{
	curft = cft;
	defft = dft;
}

/* close a string */
static void str_end(int end)
{
	if (strtx & TX_STR) {
		a2b(")");
		strtx &= ~TX_STR;
		if (!(strtx & TX_ARR))
			a2b("%s", strop);
	}
	if (!end || !(strtx & TX_ARR))
		return;
	strtx &= ~TX_ARR;
	a2b("]arrayshow");
}

/* check if some non ASCII characters */
static int non_ascii_p(char *p)
{
	while (*p != '\0') {
		if ((signed char) *p++ < 0)
			return 1;
	}
	return 0;
}

/* -- output one string -- */
static void str_ft_out1(char *p, int l)
{
	if (curft != outft) {
		str_end(1);
		a2b(" ");
		set_font(curft);
	}
	if (!(strtx & TX_STR)) {
		a2b("(");
		strtx |= TX_STR;
	}
	a2b("%.*s", l, p);
}

static char *strop_tb[] = {	/* index = action (A_xxxx) */
	"show",
	"showc",
	"showr",
	"lyshow",
	"gcshow",
	"anshow",
	"gxshow",
};

/* -- output a string and the font changes -- */
static void str_ft_out(char *p, int end)
{
	int use_glyph;
	char *q;

	use_glyph = !svg && epsf != 2 &&		/* not SVG */
		 get_font_encoding(curft) == 0;		/* utf-8 */
	if (use_glyph && non_ascii_p(p)) {
		if (curft != outft) {
			str_end(1);
			a2b(" ");
			set_font(curft);
		}
		str_end(0);
		if (!(strtx & TX_ARR)) {
			a2b("[");
			strtx |= TX_ARR;
		}
	}
	q = p;
	while (*p != '\0') {
		if ((unsigned char) *p >= 0x80
		 && use_glyph) {
			if (p > q) {
				str_ft_out1(q, p - q);
//			} else if (curft != outft) {
//				str_end(1);
//				a2b(" ");
//				set_font(curft);
			}
			str_end(0);
			if (!(strtx & TX_ARR)) {
				a2b("[");
				strtx |= TX_ARR;
			}
			q = p = glyph_out(p);
			continue;
		}
		switch ((unsigned char) *p) {
		case '$':
			if (isdigit((unsigned char) p[1])
			 && (unsigned) (p[1] - '0') < FONT_UMAX) {
				if (p > q)
					str_ft_out1(q, p - q);
				if (curft != p[1] - '0') {
					curft = p[1] - '0';
					if (curft == 0)
						curft = defft;
					use_glyph = !svg && epsf != 2 &&
						 get_font_encoding(curft) == 0;
				}
				p += 2;
				q = p;
				continue;
			}
			if (p[1] == '$') {
				str_ft_out1(q, p - q);
				q = ++p;
			}
			break;
		case '(':
		case ')':
		case '\\':
			if (p > q)
				str_ft_out1(q, p - q);
			str_ft_out1("\\", 1);
			q = p;
			break;
		}
		p++;
	}
	if (p > q)
		str_ft_out1(q, p - q);
	if (end && strtx)
		str_end(1);
}

/* -- output a string, handling the font changes -- */
void str_out(char *p, int action)
{
	if (curft <= 0)		/* first call */
		curft = defft;

	/* special case when font change at start of text */
	if (*p == '$' && isdigit((unsigned char) p[1])
	 && (unsigned) (p[1] - '0') < FONT_UMAX) {
		if (curft != p[1] - '0') {
			curft = p[1] - '0';
			if (curft == 0)
				curft = defft;
		}
		p += 2;
	}

#ifdef HAVE_PANGO
//fixme: pango KO if user modification of ly/gc/an/gxshow
	/* use pango if some characters are out of the utf-array (in syms.c) */
	if (cfmt.pango) {
		if (cfmt.pango == 2 || !is_latin((unsigned char *) p)) {
			str_pg_out(p, action);	/* output the string */
			return;
		}
	}
#endif

	/* direct output if no font change
	 * nor non ASCII characters */
	if (strchr(p, '$') == 0
	 && !non_ascii_p(p)) {
		strop = strop_tb[action];
		str_ft_out(p, 1);		/* output the string */
		return;
	}

	/* if not left aligned, build a PS function */
	switch (action) {
	case A_CENTER:
	case A_RIGHT:
		if (!svg && epsf != 2) {
			a2b("/str{");
			outft = -1;
			strop = "strop";
			break;
		}
		/* fall thru */
	default:
		strop = strop_tb[action];
		break;
	}

	str_ft_out(p, 1);		/* output the string */

	/* if not left aligned, call the PS function */
	if (svg || epsf == 2)
		return;
	if (action == A_CENTER || action == A_RIGHT) {
		a2b("}def\n"
			"strw w");
		if (action == A_CENTER)
			a2b(" 0.5 mul");
		a2b(" neg 0 RM str");
	}
}

/* -- output a string with TeX translation -- */
void put_str(char *str, int action)
{
	tex_str(str);
	str_out(tex_buf, action);
	a2b("\n");
}

/* -- output a header information -- */
static void put_inf(struct SYMBOL *s)
{
	char *p;

	p = s->as.text;
	if (p[1] == ':')
		p += 2;
	while (isspace((unsigned char) *p))
		p++;
	put_str(p, A_LEFT);
}

/* -- output a header format '111 (222)' -- */
static void put_inf2r(struct SYMBOL *s1,
			struct SYMBOL *s2,
			int action)
{
	char buf[256], *p, *q;

	if (!s1) {
		s1 = s2;
		s2 = NULL;
	}
	p = &s1->as.text[2];
	if (s1->as.text[0] == 'T')
		p = trim_title(p, s1);
	if (s2) {
		buf[sizeof buf - 1] = '\0';
		strncpy(buf, p, sizeof buf - 1);
		q = buf + strlen(buf);
		if (q < buf + sizeof buf - 4) {
			*q++ = ' ';
			*q++ = '(';
			p = &s2->as.text[2];
			strncpy(q, p, buf + sizeof buf - 2 - q);
			q += strlen(q);
			*q++ = ')';
			*q = '\0';
		}
		p = buf;
	}
	put_str(p, action);
}

/* -- write a text block (%%begintext / %%text / %%center) -- */
void write_text(char *cmd, char *s, int job)
{
	int nw;
#ifdef HAVE_PANGO
	int do_pango;
#endif
	float lineskip, parskip, strw;
	char *p;
	struct FONTSPEC *f;

	str_font(TEXTFONT);
	strlw = ((cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth)
		- cfmt.leftmargin - cfmt.rightmargin) / cfmt.scale;

	f = &cfmt.font_tb[TEXTFONT];
	lineskip = f->size * cfmt.lineskipfac;
	parskip = f->size * cfmt.parskipfac;

	/* follow lines */
	switch (job) {
	case T_LEFT:
	case T_CENTER:
	case T_RIGHT:
		switch (job) {
		case T_LEFT:
#if T_LEFT != A_LEFT
			job = A_LEFT;
#endif
			break;
		case T_CENTER:
#if T_CENTER != A_CENTER
			job = A_CENTER;
#endif
			break;
		default:
#if T_RIGHT != A_RIGHT
			job = A_RIGHT;
#endif
			break;
		}
		while (*s != '\0') {
			p = s;
			while (*p != '\0' && *p != '\n')
				p++;
			if (*p != '\0')
				*p++ = '\0';
			if (*s == '\0') {
				bskip(parskip);
				buffer_eob();
			} else {
				bskip(lineskip);
				switch (job) {
				case A_LEFT:
					a2b("0 0 M");
					break;
				case A_CENTER:
					a2b("%.1f 0 M", strlw * 0.5);
					break;
				default:
					a2b("%.1f 0 M", strlw);
					break;
				}
				put_str(s, job);
			}
			s = p;
		}
		goto skip;
	}

	/* fill or justify lines */
#ifdef HAVE_PANGO
	do_pango = cfmt.pango;
	if (do_pango == 1)
		do_pango = !is_latin((unsigned char *) s);
	if (do_pango) {
		pg_write_text(s, job, parskip);
		goto skip;
	}
#endif
//	curft = defft;
	nw = 0;					/* number of words */
	strw = 0;				/* have gcc happy */
	while (*s != '\0') {
		float lw;

		if (nw == 0) {			/* if new paragraph */
			bskip(lineskip);
			a2b("0 0 M");
			if (job == T_FILL) {
				strop = "show";
			} else {
				a2b("/str{");
				outft = -1;
				strop = "strop";
			}
			strw = 0;		/* current line width */
		}
		if (*s == '\n') {		/* empty line */
			if (strtx) {
				str_end(1);
				if (job == T_JUSTIFY)
					a2b("}def\n"
					    "/strop/show load def str");
			}
			a2b("\n");
			bskip(parskip);
			buffer_eob();
			nw = 0;
			while (isspace((unsigned char) *s))
				s++;
			continue;
		}

		/* get a word */
		p = s;
		while (*p != '\0' && !isspace((unsigned char) *p))
			p++;
		if (*p != '\0') {
			char *q;

			q = p;
			if (*p != '\n') {
				do {
					p++;
				} while (*p != '\n' && isspace((unsigned char) *p));
			}
			if (*p == '\n')
				p++;
			*q = '\0';
		}

		lw = tex_str(s);
		if (strw + lw > strlw) {
			str_end(1);
			if (job == T_JUSTIFY) {
				int n;

				n = nw - 1;
				if (n <= 0)
					n = 1;
				if (svg || epsf == 2)
					a2b("}def\n"
						"%.1f jshow"
						"/strop/show load def str",
						strlw);
				else
					a2b("}def\n"
						"strw"
						"/w %.1f w sub %d div def"
						"/strop/jshow load def str",
						strlw, n);
			}
			a2b("\n");
			bskip(lineskip);
			a2b("0 0 M");
			if (job == T_JUSTIFY) {
				a2b("/str{");
				outft = -1;
			}
			nw = 0;
			strw = 0;
		}

		if (nw != 0) {
			str_ft_out1(" ", 1);
			strw += cwid(' ') * cfmt.font_tb[curft].swfac;
		}
		str_ft_out(tex_buf, 0);
		strw += lw;
		nw++;

		s = p;
	}
	if (strtx) {
		str_end(1);
		if (job == T_JUSTIFY)
			a2b("}def\n"
				"/strop/show load def str");
	}
//	if (mbf[-1] != '\n')
		a2b("\n");
skip:
	bskip(parskip);
	buffer_eob();
}

/* -- output a line of words after tune -- */
static int put_wline(char *p,
			float x,
			int right)
{
	char *q, *r, sep;

	while (isspace((unsigned char) *p))
		p++;
	if (*p == '$' && isdigit((unsigned char) p[1])
	 && (unsigned) (p[1] - '0') < FONT_UMAX) {
		if (curft != p[1] - '0') {
			curft = p[1] - '0';
			if (curft == 0)
				curft = defft;
		}
		p += 2;
	}
	r = 0;
	q = p;
	if (isdigit((unsigned char) *p) || p[1] == '.') {
		while (*p != '\0') {
			p++;
			if (*p == ' '
			 || p[-1] == ':'
			 || p[-1] == '.')
				break;
		}
		r = p;
		while (*p == ' ')
			p++;
	}

	if (r != 0) {
		sep = *r;
		*r = '\0';
		a2b("%.1f 0 M", x);
		put_str(q,  A_RIGHT);
		*r = sep;
	}
	if (*p != '\0') {
		a2b("%.1f 0 M", x + 5);
		put_str(p, A_LEFT);
	}
	return *p == '\0' && r == 0;
}

/* -- output the words after tune -- */
void put_words(struct SYMBOL *words)
{
	struct SYMBOL *s, *s_end, *s2;
	char *p;
	int i, n, have_text, max2col;
	float middle;

	buffer_eob();
	str_font(WORDSFONT);

	/* see if we may have 2 columns */
	middle = 0.5 * ((cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth)
		- cfmt.leftmargin - cfmt.rightmargin) / cfmt.scale;
	max2col = (int) ((middle - 45.) / (cwid('a') * cfmt.font_tb[WORDSFONT].swfac));
	n = 0;
	have_text = 0;
	for (s = words; s != 0; s = s->next) {
		p = &s->as.text[2];
/*fixme:utf8*/
		if ((int) strlen(p) > max2col) {
			n = 0;
			break;
		}
		if (*p == '\0') {
			if (have_text) {
				n++;
				have_text = 0;
			}
		} else {
			have_text = 1;
		}
	}
	if (n > 0) {
		n++;
		n /= 2;
		i = n;
		have_text = 0;
		s_end = words;
		for (;;) {
			p = &s_end->as.text[2];
			while (isspace((unsigned char) *p))
				p++;
			if (*p == '\0') {
				if (have_text && --i <= 0)
					break;
				have_text = 0;
			} else {
				have_text = 1;
			}
			s_end = s_end->next;
		}
		s2 = s_end->next;
	} else {
		s_end = 0;
		s2 = 0;
	}

	/* output the text */
	bskip(cfmt.wordsspace);
	for (s = words; s != 0 || s2 != 0; ) {
//fixme:should also permit page break on stanza start
		if (s && s->as.text[2] == '\0')
			buffer_eob();
		bskip(cfmt.lineskipfac * cfmt.font_tb[WORDSFONT].size);
		if (s) {
			put_wline(&s->as.text[2], 45., 0);
			s = s->next;
			if (s == s_end)
				s = NULL;
		}
		if (s2) {
			if (put_wline(&s2->as.text[2], 20. + middle, 1)) {
				if (--n == 0) {
					if (s) {
						n++;
					} else if (s2->next) {

						/* center the last words */
/*fixme: should compute the width average.. */
						middle *= 0.6;
					}
				}
			}
			s2 = s2->next;
		}
	}
//	buffer_eob();
}

/* -- output history -- */
void put_history(void)
{
	struct SYMBOL *s, *s2;
	int font;
	unsigned u;
	float w, h;
	char tmp[265];

	font = 0;
	for (s = info['I' - 'A']; s; s = s->next) {
		u = s->as.text[0] - 'A';
		if (!(cfmt.fields[0] & (1 << u))
		 || (s2 = info[u]) == NULL)
			continue;
		if (!font) {
			bskip(cfmt.textspace);
			str_font(HISTORYFONT);
			font = 1;
		}
		get_str(tmp, &s->as.text[1], sizeof tmp);
		w = tex_str(tmp);
		h = cfmt.font_tb[HISTORYFONT].size * cfmt.lineskipfac;
		set_font(HISTORYFONT);
		a2b("0 0 M(%s)show ", tex_buf);
		for (;;) {
			put_inf(s2);
			if ((s2 = s2->next) == NULL)
				break;
			bskip(h);
			a2b("%.2f 0 M ", w);
		}
		bskip(h * 1.2);
		buffer_eob();
	}
}

/* -- move trailing "The" to front, set to uppercase letters or add xref -- */
char *trim_title(char *p, struct SYMBOL *title)
{
	char *b, *q, *r;
static char buf[STRL1];

	q = NULL;
	if (cfmt.titletrim) {
		q = strrchr(p, ',');
		if (q) {
			if (q[1] != ' ' || !isupper((unsigned char) q[2])
			 || strlen(q) > 7	/* word no more than 4 characters */
			 || strchr(q + 2, ' '))
				q = NULL;
		}
	}
	if (title != info['T' - 'A']
	 || !(cfmt.fields[0] & (1 << ('X' - 'A'))))
		title = NULL;
	if (!q
	 && !title
	 && !cfmt.titlecaps)
		return p;		/* keep the title as it is */
	b = buf;
	r = &info['X' - 'A']->as.text[2];
	if (title
	 && *r != '\0') {
		if (strlen(p) + strlen(r) + 3 >= sizeof buf) {
			error(1, NULL, "Title or X: too long");
			return p;
		}
		b += sprintf(b, "%s.  ", r);
	} else {
		if (strlen(p) >= sizeof buf) {
			error(1, NULL, "Title too long");
			return p;
		}
	}
	if (q)
		sprintf(b, "%s %.*s", q + 2, (int) (q - p), p);
	else
		strcpy(b, p);
	if (cfmt.titlecaps)
		cap_str(buf);
	return buf;
}

/* -- write a title -- */
void write_title(struct SYMBOL *s)
{
	char *p;
	float sz;

	p = &s->as.text[2];
	if (*p == '\0')
		return;
	if (s == info['T' - 'A']) {
		sz = cfmt.font_tb[TITLEFONT].size;
		bskip(cfmt.titlespace + sz);
		str_font(TITLEFONT);
		a2b("%% --- title");
	} else {
		sz = cfmt.font_tb[SUBTITLEFONT].size;
		bskip(cfmt.subtitlespace + sz);
		str_font(SUBTITLEFONT);
		a2b("%% --- titlesub");
	}
	a2b(" %s\n", p);
	if (cfmt.titleleft)
		a2b("0");
	else
		a2b("%.1f",
		     0.5 * ((cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth)
			- cfmt.leftmargin - cfmt.rightmargin) / cfmt.scale);
	a2b(" %.1f M ", sz * 0.2);
	p = trim_title(p, s);
	put_str(p, cfmt.titleleft ? A_LEFT : A_CENTER);
}

/* -- write heading with format -- */
static void write_headform(float lwidth)
{
	char *p, *q;
	struct SYMBOL *s;
	struct FONTSPEC *f;
	int align, i;
	unsigned j;
	float x, y, xa[3], ya[3], sz, yb[3];	/* !! see action A_xxx */
	char inf_nb[26];
	INFO inf_s;
	char inf_ft[26];
	float inf_sz[26];
	char fmt[64];

	memset(inf_nb, 0, sizeof inf_nb);
	memset(inf_ft, HISTORYFONT, sizeof inf_ft);
	inf_ft['A' - 'A'] = INFOFONT;
	inf_ft['C' - 'A'] = COMPOSERFONT;
	inf_ft['O' - 'A'] = COMPOSERFONT;
	inf_ft['P' - 'A'] = PARTSFONT;
	inf_ft['Q' - 'A'] = TEMPOFONT;
	inf_ft['R' - 'A'] = INFOFONT;
	inf_ft['T' - 'A'] = TITLEFONT;
	inf_ft['X' - 'A'] = TITLEFONT;
	memcpy(inf_s, info, sizeof inf_s);
	memset(inf_sz, 0, sizeof inf_sz);
	inf_sz['A' - 'A'] = cfmt.infospace;
	inf_sz['C' - 'A'] = cfmt.composerspace;
	inf_sz['O' - 'A'] = cfmt.composerspace;
	inf_sz['R' - 'A'] = cfmt.infospace;
	p = cfmt.titleformat;
	j = 0;
	for (;;) {
		while (isspace((unsigned char) *p))
			p++;
		if (*p == '\0')
			break;
		i = *p - 'A';
		if ((unsigned) i < 26) {
			inf_nb[i]++;
			switch (p[1]) {
			default:
				align = A_CENTER;
				break;
			case '1':
				align = A_RIGHT;
				p++;
				break;
			case '-':
				align = A_LEFT;
				p++;
				break;
			}
			if (j < sizeof fmt - 4) {
				fmt[j++] = i;
				fmt[j++] = align;
			}
		} else if (*p == ',') {
			if (j < sizeof fmt - 3)
				fmt[j++] = 126;		/* next line */
		} else if (*p == '+') {
			if (j > 0 && fmt[j - 1] < 125
			 && j < sizeof fmt - 4) {
				fmt[j++] = 125;		/* concatenate */
				fmt[j++] = 0;
			}
/*new fixme: add free text "..." ?*/
		}
		p++;
	}
	fmt[j++] = 126;			/* newline */
	fmt[j] = 127;			/* end of format */

	ya[0] = ya[1] = ya[2] = cfmt.titlespace;
	xa[0] = 0;
	xa[1] = lwidth * 0.5;
	xa[2] = lwidth;

	p = fmt;
	for (;;) {
		yb[0] = yb[1] = yb[2] = y = 0;
		q = p;
		for (;;) {
			i = *q++;
			if (i >= 126)		/* if newline */
				break;
			align = *q++;
			if (yb[align] != 0
			 || i == 125)
				continue;
			s = inf_s[i];
			if (s == 0 || inf_nb[i] == 0)
				continue;
			j = inf_ft[i];
			f = &cfmt.font_tb[j];
			sz = f->size * 1.1 + inf_sz[i];
			if (y < sz)
				y = sz;
			yb[align] = sz;
/*fixme:should count the height of the concatenated field*/
		}
		for (i = 0; i < 3; i++)
			ya[i] += y - yb[i];
		for (;;) {
			i = *p++;
			if (i >= 126)		/* if newline */
				break;
			align = *p++;
			if (i == 125)
				continue;
			s = inf_s[i];
			if (!s || inf_nb[i] == 0)
				continue;
			j = inf_ft[i];
			str_font(j);
			x = xa[align];
			f = &cfmt.font_tb[j];
			sz = f->size * 1.1 + inf_sz[i];
			y = ya[align] + sz;
			if (s->as.text[2] != '\0') {
				if (i == 'T' - 'A') {
					if (s == info['T' - 'A'])
						a2b("%% --- title");
					else
						a2b("%% --- titlesub");
					a2b(" %s\n", &s->as.text[2]);
				}
				a2b("%.1f %.1f M ", x, -y);
			}
			if (*p == 125) {	/* concatenate */
			    p += 2;
/*fixme: do it work with different fields*/
			    if (*p == i && p[1] == align
			     && s->next) {
				char buf[256], *r;

				q = s->as.text;
				if (q[1] == ':')
					q += 2;
				while (isspace((unsigned char) *q))
					q++;
				if (i == 'T' - 'A')
					q = trim_title(q, s);
				strncpy(buf, q, sizeof buf - 1);
				buf[sizeof buf - 1] = '\0';
				j = strlen(buf);
				if (j < sizeof buf - 1) {
					buf[j] = ' ';
					buf[j + 1] = '\0';
				}
				s = s->next;
				q = s->as.text;
				if (q[1] == ':')
					q += 2;
				while (isspace((unsigned char) *q))
					q++;
				if (s->as.text[0] == 'T' && s->as.text[1] == ':')
					q = trim_title(q, s);
				r = buf + strlen(buf);
				strncpy(r, q, buf + sizeof buf - r - 1);
				tex_str(buf);
				str_out(tex_buf, align);
				a2b("\n");
				inf_nb[i]--;
				p += 2;
			    } else {
				put_inf2r(s, NULL, align);
			    }
			} else if (i == 'Q' - 'A') {	/* special case for tempo */
				if (align != A_LEFT) {
					float w;

					w = -tempo_width(s);
					if (align == A_CENTER)
						w *= 0.5;
					a2b("%.1f 0 RM ", w);
				}
				write_tempo(s, 0, 0.75);
				info['Q' - 'A'] = NULL;	/* don't display in tune */
			} else {
				put_inf2r(s, NULL, align);
			}
			if (inf_s[i] == info['T' - 'A']) {
				inf_ft[i] = SUBTITLEFONT;
				str_font(SUBTITLEFONT);
				f = &cfmt.font_tb[SUBTITLEFONT];
				inf_sz[i] = cfmt.subtitlespace;
				sz = f->size * 1.1 + inf_sz[i];
			}
			s = s->next;
			if (inf_nb[i] == 1) {
				while (s) {
					y += sz;
					a2b("%.1f %.1f M ", x, -y);
					put_inf2r(s, 0, align);
					s = s->next;
				}
			}
			inf_s[i] = s;
			inf_nb[i]--;
			ya[align] = y;
		}
		if (ya[1] > ya[0])
			ya[0] = ya[1];
		if (ya[2] > ya[0])
			ya[0] = ya[2];
		if (*p == 127) {
			bskip(ya[0]);
			break;
		}
		ya[1] = ya[2] = ya[0];
	}
}

/* -- output the tune heading -- */
void write_heading(struct abctune *t)
{
	struct SYMBOL *s, *rhythm, *area, *author, *composer, *origin;
	float lwidth, down1, down2;

	lwidth = ((cfmt.landscape ? cfmt.pageheight : cfmt.pagewidth)
		- cfmt.leftmargin - cfmt.rightmargin) / cfmt.scale;

	if (cfmt.titleformat && cfmt.titleformat[0] != '\0') {
		write_headform(lwidth);
		bskip(cfmt.musicspace);
		return;
	}

	/* titles */
	if (cfmt.fields[0] & (1 << ('T' - 'A'))) {
		for (s = info['T' - 'A']; s; s = s->next)
			write_title(s);
	}

	/* rhythm, composer, origin */
	down1 = cfmt.composerspace + cfmt.font_tb[COMPOSERFONT].size;
	rhythm = (first_voice->key.mode >= BAGPIPE
			&& !cfmt.infoline
			&& (cfmt.fields[0] & (1 << ('R' - 'A'))))
					? info['R' - 'A'] : NULL;
	if (rhythm) {
		str_font(COMPOSERFONT);
		a2b("0 %.1f M ",
		     -(cfmt.composerspace + cfmt.font_tb[COMPOSERFONT].size));
		put_inf(rhythm);
		down1 -= cfmt.font_tb[COMPOSERFONT].size;
	}
	area = author = NULL;
	if (t->abc_vers != (2 << 16))
		area = info['A' - 'A'];
	else
		author = info['A' - 'A'];
	composer = (cfmt.fields[0] & (1 << ('C' - 'A'))) ? info['C' - 'A'] : NULL;
	origin = (cfmt.fields[0] & (1 << ('O' - 'A'))) ? info['O' - 'A'] : NULL;
	if (composer || origin || author || cfmt.infoline) {
		float xcomp;
		int align;

		str_font(COMPOSERFONT);
		bskip(cfmt.composerspace);
		if (cfmt.aligncomposer < 0) {
			xcomp = 0;
			align = A_LEFT;
		} else if (cfmt.aligncomposer == 0) {
			xcomp = lwidth * 0.5;
			align = A_CENTER;
		} else {
			xcomp = lwidth;
			align = A_RIGHT;
		}
		down2 = down1;
		if (author) {
			for (;;) {
				bskip(cfmt.font_tb[COMPOSERFONT].size);
				down2 += cfmt.font_tb[COMPOSERFONT].size;
				a2b("0 0 M ");
				put_inf(author);
				if ((author = author->next) == NULL)
					break;
			}
		}
		if (composer || origin) {
			if (cfmt.aligncomposer >= 0
			 && down1 != down2)
				bskip(down1 - down2);
			s = composer;
			for (;;) {
				bskip(cfmt.font_tb[COMPOSERFONT].size);
				a2b("%.1f 0 M ", xcomp);
				put_inf2r(s,
					  (!s || !s->next) ? origin : NULL,
					  align);
				if (!s)
					break;
				if ((s = s->next) == NULL)
					break;
				down1 += cfmt.font_tb[COMPOSERFONT].size;
			}
			if (down2 > down1)
				bskip(down2 - down1);
		}

		rhythm = rhythm ? NULL : info['R' - 'A'];
		if ((rhythm || area) && cfmt.infoline) {

			/* if only one of rhythm or area then do not use ()'s
			 * otherwise output 'rhythm (area)' */
			str_font(INFOFONT);
			bskip(cfmt.font_tb[INFOFONT].size + cfmt.infospace);
			a2b("%.1f 0 M ", lwidth);
			put_inf2r(rhythm, area, A_RIGHT);
			down1 += cfmt.font_tb[INFOFONT].size + cfmt.infospace;
		}
		down2 = 0;
	} else {
		down2 = cfmt.composerspace + cfmt.font_tb[COMPOSERFONT].size;
	}

	/* parts */
	if (info['P' - 'A']
	 && (cfmt.fields[0] & (1 << ('P' - 'A')))) {
		down1 = cfmt.partsspace + cfmt.font_tb[PARTSFONT].size - down1;
		if (down1 > 0)
			down2 += down1;
		if (down2 > 0.01)
			bskip(down2);
		str_font(PARTSFONT);
		a2b("0 0 M ");
		put_inf(info['P' - 'A']);
		down2 = 0;
	}
	bskip(down2 + cfmt.musicspace);
}

/* -- memorize a PS / SVG line -- */
/* 'use' may be:
 *	'g': SVG code
 *	'p': PS code for PS output only
 *	's': PS code for SVG output only
 *	'b': PS code for PS or SVG output
 */
void user_ps_add(char *s, char use)
{
	struct u_ps *t, *r;
	int l;

	if (*s == '\0' || *s == '%')
		return;
	l = strlen(s);
	if (use == 'g') {
		t = malloc(sizeof *user_ps - sizeof user_ps->text + l + 6);
		sprintf(t->text, "%%svg %s", s);
	} else {
		t = malloc(sizeof *user_ps - sizeof user_ps->text + l + 2);
		sprintf(t->text, "%c%s", use, s);
	}
	t->next = NULL;
	if ((r = user_ps) == NULL) {
		user_ps = t;
	} else {
		while (r->next)
			r = r->next;
		r->next = t;
	}
}

/* -- output the user defined postscript sequences -- */
void user_ps_write(void)
{
	struct u_ps *t;
	char *p;

	for (t = user_ps; t; t = t->next) {
		p = t->text;
		switch (*p) {
		case '\001': {		/* PS file */
			FILE *f;
			char line[BSIZE];

			if ((f = fopen(p + 1, "r")) == NULL) {
				error(1, NULL, "Cannot open PS file '%s'",
					&t->text[1]);
			} else {
				while (fgets(line, sizeof line, f))	/* copy the file */
					fputs(line, fout);
				fclose(f);
			}
			continue;
		    }
		case '%':		/* "%svg " = SVG code */
//			if (svg || epsf == 2)
//				svg_write(t->text, strlen(t->text));
			fputs(p + 5, fout);
			fputc('\n', fout);
			continue;
		case 'p':		/* PS code for PS output only */
//			if (secure || svg || epsf == 2)
//				continue;
			break;
		case 'b':		/* PS code for both PS and SVG */
			if (svg || epsf == 2) {
				svg_write(p + 1, strlen(p + 1));
				continue;
			}
//			if (secure)
//				continue;
			break;
		case 's':		/* PS code for SVG output only */
//			if (!svg && epsf != 2)
//				continue;
			svg_write(p + 1, strlen(&t->text[1]));
			continue;
		}
		fputs(p + 1, fout);
		fputc('\n', fout);
	}
}
abcm2ps-7.8.13/svg.c0000644000175000017500000026535612444275630012226 0ustar  jefjef/*
 * SVG definitions.
 *
 * This file is part of abcm2ps.
 *
 * Copyright (C) 1998-2014 Jean-François Moine
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 */

#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

#include "abc2ps.h"

enum elt_t {			/* element types */
	VAL,
	STR,
	SEQ,			/* {..} */
	BRK,			/* [..] */
};
struct elt_s {
	struct elt_s *next;
	char type;
	union {
		float v;
		char *s;
		struct elt_s *e;
	} u;
};
struct ps_sym_s {
	char *n;		/* name */
	struct elt_s *e;	/* value */
	int exec;		/* current number of execution */
};
/* -- PostScript tiny interpreter -- */
//jfm test
#define NELTS 2048	/* number of elements per block */
//#define NSYMS 128	/* max number of symbols */
#define NSYMS 512	/* max number of symbols */
static struct elt_s *elts;
static struct elt_s *stack, *free_elt;
static struct ps_sym_s ps_sym[NSYMS];
static int n_sym;
static int ps_error;
static int in_cnt;			/* in [..] or {..} */
static float cx, cy;			/* current point */
static char *path;
static char path_buf[256];

static float xoffs, yoffs;

/* graphical context */
#define DLW 0.7			/* default line width */
static struct gc {
	float xscale, yscale;
	char font_n[64];
	float font_s;
	float linewidth, rotate;
	int rgb;
	char dash[64];
} gcur, gold;
static float x_rot, y_rot;	/* save x and y offset when rotate != 0 */
static struct {
	struct gc gc;
	float cx, cy;
	float xoffs, yoffs;
	float x_rot, y_rot;
} gsave[8];
static int nsave;
static int g;			/* current container */
static int boxend;

/* abcm2ps definitions */
static struct {
	char *def;
	char use;
	char defined;
} def_tb[] = {
#define D_brace 0
{	"<path id=\"brace\" fill=\"currentColor\" d=\"m-2.5 101\n"
	"	c-4.5 -4.6 -7.5 -12.2 -4.4 -26.8\n"
	"	c3.5 -14.3 3.2 -21.7 -2.1 -24.2\n"
	"	c7.4 2.4 7.3 14.2 3.5 29.5\n"
	"	c-2.7 9.5 -1.5 16.2 3 21.5\n"
	"	M-2.5 1c-4.5 4.6 -7.5 12.2 -4.4 26.8\n"
	"	c3.5 14.3 3.2 21.7 -2.1 24.2\n"
	"	c7.4 -2.4 7.3 -14.2 3.5 -29.5\n"
	"	c-2.7 -9.5 -1.5 -16.2 3 -21.5\"/>\n"},
#define D_utclef 1
{	"<path id=\"utclef\" fill=\"currentColor\" d=\"m-50 -90\n"
	"	c-72 -41 -72 -158 52 -188\n"
	"	c150 -10 220 188 90 256\n"
	"	c-114 52 -275 0 -293 -136\n"
	"	c-15 -181 93 -229 220 -334\n"
	"	c88 -87 79 -133 62 -210\n"
	"	c-51 33 -94 105 -89 186\n"
	"	c17 267 36 374 49 574\n"
	"	c6 96 -19 134 -77 135\n"
	"	c-80 1 -126 -93 -61 -133\n"
	"	c85 -41 133 101 31 105\n"
	"	c23 17 92 37 90 -92\n"
	"	c-10 -223 -39 -342 -50 -617\n"
	"	c0 -90 0 -162 96 -232\n"
	"	c56 72 63 230 22 289\n"
	"	c-74 106 -257 168 -255 316\n"
	"	c9 153 148 185 252 133\n"
	"	c86 -65 29 -192 -80 -176\n"
	"	c-71 12 -105 67 -59 124\"/>\n"},
#define D_tclef 2
{	"<use id=\"tclef\" transform=\"scale(0.045)\"\n"
	"	xlink:href=\"#utclef\"/>\n", D_utclef},
#define D_stclef 3
{	"<use id=\"stclef\" transform=\"translate(0,-0.6) scale(0.037)\"\n"
	"	xlink:href=\"#utclef\"/>\n", D_utclef},
#define D_ubclef 4
{	"<path id=\"ubclef\" fill=\"currentColor\" d=\"m-200 -87\n"
	"	c124 -35 222 -78 254 -236\n"
	"	c43 -228 -167 -246 -192 -103\n"
	"	c59 -80 157 22 92 78\n"
	"	c-62 47 -115 -22 -106 -88\n"
	"	c21 -141 270 -136 274 52\n"
	"	c-1 175 -106 264 -322 297\n"
	"	m357 -250\n"
	"	c0 -36 51 -34 51 0\n"
	"	c0 37 -51 36 -51 0\n"
	"	m-2 -129\n"
	"	c0 -36 51 -34 51 0\n"
	"	c0 38 -51 37 -51 0\"/>\n"},
#define D_bclef 5
{	"<use id=\"bclef\" transform=\"scale(0.045)\"\n"
	"	xlink:href=\"#ubclef\"/>\n", D_ubclef},
#define D_sbclef 6
{	"<use id=\"sbclef\" transform=\"translate(0,-3.5) scale(0.037)\"\n"
	"	xlink:href=\"#ubclef\"/>\n", D_ubclef},
#define D_ucclef 7
{	"<path id=\"ucclef\" fill=\"currentColor\" d=\"\n"
	"	m-51 -264\n"
	"	v262\n"
	"	h-13\n"
	"	v-529\n"
	"	h13\n"
	"	v256\n"
	"	c25 -20 41 -36 63 -109\n"
	"	c14 31 13 51 56 70\n"
	"	c90 34 96 -266 -41 -185\n"
	"	c52 19 27 80 -11 77\n"
	"	c-90 -38 33 -176 139 -69\n"
	"	c72 79 1 241 -134 186\n"
	"	l-16 39 16 38\n"
	"	c135 -55 206 107 134 186\n"
	"	c-106 108 -229 -31 -139 -69\n"
	"	c38 -3 63 58 11 77\n"
	"	c137 81 131 -219 41 -185\n"
	"	c-43 19 -45 30 -56 64\n"
	"	c-22 -73 -38 -89 -63 -109\n"
	"	m-99 -267\n"
	"	h57\n"
	"	v529\n"
	"	h-57\n"
	"	v-529\"/>\n"},
#define D_cclef 8
{	"<use id=\"cclef\" transform=\"scale(0.045)\"\n"
	"	xlink:href=\"#ucclef\"/>\n", D_ucclef},
#define D_scclef 9
{	"<use id=\"scclef\" transform=\"translate(0,-2) scale(0.037)\"\n"
	"	xlink:href=\"#ucclef\"/>\n", D_ucclef},
#define D_pclef 10
{	"<path id=\"pclef\" d=\"m-2.7 -2h5.4v-20h-5.4v20\" stroke=\"currentColor\" fill=\"none\" stroke-width=\"1.4\"/>\n"},
#define D_hd 11
{	"<ellipse id=\"hd\" rx=\"4.1\" ry=\"2.9\"\n"
	"	transform=\"rotate(-20)\" fill=\"currentColor\"/>\n"},
#define D_Hd 12
{	"<path id=\"Hd\" fill=\"currentColor\" d=\"m3 -1.6\n"
	"	c-1 -1.8 -7 1.4 -6 3.2\n"
	"	c1 1.8 7 -1.4 6 -3.2\n"
	"	m0.5 -0.3\n"
	"	c2 3.8 -5 7.6 -7 3.8\n"
	"	c-2 -3.8 5 -7.6 7 -3.8\"/>\n"},
#define D_HD 13
{	"<path id=\"HD\" fill=\"currentColor\" d=\"m-2.7 -1.4\n"
	"	c1.5 -2.8 6.9 0 5.3 2.7\n"
	"	c-1.5 2.8 -6.9 0 -5.3 -2.7\n"
	"	m8.3 1.4\n"
	"	c0 -1.5 -2.2 -3 -5.6 -3\n"
	"	c-3.4 0 -5.6 1.5 -5.6 3\n"
	"	c0 1.5 2.2 3 5.6 3\n"
	"	c3.4 0 5.6 -1.5 5.6 -3\"/>\n"},
#define D_HDD 14
{	"<g id=\"HDD\">\n"
	"	<use xlink:href=\"#HD\"/>\n"
	"	<path d=\"m-6 -4v8m12 0v-8\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"</g>\n", D_HD},
#define D_breve 15
{	"<g id=\"breve\" stroke=\"currentColor\" fill=\"none\">\n"
	"	<path d=\"m-6 -2.7h12m0 5.4h-12\" stroke-width=\"2.5\"/>\n"
	"	<path d=\"m-6 -5v10m12 0v-10\"/>\n"
	"</g>\n"},
#define D_longa 16
{	"<g id=\"longa\" stroke=\"currentColor\" fill=\"none\">\n"
	"	<path d=\"m-6 2.7h12m0 -5.4h-12\" stroke-width=\"2.5\"/>\n"
	"	<path d=\"m-6 5v-10m12 0v16\"/>\n"
	"</g>\n"},
#define D_ghd 17
{	"<path id=\"ghd\" fill=\"currentColor\" d=\"m1.7 -1\n"
	"	c-1 -1.7 -4.5 0.2 -3.4 2\n"
	"	c1 1.7 4.5 -0.2 3.4 -2\"/>\n"},
#define D_r00 18
{	"<rect id=\"r00\" fill=\"currentColor\"\n"
	"	x=\"-1.6\" y=\"-6\" width=\"3\" height=\"12\"/>\n"},
#define D_r0 19
{	"<rect id=\"r0\" fill=\"currentColor\"\n"
	"	x=\"-1.6\" y=\"-6\" width=\"3\" height=\"6\"/>\n"},
#define D_r1 20
{	"<rect id=\"r1\" fill=\"currentColor\"\n"
	"	x=\"-3.5\" y=\"-6\" width=\"7\" height=\"3\"/>\n"},
#define D_r2 21
{	"<rect id=\"r2\" fill=\"currentColor\"\n"
	"	x=\"-3.5\" y=\"-3\" width=\"7\" height=\"3\"/>\n"},
#define D_r4 22
{	"<path id=\"r4\" fill=\"currentColor\" d=\"m-1 -8.5\n"
	"	l3.6 5.1 -2.1 5.2 2.2 4.3\n"
	"	c-2.6 -2.3 -5.1 0 -2.4 2.6\n"
	"	c-4.8 -3 -1.5 -6.9 1.4 -4.1\n"
	"	l-3.1 -4.5 1.9 -5.1 -1.5 -3.5\"/>\n"},
#define D_r8e 23
{	"<path id=\"r8e\" fill=\"currentColor\" d=\"m 0 0\n"
	"	c-1.5 1.5 -2.4 2 -3.6 2\n"
	"	c2.4 -2.8 -2.8 -4 -2.8 -1.2\n"
	"	c0 2.7 4.3 2.4 5.9 0.6\"/>\n"},
#define D_r8 24
{	"<g id=\"r8\">\n"
	"	<path d=\"m3.3 -4l-3.4 9.6\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"	<use x=\"3.4\" y=\"-4\" xlink:href=\"#r8e\"/>\n"
	"</g>\n", D_r8e},
#define D_r16 25
{	"<g id=\"r16\">\n"
	"	<path d=\"m3.3 -4l-4 15.6\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"	<use x=\"3.4\" y=\"-4\" xlink:href=\"#r8e\"/>\n"
	"	<use x=\"1.9\" y=\"2\" xlink:href=\"#r8e\"/>\n"
	"</g>\n", D_r8e},
#define D_r32 26
{	"<g id=\"r32\">\n"
	"	<path d=\"m4.8 -10l-5.5 21.6\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"	<use x=\"4.9\" y=\"-10\" xlink:href=\"#r8e\"/>\n"
	"	<use x=\"3.4\" y=\"-4\" xlink:href=\"#r8e\"/>\n"
	"	<use x=\"1.9\" y=\"2\" xlink:href=\"#r8e\"/>\n"
	"</g>\n", D_r8e},
#define D_r64 27
{	"<g id=\"r64\">\n"
	"	<path d=\"m4.8 -10 l-7 27.6\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"	<use x=\"4.9\" y=\"-10\" xlink:href=\"#r8e\"/>\n"
	"	<use x=\"3.4\" y=\"-4\" xlink:href=\"#r8e\"/>\n"
	"	<use x=\"1.9\" y=\"2\" xlink:href=\"#r8e\"/>\n"
	"	<use x=\"0.4\" y=\"8\" xlink:href=\"#r8e\"/>\n"
	"</g>\n", D_r8e},
#define D_r128 28
{	"<g id=\"r128\">\n"
	"	<path d=\"m5.8 -16 l-8.5 33.6\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"	<use x=\"5.9\" y=\"-16\" xlink:href=\"#r8e\"/>\n"
	"	<use x=\"4.4\" y=\"-10\" xlink:href=\"#r8e\"/>\n"
	"	<use x=\"2.9\" y=\"-4\" xlink:href=\"#r8e\"/>\n"
	"	<use x=\"1.4\" y=\"2\" xlink:href=\"#r8e\"/>\n"
	"	<use x=\"0.1\" y=\"8\" xlink:href=\"#r8e\"/>\n"
	"</g>\n", D_r8e},
#define D_mrest 29
{	"<g id=\"mrest\">\n"
	"	<path d=\"m-20 -6v-12m40 0v12\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"	<path d=\"m-20 -12h40\" stroke=\"currentColor\" stroke-width=\"5\" fill=\"none\"/>\n"
	"</g>\n"},
#define D_usharp 30
{	"<path id=\"usharp\" fill=\"currentColor\" d=\"\n"
	"	m136 -702\n"
	"	v890\n"
	"	h32\n"
	"	v-890\n"
	"	m128 840\n"
	"	h32\n"
	"	v-888\n"
	"	h-32\n"
	"	m-232 286\n"
	"	v116\n"
	"	l338 -96\n"
	"	v-116\n"
	"	m-338 442\n"
	"	v116\n"
	"	l338 -98\n"
	"	v-114\"/>\n"},
#define D_uflat 31
{	"<path id=\"uflat\" fill=\"currentColor\" d=\"\n"
	"	m100 -746\n"
	"	h32\n"
	"	v734\n"
	"	l-32 4\n"
	"	m32 -332\n"
	"	c46 -72 152 -90 208 -20\n"
	"	c100 110 -120 326 -208 348\n"
	"	m0 -28\n"
	"	c54 0 200 -206 130 -290\n"
	"	c-50 -60 -130 -4 -130 34\"/>\n"},
#define D_unat 32
{	"<path id=\"unat\" fill=\"currentColor\" d=\"\n"
	"	m96 -750\n"
	"	h-32\n"
	"	v716\n"
	"	l32 -8\n"
	"	l182 -54\n"
	"	v282\n"
	"	h32\n"
	"	v-706\n"
	"	l-34 10\n"
	"	l-180 50\n"
	"	v-290\n"
	"	m0 592\n"
	"	v-190\n"
	"	l182 -52\n"
	"	v188\"/>\n"},
#define D_udblesharp 33
{	"<path id=\"udblesharp\" fill=\"currentColor\" d=\"\n"
	"	m240 -282\n"
	"	c40 -38 74 -68 158 -68\n"
	"	v-96\n"
	"	h-96\n"
	"	c0 84 -30 118 -68 156\n"
	"	c-40 -38 -70 -72 -70 -156\n"
	"	h-96\n"
	"	v96\n"
	"	c86 0 120 30 158 68\n"
	"	c-38 38 -72 68 -158 68\n"
	"	v96\n"
	"	h96\n"
	"	c0 -84 30 -118 70 -156\n"
	"	c38 38 68 72 68 156\n"
	"	h96\n"
	"	v-96\n"
	"	c-84 0 -118 -30 -158 -68\"/>\n"},
#define D_udbleflat 34
{	"<path id=\"udbleflat\" fill=\"currentColor\" d=\"\n"
	"	m20 -746\n"
	"	h24\n"
	"	v734\n"
	"	l-24 4\n"
	"	m24 -332\n"
	"	c34 -72 114 -90 156 -20\n"
	"	c75 110 -98 326 -156 348\n"
	"	m0 -28\n"
	"	c40 0 150 -206 97 -290\n"
	"	c-37 -60 -97 -4 -97 34\n"
	"	m226 -450\n"
	"	h24\n"
	"	v734\n"
	"	l-24 4\n"
	"	m24 -332\n"
	"	c34 -72 114 -90 156 -20\n"
	"	c75 110 -98 326 -156 348\n"
	"	m0 -28\n"
	"	c40 0 150 -206 97 -290\n"
	"	c-37 -60 -97 -4 -97 34\"/>\n"},
#define D_sh0 35
{	"<use id=\"sh0\" transform=\"translate(-4,5) scale(0.018)\"\n"
	"	xlink:href=\"#usharp\"/>\n", D_usharp},
#define D_ft0 36
{	"<use id=\"ft0\" transform=\"translate(-3.5,3.5) scale(0.018)\"\n"
	"	xlink:href=\"#uflat\"/>\n", D_uflat},
#define D_nt0 37
{	"<use id=\"nt0\" transform=\"translate(-3,5) scale(0.018)\"\n"
	"	xlink:href=\"#unat\"/>\n", D_unat},
#define D_dsh0 38
{	"<use id=\"dsh0\" transform=\"translate(-4,5) scale(0.018)\"\n"
	"	xlink:href=\"#udblesharp\"/>\n", D_udblesharp},
#define D_dft0 39
{	"<use id=\"dft0\" transform=\"translate(-4,3.5) scale(0.018)\"\n"
	"	xlink:href=\"#udbleflat\"/>\n", D_udbleflat},
#define D_sh1 40
{	"<g id=\"sh1\">\n"
	"    <path d=\"M0 7.8v-15.4\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"    <path fill=\"currentColor\" d=\"M-1.8 2.7l3.6 -1.1v2.2l-3.6 1.1v-2.2z\n"
	"	M-1.8 -3.7l3.6 -1.1v2.2l-3.6 1.1v-2.2\"/>\n"
	"</g>\n"},
#define D_sh513 41
{	"<g id=\"sh513\">\n"
	"    <path d=\"M-2.5 8.7v-15.4M0 7.8v-15.4M2.5 6.9v-15.4\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"    <path fill=\"currentColor\" d=\"M-3.7 3.1l7.4 -2.2v2.2l-7.4 2.2v-2.2z\n"
	"	M-3.7 -3.2l7.4 -2.2v2.2l-7.4 2.2v-2.2\"/>\n"
	"</g>\n"},
#define D_ft1 42
{	"<g id=\"ft1\" transform=\"scale(-1,1)\">\n"
	"	<use xlink:href=\"#ft0\"/>\n"
	"</g>\n", D_ft0},
#define D_ft513 43
{	"<g id=\"ft513\">\n"
	"    <path fill=\"currentColor\" d=\"M0.6 -2.7\n"
	"	c-5.7 -3.1 -5.7 3.6 0 6.7c-3.9 -4 -4 -7.6 0 -5.8\n"
	"	M1 -2.7c5.7 -3.1 5.7 3.6 0 6.7c3.9 -4 4 -7.6 0 -5.8\"/>\n"
	"    <path d=\"M1.6 3.5v-13M0 3.5v-13\" stroke=\"currentColor\" fill=\"none\" stroke-width=\".6\"/>\n"
	"</g>\n"},
#define D_pshhd 44
{	"<g id=\"pshhd\">\n"
	"	<use xlink:href=\"#dsh0\"/>\n"
	"</g>\n", D_dsh0},
#define D_pfthd 45
{	"<g id=\"pfthd\">\n"
	"	<use xlink:href=\"#dsh0\"/>\n"
	"	<circle r=\"4\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"</g>\n", D_dsh0},
#define D_csig 46
{	"<path id=\"csig\" fill=\"currentColor\" d=\"\n"
	"	m1 -17.3\n"
	"	c0.9 0 2.3 0.7 2.4 2.2\n"
	"	c-1.2 -2 -3.6 0.1 -1.6 1.7\n"
	"	c2 1 3.8 -3.5 -0.8 -4.7\n"
	"	c-2 -0.4 -6.4 1.3 -5.8 7\n"
	"	c0.4 6.4 7.9 6.8 9.1 0.7\n"
	"	c-2.3 5.6 -6.7 5.1 -6.8 0\n"
	"	c-0.5 -4.4 0.7 -7.5 3.5 -6.9\"/>\n"},
#define D_ctsig 47
{	"<g id=\"ctsig\">\n"
	"	<use xlink:href=\"#csig\"/>\n"
	"	<path d=\"m0 -4v-16\" stroke=\"currentColor\"/>\n"
	"</g>\n", D_csig},
#define D_pmsig 48
{	"<path id=\"pmsig\" stroke=\"currentColor\" stroke-width=\"0.8\" fill=\"none\"\n"
	"	d=\"M0 -7a5 5 0 0 1 0 -10a5 5 0 0 1 0 10\"/>\n"},
#define D_pMsig 49
{	"<g id=\"pMsig\">\n"
	"	<use xlink:href=\"#pmsig\"/>\n"
	"	<path fill=\"currentColor\" d=\"M0 -10a2 2 0 0 1 0 -4a2 2 0 0 1 0 4\"/>\n"
	"</g>\n", D_pmsig},
#define D_imsig 50
{	"<path id=\"imsig\" stroke=\"currentColor\" stroke-width=\"0.8\" fill=\"none\"\n"
	"	d=\"M0 -7a5 5 0 1 1 0 -10\"/>\n"},
#define D_iMsig 51
{	"<g id=\"iMsig\">\n"
	"	<use xlink:href=\"#imsig\"/>\n"
	"	<path fill=\"currentColor\" d=\"M0 -10a2 2 0 0 1 0 -4a2 2 0 0 1 0 4\"/>\n"
	"</g>\n", D_imsig},
#define D_hl 52
{	"<path id=\"hl\" stroke=\"currentColor\" d=\"m-6 0h12\"/>\n"},
#define D_hl1 53
{	"<path id=\"hl1\" stroke=\"currentColor\" d=\"m-7 0h14\"/>\n"},
#define D_hl2 54
{	"<path id=\"hl2\" stroke=\"currentColor\" d=\"m-9 0h18\"/>\n"},
#define D_ghl 55
{	"<path id=\"ghl\" stroke=\"currentColor\" fill=\"none\" d=\"m-3 0h6\"/>\n"},
#define D_rdots 56
{	"<g id=\"rdots\" fill=\"currentColor\">\n"
	"	<circle cx=\"0\" cy=\"-9\" r=\"1.2\"/>\n"
	"	<circle cx=\"0\" cy=\"-15\" r=\"1.2\"/>\n"
	"</g>\n"},
#define D_srep 57
{	"<path id=\"srep\" fill=\"currentColor\" d=\"M-1 -6l11 -12h3l-11 12h-3\"/>\n"},
#define D_mrep 58
{	"<path id=\"mrep\" fill=\"currentColor\"\n"
	"    d=\"M-5 -16.5a1.5 1.5 0 0 1 0 3a1.5 1.5 0 0 1 0 -3\n"
	"	M4.5 -10a1.5 1.5 0 0 1 0 3a1.5 1.5 0 0 1 0 -3\n"
	"	M-7 -6l11 -12h3l-11 12h-3\"/>\n"},
#define D_mrep2 59
{	"<g id=\"mrep2\" fill=\"currentColor\">\n"
	"    <path d=\"M-5.5 -19.5a1.5 1.5 0 0 1 0 3a1.5 1.5 0 0 1 0 -3\n"
	"	M5 -7.5a1.5 1.5 0 0 1 0 3a1.5 1.5 0 0 1 0 -3\"/>\n"
	"    <path d=\"M-7 -4l14 -10m-14 4l14 -10\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n"
	"</g>\n"},
#define D_accent 60
{	"<g id=\"accent\" stroke=\"currentColor\" fill=\"none\">\n"
	"	<path d=\"m-4 0l8 -2l-8 -2\" stroke-width=\"1.2\"/>\n"
	"</g>\n"},
#define D_umrd 61
{	"<path id=\"umrd\" fill=\"currentColor\" d=\"m0 -4\n"
	"	l2.2 -2.2 2.1 2.9 0.7 -0.7 0.2 0.2\n"
	"	-2.2 2.2 -2.1 -2.9 -0.7 0.7\n"
	"	-2.2 2.2 -2.1 -2.9 -0.7 0.7 -0.2 -0.2\n"
	"	2.2 -2.2 2.1 2.9 0.7 -0.7\"/>\n"},
#define D_lmrd 62
{	"<g id=\"lmrd\">\n"
	"	<use xlink:href=\"#umrd\"/>\n"
	"	<line x1=\"0\" y1=\"0\" x2=\"0\" y2=\"-8\" stroke=\"currentColor\" stroke-width=\".6\"/>\n"
	"</g>\n", D_umrd},
#define D_grm 63
{	"<path id=\"grm\" fill=\"currentColor\" d=\"\n"
	"	m-5 -2.5\n"
	"	c5 -8.5 5.5 4.5 10 -2\n"
	"	c-5 8.5 -5.5 -4.5 -10 2\"/>\n"},
#define D_stc 64
{	"<circle id=\"stc\" fill=\"currentColor\" cx=\"0\" cy=\"-3\" r=\"1.2\"/>\n"},
#define D_sld 65
{	"<path id=\"sld\" fill=\"currentColor\" d=\"\n"
	"	m-7.2 4.8\n"
	"	c1.8 0.7 4.5 -0.2 7.2 -4.8\n"
	"	c-2.1 5 -5.4 6.8 -7.6 6\"/>\n"},
#define D_emb 66
{	"<path id=\"emb\" d=\"m-2.5 -3h5\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke=\"currentColor\"/>\n"},
#define D_hld 67
{	"<g id=\"hld\" fill=\"currentColor\">\n"
	"    <circle cx=\"0\" cy=\"-3\" r=\"1.3\"/>\n"
	"    <path d=\"m-7.5 -1.5\n"
	"	c0 -11.5 15 -11.5 15 0\n"
	"	h-0.25\n"
	"	c-1.25 -9 -13.25 -9 -14.5 0\"/>\n"
	"</g>\n"},
#define D_cpu 68
{	"<path id=\"cpu\" fill=\"currentColor\" d=\"\n"
	"	m-6 0\n"
	"	c0.4 -7.3 11.3 -7.3 11.7 0\n"
	"	c-1.3 -6 -10.4 -6 -11.7 0\"/>\n"},
#define D_upb 69
{	"<path id=\"upb\" stroke=\"currentColor\" fill=\"none\" d=\"\n"
	"	m-2.6 -9.4\n"
	"	l2.6 8.8\n"
	"	l2.6 -8.8\"/>\n"},
#define D_dnb 70
{	"<g id=\"dnb\">\n"
	"	<path d=\"M-3.2 -2v-7.2m6.4 0v7.2\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"	<path d=\"M-3.2 -6.8v-2.4l6.4 0v2.4\" fill=\"currentColor\"/>\n"
	"</g>\n"},
#define D_sgno 71
{	"<g id=\"sgno\">\n"
	"    <path fill=\"currentColor\" d=\"m0 -3\n"
	"	c1.5 1.7 6.4 -0.3 3 -3.7\n"
	"	c-10.4 -7.8 -8 -10.6 -6.5 -11.9\n"
	"	c4 -1.9 5.9 1.7 4.2 2.6\n"
	"	c-1.3 0.7 -2.9 -1.3 -0.7 -2\n"
	"	c-1.5 -1.7 -6.4 0.3 -3 3.7\n"
	"	c10.4 7.8 8 10.6 6.5 11.9\n"
	"	c-4 1.9 -5.9 -1.7 -4.2 -2.6\n"
	"	c1.3 -0.7 2.9 1.3 0.7 2\"/>\n"
	"    <line x1=\"-6\" y1=\"-4.2\" x2=\"6.6\" y2=\"-16.8\" stroke=\"currentColor\"/>\n"
	"    <circle cx=\"-6\" cy=\"-10\" r=\"1.2\"/>\n"
	"    <circle cx=\"6\" cy=\"-11\" r=\"1.2\"/>\n"
	"</g>\n"},
#define D_coda 72
{	"<g id=\"coda\" stroke=\"currentColor\" fill=\"none\">\n"
	"	<path d=\"m0 -2v-20m-10 10h20\"/>\n"
	"	<circle cx=\"0\" cy=\"-12\" r=\"6\" stroke-width=\"1.7\"/>\n"
	"</g>\n"},
#define D_dplus 73
{	"<path id=\"dplus\" stroke=\"currentColor\" stroke-width=\"1.7\"\n"
	"	d=\"m0 -0.5v-6m-3 3h6\"/>\n"},
#define D_lphr 74
{	"<path id=\"lphr\" stroke=\"currentColor\" stroke-width=\"1.2\"\n"
	"	d=\"m0 0v18\"/>\n"},
#define D_mphr 75
{	"<path id=\"mphr\" stroke=\"currentColor\" stroke-width=\"1.2\"\n"
	"	d=\"m0 0v12\"/>\n"},
#define D_sphr 76
{	"<path id=\"sphr\" stroke=\"currentColor\" stroke-width=\"1.2\"\n"
	"	d=\"m0 0v6\"/>\n"},
#define D_opend 77
{	"<circle id=\"opend\" stroke=\"currentColor\" fill=\"none\"\n"
	"	cx=\"0\" cy=\"-3\" r=\"2.5\"/>\n"},
#define D_snap 78
{	"<path id=\"snap\" stroke=\"currentColor\" fill=\"none\"\n"
	"    d=\"M-3 -6\n"
	"	c0 -5 6 -5 6 0\n"
	"	c0 5 -6 5 -6 0\n"
	"	M0 -5v6\"/>\n"},
#define D_thumb 79
{	"<path id=\"thumb\" stroke=\"currentColor\" fill=\"none\"\n"
	"    d=\"M-2.5 -7\n"
	"	c0 -6 5 -6 5 0\n"
	"	c0 6 -5 6 -5 0\n"
	"	M-2.5 -9v4\"/>\n"},
#define D_turn 80
{	"<path id=\"turn\" fill=\"currentColor\" d=\"\n"
	"	m5.2 -8\n"
	"	c1.4 0.5 0.9 4.8 -2.2 2.8\n"
	"	l-4.8 -3.5\n"
	"	c-3 -2 -5.8 1.8 -3.6 4.4\n"
	"	c1 1.1 2 0.8 2.1 -0.1\n"
	"	c0.1 -0.9 -0.7 -1.2 -1.9 -0.6\n"
	"	c-1.4 -0.5 -0.9 -4.8 2.2 -2.8\n"
	"	l4.8 3.5\n"
	"	c3 2 5.8 -1.8 3.6 -4.4\n"
	"	c-1 -1.1 -2 -0.8 -2.1 0.1\n"
	"	c-0.1 0.9 0.7 1.2 1.9 0.6\"/>\n"},
#define D_turnx 81
{	"<g id=\"turnx\">\n"
	"	<use xlink:href=\"#turn\"/>\n"
	"	<path d=\"M0 -1.5v-9\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"</g>\n", D_turn},
#define D_wedge 82
{	"<path id=\"wedge\" fill=\"currentColor\" d=\"M0 -1l-1.5 -5h3l-1.5 5\"/>\n"},
#define D_ltr 83
{	"<path id=\"ltr\" fill=\"currentColor\"\n"
	"    d=\"m0 -0.4c2 -1.5 3.4 -1.9 3.9 0.4\n"
	"	c0.2 0.8 0.7 0.7 2.1 -0.4\n"
	"	v0.8c-2 1.5 -3.4 1.9 -3.9 -0.4\n"
	"	c-0.2 -0.8 -0.7 -0.7 -2.1 0.4z\"/>\n"},
#define D_custos 84
{	"<g id=\"custos\">\n"
	"	<path d=\"M-4 0l2 2.5l2 -2.5l2 2.5l2 -2.5\n"
	"		l-2 -2.5l-2 2.5l-2 -2.5l-2 2.5\" fill=\"currentColor\"/>\n"
	"	<path d=\"M3.5 0l5 -7\" stroke=\"currentColor\" fill=\"none\"/>\n"
	"</g>\n"},
#define D_showerror 85
{	"<circle id=\"showerror\" r=\"30\" stroke=\"#ffc0c0\" stroke-width=\"2.5\" fill=\"none\"/>\n"},
};

/* PS functions */
static void elts_link(struct elt_s *e)
{
	int i;

	/* set the linkages - the first element is the link to the next block */
	for (i = 1; i < NELTS - 1; i++) {
		e[i].next = &e[i + 1];
		if (e[i].type == STR)
			free(e[i].u.s);
		e[i].type = VAL;
	}
	e[NELTS - 1].next = NULL;
}

/* (re)initialize all PS elements */
static void elts_reset(void)
{
	struct elt_s *e;

	if (!elts)
		elts = calloc(sizeof *elts, NELTS);
	elts_link(elts);
	free_elt = elts + 1;

	/* link all blocks */
	for (e = elts; e->u.e; e = e->u.e) {
		elts_link(e->u.e);
		e[NELTS - 1].next = e->u.e;
	}
}

static struct elt_s *elt_new(void)
{
	struct elt_s *e;

	e = free_elt;
	if (!e) {
		e = calloc(sizeof *e, NELTS);
		if (!e) {
			fprintf(stderr, "svg: elt_new out of memory\n");
			ps_error = 1;
			return e;
		}
		elts_link(e);
		e->u.e = elts;
		elts = e;
		e++;
	}
	free_elt = e->next;
	e->next = NULL;
	e->type = VAL;
	return e;
}

static void elt_free(struct elt_s *e)
{
	struct elt_s *e2;

	e->next = free_elt;
	free_elt = e;
	switch (e->type) {
	case STR:
		free(e->u.s);
		e->type = VAL;
		e->u.v = 0;
		break;
	case SEQ:
	case BRK:
		e2 = e->u.e;
		e->type = VAL;
		e->u.v = 0;
		while (e2) {
			e = e2->next;
			elt_free(e2);
			e2 = e;
		}
		break;
	}
}

static struct elt_s *elt_dup(struct elt_s *e)
{
	struct elt_s *e2, *e3, *e4;

	e2 = elt_new();
	if (!e2)
		return e2;
	e2->type = e->type;
	switch (e->type) {
	case VAL:
		e2->u.v = e->u.v;
		break;
	case STR:
		e2->u.s = strdup(e->u.s);
		break;
	case SEQ:
	case BRK:
		e = e->u.e;
		if (!e) {
			e2->u.e = NULL;
			break;
		}
		e3 = e2->u.e = elt_dup(e);
		if (!e3)
			break;
		for (;;) {
			e = e->next;
			if (!e)
				break;
			e4 = elt_dup(e);
			if (!e4)
				break;
			e3->next = e4;
			e3 = e4;
		}
		e3->next = NULL;
		break;
	}
	return e2;
}

static void elt_dump(struct elt_s *e)
{
	int type;

	type = e->type;
	switch (type) {
	case VAL:
		fprintf(stderr, " %.2f", e->u.v);
		break;
	case STR:
		fprintf(stderr, " %s", e->u.s);
		if (e->u.s[0] == '(')
			fprintf(stderr, ")");
		break;
	case SEQ:
	case BRK:
		fprintf(stderr, type == SEQ ? " {" : " [");
		e = e->u.e;
		while (e) {
			elt_dump(e);
			e = e->next;
		}
		fprintf(stderr, type == SEQ ? " }" : " ]");
	}
}

static void elt_lst_dump(struct elt_s *e)
{
	do {
		elt_dump(e);
		e = e->next;
	} while (e);
}

static struct ps_sym_s *ps_sym_lookup(char *name)
{
	struct ps_sym_s *ps;

	if (n_sym == 0)
		return NULL;
	ps = &ps_sym[n_sym];
	for (;;) {
		ps--;
		if (strcmp(ps->n, name) == 0)
			break;
		if (ps == ps_sym)
			return NULL;
	}
	return ps;
}

static struct ps_sym_s *ps_sym_def(char *name, struct elt_s *e)
{
	struct ps_sym_s *ps;

	ps = ps_sym_lookup(name);
	if (ps) {
		elt_free(ps->e);
	} else {
		if (n_sym >= NSYMS) {
			fprintf(stderr, "svg: Too many PS symbols\n");
			ps_error = 1;
			return NULL;
		}
		ps = &ps_sym[n_sym++];
		ps->n = strdup(name);
	}
	ps->e = e;
	ps->exec = 0;
	return ps;
}

static void push(struct elt_s *e)
{
	e->next = stack;
	stack = e;
}

static void stack_dump(void)
{
	fprintf(stderr, "stack:");
	if (stack)
		elt_lst_dump(stack);
	else
		fprintf(stderr, "(empty)");
	fprintf(stderr, "\n");
}

static struct elt_s *pop(int type)
{
	struct elt_s *e;

	e = stack;
	if (!e) {
		fprintf(stderr, "svg pop: Stack empty\n");
		ps_error = 1;
		return NULL;
	}
	if (e->type != type) {
		fprintf(stderr, "svg pop: Bad element type %d != %d\n",
			e->type, type);
		stack_dump();
		ps_error = 1;
		return NULL;
	}
	stack = e->next;
	return e;
}

static float pop_free_val(void)
{
	struct elt_s *e;

	e = pop(VAL);
	if (!e)
		return 0;
	e->next = free_elt;
	free_elt = e;
	return e->u.v;
}

static char *pop_free_str(void)
{
	struct elt_s *e;
	char *s;

	e = pop(STR);
	if (!e)
		return NULL;
	s = e->u.s;
	e->type = VAL;
	e->next = free_elt;
	free_elt = e;
	return s;
}

/* PS condition code */
#define C_EQ 0
#define C_NE 1
#define C_GT 2
#define C_GE 3
#define C_LT 4
#define C_LE 5
static void cond(int type)
{
	float v;
	char *s, *s2;

	if (!stack || !stack->next) {
		fprintf(stderr, "svg: Stack underflow in condition\n");
		ps_error = 1;
		return;
	}

	/* string compare */
	if (stack->type == STR && stack->next->type == STR) {
		s = pop_free_str();
		s2 = stack->u.s;
		switch (type) {
		case C_EQ:
			stack->u.v = strcmp(s2, s) == 0;
			break;
		case C_NE:
			stack->u.v = strcmp(s2, s) != 0;
			break;
		default:
			fprintf(stderr, "svg: String condition not treated\n");
			break;
		}
		free(s);
		free(s2);
		stack->type = VAL;
		return;
	}

	/* special case when 1 character strings */
	if (stack->type == STR) {
		s = stack->u.s;
		stack->u.v = s[1];
		free(s);
		stack->type = VAL;
	}
	if (stack->next->type == STR) {
		s = stack->next->u.s;
		stack->next->u.v = s[1];
		free(s);
		stack->next->type = VAL;
	}
	v = pop_free_val();
	if (stack->type != VAL) {
		fprintf(stderr, "svg: Bad type for condition\n");
		ps_error = 1;
		return;
	}
	switch (type) {
	case C_EQ:
		stack->u.v = stack->u.v == v;
		break;
	case C_NE:
		stack->u.v = stack->u.v != v;
		break;
	case C_GT:
		stack->u.v = stack->u.v > v;
		break;
	case C_GE:
		stack->u.v = stack->u.v >= v;
		break;
	case C_LT:
		stack->u.v = stack->u.v < v;
		break;
	case C_LE:
		stack->u.v = stack->u.v <= v;
		break;
	}
}

/* -- output information about the generation in the XHTML/SVG headers -- */
static void gen_info(void)
{
	unsigned i;
	time_t ltime;

	time(&ltime);
#ifndef WIN32
	strftime(tex_buf, TEX_BUF_SZ, "%b %e, %Y %H:%M", localtime(&ltime));
#else
	strftime(tex_buf, TEX_BUF_SZ, "%b %#d, %Y %H:%M", localtime(&ltime));
#endif
	fprintf(fout, "<!-- CreationDate: %s -->\n"
			"<!-- CommandLine:",
			tex_buf);

	for (i = 1; i < (unsigned) s_argc; i++) {
		char *p;
		int space;

		p = s_argv[i];
		space = strchr(p, ' ') != NULL || strchr(p, '\n') != NULL;
		fputc(' ', fout);
		if (space)
			fputc('\'', fout);

		/* cannot have '--' inside comment ! */
		if (*p == '-' && p[1] == '-') {
			fputs("-\\", fout);
			p++;
		}
		fputs(p, fout);
		if (space)
			fputc('\'', fout);
	}
	fputs(" -->\n", fout);
}

/* -- output the symbol definitions -- */
void define_svg_symbols(char *title, int num, float w, float h)
{
	char *s;
	unsigned i;
	static const char *svg_head =
		"<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n"
		"\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
		"\txml:space='preserve' color=\"black\"\n"
		"\twidth=\"%.2fin\" height=\"%.2fin\" viewBox=\"0 0 %.0f %.0f\">\n"
		"<title>%s %s %d</title>\n";

	xoffs = yoffs = x_rot = y_rot = 0;
	memset(&gcur, 0, sizeof gcur);
	gcur.xscale = gcur.yscale = 1;
	gcur.linewidth = DLW;
	memcpy(&gold, &gcur, sizeof gold);
	nsave = 0;
	for (i = 0; i < sizeof def_tb / sizeof def_tb[0]; i++)
		def_tb[i].defined = 0;

	if (svg == 2) {			/* if XHTML */
		if (file_initialized <= 0) {
			if ((s = strrchr(in_fname, DIRSEP)) == NULL)
				s = in_fname;
			else
				s++;
			fputs("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"
				"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1.dtd\">\n"
				"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
				"<head>\n"
				"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n"
				"<meta name=\"generator\" content=\"abcm2ps-" VERSION "\"/>\n",
				fout);
			gen_info();
			fprintf(fout,
				"<style type=\"text/css\">\n"
				"\tbody {margin:0; padding:0; border:0;");
			if (cfmt.bgcolor && cfmt.bgcolor[0] != '\0')
				fprintf(fout, " background-color:%s",
						cfmt.bgcolor);
			fprintf(fout,
				"}\n"
				"\t@page {margin:0;}\n"
				"</style>\n"
				"<title>%s</title>\n"
				"</head>\n"
				"<body>\n",
				
				s);
		}
		fputs("<p>\n", fout);
		fprintf(fout, svg_head, w / 72, h / 72, w, h, title, "page", num);
//		if (cfmt.bgcolor && cfmt.bgcolor[0] != '\0')
//			fprintf(fout,
//				"<rect width=\"100%%\" height=\"100%%\" fill=\"%s\"/>\n",
//				cfmt.bgcolor);
	} else {				/* -g, -v or -z */
		if (epsf != 3) {
			if (fout != stdout)
				fputs("<?xml version=\"1.0\" standalone=\"no\"?>\n"
					"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"
					"\t\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
					fout);
			else if (svg)
				fputs("<p>\n", fout);
		}
		fprintf(fout, svg_head, w / 72, h / 72, w, h, title,
			epsf ? "tune" : "page", num);
		fputs("<!-- Creator: abcm2ps-" VERSION " -->\n", fout);
		gen_info();
		if (cfmt.bgcolor && cfmt.bgcolor[0] != '\0')
			fprintf(fout,
				"<rect width=\"100%%\" height=\"100%%\" fill=\"%s\"/>\n",
				cfmt.bgcolor);
	}

	/* if new page, done */
	if (file_initialized > 0)
		return;

	elts_reset();
	n_sym = 0;

	in_cnt = 0;
	path = NULL;
	ps_error = 0;

	s = strdup("/defl 0 def\n"
		   "/svg 1 def\n"
		   "/gsc{gsave y T .7 dup scale 0 0}def\n");
	svg_write(s, strlen(s));
	free(s);
}

static void selfont(int back)
{
	char *p;
	int flags;

	if (gcur.font_n[0] == '\0')
		return;
	flags = 0;
	p = strchr(gcur.font_n, '-');
	if (!p) {
		fprintf(fout, " font-family=\"%s\" font-size=\"%.2f\"",
			gcur.font_n, gcur.font_s);
	} else {
		fprintf(fout, " font-family=\"%.*s\" font-size=\"%.2f\"",
			(int) (p - gcur.font_n), gcur.font_n, gcur.font_s);
		if (strstr(gcur.font_n, "Bold") != NULL) {
			fprintf(fout, " font-weight=\"bold\"");
			flags = 1;
		}
		if (strstr(gcur.font_n, "Italic") != NULL) {
			fprintf(fout, " font-style=\"italic\"");
			flags |= 2;
		} else if (strstr(gcur.font_n, "Oblique") != NULL) {
			fprintf(fout, " font-style=\"oblique\"");
			flags |= 2;
		}
	}
	if (!back)
		return;
	if (!(flags & 1)
	 && strstr(gold.font_n, "Bold") != NULL)
		fprintf(fout, " font-weight=\"normal\"");
	if (!(flags & 2)
	 && (strstr(gold.font_n, "Italic") != NULL
	  || strstr(gold.font_n, "Oblique") != NULL))
		fprintf(fout, " font-style=\"normal\"");
}

static float strw(char *s)
{
	unsigned short c;
	float w;

	w = 0;
	for (;;) {
		c = *s++;
		if (c == '\0')
			break;
		w += cwid(c) * 1.1;
	}
	return w * gcur.font_s;
}

/* define the global container */
static void setg(int newg);
static void defg1(void)
{
	setg(0);
	fputs("<g", fout);
	if (gcur.xscale != 1 || gcur.yscale != 1 || gcur.rotate != 0) {
		fprintf(fout, " transform=\"");
		if (gcur.xscale != 1 || gcur.yscale != 1) {
			if (gcur.xscale == gcur.yscale)
				fprintf(fout, "scale(%.3f)", gcur.xscale);
			else
				fprintf(fout, "scale(%.3f,%.3f)",
						gcur.xscale, gcur.yscale);
		}
		if (gcur.rotate != 0) {
			if (xoffs != 0 || yoffs != 0) {
				fprintf(fout, " translate(%.2f, %.2f)",
						xoffs, yoffs);
				x_rot = xoffs;
				y_rot = yoffs;
				xoffs = 0;
				yoffs = 0;
			}
			fprintf(fout, " rotate(%.2f)",
					gcur.rotate);
		}
		fputs("\"", fout);
	}
	if (gcur.linewidth != 1)
		fprintf(fout, " stroke-width=\"%.2f\"", gcur.linewidth);
	selfont(0);
	if (gcur.rgb != 0)
		fprintf(fout, " style=\"color:#%06x;fill:#%06x\"",
				gcur.rgb, gcur.rgb);
//jfm test
//	fprintf(fout, "%s>\n", gcur.dash);
	fprintf(fout, ">\n");
	g = 1;
	memcpy(&gold, &gcur, sizeof gold);
}

/*
 * set the state of the containers
 * state:
 *	0: no container
 *	1: graphical container
 *	2: graphical container and text
 * newg:
 *	0: close both the text and the graphical container
 *	1: close only the text and reset the graphical container
 */
static void setg(int newg)
{
#if 0 //path change
	if (in_path) {
		fputs("\"/>\n", fout);
		fprintf(stderr, "svg setg: No stroke nor fill\n");
//		ps_error = 1;
		in_path = 0;
	}
#endif
	if (g == 2) {
		fputs("</text>\n", fout);
		g = 1;
	}
	if (newg == 0) {
		if (g != 0) {
			fputs("</g>\n", fout);
			if (gcur.rotate != 0) {
				xoffs = x_rot;
				yoffs = y_rot;
				x_rot = 0;
				y_rot = 0;
			}
			g = 0;
		}
	} else if (memcmp(&gcur, &gold, sizeof gcur) != 0) {
		defg1();
	}
}

/* graphic path */
static void path_print(char *fmt, ...)
{
	va_list args;
	char *p;

	va_start(args, fmt);
	vsnprintf(path_buf, sizeof path_buf, fmt, args);
	va_end(args);
	if (!path) {
		path = malloc(strlen(path_buf) + 1);
		p = path;
	} else {
		path = realloc(path, strlen(path) + strlen(path_buf) + 1);
		p = path + strlen(path);
	}
	if (!path) {
		fprintf(stderr, "Out of memory.\n");
		exit(EXIT_FAILURE);
	}
	strcpy(p, path_buf);
}

static void path_def(void)
{
	if (path)
		return;
	setg(1);
	path_print("<path d=\"m%.2f %.2f\n", xoffs + cx, yoffs - cy);
}

static void path_end(void)
{
	setg(1);
	fputs(path, fout);
	free(path);
	path = NULL;
}

static void def_use(int def)
{
	int i;

	gcur.linewidth = DLW;
	setg(1);
	if (def_tb[def].defined)
		return;
	def_tb[def].defined = 1;
	fputs("<defs>\n", fout);
	i = def_tb[def].use;
	while (i != 0 && !def_tb[i].defined) {
		def_tb[i].defined = 1;
		fputs(def_tb[i].def, fout);
		i = def_tb[i].use;
	}
	fputs(def_tb[def].def, fout);
	fputs("</defs>\n", fout);
}

static void xysym(char *op, int use)
{
	float x, y;

	def_use(use);
	y = yoffs - pop_free_val();
	x = xoffs + pop_free_val();
	fprintf(fout, "<use x=\"%.2f\" y=\"%.2f\" xlink:href=\"#%s\"/>\n",
		x, y, op);
}

static void setxory(char *s, float v)
{
	struct elt_s *e;
	struct ps_sym_s *sym;

	sym = ps_sym_lookup(s);
	if (!sym || sym->e->type != VAL) {
		e = elt_new();
		if (!e)
			return;
		e->type = VAL;
		sym = ps_sym_def(s, e);
		if (!sym)
			return;
	}
	sym->e->u.v = v;
}

static void setxysym(char *op, int use)
{
	float x, y;

	y = pop_free_val();
	x = pop_free_val();
	setxory("x", x);
	setxory("y", y);
	def_use(use);
	fprintf(fout, "<use x=\"%.2f\" y=\"%.2f\" xlink:href=\"#%s\"/>\n",
		xoffs + x, yoffs - y, op);
}

/*  gua gda (acciaccatura) */
static void acciac(char *op)
{
	struct ps_sym_s *sym;
	float x, y, dx, dy;

	setg(1);
	dy = pop_free_val();
	dx = pop_free_val();
	sym = ps_sym_lookup("x");
	x = xoffs + sym->e->u.v;
	sym = ps_sym_lookup("y");
	y = yoffs - sym->e->u.v;
	if (op[1] == 'u') {
		x -= 1;
		y -= 4;
	} else {
		x -= 5;
		y += 4;
	}
	fprintf(fout,
		"<path d=\"M%.2f %.2fl%.2f %.2f\" stroke=\"currentColor\" fill=\"none\"/>\n",
		x, y, dx, -dy);
}

/* arp - ltr */
static void arp_ltr(char type)
{
	float x, y, t, w;
	int n;

	def_use(D_ltr);
	y = yoffs - pop_free_val();
	x = xoffs + pop_free_val();
	w = pop_free_val();
	n = (w + 5) / 6;
	if (type == 'a') {
		fprintf(fout, "<g transform=\"rotate(270)\">\n");
		t = x;
		x = -y;
		y = t;
	}
	y -= 4;
	while (--n >= 0) {
		fprintf(fout, "<use x=\"%.2f\" y=\"%.2f\" xlink:href=\"#ltr\"/>\n",
			x, y);
			x += 6;
	}
	if (type == 'a')
		fprintf(fout, "</g>\n");
}

/* sd su gd gu */
static void stem(char *op)
{
	struct ps_sym_s *sym;
	float x, y, dx, h;

	gcur.linewidth = DLW;
	setg(1);
	h = pop_free_val();
	if (op[0] == 's')
		dx = 3.5;
	else
		dx = 1.6;
	if (op[1] == 'd')
		dx = -dx;
	sym = ps_sym_lookup("x");
	x = xoffs + sym->e->u.v + dx;
	sym = ps_sym_lookup("y");
	y = yoffs - sym->e->u.v;

	fprintf(fout,
		"<path d=\"M%.2f %.2fv%.2f\" stroke=\"currentColor\" fill=\"none\"/>\n",
		x, y, -h);
}

/* output a xml string */
static void xml_str_out(char *p)
{
	char *q, *r;

	q = p;
	for (q = p; *p != '\0';) {
		switch (*p++) {
		case '<': r = "&lt;"; break;
		case '>': r = "&gt;"; break;
		case '\'': r = "&apos;"; break;
		case '"': r = "&quot;"; break;
		case '&':
			if (*p == '#')
				continue;
			r = "&amp;";
			break;
		default:
			continue;
		}
		if (p - 1 != q)
			fwrite(q, 1, p - 1 - q, fout);
		q = p;
		fputs(r, fout);
	}
	if (p != q)
		fputs(q, fout);
}

/*
 * types:
 *	s show / c showc / r showr / j jshow / b showb /x gxshow
 */
static void show(char type)
{
	float x, y, w;
	char tmp[4], *s, *p, *q;
	int span;

	span = 0;
	if (memcmp(&gcur, &gold, sizeof gcur) != 0) {
		if (g == 2)
			span = 1;
		else
			defg1();
	}
	switch (type) {
	case 'j':
		x = cx;
		y = cy;
		w = pop_free_val();
		p = tmp;
		tmp[0] = '\0';
		s = NULL;
		break;
	default:
		x = cx;
		y = cy;
		if (stack->type == STR) {
			s = pop_free_str();
			if (!s || s[0] != '(') {
				fprintf(stderr, "svg: No string\n");
				ps_error = 1;
				return;
			}
			p = s + 1;			/* remove '(' */
		} else {
			p = tmp;
			tmp[0] = pop_free_val();
			tmp[1] = '\0';
			s = NULL;
		}
		w = strw(p);
		if (type == 'x') {		/* gxshow */
			w = pop_free_val();	/* inter TAB width */
			q = strchr(p, '\t');
			*q = '\0';		/* string after the 1st one */
		}
		break;
	}
	if (span) {
		fprintf(fout,"<tspan\n\t");
		selfont(1);
		fprintf(fout,">");
	} else if (g != 2) {
		fprintf(fout, "<text x=\"%.2f\" y=\"%.2f\"", x + xoffs, yoffs - y);
		switch (type) {
		case 'c':
			fprintf(fout, " text-anchor=\"middle\"");
			w /= 2;
			break;
		case 'r':
			fprintf(fout, " text-anchor=\"end\"");
			w = 0;
			break;
		case 'j':
			fprintf(fout, " textLength=\"%.2f\"", w);
			break;
		}

//		if (gcur.rgb != 0)
//			fprintf(fout, " fill=\"currentColor\"");
		fputs(">", fout);
		g = 2;
	}

back:
	xml_str_out(p);
	if (span)
		fprintf(fout, "</tspan>");

	if (type == 'x') {
		p = p + strlen(p) + 1;		/* next string of gxshow */
		q = strchr(p, '\t');
		if (q) {
			*q = '\0';
		} else {

			/* restore the string width (!! tied to elt_free() !!) */
			w = free_elt->u.v;
			type = 's';
		}
		fprintf(fout, "<tspan dx=\"%.2f\">", w);
		span = 1;
		goto back;
	}
	if (type == 'b') {
		setg(1);
		fprintf(fout,
			"<rect stroke=\"currentColor\" fill=\"none\" stroke-width=\"0.6\"\n"
			"	x=\"%.2f\" y=\"%.2f\" width=\"%.2f\" height=\"%.2f\"/>\n",
			xoffs + cx - 2, yoffs - y - gcur.font_s + 2, w + 4, gcur.font_s + 1);
	}
	cx = x + w;
	if (s)
		free(s);
}

static void ps_exec(char *op);

/* execute a sequence
 * returns 1 on 'exit' or error */
static int seq_exec(struct elt_s *e)
{
	struct elt_s *e2;

	switch (e->type) {
	case STR:
		if (e->u.s[0] != '/'
		 && e->u.s[0] != '(') {
			if (strcmp(e->u.s, "exit") == 0)
				return 1;
			ps_exec(e->u.s);
			return 0;
		}
		/* fall thru */
	case VAL:
	case BRK:
		e = elt_dup(e);
		if (!e)
			return 1;
		push(e);
		return 0;
	}
	/* (e->type == SEQ) */
	e = e->u.e;
	while (e) {
		switch (e->type) {
		case STR:
			if (strcmp(e->u.s, "exit") == 0)
				return 1;
			if (e->u.s[0] != '(' && e->u.s[0] != '/') {
				ps_exec(e->u.s);
				break;
			}
			/* fall thru */
		default:
			e2 = elt_dup(e);
			if (!e2)
				return 1;
			push(e2);
			break;
		}
		e = e->next;
	}
	return 0;
}

/* execute a command */
/* (in case of error, a string may be not freed, but it is not important!) */
static void ps_exec(char *op)
{
	struct ps_sym_s *sym;
	struct elt_s *e, *e2;
	float x, y, w, h;
	int n;
	char *s;

	if (ps_error)
		return;
#if 0
fprintf(stderr, "%s ", op);
stack_dump();
#endif
	sym = ps_sym_lookup(op);
	if (sym) {
		sym->exec++;
		if (sym->exec > 2) {
			fprintf(stderr, "svg: Too many recursions\n");
			ps_error = 1;
			return;
		}
		seq_exec(sym->e);
		sym->exec--;
		return;
	}

	if (*op == ' ')				/* load */
		op++;

	switch (*op) {
	case '!':				/* def */
		if (op[1] == '\0') {
			if (!stack) {
				fprintf(stderr, "svg def: Stack empty\n");
				ps_error = 1;
				return;
			}
			e = pop(stack->type);	/* value */
			s = pop_free_str();	/* symbol */
			if (!s || *s != '/') {
				fprintf(stderr, "svg def: No / bad symbol\n");
				ps_error = 1;
				return;
			}
			ps_sym_def(&s[1], e);
			free(s);
			return;
		}
		break;
	case 'a':
		if (strcmp(op, "accent") == 0) {
			xysym(op, D_accent);
			return;
		}
		if (strcmp(op, "abs") == 0) {
			if (!stack || stack->type != VAL) {
				fprintf(stderr, "svg abs: Bad value\n");
				ps_error = 1;
				return;
			}
			if (stack->u.v < 0)
				stack->u.v = -stack->u.v;
			return;
		}
		if (strcmp(op, "add") == 0) {
			x = pop_free_val();
			if (!stack || stack->type != VAL) {
				fprintf(stderr, "svg add: Bad value\n");
				ps_error = 1;
				return;
			}
			stack->u.v += x;
			return;
		}
		if (strcmp(op, "and") == 0) {
			x = pop_free_val();
			if (!stack || stack->type != VAL) {
				fprintf(stderr, "svg and: Bad value\n");
				ps_error = 1;
				return;
			}
			stack->u.v = (int) x & (int) stack->u.v;
			return;
		}
		if (strcmp(op, "anshow") == 0) {
			show('s');
			return;
		}
		if (strcmp(op, "arc") == 0
		 || strcmp(op, "arcn") == 0) {
			float r, a1, a2, x1, y1, x2, y2;

			path_def();
			a2 = pop_free_val();
			a1 = pop_free_val();
			r = pop_free_val();
			if (r < 0) {
				fprintf(stderr, "svg arc: Bad value\n");
				ps_error = 1;
				return;
			}
			y = pop_free_val();
			x = pop_free_val();
			x1 = x + r * cos(a1 * M_PI / 180);
			y1 = y + r * sinf(a1 * M_PI / 180);
			if (a1 >= 360)
				a1 -= 360;
			if (a2 >= 360)
				a2 -= 360;
			path_print("\t", fout);
			if (x1 != cx || y1 != cy)
				path_print("m%.2f %.2f", 
					x1 - cx, -(y1 - cy));
			if (a1 == a2) {			/* circle */
				a2 = 180 - a1;
				x2 = x + r * cosf(a2 * M_PI / 180);
				y2 = y + r * sinf(a2 * M_PI / 180);
				path_print("a%.2f %.2f 0 0 %d %.2f %.2f"
						"a%.2f %.2f 0 0 %d %.2f %.2f\n",
					r, r, op[3] == 'n', x2 - x1, -(y2 - y1),
					r, r, op[3] == 'n', x1 - x2, -(y1 - y2));
				cx = x1;
				cy = y1;
			} else {
				x2 = x + r * cosf(a2 * M_PI / 180);
				y2 = y + r * sinf(a2 * M_PI / 180);
				path_print("a%.2f %.2f 0 0 %d %.2f %.2f\n",
					r, r, op[3] == 'n', x2 - x1, -(y2 - y1));
				cx = x2;
				cy = y2;
			}
			return;
		}
		if (strcmp(op, "arp") == 0) {
			arp_ltr('a');
			return;
		}
		if (strcmp(op, "atan") == 0) {
			y = pop_free_val();	/* den */
			if (!stack || stack->type != VAL) {
				fprintf(stderr, "svg atan: Bad value\n");
				ps_error = 1;
				return;
			}
			x = stack->u.v;		/* num */
			if (x == 0 && y == 0) {
				fprintf(stderr, "svg atan: Bad value\n");
				ps_error = 1;
				return;
			}
			stack->u.v = atan(x / y) / M_PI * 180;
			return;
		}
		break;
	case 'b':
		if (strcmp(op, "bar") == 0) {
			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			h = pop_free_val();
			fprintf(fout, "<path stroke=\"currentColor\" fill=\"none\"\n"
				"	d=\"M%.2f %.2fv%.2f\"/>\n",
				x, y, -h);
			return;
		}
		if (strcmp(op, "bclef") == 0) {
			xysym(op, D_bclef);
			return;
		}
		if (strcmp(op, "bdef") == 0) {
			ps_exec("!");
			return;
		}
		if (strcmp(op, "bind") == 0) {
			return;
		}
		if (strcmp(op, "bitshift") == 0) {
			int shift;

			shift = pop_free_val();
			if (!stack || stack->type != VAL
			 || shift >= 32  || shift < -32) {
				fprintf(stderr, "svg: Bad value for bitshift\n");
				ps_error = 1;
				return;
			}
			if (shift > 0)
				n = (int) stack->u.v << shift;
			else
				n = (int) stack->u.v >> -shift;
			stack->u.v = n;
			return;
		}
		if (strcmp(op, "bm") == 0) {
			float dx, dy;

			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			dy = pop_free_val();
			dx = pop_free_val();
			h = pop_free_val();
			fprintf(fout,
				"<path fill=\"currentColor\"\n"
				"	d=\"M%.2f %.2fl%.2f %.2fv%.2fl%.2f %.2f\"/>\n",
				x, y, dx, -dy, h,-dx, dy);
			return;
		}
		if (strcmp(op, "bnum") == 0
		 || strcmp(op, "bnumb") == 0) {
			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			s = pop_free_str();
			if (!s) {
				fprintf(stderr, "svg: No string\n");
				ps_error = 1;
				return;
			}
			if (op[4] == 'b') {
				w = 7 * strlen(s);
				fprintf(fout,
					"<rect x=\"%.2f\" y=\"%.2f\" width=\"%.2f\" height=\"12\" fill=\"white\"/>\n",
					x - w / 2, y - 10, w);
			}
			fprintf(fout,
				"<text font-family=\"serif\" font-size=\"12\" font-style=\"italic\" font-weight=\"normal\"\n"
				"	x=\"%.2f\" y=\"%.2f\" text-anchor=\"middle\">%s</text>\n",
				x, y, s + 1);
			free(s);
			return;
		}
		if (strcmp(op, "box") == 0) {
			setg(1);
			h = pop_free_val();
			w = pop_free_val();
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			fprintf(fout,
				"<rect stroke=\"currentColor\" fill=\"none\"\n"
				"	x=\"%.2f\" y=\"%.2f\" width=\"%.2f\" height=\"%.2f\"/>\n",
				x, y - h, w, h);
			return;
		}
		if (strcmp(op, "boxdraw") == 0) {
			setg(1);
			h = pop_free_val();
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			fprintf(fout,
				"<rect stroke=\"currentColor\" fill=\"none\"\n"
				"	x=\"%.2f\" y=\"%.2f\" width=\"%.2f\" height=\"%.2f\"/>\n",
				x, y - h, boxend - (x - xoffs) + 6, h);
			return;
		}
		if (strcmp(op, "boxmark") == 0) {
			if (cx > boxend)
				boxend = cx;
			return;
		}
		if (strcmp(op, "boxstart") == 0) {
			boxend = cx;
			return;
		}
		if (strcmp(op, "brace") == 0) {
			def_use(D_brace);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			h = pop_free_val() * 0.01;
			fprintf(fout,
				"<g transform=\"translate(%.2f,%.2f) scale(1,%.2f)\">\n"
				"	<use xlink:href=\"#brace\"/>\n"
				"</g>\n",
				x, y, h);
			return;
		}
		if (strcmp(op, "bracket") == 0) {
			setg(1);
			y = yoffs - pop_free_val() - 3;
			x = xoffs + pop_free_val() - 5;
			h = pop_free_val() + 2;
			fprintf(fout,
				"<path fill=\"currentColor\"\n"
				"	d=\"M%.2f %.2f\n"
				"	c10.5 1 12 -4.5 12 -3.5c0 1 -3.5 5.5 -8.5 5.5\n"
				"	v%.2f\n"
				"	c5 0 8.5 4.5 8.5 5.5c0 1 -1.5 -4.5 -12 -3.5\"/>\n",
				x, y, h);
			return;
		}
		if (strcmp(op, "breve") == 0) {
			setxysym(op, D_breve);
			return;
		}
		if (strcmp(op, "brth") == 0) {
			setg(1);
			y = yoffs - pop_free_val() - 6;
			x = xoffs + pop_free_val();
			fprintf(fout, "<text x=\"%.2f\" y=\"%.2f\" font-family=\"serif\" font-size=\"30\"\n"
				"	font-weight=\"bold\" font-style=\"italic\">,</text>\n",
				x, y);
			return;
		}
		break;
	case 'C':
		if (strcmp(op, "C") == 0) {
			float c1, c2, c3, c4;

curveto:
			path_def();
			y = pop_free_val();
			x = pop_free_val();
			c4 = yoffs - pop_free_val();
			c3 = xoffs + pop_free_val();
			c2 = yoffs - pop_free_val();
			c1 = xoffs + pop_free_val();
			path_print("\tC%.2f %.2f %.2f %.2f %.2f %.2f\n",
				c1, c2, c3, c4, xoffs + x, yoffs - y);
			cx = x;
			cy = y;
			return;
		}
		break;
	case 'c':
		if (strcmp(op, "cclef") == 0) {
			xysym(op, D_cclef);
			return;
		}
		if (strcmp(op, "csig") == 0) {
			xysym(op, D_csig);
			return;
		}
		if (strcmp(op, "ctsig") == 0) {
			xysym(op, D_ctsig);
			return;
		}
		if (strcmp(op, "coda") == 0) {
			xysym(op, D_coda);
			return;
		}
		if (strcmp(op, "closepath") == 0) {
			path_def();
			path_print("\tz");
			return;
		}
		if (strcmp(op, "composefont") == 0) {
			pop(BRK);
			pop(STR);
			return;
		}
		if (strcmp(op, "copy") == 0) {
			struct elt_s *e3;

			n = pop_free_val();
			if ((unsigned) n > 10) {
				fprintf(stderr, "svg copy: Too wide\n");
				ps_error = 1;
				return;
			}
			e = stack;
			e2 = NULL;
			while (--n >= 0) {
				if (!e)
					break;
				e3 = elt_dup(e);
				if (!e3)
					return;
				e3->next = e2;
				e2 = e3;
				e = e->next;
			}
			if (n >= 0) {
				fprintf(stderr, "svg copy: Stack empty\n");
				ps_error = 1;
				return;
			}
			while (e2) {
				e3 = e2->next;
				push(e2);
				e2 = e3;
			}
			return;
		}
		if (strcmp(op, "cos") == 0) {
			if (!stack || stack->type != VAL) {
				fprintf(stderr, "svg cos: Bad value\n");
				ps_error = 1;
				return;
			}
			stack->u.v = cos(stack->u.v * M_PI / 180);
			return;
		}
		if (strcmp(op, "cpu") == 0) {
			xysym(op, D_cpu);
			return;
		}
		if (strcmp(op, "cresc") == 0) {
			setg(1);
			y = yoffs - pop_free_val() - 5;
			x = xoffs + pop_free_val();
			w = pop_free_val();
			sym = ps_sym_lookup("defl");
			x += w;
			if ((int) sym->e->u.v & 1)
				fprintf(fout, "<path stroke=\"currentColor\" fill=\"none\"\n"
					"d=\"M%.2f %.2fl%.2f -2.2m0 -3.6l%.2f -2.2\"/>\n",
					x, y, -w, w);
			else
				fprintf(fout, "<path stroke=\"currentColor\" fill=\"none\"\n"
					"d=\"M%.2f %.2fl%.2f -4l%.2f -4\"/>\n",
					x, y, -w, w);
			return;
		}
		if (strcmp(op, "custos") == 0) {
			xysym(op, D_custos);
			return;
		}
		if (strcmp(op, "currentgray") == 0) {
			e = elt_new();
			if (!e)
				return;
			e->type = VAL;
			e->u.v = (float) gcur.rgb / 0xffffff;
			push(e);
			return;
		}
		if (strcmp(op, "currentpoint") == 0) {
			e = elt_new();
			if (!e)
				return;
			e->type = VAL;
			e->u.v = cx;
			push(e);
			e = elt_new();
			if (!e)
				return;
			e->type = VAL;
			e->u.v = cy;
			push(e);
			return;
		}
		if (strcmp(op, "curveto") == 0)
			goto curveto;
		if (strcmp(op, "cvi") == 0) {
			if (!stack || stack->type != VAL) {
				fprintf(stderr, "svg cvi: Bad value\n");
				ps_error = 1;
				return;
			}
			n = stack->u.v;
			stack->u.v = n;
			return;
		}
		if (strcmp(op, "cvx") == 0) {
			s = pop_free_str();
			if (!s || ((*s != '/') && (*s != '('))) {
				fprintf(stderr, "svg cvx: No / bad string\n");
				ps_error = 1;
				return;
			}
			*s = '{';
			svg_write(s, strlen(s));
			svg_write("}", 1);
			free(s);
			return;
		}
		break;
	case 'd':
		if (strcmp(op, "dacs") == 0) {
			setg(1);
			y = yoffs - pop_free_val() - 3;
			x = xoffs + pop_free_val();
			s = pop_free_str();
			if (!s) {
				fprintf(stderr, "svg dacs: No string\n");
				ps_error = 1;
				return;
			}
			fprintf(fout, "<text font-family=\"serif\" font-size=\"16\" font-weight=\"normal\" font-style=\"normal\"\n"
				"	x=\"%.2f\" y=\"%.2f\" text-anchor=\"middle\">%s</text>\n",
				x, y, s + 1);
			free(s);
			return;
		}
		if (strcmp(op, "def") == 0) {
			ps_exec("!");
			return;
		}
		if (strcmp(op, "dim") == 0) {
			setg(1);
			y = yoffs - pop_free_val() - 5;
			x = xoffs + pop_free_val();
			w = pop_free_val();
			sym = ps_sym_lookup("defl");
			if ((int) sym->e->u.v & 2)
				fprintf(fout, "<path stroke=\"currentColor\" fill=\"none\"\n"
					"d=\"M%.2f %.2fl%.2f -2.2m0 -3.6l%.2f -2.2\"/>\n",
					x, y, w, -w);
			else
				fprintf(fout, "<path stroke=\"currentColor\" fill=\"none\"\n"
					"d=\"M%.2f %.2fl%.2f -4l%.2f -4\"/>\n",
					x, y, w, -w);
			return;
		}
		if (strcmp(op, "div") == 0) {
			x = pop_free_val();
			if (!stack || stack->type != VAL || x == 0) {
				fprintf(stderr, "svg: Bad value for div\n");
				ps_error = 1;
				return;
			}
			stack->u.v /= x;
			return;
		}
		if (strcmp(op, "dnb") == 0) {
			xysym(op, D_dnb);
			return;
		}
		if (strcmp(op, "dplus") == 0) {
			xysym(op, D_dplus);
			return;
		}
		if (strcmp(op, "dSL") == 0) {
			float a1, a2, a3, a4, a5, a6, m1, m2;

			setg(1);
			m2 = yoffs - pop_free_val();
			m1 = xoffs + pop_free_val();
			a6 = pop_free_val();
			a5 = pop_free_val();
			a4 = pop_free_val();
			a3 = pop_free_val();
			a2 = pop_free_val();
			a1 = pop_free_val();
			fprintf(fout,
				"<path stroke=\"currentColor\" fill=\"none\" stroke-dasharray=\"5,5\"\n"
				"	d=\"M%.2f %.2fc%.2f %.2f %.2f %.2f %.2f %.2f\"/>\n",
					m1, m2, a1, -a2, a3, -a4, a5, -a6);
			return;
		}
		if (strcmp(op, "dt") == 0) {
			setg(1);
			sym = ps_sym_lookup("x");
			x = xoffs + sym->e->u.v;
			sym = ps_sym_lookup("y");
			y = yoffs - sym->e->u.v;
			y -= pop_free_val();
			x += pop_free_val();
			fprintf(fout,
				"<circle fill=\"currentColor\" cx=\"%.2f\" cy=\"%.2f\" r=\"1.2\"/>\n",
				x, y);
			return;
		}
		if (strcmp(op, "dlw") == 0) {
			gcur.linewidth = DLW;
			return;
		}
		if (strcmp(op, "dotbar") == 0) {
			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			h = pop_free_val();
			fprintf(fout,
				"<path stroke=\"currentColor\" fill=\"none\" stroke-dasharray=\"5,5\"\n"
				"	d=\"M%.2f %.2fv%.2f\"/>\n",
				x, y, -h);
			return;
		}
		if (strcmp(op, "dup") == 0) {
			if (!stack) {
				fprintf(stderr, "svg dup: Stack empty\n");
				ps_error = 1;
				return;
			}
			e = elt_dup(stack);
			if (e)
				push(e);
			return;
		}
		if (strcmp(op, "dft0") == 0) {
			xysym(op, D_dft0);
			return;
		}
		if (strcmp(op, "dsh0") == 0) {
			xysym(op, D_dsh0);
			return;
		}
		break;
	case 'e':
		if (strcmp(op, "emb") == 0) {
			xysym(op, D_emb);
			return;
		}
		if (strcmp(op, "eofill") == 0) {
			if (!path) {
				fprintf(stderr, "svg eofill: No path\n");
				ps_error = 1;
				return;
			}
			path_end();
			fprintf(fout, "\t\" fill-rule=\"evenodd\" fill=\"currentColor\"/>\n");
			return;
		}
		if (strcmp(op, "eq") == 0) {
			cond(C_EQ);
			return;
		}
		if (strcmp(op, "exch") == 0) {
			if (!stack || !stack->next) {
				fprintf(stderr, "svg exch: Stack empty\n");
				ps_error = 1;
				return;
			}
			e = stack->next;
			stack->next = e->next;
			e->next = stack;
			stack = e;
			return;
		}
		if (strcmp(op, "exec") == 0) {
			e = pop(SEQ);
			if (!e)
				return;
			seq_exec(e);
			elt_free(e);
			return;
		}
		break;
	case 'F':
		if (sscanf(op, "F%d", &n) == 1) {
			if (strlen(fontnames[n]) >= sizeof gcur.font_n - 1) {
				fprintf(stderr, "svg %s: Font name too long\n",
						op);
			}
			strncpy(gcur.font_n, fontnames[n], sizeof gcur.font_n);
			gcur.font_n[sizeof gcur.font_n - 1] = '\0';
			gcur.font_s = pop_free_val();
			return;
		}
		break;
	case 'f':
		if (strcmp(op, "false") == 0) {
			e = elt_new();
			if (!e)
				return;
			e->type = VAL;
			e->u.v = 0;
			push(e);
			return;
		}
		if (strcmp(op, "fill") == 0) {
			if (!path) {
				fprintf(stderr, "svg fill: No path\n");
//				ps_error = 1;
				return;
			}
			path_end();
			fprintf(fout, "\t\" fill=\"currentColor\"/>\n");
			return;
		}
		if (strcmp(op, "findfont") == 0) {
			s = pop_free_str();
			if (!s
			 || *s != '/'
			 || strlen(s) >= sizeof gcur.font_n) {
				fprintf(stderr, "svg selectfont: No / bad font\n");
				ps_error = 1;
				return;
			}
			strcpy(gcur.font_n, s + 1);
			free(s);
			return;
		}
		if (strcmp(op, "fng") == 0) {
			setg(1);
			y = yoffs - pop_free_val() - 1;
			x = xoffs + pop_free_val() - 3;
			s = pop_free_str();
			if (!s) {
				fprintf(stderr, "svg fng: No string\n");
				ps_error = 1;
				return;
			}
			fprintf(fout, "<text font-family=\"Bookman\" font-size=\"8\" font-weight=\"normal\" font-style=\"normal\"\n"
				"	x=\"%.2f\" y=\"%.2f\">%s</text>\n",
				x, y, s + 1);
			free(s);
			return;
		}
		if (strcmp(op, "for") == 0) {
			float init, incr, limit;

			e = pop(SEQ);			/* proc */
			if (!e)
				return;
			limit = pop_free_val();
			incr = pop_free_val();
			init = pop_free_val();
			if (incr == 0
			 || (limit - init) / incr > 100) {
				fprintf(stderr, "svg for: Bad values\n");
				ps_error = 1;
				return;
			}
			if (incr > 0) {
				while (init <= limit) {
					e2 = elt_new();
					if (!e2)
						break;
					e2->type = VAL;
					e2->u.v = init;
					push(e2);
					if (seq_exec(e) != 0)
						break;
					init += incr;
				}
			} else {
				while (init >= limit) {
					e2 = elt_new();
					if (!e2)
						break;
					e2->type = VAL;
					e2->u.v = init;
					push(e2);
					if (seq_exec(e) != 0)
						break;
					init += incr;
				}
			}
			elt_free(e);
			return;
		}
		if (strcmp(op, "forall") == 0) {
			struct elt_s *e3;
			unsigned char *p;

			e = pop(SEQ);			/* proc */
			if (!e)
				return;
			e2 = stack;			/* array/string */
			if (!e2) {
				fprintf(stderr, "svg forall: Stack empty\n");
				ps_error = 1;
				return;
			}
			stack = e2->next;
			switch (e2->type) {
			case STR:
				p = (unsigned char *) &e2->u.s[1];
				while (*p != '\0') {
					e3 = elt_new();
					if (!e3)
						return;
					e3->u.v = *p++;
					push(e3);
					if (seq_exec(e) != 0)
						break;
				}
				break;
			case BRK:
				for (e3 = e2->u.e; e3; e3 = e3->next) {
					struct elt_s *e4;

					e4 = elt_dup(e3);
					push(e4);
					if (seq_exec(e) != 0)
						break;
				}
				break;
			default:
				fprintf(stderr, "svg forall: Bad any\n");
				ps_error = 1;
				return;
			}
			elt_free(e);
			elt_free(e2);
			return;
		}
		if (strcmp(op, "ft0") == 0) {
			xysym(op, D_ft0);
			return;
		}
		if (strcmp(op, "ft1") == 0) {
			xysym(op, D_ft1);
			return;
		}
		if (strcmp(op, "ft4") == 0) {
			n = pop_free_val();
			if (n == 1)
				xysym(op, D_ft1);
			else
				xysym(op, D_ft513);
			return;
		}
		if (strcmp(op, "ft513") == 0) {
			xysym(op, D_ft513);
			return;
		}
		break;
	case 'g':
		if (strcmp(op, "gcshow") == 0) {
			show('s');
			return;
		}
		if (strcmp(op, "ge") == 0) {
			cond(C_GE);
			return;
		}
		if (strcmp(op, "get") == 0) {
			n = pop_free_val();
			if (!stack) {
				fprintf(stderr, "svg get: Stack empty\n");
				ps_error = 1;
				return;
			}
			switch (stack->type) {
			case VAL:
				if (n != 0) {
					fprintf(stderr, "svg get: Out of bounds\n");
					ps_error = 1;
					return;
				}
				return;
			case STR:
				s = stack->u.s;
				if (*s != '(') {
					fprintf(stderr, "svg get: Not a string\n");
					ps_error = 1;
					return;
				}
				if ((unsigned) n >= strlen(s) - 1) {
					fprintf(stderr, "svg get: Out of bounds\n");
					ps_error = 1;
					return;
				}
				stack->type = VAL;
				stack->u.v = s[n + 1];
				free(s);
				return;
			}
			e = stack->u.e;
			e2 = NULL;
			while (--n >= 0) {
				if (!e)
					break;
				e2 = e;
				e = e->next;
			}
			if (!e) {
				fprintf(stderr, "svg get: Out of bounds\n");
				ps_error = 1;
				return;
			}
			if (!e2)
				stack->u.e = e->next;
			else
				e2->next = e->next;
			e->next = stack->next;
			elt_free(stack);
			stack = e;
			return;
		}
		if (strcmp(op, "getinterval") == 0) {
			int count;

			count = pop_free_val();
			n = pop_free_val();
			s = pop_free_str();
			if (!s || *s != '(') {
				fprintf(stderr, "svg getinterval: No string\n");
				ps_error = 1;
				return;
			}
			if ((unsigned) n >= strlen(s)
			 || (unsigned) count >= strlen(s) - n) {
				fprintf(stderr, "svg getinterval: Out of bounds\n");
				ps_error = 1;
				return;
			}
			e = elt_new();
			if (!e)
				return;
			e->type = STR;
			e->u.s = malloc(count + 2);
			e->u.s[0] = '(';
			memcpy(&e->u.s[1], &s[n + 1], count);
			e->u.s[count + 1] = '\0';
			push(e);
			free(s);
			return;
		}
		if (strcmp(op, "ghd") == 0) {
			setxysym(op, D_ghd);
			return;
		}
		if (strcmp(op, "ghl") == 0) {
			xysym(op, D_ghl);
			return;
		}
		if (strcmp(op, "gt") == 0) {
			cond(C_GT);
			return;
		}
		if (strcmp(op, "gu") == 0
		 || strcmp(op, "gd") == 0) {
			stem(op);
			return;
		}
		if (strcmp(op, "gua") == 0
		 || strcmp(op, "gda") == 0) {
			acciac(op);
			return;
		}
		if (strcmp(op, "grestore") == 0) {
			if (nsave <= 0) {
				fprintf(stderr, "svg grestore: No gsave\n");
				ps_error = 1;
				return;
			}
			setg(1);
			nsave--;
			cx = gsave[nsave].cx;
			cy = gsave[nsave].cy;
			xoffs = gsave[nsave].xoffs;
			yoffs = gsave[nsave].yoffs;
			x_rot = gsave[nsave].x_rot;
			y_rot = gsave[nsave].y_rot;
			memcpy(&gcur, &gsave[nsave].gc, sizeof gcur);
			return;
		}
		if (strcmp(op, "grm") == 0) {
			xysym(op, D_grm);
			return;
		}
		if (strcmp(op, "gsave") == 0) {
			if (nsave >= (int) (sizeof gsave / sizeof gsave[0])) {
				fprintf(stderr, "svg grestore: Too many gsave's\n");
				ps_error = 1;
				return;
			}
			setg(1);
			memcpy(&gsave[nsave].gc, &gcur, sizeof gsave[0].gc);
			gsave[nsave].cx = cx;
			gsave[nsave].cy = cy;
			gsave[nsave].xoffs = xoffs;
			gsave[nsave].yoffs = yoffs;
			gsave[nsave].x_rot = x_rot;
			gsave[nsave].y_rot = y_rot;
			nsave++;
			return;
		}
		if (strcmp(op, "gsl") == 0) {
			float a1, a2, a3, a4, a5, a6, m1, m2;

			setg(1);
			m2 = yoffs - pop_free_val();
			m1 = xoffs + pop_free_val();
			a6 = pop_free_val();
			a5 = pop_free_val();
			a4 = pop_free_val();
			a3 = pop_free_val();
			a2 = pop_free_val();
			a1 = pop_free_val();
			fprintf(fout,
				"<path stroke=\"currentColor\" fill=\"none\"\n"
				"	d=\"M%.2f %.2fc%.2f %.2f %.2f %.2f %.2f %.2f\"/>\n",
					m1, m2, a1, -a2, a3, -a4, a5, -a6);
			return;
		}
		if (strcmp(op, "gxshow") == 0) {
			show('x');
			return;
		}
		break;
	case 'H':
		if (strcmp(op, "Hd") == 0) {
			setxysym(op, D_Hd);
			return;
		}
		if (strcmp(op, "HD") == 0) {
			setxysym(op, D_HD);
			return;
		}
		if (strcmp(op, "HDD") == 0) {
			setxysym(op, D_HDD);
			return;
		}
		break;
	case 'h':
		if (strcmp(op, "hd") == 0) {
			setxysym(op, D_hd);
			return;
		}
		if (strcmp(op, "hl") == 0) {
			xysym(op, D_hl);
			return;
		}
		if (strcmp(op, "hl1") == 0) {
			xysym(op, D_hl1);
			return;
		}
		if (strcmp(op, "hl2") == 0) {
			xysym(op, D_hl2);
			return;
		}
		if (strcmp(op, "hld") == 0) {
			xysym(op, D_hld);
			return;
		}
		if (strcmp(op, "hyph") == 0) {
			int d;

			setg(1);
			y = pop_free_val();
			x = pop_free_val();
			w = pop_free_val();
			d = 25 + (int) w / 20 * 3;
			n = (w - 15.) / d;
			x += (w - d * n - 5) / 2;
			fprintf(fout, "<path stroke=\"currentColor\" fill=\"none\" stroke-width=\"1.2\"\n"
				"	stroke-dasharray=\"5,%d\"\n"
				"	d=\"M%.2f %.2fh%d\"/>\n",
				d - 5,
				xoffs + x, yoffs - y - gcur.font_s * 0.3, d * n + 5);
			return;
		}
		break;
	case 'i':
		if (strcmp(op, "idiv") == 0) {
			n = pop_free_val();
			if (!stack || stack->type != VAL || n == 0) {
				fprintf(stderr, "svg idiv: Bad value\n");
				ps_error = 1;
				return;
			}
			n = (int) stack->u.v / n;
			stack->u.v = n;
			return;
		}
		if (strcmp(op, "if") == 0) {
			e = pop(SEQ);		/* sequence */
			if (!e)
				return;
			n = pop_free_val();	/* condition */
			if (n != 0)
				seq_exec(e);
			elt_free(e);
			return;
		}
		if (strcmp(op, "ifelse") == 0) {
			e2 = pop(SEQ);		/* sequence 2 */
			e = pop(SEQ);		/* sequence 1 */
			if (!e || !e2)
				return;
			n = pop_free_val();	/* condition */
			if (n != 0)
				seq_exec(e);
			else
				seq_exec(e2);
			elt_free(e);
			elt_free(e2);
			return;
		}
		if (strcmp(op, "imsig") == 0) {
			xysym(op, D_imsig);
			return;
		}
		if (strcmp(op, "iMsig") == 0) {
			xysym(op, D_iMsig);
			return;
		}
		if (strcmp(op, "index") == 0) {
			n = pop_free_val();
			e = stack;
			while (--n >= 0) {
				if (!e)
					break;
				e = e->next;
			}
			if (!e) {
				fprintf(stderr, "svg index: Stack empty\n");
				ps_error = 1;
				return;
			}
			e = elt_dup(e);
			if (!e)
				return;
			push(e);
			return;
		}
		break;
	case 'j':
		if (strcmp(op, "jshow") == 0) {
			show('j');
			return;
		}
		break;
	case 'L':
		if (strcmp(op, "L") == 0) {
lineto:
			path_def();
			y = pop_free_val();
			x = pop_free_val();
			if (x == cx)
				path_print("\tv%.2f\n", cy - y);
			else if (y == cy)
				path_print("\th%.2f\n", x - cx);
			else
				path_print("\tl%.2f %.2f\n",
					x - cx, cy - y);
			cx = x;
			cy = y;
			return;
		}
	case 'l':
		if (strcmp(op, "le") == 0) {
			cond(C_LE);
			return;
		}
		if (strcmp(op, "lt") == 0) {
			cond(C_LT);
			return;
		}
		if (strcmp(op, "length") == 0) {
			s = pop_free_str();
			if (!s || *s != '(') {
				fprintf(stderr, "svg length: No string\n");
				ps_error = 1;
				return;
			}
			e = elt_new();
			if (!e)
				return;
			e->type = VAL;
			e->u.v = strlen(s + 1);
			push(e);
			free(s);
			return;
		}
		if (strcmp(op, "lineto") == 0)
			goto lineto;
		if (strcmp(op, "lmrd") == 0) {
			xysym(op, D_lmrd);
			return;
		}
		if (strcmp(op, "load") == 0) {
			s = pop_free_str();
			if (!s || *s != '/') {
				fprintf(stderr, "svg load: No / bad symbol\n");
				ps_error = 1;
				return;
			}
			sym = ps_sym_lookup(s + 1);
			if (!sym) {
				e = elt_new();
				if (!e)
					return;
				e->type = STR;
				e->u.s = strdup(s);
				e->u.s[0] = ' ';	/* internal */
			} else {
				e = elt_dup(sym->e);
				if (!e)
					return;
			}
			free(s);
			push(e);
			return;
		}
		if (strcmp(op, "longa") == 0) {
			setxysym(op, D_longa);
			return;
		}
		if (strcmp(op, "lphr") == 0) {
			xysym(op, D_lphr);
			return;
		}
		if (strcmp(op, "ltr") == 0) {
			arp_ltr('l');
			return;
		}
		if (strcmp(op, "lyshow") == 0) {
			show('s');
			return;
		}
		break;
	case 'M':
		if (strcmp(op, "M") == 0) {
moveto:
			cy = pop_free_val();
			cx = pop_free_val();
			if (path) {
				path_print("\tM%.2f %.2f\n", xoffs + cx, yoffs - cy);
			} else if (g == 2) {
				fputs("</text>\n", fout);
				g = 1;
			}
			return;
		}
		break;
	case 'm':
		if (strcmp(op, "moveto") == 0)
			goto moveto;
		if (strcmp(op, "mphr") == 0) {
			xysym(op, D_mphr);
			return;
		}
		if (strcmp(op, "mod") == 0) {
			x = pop_free_val();
			if (!stack || stack->type != VAL || x == 0) {
				fprintf(stderr, "svg: Bad value for mod\n");
				ps_error = 1;
				return;
			}
			n = (int) stack->u.v % (int) x;
			stack->u.v = n;
			return;
		}
		if (strcmp(op, "mrep") == 0) {
			xysym(op, D_mrep);
			return;
		}
		if (strcmp(op, "mrep2") == 0) {
			xysym(op, D_mrep2);
			return;
		}
		if (strcmp(op, "mrest") == 0) {
			def_use(D_mrest);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			s = pop_free_str();
			if (!s) {
				fprintf(stderr, "svg: No string\n");
				ps_error = 1;
				return;
			}
			fprintf(fout, "<use x=\"%.2f\" y=\"%.2f\" xlink:href=\"#mrest\"/>\n"
				"<text font-family=\"serif\" font-size=\"15\" font-weight=\"bold\" font-style=\"normal\"\n"
				"	x=\"%.2f\" y=\"%.2f\" text-anchor=\"middle\">%s</text>\n",
				x, y, x, y - 28, s + 1);
			free(s);
			return;
		}
		if (strcmp(op, "mul") == 0) {
			x = pop_free_val();
			if (!stack || stack->type != VAL) {
				fprintf(stderr, "svg: Bad value for mul\n");
				ps_error = 1;
				return;
			}
			stack->u.v *= x;
			return;
		}
		break;
	case 'n':
		if (strcmp(op, "ne") == 0) {
			cond(C_NE);
			return;
		}
		if (strcmp(op, "neg") == 0) {
			if (!stack || stack->type != VAL) {
				fprintf(stderr, "svg: Bad value for neg\n");
				ps_error = 1;
				return;
			}
			stack->u.v = -stack->u.v;
			return;
		}
		if (strcmp(op, "newpath") == 0) {
			path_def();
			return;
		}
		if (strcmp(op, "nt0") == 0) {
			xysym(op, D_nt0);
			return;
		}
		break;
	case 'o':
		if (strcmp(op, "octl") == 0
		 || strcmp(op, "octu") == 0) {
			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			if (op[3] == 'l')
				x -= 3.5;
			else
				x -= 2.5;
			fprintf(fout, "<text font-family=\"serif\" font-size=\"12\" font-weight=\"normal\" font-style=\"normal\"\n"
				"	x=\"%.2f\" y=\"%.2f\">8</text>\n",
				x, y);
			return;
		}
		if (strcmp(op, "opend") == 0) {
			xysym(op, D_opend);
			return;
		}
		if (strcmp(op, "or") == 0) {
			x = pop_free_val();
			if (!stack || stack->type != VAL) {
				fprintf(stderr, "svg or: Bad value\n");
				ps_error = 1;
				return;
			}
			stack->u.v = (int) x & (int) stack->u.v;
			return;
		}
		break;
	case 'p':
		if (strcmp(op, "pclef") == 0) {
			def_use(D_pclef);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			fprintf(fout, "<use x=\"%.2f\" y=\"%.2f\" xlink:href=\"#%s\"/>\n",
				x, y, op);
			return;
		}
		if (strcmp(op, "pf") == 0) {
			setg(1);
			y = yoffs - pop_free_val() - 5;
			x = xoffs + pop_free_val();
			s = pop_free_str();
			if (!s) {
				fprintf(stderr, "svg pf: No string\n");
				ps_error = 1;
				return;
			}
			fprintf(fout, "<text font-family=\"serif\" font-size=\"16\" font-weight=\"bold\" font-style=\"italic\"\n"
				"	x=\"%.2f\" y=\"%.2f\">%s</text>\n",
				x, y, s + 1);
			free(s);
			return;
		}
		if (strcmp(op, "pmsig") == 0) {
			xysym(op, D_pmsig);
			return;
		}
		if (strcmp(op, "pMsig") == 0) {
			xysym(op, D_pMsig);
			return;
		}
		if (strcmp(op, "pop") == 0) {
			if (!stack) {
				fprintf(stderr, "svg pop: Stack empty\n");
				ps_error = 1;
				return;
			}
			e = pop(stack->type);
			elt_free(e);
			return;
		}
		if (strcmp(op, "pshhd") == 0) {
			setxysym(op, D_pshhd);
			return;
		}
		if (strcmp(op, "pdshhd") == 0) {
			setxysym("pshhd", D_pshhd);
			return;
		}
		if (strcmp(op, "pfthd") == 0) {
			setxysym(op, D_pfthd);
			return;
		}
		if (strcmp(op, "pdfthd") == 0) {
			setxysym("pfthd", D_pfthd);
			return;
		}
#if 0
//fixme: cannot work because duplication...
		if (strcmp(op, "put") == 0) {
			int v;

			v = pop_free_val();
			n = pop_free_val();
			if (!stack) {
				fprintf(stderr, "svg put: Stack empty\n");
				ps_error = 1;
				return;
			}
			s = pop_free_str();
			if (!s || *s != '(') {
				fprintf(stderr, "svg put: No string\n");
				ps_error = 1;
				return;
			}
			if ((unsigned) n >= strlen(s) - 1) {
				fprintf(stderr, "svg put: Out of bounds\n");
				ps_error = 1;
				return;
			}
//fixme: should keep the original string...
			s[n + 1] = v;
			free(s);
			return;
		}
#endif
		break;
	case 'R':
		if (strcmp(op, "RC") == 0) {
			float c1, c2, c3, c4;

rcurveto:
			path_def();
			y = pop_free_val();
			x = pop_free_val();
			c4 = pop_free_val();
			c3 = pop_free_val();
			c2 = pop_free_val();
			c1 = pop_free_val();
			path_print("\tc%.2f %.2f %.2f %.2f %.2f %.2f\n",
				c1, -c2, c3, -c4, x, -y);
			cx += x;
			cy += y;
			return;
		}
		if (strcmp(op, "RL") == 0) {
rlineto:
			path_def();
			y = pop_free_val();
			x = pop_free_val();
			if (x == 0)
				path_print("\tv%.2f\n", -y);
			else if (y == 0)
				path_print("\th%.2f\n", x);
			else
				path_print("\tl%.2f %.2f\n", x, -y);
			cx += x;
			cy += y;
			return;
		}
		if (strcmp(op, "RM") == 0) {
rmoveto:
			y = pop_free_val();
			x = pop_free_val();
			if (path) {
				path_print("\tm%.2f %.2f\n", x, -y);
			} else if (g == 2) {
				fputs("</text>\n", fout);
				g = 1;
			}
			cx += x;
			cy += y;
			return;
		}
		break;
	case 'r':
		if (strcmp(op, "r00") == 0) {
			setxysym(op, D_r00);
			return;
		}
		if (strcmp(op, "r0") == 0) {
			setxysym(op, D_r0);
			return;
		}
		if (strcmp(op, "r1") == 0) {
			setxysym(op, D_r1);
			return;
		}
		if (strcmp(op, "r2") == 0) {
			setxysym(op, D_r2);
			return;
		}
		if (strcmp(op, "r4") == 0) {
			setxysym(op, D_r4);
			return;
		}
		if (strcmp(op, "r8") == 0) {
			setxysym(op, D_r8);
			return;
		}
		if (strcmp(op, "r16") == 0) {
			setxysym(op, D_r16);
			return;
		}
		if (strcmp(op, "r32") == 0) {
			setxysym(op, D_r32);
			return;
		}
		if (strcmp(op, "r64") == 0) {
			setxysym(op, D_r64);
			return;
		}
		if (strcmp(op, "r128") == 0) {
			setxysym(op, D_r128);
			return;
		}
		if (strcmp(op, "rdots") == 0) {
			xysym(op, D_rdots);
			return;
		}
		if (strcmp(op, "rcurveto") == 0)
			goto rcurveto;
		if (strcmp(op, "rlineto") == 0)
			goto rlineto;
		if (strcmp(op, "rmoveto") == 0)
			goto rmoveto;
		if (strcmp(op, "roll") == 0) {
			int i, j;

			j = pop_free_val();
			n = pop_free_val();
			if (n <= 0) {
				fprintf(stderr, "svg roll: Invalid value\n");
				ps_error = 1;
				return;
			}
			if (j > 0) {
				j = j % n;
				if (j > n / 2)
					j -= n;
			} else if (j < 0) {
				j = -(-j % n);
				if (j < -n / 2)
					j += n;
			}
			if (j == 0)
				return;
			e2 = stack;		/* check the stack */
			i = n;
			for (;;) {
				if (!e2) {
					fprintf(stderr, "svg roll: Stack empty\n");
					ps_error = 1;
					return;
				}
				if (--i <= 0)
					break;
				e2 = e2->next;
			}
			if (j > 0) {
				while (j-- > 0) {
					e = stack;
					stack = e->next;
					e->next = e2->next;
					e2->next = e;
					e2 = e;
				}
				return;
			}
			while (j++ < 0) {
				e = stack;
				for (i = 0; i < n - 2; i++)
					e = e->next;
				e2 = e->next;
				e->next = e2->next;
				e2->next = stack;
				stack = e2;
			}
			return;
		}
		if (strcmp(op, "repbra") == 0) {
			int i;

			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			w = pop_free_val();
			i = pop_free_val();
			h = pop_free_val();
			s = pop_free_str();
			if (!s) {
				fprintf(stderr, "svg repbra: No string\n");
				ps_error = 1;
				return;
			}
			fprintf(fout,
				"<text x=\"%.2f\" y=\"%.2f\">",
				x + 4, y - h);
			xml_str_out(s + 1);
			fprintf(fout,
				"</text>\n"
				"<path stroke=\"currentColor\" fill=\"none\"\n"
				"	d=\"M%.2f %.2f",
				x, y);
			if (i != 1)
				fprintf(fout, "v20M%.2f %.2f", x, y);
			fprintf(fout, "h%.2f", w);
			if (i != 0)
				fprintf(fout, "v20");
			fprintf(fout, "\"/>\n");
			free(s);
			return;
		}
		if (strcmp(op, "repeat") == 0) {
			e = pop(SEQ);		/* sequence */
			if (!e)
				return;
			n = pop_free_val();	/* n times */
			if ((unsigned) n >= 100) {
				fprintf(stderr, "svg repeat: Too high value\n");
				ps_error = 1;
			}
			while (--n >= 0) {
				if (seq_exec(e))
					break;		/* exit */
				if (ps_error)
					break;
			}
			elt_free(e);
			return;
		}
		if (strcmp(op, "rotate") == 0) {
			setg(0);
#if 1
			h = 360 - pop_free_val();
			gcur.rotate += h;
#else
			h = pop_free_val();
			gcur.rotate -= h;
#endif
			h = h * M_PI / 180;
			x = cx;
			cx = x * cos(h) + cy * sin(h);
			cy = -x * sin(h) + cy * cos(h);
			return;
		}
		break;
	case 'S':
		if (strcmp(op, "SL") == 0) {
			float c1, c2, c3, c4, c5, c6, l1, l2;
			float a1, a2, a3, a4, a5, a6, m1, m2;

			setg(1);
			m2 = yoffs - pop_free_val();
			m1 = xoffs + pop_free_val();
			a6 = pop_free_val();
			a5 = pop_free_val();
			a4 = pop_free_val();
			a3 = pop_free_val();
			a2 = pop_free_val();
			a1 = pop_free_val();
			l2 = pop_free_val();
			l1 = pop_free_val();
			c6 = pop_free_val();
			c5 = pop_free_val();
			c4 = pop_free_val();
			c3 = pop_free_val();
			c2 = pop_free_val();
			c1 = pop_free_val();
			fprintf(fout,
				"<path fill=\"currentColor\"\n"
				"	d=\"M%.2f %.2fc%.2f %.2f %.2f %.2f %.2f %.2f\n"
				"	l%.2f %.2fc%.2f %.2f %.2f %.2f %.2f %.2f\"/>\n",
				m1, m2, a1, -a2, a3, -a4, a5, -a6,
				l1, -l2, c1, -c2, c3, -c4, c5, -c6);
			return;
		}
		if (strcmp(op, "SLW") == 0) {
			gcur.linewidth = pop_free_val();
			return;
		}
		break;
	case 's':
		if (strcmp(op, "scale") == 0) {
			y = pop_free_val();
			x = pop_free_val();
			xoffs /= x;
			yoffs /= y;
			cx /= x;
			cy /= y;
			gcur.xscale *= x;
			gcur.yscale *= y;
			return;
		}
		if (strcmp(op, "scalefont") == 0) {
			w = pop_free_val();
			gcur.font_s = w;
			return;
		}
		if (strcmp(op, "search") == 0) {
			char *p;

			e = pop(STR);			/* seek */
			e2 = pop(STR);			/* string */
			if (!e || !e2
			 || e->u.s[0] != '(' || e2->u.s[0] != '(') {
				fprintf(stderr, "svg search: No string\n");
				ps_error = 1;
				return;
			}
			p = strstr(&e2->u.s[1], &e->u.s[1]);
			if (p) {
				struct elt_s *e3;
				int l1, l2, l3;

				l1 = p - e2->u.s;
				l2 = strlen(e->u.s);
				l3 = strlen(e2->u.s) - l2 - l1 + 2;
				e3 = elt_new();
				if (!e3)
					return;
				e3->type = STR;
				e3->u.s = malloc(l3);
				e3->u.s[0] = '(';
				memcpy(&e3->u.s[1],
					&e2->u.s[l1 + l2 - 2],
					l3 - 1);
				e3->u.s[l1 + l2 - 1] = '\0';
				push(e3);
				push(e);
				e2->u.s[l1] = '\0';
				push (e2);
				e = elt_new();
				if (!e)
					return;
				e->type = VAL;
				e->u.v = 1;
			} else {
				push(e2);
				free(e->u.s);
				e->type = VAL;
				e->u.v = 0;
			}
			push(e);
			return;
		}
		if (strcmp(op, "selectfont") == 0) {
			w = pop_free_val();
			s = pop_free_str();
			if (!s
			 || *s != '/'
			 || strlen(s) >= sizeof gcur.font_n) {
				fprintf(stderr, "svg selectfont: No / bad font\n");
				ps_error = 1;
				return;
			}
			strcpy(gcur.font_n, s + 1);
			gcur.font_s = w;
			free(s);
			return;
		}
		if (strcmp(op, "sep0") == 0) {
			x = pop_free_val();
			w = pop_free_val();
			fprintf(fout,
				"<path stroke=\"currentColor\" fill=\"none\"\n"
				"	d=\"M%.2f %.2fh%.2f\"/>\n",
					xoffs + x, yoffs, w);
			return;
		}
		if (strcmp(op, "setdash") == 0) {
			char *p;

			n = pop_free_val();
			e = pop(BRK);
			if (!e) {
				fprintf(stderr, "svg setdash: Bad pattern\n");
				ps_error = 1;
				return;
			}
			e = e->u.e;
			if (!e) {
				gcur.dash[0] = '\0';
				return;
			}
			p = gcur.dash;
			if (n != 0)
				p += sprintf(p, " stroke-dashoffset=\"%d\"", n);
			p += sprintf(p, " stroke-dasharray=\"");
			do {
				if (e->type != VAL) {
					fprintf(stderr, "svg setdash: Bad pattern type\n");
					ps_error = 1;
					return;
				}
				if (p >= &gcur.dash[sizeof gcur.dash] - 10) {
					fprintf(stderr, "svg setdash: Pattern too wide\n");
					ps_error = 1;
					return;
				}
				p += sprintf(p, "%d,", (int) e->u.v);
				e = e->next;
			} while (e);
			p--;
			sprintf(p, "\"");
			return;
		}
		if (strcmp(op, "setfont") == 0) {
			return;
		}
		if (strcmp(op, "setgray") == 0) {
			gcur.rgb = pop_free_val() * 0xffffff;
			return;
		}
		if (strcmp(op, "setlinewidth") == 0) {
			gcur.linewidth = pop_free_val();
			return;
		}
//fixme: use 'use' for flags
		if (strcmp(op, "sfu") == 0) {
			setg(1);
			h = pop_free_val();
			n = pop_free_val();
			sym = ps_sym_lookup("x");
			x = xoffs + sym->e->u.v + 3.5;
			sym = ps_sym_lookup("y");
			y = yoffs - sym->e->u.v;
			fprintf(fout,
				"<path d=\"M%.2f %.2fv%.2f\" stroke=\"currentColor\" fill=\"none\"/>\n"
				"<path fill=\"currentColor\"\n"
				"	d=\"",
				x, y, -h);
			if (n == 1) {
				fprintf(fout,
					"	M%.2f %.2fc0.6 5.6 9.6 9 5.6 18.4\n"
					"	c1.6 -6 -1.3 -11.6 -5.6 -12.8\n",
					x, y - h);
			} else {
				y -= h;
				while (--n >= 0) {
					fprintf(fout,
						"M%.2f %.2fc0.9 3.7 9.1 6.4 6 12.4\n"
						"	c1 -5.4 -4.2 -8.4 -6 -8.4\n",
						x, y);
					y += 5.4;
				}
			}
			fprintf(fout, "\"/>\n");
			return;
		}
		if (strcmp(op, "sfd") == 0) {
			setg(1);
			h = pop_free_val();
			n = pop_free_val();
			sym = ps_sym_lookup("x");
			x = xoffs + sym->e->u.v - 3.5;
			sym = ps_sym_lookup("y");
			y = yoffs - sym->e->u.v;
			fprintf(fout,
				"<path d=\"M%.2f %.2fv%.2f\" stroke=\"currentColor\" fill=\"none\"/>\n"
				"<path fill=\"currentColor\"\n"
				"	d=\"",
				x, y, -h);
			if (n == 1) {
				fprintf(fout,
					"M%.2f %.2fc0.6 -5.6 9.6 -9 5.6 -18.4\n"
					"	c1.6 6 -1.3 11.6 -5.6 12.8\n",
					x, y - h);
			} else {
				y -= h;
				while (--n >= 0) {
					fprintf(fout,
					"M%.2f %.2fc0.9 -3.7 9.1 -6.4 6 -12.4\n"
					"	c1 5.4 -4.2 8.4 -6 8.4\n",
					x, y);
					y -= 5.4;
				}
			}
			fprintf(fout, "\"/>\n");
			return;
		}
		if (strcmp(op, "sfs") == 0) {
			setg(1);
			h = pop_free_val();
			n = pop_free_val();
			sym = ps_sym_lookup("x");
			x = xoffs + sym->e->u.v;
			sym = ps_sym_lookup("y");
			y = yoffs - sym->e->u.v - 1;
			if (h > 0) {
				x += 3.5;
				y -= 1;
				fprintf(fout,
					"<path d=\"M%.2f %.2fv%.2f\" stroke=\"currentColor\" fill=\"none\"/>\n"
					"<path fill=\"currentColor\"\n"
					"	d=\"",
					x, y, -h + 1);
				y -= h - 1;
				while (--n >= 0) {
					fprintf(fout,
						"M%.2f %.2fl7 3.2 0 3.2 -7 -3.2z\n",
						x, y);
					y += 5.4;
				}
			} else {
				x -= 3.5;
				y += 1;
				fprintf(fout,
					"<path d=\"M%.2f %.2fv%.2f\" stroke=\"currentColor\" fill=\"none\"/>\n"
					"<path fill=\"currentColor\"\n"
					"	d=\"",
					x, y, -h - 1);
				y -= h + 1;
				while (--n >= 0) {
					fprintf(fout,
						"M%.2f %.2fl7 -3.2 0 -3.2 -7 3.2z\n",
						x, y);
					y -= 5.4;
				}
			}
			fprintf(fout, "\"/>\n");
			return;
		}
		if (strcmp(op, "sgu") == 0) {
			setg(1);
			h = pop_free_val();
			n = pop_free_val();
			sym = ps_sym_lookup("x");
			x = xoffs + sym->e->u.v + 1.6;
			sym = ps_sym_lookup("y");
			y = yoffs - sym->e->u.v;
			fprintf(fout,
				"<path d=\"M%.2f %.2fv%.2f\" stroke=\"currentColor\" fill=\"none\"/>\n"
				"<path fill=\"currentColor\"\n"
				"	d=\"",
				x, y, -h);
			if (n == 1) {
				fprintf(fout,
					"M%.2f %.2fc0.6 3.4 5.6 3.8 3 10\n"
					"	c1.2 -4.4 -1.4 -7 -3 -7\n",
					x, y - h);
			} else {
				y -= h;
				while (--n >= 0) {
					fprintf(fout,
						"M%.2f %.2fc1 3.2 5.6 2.8 3.2 8\n"
						"	c1.4 -4.8 -2.4 -5.4 -3.2 -5.2\n",
					x, y);
					y += 3.5;
				}
			}
			fprintf(fout, "\"/>\n");
			return;
		}
		if (strcmp(op, "sgd") == 0) {
			setg(1);
			h = pop_free_val();
			n = pop_free_val();
			sym = ps_sym_lookup("x");
			x = xoffs + sym->e->u.v - 1.6;
			sym = ps_sym_lookup("y");
			y = yoffs - sym->e->u.v;
			fprintf(fout,
				"<path d=\"M%.2f %.2fv%.2f\" stroke=\"currentColor\" fill=\"none\"/>\n"
				"<path fill=\"currentColor\"\n"
				"	d=\"",
				x, y, -h);
			if (n == 1) {
				fprintf(fout,
					"M%.2f %.2fc0.6 -3.4 5.6 -3.8 3 -10\n"
					"	c1.2 4.4 -1.4 7 -3 7\n",
					x, y - h);
			} else {
				y -= h;
				while (--n >= 0) {
					fprintf(fout,
						"M%.2f %.2fc1 -3.2 5.6 -2.8 3.2 -8\n"
						"	c1.4 4.8 -2.4 5.4 -3.2 5.2\n",
						x, y);
						y -= 3.5;
				}
			}
			fprintf(fout, "\"/>\n");
			return;
		}
		if (strcmp(op, "sgs") == 0) {
			setg(1);
			h = pop_free_val();
			n = pop_free_val();
			sym = ps_sym_lookup("x");
			x = xoffs + sym->e->u.v + 1.6;
			sym = ps_sym_lookup("y");
			y = yoffs - sym->e->u.v;
			fprintf(fout,
				"<path d=\"M%.2f %.2fv%.2f\" stroke=\"currentColor\" fill=\"none\"/>\n"
				"<path fill=\"currentColor\"\n"
				"	d=\"",
				x, y, -h);
			y -= h;
			while (--n >= 0) {
				fprintf(fout,
					"M%.2f %.2fl3 1.5 0 2 -3 -1.5z\n",
					x, y);
				y += 3;
			}
			fprintf(fout, "\"/>\n");
			return;
		}
		if (strcmp(op, "sfz") == 0) {
			setg(1);
			y = yoffs - pop_free_val() - 5;
			x = xoffs + pop_free_val() - 7;
			s = pop_free_str();
			if (s)
				free(s);
			fprintf(fout, "<text font-family=\"serif\" font-size=\"14\" font-style=\"italic\" font-weight=\"normal\"\n"
				"	x=\"%.2f\" y=\"%.2f\">s<tspan\n"
				"	font-size=\"16\" font-weight=\"bold\">f</tspan>z</text>\n",
				x, y);
			return;
		}
		if (strcmp(op, "sgno") == 0) {
			xysym(op, D_sgno);
			return;
		}
		if (strcmp(op, "show") == 0) {
			show('s');
			return;
		}
		if (strcmp(op, "showb") == 0) {
			show('b');
			return;
		}
		if (strcmp(op, "showc") == 0) {
			show('c');
			return;
		}
		if (strcmp(op, "showr") == 0) {
			show('r');
			return;
		}
		if (strcmp(op, "showerror") == 0) {
			def_use(D_showerror);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			fprintf(fout, "<use x=\"%.2f\" y=\"%.2f\" xlink:href=\"#%s\"/>\n",
				x, y, op);
			return;
		}
		if (strcmp(op, "sld") == 0) {
			xysym(op, D_sld);
			return;
		}
		if (strcmp(op, "snap") == 0) {
			xysym(op, D_snap);
			return;
		}
		if (strcmp(op, "sphr") == 0) {
			xysym(op, D_sphr);
			return;
		}
		if (strcmp(op, "spclef") == 0) {
			def_use(D_pclef);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			fprintf(fout, "<use x=\"%.2f\" y=\"%.2f\" xlink:href=\"#pclef\"/>\n",
				x, y);
			return;
		}
		if (strcmp(op, "setrgbcolor") == 0) {
			int r, g, b;

			b = pop_free_val() * 255;
			g = pop_free_val() * 255;
			r = pop_free_val() * 255;
			gcur.rgb = (r << 16) | (g << 8) | b;
			return;
		}
		if (strcmp(op, "staff") == 0) {
			gcur.linewidth = DLW;
			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			n = pop_free_val();
			w = pop_free_val();
			fprintf(fout,
				"<path stroke=\"currentColor\" fill=\"none\"\n"
				"	d=\"M%.2f %.2f", x, y);
			for (;;) {
				fprintf(fout, "h%.2f", w);
				if (--n <= 0)
					break;
				fprintf(fout, "m%.2f -6", -w);
			}
			fprintf(fout, "\"/>\n");
			return;
		}
		if (strcmp(op, "stc") == 0) {
			xysym(op, D_stc);
			return;
		}
		if (strcmp(op, "stroke") == 0) {
			if (!path) {
				fprintf(stderr, "svg: 'stroke' with no path\n");
//				ps_error = 1;
				return;
			}
			path_end();
			fprintf(fout, "\t\" stroke=\"currentColor\" fill=\"none\"%s/>\n",
					gcur.dash);
			return;
		}
		if (strcmp(op, "su") == 0
		 || strcmp(op, "sd") == 0) {
			stem(op);
			return;
		}
		if (strcmp(op, "stsig") == 0) {
			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			s = pop_free_str();
			if (!s) {
				fprintf(stderr, "svg: No string\n");
				ps_error = 1;
				return;
			}
			fprintf(fout, "<g font-family=\"serif\" font-size=\"18\" font-weight=\"bold\" font-style=\"normal\"\n"
				"	transform=\"translate(%.2f,%.2f) scale(1.2,1)\">\n"
				"	<text x=\"0\" y=\"-7\" text-anchor=\"middle\">%s</text>\n"
				"</g>\n",
				x, y, s + 1);
			free(s);
			return;
		}
		if (strcmp(op, "sub") == 0) {
			x = pop_free_val();
			if (!stack || stack->type != VAL) {
				fprintf(stderr, "svg: Bad value for sub\n");
				ps_error = 1;
				return;
			}
			stack->u.v -= x;
			return;
		}
		if (strcmp(op, "sbclef") == 0) {
			xysym(op, D_sbclef);
			return;
		}
		if (strcmp(op, "scclef") == 0) {
			xysym(op, D_scclef);
			return;
		}
		if (strcmp(op, "sh0") == 0) {
			xysym(op, D_sh0);
			return;
		}
		if (strcmp(op, "sh1") == 0) {
			xysym(op, D_sh1);
			return;
		}
		if (strcmp(op, "sh4") == 0) {
			n = pop_free_val();
			if (n == 1)
				xysym(op, D_sh1);
			else
				xysym(op, D_sh513);
			return;
		}
		if (strcmp(op, "sh513") == 0) {
			xysym(op, D_sh513);
			return;
		}
		if (strcmp(op, "srep") == 0) {
			xysym(op, D_srep);
			return;
		}
		if (strcmp(op, "stclef") == 0) {
			xysym(op, D_stclef);
			return;
		}
		if (strcmp(op, "stringwidth") == 0) {
			s = pop_free_str();
			if (!s || *s != '(') {
				fprintf(stderr, "svg stringwidth: No string\n");
				ps_error = 1;
				return;
			}
			e = elt_new();
			if (!e)
				return;
			e->type = VAL;
			e->u.v = strw(s + 1);
			push(e);
			e = elt_new();
			if (!e)
				return;
			e->type = VAL;
			e->u.v = gcur.font_s;
			push(e);
			return;
		}
		if (strcmp(op, "svg") == 0) {
			e = elt_new();
			if (!e)
				return;
			e->type = VAL;
			e->u.v = 1;
			push(e);
			return;
		}
		break;
	case 'T':
		if (strcmp(op, "T") == 0) {
translate:
//fixme:test
//			setg(1);
			y = pop_free_val();
			x = pop_free_val();
			xoffs += x;
			yoffs -= y;
			cx -= x;
			cy -= y;
//fprintf(stderr, "T %.2f %.2f -> %.2f %.2f\n", x, y, xoffs, yoffs);
			return;
		}
		break;
	case 't':
		if (strcmp(op, "tclef") == 0) {
			xysym(op, D_tclef);
			return;
		}
		if (strcmp(op, "thbar") == 0) {
			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val() + 1.5;
			h = pop_free_val();
			fprintf(fout,
				"<path stroke=\"currentColor\" fill=\"none\" stroke-width=\"3\"\n"
				"	d=\"M%.2f %.2fv%.2f\"/>\n",
				x, y, -h);
			return;
		}
		if (strcmp(op, "thumb") == 0) {
			xysym(op, D_thumb);
			return;
		}
		if (strcmp(op, "translate") == 0)
			goto translate;
		if (strcmp(op, "trem") == 0) {
			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val() - 4.5;
			n = pop_free_val();
			fprintf(fout, "<path fill=\"currentColor\" d=\"m%.2f %.2f\n\t",
				x, y);
			for (;;) {
				fputs("l9 -3v3l-9 3z", fout);
				if (--n <= 0)
					break;
				fputs("m0 5.4", fout);
			}
			fputs("\"/>", fout);
			return;
		}
		if (strcmp(op, "trl") == 0) {
			setg(1);
			y = yoffs - pop_free_val() - 2;
			x = xoffs + pop_free_val() - 4;
			fprintf(fout, "<text font-family=\"serif\" font-size=\"16\" font-weight=\"bold\" font-style=\"italic\"\n"
				"	x=\"%.2f\" y=\"%.2f\">tr</text>\n",
				x, y);
			return;
		}
		if (strcmp(op, "true") == 0) {
			e = elt_new();
			if (!e)
				return;
			e->type = VAL;
			e->u.v = 1;
			push(e);
			return;
		}
		if (strcmp(op, "tsig") == 0) {
			char *d;

			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			d = pop_free_str();
			s = pop_free_str();
			if (!d || !s) {
				fprintf(stderr, "svg: No string\n");
				ps_error = 1;
				return;
			}
			fprintf(fout, "<g font-family=\"serif\" font-size=\"16\" font-weight=\"bold\" font-style=\"normal\"\n"
				"	transform=\"translate(%.2f,%.2f) scale(1.2,1)\">\n"
				"	<text y=\"-1\" text-anchor=\"middle\">%s</text>\n"
				"	<text y=\"-13\" text-anchor=\"middle\">%s</text>\n"
				"</g>\n",
				x, y, d + 1, s + 1);
			free(d);
			free(s);
			return;
		}
		if (strcmp(op, "tubr") == 0
		 || strcmp(op, "tubrl") == 0) {
			float dx, dy;
			int h;

			setg(1);
			y = yoffs - pop_free_val();
			x = xoffs + pop_free_val();
			dy = pop_free_val();
			dx = pop_free_val();
			if (op[4] == 'l') {
				h = 3;
				y -= 3;
			} else {
				h = -3;
				y += 3;
			}
			fprintf(fout,
				"<path stroke=\"currentColor\" fill=\"none\"\n"
				"	d=\"M%.2f %.2fv%dl%.2f %.2fv%d\"/>\n",
				x, y, h, dx, -dy, -h);
			return;
		}
		if (strcmp(op, "turn") == 0) {
			xysym(op, D_turn);
			return;
		}
		if (strcmp(op, "turnx") == 0) {
			xysym(op, D_turnx);
			return;
		}
		break;
	case 'u':
		if (strcmp(op, "upb") == 0) {
			xysym(op, D_upb);
			return;
		}
		if (strcmp(op, "umrd") == 0) {
			xysym(op, D_umrd);
			return;
		}
		break;
	case 'w':
		if (strcmp(op, "wedge") == 0) {
			xysym(op, D_wedge);
			return;
		}
		if (strcmp(op, "wln") == 0) {
			setg(1);
			y = pop_free_val();
			x = pop_free_val();
			w = pop_free_val();
			fprintf(fout, "<path stroke=\"currentColor\" fill=\"none\" stroke-width=\"0.8\"\n"
				"	d=\"M%.2f %.2fh%.2f\"/>\n",
				xoffs + x, yoffs - y, w);
			return;
		}
		if (strcmp(op, "where") == 0) {
			s = pop_free_str();		/* symbol */
			if (!s || *s != '/') {
				fprintf(stderr, "svg where: No / bad symbol\n");
				ps_error = 1;
				return;
			}
			e = elt_new();
			if (!e)
				return;
			e->type = VAL;
			sym = ps_sym_lookup(&s[1]);
			if (!sym) {
				e->u.v = 0;
			} else {
				e->u.v = 1;
				e2 = elt_new();		/* dictionnary */
				if (!e2)
					return;
				e2->type = VAL;
				e2->u.v = 0;
				push(e2);
			}
			free(s);
			push(e);
			return;
		}
		break;
	case 'x':
		if (strcmp(op, "xymove") == 0) {
			cy = y = pop_free_val();
			cx = x = pop_free_val();
			setxory("x", x);
			setxory("y", y);
			return;
		}
		break;
	}
	fprintf(stderr, "svg: Symbol '%s' not defined\n", op);
	ps_error = 1;
}

void svg_write(char *buf, int len)
{
	int l;
	struct elt_s *e, *e2;
	unsigned char c, *p, *q, *r;

	if (ps_error)
		return;

	p = (unsigned char *) buf;
#if 0
	if (strncmp((char *) p, "%svg ", 5) == 0) {	/* %%beginsvg */
		fwrite(p + 5, 1, len - 5, fout);
		fputs("\n", fout);
		return;
	}
#endif

	/* scan the string */
	while (--len >= 0) {
		c = *p++;
		switch (c) {
		case ' ':
		case '\t':
		case '\n':
			continue;
		case '{':
		case '[':		/* treat '[' as '{' */
			e = elt_new();
			if (!e)
				return;
			in_cnt++;
			e->type = STR;
			e->u.s = strdup(c == '{' ? "{" : "[");
			push(e);
			break;
		case '}':
		case ']':
			in_cnt--;
			if (in_cnt < 0) {
				if (c == '}')
					fprintf(stderr, "svg: '}' without '{'\n");
				else
					fprintf(stderr, "svg: ']' without '['\n");
				ps_error = 1;
				return;
			}
			e = elt_new();
			if (!e)
				return;

			/* create a container with elements in direct order */
			e->u.e = NULL;
			if (c == '}') {
				e->type = SEQ;
				c = '{';
			} else {
				e->type = BRK;
				c = '[';
			}
			for (;;) {
				e2 = stack;
				stack = stack->next;
				if (e2->type == STR
				 && (e2->u.s[0] == '['
				  || e2->u.s[0] == '{'))
					break;
				e2->next = e->u.e;
				e->u.e = e2;
			}
			if (e2->u.s[0] != c) {
				fprintf(stderr, "svg: '%c' found before '%c'\n",
					e2->u.s[0], c);
				ps_error = 1;
				return;
			}
			elt_free(e2);
			push(e);
			break;
		case '%':
			q = p;
			while (--len >= 0) {
				c = *p++;
				if (c == '\n')
					break;
			}
			if ((char *) q != &buf[1] && q[-2] != '\n')
				break;
			if (strncmp((char *) q, "A ", 2) == 0) {	/* annotation */
				char type;
				int row , col, h;
				float x, y, w;

				q += 2;
				type = *q++;
				if (type != 'b' && type != 'e') {	/* if not beam */
					sscanf((char *) q + 1, "%d %d %f %f %f %d",
						&row, &col, &x, &y, &w, &h);
				} else {
					sscanf((char *) q + 1, "%d %d %f %f",
						&row, &col, &x, &y);
					w = h = 6;
				}
					fprintf(fout, "<abc type=\"%c\" row=\"%d\" col=\"%d\" x=\"%.2f\" y=\"%.2f\" width=\"%.2f\" height=\"%d\"/>\n",
						type, row, col, xoffs + x, yoffs - y - h, w, h);
				break;
			}
			if (strncmp((char *) q, " --- ", 5) == 0	/* title info */
			 && strncmp((char *) p - 6, ") ---", 5) == 0) {
				setg(1);
				if (q[5] == '+') {		/* subtitle */
					q += 8;		/* % --- + (%s) ... */
					r = (unsigned char *) strchr((char *) q, ')');
//					if (!r)
//						break;
					fprintf(fout, "<!-- subtitle: %.*s -->\n",
							(int) (r - q), q);
					break;
				}
				q = (unsigned char *) strchr((char *) q, '(');
//				if (!q)
//					break;
				q++;
				r = (unsigned char *) strchr((char *) q, ')');
//				if (!r)
//					break;
				fprintf(fout, "<!-- title: %.*s -->\n",
						(int) (r - q), q);
				break;
			}
			break;
		case '(':
			q = p - 1;
			l = 1;
			for (;;) {
				switch (*p++) {
				case '\\':
					p++;
					l--;
					continue;
				default:
					continue;
				case ')':
					break;
				}
				break;
			}
			len -= p - q - 1;
			l += p - q - 1;
			p = q;
			e = elt_new();
			if (!e)
				return;
			e->type = STR;
			r = malloc(l);
			e->u.s = (char *) r;
			for (;;) {
				c = *p++;
				switch (c) {
				case '\\':
					*r++ = *p++;
					continue;
				default:
					*r++ = c;
					continue;
				case ')':
					break;
				}
				break;
			}
			*r = '\0';
			push(e);
			break;
		default:
			q = p - 1;
			while (--len >= 0) {
				c = *p++;
				switch (c) {
				case '(':
				case ' ':
				case '\t':
				case '\n':
				case '{':
				case '}':
				case '[':
				case ']':
				case '%':
				case '/':
					break;
				default:
					continue;
				}
				break;
			}
			if (len >= 0) {
				p--;
				len++;
			}
			if (isdigit((unsigned) *q) || *q == '-' || *q == '.') {
				int i;
				float v;

				e = elt_new();
				if (!e)
					return;
				e->type = VAL;
				c = *p;
				*p = '\0';
				if (q[1] == '#') {
					i = strtol((char *) q + 2, 0, 8);
					e->u.v = i;
				} else if (q[2] == '#') {
					i = strtol((char *) q + 3, 0, 16);
					e->u.v = i;
				} else {
					if (sscanf((char *) q, "%f", &v) != 1) {
						fprintf(stderr, "svg: Bad numeric value in '%s'",
							buf);
						v = 0;
					}
					e->u.v = v;
				}
				*p = c;
			} else {
				if (!in_cnt) {
					if (*q != '/') {	/* operator */
						c = *p;
						*p = '\0';
						ps_exec((char *) q);
						if (ps_error)
							return;
						*p = c;
						break;
					}
				} else if (strncmp((char *) q, "pdfmark", 7) == 0) {
					in_cnt--;
					for (;;) {
						e = pop(stack->type);
						if (e->type == STR
						 && (e->u.s[0] == '['
						  || e->u.s[0] == '{'))
							break;
						elt_free(e);
					}
					elt_free(e);
					break;
				}
				l = p - q;
				r = malloc(l + 1);
				memcpy(r, q, l);
				r[l] = '\0';
				e = elt_new();
				if (!e)
					return;
				e->type = STR;
				e->u.s = (char *) r;
			}
			push(e);
			break;
		}
	}
}

int svg_output(FILE *out, const char *fmt, ...)
{
	va_list args;
	char tmp[128];

	va_start(args, fmt);
	vsnprintf(tmp, sizeof tmp, fmt, args);
	va_end(args);
	svg_write(tmp, strlen(tmp));
	return 0;
}

void svg_close(void)
{
	struct elt_s *e, *e2;

	setg(0);
	fputs("</svg>\n", fout);
	e = stack;
	if (e) {
		stack = NULL;
		fprintf(stderr, "svg close: stack not empty ");
		elt_lst_dump(e);
		fprintf(stderr, "\n");
		do {
			e2 = e->next;
			elt_free(e);
			e = e2;
		} while (e);
	}
}
abcm2ps-7.8.13/syms.c0000644000175000017500000006317512314503212012377 0ustar  jefjef/*
 * Postscript definitions.
 *
 * This file is part of abcm2ps.
 *
 * Copyright (C) 1998-2014 Jean-François Moine
 * Adapted from abc2ps, Copyright (C) 1996,1997 Michael Methfessel
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
 */

#include <string.h>

#include "abc2ps.h"

static char ps_head[] =
	"/xymove{/x 2 index def/y 1 index def M}!\n"

	/* str showc - center at current pt */
	"/showc{dup stringwidth pop .5 mul neg 0 RM show}!\n"

	/* str showr - show right-aligned */
	"/showr{dup stringwidth pop neg 0 RM show}!\n"

	/* str showb - show in box */
	"/showb{	dup currentpoint 3 -1 roll show\n"
	"	.6 SLW\n"
	"	exch 2 sub exch 3 sub 3 -1 roll\n"
	"	stringwidth pop 4 add\n"
	"	currentfont/ScaleMatrix get 0 get .8 mul\n"
	"	4 add rectstroke}!\n"

	/* x y tclef - treble clef */
	"/utclef{<95200072\n"
	"	0000ff2e01c2030c\n"
	"	00ac0056\n"
	"	0064007f006400f400e00112\n"
	"	0176011c01bc0056013a0012\n"
	"	00c8ffde002700120015009a\n"
	"	0006014f0072017f00f101e8\n"
	"	0149023f0140026d012f02ba\n"
	"	00fc029900d1025100d60200\n"
	"	00e700f500fa008a0107ffc2\n"
	"	010dff6200f4ff3c00baff3b\n"
	"	006aff3a003cff98007dffc0\n"
	"	00d2ffe90102ff5b009cff57\n"
	"	00b3ff4600f8ff3200f6ffb3\n"
	"	00ec009200cf010900c4021c\n"
	"	00c4027600c402be01240304\n"
	"	015c02bc0163021e013a01e3\n"
	"	00f001790039013b003b00a7\n"
	"	0044000e00cfffee01370022\n"
	"	018d0063015400e200e700d2\n"
	"	00a000c6007e008f00ac0056\n"
	"	><0b000132050a>}cvlit def\n"
	"/tclef{gsave T -10 0 T .045 dup scale utclef ufill grestore}!\n"
	"/stclef{gsave T -10 0 T .037 dup scale utclef ufill grestore}!\n"

	/* x y octu - upper '8' */
	"/octu{/Times-Roman 12 selectfont M -2.5 0 RM(8)show}!\n"
	/* x y octl - lower '8' */
	"/octl{/Times-Roman 12 selectfont M -3.5 0 RM(8)show}!\n"

	/* x y bclef - bass clef */
	"/ubclef{<95200046\n"
	"	00000050019a0244\n"
	"	00010057\n"
	"	007d007a00df00a500ff0143\n"
	"	012a022700580239003f01aa\n"
	"	007a01fa00dc0194009b015c\n"
	"	005d012d00280172003101b4\n"
	"	00460241013f023c01430180\n"
	"	014200d100d9007800010057\n"
	"	01660151\n"
	"	016601750199017301990151\n"
	"	0199012c0166012d01660151\n"
	"	016401d2\n"
	"	016401f6019701f4019701d2\n"
	"	019701ac016401ad016401d2\n"
	"	><0b000126050a0122050a0122050a>}cvlit def\n"
	"/bclef{gsave T -10 0 T .045 dup scale ubclef ufill grestore}!\n"
	"/sbclef{gsave T -10 3 T .037 dup scale ubclef ufill grestore}!\n"

	/* x y cclef */
	"/ucclef{<95200066\n"
	"	006effbe01e70256\n"
	"	00d10108\n"
	"	00d10002\n"
	"	00c40002\n"
	"	00c40213\n"
	"	00d10213\n"
	"	00d10113\n"
	"	00ea012700fa013701100180\n"
	"	011e0161011d014d0148013a\n"
	"	01a2011801a80244011f01f3\n"
	"	015301e0013a01a3011401a6\n"
	"	00ba01cc01350256019f01eb\n"
	"	01e7019c01a000fa01190131\n"
	"	0109010a\n"
	"	011900e4\n"
	"	01a0011b01e70079019f002a\n"
	"	0135ffbe00ba00490114006f\n"
	"	013a007201530035011f0022\n"
	"	01a8ffd101a200fd014800db\n"
	"	011d00c8011b00bd0110009b\n"
	"	00fa00e400ea00f400d10108\n"
	"	006e0213\n"
	"	00a70213\n"
	"	00a70002\n"
	"	006e0002\n"
	"	006e0213\n"
	"	><0b000125032605220326050a0124030a>}cvlit def\n"
	"/cclef{gsave T -12 0 T .045 dup scale ucclef ufill grestore}!\n"
	"/scclef{gsave T -12 2 T .037 dup scale ucclef ufill grestore}!\n"

	/* x y pclef */
	"/pclef{	exch 2.7 sub exch 2 add 5.4 20\n"
	"	1.4 SLW rectstroke}!\n"
	"/spclef{pclef}!\n"

	/* t dx dy x y bm - beam, depth t */
	"/bm{	M 3 copy RL neg 0 exch RL\n"
	"	neg exch neg exch RL 0 exch RL fill}!\n"

	/* str x y bnum - tuplet number / ratio */
	"/bnum{M/Times-Italic 12 selectfont showc}!\n"
	/* same with clearing below the number */
	"/bnumb{	currentgray/Times-Italic 12 selectfont\n"
	"	3 index stringwidth pop 4 add\n"
	"	dup .5 mul neg 4 index add 3 index 3 -1 roll 8\n"
	"	1.0 setgray rectfill setgray M showc}!\n"

	/* dx dy x y tubr - tuplet bracket */
	"/tubr{3 sub M 0 3 RL RL 0 -3 RL dlw stroke}!\n"
	"/tubrl{3 add M 0 -3 RL RL 0 3 RL dlw stroke}!\n"

	/* x y r00 - longa rest */
	"/r00{	xymove\n"
	"	-1.5 -6 RM currentpoint 3 12 rectfill}!\n"

	/* x y r0 - breve rest */
	"/r0{	xymove\n"
	"	-1.5 0 RM currentpoint 3 6 rectfill}!\n"

	/* x y r1 - rest */
	"/r1{	xymove\n"
	"	-3.5 3 RM currentpoint 7 3 rectfill}!\n"

	/* x y r2 - half rest */
	"/r2{	xymove\n"
	"	-3.5 0 RM currentpoint 7 3 rectfill}!\n"

	/* x y r4 - quarter rest */
	"/r4{	xymove\n"
	"	-1 8.5 RM\n"
	"	3.6 -5.1 RL\n"
	"	-2.1 -5.2 RL\n"
	"	2.2 -4.3 RL\n"
	"	-2.6 2.3 -5.1 0 -2.4 -2.6 RC\n"
	"	-4.8 3 -1.5 6.9 1.4 4.1 RC\n"
	"	-3.1 4.5 RL\n"
	"	1.9 5.1 RL\n"
	"	-1.5 3.5 RL\n"
	"	fill}!\n"

	/* 1/8 .. 1/64 rest element */
	"/r8e{	-1.5 -1.5 -2.4 -2 -3.6 -2 RC\n"
	"	2.4 2.8 -2.8 4 -2.8 1.2 RC\n"
	"	0 -2.7 4.3 -2.4 5.9 -0.6 RC\n"
	"	fill}!\n"

	/* x y r8 - eighth rest */
	"/r8{	xymove\n"
	"	.5 SLW 3.3 4 RM\n"
	"	-3.4 -9.6 RL stroke\n"
	"	x y M 3.4 4 RM r8e}!\n"

	/* x y r16 - 16th rest */
	"/r16{	xymove\n"
	"	.5 SLW 3.3 4 RM\n"
	"	-4 -15.6 RL stroke\n"
	"	x y M 3.4 4 RM r8e\n"
	"	x y M 1.9 -2 RM r8e}!\n"

	/* x y r32 - 32th rest */
	"/r32{	xymove\n"
	"	.5 SLW 4.8 10 RM\n"
	"	-5.5 -21.6 RL stroke\n"
	"	x y M 4.9 10 RM r8e\n"
	"	x y M 3.4 4 RM r8e\n"
	"	x y M 1.9 -2 RM r8e}!\n"

	/* x y r64 - 64th rest */
	"/r64{	xymove\n"
	"	.5 SLW 4.8 10 RM\n"
	"	-7 -27.6 RL stroke\n"
	"	x y M 4.9 10 RM r8e\n"
	"	x y M 3.4 4 RM r8e\n"
	"	x y M 1.9 -2 RM r8e\n"
	"	x y M 0.4 -8 RM r8e}!\n"

	/* x y r128 - 128th rest */
	"/r128{	xymove\n"
	"	.5 SLW 5.8 16 RM\n"
	"	-8.5 -33.6 RL stroke\n"
	"	x y M 5.9 16 RM r8e\n"
	"	x y M 4.4 10 RM r8e\n"
	"	x y M 2.9 4 RM r8e\n"
	"	x y M 1.4 -2 RM r8e\n"
	"	x y M -0.1 -8 RM r8e}!\n"

	/* dx dy dt - dot relative to head */
	"/dt{x y M RM currentpoint 1.2 0 360 arc fill}!\n"

	/* x y hld - fermata */
	"/hld{	1.5 add 2 copy 1.5 add M currentpoint 1.3 0 360 arc\n"
	"	M -7.5 0 RM\n"
	"	0 11.5 15 11.5 15 0 RC\n"
	"	-0.25 0 RL\n"
	"	-1.25 9 -13.25 9 -14.5 0 RC\n"
	"	fill}!\n"

	/* x y dnb - down bow */
	"/dnb{	dlw M -3.2 2 RM\n"
	"	0 7.2 RL\n"
	"	6.4 0 RM\n"
	"	0 -7.2 RL\n"
	"	currentpoint stroke M\n"
	"	-6.4 4.8 RM\n"
	"	0 2.4 RL\n"
	"	6.4 0 RL\n"
	"	0 -2.4 RL\n"
	"	fill}!\n"

	/* x y upb - up bow */
	"/upb{	dlw M -2.6 9.4 RM\n"
	"	2.6 -8.8 RL\n"
	"	2.6 8.8 RL\n"
	"	stroke}!\n"

	/* x y grm - gracing mark */
	"/grm{	M -5 2.5 RM\n"
	"	5 8.5 5.5 -4.5 10 2 RC\n"
	"	-5 -8.5 -5.5 4.5 -10 -2 RC fill}!\n"

	/* x y stc - staccato mark */
	"/stc{3 add M currentpoint 1.2 0 360 arc fill}!\n"

	/* x y emb - emphasis bar */
	"/emb{	1.2 SLW 1 setlinecap M\n"
	"	-2.5 3 RM 5 0 RL stroke 0 setlinecap}!\n"

	/* x y cpu - roll sign above head */
	"/cpu{	M -6 0 RM\n"
	"	0.4 7.3 11.3 7.3 11.7 0 RC\n"
	"	-1.3 6 -10.4 6 -11.7 0 RC fill}!\n"

	/* x y sld - slide */
	"/sld{	M -7.2 -4.8 RM\n"
	"	1.8 -0.7 4.5 0.2 7.2 4.8 RC\n"
	"	-2.1 -5 -5.4 -6.8 -7.6 -6 RC fill}!\n"

	/* x y trl - trill sign */
	"/trl{	/Times-BoldItalic 16 selectfont\n"
	"	M -4 2 RM(tr)show}!\n"

	/* x y umrd - upper mordent */
	"/umrd{	4 add M\n"
	"	2.2 2.2 RL 2.1 -2.9 RL 0.7 0.7 RL\n"
	"	-2.2 -2.2 RL -2.1 2.9 RL -0.7 -0.7 RL\n"
	"	-2.2 -2.2 RL -2.1 2.9 RL -0.7 -0.7 RL\n"
	"	2.2 2.2 RL 2.1 -2.9 RL 0.7 0.7 RL fill}!\n"

	/* x y lmrd - lower mordent */
	"/lmrd{	2 copy umrd M\n"
	"	.6 SLW 0 8 RL stroke}!\n"

	/* str x y fng - finger (0-5) */
	"/fng{/Bookman-Demi 8 selectfont M -3 1 RM show}!\n"

	/* str x y dacs - D.C. / D.S. */
	"/dacs{/Times-Roman 16 selectfont 3 add M showc}!\n"

	/* x y brth - breath */
	"/brth{/Times-BoldItalic 30 selectfont 6 add M(,)show}!\n"

	/* str x y pf - p, f, pp, .. */
	"/pf{/Times-BoldItalic 16 selectfont 5 add M show}!\n"

	/* str x y sfz */
	"/sfz{	M -7 5 RM pop\n"
	"	/Times-Italic 14 selectfont(s)show\n"
	"	/Times-BoldItalic 16 selectfont(f)show\n"
	"	/Times-Italic 14 selectfont(z)show}!\n"

	/* x y coda - coda */
	"/coda{	1 SLW 2 add 2 copy M 0 20 RL\n"
	"	2 copy M -10 10 RM 20 0 RL stroke\n"
	"	10 add 6 0 360 arc 1.7 SLW stroke}!\n"

	/* x y sgno - segno */
	"/sgno{	M 0 3 RM currentpoint currentpoint currentpoint\n"
	"	1.5 -1.7 6.4 0.3 3 3.7 RC\n"
	"	-10.4 7.8 -8 10.6 -6.5 11.9 RC\n"
	"	4 1.9 5.9 -1.7 4.2 -2.6 RC\n"
	"	-1.3 -0.7 -2.9 1.3 -0.7 2 RC\n"
	"	-1.5 1.7 -6.4 -0.3 -3 -3.7 RC\n"
	"	10.4 -7.8 8 -10.6 6.5 -11.9 RC\n"
	"	-4 -1.9 -5.9 1.7 -4.2 2.6 RC\n"
	"	1.3 0.7 2.9 -1.3 0.7 -2 RC\n"
	"	fill\n"
	"	M 0.8 SLW -6 1.2 RM 12.6 12.6 RL stroke\n"
	"	7 add exch 6 sub exch 1.2 0 360 arc fill\n"
	"	8 add exch 6 add exch 1.2 0 360 arc fill}!\n"

	/* w x y cresc - crescendo */
	"/cresc{	1 SLW M dup 5 RM\n"
	"	defl 1 and 0 eq\n"
	"	{dup neg 4 RL 4 RL}\n"
	"	{dup neg 2.2 RL 0 3.6 RM 2.2 RL}\n"
	"	ifelse stroke}!\n"

	/* w x y dim - diminuendo */
	"/dim{	1 SLW 5 add M\n"
	"	defl 2 and 0 eq\n"
	"	{dup 4 RL neg 4 RL}\n"
	"	{dup 2.2 RL 0 3.6 RM neg 2.2 RL}\n"
	"	ifelse stroke}!\n"

	/* x y dplus - plus */
	"/dplus{	1.2 SLW 0.5 add M 0 6 RL\n"
	"	-3 -3 RM 6 0 RL stroke}!\n"

	/* x y accent - accent */
	"/accent{1.2 SLW M -4 0 RM\n"
	"	8 2 RL -8 2 RL stroke}!\n"

	/* x y turn - turn */
	"/turn{	M 5.2 8 RM\n"
	"	1.4 -0.5 0.9 -4.8 -2.2 -2.8 RC\n"
	"	-4.8 3.5 RL\n"
	"	-3 2 -5.8 -1.8 -3.6 -4.4 RC\n"
	"	1 -1.1 2 -0.8 2.1 0.1 RC\n"
	"	0.1 0.9 -0.7 1.2 -1.9 0.6 RC\n"
	"	-1.4 0.5 -0.9 4.8 2.2 2.8 RC\n"
	"	4.8 -3.5 RL\n"
	"	3 -2 5.8 1.8 3.6 4.4 RC\n"
	"	-1 1.1 -2 0.8 -2.1 -0.1 RC\n"
	"	-0.1 -0.9 0.7 -1.2 1.9 -0.6 RC\n"
	"	fill}!\n"

	/* x y trnx - turn with line through it */
	"/turnx{	2 copy turn M\n"
	"	.6 SLW 0 1.5 RM 0 9 RL stroke}!\n"

	/* x y lphr - longphrase */
	"/lphr{1.2 SLW M 0 -18 RL stroke}!\n"

	/* x y mphr - mediumphrase */
	"/mphr{1.2 SLW M 0 -12 RL stroke}!\n"

	/* x y sphr - shortphrase */
	"/sphr{1.2 SLW M 0 -6 RL stroke}!\n"

	/* w x y ltr - long trill */
	"/ltr{	gsave 4 add T\n"
	"	0 6 3 -1 roll{\n"
	/*		% first loop draws left half of squiggle; second draws right\n*/
	"		2{\n"
	"			0 0.4 M\n"
	"			2 1.9 3.4 2.3 3.9 0 C\n"
	"			2.1 0 L\n"
	"			1.9 0.8 1.4 0.7 0 -0.4 C\n"
	"			fill\n"
	"			180 rotate -6 0 T\n"
	"		}repeat\n"
	/*		% shift axes right one squiggle*/
	"		pop 6 0 T\n"
	"	}for\n"
	"	grestore}!\n"

	/* h x ylow arp - arpeggio */
	"/arp{gsave 90 rotate exch neg ltr grestore}!\n"

	/* x y wedge - wedge */
	"/wedge{1 add M -1.5 5 RL 3 0 RL -1.5 -5 RL fill}!\n"

	/* x y opend - 'open' sign */
	"/opend{dlw M currentpoint 3 add 2.5 -90 270 arc stroke}!\n"

	/* x y snap - 'snap' sign */
	"/snap{	dlw 2 copy M -3 6 RM\n"
	"	0 5 6 5 6 0 RC\n"
	"	0 -5 -6 -5 -6 0 RC\n"
	"	5 add M 0 -6 RL stroke}!\n"

	/* x y thumb - 'thumb' sign */
	"/thumb{	dlw 2 copy M -2.5 7 RM\n"
	"	0 6 5 6 5 0 RC\n"
	"	0 -6 -5 -6 -5 0 RC\n"
	"	2 add M 0 -4 RL stroke}!\n"

	/* n x y trem - <n> tremolo on one note */
	"/trem{	M -4.5 0 RM{\n"
	"		currentpoint\n"
	"		9 3 RL 0 -3 RL -9 -3 RL 0 3 RL\n"
	"		fill 5.4 sub M\n"
	"	}repeat}!\n"

	/* x y hl - ledger line */
	"/hl{	.8 SLW M -6 0 RM 12 0 RL stroke}!\n"
	/* x y hl1 - longer ledger line */
	"/hl1{	.8 SLW M -7 0 RM 14 0 RL stroke}!\n"
	/* x y hl2 - more longer ledger line */
	"/hl2{	.7 SLW M -9 0 RM 18 0 RL stroke}!\n"

	/* -- accidentals -- */
	/* glyphs 1000 */
	"/usharp{<95200024\n"		/* width 460 */
	"	003cff42019a02ee\n"
	"	008802be\n"
	"	0088ff44\n"
	"	00a8ff44\n"
	"	00a802be\n"
	"	0128ff76\n"
	"	0148ff76\n"
	"	014802ee\n"
	"	012802ee\n"
	"	004001d0\n"
	"	0040015c\n"
	"	019201bc\n"
	"	01920230\n"
	"	00400076\n"
	"	00400002\n"
	"	01920064\n"
	"	019200d6\n"
	"	><0b000123030a0123030a0123030a0123030a>}cvlit def\n"
	"/uflat{<95200028\n"		/* width 400 */
	"	0064000001b802ee\n"
	"	006402ea\n"
	"	008402ea\n"
	"	0084000c\n"
	"	00640008\n"
	"	00840154\n"
	"	00b2019c011c01ae01540168\n"
	"	01b800fa00dc00220084000c\n"
	"	00840028\n"
	"	00ba0028014c00f60106014a\n"
	"	00d401860084014e00840128\n"
	"	><0b00010303030a0105050105050a>}cvlit def\n"
	"/unat{<95200022\n"		/* width 380 */
	"	003cff42013602ee\n"
	"	006002ee\n"
	"	004002ee\n"
	"	00400022\n"
	"	0060002a\n"
	"	01160060\n"
	"	0116ff46\n"
	"	0136ff46\n"
	"	01360208\n"
	"	011401fe\n"
	"	006001cc\n"
	"	006002ee\n"
	"	0060009e\n"
	"	0060015c\n"
	"	01160190\n"
	"	011600d4\n"
	"	><0b00012a030a0123030a>}cvlit def\n"
	"/udblesharp{<95200046\n"	/* width 460 */
	"	003c006e019001c2\n"
	"	00f0011a\n"
	"	01180140013a015e018e015e\n"
	"	018e01be\n"
	"	012e01be\n"
	"	012e016a0110014800ea0122\n"
	"	00c2014800a4016a00a401be\n"
	"	004401be\n"
	"	0044015e\n"
	"	009a015e00bc014000e2011a\n"
	"	00bc00f4009a00d6004400d6\n"
	"	00440076\n"
	"	00a40076\n"
	"	00a400ca00c200ec00ea0112\n"
	"	011000ec012e00ca012e0076\n"
	"	018e0076\n"
	"	018e00d6\n"
	"	013a00d6011800f400f0011a\n"
	"	><0b0001050303050503030505030305050303050a>}cvlit def\n"
	"/udbleflat{<9520004c\n"	/* width 500 */
	"	00140000022602ee\n"
	"	001402ea\n"
	"	002c02ea\n"
	"	002c000c\n"
	"	00140008\n"
	"	002c0154\n"
	"	004e019c009e01ae00c80168\n"
	"	011300fa00660022002c000c\n"
	"	002c0028\n"
	"	0054002800c200f6008d014a\n"
	"	00680186002c014e002c0128\n"
	"	010e02ea\n"
	"	012602ea\n"
	"	0126000c\n"
	"	010e0008\n"
	"	01260154\n"
	"	0148019c019801ae01c20168\n"
	"	020d00fa016000220126000c\n"
	"	01260028\n"
	"	014e002801bc00f60187014a\n"
	"	016201860126014e01260128\n"
	"	><0b000123030a0105050105050a0123030a0105050105050a>}cvlit def\n"

	/* x y sh0 - sharp sign */
	"/sh0{	gsave T -4 -5 T .018 dup scale usharp ufill grestore}!\n"
	/* x y ft0 - flat sign */
	"/ft0{	gsave T -3.5 -3.5 T .018 dup scale uflat ufill grestore}!\n"
	/* x y nt0 - natural sign */
	"/nt0{	gsave T -3 -5 T .018 dup scale unat ufill grestore}!\n"
	/* x y dsh0 - double sharp */
	"/dsh0{	gsave T -4 -5 T .018 dup scale udblesharp ufill grestore}!\n"
	/* x y dft0 - double flat sign */
	"/dft0{	gsave T -4 -3.5 T .018 dup scale udbleflat ufill grestore}!\n"
	/* ancillary function for grace note accidentals */
	"/gsc{gsave y T .7 dup scale 0 0}!\n"

	/* some microtone accidentals */
	/* 1/4 ton sharp */
	"/sh1{	gsave T .9 SLW\n"
	"	0 -7.8 M 0 15.4 RL stroke\n"
	"	-1.8 -2.7 M 3.6 1.1 RL 0 -2.2 RL -3.6 -1.1 RL 0 2.2 RL fill\n"
	"	-1.8 3.7 M 3.6 1.1 RL 0 -2.2 RL -3.6 -1.1 RL 0 2.2 RL fill\n"
	"	grestore}!\n"
	/* 3/4 ton sharp */
	"/sh513{	gsave T .8 SLW\n"
	"	-2.5 -8.7 M 0 15.4 RL\n"
	"	0 -7.8 M 0 15.4 RL\n"
	"	2.5 -6.9 M 0 15.4 RL stroke\n"
	"	-3.7 -3.1 M 7.4 2.2 RL 0 -2.2 RL -7.4 -2.2 RL 0 2.2 RL fill\n"
	"	-3.7 3.2 M 7.4 2.2 RL 0 -2.2 RL -7.4 -2.2 RL 0 2.2 RL fill\n"
	"	grestore}!\n"
	/* 1/4 ton flat */
	"/ft1{gsave -1 1 scale exch neg exch ft0 grestore}!\n"
	/* x y ftx - narrow flat sign */
	"/ftx{	-1.4 2.7 RM\n"
	"	5.7 3.1 5.7 -3.6 0 -6.7 RC\n"
	"	3.9 4 4 7.6 0 5.8 RC\n"
	"	currentpoint fill M\n"
	"	dlw 0 7.1 RM 0 -12.4 RL stroke}!\n"
	/* 3/4 ton flat */
	"/ft513{2 copy gsave -1 1 scale exch neg 3 add exch M ftx grestore\n"
	"	M 1.5 0 RM ftx}!\n"
	/* microscale= 4 */
	"/sh4tb[/.notdef/sh1/sh0/sh513/dsh0]def\n"
	"/sh4{sh4tb exch get cvx exec}!\n"
	"/ft4tb[/.notdef/ft1/ft0/ft513/dft0]def\n"
	"/ft4{ft4tb exch get cvx exec}!\n"

	/* str gcshow - guitar chord */
	"/gcshow{show}!\n"
	/* x y w h box - draw a box */
	"/box{.6 SLW rectstroke}!\n"
	/* set the start of a guitar chord in a box */
	"/boxstart{currentpoint pop/x exch def}!\n"
	/* mark the end of a guitar chord in a box */
	"/boxmark{currentpoint pop dup x gt\n"
	"	{/x exch def}{pop}ifelse}!\n"
	/* x y dy boxdraw - draw a box around a guitar chord */
	"/boxdraw{x 3 index sub 2 add exch box}!\n"
	/* w str gxshow - expand a guitar chord */
	"/gxshow{0 9 3 -1 roll widthshow}!\n"

	/* str anshow - annotation */
	"/anshow{show}!\n"

	/* -- lyrics under notes -- */
	/* w x y wln - underscore line */
	"/wln{M .8 SLW 0 RL stroke}!\n"
	/* w x y hyph - hyphen */
	"/hyph{	.8 SLW 3 add M\n"
	"	dup cvi 20 idiv 3 mul 25 add\n"	/* w d */
	"	1 index cvi exch idiv 1 add "	/* w n */
		"exch "				/* n w */
		"1 index div\n"			/* n dx */
	"	dup 4 sub "			/* n dx (dx-4) */
		"3 1 roll "			/* (dx-4) n dx */
		".5 mul 2 sub 0 RM\n"		/* (dx / 2 - 4) rmoveto */
	"	{4 0 RL dup 0 RM}repeat stroke pop}!\n"
	/* str lyshow - lyrics */
	"/lyshow{show}!\n"

	/* -- bars -- */
	/* h x y bar - thin bar */
	"/bar{M dlw 0 exch RL stroke}!\n"
	/* h x y dotbar - dotted bar */
	"/dotbar{[5] 0 setdash bar [] 0 setdash}!\n"
	/* h x y thbar - thick bar */
	"/thbar{3 -1 roll 3 exch rectfill}!\n"
	/* x y rdots - repeat dots */
	"/rdots{	2 copy 9 add M currentpoint 1.2 0 360 arc\n"
	"	15 add M currentpoint 1.2 0 360 arc fill}!\n"

	/* x y csig - C timesig */
	"/csig{	M\n"
	"	1 17.3 RM\n"
	"	0.9 0 2.3 -0.7 2.4 -2.2 RC\n"
	"	-1.2 2 -3.6 -0.1 -1.6 -1.7 RC\n"
	"	2 -1 3.8 3.5 -0.8 4.7 RC\n"
	"	-2 0.4 -6.4 -1.3 -5.8 -7 RC\n"
	"	0.4 -6.4 7.9 -6.8 9.1 -0.7 RC\n"
	"	-2.3 -5.6 -6.7 -5.1 -6.8 0 RC\n"
	"	-0.5 4.4 0.7 7.5 3.5 6.9 RC\n"
	"	fill}!\n"

	/* x y ctsig - C| timesig */
	"/ctsig{dlw 2 copy csig 4 add M 0 16 RL stroke}!\n"

	/* x y xxsig - old time signatures ('o', 'o.', 'c' 'c.') */
	"/pmsig{0.3 SLW 12 add M currentpoint 5 0 360 arc stroke}!\n"
	"/pMsig{2 copy pmsig 12 add M currentpoint 1.3 0 360 arc fill}!\n"
	"/imsig{0.3 SLW 12 add 2 copy 5 add M 5 90 270 arc stroke}!\n"
	"/iMsig{2 copy imsig 12 add M currentpoint 1.3 0 360 arc fill}!\n"

	/* (top) (bot) x y tsig - time signature */
	"/tsig{	M gsave/Times-Bold 16 selectfont 1.2 1 scale\n"
	"	0 1 RM currentpoint 3 -1 roll showc\n"
	"	12 add M showc grestore}!\n"

	/* (meter) x y stsig - single time signature */
	"/stsig{	M gsave/Times-Bold 18 selectfont 1.2 1 scale\n"
	"	0 7 RM showc grestore}!\n"

	/* width n x y staff - staff with n lines*/
	"/staff{	dlw M{dup 0 RL dup neg 6 RM}repeat\n"
	"	pop stroke}!\n"

	/* l x sep0 - hline separator */
	"/sep0{dlw 0 M 0 RL stroke}!\n"

	"/hbrce{	-2.5 1 RM\n"
	"	-4.5 -4.6 -7.5 -12.2 -4.4 -26.8 RC\n"
	"	3.5 -14.3 3.2 -21.7 -2.1 -24.2 RC\n"
	"	7.4 2.4 7.3 14.2 3.5 29.5 RC\n"
	"	-2.7 9.5 -1.5 16.2 3 21.5 RC\n"
	"	fill}!\n"
	/* h x y brace */
	"/brace{	gsave T 0 0 M .01 mul 1 exch scale hbrce\n"
	"	0 -100 M 1 -1 scale hbrce grestore}!\n"

	/* h x y bracket */
	"/bracket{M -5 2 RM currentpoint\n"
	"	-1.7 2 RM 10.5 -1 12 4.5 12 3.5 RC\n"
	"	0 -1 -3.5 -5.5 -8.5 -5.5 RC fill\n"
	"	3 SLW M 0 2 RM\n"
	"	0 exch neg 8 sub RL currentpoint stroke\n"
	"	M -1.7 0 RM\n"
	"	10.5 1 12 -4.5 12 -3.5 RC\n"
	"	0 1 -3.5 5.5 -8.5 5.5 RC fill}!\n"

	/* nb_measures x y mrest */
	"/mrest{	gsave T 1 SLW\n"
	"	-20 6 M 0 12 RL 20 6 M 0 12 RL stroke\n"
	"	5 SLW -20 12 M 40 0 RL stroke\n"
	"	/Times-Bold 15 selectfont 0 28 M showc grestore}!\n"

	/* x y mrep - measure repeat */
	"/mrep{	2 copy 2 copy\n"
	"	M -5 15 RM currentpoint 1.4 0 360 arc\n"
	"	M 5 9 RM currentpoint 1.4 0 360 arc\n"
	"	M -7 6 RM 11 12 RL 3 0 RL -11 -12 RL -3 0 RL\n"
	"	fill}!\n"

	/* x y mrep2 - measure repeat 2 times */
	"/mrep2{	2 copy 2 copy\n"
	"	M -5 18 RM currentpoint 1.4 0 360 arc\n"
	"	M 5 6 RM currentpoint 1.4 0 360 arc fill\n"
	"	M 1.8 SLW\n"
	"	-7 4 RM 14 10 RL -14 -4 RM 14 10 RL\n"
	"	stroke}!\n"

	/* x y srep - sequence repeat */
	"/srep{	M -1 6 RM 11 12 RL 3 0 RL -11 -12 RL -3 0 RL\n"
	"	fill}!\n"

	/* str dy bracket_type dx x y repbra - repeat bracket */
	"/repbra{gsave dlw T 0 -20 M\n"
	"	0 20 3 index 1 ne{RL}{RM}ifelse 0 RL 0 ne{0 -20 RL}if stroke\n"
	"	4 exch M show grestore}!\n"

	/* pp2x pp1x p1 pp1 pp2 p2 p1 SL - slur / tie */
	"/SL{M RC RL RC closepath fill}!\n"

	/* pp2x pp1x p1 pp1 pp2 p2 p1 dSL - dotted slur / tie */
	"/dSL{	M [4] 0 setdash .8 SLW\n"
	"	RC stroke [] 0 setdash}!\n"

	/* -- text -- */
	"/strw{	gsave 0 1000 M/strop/show load def 1 setgray str\n"
	"	0 setgray currentpoint pop/w exch def grestore}!\n"
	"/jshow{w 0 32 4 -1 roll widthshow}!\n"
	"/strop/show load def\n"
	"/arrayshow{{dup type/stringtype eq{strop}{glyphshow}ifelse}forall}def\n"

	/* -- note heads -- */
	/* x y hd - full head */
	"/uhd{{	100 -270 640 280\n"
	"	560 82\n"
	"	474 267 105 105 186 -80\n"
	"	267 -265 636 -102 555 82\n"
	"	}<0b000122050a>}cvlit def\n"
	"/hd{	/x 2 index def/y 1 index def\n"
	"	gsave T -7.4 0 T .02 dup scale uhd ufill grestore}!\n"
	/* x y Hd - open head for half */
	"/Hd{	xymove\n"
	"	3 1.6 RM\n"
	"	-1 1.8 -7 -1.4 -6 -3.2 RC\n"
	"	1 -1.8 7 1.4 6 3.2 RC\n"
	"	0.5 0.3 RM\n"
	"	2 -3.8 -5 -7.6 -7 -3.8 RC\n"
	"	-2 3.8 5 7.6 7 3.8 RC\n"
	"	fill}!\n"
	/* x y HD - open head for whole */
	"/HD{	xymove\n"
	"	-2.7 1.4 RM\n"
	"	1.5 2.8 6.9 0 5.3 -2.7 RC\n"
	"	-1.5 -2.8 -6.9 0 -5.3 2.7 RC\n"
	"	8.3 -1.4 RM\n"
	"	0 1.5 -2.2 3 -5.6 3 RC\n"
	"	-3.4 0 -5.6 -1.5 -5.6 -3 RC\n"
	"	0 -1.5 2.2 -3 5.6 -3 RC\n"
	"	3.4 0 5.6 1.5 5.6 3 RC\n"
	"	fill}!\n"
	/* x y HDD - round breve */
	"/HDD{	dlw HD\n"
	"	x y M -6 -4 RM 0 8 RL\n"
	"	12 0 RM 0 -8 RL stroke}!\n"
	/* x y breve - square breve */
	"/breve{	xymove\n"
	"	2.5 SLW -6 -2.7 RM 12 0 RL\n"
	"	0 5.4 RM -12 0 RL stroke\n"
	"	dlw x y M -6 -5 RM 0 10 RL\n"
	"	12 0 RM 0 -10 RL stroke}!\n"
	/* x y longa */
	"/longa{	xymove\n"
	"	2.5 SLW -6 -2.7 RM 12 0 RL\n"
	"	0 5.4 RM -12 0 RL stroke\n"
	"	dlw x y M -6 -5 RM 0 10 RL\n"
	"	12 0 RM 0 -16 RL stroke}!\n"

	/* -- default percussion heads -- */
	/* x y pshhd - percussion sharp head */
	"/pshhd{/x 2 index def/y 1 index def dsh0}!\n"
	/* x y pfthd - percussion flat head */
	"/pfthd{/x 2 index def/y 1 index def dsh0\n"
	"	.7 SLW x y 4 0 360 arc stroke}!\n"
	/* same for dble sharp/flat */
	"/pdshhd{pshhd}!\n"
	"/pdfthd{pfthd}!\n"

	/* x y ghd - grace note head */
	"/ghd{	xymove\n"
	"	1.7 1 RM\n"
	"	-1 1.7 -4.5 -0.2 -3.4 -2 RC\n"
	"	1 -1.7 4.5 0.2 3.4 2 RC fill}!\n"

	/* dx dy gua / gda - acciaccatura */
	"/gua{x y M -1 4 RM RL stroke}!\n"
	"/gda{x y M -5 -4 RM RL stroke}!\n"

	/* x y ghl - grace note ledger line */
	"/ghl{	.6 SLW M -3 0 RM 6 0 RL stroke}!\n"

	/* x1 y2 x2 y2 x3 y3 x0 y0 gsl - grace note slur */
	"/gsl{dlw M RC stroke}!\n"

	/* x y custos */
	"/custos{2 copy M -4 0 RM 2 2.5 RL 2 -2.5 RL 2 2.5 RL 2 -2.5 RL\n"
	"	-2 -2.5 RL -2 2.5 RL -2 -2.5 RL -2 2.5 RL fill\n"
	"	M 3.5 0 RM 5 7 RL dlw stroke}!\n"

#ifdef HAVE_PANGO
	"/glypharray{{glyphshow}forall}!\n"
#endif

	/* x y showerror */
	"/showerror{gsave 1 0.7 0.7 setrgbcolor 2.5 SLW newpath\n"
	"	30 0 360 arc stroke grestore}!\n"

	"/pdfmark where{pop}{userdict/pdfmark/cleartomark load put}ifelse\n"

	"0 setlinecap 0 setlinejoin\n";

/* -- define a font -- */
void define_font(char name[],
		 int num,
		 int enc)
{
	if (enc == 0)		/* utf-8 */
		fprintf(fout, "/%s-utf8/%s mkfont\n"
			"/F%d{/%s-utf8 exch selectfont}!\n",
			name, name, num, name);
	else			/* native encoding */
		fprintf(fout, "/F%d{/%s exch selectfont}!\n", num, name);
}

/* -- output the symbol definitions -- */
void define_symbols(void)
{
	fputs(ps_head, fout);

	/* len su - up stem */
	fprintf(fout, "/su{dlw x y M %.1f %.1f RM %.1f sub 0 exch RL stroke}!\n",
		STEM_XOFF, STEM_YOFF, STEM_YOFF);

	/* len sd - down stem */
	fprintf(fout, "/sd{dlw x y M %.1f %.1f RM %.1f add 0 exch RL stroke}!\n",
		-STEM_XOFF, -STEM_YOFF, STEM_YOFF);

	/* n len sfu - stem and n flags up */
	fprintf(fout, "/sfu{	dlw x y M %.1f %.1f RM\n"
		"	%.1f sub 0 exch RL currentpoint stroke\n"
		"	M dup 1 eq{\n"
		"		pop\n"
		"		0.6 -5.6 9.6 -9 5.6 -18.4 RC\n"
		"		1.6 6 -1.3 11.6 -5.6 12.8 RC\n"
		"		fill\n"
		"	  }{\n"
		"		1 sub{	currentpoint\n"
		"			0.9 -3.7 9.1 -6.4 6 -12.4 RC\n"
		"			1 5.4 -4.2 8.4 -6 8.4 RC\n"
		"			fill 5.4 sub M\n"
		"		}repeat\n"
		"		1.2 -3.2 9.6 -5.7 5.6 -14.6 RC\n"
		"		1.6 5.4 -1 10.2 -5.6 11.4 RC\n"
		"		fill\n"
		"	  }ifelse}!\n",
		STEM_XOFF, STEM_YOFF, STEM_YOFF);

	/* n len sfd - stem and n flags down */
	fprintf(fout, "/sfd{	dlw x y M %.1f %.1f RM\n"
		"	%.1f add 0 exch RL currentpoint stroke\n"
		"	M dup 1 eq{\n"
		"		pop\n"
		"		0.6 5.6 9.6 9 5.6 18.4 RC\n"
		"		1.6 -6 -1.3 -11.6 -5.6 -12.8 RC\n"
		"		fill\n"
		"	  }{\n"
		"		1 sub{	currentpoint\n"
		"			0.9 3.7 9.1 6.4 6 12.4 RC\n"
		"			1 -5.4 -4.2 -8.4 -6 -8.4 RC\n"
		"			fill 5.4 add M\n"
		"		}repeat\n"
		"		1.2 3.2 9.6 5.7 5.6 14.6 RC\n"
		"		1.6 -5.4 -1 -10.2 -5.6 -11.4 RC\n"
		"		fill\n"
		"	  }ifelse}!\n",
		-STEM_XOFF, -STEM_YOFF, STEM_YOFF);

	/* n len sfs - stem and n straight flag down */
	fprintf(fout, "/sfs{	dup 0 lt{\n"
		"		dlw x y M -%.1f -%.1f RM\n"
		"		%.1f add 0 exch RL currentpoint stroke\n"
		"		M{	currentpoint\n"
		"			7 %.1f RL\n"
		"			0 %.1f RL\n"
		"			-7 -%.1f RL\n"
		"			fill 5.4 add M\n"
		"		}repeat\n"
		"	}{\n"
		"		dlw x y M %.1f %.1f RM\n"
		"		%.1f sub 0 exch RL currentpoint stroke\n"
		"		M{	currentpoint\n"
		"			7 -%.1f RL\n"
		"			0 -%.1f RL\n"
		"			-7 %.1f RL\n"
		"			fill 5.4 sub M\n"
		"		}repeat\n"
		"	}ifelse}!\n",
		STEM_XOFF, STEM_YOFF, STEM_YOFF,
		BEAM_DEPTH, BEAM_DEPTH, BEAM_DEPTH,
		STEM_XOFF, STEM_YOFF, STEM_YOFF,
		BEAM_DEPTH, BEAM_DEPTH, BEAM_DEPTH);

	/* len gu - grace note stem up */
	fprintf(fout, "/gu{	.6 SLW x y M\n"
		"	%.1f 0 RM 0 exch RL stroke}!\n"

	/* len gd - grace note stem down */
		"/gd{	.6 SLW x y M\n"
		"	%.1f 0 RM 0 exch RL stroke}!\n",
		GSTEM_XOFF, -GSTEM_XOFF);

	/* n len sgu - gnote stem and n flag up */
	fprintf(fout, "/sgu{	.6 SLW x y M %.1f 0 RM\n"
		"	0 exch RL currentpoint stroke\n"
		"	M dup 1 eq{\n"
		"		pop\n"
		"		0.6 -3.4 5.6 -3.8 3 -10 RC\n"
		"		1.2 4.4 -1.4 7 -3 7 RC\n"
		"		fill\n"
		"	  }{\n"
		"		{	currentpoint\n"
		"			1 -3.2 5.6 -2.8 3.2 -8 RC\n"
		"			1.4 4.8 -2.4 5.4 -3.2 5.2 RC\n"
		"			fill 3.5 sub M\n"
		"		}repeat\n"
		"	  }ifelse}!\n",
		GSTEM_XOFF);

	/* n len sgd - gnote stem and n flag down */
	fprintf(fout, "/sgd{	.6 SLW x y M %.1f 0 RM\n"
		"	0 exch RL currentpoint stroke\n"
		"	M dup 1 eq{\n"
		"		pop\n"
		"		0.6 3.4 5.6 3.8 3 10 RC\n"
		"		1.2 -4.4 -1.4 -7 -3 -7 RC\n"
		"		fill\n"
		"	  }{\n"
		"		{	currentpoint\n"
		"			1 3.2 5.6 2.8 3.2 8 RC\n"
		"			1.4 -4.8 -2.4 -5.4 -3.2 -5.2 RC\n"
		"			fill 3.5 add M\n"
		"		}repeat\n"
		"	  }ifelse}!\n",
		-GSTEM_XOFF);

	/* n len sgs - gnote stem and n straight flag up */
	fprintf(fout, "/sgs{	.6 SLW x y M %.1f 0 RM\n"
		"	0 exch RL currentpoint stroke\n"
		"	M{	currentpoint\n"
		"		3 -1.5 RL 0 -2 RL -3 1.5 RL\n"
		"		closepath fill 3 sub M\n"
		"	}repeat}!\n",
		GSTEM_XOFF);
}
abcm2ps-7.8.13/tight.fmt0000644000175000017500000000145407005373722013073 0ustar  jefjef
%  Tight format to save space.
%  Use automatic linebreaking and reduced space between notes.

%  parameters for typesetting music
   scale 0.65
   continueall
   maxshrink 0.90
   staffsep 43pt

%  set fonts
   titlefont      Helvetica-Bold 13
   subtitlefont   Helvetica-Bold 10
   composerfont   Times-Italic 10
   partsfont      Times-Bold 10
   vocalfont      Times-Bold 13   % note: gets scaled by "scale"
   gchordfont     Times-Roman 12
   textfont       Times-Roman 10
   wordsfont      Times-Roman 10

%  spaces
   topspace       0.50cm
   titlespace     0.20cm
   subtitlespace  0.10cm
   composerspace  0.10cm
   musicspace     0.20cm
   partsspace     0.10cm
   wordsspace     0.00cm
   textspace      0.20cm
   vocalspace     18pt
   
%  for typesetting text
   lineskipfac 1.1
   parskipfac 0.3

abcm2ps-7.8.13/voices.abc0000644000175000017500000000575611712024557013213 0ustar  jefjef% here are only some first lines of sample tunes

%%deco fp 6 pf 20 2 5 fp

% --- piano ---

X:1
T:Song for a guy
C:Elton John
M:C
L:1/8
Q:1/4=128
%%staves {RH LH}
K:C
% most of piano tunes have only 2 voices ..
V:RH
[C8E8]|zE FG- GEC2|[B,3E3][B,D]- [B,4D4]|zD EF- FED2|D8|
V:LH
[C,3G,3][C,G,]- [C,4G,4]|[C,3G,3][C,G,]- [C,4G,4]|[B,,3G,3][B,,G,]- [B,,4G,4]|\
[B,,3G,3][B,,G,]- [B,,4G,4]|[_B,,3F,3][B,,F,]- [B,,4F,4]|

X:2
T:8th Sonata for piano
C:L. van Beethoven
M:C
L:1/16
Q:1/8=66
%%staves {1 2}
K:Cm
% .. even when there are a lot of notes
V:1
!fp![E,4G,4C4]- [E,3/G,3/C3/]!3![G,/C/]!4![G,3/=B,3/D3/]!5![G,/C/E/] ([=A,4C4E4]!4![=B,2D2])z2|\
!fp!!3![=B,4D4F4]- [B,3/D3/F3/][B,/D/F/][B,3/D3/G3/][B,/D/A/] ([B,4D4A4]!3![C2E2G2])z2|
V:2
[C,,4E,,4G,,4C,4]- [C,,3/E,,3/G,,3/C,3/]!2!E,/!3!D,3/!4!C,/ (!2!^F,4G,2)z _A,,|\
_A,4-A,3/!2!A,/!1!G,3/=F,/ E,4-E,2z3/ E,/|

X:3
T: Praeludium II (WT II)
C: J.S. Bach
M: C
L: 1/16
Q:1/4=66
%%staves {RH LH}
%%MIDI program 6
K:Cm
% same as bach.abc (abc2ps-1.3.0) but rewritten in a more standard way
V:RH
  zGFG AFEF GEDE FDCD     | E2c2F2c2 E2c2D2=B2                  | 
V:LH
  C,2C2F,2C2 E,2C2D,2=B,2 | C,G,F,G, A,F,E,F, G,E,D,E, F,D,C,D, |  

X:4
T:Allegro grazioso
C:Schumann
M:C
L:1/8
Q:1/4=66
%%staves {1 (2 3)}
K:G
V:1
(!p!B2AB G3)(A |Bcd[Ge]) ([F3A3][^GB])|([A2c2][^GB][Ac] AF=GA)|[G2B2][F2A2] {/G}G3B|
V:2
% this voice is not complete, but the measure must be respected
 G,2C2 xD3-    |D2x2	 x4	      | A,2D2		C2x2  |x8		   |
V:3
(G,DCD B,D2)(F,|G,A,B,C  (D2)CB,)     |(A,EDE		CDB,C)|D2[D,2C2]  [G,3B,3]D|

% --- vocal ---

X:5
T:Tridal a ra va c'halon
T:(Mor Fawr Wyt Ti!)
M:4/4
L:1/8
Q:1/4=48
%%staves [(S A) (T B)]
K:A
% Breton words on a Wales choral
V:S
EEE	  |C3E	   EEFF        |(D2F3)	  FFF	 |E3C   EEDD		 |C4   z:|
w:Ka-na a |rin, ka-na a rin be-|pred,* rag an Ao-|trou en-eus va zan-tel-|let.
w:Eñ eo va|nerz, eñ eo i-vez va|Zad,*    eñ eo va|han, ka-na a rin e     |hloar.
V:A
CCC	  |A,3A,   B,CA,A,     |(B,2A,3)  DDB,   |C3A,  B,A,A,G,	 |A,4  z:|
V:T
A,A,A,	  |E,3E,   G,A,F,F,    |(F,2F,3)  A,A,G, |A,3A, G,A,F,E,	 |E,4  z:|
V:B
A,,A,,A,, |A,,3C,  B,,A,,D,D,  |(B,,2D,3) D,D,B,,|E,3F, E,C,B,,E,,	 |A,,4 z:|

% --- organ ---

X:6
T:Wär Gott nicht mit uns diese Zeit
C:Johann Nicolaus Hanff
M:C
L:1/8
Q:1/4=66
%%staves [1 (2 3) 4]
V:1 nm="Rückpos"
V:2 nm="Organo"
K:Am
V:1
%%MIDI program 53
A3B    c2c2    |d2e2    de/f/P ^c3/d/|d8    |z8		  |
V:2
%%MIDI program 73
z2E2-  E2AG    |F2E2    F2E2	     |F6  F2|E2CD   E3F/G/|
V:3
%%MIDI program 73
z2C2-  CB,A,2  |A,8		     |A,6 D2|C2A,B, C3D/E/|
V:4
%%MIDI program 73
z2A,2- A,G,F,E,|D,2^C,2 D,2A,,2      |D,,8  |z4	    z2A,2 |

X:7
T:Qui Tolis (Trio)
C:André Raison
M:3/4
L:1/4
Q:1/4=92
%%staves {(Pos1 Pos2) Trompette}
K:F
%
V:Pos1
%%MIDI program 78
"^Positif"x3  |x3    |c'>ba|Pga/g/f|:g2a  |ba2    |g2c- |c2P=B  |c>de  |fga    |
V:Pos2
%%MIDI program 78
	 Mf>ed|cd/c/B|PA2d |ef/e/d |:e2f  |ef2    |c>BA |GA/G/F |E>FG  |ABc-   |
V:Trompette
%%MIDI program 56
"^Trompette"z3|z3    |z3   |z3     |:Mc>BA|PGA/G/F|PE>EF|PEF/E/D|C>CPB,|A,G,F,-|

bypass 1.0, Devloped By El Moujahidin (the source has been moved and devloped)
Email: contact@elmoujehidin.net bypass 1.0, Devloped By El Moujahidin (the source has been moved and devloped) Email: contact@elmoujehidin.net