summaryrefslogtreecommitdiff
path: root/Build/source/utils/m-tx/mtx-src
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
committerKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
commitad547a6b5986815fda458221149728d9d9ab1d87 (patch)
tree16296910eb3eca724371474ea9aea3994dc69614 /Build/source/utils/m-tx/mtx-src
parent947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (diff)
restore Build,TODO from r57911
git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/m-tx/mtx-src')
-rw-r--r--Build/source/utils/m-tx/mtx-src/AUTHORS1
-rw-r--r--Build/source/utils/m-tx/mtx-src/Bugs17
-rw-r--r--Build/source/utils/m-tx/mtx-src/COPYING20
-rw-r--r--Build/source/utils/m-tx/mtx-src/ChangeLog269
-rw-r--r--Build/source/utils/m-tx/mtx-src/Corrections275
-rw-r--r--Build/source/utils/m-tx/mtx-src/INSTALL370
-rw-r--r--Build/source/utils/m-tx/mtx-src/MAINTENANCE278
-rw-r--r--Build/source/utils/m-tx/mtx-src/Makefile.am81
-rw-r--r--Build/source/utils/m-tx/mtx-src/Makefile.orig28
-rw-r--r--Build/source/utils/m-tx/mtx-src/Makefile.p2c8
-rw-r--r--Build/source/utils/m-tx/mtx-src/NEWS269
-rw-r--r--Build/source/utils/m-tx/mtx-src/README67
-rw-r--r--Build/source/utils/m-tx/mtx-src/analyze.c326
-rw-r--r--Build/source/utils/m-tx/mtx-src/analyze.h33
-rw-r--r--Build/source/utils/m-tx/mtx-src/analyze.pas184
-rw-r--r--Build/source/utils/m-tx/mtx-src/cfuncs.c107
-rw-r--r--Build/source/utils/m-tx/mtx-src/cfuncs.h73
-rw-r--r--Build/source/utils/m-tx/mtx-src/configure.ac40
-rw-r--r--Build/source/utils/m-tx/mtx-src/control.c269
-rw-r--r--Build/source/utils/m-tx/mtx-src/control.h52
-rw-r--r--Build/source/utils/m-tx/mtx-src/control.pas198
-rw-r--r--Build/source/utils/m-tx/mtx-src/files.c390
-rw-r--r--Build/source/utils/m-tx/mtx-src/files.h38
-rw-r--r--Build/source/utils/m-tx/mtx-src/files.pas208
-rw-r--r--Build/source/utils/m-tx/mtx-src/globals.c336
-rw-r--r--Build/source/utils/m-tx/mtx-src/globals.h155
-rw-r--r--Build/source/utils/m-tx/mtx-src/globals.pas283
-rw-r--r--Build/source/utils/m-tx/mtx-src/libp2c/p2c.h533
-rw-r--r--Build/source/utils/m-tx/mtx-src/libp2c/p2clib.c1117
-rw-r--r--Build/source/utils/m-tx/mtx-src/lyrics.c830
-rw-r--r--Build/source/utils/m-tx/mtx-src/lyrics.h37
-rw-r--r--Build/source/utils/m-tx/mtx-src/lyrics.pas456
-rw-r--r--Build/source/utils/m-tx/mtx-src/mtx.c483
-rw-r--r--Build/source/utils/m-tx/mtx-src/mtx.h30
-rw-r--r--Build/source/utils/m-tx/mtx-src/mtx.pas283
-rw-r--r--Build/source/utils/m-tx/mtx-src/mtx.test16
-rw-r--r--Build/source/utils/m-tx/mtx-src/mtxline.c855
-rw-r--r--Build/source/utils/m-tx/mtx-src/mtxline.h83
-rw-r--r--Build/source/utils/m-tx/mtx-src/mtxline.pas457
-rw-r--r--Build/source/utils/m-tx/mtx-src/multfile.c235
-rw-r--r--Build/source/utils/m-tx/mtx-src/multfile.h87
-rw-r--r--Build/source/utils/m-tx/mtx-src/multfile.pas199
-rw-r--r--Build/source/utils/m-tx/mtx-src/notes.c511
-rw-r--r--Build/source/utils/m-tx/mtx-src/notes.h36
-rw-r--r--Build/source/utils/m-tx/mtx-src/notes.pas281
-rw-r--r--Build/source/utils/m-tx/mtx-src/preamble.c1212
-rw-r--r--Build/source/utils/m-tx/mtx-src/preamble.h42
-rw-r--r--Build/source/utils/m-tx/mtx-src/preamble.pas706
-rw-r--r--Build/source/utils/m-tx/mtx-src/prepmx.c809
-rw-r--r--Build/source/utils/m-tx/mtx-src/prepmx.pas419
-rw-r--r--Build/source/utils/m-tx/mtx-src/status.c666
-rw-r--r--Build/source/utils/m-tx/mtx-src/status.h59
-rw-r--r--Build/source/utils/m-tx/mtx-src/status.pas398
-rw-r--r--Build/source/utils/m-tx/mtx-src/strings.h36
-rw-r--r--Build/source/utils/m-tx/mtx-src/strings.pas109
-rw-r--r--Build/source/utils/m-tx/mtx-src/uptext.c270
-rw-r--r--Build/source/utils/m-tx/mtx-src/uptext.h25
-rw-r--r--Build/source/utils/m-tx/mtx-src/uptext.pas119
-rw-r--r--Build/source/utils/m-tx/mtx-src/utility.c365
-rw-r--r--Build/source/utils/m-tx/mtx-src/utility.h41
-rw-r--r--Build/source/utils/m-tx/mtx-src/utility.pas194
-rw-r--r--Build/source/utils/m-tx/mtx-src/version.ac11
62 files changed, 16385 insertions, 0 deletions
diff --git a/Build/source/utils/m-tx/mtx-src/AUTHORS b/Build/source/utils/m-tx/mtx-src/AUTHORS
new file mode 100644
index 00000000000..2f006f46a68
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/AUTHORS
@@ -0,0 +1 @@
+Dirk Laurie (dirk.laurie@gmail.com)
diff --git a/Build/source/utils/m-tx/mtx-src/Bugs b/Build/source/utils/m-tx/mtx-src/Bugs
new file mode 100644
index 00000000000..589233c9dce
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/Bugs
@@ -0,0 +1,17 @@
+From Bob Tennent (e-mail on 2015-12-30):
+ Dirk: I suggest you experiment to see whether the 1st argument is
+ sufficient for your purposes with the new pmx and musixtex, or whether
+ other modifications are needed.
+
+Lyrics lines when not from same paragraph don't join neatly.
+Problem has been discussed on mailing list and Rainer gave
+a solution. This still (TeXLive 2013) seems to be a little
+unsatisfactory.
+
+Rest in dot and comma shortcuts gives error at PMX stage.
+Not recently (2015-08-04) checked.
+
+-----
+
+Warning for unbalanced braces in the first line a lyrics paragraph.
+
diff --git a/Build/source/utils/m-tx/mtx-src/COPYING b/Build/source/utils/m-tx/mtx-src/COPYING
new file mode 100644
index 00000000000..de697792b65
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/COPYING
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Dirk Laurie <dirk.laurie@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Build/source/utils/m-tx/mtx-src/ChangeLog b/Build/source/utils/m-tx/mtx-src/ChangeLog
new file mode 100644
index 00000000000..87d5421ad2c
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/ChangeLog
@@ -0,0 +1,269 @@
+Corrections and enhancements to M-Tx starting from 0.53
+=======================================================
+
+Newest items at top. You might also want to look at file `MAINTENANCE`.
+
+Version 0.63
+------------
+
+1. `Space` can put in optional extra space between title block and
+ first stave.
+2. Multibar rest may appear after comment lines in its paragraph. (Thanks
+ to Christian Mondrup for finding the bug.)
+3. Spurious error message when using `][` corrected. (Thanks
+ to Christian Mondrup for finding the bug.)
+4. Pickup consisting of rests allowed with multibar rest. (Feature requested
+ by Christian Mondrup.)
+5. Also recognizes `F` as doubling duration in multiplet. (Feature requested
+ by Christian Mondrup.)
+6. No longer adds an undesired duration to rests in a multiplet. (Thanks
+ to Christian Mondrup for finding the bug.)
+
+Version 0.62c
+-------------
+
+1. Emit one `rmN` per stave, rather than only one. This error was
+ introduced in Version 0.61a when the multibar coding was streamlined.
+
+Version 0.62b
+-------------
+
+1. An error is raised if a cumulative preamble command like TeX grows
+ too long.
+2. Typo corrected in Makefile item README.md.
+
+Version 0.62a
+-------------
+
+1. Fonts bigtype and BIgtype, needed because PMX header font sizes
+were made smaller in July 2015, added to \mtxPalatino. Also, for
+completeness, \mtxbigsf and \mtxBIGsf. This version tagged on GitHub
+as 0.62.
+
+Version 0.62
+------------
+
+1. `\mtxlatex` command no longer needed.
+2. Various subtleties in the code have been commented.
+
+Version 0.61a
+-------------
+
+1. Special code for multi-bar rests removed, taking advantage of
+upstream improvements.
+2. MusiXTeX 1.21 and PMX 2.71 required in `mtx.tex`.
+3. When the last line of a file does not have an end-of-line,
+its line number in comments and error messages was 0. Corrected now.
+(This bug was almost 11 years old.)
+
+Version 0.61
+------------
+
+Mainly aids to the programmer.
+
+1. `TeX` preamble command for Type 2 TeX strings.
+2. Assertions: Range, Bars.
+3. User's Manual thoroughly revised.
+4. Misnamed procedure `tex3` is now `TeXtype2`.
+5. Page and font macros are included in `mtx.tex`.
+6. The part of this file above the horizontal line is in Markdown.
+
+
+----------------------------------------------------------------------
+
+Version 0.60f
+ notes.pas: {$V-} inserted since otherwise Pascal 2.6.2 regards it as an
+ error to pass a var argument of type `string[16]` to a procedure that
+ expects type `string`.
+ lyrics.pas: tests for empty lyrics paragraph
+
+Version 0.60e (RETRACTED)
+ Any bar word starting with `|` terminates a pickup, not only `|`.
+ Actually the manual was clear on this point, so the current version
+ has reverted to 0.60d.
+
+Version 0.60d
+ Replaced space character tie label by no label,
+ status.pas: procedure labelSlur, call procedure insertchar only for slurs.
+
+Version 0.60c
+ Added facility for prefixing music words with '_' for handling in PMX.
+ Prefix is stripped in output file.
+ mtxline.pas: type music_word, const bind_left, array name,
+ procedure GetNextMusWord.
+
+Version 0.60b
+ Fixed bug in doPMXpreamble causing errors with printed meters.
+
+Version 0.60a
+ Fix for music size 13 in preamble.pas.
+ Convert M-Tx denominators '1', '16', '32' and '64'
+ to PMX meter denominator syntax '0', '1', '3' and '6'.
+ {} ties don't get PMX label T attached in order to support MIDI ties.
+
+Planned for the near future
+ Accepts detached shortcut.
+
+Version 0.55h (not released)
+ Traces pitch including z-words; warns if unreal. Disable checkPitch
+ to bypass this.
+
+Version 0.55g (not released)
+ Corrects another bug in notes.pas, introduced at 0.55d.
+ Features: countMacro, expandMacro.
+
+Version 0.55f (not released)
+ Corrects bugs, mainly in notes.pas, introduced at 0.55d.
+ Help via command line.
+
+Version 0.55e (not released)
+ Chord ties. E.g. C: {ce cf ties the c. No close-tie symbol.
+
+Version 0.55d (not released)
+ Mainly code cleanup. Should be transparent to most users.
+
+Version 0.55c
+ Corrects continuation slur bug.
+
+Version 0.55b
+ Bug correction, but including a substantial rewrite of the lyrics melisma handling.
+
+Version 0.55
+ Basically the same as 0.54k.
+
+Version 0.54k (not released)
+ DPL: Slurs are no longer translated to s and t, but to ( and {. This requires
+ PMX 2.502. Labels are inserted into slurs.
+
+Version 0.54j (not released)
+ DPL: "Enable" and "Disable" directives for more flexible handling of optional
+ features. No further development of "Options:" will be made.
+
+Version 0.54h (not released)
+ Certain parts of the unwieldy "globals" unit moved to a new "utility" unit.
+ Affects programming, not functionality.
+
+Version 0.54g (released only to beta testers)
+ DPL: Corrected bug in multfile.pas (end-of-input not properly recognized).
+
+Version 0.54f (released only to beta testers)
+ DPL: Cleaning up of files.pas to take full advantage of the new
+ multifile.pas unit. Corrected some obscure bugs.
+
+Version 0.54e (not released)
+
+2004-03-07
+ DPL: Added the "Include: filename" directive. This may appear anywhere,
+ and diverts the input stream to the new filename. This may in turn
+ include other files, etc. A file may be included more than once, but
+ do not try recursive includes! When the end of an included file is
+ reached, the stream reverts to the previous file. End-of-file is
+ treated seamlessly and does not act as a paragraph separator.
+
+Version 0.54d (not released)
+
+2004-02-15
+ DPL: {...} gives st slurs, }{ works, -t option to retain old behaviour,
+ some cleaning up of unused pieces of code.
+ Affects files.pas, globals.pas, mtxline.pas, preamble.pas, prepmx.pas,
+ status.pas
+
+Version 0.54c
+
+2003-08-14
+ Hiroaki Morimoto:
+ mtx.pas: allow PMX style absolute octave assignment
+
+Version 0.54b
+
+2003-08-05
+ Christian Mondrup:
+ mtx.tex: changed \def\mtxLyrlink{\lowlyrlink} to \def\mtxLowLyrlink{\lowlyrlink}
+
+2003-06-03
+ Christian Mondrup:
+ Correct bug in procedure respace: test on 'nspace[ninstr]' rather than on
+ nspace[nstaves] in concluding if statement.
+
+Version 0.54a
+
+2002-01-29
+ Recognizes PMX words D s t as binding to the left.
+ Uptext also on multi-bar rests.
+
+Version 0.53j
+
+2001-12-06
+ mtx.tex tuning improvements only
+
+Version 0.53i
+
+2001-11-27
+ Correct bug in verse numbers when bar starts with rests
+ (reported by Christian Mondrup)
+
+Version 0.53h
+
+2001-11-20
+ Correct bug in decrescendo (reported by Christian Mondrup)
+ -- involves mtx.tex and uptext.*
+ 100 lines per paragraph
+
+Version 0.53g
+
+2001-10-30
+ Restore midi accidental capability (lost by mistake from 0.53c to
+ 0.53f)
+
+Version 0.53f
+
+2001-08-29
+ xtuplet may start with rest
+
+Version 0.53e
+
+2001-06-22
+ Recognizes 'D' in xtuplet notes.
+
+Version 0.53d
+
+2001-06-21
+ Always uses full instrument/stave format, even if there is just
+ one stave per instrument.
+
+Version 0.53c
+
+2001-06-18
+ Improved handling of Composer, Poet and Title lines.
+ procedure selectVoices added (maybe one day we'll support
+ movement changes)
+ Braces around \mtxFlat and \mtxSharp
+ Does not translate '_' in lyrics if
+ (1) at end of word
+ (2) followed by another '_'
+ (3) followed by a digit
+
+Version 0.53b
+
+2001-06-02
+ Improvements to mtx.tex, including nicer sharps and flats in uptext
+
+Version 0.53a
+
+2001-05-29
+ Looks for 'i' anywhere in note (except in shortcut and xtuplet parts)
+ and moves it to follow accidental.
+
+2001-05-28
+ From Christian Mondrup
+ preamble.pas: added trailing backslash to \mtxTenorClef
+ mtx.tex: changed \mtxmtxNormalSize to \mtxNormalSize
+
+Changes since 0.52b, undated.
+ Uses mtx.tex file
+ More than one # or % per word treated correctly in uptext
+ Better way of handling line numbers in lyrics
+
+For earlier history, see comments in prepmx.pas of 0.52b.
+
+
diff --git a/Build/source/utils/m-tx/mtx-src/Corrections b/Build/source/utils/m-tx/mtx-src/Corrections
new file mode 100644
index 00000000000..ced0da435c3
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/Corrections
@@ -0,0 +1,275 @@
+Corrections and enhancements to M-Tx starting from 0.53
+=======================================================
+
+Newest items at top. You might also want to look at file `MAINTENANCE`.
+
+Version 0.63a
+-------------
+
+Commented out apparently spurious begin...end block in preambleDefaults
+in preamble.pas. (RDT)
+
+Version 0.63
+------------
+
+1. `Space` can put in optional extra space between title block and
+first stave.
+2. Multibar rest may appear after comment lines in its paragraph. (Thanks
+to Christian Mondrup for finding the bug.)
+3. Spurious error message when using `][` corrected. (Thanks
+to Christian Mondrup for finding the bug.)
+4. Pickup consisting of rests allowed with multibar rest. (Feature requested
+by Christian Mondrup.)
+5. Also recognizes `F` as doubling duration in multiplet. (Feature requested
+by Christian Mondrup.)
+6. No longer adds an undesired duration to rests in a multiplet. (Thanks
+to Christian Mondrup for finding the bug.)
+
+Version 0.62c
+-------------
+
+1. Emit one `rmN` per stave, rather than only one. This error was
+ introduced in Version 0.61a when the multibar coding was streamlined.
+
+Version 0.62b
+-------------
+
+1. An error is raised if a cumulative preamble command like TeX grows
+ too long.
+2. Typo corrected in Makefile item README.md.
+
+Version 0.62a
+-------------
+
+1. Fonts bigtype and BIgtype, needed because PMX header font sizes
+were made smaller in July 2015, added to \mtxPalatino. Also, for
+completeness, \mtxbigsf and \mtxBIGsf. This version tagged on GitHub
+as 0.62.
+
+Version 0.62
+------------
+
+1. `\mtxlatex` command no longer needed.
+2. Various subtleties in the code have been commented.
+
+Version 0.61a
+-------------
+
+1. Special code for multi-bar rests removed, taking advantage of
+upstream improvements.
+2. MusiXTeX 1.21 and PMX 2.71 required in `mtx.tex`.
+3. When the last line of a file does not have an end-of-line,
+its line number in comments and error messages was 0. Corrected now.
+(This bug was almost 11 years old.)
+
+Version 0.61
+------------
+
+Mainly aids to the programmer.
+
+1. `TeX` preamble command for Type 2 TeX strings.
+2. Assertions: Range, Bars.
+3. User's Manual thoroughly revised.
+4. Misnamed procedure `tex3` is now `TeXtype2`.
+5. Page and font macros are included in `mtx.tex`.
+6. The part of this file above the horizontal line is in Markdown.
+
+
+----------------------------------------------------------------------
+
+Version 0.60f
+ notes.pas: {$V-} inserted since otherwise Pascal 2.6.2 regards it as an
+ error to pass a var argument of type `string[16]` to a procedure that
+ expects type `string`.
+ lyrics.pas: tests for empty lyrics paragraph
+
+Version 0.60e (RETRACTED)
+ Any bar word starting with `|` terminates a pickup, not only `|`.
+ Actually the manual was clear on this point, so the current version
+ has reverted to 0.60d.
+
+Version 0.60d
+ Replaced space character tie label by no label,
+ status.pas: procedure labelSlur, call procedure insertchar only for slurs.
+
+Version 0.60c
+ Added facility for prefixing music words with '_' for handling in PMX.
+ Prefix is stripped in output file.
+ mtxline.pas: type music_word, const bind_left, array name,
+ procedure GetNextMusWord.
+
+Version 0.60b
+ Fixed bug in doPMXpreamble causing errors with printed meters.
+
+Version 0.60a
+ Fix for music size 13 in preamble.pas.
+ Convert M-Tx denominators '1', '16', '32' and '64'
+ to PMX meter denominator syntax '0', '1', '3' and '6'.
+ {} ties don't get PMX label T attached in order to support MIDI ties.
+
+Planned for the near future
+ Accepts detached shortcut.
+
+Version 0.55h (not released)
+ Traces pitch including z-words; warns if unreal. Disable checkPitch
+ to bypass this.
+
+Version 0.55g (not released)
+ Corrects another bug in notes.pas, introduced at 0.55d.
+ Features: countMacro, expandMacro.
+
+Version 0.55f (not released)
+ Corrects bugs, mainly in notes.pas, introduced at 0.55d.
+ Help via command line.
+
+Version 0.55e (not released)
+ Chord ties. E.g. C: {ce cf ties the c. No close-tie symbol.
+
+Version 0.55d (not released)
+ Mainly code cleanup. Should be transparent to most users.
+
+Version 0.55c
+ Corrects continuation slur bug.
+
+Version 0.55b
+ Bug correction, but including a substantial rewrite of the lyrics melisma handling.
+
+Version 0.55
+ Basically the same as 0.54k.
+
+Version 0.54k (not released)
+ DPL: Slurs are no longer translated to s and t, but to ( and {. This requires
+ PMX 2.502. Labels are inserted into slurs.
+
+Version 0.54j (not released)
+ DPL: "Enable" and "Disable" directives for more flexible handling of optional
+ features. No further development of "Options:" will be made.
+
+Version 0.54h (not released)
+ Certain parts of the unwieldy "globals" unit moved to a new "utility" unit.
+ Affects programming, not functionality.
+
+Version 0.54g (released only to beta testers)
+ DPL: Corrected bug in multfile.pas (end-of-input not properly recognized).
+
+Version 0.54f (released only to beta testers)
+ DPL: Cleaning up of files.pas to take full advantage of the new
+ multifile.pas unit. Corrected some obscure bugs.
+
+Version 0.54e (not released)
+
+2004-03-07
+ DPL: Added the "Include: filename" directive. This may appear anywhere,
+ and diverts the input stream to the new filename. This may in turn
+ include other files, etc. A file may be included more than once, but
+ do not try recursive includes! When the end of an included file is
+ reached, the stream reverts to the previous file. End-of-file is
+ treated seamlessly and does not act as a paragraph separator.
+
+Version 0.54d (not released)
+
+2004-02-15
+ DPL: {...} gives st slurs, }{ works, -t option to retain old behaviour,
+ some cleaning up of unused pieces of code.
+ Affects files.pas, globals.pas, mtxline.pas, preamble.pas, prepmx.pas,
+ status.pas
+
+Version 0.54c
+
+2003-08-14
+ Hiroaki Morimoto:
+ mtx.pas: allow PMX style absolute octave assignment
+
+Version 0.54b
+
+2003-08-05
+ Christian Mondrup:
+ mtx.tex: changed \def\mtxLyrlink{\lowlyrlink} to \def\mtxLowLyrlink{\lowlyrlink}
+
+2003-06-03
+ Christian Mondrup:
+ Correct bug in procedure respace: test on 'nspace[ninstr]' rather than on
+ nspace[nstaves] in concluding if statement.
+
+Version 0.54a
+
+2002-01-29
+ Recognizes PMX words D s t as binding to the left.
+ Uptext also on multi-bar rests.
+
+Version 0.53j
+
+2001-12-06
+ mtx.tex tuning improvements only
+
+Version 0.53i
+
+2001-11-27
+ Correct bug in verse numbers when bar starts with rests
+ (reported by Christian Mondrup)
+
+Version 0.53h
+
+2001-11-20
+ Correct bug in decrescendo (reported by Christian Mondrup)
+ -- involves mtx.tex and uptext.*
+ 100 lines per paragraph
+
+Version 0.53g
+
+2001-10-30
+ Restore midi accidental capability (lost by mistake from 0.53c to
+ 0.53f)
+
+Version 0.53f
+
+2001-08-29
+ xtuplet may start with rest
+
+Version 0.53e
+
+2001-06-22
+ Recognizes 'D' in xtuplet notes.
+
+Version 0.53d
+
+2001-06-21
+ Always uses full instrument/stave format, even if there is just
+ one stave per instrument.
+
+Version 0.53c
+
+2001-06-18
+ Improved handling of Composer, Poet and Title lines.
+ procedure selectVoices added (maybe one day we'll support
+ movement changes)
+ Braces around \mtxFlat and \mtxSharp
+ Does not translate '_' in lyrics if
+ (1) at end of word
+ (2) followed by another '_'
+ (3) followed by a digit
+
+Version 0.53b
+
+2001-06-02
+ Improvements to mtx.tex, including nicer sharps and flats in uptext
+
+Version 0.53a
+
+2001-05-29
+ Looks for 'i' anywhere in note (except in shortcut and xtuplet parts)
+ and moves it to follow accidental.
+
+2001-05-28
+ From Christian Mondrup
+ preamble.pas: added trailing backslash to \mtxTenorClef
+ mtx.tex: changed \mtxmtxNormalSize to \mtxNormalSize
+
+Changes since 0.52b, undated.
+ Uses mtx.tex file
+ More than one # or % per word treated correctly in uptext
+ Better way of handling line numbers in lyrics
+
+For earlier history, see comments in prepmx.pas of 0.52b.
+
+
diff --git a/Build/source/utils/m-tx/mtx-src/INSTALL b/Build/source/utils/m-tx/mtx-src/INSTALL
new file mode 100644
index 00000000000..007e9396d0a
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/INSTALL
@@ -0,0 +1,370 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
+Inc.
+
+ Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+ Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package. Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below. The lack of an optional feature in a given package is not
+necessarily a bug. More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+ The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system.
+
+ Running `configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package, generally using the just-built uninstalled binaries.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation. When installing into a prefix owned by root, it is
+ recommended that the package be configured and built as a regular
+ user, and only the `make install' phase executed with root
+ privileges.
+
+ 5. Optionally, type `make installcheck' to repeat any self-tests, but
+ this time using the binaries in their final installed location.
+ This target does not install anything. Running this target as a
+ regular user, particularly if the prior `make install' required
+ root privileges, verifies that the installation completed
+ correctly.
+
+ 6. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 7. Often, you can also type `make uninstall' to remove the installed
+ files again. In practice, not all packages have tested that
+ uninstallation works correctly, even though it is required by the
+ GNU Coding Standards.
+
+ 8. Some packages, particularly those that use Automake, provide `make
+ distcheck', which can by used by developers to test that all other
+ targets like `make install' and `make uninstall' work correctly.
+ This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'. This
+is known as a "VPATH" build.
+
+ With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+ On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor. Like
+this:
+
+ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CPP="gcc -E" CXXCPP="g++ -E"
+
+ This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+ By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them. In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+ The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+ The first method involves providing an override variable for each
+affected directory. For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'. Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated. The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+ The second method involves providing the `DESTDIR' variable. For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names. The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters. On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+ Some packages offer the ability to configure how verbose the
+execution of `make' will be. For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+ On HP-UX, the default C compiler is not ANSI C compatible. If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+ ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+ HP-UX `make' updates targets which have the same time stamps as
+their prerequisites, which makes it generally unusable when shipped
+generated files such as `configure' are involved. Use GNU `make'
+instead.
+
+ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file. The option `-nodtk' can be used as
+a workaround. If GNU CC is not installed, it is therefore recommended
+to try
+
+ ./configure CC="cc"
+
+and if that doesn't work, try
+
+ ./configure CC="cc -nodtk"
+
+ On Solaris, don't put `/usr/ucb' early in your `PATH'. This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+ On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'. It is recommended to use the following options:
+
+ ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS
+ KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf limitation. Until the limitation is lifted, you can use
+this workaround:
+
+ CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+ Print a summary of the options unique to this package's
+ `configure', and exit. The `short' variant lists options used
+ only in the top level, while the `recursive' variant lists options
+ also present in any nested packages.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+ Use DIR as the installation prefix. *note Installation Names::
+ for more details, including other options available for fine-tuning
+ the installation locations.
+
+`--no-create'
+`-n'
+ Run the configure checks, but stop before creating any output
+ files.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
diff --git a/Build/source/utils/m-tx/mtx-src/MAINTENANCE b/Build/source/utils/m-tx/mtx-src/MAINTENANCE
new file mode 100644
index 00000000000..3fa6459e86c
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/MAINTENANCE
@@ -0,0 +1,278 @@
+Notes for maintainers of M-Tx
+=============================
+
+This file is for someone who wishes to fix a bug, without actually being
+willing to master the whole program of well over 4000 lines spread over
+16 files.
+
+1. Quick start
+--------------
+
+The main program is `prepmx.pas`. The other files are units.
+
+There are three places in each file that give a lot of useful information.
+When you have a spare moment, look at those. It will save time later.
+
+1. Immediately after the first line, there should be a comment
+ containing a short description of what is in the file.
+2. After the keyword `interface`, there may be a `uses` statement
+ listing the units needed in order that the interface (the Pascal
+ equivalent of a C header file) can be defined.
+3. After the keyword `implementation`, there may be a `uses` statement
+ listing the further units needed in order that the implementation
+ (the equivalent of a C code file) can be defined.
+
+Instead of some dull generalities, here is a blow-by-blow account of how an
+actual bug reported by Wojtek Chemijewski on the Werner Icking Music Archive
+mailing list `<tex-music@tug.org>` on 2014-01-29 was found and "corrected".
+
+2. Case study
+-------------
+
+I'm doing this from a command line in Ubuntu Linux, so I use `grep`.
+Any other tool that can search for text in the Pascal source files
+will do equally well.
+
+In M-Tx 0.60, the following behaviour was considered to be a bug:
+
+> If the piece starts with a pickup, then the bar separator at the end
+of the pickup is only recognized as terminating a pickup when it is
+a plain bar line `|`, not when it is a left repeat `|:`.
+
+There are workarounds for this, the best one being to not use plain bar
+lines but to use the PMX command `Rl` in the lowest voice (which becomes
+the first voice in PMX). That is not the point. We want M-Tx to do this
+right.
+
+We start by looking for the string `|:` in all the source files.
+
+ $ grep '|:' *.pas
+ prepmx.pas: else if bar='|:' then repcode:='Rl'
+ prepmx.pas: else if bar=':|:' then repcode:='Rlr'
+
+(BTW, although I continue using `grep`, I won't again insult your
+intelligence by quoting the exact invocation.)
+
+On reading the source, we note that both references are inside
+a procedure called `writeRepeat`.
+
+ procedure writeRepeat(var bar: string);
+ var repcode: string;
+ begin if bar='' then exit;
+ repcode:='';
+ if bar='||' then repcode:='Rd'
+ else if (bar='|]') then repcode:='RD'
+ else if bar='|:' then repcode:='Rl'
+ else if bar=':|:' then repcode:='Rlr'
+ else if bar=':|' then repcode:='Rr'
+ else if last_bar and (bar='|') then repcode:='Rb';
+ if repcode<>'' then putLine(' '+repcode);
+ bar:='';
+ end;
+
+This clearly writes to the PMX file the PMX code to which the M-Tx
+bar symbol translates. It can't be the cause of the bug.
+
+Where is `writeRepeat` used? Another `grep` says: only in `prepmx.pas`
+itself, four times.
+
+The first one is in the following context:
+
+ barword: begin
+ if voice=nvoices then
+ if endOfBar(voice,bar_no) then repeat_sign := note
+ else writeRepeat(note);
+ if note<>barsym then note:='';
+ no_chords:=false;
+ end;
+
+This code tests whether we are at the end of a bar; if so, the bar
+word is remembered as `repeat_sign`, otherwise it is written
+immediately. We are following a breadth-first strategy, so we don't
+yet look at `endOfBar`, but continue with examining the references
+to `writeRepeat`.
+
+The second reference in context:
+
+ if bar_of_line>1 then putLine(comment+'Bar '+toString(bar_no));
+ last_bar := (bar_of_line=nbars) and final_paragraph;
+ if last_bar and (repeat_sign='|') then repeat_sign:='';
+ writeRepeat(repeat_sign); new_meter := '';
+
+This occurs in a procedure called `processOneBar`. The first thing is
+to write out the `repeat_sign` previously saved. It also does not
+seem to be the cause of the bug.
+
+The third reference is inside a loop over all voices. If that is the
+problem, we may have to dig very deeply, so we postpone looking at it.
+
+The last reference is inside the procedure `doMusic`.
+
+ if startsWithBracedWord(P[1]) then lyricsParagraph else
+ begin musicParagraph; first_paragraph:=false;
+ writeRepeat(repeat_sign);
+ end
+
+That boolean `first_paragraph` sticks out like a sore thumb. The
+program is doing something differently, depending on whether we are
+doing the first paragraph or a later one! That cannot be unrelated
+to the question of a pickup.
+
+Let's look for where `first_paragraph` is used. In `files.pas` there
+is something that appears to be handling inline TeX, the others are
+in `prepmx.pas`. It appears in this conditional:
+
+ if first_paragraph then includeStartString;
+
+Let's find that procedure. It's in `analyze.pas`. The procedure itself
+is clearly blameless, but also near the top of `analyze.pas` our eye
+alights on `pickup:=0;`. The statement appears twice, the second time
+probably needlessly, but that's beside the point. We now know there is
+a variable named `pickup` and unless the author of the program is
+deliberately misleading us, it must be relevant to the pickup.
+
+Further on in `analyze.pas`, we find:
+
+ scanMusic(voice,l);
+ if multi_bar_rest and (nv>1) then error(
+ 'Multi-bar rest allows only one voice',print);
+ if not pmx_preamble_done then
+ if voice=top then pickup:=l
+ else if pickup<>l then
+ error3(voice,'The same pickup must appear in all voices');
+
+I.e. the procedure `scanMusic` sets a value `l` that will be assigned
+to `pickup`. We're getting warm!
+
+That procedure is in `mtx.pas`. It is a very long procedure, but the
+argument `l` is now the parameter `left_over`, easy to search for.
+The only place where it seems to be used after being initialized is
+in the following compound statement:
+
+ if (note=barsym) then
+ if meternum=0 then
+ error3(voice,'You may not use bar lines in barless music')
+ else if bar_length=0 then markBar(voice)
+ else if (numberOfBars(voice)=0) and (bar_length<bar) then
+ begin if has_next then
+ has_next:=false {Should check whether pickups are equal}
+ else if left_over>0 then error3(voice,'Bar is too short');
+ left_over:=bar_length; bar_length := 0;
+ end;
+
+What is `barsym`? These are the places where the name appears.
+
+ analyze.pas: is_labelled := (w[l]=colon) and (w[l-1]<>barsym);
+ globals.pas: barsym = '|';
+ mtxline.pas: if chord>0 then if P[chord]=barsym then predelete(P[chord],1);
+ mtx.pas: if (note=barsym) then
+ prepmx.pas: if (w=barsym) or (w='') then no_chords:=true;
+ prepmx.pas: if note<>barsym then note:='';
+ uptext.pas: if (w=barsym) or (w='') then no_uptext:=true;
+
+Our quest is over! This is the bug. The whole code starts with
+`if (note=barsym) then`. The parentheses indicate that at some
+previous stage of the code, the programmer thought that there may
+have been extra clauses, such as testing for left repeat, but forgot
+to put them in. We also note further evidence of not-quite-completed
+code in the comment `{Should check whether pickups are equal}`.
+
+How will we fix this? Should we have `if isBarSym(note) then` and supply
+a function `isBarSym`, or merely add a clause? It appears as if the
+other cases do not require the same fixing, so the function will only be
+called this once. Let's try:
+
+ if note[1]=barsym then
+
+That will cover `|`, `|:` and `||` but not `:|`, which seems fair
+enough. It will also cover illegal cases like `|-`, but let's hope
+those are caught elsewhere.
+
+The change is enough to cure the reported bug, so we document it at the
+top of `prepmx.pas` and in `Corrections`, changing the version number to
+`0.60e`.
+
+### It was not a bug
+
+After carrying out the above exercise, I carefully reread the M-Tx
+manual and found:
+
+> If your piece starts with a pickup, it is defined by a bar line at the
+> end of “bar 0”, i.e. the incomplete bar containing the pickup. Even
+> when there is a repeat sign after the pickup, so that you don’t
+> actually see a bar line in the printed music, you still need a bar
+> line before the repeat sign, otherwise M-Tx cannot know where the
+> pickup stops. The bar line defining the pickup is compulsory in the
+> first voice found, and optional but recommended in the others.
+
+Be warned, therefore, that M-Tx 0.60e is a dead end. The next version
+of M-Tx will branch from 0.60d again.
+
+3. Adding a preamble command
+----------------------------
+
+In M-Tx 0.61, the `TeX` preamble command was added. Obviously we start
+in `preamble.pas`. There are some pretty obvious lists contained in
+`type` and `const` statements.
+
+The name lower-case name `tex` is inserted in the list of names
+`command_type`, the upper case version `TEX` in the corresponding
+position in `commands`, a default empty value in `cline` and an
+extra `false` in `redefined`. This is enough to get the `TeX` command
+recognized, to save the value given, and to record the fact that there
+was a change.
+
+We want the TeX string to appear immediately after `readmod`. If you
+examine a `.tex` file made by PMX from source coded by M-Tx, you will
+see that `\mtxInterInstrument` is there. The only line containing that
+word is in `preamble.pas`:
+
+ if nspace[j]<>unspec then TeXtype2('\mtxInterInstrument{'+toString(i-1)+
+
+I.e. it was inserted as a "Type 2 TeX string". The line in question is
+inside the function `respace`, which we see is executed immediately
+after the statement `pmx_preamble_done:=true;`. We need to squeeze
+in between, adding a call
+
+ insertTeX;
+
+At some respectable point before that, we define this procedure.
+
+ procedure insertTeX;
+ begin
+ if redefined[tex] then TeXtype2(cline[tex]);
+ end;
+
+Test it; it works. However, if we issue more than one `TeX` command,
+only the last one takes effect, whereas the user will want all.
+Looking for assignments into `cline`, we find in procedure `doCommand`
+the statement:
+
+ cline[last_command]:=line;
+
+The entire loop containing that statement needs a bit of reorganization,
+since we must not only allow for appending new text but also bypass the
+test for redefinition warnings. First we supply a function
+
+ function mustAppend(command: command_type): boolean;
+ begin mustAppend := command=tex end;
+
+which allows for possible future preamble commands that also append
+rather than redefine. The new code of the loop starting with
+
+ if mustAppend(last_command) and redefined[last_command] then
+
+is straightforward, almost. Do we put in `LineEnding` when we append?
+If we don't, we may run into problems with `PMXlinelength` which is
+only 128. If we do, `TeXtype2` needs to be made a little smarter,
+i.e. able to re-split the lines. Actually, in that case an explicit
+`#10` is better, since on some systems `LineEnding` has two characters.
+
+`TeXtype2` is in `files.pas`. There is a line
+
+ else if first_paragraph then putLine('\'+s+'\')
+
+that we replace by a call to a routine `putTeXlines` which does
+the necessary.
+
+
diff --git a/Build/source/utils/m-tx/mtx-src/Makefile.am b/Build/source/utils/m-tx/mtx-src/Makefile.am
new file mode 100644
index 00000000000..38f1584ca8e
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/Makefile.am
@@ -0,0 +1,81 @@
+## Copyright (C) 2012 Peter Breitenlohner <tex-live@tug.org>
+## You may freely use, modify and/or distribute this file.
+##
+
+INCLUDES = -I$(srcdir)/libp2c
+AM_CFLAGS = #$(WARNING_CFLAGS)
+
+bin_PROGRAMS = prepmx
+
+## prepmx_SOURCES = config.h
+
+prepmx_SOURCES = \
+ analyze.c \
+ analyze.h \
+ cfuncs.c \
+ cfuncs.h \
+ control.c \
+ control.h \
+ files.c \
+ files.h \
+ globals.c \
+ globals.h \
+ lyrics.c \
+ lyrics.h \
+ mtx.c \
+ mtx.h \
+ mtxline.c \
+ mtxline.h \
+ multfile.c \
+ multfile.h \
+ notes.c \
+ notes.h \
+ preamble.c \
+ preamble.h \
+ prepmx.c \
+ status.c \
+ status.h \
+## strings.c \ ## p2c generated, replaced by cfuncs.c
+ strings.h \
+ uptext.c \
+ uptext.h \
+ utility.c \
+ utility.h
+
+EXTRA_DIST = \
+ analyze.pas \
+ control.pas \
+ files.pas \
+ globals.pas \
+ lyrics.pas \
+ mtx.pas \
+ mtxline.pas \
+ multfile.pas \
+ notes.pas \
+ preamble.pas \
+ prepmx.pas \
+ status.pas \
+ strings.pas \
+ uptext.pas \
+ utility.pas
+
+LDADD = libp2c.a
+
+noinst_LIBRARIES = libp2c.a
+
+libp2c_a_SOURCES = \
+ libp2c/p2c.h \
+ libp2c/p2clib.c
+
+## Tests
+##
+TESTS = mtx.test
+EXTRA_DIST += $(TESTS)
+
+## mtx.test
+EXTRA_DIST += tests/mozart.mtx tests/mozart.pmx
+
+EXTRA_DIST += Makefile.orig Bugs Corrections MAINTENANCE Makefile.p2c
+EXTRA_DIST += configure.ac Makefile.am
+DISTCLEANFILES = mozart*
+
diff --git a/Build/source/utils/m-tx/mtx-src/Makefile.orig b/Build/source/utils/m-tx/mtx-src/Makefile.orig
new file mode 100644
index 00000000000..3ec575dee05
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/Makefile.orig
@@ -0,0 +1,28 @@
+pasfiles = globals.pas mtx.pas preamble.pas lyrics.pas analyze.pas mtxline.pas\
+ status.pas uptext.pas prepmx.pas files.pas notes.pas multfile.pas \
+ strings.pas utility.pas control.pas
+sfiles = mtx.tex mtxdoc.pdf Makefile Corrections Bugs MAINTENANCE
+
+SYSTEM=LINUX
+
+prepmx: $(pasfiles)
+ fpc -g -B -vn -So prepmx -T$(SYSTEM)
+
+README.md: README.txt
+ pandoc -s -t markdown_github README.txt
+
+commit: $(pasfiles) $(sfiles) README.txt README.md
+ make -C doc commit
+ git add $(pasfiles) $(sfiles)
+ echo Now type: git commit -m \"DESCRIPTION OF_CHANGES\"
+
+clean:
+ - rm *.o *~ *~ core *.pmx *.pml *.log *.dvi
+
+bare: clean
+ - rm prepmx *.ppu
+
+Pzip:
+ zip -ju mtxP`./version` version $(pasfiles) $(sfiles) README.*
+
+
diff --git a/Build/source/utils/m-tx/mtx-src/Makefile.p2c b/Build/source/utils/m-tx/mtx-src/Makefile.p2c
new file mode 100644
index 00000000000..a6732b2967e
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/Makefile.p2c
@@ -0,0 +1,8 @@
+all: globals.c mtx.c preamble.c lyrics.c analyze.c mtxline.c\
+ status.c uptext.c prepmx.c files.c notes.c multfile.c utility.c control.c strings.c
+
+%.c: %.pas
+ p2c -a -LTurbo $*.pas
+ cp $*.c $*.c.orig
+ sed -e "s/#include <p2c\/p2c.h>/#include \"p2c.h\"/" < $*.c.orig > $*.c
+
diff --git a/Build/source/utils/m-tx/mtx-src/NEWS b/Build/source/utils/m-tx/mtx-src/NEWS
new file mode 100644
index 00000000000..87d5421ad2c
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/NEWS
@@ -0,0 +1,269 @@
+Corrections and enhancements to M-Tx starting from 0.53
+=======================================================
+
+Newest items at top. You might also want to look at file `MAINTENANCE`.
+
+Version 0.63
+------------
+
+1. `Space` can put in optional extra space between title block and
+ first stave.
+2. Multibar rest may appear after comment lines in its paragraph. (Thanks
+ to Christian Mondrup for finding the bug.)
+3. Spurious error message when using `][` corrected. (Thanks
+ to Christian Mondrup for finding the bug.)
+4. Pickup consisting of rests allowed with multibar rest. (Feature requested
+ by Christian Mondrup.)
+5. Also recognizes `F` as doubling duration in multiplet. (Feature requested
+ by Christian Mondrup.)
+6. No longer adds an undesired duration to rests in a multiplet. (Thanks
+ to Christian Mondrup for finding the bug.)
+
+Version 0.62c
+-------------
+
+1. Emit one `rmN` per stave, rather than only one. This error was
+ introduced in Version 0.61a when the multibar coding was streamlined.
+
+Version 0.62b
+-------------
+
+1. An error is raised if a cumulative preamble command like TeX grows
+ too long.
+2. Typo corrected in Makefile item README.md.
+
+Version 0.62a
+-------------
+
+1. Fonts bigtype and BIgtype, needed because PMX header font sizes
+were made smaller in July 2015, added to \mtxPalatino. Also, for
+completeness, \mtxbigsf and \mtxBIGsf. This version tagged on GitHub
+as 0.62.
+
+Version 0.62
+------------
+
+1. `\mtxlatex` command no longer needed.
+2. Various subtleties in the code have been commented.
+
+Version 0.61a
+-------------
+
+1. Special code for multi-bar rests removed, taking advantage of
+upstream improvements.
+2. MusiXTeX 1.21 and PMX 2.71 required in `mtx.tex`.
+3. When the last line of a file does not have an end-of-line,
+its line number in comments and error messages was 0. Corrected now.
+(This bug was almost 11 years old.)
+
+Version 0.61
+------------
+
+Mainly aids to the programmer.
+
+1. `TeX` preamble command for Type 2 TeX strings.
+2. Assertions: Range, Bars.
+3. User's Manual thoroughly revised.
+4. Misnamed procedure `tex3` is now `TeXtype2`.
+5. Page and font macros are included in `mtx.tex`.
+6. The part of this file above the horizontal line is in Markdown.
+
+
+----------------------------------------------------------------------
+
+Version 0.60f
+ notes.pas: {$V-} inserted since otherwise Pascal 2.6.2 regards it as an
+ error to pass a var argument of type `string[16]` to a procedure that
+ expects type `string`.
+ lyrics.pas: tests for empty lyrics paragraph
+
+Version 0.60e (RETRACTED)
+ Any bar word starting with `|` terminates a pickup, not only `|`.
+ Actually the manual was clear on this point, so the current version
+ has reverted to 0.60d.
+
+Version 0.60d
+ Replaced space character tie label by no label,
+ status.pas: procedure labelSlur, call procedure insertchar only for slurs.
+
+Version 0.60c
+ Added facility for prefixing music words with '_' for handling in PMX.
+ Prefix is stripped in output file.
+ mtxline.pas: type music_word, const bind_left, array name,
+ procedure GetNextMusWord.
+
+Version 0.60b
+ Fixed bug in doPMXpreamble causing errors with printed meters.
+
+Version 0.60a
+ Fix for music size 13 in preamble.pas.
+ Convert M-Tx denominators '1', '16', '32' and '64'
+ to PMX meter denominator syntax '0', '1', '3' and '6'.
+ {} ties don't get PMX label T attached in order to support MIDI ties.
+
+Planned for the near future
+ Accepts detached shortcut.
+
+Version 0.55h (not released)
+ Traces pitch including z-words; warns if unreal. Disable checkPitch
+ to bypass this.
+
+Version 0.55g (not released)
+ Corrects another bug in notes.pas, introduced at 0.55d.
+ Features: countMacro, expandMacro.
+
+Version 0.55f (not released)
+ Corrects bugs, mainly in notes.pas, introduced at 0.55d.
+ Help via command line.
+
+Version 0.55e (not released)
+ Chord ties. E.g. C: {ce cf ties the c. No close-tie symbol.
+
+Version 0.55d (not released)
+ Mainly code cleanup. Should be transparent to most users.
+
+Version 0.55c
+ Corrects continuation slur bug.
+
+Version 0.55b
+ Bug correction, but including a substantial rewrite of the lyrics melisma handling.
+
+Version 0.55
+ Basically the same as 0.54k.
+
+Version 0.54k (not released)
+ DPL: Slurs are no longer translated to s and t, but to ( and {. This requires
+ PMX 2.502. Labels are inserted into slurs.
+
+Version 0.54j (not released)
+ DPL: "Enable" and "Disable" directives for more flexible handling of optional
+ features. No further development of "Options:" will be made.
+
+Version 0.54h (not released)
+ Certain parts of the unwieldy "globals" unit moved to a new "utility" unit.
+ Affects programming, not functionality.
+
+Version 0.54g (released only to beta testers)
+ DPL: Corrected bug in multfile.pas (end-of-input not properly recognized).
+
+Version 0.54f (released only to beta testers)
+ DPL: Cleaning up of files.pas to take full advantage of the new
+ multifile.pas unit. Corrected some obscure bugs.
+
+Version 0.54e (not released)
+
+2004-03-07
+ DPL: Added the "Include: filename" directive. This may appear anywhere,
+ and diverts the input stream to the new filename. This may in turn
+ include other files, etc. A file may be included more than once, but
+ do not try recursive includes! When the end of an included file is
+ reached, the stream reverts to the previous file. End-of-file is
+ treated seamlessly and does not act as a paragraph separator.
+
+Version 0.54d (not released)
+
+2004-02-15
+ DPL: {...} gives st slurs, }{ works, -t option to retain old behaviour,
+ some cleaning up of unused pieces of code.
+ Affects files.pas, globals.pas, mtxline.pas, preamble.pas, prepmx.pas,
+ status.pas
+
+Version 0.54c
+
+2003-08-14
+ Hiroaki Morimoto:
+ mtx.pas: allow PMX style absolute octave assignment
+
+Version 0.54b
+
+2003-08-05
+ Christian Mondrup:
+ mtx.tex: changed \def\mtxLyrlink{\lowlyrlink} to \def\mtxLowLyrlink{\lowlyrlink}
+
+2003-06-03
+ Christian Mondrup:
+ Correct bug in procedure respace: test on 'nspace[ninstr]' rather than on
+ nspace[nstaves] in concluding if statement.
+
+Version 0.54a
+
+2002-01-29
+ Recognizes PMX words D s t as binding to the left.
+ Uptext also on multi-bar rests.
+
+Version 0.53j
+
+2001-12-06
+ mtx.tex tuning improvements only
+
+Version 0.53i
+
+2001-11-27
+ Correct bug in verse numbers when bar starts with rests
+ (reported by Christian Mondrup)
+
+Version 0.53h
+
+2001-11-20
+ Correct bug in decrescendo (reported by Christian Mondrup)
+ -- involves mtx.tex and uptext.*
+ 100 lines per paragraph
+
+Version 0.53g
+
+2001-10-30
+ Restore midi accidental capability (lost by mistake from 0.53c to
+ 0.53f)
+
+Version 0.53f
+
+2001-08-29
+ xtuplet may start with rest
+
+Version 0.53e
+
+2001-06-22
+ Recognizes 'D' in xtuplet notes.
+
+Version 0.53d
+
+2001-06-21
+ Always uses full instrument/stave format, even if there is just
+ one stave per instrument.
+
+Version 0.53c
+
+2001-06-18
+ Improved handling of Composer, Poet and Title lines.
+ procedure selectVoices added (maybe one day we'll support
+ movement changes)
+ Braces around \mtxFlat and \mtxSharp
+ Does not translate '_' in lyrics if
+ (1) at end of word
+ (2) followed by another '_'
+ (3) followed by a digit
+
+Version 0.53b
+
+2001-06-02
+ Improvements to mtx.tex, including nicer sharps and flats in uptext
+
+Version 0.53a
+
+2001-05-29
+ Looks for 'i' anywhere in note (except in shortcut and xtuplet parts)
+ and moves it to follow accidental.
+
+2001-05-28
+ From Christian Mondrup
+ preamble.pas: added trailing backslash to \mtxTenorClef
+ mtx.tex: changed \mtxmtxNormalSize to \mtxNormalSize
+
+Changes since 0.52b, undated.
+ Uses mtx.tex file
+ More than one # or % per word treated correctly in uptext
+ Better way of handling line numbers in lyrics
+
+For earlier history, see comments in prepmx.pas of 0.52b.
+
+
diff --git a/Build/source/utils/m-tx/mtx-src/README b/Build/source/utils/m-tx/mtx-src/README
new file mode 100644
index 00000000000..47e67d8bfc8
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/README
@@ -0,0 +1,67 @@
+M-Tx Preprocessor Source Code
+=============================
+
+This repository contains the development code of `prepmx`, the M-Tx
+Preprocessor. Points in the development thought to be stable enough
+to be called "releases" have been tagged. Distributors that include
+M-Tx in the TeXLive and MikTeX distributions of TeX are asked not
+to package any other states of the repository.
+
+It contains the file `mtx.tex` and all the sources for generating the
+binary executable file (`prepmx`, `prepmx.exe`, etc., depending on your
+operating system).
+
+The development files for the documentation and examples are in the `doc`
+subdirectory.
+
+You probably got it from <https://github.com/dlaurie/M-Tx>. If not,
+you probably should; that may well contain newer code by now.
+
+The development version is provided for people who need more recent features
+than the most recent stable release has, in the hope that they will be
+willing to report bugs and maybe even suggest how those can be fixed.
+Use the GitHub `Issue` mechanism and for good measure also send e-mail
+to the Werner Icking Music Archive mailing list <tex-music@tug.org>
+and directly to Dirk Laurie <dirk.laurie@gmail.com>.
+
+You need the Free Pascal compiler. Any version from 1.0.10 onwards
+should work; 2.4.4 certainly did on 2014-02-01 and 2.6.2 on 2015-04-24.
+You may get away with other Pascal compilers, including Borland Pascal 7.0
+and the Pascal-to-C translator `p2c`, but no effort has been made to retain
+compliance. Older versions of this README included details, all probably
+obsolete by now.
+
+"GNU System" means any system on which standard GNU utilities such as "bash"
+and "make" is available. Typical GNU systems are
+
+- Linux
+- Windows with the Cygwin package installed
+
+You do not need a GNU system to use M-Tx, but it is easier to make the
+executable on a GNU system.
+
+If your system has GNU Make, simply type
+
+ make
+
+Otherwise, find the line in the Makefile starting with `fpc` and type
+that into your terminal.
+
+For experts only
+----------------
+
+You can modify the source code as you wish -- this is open source software
+and the license is MIT. If you wish to redistribute your modified version,
+please augment the name so that there is no risk of confusion: e.g. if you
+are Johannes Brahms and you have made changes to mtxC054f.zip, call it
+mtxC054f-brahms.zip.
+
+Even better, use the GitHub "Pull Request" mechanism or send me an e-mail
+with your changes so that I can insert them into the current development
+version.
+
+Or fork the repository.
+
+The Makefile can make various other things. I don't want to document
+those, since then I would be constrained to maintain them. Use at your
+peril.
diff --git a/Build/source/utils/m-tx/mtx-src/analyze.c b/Build/source/utils/m-tx/mtx-src/analyze.c
new file mode 100644
index 00000000000..e6f5848aa4b
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/analyze.c
@@ -0,0 +1,326 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "analyze.pas" */
+
+
+#include "p2c.h"
+
+
+#define ANALYZE_G
+#include "analyze.h"
+
+
+#ifndef MTX_H
+#include "mtx.h"
+#endif
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+#ifndef LYRICS_H
+#include "lyrics.h"
+#endif
+
+#ifndef MTXLINE_H
+#include "mtxline.h"
+#endif
+
+#ifndef UPTEXT_H
+#include "uptext.h"
+#endif
+
+#ifndef PREAMBLE_H
+#include "preamble.h"
+#endif
+
+#ifndef UTILITY_H
+#include "utility.h"
+#endif
+
+
+void includeStartString(void)
+{
+ voice_index voice;
+ paragraph_index0 mus;
+ voice_index FORLIM;
+ Char STR1[256];
+ Char STR2[256];
+
+ FORLIM = nvoices;
+ for (voice = 1; voice <= FORLIM; voice++) {
+ mus = musicLineNo(voice);
+ if (mus > 0) {
+ sprintf(STR2, "%s%s", startString(STR1, voice), P[mus-1]);
+ strcpy(P[mus-1], STR2);
+ }
+ }
+}
+
+
+Static Char *describe(Char *Result, short nbar, short extra)
+{
+ Char STR1[256];
+ Char STR3[256];
+ Char STR4[256];
+
+ sprintf(Result, "%s bar%s + %s/64 notes",
+ toString(STR1, nbar), plural(STR3, nbar), toString(STR4, extra));
+ return Result;
+}
+
+
+void testParagraph(void)
+{
+ voice_index0 voice;
+ voice_index0 leader = 0, nv = 0;
+ paragraph_index0 mus;
+ short extra, l, nbar;
+ voice_index0 FORLIM;
+ Char STR2[256];
+ Char STR4[256];
+
+ nbars = 0;
+ pickup = 0;
+ nleft = 0;
+ if (top > bottom)
+ return;
+ pickup = 0;
+ *multi_bar_rest = '\0';
+ FORLIM = bottom;
+ for (voice = top; voice <= FORLIM; voice++) {
+ mus = musicLineNo(voice);
+ if (mus > 0) { /** -------------- Voice is present ---- */
+ nv++;
+ line_no = orig_line_no[mus-1];
+ scanMusic(voice, &l);
+ if (*multi_bar_rest != '\0' && nv > 1)
+ error("Multi-bar rest allows only one voice", print);
+ if (!pmx_preamble_done) {
+ if (voice == top)
+ pickup = l;
+ else if (pickup != l)
+ error3(voice, "The same pickup must appear in all voices");
+ }
+ nbar = numberOfBars(voice);
+ extra = ExtraLength(voice);
+ if (*multi_bar_rest != '\0' && (nbar > 0 || extra > 0))
+ error3(voice, "Multi-bar rest allows no other rests or notes");
+ if (nbar > nbars || nbar == nbars && extra > nleft) {
+ nbars = nbar;
+ nleft = extra;
+ leader = voice;
+ }
+ if (!final_paragraph && meternum > 0 && extra > 0) {
+ printf("Line has %s\n", describe(STR2, nbar, extra));
+ error(" Line does not end at complete bar", print);
+ }
+ if (pmx_preamble_done && l > 0 && meternum > 0) {
+ printf("l=%d meternum=%d\n", l, meternum);
+ error3(voice, "Short bar with no meter change");
+ }
+ }
+ }
+ if (!pmx_preamble_done) {
+ xmtrnum0 = (double)pickup / one_beat; /* Don't want an integer result */
+ if (beVerbose())
+ printf("Pickup = %d/64\n", pickup);
+ }
+ if (leader <= 0)
+ return;
+ FORLIM = bottom;
+ for (voice = top; voice <= FORLIM; voice++) {
+ if (musicLineNo(voice) > 0) {
+ if (voice != leader) {
+ mus = musicLineNo(voice);
+ line_no = orig_line_no[mus-1];
+ if (numberOfBars(voice) != numberOfBars(leader) ||
+ ExtraLength(voice) != ExtraLength(leader)) {
+ printf("Following line has %s\n",
+ describe(STR4, numberOfBars(voice), ExtraLength(voice)));
+ puts(musicLine(STR4, voice));
+ printf("Longest line has %s\n",
+ describe(STR2, numberOfBars(leader), ExtraLength(leader)));
+ puts(musicLine(STR2, leader));
+ error("Line duration anomaly", print);
+ }
+ }
+ }
+ }
+}
+
+
+void describeParagraph(void)
+{
+ voice_index0 voice;
+ Char STR2[256];
+ voice_index0 FORLIM;
+
+ printf("---- Paragraph %d starting at line %d bar %d\n",
+ paragraph_no, orig_line_no[0], bar_no);
+ FORLIM = bottom;
+ for (voice = top; voice <= FORLIM; voice++)
+ describeVoice(voice, lyricsReport(STR2, voice));
+}
+
+
+/* Local variables for paragraphSetup: */
+struct LOC_paragraphSetup {
+ voice_index0 *voice;
+ short l;
+ voice_index0 k;
+ Char P_keep[256], w[256];
+ boolean is_labelled;
+} ;
+
+Local void maybeUptext(short i, struct LOC_paragraphSetup *LINK)
+{
+ if (!doUptext())
+ return;
+ if (strlen(LINK->w) == 1) {
+ if (*LINK->voice == nvoices)
+ warning("Uptext line below bottom voice should be labelled", print);
+ }
+ if (strlen(LINK->w) == 1) { /** Standard chord line ------ */
+ LINK->k = *LINK->voice + 1;
+ if (LINK->k > nvoices)
+ LINK->k--;
+ setUptextLineNo(LINK->k, i);
+ /** Labelled chord line ---- */
+ return;
+ }
+ predelete(LINK->w, 1);
+ LINK->k = findVoice(LINK->w);
+ if (LINK->k == 0)
+ error("Uptext line belongs to unknown voice", print);
+ else
+ setUptextLineNo(LINK->k, i);
+}
+
+Local void maybeChords(short i, struct LOC_paragraphSetup *LINK)
+{
+ if (!doChords())
+ return;
+ if (strlen(LINK->w) == 1 && *LINK->voice == 0 && pedanticWarnings())
+ warning("Chord line above top voice should be labelled", print);
+ if (strlen(LINK->w) == 1) { /** Standard chord line ------ */
+ LINK->k = *LINK->voice;
+ if (LINK->k == 0)
+ LINK->k = 1;
+ setChordLineNo(LINK->k, i);
+ /** Labelled chord line ---- */
+ return;
+ }
+ predelete(LINK->w, 1);
+ LINK->k = findVoice(LINK->w);
+ if (LINK->k == 0)
+ error("Chord line belongs to unknown voice", print);
+ else
+ setChordLineNo(LINK->k, i);
+}
+
+Local void analyzeParagraph(struct LOC_paragraphSetup *LINK)
+{
+ paragraph_index i, FORLIM;
+
+ *LINK->voice = 0;
+ bottom = 0;
+ top = nvoices + 1;
+ clearLabels();
+ clearTags();
+ clearUptext();
+ FORLIM = para_len;
+ for (i = 1; i <= FORLIM; i++)
+ { /* ----- Paragraph analysis main loop ----- */
+ if (*P[i-1] != '\0' && P[i-1][0] != comment) {
+ NextWord(LINK->w, P[i-1], blank, colon);
+ line_no = orig_line_no[i-1];
+ LINK->l = strlen(LINK->w);
+ LINK->is_labelled = (LINK->w[LINK->l-1] == colon &&
+ LINK->w[LINK->l-2] != barsym);
+ if (LINK->is_labelled) {
+ strcpy(LINK->P_keep, P[i-1]);
+ predelete(P[i-1], LINK->l);
+ shorten(LINK->w, LINK->l - 1);
+ LINK->k = findVoice(LINK->w); /* First look for a voice label */
+ if (LINK->k > 0) {
+ *LINK->voice = LINK->k;
+ setMusicLineNo(*LINK->voice, i);
+ } else if (LINK->w[0] == 'L')
+ maybeLyrics(*LINK->voice, i, LINK->w);
+ else if (LINK->w[0] == 'C')
+ maybeChords(i, LINK);
+ else if (LINK->w[0] == 'U')
+ maybeUptext(i, LINK);
+ else {
+ if (startsWithIgnoreCase(LINK->w, "SPACE")) {
+ setSpace(P[i-1]);
+ must_respace = true;
+ } else {
+ if (startsWithIgnoreCase(LINK->w, "VOICES")) {
+ selectVoices(P[i-1]);
+ must_restyle = true;
+ } else {
+ strcpy(P[i-1], LINK->P_keep);
+ LINK->is_labelled = false;
+ if (!isNoteOrRest(LINK->w)) {
+ error("Unknown line label", print);
+ /** ------------ Maybe Space command ------------ */
+ /** ------------ Maybe Voices command ------------ */
+ /** Could be sticky attribute **/
+ }
+ }
+ }
+ }
+ }
+ if (!LINK->is_labelled) {
+ (*LINK->voice)++;
+ setMusicLineNo(*LINK->voice, i);
+ }
+ if (*LINK->voice > bottom)
+ bottom = *LINK->voice;
+ if (*LINK->voice > 0 && *LINK->voice < top)
+ top = *LINK->voice;
+ }
+ }
+}
+
+Local void obliterate(struct LOC_paragraphSetup *LINK)
+{
+ paragraph_index i;
+ Char new_only[256];
+ paragraph_index FORLIM;
+
+ *new_only = '\0';
+ FORLIM = para_len;
+ for (i = 0; i <= FORLIM - 1; i++) {
+ if (startsWithIgnoreCase(P[i], "only:")) {
+ strcpy(new_only, P[i]);
+ strcpy(P[i], "%");
+ }
+ }
+ if (*new_only != '\0') {
+ setOnly(new_only);
+ return;
+ }
+ FORLIM = para_len;
+ for (i = 1; i <= FORLIM; i++) {
+ if (omitLine(i))
+ strcpy(P[i-1], "%");
+ }
+}
+
+
+void paragraphSetup(voice_index0 *voice_)
+{
+ struct LOC_paragraphSetup V;
+
+ V.voice = voice_;
+ obliterate(&V);
+ analyzeParagraph(&V);
+ reviseLyrics();
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/analyze.h b/Build/source/utils/m-tx/mtx-src/analyze.h
new file mode 100644
index 00000000000..1a01de09170
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/analyze.h
@@ -0,0 +1,33 @@
+/* Header for module analyze, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef ANALYZE_H
+#define ANALYZE_H
+
+
+/* Decide which lines of paragraphs go where; test total duration of lines. */
+
+#ifndef CONTROL_H
+#include "control.h"
+#endif
+
+#ifndef GLOBALS_H
+#include "globals.h"
+#endif
+
+
+#ifdef ANALYZE_G
+# define vextern
+#else
+# define vextern extern
+#endif
+
+extern void testParagraph(void);
+extern void describeParagraph(void);
+extern void paragraphSetup(voice_index0 *voice);
+extern void includeStartString(void);
+
+
+#undef vextern
+
+#endif /*ANALYZE_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/analyze.pas b/Build/source/utils/m-tx/mtx-src/analyze.pas
new file mode 100644
index 00000000000..499c73ba317
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/analyze.pas
@@ -0,0 +1,184 @@
+unit analyze;
+
+{ Decide which lines of paragraphs go where; test total duration of lines. }
+
+interface uses control, globals;
+
+procedure testParagraph;
+procedure describeParagraph;
+procedure paragraphSetup (var voice: voice_index0);
+procedure includeStartString;
+
+implementation uses mtx, strings, lyrics, mtxline, uptext,
+ preamble, utility;
+
+procedure includeStartString;
+ var voice: voice_index;
+ mus: paragraph_index0;
+begin for voice:=1 to nvoices do
+ begin mus:=musicLineNo(voice); if mus>0 then
+ P[mus]:=startString(voice)+P[mus];
+ end;
+end;
+
+function describe(nbar,extra: integer): string;
+begin describe:=toString(nbar)+' bar'+plural(nbar)+' + '+
+ toString(extra)+'/64 notes';
+end;
+
+procedure testParagraph;
+ var voice, leader, nv: voice_index0;
+ mus: paragraph_index0;
+ extra, l, nbar: integer;
+begin
+ nbars:=0; pickup:=0; nleft:=0; if top>bottom then exit;
+ pickup:=0; nv:=0; leader:=0; multi_bar_rest := '';
+ for voice:=top to bottom do
+ begin mus:=musicLineNo(voice);
+ if mus>0 then {* -------------- Voice is present ---- }
+ begin inc(nv); line_no:=orig_line_no[mus];
+ scanMusic(voice,l);
+ if (multi_bar_rest<>'') and (nv>1) then error(
+ 'Multi-bar rest allows only one voice',print);
+ if not pmx_preamble_done then
+ if voice=top then pickup:=l
+ else if pickup<>l then
+ error3(voice,'The same pickup must appear in all voices');
+ nbar := numberOfBars(voice); extra := extraLength(voice);
+ if (multi_bar_rest<>'') and ((nbar>0) or (extra>0)) then error3(voice,
+ 'Multi-bar rest allows no other rests or notes');
+ if (nbar>nbars) or (nbar=nbars) and (extra>nleft) then
+ begin nbars:=nbar; nleft:=extra; leader:=voice; end;
+ if not final_paragraph and (meternum>0) and (extra>0) then
+ begin writeln('Line has ', describe(nbar,extra));
+ error(' Line does not end at complete bar',print);
+ end;
+ if pmx_preamble_done and (l>0) and (meternum>0) then
+begin
+ writeln('l=',l,' meternum=',meternum);
+ error3(voice,'Short bar with no meter change');
+end
+ end
+ end;
+ if not pmx_preamble_done then
+ begin
+ xmtrnum0 := pickup/one_beat; { Don't want an integer result }
+ if beVerbose then writeln ('Pickup = ', pickup, '/64');
+ end;
+ if leader>0 then
+ for voice:=top to bottom do if musicLineNo(voice)>0 then
+ if voice<>leader then
+ begin mus:=musicLineNo(voice);
+ line_no:=orig_line_no[mus];
+ if (numberOfBars(voice)<>numberOfBars(leader))
+ or (extraLength(voice)<>extraLength(leader)) then
+ begin
+ writeln('Following line has ',
+ describe(numberOfBars(voice), extraLength(voice)));
+ writeln(musicLine(voice));
+ writeln('Longest line has ',
+ describe(numberOfBars(leader), extraLength(leader)));
+ writeln(musicLine(leader));
+ error('Line duration anomaly',print);
+ end;
+ end;
+end;
+
+procedure describeParagraph;
+ var voice: voice_index0;
+ begin writeln('---- Paragraph ',paragraph_no,
+ ' starting at line ', orig_line_no[1], ' bar ', bar_no);
+ for voice:=top to bottom do describeVoice(voice,lyricsReport(voice));
+ end;
+
+procedure paragraphSetup (var voice: voice_index0);
+ var l: integer;
+ k: voice_index0;
+ P_keep, w: string;
+ is_labelled: boolean;
+
+ procedure maybeUptext(i: integer);
+ begin if not doUptext then exit;
+ if (length(w)=1) then if (voice=nvoices) then
+ warning('Uptext line below bottom voice should be labelled',print);
+ if length(w)=1 then {* Standard chord line ------ }
+ begin k:=voice+1; if k>nvoices then dec(k);
+ setUptextLineNo(k,i);
+ end
+ else {* Labelled chord line ---- }
+ begin predelete(w,1); k:=findVoice(w);
+ if k=0 then error('Uptext line belongs to unknown voice',print)
+ else setUptextLineNo(k,i);
+ end
+ end;
+
+ procedure maybeChords(i: integer);
+ begin if not doChords then exit;
+ if (length(w)=1) and (voice=0) and pedanticWarnings then
+ warning('Chord line above top voice should be labelled',print);
+ if length(w)=1 then {* Standard chord line ------ }
+ begin k:=voice; if k=0 then k:=1;
+ setChordLineNo(k,i);
+ end
+ else {* Labelled chord line ---- }
+ begin predelete(w,1); k:=findVoice(w);
+ if k=0 then error('Chord line belongs to unknown voice',print)
+ else setChordLineNo(k,i);
+ end
+ end;
+
+ procedure analyzeParagraph;
+ var i: paragraph_index;
+ begin voice:=0; bottom:=0; top:=nvoices+1;
+ clearLabels; clearTags; clearUptext;
+ for i:=1 to para_len do { ----- Paragraph analysis main loop ----- }
+ if (P[i]<>'') and (P[i,1]<>comment) then
+ begin
+ w:=NextWord(P[i],blank,colon); line_no := orig_line_no[i];
+ l:=length(w);
+ is_labelled := (w[l]=colon) and (w[l-1]<>barsym);
+ if is_labelled then
+ begin P_keep := P[i]; predelete(P[i],l); shorten(w,l-1);
+ k:=findVoice(w); { First look for a voice label }
+ if k>0 then
+ begin voice:=k; setMusicLineNo(voice,i);
+ end
+ else if w[1]='L' then maybeLyrics(voice,i,w)
+ else if w[1]='C' then maybeChords(i)
+ else if w[1]='U' then maybeUptext(i)
+ else begin {* ------------ Maybe Space command ------------ }
+ if startsWithIgnoreCase(w,'SPACE') then
+ begin setSpace(P[i]); must_respace:=true;
+ end
+ else {* ------------ Maybe Voices command ------------ }
+ if startsWithIgnoreCase(w,'VOICES') then
+ begin selectVoices(P[i]); must_restyle:=true;
+ end
+ else begin {* Could be sticky attribute *}
+ P[i] := P_keep; is_labelled := false;
+ if not isNoteOrRest(w) then error('Unknown line label',print);
+ end
+ end
+ end;
+ if not is_labelled then
+ begin inc(voice); setMusicLineNo(voice,i);
+ end;
+ if voice>bottom then bottom:=voice;
+ if (voice>0) and (voice<top) then top:=voice;
+ end;
+ end;
+
+ procedure obliterate;
+ var i: paragraph_index;
+ new_only: string;
+ begin new_only:='';
+ for i:=1 to para_len do if startsWithIgnoreCase(P[i],'only:')
+ then begin new_only:=P[i]; P[i]:='%'; end;
+ if new_only<>'' then setOnly(new_only)
+ else for i:=1 to para_len do if omitLine(i) then P[i]:='%';
+ end;
+
+begin obliterate; analyzeParagraph; reviseLyrics;
+end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/cfuncs.c b/Build/source/utils/m-tx/mtx-src/cfuncs.c
new file mode 100644
index 00000000000..4885ee72a00
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/cfuncs.c
@@ -0,0 +1,107 @@
+# define CFUNCS_C
+#include "cfuncs.h"
+
+int P_argc;
+char **P_argv;
+int P_ioresult;
+int _EscIO2 (int errorcode, char* filename)
+{ fprintf(stderr,"Input file %s not found\n",filename);
+ exit(errorcode); return errorcode; }
+int _EscIO (int errorcode){ return _EscIO2(errorcode,""); }
+int _Escape (int exitcode)
+{ exit(exitcode); return exitcode; }
+int _SETIO (int OK, int errorcode){ return P_ioresult = OK ? 0 : errorcode; }
+int P_eof (FILE * infile)
+{ int x;
+ if (feof(infile)) return 1;
+ x = fgetc(infile);
+ if (x==EOF) return 1;
+ ungetc(x,infile); return 0;
+ }
+void *__MallocTemp__;
+int _OutMem(void) { fprintf(stderr,"Out of memory\n"); exit(-2); return -2; }
+void PASCAL_MAIN (int npars, char ** pars)
+{ P_argc = npars; P_argv = pars; }
+
+void scan1(char *s, short p, short *n)
+{ sscanf(s+p-1,"%hd",n);
+}
+
+short pos1(char c, char *s)
+{ char *t = strchr(s,c);
+ if (t) return (short) (t-s+1); else return 0;
+}
+
+void delete1(char *s, short p)
+{ char *t = (s+=p); s=t-1;
+ while (*s) *s++ = *t++;
+}
+
+void predelete(char *s, short l)
+{ char *t = s+l;
+ while (*t) *s++ = *t++;
+ *s = *t;
+}
+
+void shorten(char *s, short new_length)
+{ s[new_length] = '\0';
+}
+
+short posNot(char c, char *s)
+{ char *t = s;
+ while (*t == c) t++;
+ if (*t) return t-s+1;
+ else return 0;
+}
+
+void getNum(char *line, short *k)
+{ int j=sscanf(line,"%hd",k);
+ if (j<1) *k=0;
+}
+
+
+void getTwoNums(char *line, short *k1, short *k2)
+{ int param = sscanf(line,"%hd/%hd",k1,k2);
+ if (param<2) *k2 = 0;
+}
+
+void toUpper(char *s)
+{ while (*s) { *s = toupper(*s); s++; }
+}
+
+boolean startsWith(char *s1, char *s2)
+{ while (*s2) { if (*s1++ != *s2++) return false; }
+ return true;
+}
+
+void insertChar(char c, char *s, short p)
+{ char x;
+ s += p-1;
+ do { x=c; c=*s; *s++=x; } while (x);
+}
+
+char *substr_(char *Result, char *s, short start, short count)
+{ char *R = Result;
+ s += start-1;
+ while (count--) *R++ = *s++;
+ *R = '\0';
+ return Result;
+}
+
+short strpos2 (char *s1, char *s2, short p)
+{ char *r = strstr (s1+p, s2);
+ if (r == NULL) return 0;
+ else return r-s1;
+}
+
+short nextWordBound(char *s, char trigger, short p)
+{
+ do {
+ p++;
+ } while (p <= strlen(s) && s[p-1] != trigger);
+ while (p < strlen(s) && s[p] != ' ')
+ p++;
+ return p;
+}
+
+# undef CFUNCS_C
diff --git a/Build/source/utils/m-tx/mtx-src/cfuncs.h b/Build/source/utils/m-tx/mtx-src/cfuncs.h
new file mode 100644
index 00000000000..f8f3e0c2d0d
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/cfuncs.h
@@ -0,0 +1,73 @@
+/* cfuncs.h DPL 1997-03-31, 2001-12-22 */
+
+#ifndef CFUNCS_H
+# define CFUNCS_H
+
+#define STRINGS_H
+typedef char Char;
+typedef void Void;
+#define Static static
+#define Local static
+#define SHORT_MAX 65535
+
+# define FileNotFound 10
+# define FileWriteError 38
+#ifndef STDIO_H
+# include <stdio.h>
+#endif
+#ifndef CTYPE_H
+# include <ctype.h>
+#endif
+#ifndef STRING_H
+# include <string.h>
+#endif
+#ifndef STDLIB_H
+# include <stdlib.h>
+#endif
+#ifndef _FNSIZE
+# define _FNSIZE 120
+#endif
+
+typedef unsigned boolean;
+#define false 0
+#define true 1
+
+extern int _EscIO (int);
+extern int _EscIO2 (int errorcode, char* filename);
+extern int _Escape (int);
+extern int P_eof (FILE *);
+extern int _SETIO (int, int);
+
+extern void PASCAL_MAIN (int, char **);
+extern int P_argc;
+extern int P_ioresult;
+extern char **P_argv;
+
+#ifdef CFUNCS_C
+# define vextern
+#else
+# define vextern extern
+#endif
+/* String handling primitives. */
+
+extern void scan1(char *s, short p, short *n);
+/* Read an integer at position p of s */
+extern boolean startsWith(char *s1, char *s2);
+/* True if s1 starts with s2 */
+extern short pos1(char c, char *s);
+extern short posNot(char c, char *s);
+extern void insertChar(char c, char *s, short p);
+extern char *substr_(char *Result, char *s, short start, short count);
+extern void getNum(char *line, short *k);
+extern void getTwoNums(char *line, short *k1, short *k2);
+extern void toUpper(char *s);
+extern void delete1(char *s, short p);
+extern void predelete(char *s, short l);
+extern void shorten(char *s, short new_length);
+extern short strpos2 (char *s1, char *s2, short p);
+extern short nextWordBound(char *s, char trigger, short p);
+
+#undef vextern
+
+#endif /*CFUNCS_H*/
+
diff --git a/Build/source/utils/m-tx/mtx-src/configure.ac b/Build/source/utils/m-tx/mtx-src/configure.ac
new file mode 100644
index 00000000000..99c60fa12ef
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/configure.ac
@@ -0,0 +1,40 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl Copyright (C) 2012 Peter Breitenlohner <tex-live@tug.org>
+dnl
+dnl This file is free software; the copyright holder
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+m4_include([version.ac])[] dnl define mtx_version
+AC_INIT([mtx], mtx_version, [rdt@cs.queensu.ca])
+AC_PREREQ([2.69])
+AC_CONFIG_SRCDIR([analyze.c])
+AC_CONFIG_AUX_DIR([.])
+
+AM_INIT_AUTOMAKE
+
+dnl Check compiler and flags
+AC_PROG_CC
+
+AM_CONDITIONAL([WIN32], [test "x$kpse_cv_have_win32" != xno])
+
+dnl Checks for programs.
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_CHECK_HEADERS([memory.h stddef.h stdlib.h string.h strings.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_SIZE_T
+
+# Checks for library functions.
+AC_CHECK_FUNCS([memchr memmove memset strchr strrchr strtol])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/Build/source/utils/m-tx/mtx-src/control.c b/Build/source/utils/m-tx/mtx-src/control.c
new file mode 100644
index 00000000000..ee6907802df
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/control.c
@@ -0,0 +1,269 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "control.pas" */
+
+
+#include "p2c.h"
+
+
+#define CONTROL_G
+#include "control.h"
+
+
+#ifndef UTILITY_H
+#include "utility.h"
+#endif
+
+
+/* enables Include: directive */
+/* one-word shortcut is treated by simply inserting a blank */
+/* detached form of shortcut allowed */
+/* C: lines are taken into account */
+/* U: lines are taken into account */
+/* L: lines are taken into account */
+/* non-melismatic eighth and shorter notes in vocal lines are unbeamed */
+/* blind slurs are hidden */
+/* U: lines synchronize with words and rests */
+/* always insert duration into notes */
+/* include macros in the count */
+/* literally expand macros */
+/* keep track of pitch and warn if unreal */
+/* transform note words to canical form */
+/* use solfa note names */
+/* issue warnings even when default action is likely to be correct */
+/* ignore all errors except fatal errors */
+/* set instrument names */
+/* report what is being done */
+/* write all possible infomative messages */
+typedef enum {
+ noSuchFeature, FmultiFile, FsplitShortcut, FnewWordShortcut, FdoChords,
+ FdoUptext, FdoLyrics, FunbeamVocal, FhideBlindSlurs, FuptextOnRests,
+ FinsertDuration, FcountMacro, FexpandMacro, FcheckPitch, FrearrangeNote,
+ FsolfaNoteNames, FpedanticWarnings, FignoreErrors, FinstrumentNames,
+ FbeVerbose, FdebugMode
+} feature;
+
+typedef struct Tfeature {
+ Char tag[31];
+ boolean active, changed;
+} Tfeature;
+
+
+#define firstFeature FmultiFile
+#define lastFeature FdebugMode
+
+
+Static Tfeature feat[21] = {
+ { "", false, false },
+ { "multiFile", true, false },
+ { "splitShortcut", true, false },
+ { "newWordShortcut", true, false },
+ { "doChords", true, false },
+ { "doUptext", true, false },
+ { "doLyrics", true, false },
+ { "unbeamVocal", true, false },
+ { "hideBlindSlurs", true, false },
+ { "uptextOnRests", true, false },
+ { "insertDuration", true, false },
+ { "countMacro", false, false },
+ { "expandMacro", false, false },
+ { "checkPitch", true, false },
+ { "rearrangeNote", true, false },
+ { "solfaNoteNames", false, false },
+ { "pedanticWarnings", false, false },
+ { "ignoreErrors", false, false },
+ { "instrumentNames", false, false },
+ { "beVerbose", false, false },
+ { "debugMode", false, false }
+};
+
+
+void printFeatures(boolean anyway)
+{
+ feature i;
+ Tfeature *WITH;
+
+ for (i = firstFeature; i <= lastFeature; i = (feature)((long)i + 1)) {
+ WITH = &feat[(long)i];
+ if (WITH->changed || anyway)
+ printf("%s = %s\n", WITH->tag, WITH->active ? " TRUE" : "FALSE");
+ }
+}
+
+
+Static feature featureNamed(Char *s)
+{
+ feature i;
+
+ for (i = firstFeature; i <= lastFeature; i = (feature)((long)i + 1)) {
+ if (equalsIgnoreCase(s, feat[(long)i].tag))
+ return i;
+ }
+ return noSuchFeature;
+}
+
+
+boolean setFeature(Char *which, boolean val)
+{
+ boolean Result = false;
+ feature f;
+ Tfeature *WITH;
+
+ f = featureNamed(which);
+ if (f != noSuchFeature) {
+ WITH = &feat[(long)f];
+ WITH->active = val;
+ WITH->changed = true;
+ Result = true;
+ }
+ if (f == FdebugMode && val)
+ feat[(long)FbeVerbose].active = true;
+ if (f == FbeVerbose && !val)
+ feat[(long)FdebugMode].active = false;
+ return Result;
+}
+
+
+void mtxLevel(Char *level)
+{
+ if (strcmp(level, "0.57") < 0) {
+ setFeature("splitShortcut", false);
+ setFeature("newWordShortcut", false);
+ }
+}
+
+
+/* Feature functions. To add a new feature "newFeature":
+ 1. Insert a new value "FnewFeature" in the declaration of type "feature".
+ 2. Insert an entry for it in array "feat".
+ 3. Copy the template below and change "FEATURE" into "newFeature".
+ 4. Copy the function header to the interface section.
+ 5. (Optional) Insert code into "mtxLevel" to enable/disable the feature.
+
+function FEATURE: boolean;
+begin FEATURE := feat[FFEATURE].active end;
+*/
+
+boolean checkPitch(void)
+{
+ return (feat[(long)FcheckPitch].active);
+}
+
+
+boolean countMacro(void)
+{
+ return (feat[(long)FcountMacro].active);
+}
+
+
+boolean expandMacro(void)
+{
+ return (feat[(long)FexpandMacro].active);
+}
+
+
+boolean insertDuration(void)
+{
+ return (feat[(long)FinsertDuration].active);
+}
+
+
+boolean rearrangeNote(void)
+{
+ return (feat[(long)FrearrangeNote].active);
+}
+
+
+boolean beVerbose(void)
+{
+ return (feat[(long)FbeVerbose].active);
+}
+
+
+boolean debugMode(void)
+{
+ return (feat[(long)FdebugMode].active);
+}
+
+
+boolean instrumentNames(void)
+{
+ return (feat[(long)FinstrumentNames].active);
+}
+
+
+boolean hideBlindSlurs(void)
+{
+ return (feat[(long)FhideBlindSlurs].active);
+}
+
+
+boolean doLyrics(void)
+{
+ return (feat[(long)FdoLyrics].active);
+}
+
+
+boolean ignoreErrors(void)
+{
+ return (feat[(long)FignoreErrors].active);
+}
+
+
+boolean pedanticWarnings(void)
+{
+ return (feat[(long)FpedanticWarnings].active);
+}
+
+
+boolean solfaNoteNames(void)
+{
+ return (feat[(long)FsolfaNoteNames].active);
+}
+
+
+boolean uptextOnRests(void)
+{
+ return (feat[(long)FuptextOnRests].active);
+}
+
+
+boolean unbeamVocal(void)
+{
+ return (feat[(long)FunbeamVocal].active);
+}
+
+
+boolean doChords(void)
+{
+ return (feat[(long)FdoChords].active);
+}
+
+
+boolean doUptext(void)
+{
+ return (feat[(long)FdoUptext].active);
+}
+
+
+boolean newWordShortcut(void)
+{
+ return (feat[(long)FnewWordShortcut].active);
+}
+
+
+boolean splitShortcut(void)
+{
+ return (feat[(long)FsplitShortcut].active);
+}
+
+
+boolean multiFile(void)
+{
+ return (feat[(long)FmultiFile].active);
+}
+
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/control.h b/Build/source/utils/m-tx/mtx-src/control.h
new file mode 100644
index 00000000000..32318eedf7d
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/control.h
@@ -0,0 +1,52 @@
+/* Header for module control, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef CONTROL_H
+#define CONTROL_H
+
+
+#ifdef CONTROL_G
+# define vextern
+#else
+# define vextern extern
+#endif
+/* DPL 2004-03-21 */
+/* Controls which M-Tx features are enabled.
+ The interface allows one to interrogate the feature state, to set
+ features according to the M-Tx level, and to override features given
+ the feature name as a character string.
+*/
+
+
+extern void mtxLevel(Char *level);
+extern boolean setFeature(Char *which, boolean val);
+/* return TRUE means OK, return FALSE means there is no such feature */
+extern void printFeatures(boolean anyway);
+/* anyway TRUE means print all feature settings, FALSE means only those
+ that were set via setFeature */
+
+extern boolean multiFile(void);
+extern boolean splitShortcut(void);
+extern boolean newWordShortcut(void);
+extern boolean doChords(void);
+extern boolean doUptext(void);
+extern boolean doLyrics(void);
+extern boolean unbeamVocal(void);
+extern boolean uptextOnRests(void);
+extern boolean solfaNoteNames(void);
+extern boolean pedanticWarnings(void);
+extern boolean ignoreErrors(void);
+extern boolean hideBlindSlurs(void);
+extern boolean instrumentNames(void);
+extern boolean beVerbose(void);
+extern boolean debugMode(void);
+extern boolean insertDuration(void);
+extern boolean rearrangeNote(void);
+extern boolean countMacro(void);
+extern boolean expandMacro(void);
+extern boolean checkPitch(void);
+
+
+#undef vextern
+
+#endif /*CONTROL_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/control.pas b/Build/source/utils/m-tx/mtx-src/control.pas
new file mode 100644
index 00000000000..fbe224658a8
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/control.pas
@@ -0,0 +1,198 @@
+unit control; { DPL 2004-03-21 }
+{ Controls which M-Tx features are enabled.
+ The interface allows one to interrogate the feature state, to set
+ features according to the M-Tx level, and to override features given
+ the feature name as a character string.
+}
+
+interface
+
+procedure mtxLevel(level: string);
+function setFeature(which: string; val: boolean): boolean;
+ { return TRUE means OK, return FALSE means there is no such feature }
+procedure printFeatures(anyway: boolean);
+ { anyway TRUE means print all feature settings, FALSE means only those
+ that were set via setFeature }
+
+function multiFile: boolean;
+function splitShortcut: boolean;
+function newWordShortcut: boolean;
+function doChords: boolean;
+function doUptext: boolean;
+function doLyrics: boolean;
+function unbeamVocal: boolean;
+function uptextOnRests: boolean;
+function solfaNoteNames: boolean;
+function pedanticWarnings: boolean;
+function ignoreErrors: boolean;
+function hideBlindSlurs: boolean;
+function instrumentNames: boolean;
+function beVerbose: boolean;
+function debugMode: boolean;
+function insertDuration: boolean;
+function rearrangeNote: boolean;
+function countMacro: boolean;
+function expandMacro: boolean;
+function checkPitch: boolean;
+
+implementation uses utility;
+
+type feature = (noSuchFeature,
+ FmultiFile, { enables Include: directive }
+ FsplitShortcut, { one-word shortcut is treated by simply inserting a blank }
+ FnewWordShortcut, { detached form of shortcut allowed }
+ FdoChords, { C: lines are taken into account }
+ FdoUptext, { U: lines are taken into account }
+ FdoLyrics, { L: lines are taken into account }
+ FunbeamVocal, { non-melismatic eighth and shorter notes in vocal lines are unbeamed }
+ FhideBlindSlurs, { blind slurs are hidden }
+ FuptextOnRests, { U: lines synchronize with words and rests }
+ FinsertDuration, { always insert duration into notes }
+ FcountMacro, { include macros in the count }
+ FexpandMacro, { literally expand macros }
+ FcheckPitch, { keep track of pitch and warn if unreal }
+ FrearrangeNote, { transform note words to canical form }
+ FsolfaNoteNames, { use solfa note names }
+ FpedanticWarnings, { issue warnings even when default action is likely to be correct }
+ FignoreErrors, { ignore all errors except fatal errors }
+ FinstrumentNames, { set instrument names }
+ FbeVerbose, { report what is being done }
+ FdebugMode { write all possible infomative messages } );
+
+ Tfeature = record
+ tag: string[30];
+ active, changed: boolean
+ end;
+
+const
+ firstFeature = FmultiFile;
+ lastFeature = FdebugMode;
+
+ feat: array[feature] of Tfeature = (
+ ( tag: ''; active: false; changed: false),
+ ( tag: 'multiFile'; active: true; changed: false),
+ ( tag: 'splitShortcut'; active: true; changed: false),
+ ( tag: 'newWordShortcut'; active: true; changed: false),
+ ( tag: 'doChords'; active: true; changed: false),
+ ( tag: 'doUptext'; active: true; changed: false),
+ ( tag: 'doLyrics'; active: true; changed: false),
+ ( tag: 'unbeamVocal'; active: true; changed: false),
+ ( tag: 'hideBlindSlurs'; active: true; changed: false),
+ ( tag: 'uptextOnRests'; active: true; changed: false),
+ ( tag: 'insertDuration'; active: true; changed: false),
+ ( tag: 'countMacro'; active: false; changed: false),
+ ( tag: 'expandMacro'; active: false; changed: false),
+ ( tag: 'checkPitch'; active: true; changed: false),
+ ( tag: 'rearrangeNote'; active: true; changed: false),
+ ( tag: 'solfaNoteNames'; active: false; changed: false),
+ ( tag: 'pedanticWarnings'; active: false; changed: false),
+ ( tag: 'ignoreErrors'; active: false; changed: false),
+ ( tag: 'instrumentNames'; active: false; changed: false),
+ ( tag: 'beVerbose'; active: false; changed: false),
+ ( tag: 'debugMode'; active: false; changed: false)
+ );
+
+procedure printFeatures(anyway: boolean);
+ var i: feature;
+begin for i:=firstFeature to lastFeature do with feat[i] do
+ if changed or anyway then writeln(tag, ' = ', active)
+end;
+
+function featureNamed(s: string): feature;
+ var i: feature;
+begin for i:=firstFeature to lastFeature do
+ if equalsIgnoreCase(s,feat[i].tag) then begin featureNamed := i; exit end;
+ featureNamed := noSuchFeature
+end;
+
+function setFeature(which: string; val: boolean): boolean;
+ var f: feature;
+begin setFeature := false; f := featureNamed(which);
+ if f <> noSuchFeature then with feat[f] do
+ begin active := val; changed := true; setFeature := true end;
+ if (f=FdebugMode) and val then feat[FbeVerbose].active := true;
+ if (f=FbeVerbose) and not val then feat[FdebugMode].active := false;
+end;
+
+procedure mtxLevel(level: string);
+begin
+ if level<'0.57' then
+ begin
+ setFeature('splitShortcut',false);
+ setFeature('newWordShortcut',false);
+ end
+end;
+
+{ Feature functions. To add a new feature "newFeature":
+ 1. Insert a new value "FnewFeature" in the declaration of type "feature".
+ 2. Insert an entry for it in array "feat".
+ 3. Copy the template below and change "FEATURE" into "newFeature".
+ 4. Copy the function header to the interface section.
+ 5. (Optional) Insert code into "mtxLevel" to enable/disable the feature.
+
+function FEATURE: boolean;
+begin FEATURE := feat[FFEATURE].active end;
+}
+
+function checkPitch: boolean;
+begin checkPitch := feat[FcheckPitch].active end;
+
+function countMacro: boolean;
+begin countMacro := feat[FcountMacro].active end;
+
+function expandMacro: boolean;
+begin expandMacro := feat[FexpandMacro].active end;
+
+function insertDuration: boolean;
+begin insertDuration := feat[FinsertDuration].active end;
+
+function rearrangeNote: boolean;
+begin rearrangeNote := feat[FrearrangeNote].active end;
+
+function beVerbose: boolean;
+begin beVerbose := feat[FbeVerbose].active end;
+
+function debugMode: boolean;
+begin debugMode := feat[FdebugMode].active end;
+
+function instrumentNames: boolean;
+begin instrumentNames := feat[FinstrumentNames].active end;
+
+function hideBlindSlurs: boolean;
+begin hideBlindSlurs := feat[FhideBlindSlurs].active end;
+
+function doLyrics: boolean;
+begin doLyrics := feat[FdoLyrics].active end;
+
+function ignoreErrors: boolean;
+begin ignoreErrors := feat[FignoreErrors].active end;
+
+function pedanticWarnings: boolean;
+begin pedanticWarnings := feat[FpedanticWarnings].active end;
+
+function solfaNoteNames: boolean;
+begin solfaNoteNames := feat[FsolfaNoteNames].active end;
+
+function uptextOnRests: boolean;
+begin uptextOnRests := feat[FuptextOnRests].active end;
+
+function unbeamVocal: boolean;
+begin unbeamVocal := feat[FunbeamVocal].active end;
+
+function doChords: boolean;
+begin doChords := feat[FdoChords].active end;
+
+function doUptext: boolean;
+begin doUptext := feat[FdoUptext].active end;
+
+function newWordShortcut: boolean;
+begin newWordShortcut := feat[FnewWordShortcut].active end;
+
+function splitShortcut: boolean;
+begin splitShortcut := feat[FsplitShortcut].active end;
+
+function multiFile: boolean;
+begin multiFile := feat[FmultiFile].active end;
+
+end.
+
diff --git a/Build/source/utils/m-tx/mtx-src/files.c b/Build/source/utils/m-tx/mtx-src/files.c
new file mode 100644
index 00000000000..f78ba27d860
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/files.c
@@ -0,0 +1,390 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "files.pas" */
+
+
+#include "p2c.h"
+
+
+#define FILES_G
+#include "files.h"
+
+
+#ifndef CONTROL_H
+#include "control.h"
+#endif
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+#ifndef UTILITY_H
+#include "utility.h"
+#endif
+
+
+#define param_leader '-'
+
+
+Static Char stylefilename[256] = "mtxstyle.txt";
+
+Static short teststyle;
+
+
+boolean endOfInfile(void)
+{
+ return (eofAll());
+}
+
+
+Static void putTeXlines(Char *s_)
+{
+ Char s[256];
+ short p;
+ Char STR1[256], STR3[256];
+
+ strcpy(s, s_);
+ p = pos1('\n', s);
+ while (p > 0) {
+ sprintf(STR3, "\\%s\\", substr_(STR1, s, 1, p - 1));
+ putLine(STR3);
+ predelete(s, p);
+ p = pos1('\n', s);
+ }
+ if (*s != '\0') {
+ sprintf(STR3, "\\%s\\", s);
+ putLine(STR3);
+ }
+}
+
+
+void TeXtype2(Char *s)
+{
+ Char STR2[256];
+
+ if (!pmx_preamble_done) {
+ putLine(s);
+ return;
+ }
+ if (s[0] == '%') {
+ putLine(s);
+ return;
+ }
+ if (first_paragraph)
+ putTeXlines(s);
+ else {
+ sprintf(STR2, "\\\\%s\\", s);
+ putLine(STR2);
+ }
+}
+
+
+void putLine(Char *line)
+{
+ if (outlen + strlen(line) >= PMXlinelength)
+ putc('\n', outfile);
+ fprintf(outfile, "%s\n", line);
+ outlen = 0;
+}
+
+
+void put(Char *line_, boolean putspace_)
+{
+ Char line[256];
+ short l;
+ Char STR1[256];
+
+ strcpy(line, line_);
+ l = strlen(line);
+ if (l > PMXlinelength)
+ error("Item longer than PMX line length", print);
+ if (outlen + l >= PMXlinelength) {
+ putLine("");
+ put(line, false);
+ return;
+ }
+ if (putspace_ && outlen > 0 && line[0] != ' ')
+ sprintf(line, " %s", strcpy(STR1, line));
+ fputs(line, outfile);
+ outlen += l;
+}
+
+
+boolean styleFileFound(void)
+{
+ return (teststyle != 0);
+}
+
+
+Static void helpmessage(void)
+{
+ printf("Usage: prepmx [-bcfnhimtuvwDH0123456789] MTXFILE [TEXDIR] [STYLEFILE]\n");
+}
+
+
+Static void bighelpmessage(void)
+{
+ helpmessage();
+ printf("\nMTXFILE: name of .mtx file without its extension\n");
+ printf("TEXDIR: directory where the TeX file made by PMX goes, default is ./\n");
+ printf("STYLEFILE: name of a file containing style definitions. Default is\n");
+ printf(" mtxstyle.txt. This feature is now deprecated; use Include: STYLEFILE\n");
+ printf(" in the preamble of the .mtx file instead.\n");
+ printf("Options: (can also be entered separately: -b -c ...)\n");
+ printf(" -b: disable unbeamVocal\n");
+ printf(" -c: disable doChords\n");
+ printf(" -f: enable solfaNoteNames\n");
+ printf(" -h: display this message and quit\n");
+ printf(" -i: enable ignoreErrors\n");
+ printf(" -m: disable doLyrics\n");
+ printf(" -n: enable instrumentNames\n");
+ printf(" -t: disable doUptext\n");
+ printf(" -u: disable uptextOnRests\n");
+ printf(" -v: enable beVerbose\n");
+ printf(" -w: enable pedanticWarnings\n");
+ printf(" -D: enable debugMode\n");
+ printf(" -0123456789: select Case\n");
+ printf(" -H: print enabled status of all options\n");
+ printf("All the above, and some other, options can be enabled or disabled\n");
+ printf(" in the preamble. What you do there overrides what you do here.\n");
+}
+
+
+void processOption(Char j)
+{
+ switch (j) {
+
+ case 'b':
+ setFeature("unbeamVocal", false);
+ break;
+
+ case 'c':
+ setFeature("doChords", false);
+ break;
+
+ case 'f':
+ setFeature("solfaNoteNames", true);
+ break;
+
+ case 'h':
+ bighelpmessage();
+ _Escape(255);
+ break;
+
+ case 'i':
+ setFeature("ignoreErrors", true);
+ break;
+
+ case 'm':
+ setFeature("doLyrics", false);
+ break;
+
+ case 'n':
+ setFeature("instrumentNames", true);
+ break;
+
+ case 't':
+ setFeature("doUptext", false);
+ break;
+
+ case 'u':
+ setFeature("uptextOnRests", false);
+ break;
+
+ case 'v':
+ setFeature("beVerbose", true);
+ break;
+
+ case 'w':
+ setFeature("pedanticWarnings", true);
+ break;
+
+ case 'D':
+ setFeature("debugMode", true);
+ break;
+
+ case 'H':
+ printFeatures(true);
+ break;
+
+ default:
+ if (isdigit(j))
+ choice = j;
+ else {
+ putchar(j);
+ error(": invalid option", !print);
+ }
+ break;
+ }
+}
+
+
+/* Local variables for OpenFiles: */
+struct LOC_OpenFiles {
+ short testin;
+ Char basename[256];
+} ;
+
+Local void checkExistingFile(struct LOC_OpenFiles *LINK)
+{
+ FILE *tryfile;
+ Char tryfile_NAME[_FNSIZE];
+
+ strcpy(tryfile_NAME, LINK->basename);
+ tryfile = fopen(tryfile_NAME, "r+b");
+ _SETIO(tryfile != NULL, FileNotFound);
+ LINK->testin = P_ioresult;
+ if (LINK->testin != 0)
+ return;
+ if (tryfile != NULL)
+ fclose(tryfile);
+ printf("There exists a file named %s. I am treating this\n",
+ LINK->basename);
+ error(" as a fatal error unless you specify -i", !print);
+}
+
+
+void OpenFiles(void)
+{
+ struct LOC_OpenFiles V;
+ short i, j, l;
+ short fileid = 0;
+ Char infilename[256], outfilename[256], param[256], ext[256];
+ short FORLIM1;
+ Char STR3[256];
+
+ line_no = 0;
+ paragraph_no = 0;
+ for (i = 1; i <= P_argc - 1; i++) {
+ strcpy(param, P_argv[i]);
+ if (param[0] == param_leader) {
+ FORLIM1 = strlen(param);
+ for (j = 1; j <= FORLIM1 - 1; j++)
+ processOption(param[j]);
+ } else if (fileid == 0)
+ fileid = i;
+ else if (*texdir == '\0')
+ strcpy(texdir, param);
+ else
+ strcpy(stylefilename, param);
+ }
+ if (fileid == 0) {
+ helpmessage();
+ printf("Try \"prepmx -h\" for more information.\n");
+ _Escape(255);
+ }
+ strcpy(V.basename, P_argv[fileid]);
+ l = strlen(V.basename);
+ if (l > 4 && V.basename[l-4] == '.') {
+ substr_(ext, V.basename, l - 2, 3);
+ toUpper(ext);
+ if (!strcmp(ext, "MTX")) {
+ warning(".mtx extension deleted from basename", !print);
+ shorten(V.basename, l - 4);
+ }
+ }
+ if (pos1('.', V.basename) > 0)
+ checkExistingFile(&V);
+ sprintf(infilename, "%s.mtx", V.basename);
+ sprintf(outfilename, "%s.pmx", V.basename);
+ pushFile(infilename);
+ strcpy(outfile_NAME, outfilename);
+ if (outfile != NULL)
+ outfile = freopen(outfile_NAME, "wb", outfile);
+ else
+ outfile = fopen(outfile_NAME, "wb");
+ _SETIO(outfile != NULL, FileNotFound);
+ strcpy(stylefile_NAME, stylefilename);
+ if (stylefile != NULL)
+ stylefile = freopen(stylefile_NAME, "r", stylefile);
+ else
+ stylefile = fopen(stylefile_NAME, "r");
+ _SETIO(stylefile != NULL, FileNotFound);
+ teststyle = P_ioresult;
+ if (teststyle != 0 && strcmp(stylefilename, "mtxstyle.txt"))
+ _SETIO(printf("Can't read %s\n", stylefilename) >= 0, FileWriteError);
+ if (fileError()) {
+ sprintf(STR3, "Input file %s not found", infilename);
+ fatalerror(STR3);
+ }
+ outfile_open = true;
+ printf("Writing to %s.pmx\n", V.basename);
+}
+
+
+void CloseFiles(void)
+{
+ if (outfile != NULL)
+ fclose(outfile);
+ outfile = NULL;
+ closeAll();
+ if (teststyle != 0)
+ return;
+ if (stylefile != NULL)
+ fclose(stylefile);
+ stylefile = NULL;
+}
+
+
+void readParagraph(Char (*P)[256], short *no, paragraph_index0 *L)
+{
+ boolean another;
+ Char filename[256], buffer[256];
+ Char STR1[256], STR3[256];
+
+ *L = 0;
+ readData(buffer);
+ line_no = currentLineNo();
+ if (isEmpty(buffer))
+ return;
+ if (debugMode())
+ printf(">>>> %s\n", buffer);
+ paragraph_no++;
+ /* Handle directives affecting the processing of the input file */
+ do {
+ another = false;
+ if (startsWithIgnoreCase(buffer, "SUSPEND")) {
+ ignore_input = true;
+ another = true;
+ if (beVerbose())
+ printf("-->> Suspending input file %s at line %d\n",
+ currentFilename(STR3), line_no);
+ }
+ if (startsWithIgnoreCase(buffer, "RESUME")) {
+ ignore_input = false;
+ another = true;
+ if (beVerbose())
+ printf("-->> Resuming input file %s at line %d\n",
+ currentFilename(STR1), line_no);
+ }
+ if (startsWithIgnoreCase(buffer, "INCLUDE:")) {
+ predelete(buffer, 8);
+ NextWord(filename, buffer, ' ', ' ');
+ pushFile(filename);
+ another = true;
+ }
+ if (another) {
+ readLine(buffer);
+ line_no = currentLineNo();
+ }
+ } while (another);
+ /* Normal paragraph input*/
+ do {
+ if (*L < lines_in_paragraph) {
+ (*L)++;
+ strcpy(P[*L - 1], buffer);
+ *buffer = '\0';
+ no[*L - 1] = line_no;
+ } else
+ warning("Paragraph too long: skipping line", !print);
+ readLine(buffer);
+ line_no = currentLineNo();
+ if (debugMode())
+ printf("%d >> %s\n", line_no, buffer);
+ } while (!isEmpty(buffer));
+ skipBlanks(); /* needed to identify final paragraph */
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/files.h b/Build/source/utils/m-tx/mtx-src/files.h
new file mode 100644
index 00000000000..3f6381db489
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/files.h
@@ -0,0 +1,38 @@
+/* Header for module files, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef FILES_H
+#define FILES_H
+
+
+/* Open and close files, interpret command line, do input, do most output*/
+
+#ifndef GLOBALS_H
+#include "globals.h"
+#endif
+
+#ifndef MULTFILE_H
+#include "multfile.h"
+#endif
+
+
+#ifdef FILES_G
+# define vextern
+#else
+# define vextern extern
+#endif
+
+extern void readParagraph(Char (*P)[256], short *no, paragraph_index0 *L);
+extern boolean styleFileFound(void);
+extern void processOption(Char j);
+extern void OpenFiles(void);
+extern void CloseFiles(void);
+extern void putLine(Char *line);
+extern void put(Char *line, boolean putspace_);
+extern void TeXtype2(Char *s);
+extern boolean endOfInfile(void);
+
+
+#undef vextern
+
+#endif /*FILES_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/files.pas b/Build/source/utils/m-tx/mtx-src/files.pas
new file mode 100644
index 00000000000..446a7041508
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/files.pas
@@ -0,0 +1,208 @@
+unit files;
+{ Open and close files, interpret command line, do input, do most output}
+
+interface uses globals, multfile;
+
+procedure readParagraph (var P: paragraph; var no: line_nos;
+ var L: paragraph_index0);
+function styleFileFound: boolean;
+procedure processOption(j: char);
+procedure OpenFiles;
+procedure CloseFiles;
+procedure putLine (line: string);
+procedure put(line: string; putspace: boolean);
+procedure TeXtype2 (s: string);
+function endOfInfile: boolean;
+
+implementation uses control, strings, utility;
+
+const param_leader = '-';
+ stylefilename: string = 'mtxstyle.txt';
+
+var teststyle: integer;
+
+function endOfInfile: boolean;
+ begin endOfInfile:=eofAll; end;
+
+procedure putTeXlines(s: string);
+ var p: integer;
+begin p:=pos1(#10,s);
+ while p>0 do
+ begin
+ putLine('\'+substr(s,1,p-1)+'\');
+ predelete(s,p);
+ p:=pos1(#10,s)
+ end;
+ if length(s)>0 then putLine('\'+s+'\');
+end;
+
+procedure TeXtype2 (s: string);
+ begin
+ if pmx_preamble_done then
+ if s[1]='%' then putLine(s)
+ else if first_paragraph then putTeXLines(s)
+ else putLine('\\'+s+'\')
+ else putLine(s);
+ end;
+
+procedure putLine (line: string);
+ begin if outlen+length(line) > pmxlinelength-1 then writeln(outfile);
+ writeln(outfile,line); outlen:=0;
+ end;
+
+procedure put(line: string; putspace: boolean);
+ var l: integer;
+ begin l:=length(line);
+ if l>pmxlinelength then error('Item longer than PMX line length',print);
+ if outlen+l > pmxlinelength-1 then
+ begin putLine(''); put(line,false) end
+ else begin if putspace and (outlen>0) and (line[1]<>' ') then
+ line:=' '+line;
+ write(outfile,line); inc(outlen,l);
+ end
+ end;
+
+function styleFileFound: boolean;
+begin styleFileFound := teststyle<>0; end;
+
+procedure helpmessage;
+begin
+ writeln('Usage: prepmx [-bcfnhimtuvwDH0123456789] MTXFILE [TEXDIR] [STYLEFILE]')
+end;
+
+procedure bighelpmessage;
+begin helpmessage; writeln;
+ writeln('MTXFILE: name of .mtx file without its extension');
+ writeln('TEXDIR: directory where the TeX file made by PMX goes, default is ./');
+ writeln('STYLEFILE: name of a file containing style definitions. Default is');
+ writeln(' mtxstyle.txt. This feature is now deprecated; use Include: STYLEFILE');
+ writeln(' in the preamble of the .mtx file instead.');
+ writeln('Options: (can also be entered separately: -b -c ...)');
+ writeln(' -b: disable unbeamVocal');
+ writeln(' -c: disable doChords');
+ writeln(' -f: enable solfaNoteNames');
+ writeln(' -h: display this message and quit');
+ writeln(' -i: enable ignoreErrors');
+ writeln(' -m: disable doLyrics');
+ writeln(' -n: enable instrumentNames');
+ writeln(' -t: disable doUptext');
+ writeln(' -u: disable uptextOnRests');
+ writeln(' -v: enable beVerbose');
+ writeln(' -w: enable pedanticWarnings');
+ writeln(' -D: enable debugMode');
+ writeln(' -0123456789: select Case');
+ writeln(' -H: print enabled status of all options');
+ writeln('All the above, and some other, options can be enabled or disabled');
+ writeln(' in the preamble. What you do there overrides what you do here.')
+end;
+
+procedure processOption(j: char);
+ begin case j of
+ 'b': setFeature('unbeamVocal',false);
+ 'c': setFeature('doChords',false);
+ 'f': setFeature('solfaNoteNames',true);
+ 'h': begin bighelpmessage; halt(255) end;
+ 'i': setFeature('ignoreErrors',true);
+ 'm': setFeature('doLyrics',false);
+ 'n': setFeature('instrumentNames',true);
+ 't': setFeature('doUptext',false);
+ 'u': setFeature('uptextOnRests',false);
+ 'v': setFeature('beVerbose',true);
+ 'w': setFeature('pedanticWarnings',true);
+ 'D': setFeature('debugMode',true);
+ '0'..'9': choice:=j;
+ 'H': printFeatures(true);
+ else write(j); error(': invalid option',not print);
+ end;
+end;
+
+procedure OpenFiles;
+var i, j, l, fileid, testin: integer;
+ infilename, outfilename, basename, param, ext: string;
+ procedure checkExistingFile;
+ var tryfile: file;
+ begin
+{$I-}
+ assign(tryfile,basename); reset(tryfile); testin := ioresult;
+{$I+}
+ if testin<>0 then exit else close(tryfile);
+ writeln('There exists a file named ',basename,'. I am treating this');
+ error(' as a fatal error unless you specify -i',not print);
+ end;
+begin
+ fileid:=0; line_no:=0; paragraph_no:=0;
+ for i:=1 to ParamCount do
+ begin param:=ParamStr(i);
+ if param[1]=param_leader then
+ for j:=2 to length(param) do processOption(param[j])
+ else if fileid=0 then fileid:=i
+ else if texdir='' then texdir:=param
+ else stylefilename:=param;
+ end;
+ if fileid=0 then
+ begin helpmessage; writeln('Try "prepmx -h" for more information.'); halt(255) end
+ else basename:=paramstr(fileid);
+ l:=length(basename);
+ if (l>4) and (basename[l-3]='.') then
+ begin ext:=substr(basename,l-2,3); toUpper(ext); if ext='MTX' then
+ begin warning('.mtx extension deleted from basename',not print);
+ shorten(basename,l-4);
+ end;
+ end;
+ if pos1('.',basename)>0 then checkExistingFile;
+ infilename := basename+'.mtx'; outfilename := basename+'.pmx';
+{$I-}
+ pushFile(infilename);
+ assign(outfile,outfilename); rewrite(outfile);
+ assign(stylefile,stylefilename); reset(stylefile); teststyle := ioresult;
+ if (teststyle<>0) and (stylefilename<>'mtxstyle.txt') then
+ writeln('Can''t read ',stylefilename);
+{$I+}
+ if fileError then fatalError('Input file '+infilename+' not found');
+ outfile_open := true; writeln('Writing to ',basename,'.pmx');
+end;
+
+procedure CloseFiles;
+begin close(outfile); closeAll; if teststyle=0 then close(stylefile);
+end;
+
+procedure readParagraph (var P: paragraph; var no: line_nos;
+ var L: paragraph_index0);
+ var another: boolean;
+ filename, buffer: string;
+begin
+ L:=0; buffer:=readData; line_no:=currentLineNo;
+ if isEmpty(buffer) then exit;
+ if debugMode then writeln('>>>> ',buffer);
+ inc(paragraph_no);
+{ Handle directives affecting the processing of the input file }
+ repeat another:=false;
+ if startsWithIgnoreCase(buffer,'SUSPEND') then
+ begin ignore_input:=true; another:=true; if beVerbose then
+ writeln('-->> Suspending input file ',currentFilename,
+ ' at line ', line_no);
+ end;
+ if startsWithIgnoreCase(buffer,'RESUME') then
+ begin ignore_input:=false; another:=true; if beVerbose then
+ writeln('-->> Resuming input file ',currentFilename,
+ ' at line ', line_no);
+ end;
+ if startsWithIgnoreCase(buffer,'INCLUDE:') then
+ begin predelete(buffer,8); filename:=nextWord(buffer,' ',' ');
+ pushfile(filename); another:=true;
+ end;
+ if another then begin buffer:=readLine; line_no:=currentLineNo; end;
+ until not another;
+{ Normal paragraph input}
+ repeat
+ if L<lines_in_paragraph then
+ begin inc(L); P[L]:=buffer; buffer:=''; no[L]:=line_no;
+ end
+ else warning('Paragraph too long: skipping line',not print);
+ buffer:=readLine; line_no := currentLineNo;
+ if debugMode then writeln(line_no,' >> ', buffer);
+ until isEmpty(buffer);
+ skipBlanks; { needed to identify final paragraph }
+end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/globals.c b/Build/source/utils/m-tx/mtx-src/globals.c
new file mode 100644
index 00000000000..6a359d77fee
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/globals.c
@@ -0,0 +1,336 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "globals.pas" */
+
+
+#include "p2c.h"
+
+
+#define GLOBALS_G
+#include "globals.h"
+
+
+Char double_comment[3] = "%%";
+Char durations[ndurs + 1] = "90248136";
+Char terminators[256] = ".x";
+Char has_duration[9] = "abcdefgr";
+Char solfa_names[8] = "drmfslt";
+Char choice = ' ';
+boolean outfile_open = false;
+Char texdir[256] = "";
+Char old_meter_word[256] = "";
+short outlen = 0;
+boolean ignore_input = false;
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+#ifndef CONTROL_H
+#include "control.h"
+#endif
+
+#ifndef UTILITY_H
+#include "utility.h"
+#endif
+
+
+boolean isNoteOrRest(Char *w)
+{
+ return (pos1(w[0], has_duration) > 0);
+}
+
+
+boolean isPause(Char *note)
+{
+ return (startsWith(note, pause));
+}
+
+
+void cancel(short *num, short *denom, short lowest)
+{
+ while (((*num) & 1) == 0 && *denom > lowest) {
+ *num /= 2;
+ *denom /= 2;
+ }
+}
+
+
+Char *meterWord(Char *Result, short num, short denom, short pnum,
+ short pdenom)
+{
+ Char STR1[256], STR2[256], STR4[256], STR5[256];
+
+ sprintf(Result, "m%s/%s/%s/%s",
+ toString(STR1, num), toString(STR2, denom), toString(STR4, pnum),
+ toString(STR5, pdenom));
+ return Result;
+}
+
+
+Char *meterChange(Char *Result, short n1, short n2, boolean blind)
+{
+ short f = 64;
+ short l;
+
+ if (!blind)
+ return (meterWord(Result, n1, PMXmeterdenom(n2), 0, 0));
+ /* CMO: process denominator value with function PMXmeterdenom */
+ l = n1 * (64 / n2);
+ cancel(&l, &f, meterdenom);
+ /* CMO: process denominator value with function PMXmeterdenom */
+ meterWord(Result, l, PMXmeterdenom(f), 0, 0);
+ if (meternum > 0)
+ printf("Blind meter change to %d/%d on line %d\n", l, f, line_no);
+ return Result;
+}
+
+
+void setSpace(Char *line_)
+{
+ Char line[256];
+ short i;
+ Char word[256];
+ Char STR1[256];
+
+ strcpy(line, line_);
+ i = pos1(';', line);
+ if (i > 0) {
+ getNum(substr_(STR1, line, 1, i - 1), nspace);
+ predelete(line, i);
+ }
+ i = 0;
+ while (i < ninstr) {
+ GetNextWord(word, line, blank, dummy);
+ if (*word == '\0')
+ return;
+ i++;
+ getNum(word, &nspace[i]);
+ }
+}
+
+
+Static void onumber(Char *s, short *j, short *n1)
+{
+ if (s[*j - 1] == 'o')
+ *n1 = 1;
+ else if (s[*j - 1] == '1') {
+ *n1 = digit(s[*j]) + 10;
+ (*j)++;
+ } else
+ *n1 = digit(s[*j - 1]);
+ (*j)++;
+}
+
+
+Static void extractNumber(Char *s, short *k)
+{
+ Char w[256];
+
+ GetNextWord(w, s, '/', dummy);
+ getNum(w, k);
+}
+
+
+Static void readMeter(Char *meter_, short *meternum, short *meterdenom,
+ short *pmnum, short *pmdenom)
+{
+ Char meter[256];
+ short j;
+
+ strcpy(meter, meter_);
+ if (meter[0] == 'm') {
+ if (pos1('/', meter) == 0) {
+ j = 2;
+ onumber(meter, &j, meternum);
+ onumber(meter, &j, meterdenom);
+ onumber(meter, &j, pmnum);
+ onumber(meter, &j, pmdenom);
+ return;
+ }
+ predelete(meter, 1);
+ extractNumber(meter, meternum);
+ extractNumber(meter, meterdenom);
+ extractNumber(meter, pmnum);
+ extractNumber(meter, pmdenom);
+ return;
+ }
+ getTwoNums(meter, meternum, meterdenom);
+ *pmnum = *meternum;
+ *pmdenom = *meterdenom;
+}
+
+
+void getMeter(Char *line_, short *meternum, short *meterdenom, short *pmnum,
+ short *pmdenom)
+{
+ Char line[256];
+ Char meter[256];
+ Char STR1[256];
+
+ strcpy(line, line_);
+ GetNextWord(meter, line, blank, dummy);
+ if (!strcmp(meter, "C/") || !strcmp(meter, "mC/")) {
+ *meternum = 2;
+ *meterdenom = 2;
+ *pmdenom = 5;
+ *pmnum = 0;
+ } else if (!strcmp(meter, "C") || !strcmp(meter, "mC")) {
+ *meternum = 4;
+ *meterdenom = 4;
+ *pmdenom = 6;
+ *pmnum = 0;
+ } else
+ readMeter(meter, meternum, meterdenom, pmnum, pmdenom);
+ if (*meterdenom == 0) {
+ sprintf(STR1, "%s: Meter denominator must be nonzero", meter);
+ error(STR1, print);
+ }
+ /* CMO: Convert PMX syntax meter denominator '0' to '1' to be used for
+ prepmx duration checks */
+ /* if meterdenom=0 then meterdenom:=1; */
+}
+
+
+Static short whereInParagraph(short l)
+{
+ short Result = 0;
+ short j, FORLIM;
+
+ FORLIM = para_len;
+ for (j = 1; j <= FORLIM; j++) {
+ if (orig_line_no[j-1] == l)
+ return j;
+ }
+ return Result;
+}
+
+
+void fatalerror(Char *message)
+{
+ setFeature("ignoreErrors", false);
+ error(message, !print);
+}
+
+
+void error(Char *message, boolean printLine)
+{
+ short j;
+
+ j = whereInParagraph(line_no);
+ if (j > 0 && printLine)
+ puts(orig_P[j-1]);
+ printf("%s: ERROR on line %d\n", message, line_no);
+ if (j > 0 && printLine) {
+ printf("The line has been modified internally to:\n");
+ puts(P[j-1]);
+ }
+ if (ignoreErrors())
+ return;
+ if (outfile_open) {
+ if (outfile != NULL)
+ fclose(outfile);
+ outfile = NULL;
+ outfile = fopen(outfile_NAME, "wb");
+ if (outfile == NULL)
+ _EscIO2(FileNotFound, outfile_NAME);
+ fclose(outfile);
+ outfile = NULL;
+ }
+ if (line_no == 0)
+ line_no = 10000;
+ _Escape(line_no);
+}
+
+
+void warning(Char *message, boolean printLine)
+{
+ short j;
+
+ if (line_no <= 0) {
+ printf("%s: WARNING in preamble\n", message);
+ return;
+ }
+ printf("%s: WARNING on line %d\n", message, line_no);
+ if (!printLine)
+ return;
+ j = whereInParagraph(line_no);
+ if (j > 0)
+ puts(P[j-1]);
+}
+
+
+short PMXinstr(short stave)
+{
+ return (ninstr - instr[stave-1] + 1);
+}
+
+
+void setDefaultDuration(short meterdenom)
+{
+ switch (meterdenom) {
+
+ case 1:
+ default_duration = '0';
+ break;
+
+ case 2:
+ default_duration = '2';
+ break;
+
+ case 4:
+ default_duration = '4';
+ break;
+
+ case 8:
+ default_duration = '8';
+ break;
+
+ case 16:
+ default_duration = '1';
+ break;
+
+ case 32:
+ default_duration = '3';
+ break;
+
+ case 64:
+ default_duration = '6';
+ break;
+ }
+}
+
+
+short PMXmeterdenom(short denom)
+{
+ short Result;
+
+ /* CMO: Convert M-Tx meter denominators to PMX syntax */
+ switch (denom) {
+
+ case 1:
+ Result = 0;
+ break;
+
+ case 16:
+ Result = 1;
+ break;
+
+ case 32:
+ Result = 3;
+ break;
+
+ case 64:
+ Result = 6;
+ break;
+
+ default:
+ Result = denom;
+ break;
+ }
+ return Result;
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/globals.h b/Build/source/utils/m-tx/mtx-src/globals.h
new file mode 100644
index 00000000000..f121dcc7f63
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/globals.h
@@ -0,0 +1,155 @@
+/* Header for module globals, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef GLOBALS_H
+#define GLOBALS_H
+
+
+#ifdef GLOBALS_G
+# define vextern
+#else
+# define vextern extern
+#endif
+
+
+/* 1. All global variables.
+ 2. Miscellaneous other procedures required by several Units.
+*/
+
+/* CMO: addition/change by Christian Mondrup */
+
+
+#define PMXlinelength 128
+/* !!! One or more of the following constants should be reduced if this
+ program is to be compiled by a 16-bit compiler (e.g. Turbo Pascal),
+ otherwise you get a "Data segment too large" error */
+#define lines_in_paragraph 100
+#define max_words 128
+#define max_notes 128
+/* Christian Mondrup's suggestion to reduce data segment size:
+ lines_in_paragraph = 50;
+ max_words = 64;
+ max_notes = 64;
+*/
+#define max_bars 16
+#define maxstaves 15
+#define maxvoices 15
+#define maxgroups 3
+#define standardPMXvoices 12
+
+#define max_lyrics_line_length (PMXlinelength - 4)
+
+#define inf 32000
+#define unspec 1000
+#define default_size 20
+
+#define start_beam '['
+#define stop_beam ']'
+#define rest 'r'
+
+#define pause "rp"
+
+#define dotcode 'd'
+#define grace_group 'G'
+#define multi_group 'x'
+#define barsym '|'
+#define comment '%'
+#define blank ' '
+#define dot '.'
+#define comma ','
+#define colon ':'
+#define tilde '~'
+#define dummy '\0'
+
+#define ndurs 8
+
+#define unspecified '5' /* Not a valid duration */
+
+#define whole 2 /* position of '0' in durations */
+
+#define digits "123456789"
+#define digitsdot "0123456789."
+
+#define putspace true
+#define nospace false
+#define print true
+
+
+typedef char paragraph_index;
+
+typedef char voice_index;
+
+typedef char stave_index;
+
+typedef char bar_index0;
+
+typedef uchar word_index0;
+
+typedef char paragraph_index0;
+
+typedef char voice_index0;
+
+typedef char stave_index0;
+
+typedef Char paragraph[lines_in_paragraph][256];
+typedef short line_nos[lines_in_paragraph];
+
+
+extern Char double_comment[3];
+extern Char durations[ndurs + 1];
+extern Char terminators[256];
+extern Char has_duration[9];
+extern Char solfa_names[8];
+
+extern Char choice;
+extern boolean outfile_open;
+extern Char texdir[256];
+extern Char old_meter_word[256];
+extern short outlen;
+extern boolean ignore_input;
+vextern Char voice_label[maxvoices][256];
+vextern Char clef[maxstaves];
+vextern voice_index0 instr[maxstaves], stave[maxstaves],
+ first_on_stave[maxstaves], number_on_stave[maxstaves];
+vextern short stave_size[maxstaves];
+vextern short nspace[maxstaves + 1];
+vextern voice_index0 nvoices, nstaves, ninstr, bottom, top;
+vextern short one_beat, full_bar, line_no, short_note, musicsize, meternum,
+ meterdenom, pmnum, pmdenom, paragraph_no, bar_no, pickup, nbars,
+ nleft;
+vextern paragraph_index0 para_len;
+vextern double xmtrnum0;
+vextern paragraph P, orig_P;
+vextern line_nos orig_line_no;
+vextern FILE *infile, *outfile, *stylefile;
+vextern Char default_duration;
+vextern Char fracindent[256], this_version[256], this_version_date[256],
+ multi_bar_rest[256];
+vextern boolean pmx_preamble_done, first_paragraph, final_paragraph,
+ must_respace, must_restyle, some_vocal;
+vextern Char infile_NAME[_FNSIZE];
+vextern Char outfile_NAME[_FNSIZE];
+vextern Char stylefile_NAME[_FNSIZE];
+
+
+extern void error(Char *message, boolean printLine);
+extern void fatalerror(Char *message);
+extern void warning(Char *message, boolean printLine);
+extern short PMXinstr(short stave);
+extern void setDefaultDuration(short meterdenom);
+extern void getMeter(Char *line, short *meternum, short *meterdenom,
+ short *pmnum, short *pmdenom);
+extern void setSpace(Char *line);
+extern Char *meterChange(Char *Result, short n1, short n2, boolean blind);
+extern Char *meterWord(Char *Result, short num, short denom, short pnum,
+ short pdenom);
+extern void cancel(short *num, short *denom, short lowest);
+extern boolean isNoteOrRest(Char *w);
+extern boolean isPause(Char *note);
+/* CMO: */
+extern short PMXmeterdenom(short denom);
+
+
+#undef vextern
+
+#endif /*GLOBALS_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/globals.pas b/Build/source/utils/m-tx/mtx-src/globals.pas
new file mode 100644
index 00000000000..cca8083a400
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/globals.pas
@@ -0,0 +1,283 @@
+unit globals;
+
+{ 1. All global variables.
+ 2. Miscellaneous other procedures required by several Units.
+}
+
+{ CMO: addition/change by Christian Mondrup }
+
+interface
+
+const PMXlinelength = 128;
+{ !!! One or more of the following constants should be reduced if this
+ program is to be compiled by a 16-bit compiler (e.g. Turbo Pascal),
+ otherwise you get a "Data segment too large" error }
+ lines_in_paragraph = 100;
+ max_words = 128;
+ max_notes = 128;
+{ Christian Mondrup's suggestion to reduce data segment size:
+ lines_in_paragraph = 50;
+ max_words = 64;
+ max_notes = 64;
+}
+ max_bars = 16;
+ maxstaves = 15;
+ maxvoices = 15;
+ maxgroups = 3;
+ standardPMXvoices = 12;
+ max_lyrics_line_length = PMXlinelength-4;
+ inf = 32000;
+ unspec = 1000;
+ default_size = 20;
+
+ start_beam = '[';
+ stop_beam = ']';
+ rest = 'r';
+ pause = 'rp';
+ dotcode = 'd';
+ grace_group = 'G';
+ multi_group = 'x';
+ barsym = '|';
+ comment = '%';
+ double_comment: string[2] = '%%';
+ blank = ' ';
+ dot = '.';
+ comma = ',';
+ colon = ':';
+ tilde = '~';
+ dummy = #0;
+
+ ndurs = 8;
+ durations: string[ndurs] = '90248136';
+ unspecified = '5'; { Not a valid duration }
+ whole = 2; { position of '0' in durations }
+ terminators: string = '.x';
+ digits = '123456789';
+ digitsdot = '0123456789.';
+ has_duration: string[8] = 'abcdefgr';
+ solfa_names: string[7] = 'drmfslt';
+
+ choice: char = ' ';
+ outfile_open: boolean = false;
+ texdir: string = '';
+ old_meter_word: string = '';
+ outlen: integer = 0;
+ putspace = true;
+ nospace = false;
+ ignore_input: boolean = false;
+ print = true;
+
+type
+ paragraph_index = 1..lines_in_paragraph;
+ voice_index = 1..maxvoices;
+ stave_index = 1..maxstaves;
+ bar_index0 = 0..max_bars;
+ word_index0 = 0..max_words;
+ paragraph_index0 = 0..lines_in_paragraph;
+ voice_index0 = 0..maxvoices;
+ stave_index0 = 0..maxstaves;
+ paragraph = array[paragraph_index] of string;
+ line_nos = array[paragraph_index] of integer;
+
+var voice_label: array[voice_index] of string;
+ clef: array[stave_index] of char;
+ instr, stave, first_on_stave, number_on_stave:
+ array[stave_index] of voice_index0;
+ stave_size: array[stave_index] of integer;
+ nspace: array[stave_index0] of integer;
+ nvoices, nstaves, ninstr, bottom, top: voice_index0;
+ one_beat, full_bar, line_no, short_note, musicsize,
+ meternum, meterdenom, pmnum, pmdenom, paragraph_no,
+ bar_no, pickup, nbars, nleft: integer;
+ para_len: paragraph_index0;
+ xmtrnum0: real;
+ P, orig_P: paragraph;
+ orig_line_no: line_nos;
+ infile, outfile, stylefile: text;
+ default_duration: char;
+ fracindent, this_version, this_version_date, multi_bar_rest: string;
+ pmx_preamble_done, first_paragraph, final_paragraph, must_respace,
+ must_restyle, some_vocal: boolean;
+
+procedure error(message: string; printLine: boolean);
+procedure fatalerror(message: string);
+procedure warning(message: string; printLine: boolean);
+function PMXinstr (stave: integer): integer;
+procedure setDefaultDuration(meterdenom: integer);
+procedure getMeter(line: string;
+ var meternum, meterdenom, pmnum, pmdenom: integer);
+procedure setSpace(line: string);
+function meterChange(n1, n2: integer; blind: boolean): string;
+function meterWord (num, denom, pnum, pdenom: integer): string;
+procedure cancel(var num,denom: integer; lowest: integer);
+function isNoteOrRest(w: string): boolean;
+function isPause(note: string): boolean;
+{ CMO: }
+function PMXmeterdenom(denom: integer): integer;
+
+implementation uses strings, control, utility;
+
+function isNoteOrRest(w: string): boolean;
+begin isNoteOrRest := pos1(w[1],has_duration)>0; end;
+
+function isPause(note: string): boolean;
+begin isPause:=startsWith(note,pause); end;
+
+procedure cancel(var num,denom: integer; lowest: integer);
+begin while (num mod 2 = 0) and (denom>lowest) do
+ begin num:=num div 2; denom:=denom div 2; end;
+end;
+
+function meterWord (num,denom,pnum,pdenom: integer): string;
+begin meterWord := 'm' + toString(num) + '/' + toString(denom) +
+ '/' + toString(pnum) + '/' + toString(pdenom);
+end;
+
+function meterChange(n1, n2: integer; blind: boolean): string;
+ var f, l: integer;
+begin
+ if blind then
+ begin f:=64; l:=n1 * (64 div n2);
+ cancel(l,f,meterdenom);
+ { CMO: process denominator value with function PMXmeterdenom }
+ meterChange := meterWord (l,PMXmeterdenom(f),0,0);
+ if meternum>0 then
+ writeln('Blind meter change to ', l, '/', f, ' on line ', line_no);
+ end
+ { CMO: process denominator value with function PMXmeterdenom }
+ else meterChange := meterWord(n1,PMXmeterdenom(n2),0,0);
+end;
+
+procedure setSpace(line: string);
+ var i: integer;
+ word: string;
+ begin
+ i := pos1(';',line);
+ if i>0 then
+ begin
+ getNum(substr(line,1,i-1),nspace[0]);
+ predelete (line,i)
+ end;
+ i:=0;
+ while i<ninstr do
+ begin word:=GetNextWord(line,blank,dummy);
+ if word='' then exit;
+ inc(i); getNum(word,nspace[i]);
+ end;
+ end;
+
+procedure onumber (s: string; var j, n1: integer);
+ begin if s[j]='o' then n1:=1 else if s[j]='1' then
+ begin n1:=10+digit(s[j+1]); inc(j); end
+ else n1:=digit(s[j]);
+ inc(j);
+ end;
+
+procedure extractNumber(var s: string; var k: integer);
+ var w: string;
+begin w:=getNextWord(s,'/',dummy); getNum(w,k);
+end;
+
+procedure readMeter (meter: string;
+ var meternum, meterdenom, pmnum, pmdenom: integer);
+ var j: integer;
+begin if meter[1]='m' then
+ if pos1('/',meter)=0 then
+ begin j:=2; onumber(meter,j,meternum); onumber(meter,j,meterdenom);
+ onumber(meter,j,pmnum); onumber(meter,j,pmdenom);
+ end
+ else begin predelete(meter,1);
+ extractNumber(meter,meternum); extractNumber(meter,meterdenom);
+ extractNumber(meter,pmnum); extractNumber(meter,pmdenom);
+ end
+ else begin getTwoNums(meter, meternum, meterdenom);
+ pmnum:=meternum; pmdenom:=meterdenom;
+ end;
+end;
+
+procedure getMeter(line: string;
+ var meternum, meterdenom, pmnum, pmdenom: integer);
+ var meter: string;
+begin meter:=GetNextWord(line,blank,dummy);
+ if (meter='C/') or (meter='mC/') then
+ begin meternum:=2; meterdenom:=2; pmdenom:=5; pmnum:=0; end
+ else if (meter='C') or (meter='mC') then
+ begin meternum:=4; meterdenom:=4; pmdenom:=6; pmnum:=0; end
+ else readMeter(meter,meternum,meterdenom,pmnum,pmdenom);
+ if meterdenom=0 then Error
+ (meter+': Meter denominator must be nonzero',print);
+ { CMO: Convert PMX syntax meter denominator '0' to '1' to be used for
+ prepmx duration checks }
+ { if meterdenom=0 then meterdenom:=1; }
+end;
+
+function whereInParagraph(l: integer): integer;
+ var j: integer;
+begin whereInParagraph:=0;
+ for j:=1 to para_len do if orig_line_no[j]=l then
+ begin whereInParagraph:=j; exit end;
+end;
+
+procedure fatalerror(message: string);
+begin setFeature('ignoreErrors',false); error(message,not print) end;
+
+procedure error(message: string; printline: boolean);
+ var j: integer;
+begin
+ j:=whereInParagraph(line_no); if (j>0) and printline then
+ writeln(orig_P[j]);
+ writeln (message, ': ERROR on line ', line_no);
+ if (j>0) and printline then
+ begin
+ writeln ('The line has been modified internally to:');
+ writeln(P[j]);
+ end;
+ if not ignoreErrors then
+ begin if outfile_open then
+ begin close(outfile); rewrite(outfile); close(outfile); end;
+ if line_no=0 then line_no:=10000;
+ halt(line_no);
+ end;
+end;
+
+procedure warning(message: string; printline: boolean);
+ var j: integer;
+begin
+ if line_no>0 then
+ begin writeln (message, ': WARNING on line ', line_no);
+ if not printline then exit;
+ j:=whereInParagraph(line_no); if j>0 then writeln(P[j])
+ end
+ else writeln (message, ': WARNING in preamble');
+end;
+
+function PMXinstr (stave: integer): integer;
+begin PMXinstr := ninstr + 1 - instr[stave]; end;
+
+procedure setDefaultDuration(meterdenom: integer);
+begin
+ case meterdenom of
+ 1: default_duration:='0';
+ 2: default_duration:='2';
+ 4: default_duration:='4';
+ 8: default_duration:='8';
+ 16: default_duration:='1';
+ 32: default_duration:='3';
+ 64: default_duration:='6';
+ end;
+end;
+
+function PMXmeterdenom(denom: integer): integer;
+begin
+ { CMO: Convert M-Tx meter denominators to PMX syntax }
+ case denom of
+ 1 : PMXmeterdenom:=0;
+ 16 : PMXmeterdenom:=1;
+ 32 : PMXmeterdenom:=3;
+ 64 : PMXmeterdenom:=6;
+ else
+ PMXmeterdenom:=denom;
+ end;
+end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/libp2c/p2c.h b/Build/source/utils/m-tx/mtx-src/libp2c/p2c.h
new file mode 100644
index 00000000000..03b95201794
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/libp2c/p2c.h
@@ -0,0 +1,533 @@
+#ifndef P2C_H
+#define P2C_H
+
+
+/* Header file for code generated by "p2c", the Pascal-to-C translator */
+
+/* "p2c" Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation.
+ * By Dave Gillespie, daveg@synaptics.com. Version 1.21alpha-07.Dec.93.
+ * This file may be copied, modified, etc. in any way. It is not restricted
+ * by the licence agreement accompanying p2c itself.
+ */
+
+
+#include <stdio.h>
+
+#define DOUBLE double
+
+
+
+/* If the following heuristic fails, compile -DBSD=0 for non-BSD systems,
+ or -DBSD=1 for BSD systems. */
+
+#ifdef M_XENIX
+# define BSD 0
+#endif
+
+#ifdef vms
+# define BSD 0
+# ifndef __STDC__
+# define __STDC__ 1
+# endif
+#endif
+
+#ifdef __TURBOC__
+# define MSDOS 1
+#endif
+
+#ifdef MSDOS
+# define BSD 0
+#endif
+
+#ifdef FILE /* a #define in BSD, a typedef in SYSV (hp-ux, at least) */
+# ifndef BSD /* (a convenient, but horrible kludge!) */
+# define BSD 1
+# endif
+#endif
+
+#ifdef BSD
+# if !BSD
+# undef BSD
+# endif
+#endif
+
+
+#if (defined(__STDC__) && !defined(M_XENIX)) || defined(__TURBOC__)
+# include <stdlib.h>
+# include <stddef.h>
+# define HAS_STDLIB
+# if defined(vms) || defined(__TURBOC__)
+# define NON_ANSI_CAT
+# endif
+#else
+# ifndef BSD
+# ifndef __TURBOC__
+# include <memory.h>
+# endif
+# endif
+# ifdef hpux
+# ifdef _INCLUDE__STDC__
+# include <stddef.h>
+# include <stdlib.h>
+# define HAS_STDLIB
+# endif
+# endif
+# include <sys/types.h>
+# if !defined(MSDOS) || defined(__TURBOC__)
+# define NON_ANSI_CAT
+# endif
+#endif
+
+#if defined(NON_ANSI_CAT) && !defined(ANSI_CAT)
+# ifdef NON_ANSI_CAT_ALTERNATE
+# define __CAT__(a,b)a/**/b
+# else
+# define __ID__(a)a
+# define __CAT__(a,b)__ID__(a)b
+# endif
+#else
+# define __CAT__(a,b)a##b
+#endif
+
+
+#ifdef BSD
+# include <strings.h>
+# define memcpy(a,b,n) (bcopy(b,a,n),a)
+# define memcmp(a,b,n) bcmp(a,b,n)
+# define strchr(s,c) index(s,c)
+# define strrchr(s,c) rindex(s,c)
+#else
+# include <string.h>
+#endif
+
+#include <ctype.h>
+#include <math.h>
+#include <setjmp.h>
+#include <assert.h>
+
+
+#ifndef NO_LACK
+#ifdef vms
+
+#define LACK_LABS
+#define LACK_MEMMOVE
+#define LACK_MEMCPY
+
+#else
+
+#define LACK_LABS /* Undefine these if your library has these */
+#define LACK_MEMMOVE
+
+#endif
+#endif
+
+
+typedef struct __p2c_jmp_buf {
+ struct __p2c_jmp_buf *next;
+ jmp_buf jbuf;
+} __p2c_jmp_buf;
+
+
+/* Warning: The following will not work if setjmp is used simultaneously.
+ This also violates the ANSI restriction about using vars after longjmp,
+ but a typical implementation of longjmp will get it right anyway. */
+
+#ifndef FAKE_TRY
+# define TRY(x) do { __p2c_jmp_buf __try_jb; \
+ __try_jb.next = __top_jb; \
+ if (!setjmp((__top_jb = &__try_jb)->jbuf)) {
+# define RECOVER(x) __top_jb = __try_jb.next; } else {
+# define RECOVER2(x,L) __top_jb = __try_jb.next; } else { \
+ if (0) { L: __top_jb = __try_jb.next; }
+# define ENDTRY(x) } } while (0)
+#else
+# define TRY(x) if (1) {
+# define RECOVER(x) } else do {
+# define RECOVER2(x,L) } else do { L: ;
+# define ENDTRY(x) } while (0)
+#endif
+
+
+
+#ifdef M_XENIX /* avoid compiler bug */
+# define SHORT_MAX (32767)
+# define SHORT_MIN (-32768)
+#endif
+
+
+/* The following definitions work only on twos-complement machines */
+#ifndef SHORT_MAX
+# define SHORT_MAX ((short)(((unsigned short) -1) >> 1))
+# define SHORT_MIN (~SHORT_MAX)
+#endif
+
+#ifndef INT_MAX
+# define INT_MAX ((int)(((unsigned int) -1) >> 1))
+# define INT_MIN (~INT_MAX)
+#endif
+
+#ifndef LONG_MAX
+# define LONG_MAX ((long)(((unsigned long) -1) >> 1))
+# define LONG_MIN (~LONG_MAX)
+#endif
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+# define SEEK_CUR 1
+# define SEEK_END 2
+#endif
+
+#ifndef EXIT_SUCCESS
+# ifdef vms
+# define EXIT_SUCCESS 1
+# define EXIT_FAILURE (02000000000L)
+# else
+# define EXIT_SUCCESS 0
+# define EXIT_FAILURE 1
+# endif
+#endif
+
+
+#define SETBITS 32
+
+
+#if defined(__STDC__) || defined(__TURBOC__)
+# if !defined(vms) && !defined(M_LINT)
+# define Signed signed
+# else
+# define Signed
+# endif
+# define Void void /* Void f() = procedure */
+# ifndef Const
+# define Const const
+# endif
+# ifndef Volatile
+# define Volatile volatile
+# endif
+# ifdef M_LINT
+# define PP(x) ()
+# define PV() ()
+typedef char *Anyptr;
+# else
+# define PP(x) x /* function prototype */
+# define PV() (void) /* null function prototype */
+typedef void *Anyptr;
+# endif
+#else
+# define Signed
+# define Void void
+# ifndef Const
+# define Const
+# endif
+# ifndef Volatile
+# define Volatile
+# endif
+# define PP(x) ()
+# define PV() ()
+typedef char *Anyptr;
+#endif
+
+#ifdef __GNUC__
+# define Inline inline
+#else
+# define Inline
+#endif
+
+#define Register register /* Register variables */
+#define Char char /* Characters (not bytes) */
+
+#ifndef Static
+# define Static static /* Private global funcs and vars */
+#endif
+
+#ifndef Local
+# define Local static /* Nested functions */
+#endif
+
+typedef Signed char schar;
+typedef unsigned char uchar;
+typedef unsigned char boolean;
+
+#ifndef NO_DECLARE_ALFA
+typedef Char alfa[10];
+#endif
+
+#ifndef true
+# define true 1
+# define false 0
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+
+typedef struct {
+ Anyptr proc, link;
+} _PROCEDURE;
+
+#ifndef _FNSIZE
+# define _FNSIZE 120
+#endif
+
+
+extern Void PASCAL_MAIN PP( (int, Char **) );
+extern Char **P_argv;
+extern int P_argc;
+extern short P_escapecode;
+extern int P_ioresult;
+extern __p2c_jmp_buf *__top_jb;
+
+
+#ifdef P2C_H_PROTO /* if you have Ansi C but non-prototyped header files */
+extern Char *strcat PP( (Char *, Const Char *) );
+extern Char *strchr PP( (Const Char *, int) );
+extern int strcmp PP( (Const Char *, Const Char *) );
+extern Char *strcpy PP( (Char *, Const Char *) );
+extern size_t strlen PP( (Const Char *) );
+extern Char *strncat PP( (Char *, Const Char *, size_t) );
+extern int strncmp PP( (Const Char *, Const Char *, size_t) );
+extern Char *strncpy PP( (Char *, Const Char *, size_t) );
+extern Char *strrchr PP( (Const Char *, int) );
+
+extern Anyptr memchr PP( (Const Anyptr, int, size_t) );
+extern Anyptr memmove PP( (Anyptr, Const Anyptr, size_t) );
+extern Anyptr memset PP( (Anyptr, int, size_t) );
+#ifndef memcpy
+extern Anyptr memcpy PP( (Anyptr, Const Anyptr, size_t) );
+extern int memcmp PP( (Const Anyptr, Const Anyptr, size_t) );
+#endif
+
+extern int atoi PP( (Const Char *) );
+extern double atof PP( (Const Char *) );
+extern long atol PP( (Const Char *) );
+extern double strtod PP( (Const Char *, Char **) );
+extern long strtol PP( (Const Char *, Char **, int) );
+#endif /*P2C_H_PROTO*/
+
+#ifndef HAS_STDLIB
+#ifndef NO_DECLARE_MALLOC
+extern Anyptr malloc PP( (size_t) );
+extern Void free PP( (Anyptr) );
+#endif
+#endif
+
+extern int _OutMem PV();
+extern int _CaseCheck PV();
+extern int _NilCheck PV();
+extern int _Escape PP( (int) );
+extern int _EscIO PP( (int) );
+extern int _EscIO2 PP( (int, Char *) );
+
+extern long ipow PP( (long, long) );
+extern long P_imax PP( (long, long) );
+extern long P_imin PP( (long, long) );
+extern double P_rmax PP( (double, double) );
+extern double P_rmin PP( (double, double) );
+extern Char *strsub PP( (Char *, Char *, int, int) );
+extern Char *strltrim PP( (Char *) );
+extern Char *strrtrim PP( (Char *) );
+extern Char *strrpt PP( (Char *, Char *, int) );
+extern Char *strpad PP( (Char *, Char *, int, int) );
+extern int strpos2 PP( (Char *, Char *, int) );
+extern long memavail PV();
+extern int P_peek PP( (FILE *) );
+extern int P_eof PP( (FILE *) );
+extern int P_eoln PP( (FILE *) );
+extern Void P_readpaoc PP( (FILE *, Char *, int) );
+extern Void P_readlnpaoc PP( (FILE *, Char *, int) );
+extern long P_maxpos PP( (FILE *) );
+extern Char *P_trimname PP( (Char *, int) );
+extern long *P_setunion PP( (long *, long *, long *) );
+extern long *P_setint PP( (long *, long *, long *) );
+extern long *P_setdiff PP( (long *, long *, long *) );
+extern long *P_setxor PP( (long *, long *, long *) );
+extern int P_inset PP( (unsigned, long *) );
+extern int P_setequal PP( (long *, long *) );
+extern int P_subset PP( (long *, long *) );
+extern long *P_addset PP( (long *, unsigned) );
+extern long *P_addsetr PP( (long *, unsigned, unsigned) );
+extern long *P_remset PP( (long *, unsigned) );
+extern long *P_setcpy PP( (long *, long *) );
+extern long *P_expset PP( (long *, long) );
+extern long P_packset PP( (long *) );
+extern int P_getcmdline PP( (int, int, Char *) );
+extern Void TimeStamp PP( (int *, int *, int *,
+ int *, int *, int *) );
+extern Void P_sun_argv PP( (char *, int, int) );
+extern FILE *_skipspaces PP( (FILE *) );
+extern FILE *_skipnlspaces PP( (FILE *) );
+
+
+/* I/O error handling */
+#define _CHKIO(cond,ior,val,def) ((cond) ? P_ioresult=0,(val) \
+ : P_ioresult=(ior),(def))
+#define _SETIO(cond,ior) (P_ioresult = (cond) ? 0 : (ior))
+
+/* Following defines are suitable for the HP Pascal operating system */
+#define FileNotFound 10
+#define FileNotOpen 13
+#define FileWriteError 38
+#define BadInputFormat 14
+#define EndOfFile 30
+
+#define FILENOTFOUND 10
+#define FILENOTOPEN 13
+#define FILEWRITEERROR 38
+#define BADINPUTFORMAT 14
+#define ENDOFFILE 30
+
+/* Creating temporary files */
+#if (defined(BSD) || defined(NO_TMPFILE)) && !defined(HAVE_TMPFILE)
+# define tmpfile() (fopen(tmpnam(NULL), "w+"))
+#endif
+
+/* File buffers */
+#define FILEBUF(f,sc,type) sc int __CAT__(f,_BFLAGS); \
+ sc type __CAT__(f,_BUFFER)
+#define FILEBUFNC(f,type) int __CAT__(f,_BFLAGS); \
+ type __CAT__(f,_BUFFER)
+
+#define RESETBUF(f,type) (__CAT__(f,_BFLAGS) = 1)
+#define SETUPBUF(f,type) (__CAT__(f,_BFLAGS) = 0)
+
+#define GETFBUF(f,type) (*((__CAT__(f,_BFLAGS) == 1 && \
+ ((__CAT__(f,_BFLAGS) = 2), \
+ fread(&__CAT__(f,_BUFFER), \
+ sizeof(type),1,(f)))),\
+ &__CAT__(f,_BUFFER)))
+#define AGETFBUF(f,type) ((__CAT__(f,_BFLAGS) == 1 && \
+ ((__CAT__(f,_BFLAGS) = 2), \
+ fread(__CAT__(f,_BUFFER), \
+ sizeof(type),1,(f)))),\
+ __CAT__(f,_BUFFER))
+
+#define PUTFBUF(f,type,v) (GETFBUF(f,type) = (v))
+#define CPUTFBUF(f,v) (PUTFBUF(f,char,v))
+#define APUTFBUF(f,type,v) (memcpy(AGETFBUF(f,type), (v), \
+ sizeof(__CAT__(f,_BUFFER))))
+
+#define GET(f,type) (__CAT__(f,_BFLAGS) == 1 ? \
+ fread(&__CAT__(f,_BUFFER),sizeof(type),1,(f)) : \
+ (__CAT__(f,_BFLAGS) = 1))
+
+#define PUT(f,type) (fwrite(&__CAT__(f,_BUFFER),sizeof(type),1,(f)), \
+ (__CAT__(f,_BFLAGS) = 0))
+#define CPUT(f) (PUT(f,char))
+
+#define BUFEOF(f) (__CAT__(f,_BFLAGS) != 2 && P_eof(f))
+#define BUFFPOS(f) (ftell(f) - (__CAT__(f,_BFLAGS) == 2))
+
+typedef struct {
+ FILE *f;
+ int f_BFLAGS; /* FILEBUFNC(f,Char); */
+ Char f_BUFFER;
+ Char name[_FNSIZE];
+} _TEXT;
+
+/* Memory allocation */
+#ifdef __GCC__
+# define Malloc(n) (malloc(n) ?: (Anyptr)(size_t)_OutMem())
+#else
+extern Anyptr __MallocTemp__;
+# define Malloc(n) ((__MallocTemp__ = malloc(n)) ? __MallocTemp__ : (Anyptr)(size_t)_OutMem())
+#endif
+#define FreeR(p) (free((Anyptr)(p))) /* used if arg is an rvalue */
+#define Free(p) (free((Anyptr)(p)), (p)=NULL)
+
+/* sign extension */
+#define SEXT(x,n) ((x) | -(((x) & (1L<<((n)-1))) << 1))
+
+/* packed arrays */ /* BEWARE: these are untested! */
+#define P_getbits_UB(a,i,n,L) ((int)((a)[(i)>>(L)-(n)] >> \
+ (((~(i))&((1<<(L)-(n))-1)) << (n)) & \
+ (1<<(1<<(n)))-1))
+
+#define P_getbits_SB(a,i,n,L) ((int)((a)[(i)>>(L)-(n)] << \
+ (16 - ((((~(i))&((1<<(L)-(n))-1))+1) <<\
+ (n)) >> (16-(1<<(n))))))
+
+#define P_putbits_UB(a,i,x,n,L) ((a)[(i)>>(L)-(n)] |= \
+ (x) << (((~(i))&((1<<(L)-(n))-1)) << (n)))
+
+#define P_putbits_SB(a,i,x,n,L) ((a)[(i)>>(L)-(n)] |= \
+ ((x) & (1<<(1<<(n)))-1) << \
+ (((~(i))&((1<<(L)-(n))-1)) << (n)))
+
+#define P_clrbits_B(a,i,n,L) ((a)[(i)>>(L)-(n)] &= \
+ ~( ((1<<(1<<(n)))-1) << \
+ (((~(i))&((1<<(L)-(n))-1)) << (n))) )
+
+/* small packed arrays */
+#define P_getbits_US(v,i,n) ((int)((v) >> ((i)<<(n)) & (1<<(1<<(n)))-1))
+#define P_getbits_SS(v,i,n) ((int)((long)(v) << (SETBITS - (((i)+1) << (n))) >> (SETBITS-(1<<(n)))))
+#define P_putbits_US(v,i,x,n) ((v) |= (x) << ((i) << (n)))
+#define P_putbits_SS(v,i,x,n) ((v) |= ((x) & (1<<(1<<(n)))-1) << ((i)<<(n)))
+#define P_clrbits_S(v,i,n) ((v) &= ~( ((1<<(1<<(n)))-1) << ((i)<<(n)) ))
+
+#define P_max(a,b) ((a) > (b) ? (a) : (b))
+#define P_min(a,b) ((a) < (b) ? (a) : (b))
+
+
+/* Fix ANSI-isms */
+
+#ifdef LACK_LABS
+# ifndef labs
+# define labs my_labs
+ extern long my_labs PP( (long) );
+# endif
+#endif
+
+#ifdef LACK_MEMMOVE
+# ifndef memmove
+# define memmove my_memmove
+ extern Anyptr my_memmove PP( (Anyptr, Const Anyptr, size_t) );
+# endif
+#endif
+
+#ifdef LACK_MEMCPY
+# ifndef memcpy
+# define memcpy my_memcpy
+ extern Anyptr my_memcpy PP( (Anyptr, Const Anyptr, size_t) );
+# endif
+# ifndef memcmp
+# define memcmp my_memcmp
+ extern int my_memcmp PP( (Const Anyptr, Const Anyptr, size_t) );
+# endif
+# ifndef memset
+# define memset my_memset
+ extern Anyptr my_memset PP( (Anyptr, int, size_t) );
+# endif
+#endif
+
+/* Fix toupper/tolower on Suns and other stupid BSD systems */
+#ifdef toupper
+# undef toupper
+# undef tolower
+# define toupper(c) my_toupper(c)
+# define tolower(c) my_tolower(c)
+#endif
+
+#ifndef _toupper
+# if 'A' == 65 && 'a' == 97
+# define _toupper(c) ((c)-'a'+'A')
+# define _tolower(c) ((c)-'A'+'a')
+# else
+# ifdef toupper
+# undef toupper /* hope these are shadowing real functions, */
+# undef tolower /* because my_toupper calls _toupper! */
+# endif
+# define _toupper(c) toupper(c)
+# define _tolower(c) tolower(c)
+# endif
+#endif
+
+
+#endif /* P2C_H */
+
+
+
+/* End. */
+
+
diff --git a/Build/source/utils/m-tx/mtx-src/libp2c/p2clib.c b/Build/source/utils/m-tx/mtx-src/libp2c/p2clib.c
new file mode 100644
index 00000000000..247ddd1e634
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/libp2c/p2clib.c
@@ -0,0 +1,1117 @@
+
+/* Run-time library for use with "p2c", the Pascal to C translator */
+
+/* "p2c" Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation.
+ * By Dave Gillespie, daveg@synaptics.com. Version --VERSION--.
+ * This file may be copied, modified, etc. in any way. It is not restricted
+ * by the licence agreement accompanying p2c itself.
+ */
+
+
+
+#include "p2c.h"
+
+
+#ifndef NO_TIME
+# include <time.h>
+#endif
+
+
+#define Isspace(c) isspace(c) /* or "((c) == ' ')" if preferred */
+
+
+
+
+int P_argc;
+char **P_argv;
+
+short P_escapecode;
+int P_ioresult;
+
+long EXCP_LINE; /* Used by Pascal workstation system */
+
+Anyptr __MallocTemp__;
+
+__p2c_jmp_buf *__top_jb;
+
+
+
+
+void PASCAL_MAIN(argc, argv)
+int argc;
+char **argv;
+{
+ P_argc = argc;
+ P_argv = argv;
+ __top_jb = NULL;
+
+#ifdef LOCAL_INIT
+ LOCAL_INIT();
+#endif
+}
+
+
+
+
+
+/* In case your system lacks these... */
+
+long my_labs(x)
+long x;
+{
+ return((x > 0) ? x : -x);
+}
+
+
+#ifdef __STDC__
+Anyptr my_memmove(Anyptr d, Const Anyptr s, size_t n)
+#else
+Anyptr my_memmove(d, s, n)
+Anyptr d, s;
+register int n;
+#endif
+{
+ register char *dd = (char *)d, *ss = (char *)s;
+ if (dd < ss || dd - ss >= n) {
+#if defined(bcopy) && defined(memcpy)
+ Anyptr my_memcpy(Anyptr d, Const Anyptr s, size_t n);
+#else
+ memcpy(dd, ss, n);
+#endif
+ } else if (n > 0) {
+ dd += n;
+ ss += n;
+ while (n-- > 0)
+ *--dd = *--ss;
+ }
+ return d;
+}
+
+#ifdef __STDC__
+Anyptr my_memcpy(Anyptr d, Const Anyptr s, size_t n)
+#else
+Anyptr my_memcpy(d, s, n)
+Anyptr d, s;
+register int n;
+#endif
+{
+ register char *ss = (char *)s, *dd = (char *)d;
+ while (n-- > 0)
+ *dd++ = *ss++;
+ return d;
+}
+
+
+#ifdef __STDC__
+int my_memcmp(Const Anyptr s1, Const Anyptr s2, size_t n)
+#else
+int my_memcmp(s1, s2, n)
+Anyptr s1, s2;
+register int n;
+#endif
+{
+ register char *a = (char *)s1, *b = (char *)s2;
+ register int i;
+ while (n-- > 0)
+ if ((i = (*a++) - (*b++)) != 0)
+ return i;
+ return 0;
+}
+
+#ifdef __STDC__
+Anyptr my_memset(Anyptr d, int c, size_t n)
+#else
+Anyptr my_memset(d, c, n)
+Anyptr d;
+register int c;
+register int n;
+#endif
+{
+ register char *dd = (char *)d;
+ while (n-- > 0)
+ *dd++ = c;
+ return d;
+}
+
+
+int my_toupper(c)
+int c;
+{
+ if (islower(c))
+ return _toupper(c);
+ else
+ return c;
+}
+
+
+int my_tolower(c)
+int c;
+{
+ if (isupper(c))
+ return _tolower(c);
+ else
+ return c;
+}
+
+
+
+
+long ipow(a, b)
+long a, b;
+{
+ long v;
+
+ if (a == 0 || a == 1)
+ return a;
+ if (a == -1)
+ return (b & 1) ? -1 : 1;
+ if (b < 0)
+ return 0;
+ if (a == 2)
+ return 1L << b;
+ v = (b & 1) ? a : 1;
+ while ((b >>= 1) > 0) {
+ a *= a;
+ if (b & 1)
+ v *= a;
+ }
+ return v;
+}
+
+
+long P_imax(a, b)
+long a, b;
+{
+ if (a > b)
+ return a;
+ else
+ return b;
+}
+
+long P_imin(a, b)
+long a, b;
+{
+ if (a < b)
+ return a;
+ else
+ return b;
+}
+
+
+double P_rmax(a, b)
+double a, b;
+{
+ if (a > b)
+ return a;
+ else
+ return b;
+}
+
+double P_rmin(a, b)
+double a, b;
+{
+ if (a < b)
+ return a;
+ else
+ return b;
+}
+
+
+
+
+/* Common string functions: */
+
+/* Store in "ret" the substring of length "len" starting from "pos" (1-based).
+ Store a shorter or null string if out-of-range. Return "ret". */
+
+char *strsub(ret, s, pos, len)
+register char *ret, *s;
+register int pos, len;
+{
+ register char *s2;
+
+ if (--pos < 0 || len <= 0) {
+ *ret = 0;
+ return ret;
+ }
+ while (pos > 0) {
+ if (!*s++) {
+ *ret = 0;
+ return ret;
+ }
+ pos--;
+ }
+ s2 = ret;
+ while (--len >= 0) {
+ if (!(*s2++ = *s++))
+ return ret;
+ }
+ *s2 = 0;
+ return ret;
+}
+
+
+/* Return the index of the first occurrence of "pat" as a substring of "s",
+ starting at index "pos" (1-based). Result is 1-based, 0 if not found. */
+
+int strpos2(s, pat, pos)
+char *s;
+register char *pat;
+register int pos;
+{
+ register char *cp, ch;
+ register int slen;
+
+ if (--pos < 0)
+ return 0;
+ slen = strlen(s) - pos;
+ cp = s + pos;
+ if (!(ch = *pat++))
+ return 0;
+ pos = strlen(pat);
+ slen -= pos;
+ while (--slen >= 0) {
+ if (*cp++ == ch && !strncmp(cp, pat, pos))
+ return cp - s;
+ }
+ return 0;
+}
+
+
+/* Case-insensitive version of strcmp. */
+
+int strcicmp(s1, s2)
+register char *s1, *s2;
+{
+ register unsigned char c1, c2;
+
+ while (*s1) {
+ if (*s1++ != *s2++) {
+ if (!s2[-1])
+ return 1;
+ c1 = toupper(s1[-1]);
+ c2 = toupper(s2[-1]);
+ if (c1 != c2)
+ return c1 - c2;
+ }
+ }
+ if (*s2)
+ return -1;
+ return 0;
+}
+
+
+
+
+/* HP and Turbo Pascal string functions: */
+
+/* Trim blanks at left end of string. */
+
+char *strltrim(s)
+register char *s;
+{
+ while (Isspace(*s++)) ;
+ return s - 1;
+}
+
+
+/* Trim blanks at right end of string. */
+
+char *strrtrim(s)
+register char *s;
+{
+ register char *s2 = s;
+
+ if (!*s)
+ return s;
+ while (*++s2) ;
+ while (s2 > s && Isspace(*--s2))
+ *s2 = 0;
+ return s;
+}
+
+
+/* Store in "ret" "num" copies of string "s". Return "ret". */
+
+char *strrpt(ret, s, num)
+char *ret;
+register char *s;
+register int num;
+{
+ register char *s2 = ret;
+ register char *s1;
+
+ while (--num >= 0) {
+ s1 = s;
+ while ((*s2++ = *s1++)) ;
+ s2--;
+ }
+ return ret;
+}
+
+
+/* Store in "ret" string "s" with enough pad chars added to reach "size". */
+
+char *strpad(ret, s, padchar, num)
+char *ret;
+register char *s;
+register int padchar, num;
+{
+ register char *d = ret;
+
+ if (s == d) {
+ while (*d++) ;
+ } else {
+ while ((*d++ = *s++)) ;
+ }
+ num -= (--d - ret);
+ while (--num >= 0)
+ *d++ = padchar;
+ *d = 0;
+ return ret;
+}
+
+
+/* Copy the substring of length "len" from index "spos" of "s" (1-based)
+ to index "dpos" of "d", lengthening "d" if necessary. Length and
+ indices must be in-range. */
+
+void strmove(len, s, spos, d, dpos)
+register char *s, *d;
+register int len, spos, dpos;
+{
+ s += spos - 1;
+ d += dpos - 1;
+ while (*d && --len >= 0)
+ *d++ = *s++;
+ if (len > 0) {
+ while (--len >= 0)
+ *d++ = *s++;
+ *d = 0;
+ }
+}
+
+
+/* Delete the substring of length "len" at index "pos" from "s".
+ Delete less if out-of-range. */
+
+void strdelete(s, pos, len)
+register char *s;
+register int pos, len;
+{
+ register int slen;
+
+ if (--pos < 0)
+ return;
+ slen = strlen(s) - pos;
+ if (slen <= 0)
+ return;
+ s += pos;
+ if (slen <= len) {
+ *s = 0;
+ return;
+ }
+ while ((*s = s[len])) s++;
+}
+
+
+/* Insert string "src" at index "pos" of "dst". */
+
+void strinsert(src, dst, pos)
+register char *src, *dst;
+register int pos;
+{
+ register int slen, dlen;
+
+ if (--pos < 0)
+ return;
+ dlen = strlen(dst);
+ dst += dlen;
+ dlen -= pos;
+ if (dlen <= 0) {
+ strcpy(dst, src);
+ return;
+ }
+ slen = strlen(src);
+ do {
+ dst[slen] = *dst;
+ --dst;
+ } while (--dlen >= 0);
+ dst++;
+ while (--slen >= 0)
+ *dst++ = *src++;
+}
+
+
+
+
+/* File functions */
+
+/* Peek at next character of input stream; return EOF at end-of-file. */
+
+int P_peek(f)
+FILE *f;
+{
+ int ch;
+
+ ch = getc(f);
+ if (ch == EOF)
+ return EOF;
+ ungetc(ch, f);
+ return (ch == '\n') ? ' ' : ch;
+}
+
+
+/* Check if at end of file, using Pascal "eof" semantics. End-of-file for
+ stdin is broken; remove the special case for it to be broken in a
+ different way. */
+
+int P_eof(f)
+FILE *f;
+{
+ register int ch;
+
+ if (feof(f))
+ return 1;
+#ifdef HAVE_ISATTY
+ if (isatty(fileno(f)))
+#else
+ if (f == stdin)
+#endif
+ return 0; /* not safe to look-ahead on the keyboard! */
+ ch = getc(f);
+ if (ch == EOF)
+ return 1;
+ ungetc(ch, f);
+ return 0;
+}
+
+
+/* Check if at end of line (or end of entire file). */
+
+int P_eoln(f)
+FILE *f;
+{
+ register int ch;
+
+ ch = getc(f);
+ if (ch == EOF)
+ return 1;
+ ungetc(ch, f);
+ return (ch == '\n');
+}
+
+
+/* Skip whitespace (including newlines) in a file. */
+
+FILE *_skipnlspaces(f)
+FILE *f;
+{
+ register int ch;
+
+ do {
+ ch = getc(f);
+ } while (ch == ' ' || ch == '\t' || ch == '\n');
+ if (ch != EOF)
+ ungetc(ch, f);
+ return f;
+}
+
+
+/* Skip whitespace (not including newlines) in a file. */
+
+FILE *_skipspaces(f)
+FILE *f;
+{
+ register int ch;
+
+ do {
+ ch = getc(f);
+ } while (ch == ' ' || ch == '\t');
+ if (ch != EOF)
+ ungetc(ch, f);
+ return f;
+}
+
+
+/* Read a packed array of characters from a file. */
+
+Void P_readpaoc(f, s, len)
+FILE *f;
+char *s;
+int len;
+{
+ int ch;
+
+ for (;;) {
+ if (len <= 0)
+ return;
+ ch = getc(f);
+ if (ch == EOF || ch == '\n')
+ break;
+ *s++ = ch;
+ --len;
+ }
+ while (--len >= 0)
+ *s++ = ' ';
+ if (ch != EOF)
+ ungetc(ch, f);
+}
+
+Void P_readlnpaoc(f, s, len)
+FILE *f;
+char *s;
+int len;
+{
+ int ch;
+
+ for (;;) {
+ ch = getc(f);
+ if (ch == EOF || ch == '\n')
+ break;
+ if (len > 0) {
+ *s++ = ch;
+ --len;
+ }
+ }
+ while (--len >= 0)
+ *s++ = ' ';
+}
+
+
+/* Compute maximum legal "seek" index in file (0-based). */
+
+long P_maxpos(f)
+FILE *f;
+{
+ long savepos = ftell(f);
+ long val;
+
+ if (fseek(f, 0L, SEEK_END))
+ return -1;
+ val = ftell(f);
+ if (fseek(f, savepos, SEEK_SET))
+ return -1;
+ return val;
+}
+
+
+/* Use packed array of char for a file name. */
+
+Char *P_trimname(fn, len)
+register Char *fn;
+register int len;
+{
+ static Char fnbuf[256];
+ register Char *cp = fnbuf;
+
+ while (--len >= 0 && *fn && !isspace(*fn))
+ *cp++ = *fn++;
+ *cp = 0;
+ return fnbuf;
+}
+
+
+
+
+/* Pascal's "memavail" doesn't make much sense in Unix with virtual memory.
+ We fix memory size as 10Meg as a reasonable compromise. */
+
+long memavail()
+{
+ return 10000000; /* worry about this later! */
+}
+
+long maxavail()
+{
+ return memavail();
+}
+
+
+
+
+/* Sets are stored as an array of longs. S[0] is the size of the set;
+ S[N] is the N'th 32-bit chunk of the set. S[0] equals the maximum
+ I such that S[I] is nonzero. S[0] is zero for an empty set. Within
+ each long, bits are packed from lsb to msb. The first bit of the
+ set is the element with ordinal value 0. (Thus, for a "set of 5..99",
+ the lowest five bits of the first long are unused and always zero.) */
+
+/* (Sets with 32 or fewer elements are normally stored as plain longs.) */
+
+long *P_setunion(d, s1, s2) /* d := s1 + s2 */
+register long *d, *s1, *s2;
+{
+ long *dbase = d++;
+ register int sz1 = *s1++, sz2 = *s2++;
+ while (sz1 > 0 && sz2 > 0) {
+ *d++ = *s1++ | *s2++;
+ sz1--, sz2--;
+ }
+ while (--sz1 >= 0)
+ *d++ = *s1++;
+ while (--sz2 >= 0)
+ *d++ = *s2++;
+ *dbase = d - dbase - 1;
+ return dbase;
+}
+
+
+long *P_setint(d, s1, s2) /* d := s1 * s2 */
+register long *d, *s1, *s2;
+{
+ long *dbase = d++;
+ register int sz1 = *s1++, sz2 = *s2++;
+ while (--sz1 >= 0 && --sz2 >= 0)
+ *d++ = *s1++ & *s2++;
+ while (--d > dbase && !*d) ;
+ *dbase = d - dbase;
+ return dbase;
+}
+
+
+long *P_setdiff(d, s1, s2) /* d := s1 - s2 */
+register long *d, *s1, *s2;
+{
+ long *dbase = d++;
+ register int sz1 = *s1++, sz2 = *s2++;
+ while (--sz1 >= 0 && --sz2 >= 0)
+ *d++ = *s1++ & ~*s2++;
+ if (sz1 >= 0) {
+ while (sz1-- >= 0)
+ *d++ = *s1++;
+ }
+ while (--d > dbase && !*d) ;
+ *dbase = d - dbase;
+ return dbase;
+}
+
+
+long *P_setxor(d, s1, s2) /* d := s1 / s2 */
+register long *d, *s1, *s2;
+{
+ long *dbase = d++;
+ register int sz1 = *s1++, sz2 = *s2++;
+ while (sz1 > 0 && sz2 > 0) {
+ *d++ = *s1++ ^ *s2++;
+ sz1--, sz2--;
+ }
+ while (--sz1 >= 0)
+ *d++ = *s1++;
+ while (--sz2 >= 0)
+ *d++ = *s2++;
+ while (--d > dbase && !*d) ;
+ *dbase = d - dbase;
+ return dbase;
+}
+
+
+int P_inset(val, s) /* val IN s */
+register unsigned val;
+register long *s;
+{
+ register int bit;
+ bit = val % SETBITS;
+ val /= SETBITS;
+ if (val < *s++ && ((1L<<bit) & s[val]))
+ return 1;
+ return 0;
+}
+
+
+long *P_addset(s, val) /* s := s + [val] */
+register long *s;
+register unsigned val;
+{
+ register long *sbase = s;
+ register int bit, size;
+ bit = val % SETBITS;
+ val /= SETBITS;
+ size = *s;
+ if (++val > size) {
+ s += size;
+ while (val > size)
+ *++s = 0, size++;
+ *sbase = size;
+ } else
+ s += val;
+ *s |= 1L<<bit;
+ return sbase;
+}
+
+
+long *P_addsetr(s, v1, v2) /* s := s + [v1..v2] */
+register long *s;
+register unsigned v1, v2;
+{
+ register long *sbase = s;
+ register int b1, b2, size;
+ if ((int)v1 > (int)v2)
+ return sbase;
+ b1 = v1 % SETBITS;
+ v1 /= SETBITS;
+ b2 = v2 % SETBITS;
+ v2 /= SETBITS;
+ size = *s;
+ v1++;
+ if (++v2 > size) {
+ while (v2 > size)
+ s[++size] = 0;
+ s[v2] = 0;
+ *s = v2;
+ }
+ s += v1;
+ if (v1 == v2) {
+ *s |= (~((-2L)<<(b2-b1))) << b1;
+ } else {
+ *s++ |= (-1L) << b1;
+ while (++v1 < v2)
+ *s++ = -1;
+ *s |= ~((-2L) << b2);
+ }
+ return sbase;
+}
+
+
+long *P_remset(s, val) /* s := s - [val] */
+register long *s;
+register unsigned val;
+{
+ register int bit;
+ bit = val % SETBITS;
+ val /= SETBITS;
+ if (++val <= *s) {
+ if (!(s[val] &= ~(1L<<bit)))
+ while (*s && !s[*s])
+ (*s)--;
+ }
+ return s;
+}
+
+
+int P_setequal(s1, s2) /* s1 = s2 */
+register long *s1, *s2;
+{
+ register int size = *s1++;
+ if (*s2++ != size)
+ return 0;
+ while (--size >= 0) {
+ if (*s1++ != *s2++)
+ return 0;
+ }
+ return 1;
+}
+
+
+int P_subset(s1, s2) /* s1 <= s2 */
+register long *s1, *s2;
+{
+ register int sz1 = *s1++, sz2 = *s2++;
+ if (sz1 > sz2)
+ return 0;
+ while (--sz1 >= 0) {
+ if (*s1++ & ~*s2++)
+ return 0;
+ }
+ return 1;
+}
+
+
+long *P_setcpy(d, s) /* d := s */
+register long *d, *s;
+{
+ register long *save_d = d;
+
+#ifdef SETCPY_MEMCPY
+ memcpy(d, s, (*s + 1) * sizeof(long));
+#else
+ register int i = *s + 1;
+ while (--i >= 0)
+ *d++ = *s++;
+#endif
+ return save_d;
+}
+
+
+/* s is a "smallset", i.e., a 32-bit or less set stored
+ directly in a long. */
+
+long *P_expset(d, s) /* d := s */
+register long *d;
+register long s;
+{
+ if (s) {
+ d[1] = s;
+ *d = 1;
+ } else
+ *d = 0;
+ return d;
+}
+
+
+long P_packset(s) /* convert s to a small-set */
+register long *s;
+{
+ if (*s++)
+ return *s;
+ else
+ return 0;
+}
+
+
+
+
+
+/* Oregon Software Pascal extensions, courtesy of William Bader */
+
+int P_getcmdline(l, h, line)
+int l, h;
+Char *line;
+{
+ int i, len;
+ char *s;
+
+ h = h - l + 1;
+ len = 0;
+ for(i = 1; i < P_argc; i++) {
+ s = P_argv[i];
+ while (*s) {
+ if (len >= h) return len;
+ line[len++] = *s++;
+ }
+ if (len >= h) return len;
+ line[len++] = ' ';
+ }
+ return len;
+}
+
+Void TimeStamp(Day, Month, Year, Hour, Min, Sec)
+int *Day, *Month, *Year, *Hour, *Min, *Sec;
+{
+#ifndef NO_TIME
+ struct tm *tm;
+ long clock;
+
+ time(&clock);
+ tm = localtime(&clock);
+ *Day = tm->tm_mday;
+ *Month = tm->tm_mon + 1; /* Jan = 0 */
+ *Year = tm->tm_year;
+ if (*Year < 1900)
+ *Year += 1900; /* year since 1900 */
+ *Hour = tm->tm_hour;
+ *Min = tm->tm_min;
+ *Sec = tm->tm_sec;
+#endif
+}
+
+Void VAXdate(s)
+char *s;
+{
+ long clock;
+ char *c;
+ int i;
+ static int where[] = {8, 9, 0, 4, 5, 6, 0, 20, 21, 22, 23};
+
+ time(&clock);
+ c = ctime(&clock);
+ for (i = 0; i < 11; i++)
+ s[i] = my_toupper(c[where[i]]);
+ s[2] = '-';
+ s[6] = '-';
+}
+
+Void VAXtime(s)
+char *s;
+{
+ long clock;
+ char *c;
+ int i;
+
+ time(&clock);
+ c = ctime(&clock);
+ for (i = 0; i < 8; i++)
+ s[i] = c[i+11];
+ s[8] = '.';
+ s[9] = '0';
+ s[10] = '0';
+}
+
+
+
+
+/* SUN Berkeley Pascal extensions */
+
+Void P_sun_argv(s, len, n)
+register char *s;
+register int len, n;
+{
+ register char *cp;
+
+ if ((unsigned)n < P_argc)
+ cp = P_argv[n];
+ else
+ cp = "";
+ while (*cp && --len >= 0)
+ *s++ = *cp++;
+ while (--len >= 0)
+ *s++ = ' ';
+}
+
+
+
+
+int _OutMem()
+{
+ return _Escape(-2);
+}
+
+int _CaseCheck()
+{
+ return _Escape(-9);
+}
+
+int _NilCheck()
+{
+ return _Escape(-3);
+}
+
+
+
+
+
+/* The following is suitable for the HP Pascal operating system.
+ It might want to be revised when emulating another system. */
+
+char *_ShowEscape(buf, code, ior, prefix)
+char *buf, *prefix;
+int code, ior;
+{
+ char *bufp;
+
+ if (prefix && *prefix) {
+ strcpy(buf, prefix);
+ strcat(buf, ": ");
+ bufp = buf + strlen(buf);
+ } else {
+ bufp = buf;
+ }
+ if (code == -10) {
+ sprintf(bufp, "Pascal system I/O error %d", ior);
+ switch (ior) {
+ case 3:
+ strcat(buf, " (illegal I/O request)");
+ break;
+ case 7:
+ strcat(buf, " (bad file name)");
+ break;
+ case FileNotFound: /*10*/
+ strcat(buf, " (file not found)");
+ break;
+ case FileNotOpen: /*13*/
+ strcat(buf, " (file not open)");
+ break;
+ case BadInputFormat: /*14*/
+ strcat(buf, " (bad input format)");
+ break;
+ case 24:
+ strcat(buf, " (not open for reading)");
+ break;
+ case 25:
+ strcat(buf, " (not open for writing)");
+ break;
+ case 26:
+ strcat(buf, " (not open for direct access)");
+ break;
+ case 28:
+ strcat(buf, " (string subscript out of range)");
+ break;
+ case EndOfFile: /*30*/
+ strcat(buf, " (end-of-file)");
+ break;
+ case FileWriteError: /*38*/
+ strcat(buf, " (file write error)");
+ break;
+ }
+ } else {
+ sprintf(bufp, "Pascal system error %d", code);
+ switch (code) {
+ case -2:
+ strcat(buf, " (out of memory)");
+ break;
+ case -3:
+ strcat(buf, " (reference to NIL pointer)");
+ break;
+ case -4:
+ strcat(buf, " (integer overflow)");
+ break;
+ case -5:
+ strcat(buf, " (divide by zero)");
+ break;
+ case -6:
+ strcat(buf, " (real math overflow)");
+ break;
+ case -8:
+ strcat(buf, " (value range error)");
+ break;
+ case -9:
+ strcat(buf, " (CASE value range error)");
+ break;
+ case -12:
+ strcat(buf, " (bus error)");
+ break;
+ case -20:
+ strcat(buf, " (stopped by user)");
+ break;
+ }
+ }
+ return buf;
+}
+
+
+int _Escape(code)
+int code;
+{
+ char buf[100];
+
+ P_escapecode = code;
+ if (__top_jb) {
+ __p2c_jmp_buf *jb = __top_jb;
+ __top_jb = jb->next;
+ longjmp(jb->jbuf, 1);
+ }
+ if (code == 0)
+ exit(EXIT_SUCCESS);
+ if (code == -1)
+ exit(EXIT_FAILURE);
+ fprintf(stderr, "%s\n", _ShowEscape(buf, P_escapecode, P_ioresult, ""));
+ exit(EXIT_FAILURE);
+}
+
+int _EscIO(code)
+int code;
+{
+ P_ioresult = code;
+ return _Escape(-10);
+}
+
+int _EscIO2(code, name)
+int code;
+char *name;
+{
+ P_ioresult = code;
+ if (!__top_jb && name && *name) {
+ char buf[100];
+ fprintf(stderr, "%s: %s\n",
+ name, _ShowEscape(buf, P_escapecode, P_ioresult, ""));
+ exit(EXIT_FAILURE);
+ }
+ return _Escape(-10);
+}
+
+
+
+/* End. */
+
+
+
diff --git a/Build/source/utils/m-tx/mtx-src/lyrics.c b/Build/source/utils/m-tx/mtx-src/lyrics.c
new file mode 100644
index 00000000000..634afc061ba
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/lyrics.c
@@ -0,0 +1,830 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "lyrics.pas" */
+
+
+#include "p2c.h"
+
+
+#define LYRICS_G
+#include "lyrics.h"
+
+
+#ifndef CONTROL_H
+#include "control.h"
+#endif
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+#ifndef MTXLINE_H
+#include "mtxline.h"
+#endif
+
+#ifndef STATUS_H
+#include "status.h"
+#endif
+
+#ifndef MULTFILE_H
+#include "multfile.h"
+#endif
+
+#ifndef FILES_H
+#include "files.h"
+#endif
+
+#ifndef UTILITY_H
+#include "utility.h"
+#endif
+
+
+/* Symbols used in strings of melismatype */
+
+#define beam_melisma '['
+#define inhibit_beam_melisma '<'
+#define slur_melisma '('
+#define inhibit_slur_melisma '{'
+
+
+typedef char other_index;
+
+typedef char other_index0;
+
+typedef Char melismatype[256];
+
+typedef enum {
+ nolyr, haslyr
+} haslyrtype;
+typedef enum {
+ normal, aux
+} auxtype;
+typedef enum {
+ asbefore, newassign
+} assigntype;
+typedef enum {
+ virgin, active
+} inittype;
+
+typedef struct lyrinfotype {
+ short lyr_adjust, slur_level, slur_change, beam_level, beam_change;
+ melismatype melisma;
+ boolean numbered;
+} lyrinfotype;
+
+typedef enum {
+ none_given, global_lyrics, local_lyrics
+} lyrlinetype;
+
+typedef struct lyrtagtype {
+ lyrlinetype lyrsource;
+ haslyrtype has_lyrics;
+ auxtype auxiliary;
+ assigntype new_assign;
+ inittype initialized;
+ short linecount;
+ Char tags[256];
+} lyrtagtype;
+
+
+#define maxLyrNums 64
+#define lyrtaglength 40
+
+
+#define lyr_adjust_undef (-12345)
+#define interstave 24
+
+
+Static short LyrNum = 0;
+
+Static boolean lyrmodealter[maxstaves], oldlyrmodealter[maxstaves];
+Static lyrtagtype tag[maxvoices], oldtag[maxvoices];
+Static lyrinfotype lyrinfo[maxvoices];
+Static Char numberedParagraph[maxLyrNums][lyrtaglength + 1];
+
+
+/* Information flow for verse numbers: at the SetLyrics stage, the first
+line of each lyrics paragraph is checked for a verse number, and if
+found, the paragraph tag is remembered. At the AssignLyrics stage,
+the first time that paragraph is encountered, the particular voice
+is marked in lyrinfo as being numbered. When that voice is later processed,
+the mark in lyrinfo is interrogated and turned off: if it was on, the
+mtxVerse pre-TeX string is put into the output. */
+
+boolean hasVerseNumber(voice_index voice)
+{
+ boolean Result;
+
+ Result = lyrinfo[voice-1].numbered;
+ lyrinfo[voice-1].numbered = false;
+ return Result;
+}
+
+
+Static boolean isNumberedLyricsParagraph(Char *tag)
+{
+ short i, FORLIM;
+
+ FORLIM = LyrNum;
+ for (i = 0; i <= FORLIM - 1; i++) {
+ if (!strcmp(tag, numberedParagraph[i]))
+ return true;
+ }
+ return false;
+}
+
+
+Static boolean anyTagNumbered(Char *tags_)
+{
+ boolean Result;
+ Char tags[256];
+ Char s[256];
+
+ strcpy(tags, tags_);
+/* p2c: lyrics.pas: Note: Eliminated unused assignment statement [338] */
+ if (curtail(tags, '}') > 0)
+ delete1(tags, 1);
+ do {
+ GetNextWord(s, tags, ',', dummy);
+ if (*s == '\0')
+ return false;
+ if (isNumberedLyricsParagraph(s))
+ return true;
+ } while (true);
+ return false;
+}
+
+
+/* Save the tag in the numberedParagraph list, stripping off braces if any */
+Static void markNumbered(Char *tag_)
+{
+ Char tag[256];
+
+ strcpy(tag, tag_);
+ if (LyrNum >= maxLyrNums) {
+ error("Too many numbered lines in the lyrics", !print);
+ return;
+ }
+ LyrNum++;
+ if (curtail(tag, '}') > 0)
+ delete1(tag, 1);
+ strcpy(numberedParagraph[LyrNum-1], tag);
+/* p2c: lyrics.pas, line 104:
+ * Note: Possible string truncation in assignment [145] */
+}
+
+
+/* --- end of procedures to keep track of verse numbering --- */
+
+void lyricsParagraph(void)
+{
+ Char first[256], w[256];
+ paragraph_index0 l, line;
+ other_index0 i;
+ other_index0 nother = 0;
+ Char other_[10][lyrtaglength + 1];
+ boolean numbered;
+ Char STR1[256], STR3[256];
+ paragraph_index0 FORLIM;
+ Char STR4[256];
+ Char STR5[256];
+
+ if (!doLyrics())
+ return;
+ if (para_len < 2)
+ fatalerror("empty lyrics paragraph");
+ NextWord(w, P[0], blank, dummy);
+ l = strlen(w);
+ line_no = orig_line_no[0];
+ if (w[l-1] != '}')
+ strcat(w, "}");
+ GetNextWord(first, w, dummy, '}');
+ while (*w != '\0') {
+ if (w[0] == '=')
+ predelete(w, 1);
+ if (w[0] != '{')
+ sprintf(w, "{%s", strcpy(STR1, w));
+ nother++;
+ GetNextWord(other_[nother-1], w, dummy, '}');
+/* p2c: lyrics.pas, line 123:
+ * Note: Possible string truncation in assignment [145] */
+ }
+ if (beVerbose()) {
+ printf("---- Paragraph %d starting at line %d has lyrics headed %s",
+ paragraph_no, line_no, first);
+ for (i = 0; i <= nother - 1; i++)
+ printf("=%s", other_[i]);
+ putchar('\n');
+ }
+ sprintf(STR5, "%c Paragraph %s line %s bar %s",
+ comment, toString(STR1, paragraph_no), toString(STR3, line_no),
+ toString(STR4, bar_no));
+ TeXtype2(STR5);
+ sprintf(STR3, "\\mtxSetLyrics%s{%%", first);
+ TeXtype2(STR3);
+ FORLIM = para_len;
+ for (line = 2; line <= FORLIM; line++) {
+ lyrTranslate(P[line-1], &numbered);
+ if (numbered) {
+ if (line > 2)
+ warning("Verse number not in first line of paragraph treated as lyrics",
+ print);
+ else {
+ markNumbered(first);
+ for (i = 0; i <= nother - 1; i++)
+ markNumbered(other_[i]);
+ }
+ }
+ line_no = orig_line_no[line-1];
+ if (strlen(P[line-1]) > max_lyrics_line_length && pmx_preamble_done)
+ error("Lyrics line too long", print);
+ if (pmx_preamble_done) {
+ if (line == 2) {
+ sprintf(STR3, "\\\\\\:%s", P[line-1]);
+ put(STR3, putspace);
+ } else {
+ sprintf(STR3, "\\\\\\ %s", P[line-1]);
+ put(STR3, putspace);
+ }
+ } else
+ put(P[line-1], putspace);
+ if (line < para_len) {
+ if (pmx_preamble_done)
+ putLine(" %\\");
+ else
+ putLine(" %");
+ } else if (pmx_preamble_done)
+ putLine("}\\");
+ else
+ putLine("}");
+ }
+ for (i = 0; i <= nother - 1; i++) {
+ sprintf(STR1, "\\mtxCopyLyrics%s%s", first, other_[i]);
+ TeXtype2(STR1);
+ }
+}
+
+
+Static Char *songraise(Char *Result, voice_index voice)
+{
+ Char s[256];
+ lyrtagtype *WITH;
+ lyrinfotype *WITH1;
+ Char STR1[256], STR3[256];
+
+ WITH = &tag[voice-1];
+ WITH1 = &lyrinfo[voice-1];
+ if (WITH->initialized == virgin && WITH1->lyr_adjust == 0)
+ return strcpy(Result, "");
+ else {
+ if (WITH->auxiliary == aux)
+ strcpy(s, "Aux");
+ else
+ *s = '\0';
+ sprintf(Result, "\\mtx%sLyricsAdjust{%s}{%s}",
+ s, toString(STR1, PMXinstr(voiceStave(voice))),
+ toString(STR3, WITH1->lyr_adjust));
+ return Result;
+ }
+}
+
+
+Char *lyricsReport(Char *Result, voice_index voice)
+{
+ Char l[256];
+ lyrtagtype *WITH;
+
+ WITH = &tag[voice-1];
+ if (WITH->has_lyrics == nolyr ||
+ WITH->lyrsource == none_given && *WITH->tags == '\0')
+ return strcpy(Result, " but has no own lyrics");
+ else {
+ strcpy(l, " with ");
+ if (WITH->auxiliary == aux)
+ strcat(l, "auxiliary ");
+ strcat(l, "lyrics ");
+ if (WITH->lyrsource == local_lyrics)
+ strcat(l, "locally defined as \"");
+ else
+ strcat(l, "labelled \"");
+ sprintf(l + strlen(l), "%s\"", WITH->tags);
+ if (anyTagNumbered(WITH->tags))
+ strcat(l, " with verse numbers");
+ return strcpy(Result, l);
+ }
+}
+
+
+void initLyrics(void)
+{
+ /* at the start only */
+ stave_index stave;
+ voice_index voice, FORLIM;
+ lyrinfotype *WITH;
+ lyrtagtype *WITH1;
+ stave_index FORLIM1;
+
+ FORLIM = nvoices;
+ for (voice = 0; voice <= FORLIM - 1; voice++) {
+ WITH = &lyrinfo[voice];
+ WITH1 = &tag[voice];
+ WITH1->has_lyrics = nolyr;
+ WITH->lyr_adjust = lyr_adjust_undef;
+ *WITH->melisma = '\0';
+ WITH->slur_level = 0;
+ WITH->beam_level = 0;
+ WITH1->auxiliary = aux;
+ WITH1->lyrsource = none_given;
+ WITH1->new_assign = asbefore;
+ WITH1->initialized = virgin;
+ }
+ FORLIM1 = nstaves;
+ for (stave = 0; stave <= FORLIM1 - 1; stave++)
+ oldlyrmodealter[stave] = false;
+}
+
+
+Static void registerLyrics(voice_index voice, Char *w)
+{
+ lyrtagtype *WITH;
+
+ WITH = &tag[voice-1];
+ strcpy(oldtag[voice-1].tags, WITH->tags);
+ oldtag[voice-1].lyrsource = WITH->lyrsource;
+ WITH->lyrsource = global_lyrics;
+ switch (strlen(w)) {
+
+ case 0:
+ *WITH->tags = '\0';
+ break;
+
+ case 1:
+ fatalerror("M-Tx system error in registerLyrics");
+ break;
+
+ default:
+ strcpy(WITH->tags, w);
+ break;
+ }
+}
+
+
+void extractLyrtag(voice_index voice, Char *note)
+{
+ /* inline lyrics change */
+ lyrtagtype *WITH;
+ Char STR1[256], STR2[256];
+
+ WITH = &tag[voice-1];
+ if (WITH->has_lyrics == nolyr) {
+ error3(voice, "Inline lyrics change on no-lyrics line");
+ return;
+ }
+ registerLyrics(voice, note); /* was: ''); */
+ sprintf(note, "\\mtxAssignLyrics{%s}%s",
+ toString(STR1, PMXinstr(voiceStave(voice))), strcpy(STR2, note));
+ if (WITH->auxiliary == aux)
+ sprintf(note, "\\mtxAuxLyr{%s}\\", strcpy(STR2, note));
+ else
+ strcat(note, "\\");
+}
+
+
+void clearTags(void)
+{
+ /* at start of paragraph analyis */
+ voice_index voice, FORLIM;
+ lyrtagtype *WITH;
+
+ memcpy(oldtag, tag, maxvoices * sizeof(lyrtagtype));
+ FORLIM = nvoices;
+ for (voice = 0; voice <= FORLIM - 1; voice++) {
+ WITH = &tag[voice];
+ WITH->lyrsource = none_given;
+ *WITH->tags = '\0';
+ WITH->linecount = 0;
+ }
+}
+
+
+#define maxlyrlen (PMXlinelength - 15)
+
+
+Local void convertlyrics(Char *lyn, voice_index voice, auxtype mx)
+{
+ static Char setlyr[256] = "%%\\\\\\mtxSetLyrics";
+ Char btag[256], thistag[256], w[256];
+ boolean numbered;
+ Char STR1[256];
+ lyrtagtype *WITH;
+ Char STR2[256];
+
+ NextWord(w, lyn, blank, dummy);
+ WITH = &tag[voice-1];
+ if (*w == '\0') {
+ *WITH->tags = '\0';
+ return;
+ }
+ WITH->has_lyrics = haslyr;
+ WITH->auxiliary = mx;
+ if (w[0] == '{') {
+ registerLyrics(voice, w);
+ return;
+ }
+ WITH->lyrsource = local_lyrics;
+ WITH->linecount++;
+ toString(thistag, voice * 10 + WITH->linecount);
+ sprintf(btag, "{%s}", thistag);
+ if (*WITH->tags == '\0')
+ strcpy(WITH->tags, btag);
+ else {
+ WITH->tags[strlen(WITH->tags) - 1] = ',';
+ sprintf(WITH->tags + strlen(WITH->tags), "%s}", thistag);
+ }
+ trim(lyn);
+ lyrTranslate(lyn, &numbered);
+ if (numbered)
+ markNumbered(thistag);
+ if (strlen(lyn) + strlen(btag) > maxlyrlen)
+ sprintf(lyn, "%s%s{\\\n\\\\\\:%s}\\", setlyr, btag, strcpy(STR2, lyn));
+ else
+ sprintf(lyn, "%s%s{%s}\\", setlyr, btag, strcpy(STR1, lyn));
+}
+
+#undef maxlyrlen
+
+
+void maybeLyrics(voice_index voice, paragraph_index parline, Char *w_)
+{
+ /* during paragraph analysis, parline had L:, already stripped */
+ Char w[256];
+ voice_index0 k;
+
+ /** Labelled lyrics line -- */
+ strcpy(w, w_);
+ if (!doLyrics())
+ return;
+ if (strlen(w) == 1 && voice == 0)
+ warning("Lyrics line above top voice should be labelled", print);
+ if (strlen(w) == 1) { /** Standard lyrics line -------- */
+ k = voice;
+ if (k == 0)
+ k = 1;
+ convertlyrics(P[parline-1], k, normal);
+ return;
+ }
+ predelete(w, 1);
+ k = findVoice(w);
+ if (k == 0)
+ error("Lyrics line belongs to unknown voice", print);
+ else
+ convertlyrics(P[parline-1], k, aux);
+}
+
+
+void reviseLyrics(void)
+{
+ /* after paragraph analysis */
+ voice_index voice;
+ stave_index stave;
+ voice_index FORLIM;
+ lyrtagtype *WITH;
+ stave_index FORLIM1;
+
+ FORLIM = nvoices;
+ for (voice = 0; voice <= FORLIM - 1; voice++) {
+ WITH = &tag[voice];
+ if (oldtag[voice].lyrsource == global_lyrics &&
+ WITH->lyrsource == none_given) {
+ strcpy(WITH->tags, oldtag[voice].tags);
+ WITH->lyrsource = global_lyrics;
+ }
+ WITH->new_assign = (assigntype)(WITH->has_lyrics == haslyr &&
+ strcmp(WITH->tags, oldtag[voice].tags));
+ if (*WITH->tags == '\0')
+ WITH->has_lyrics = nolyr;
+ strcpy(oldtag[voice].tags, WITH->tags);
+ oldtag[voice].lyrsource = WITH->lyrsource;
+ }
+ FORLIM1 = nstaves;
+ for (stave = 1; stave <= FORLIM1; stave++) {
+ WITH = &tag[first_on_stave[stave-1] - 1];
+ lyrmodealter[stave-1] = (!aloneOnStave(stave) &&
+ WITH->has_lyrics == haslyr &&
+ WITH->auxiliary == normal);
+ }
+}
+
+
+void assignLyrics(stave_index stave, Char *lyrassign)
+{
+ /* at start of new block */
+ Char atag[256], instr[256], l[256];
+ voice_index v1, v2, voice;
+ lyrtagtype *WITH;
+ Char STR2[256];
+ lyrinfotype *WITH1;
+
+ *lyrassign = '\0';
+ toString(instr, PMXinstr(stave));
+ v1 = first_on_stave[stave-1];
+ v2 = v1 + number_on_stave[stave-1] - 1;
+ /* don't reassign if other voice takes over */
+ if (tag[v1-1].auxiliary == tag[v2-1].auxiliary &&
+ tag[v1-1].has_lyrics != tag[v2-1].has_lyrics) {
+ for (voice = v1 - 1; voice <= v2 - 1; voice++) {
+ WITH = &tag[voice];
+ if (WITH->new_assign == newassign)
+ WITH->new_assign = (assigntype)WITH->has_lyrics;
+ }
+ }
+ for (voice = v1 - 1; voice <= v2 - 1; voice++)
+ lyrinfo[voice].numbered = false;
+ for (voice = v1; voice <= v2; voice++) {
+ WITH = &tag[voice-1];
+ if (WITH->new_assign == newassign) {
+ strcpy(atag, WITH->tags);
+ if (*atag == '\0')
+ strcpy(atag, "{}");
+ sprintf(l, "\\mtxAssignLyrics{%s}%s", instr, atag);
+ if (WITH->auxiliary == aux)
+ sprintf(l, "\\mtxAuxLyr{%s}", strcpy(STR2, l));
+ strcat(lyrassign, l);
+ if (*WITH->tags == '\0')
+ WITH->has_lyrics = nolyr;
+ if (WITH->has_lyrics == haslyr && WITH->initialized == virgin) {
+ WITH1 = &lyrinfo[voice-1];
+ if (WITH->auxiliary == aux && upper(voice))
+ WITH1->lyr_adjust = interstave;
+ else
+ WITH1->lyr_adjust = 0;
+ strcat(lyrassign, songraise(STR2, voice));
+ WITH->initialized = active;
+ }
+ if (anyTagNumbered(atag))
+ lyrinfo[voice-1].numbered = true;
+ }
+ }
+ if (lyrmodealter[stave-1] == oldlyrmodealter[stave-1])
+ return;
+ if (lyrmodealter[stave-1])
+ sprintf(lyrassign + strlen(lyrassign), "\\mtxLyrModeAlter{%s}", instr);
+ else
+ sprintf(lyrassign + strlen(lyrassign), "\\mtxLyrModeNormal{%s}", instr);
+ oldlyrmodealter[stave-1] = lyrmodealter[stave-1];
+}
+
+
+void lyricsAdjust(voice_index voice, Char *note)
+{
+ /* inline at-word */
+ short adj;
+ boolean force, put_above, put_below;
+ lyrinfotype *WITH;
+ lyrtagtype *WITH1;
+ Char STR2[256];
+
+ WITH = &lyrinfo[voice-1];
+ WITH1 = &tag[voice-1];
+ predelete(note, 1);
+ force = (note[0] == '=');
+ if (force)
+ predelete(note, 1);
+ put_above = (note[0] == '^');
+ if (put_above)
+ predelete(note, 1);
+ put_below = (note[0] == 'v');
+ if (put_below)
+ predelete(note, 1);
+ if (*note != '\0')
+ getNum(note, &adj);
+ else
+ adj = 0;
+ if (WITH1->has_lyrics == nolyr) {
+ *note = '\0';
+ return;
+ }
+ if (put_above)
+ WITH->lyr_adjust = interstave;
+ else if (put_below)
+ WITH->lyr_adjust = 0;
+ if (force)
+ WITH->lyr_adjust = adj;
+ else
+ WITH->lyr_adjust += adj;
+ songraise(note, voice);
+ if (*note != '\0')
+ sprintf(note, "\\\\%s\\", strcpy(STR2, note));
+}
+
+
+void lyrTranslate(Char *P, boolean *numbered)
+{ /* Test for starting number */
+ short k, l, number;
+ Char Q[256], w[256];
+
+ NextWord(w, P, blank, dummy);
+ *numbered = false;
+ if (endsWith(w, ".")) {
+ getNum(w, &number);
+ *numbered = (number != 0);
+ }
+ /*Translate lyrics link */
+ *Q = '\0';
+ l = strlen(P);
+ for (k = 1; k <= l - 1; k++) {
+ if (P[k-1] != '_' || P[k] == '_' || P[k] == ' ' || pos1(P[k], digits) > 0)
+ sprintf(Q + strlen(Q), "%c", P[k-1]);
+ else if (k > 1 && P[k-2] == '\\')
+ strcat(Q, "mtxLowLyrlink ");
+ else
+ strcat(Q, "\\mtxLyrlink ");
+ }
+ sprintf(Q + strlen(Q), "%c", P[l-1]);
+ strcpy(P, Q);
+}
+
+
+typedef enum {
+ beam, slur
+} melismaEnd;
+
+
+Static Char removeLast(Char *s, Char *t)
+{
+ Char Result;
+ short i, l;
+
+ l = strlen(s);
+ for (i = l; i >= 1; i--) {
+ if (pos1(s[i-1], t) > 0) {
+ Result = s[i-1];
+ delete1(s, i);
+ return Result;
+ }
+ }
+ return dummy;
+}
+
+
+Static boolean OpenMelisma(Char *s)
+{
+ return (pos1(slur_melisma, s) > 0 || pos1(beam_melisma, s) > 0);
+}
+
+
+/* Local variables for getSyllable: */
+struct LOC_getSyllable {
+ voice_index voice;
+ boolean BM, EM;
+} ;
+
+Local void startMelismas(Char *t, struct LOC_getSyllable *LINK)
+{
+ boolean open_before, open_now;
+ short i, k;
+ lyrinfotype *WITH;
+
+ k = strlen(t);
+ for (i = 0; i <= k - 1; i++) {
+ WITH = &lyrinfo[LINK->voice-1];
+ open_before = OpenMelisma(WITH->melisma);
+ sprintf(WITH->melisma + strlen(WITH->melisma), "%c", t[i]);
+ open_now = OpenMelisma(WITH->melisma);
+ LINK->BM = (LINK->BM || open_now && !open_before);
+ }
+}
+
+Local boolean endMelisma(short voice, struct LOC_getSyllable *LINK)
+{
+ Char found;
+ short i;
+ short count[2];
+ melismaEnd t;
+ short FORLIM1;
+ lyrinfotype *WITH;
+ Char STR1[4];
+
+ LINK->EM = false;
+ count[(long)slur] = -lyrinfo[voice-1].slur_change;
+ count[(long)beam] = -lyrinfo[voice-1].beam_change;
+ for (t = beam; t <= slur; t = (melismaEnd)((long)t + 1)) {
+ FORLIM1 = count[(long)t];
+ for (i = 1; i <= FORLIM1; i++) {
+ WITH = &lyrinfo[voice-1];
+ switch (t) {
+
+ case slur:
+ sprintf(STR1, "%c%c", slur_melisma, inhibit_slur_melisma);
+ found = removeLast(WITH->melisma, STR1);
+ break;
+
+ case beam:
+ sprintf(STR1, "%c%c", beam_melisma, inhibit_beam_melisma);
+ found = removeLast(WITH->melisma, STR1);
+ break;
+ }
+ if (found == dummy)
+ error3(voice, "Ending a melisma that was never started");
+ LINK->EM = (LINK->EM ||
+ (!OpenMelisma(WITH->melisma) &&
+ pos1(found, (sprintf(STR1, "%c%c", slur_melisma, beam_melisma),
+ STR1)) > 0));
+ }
+ }
+ return LINK->EM;
+}
+
+Local void startSlurMelisma(voice_index voice, struct LOC_getSyllable *LINK)
+{
+ static Char start[2] = {
+ slur_melisma, inhibit_slur_melisma
+ };
+
+ Char slurs[256];
+ short k, FORLIM;
+ Char STR1[256];
+
+ *slurs = '\0';
+ FORLIM = lyrinfo[voice-1].slur_change;
+ for (k = 1; k <= FORLIM; k++)
+ sprintf(slurs, "%c%s",
+ start[noSlurMelisma(voice, 1 - k)], strcpy(STR1, slurs));
+ startMelismas(slurs, LINK);
+}
+
+Local void startBeamMelisma(voice_index voice, struct LOC_getSyllable *LINK)
+{
+ static Char start[2] = {
+ beam_melisma, inhibit_beam_melisma
+ };
+
+ Char beams[256];
+ short k, FORLIM;
+ Char STR1[256];
+
+ *beams = '\0';
+ FORLIM = lyrinfo[voice-1].beam_change;
+ for (k = 1; k <= FORLIM; k++)
+ sprintf(beams, "%c%s", start[noBeamMelisma(voice)], strcpy(STR1, beams));
+ startMelismas(beams, LINK);
+}
+
+Local boolean startMelisma(short voice, struct LOC_getSyllable *LINK)
+{
+ LINK->BM = false;
+ startSlurMelisma(voice, LINK);
+ startBeamMelisma(voice, LINK);
+ return LINK->BM;
+}
+
+
+/* Append mtxBM or mtxEM to pretex when appropriate */
+void getSyllable(voice_index voice_, Char *pretex)
+{
+ struct LOC_getSyllable V;
+ short t;
+ lyrtagtype *WITH;
+ lyrinfotype *WITH1;
+
+ V.voice = voice_;
+ WITH = &tag[V.voice-1];
+ WITH1 = &lyrinfo[V.voice-1];
+ if (WITH->has_lyrics != haslyr)
+ return;
+ t = WITH1->slur_level;
+ WITH1->slur_level = slurLevel(V.voice);
+ WITH1->slur_change = WITH1->slur_level - t;
+ t = WITH1->beam_level;
+ WITH1->beam_level = beamLevel(V.voice);
+ WITH1->beam_change = WITH1->beam_level - t;
+ if (startMelisma(V.voice, &V)) {
+ if (WITH->auxiliary == aux)
+ strcat(pretex, "\\mtxAuxBM");
+ else
+ strcat(pretex, "\\mtxBM");
+ }
+ if (!endMelisma(V.voice, &V))
+ return;
+ if (WITH->auxiliary == aux)
+ strcat(pretex, "\\mtxAuxEM");
+ else
+ strcat(pretex, "\\mtxEM");
+}
+
+
+Static void getSyllable1(voice_index voice, Char *pretex)
+{
+ lyrinfotype *WITH;
+
+ WITH = &lyrinfo[voice-1];
+ printf("voice=%d, slurchange=%d, melisma=%s, beamchange=%d\n",
+ voice, WITH->slur_change, WITH->melisma, WITH->beam_change);
+ getSyllable1(voice, pretex);
+ if (*pretex != '\0')
+ printf("pretex = %s\n", pretex);
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/lyrics.h b/Build/source/utils/m-tx/mtx-src/lyrics.h
new file mode 100644
index 00000000000..89ab1532cb6
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/lyrics.h
@@ -0,0 +1,37 @@
+/* Header for module lyrics, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef LYRICS_H
+#define LYRICS_H
+
+
+/* Everything related to lyrics */
+
+#ifndef GLOBALS_H
+#include "globals.h"
+#endif
+
+
+#ifdef LYRICS_G
+# define vextern
+#else
+# define vextern extern
+#endif
+
+extern void initLyrics(void);
+extern void clearTags(void);
+extern void reviseLyrics(void);
+extern void lyrTranslate(Char *P, boolean *numbered);
+extern void getSyllable(voice_index voice, Char *pretex);
+extern Char *lyricsReport(Char *Result, voice_index voice);
+extern void maybeLyrics(voice_index voice, paragraph_index parline, Char *w);
+extern void extractLyrtag(voice_index voice, Char *note);
+extern void lyricsAdjust(voice_index voice, Char *note);
+extern void assignLyrics(stave_index stave, Char *lyrassign);
+extern void lyricsParagraph(void);
+extern boolean hasVerseNumber(voice_index voice);
+
+
+#undef vextern
+
+#endif /*LYRICS_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/lyrics.pas b/Build/source/utils/m-tx/mtx-src/lyrics.pas
new file mode 100644
index 00000000000..51253b222d7
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/lyrics.pas
@@ -0,0 +1,456 @@
+unit lyrics;
+{ Everything related to lyrics }
+
+interface uses globals;
+
+procedure initLyrics;
+procedure clearTags;
+procedure reviseLyrics;
+procedure lyrTranslate(var P: string; var numbered: boolean);
+procedure getSyllable(voice: voice_index; var pretex: string);
+function lyricsReport (voice: voice_index): string;
+procedure maybeLyrics (voice: voice_index; parline: paragraph_index;
+ w: string);
+procedure extractLyrtag (voice: voice_index; var note: string);
+procedure lyricsAdjust (voice: voice_index; var note: string);
+procedure assignLyrics(stave: stave_index; var lyrassign: string);
+procedure lyricsParagraph;
+function hasVerseNumber(voice: voice_index): boolean;
+
+implementation uses control, strings, mtxline, status, files, utility;
+
+{ Symbols used in strings of melismatype }
+const
+ beam_melisma = '[';
+ inhibit_beam_melisma = '<';
+ slur_melisma = '(';
+ inhibit_slur_melisma = '{';
+
+type
+ other_index = 1..10;
+ other_index0 = 0..10;
+ melismatype = string;
+ haslyrtype = (nolyr, haslyr);
+ auxtype= (normal, aux);
+ assigntype = (asbefore, newassign);
+ inittype = (virgin,active);
+ lyrinfotype = record
+ lyr_adjust, slur_level, slur_change, beam_level, beam_change: integer;
+ melisma: melismatype;
+ numbered: boolean;
+ end;
+
+ lyrlinetype = (none_given, global_lyrics, local_lyrics);
+ lyrtagtype = record
+ lyrsource: lyrlinetype;
+ has_lyrics: haslyrtype;
+ auxiliary: auxtype;
+ new_assign: assigntype;
+ initialized: inittype;
+ linecount: integer;
+ tags: string;
+ end;
+
+const maxLyrNums=64;
+ lyrtaglength=40;
+ LyrNum: integer=0;
+
+var lyrmodealter, oldlyrmodealter: array[stave_index] of boolean;
+ tag, oldtag: array[voice_index] of lyrtagtype;
+ lyrinfo: array[voice_index] of lyrinfotype;
+ numberedParagraph: array[1..maxLyrNums] of string[lyrtaglength];
+
+const lyr_adjust_undef = -12345;
+ interstave = 24;
+
+{ Information flow for verse numbers: at the SetLyrics stage, the first
+line of each lyrics paragraph is checked for a verse number, and if
+found, the paragraph tag is remembered. At the AssignLyrics stage,
+the first time that paragraph is encountered, the particular voice
+is marked in lyrinfo as being numbered. When that voice is later processed,
+the mark in lyrinfo is interrogated and turned off: if it was on, the
+mtxVerse pre-TeX string is put into the output. }
+
+function hasVerseNumber(voice: voice_index): boolean;
+begin hasVerseNumber:=lyrinfo[voice].numbered;
+ lyrinfo[voice].numbered:=false;
+end;
+
+function isNumberedLyricsParagraph(tag: string): boolean;
+ var i: integer;
+begin
+ for i:=1 to LyrNum do if tag=numberedParagraph[i] then
+ begin isNumberedLyricsParagraph:=true; exit; end;
+ isNumberedLyricsParagraph:=false;
+end;
+
+function anyTagNumbered(tags: string): boolean;
+ var s: string;
+begin anyTagNumbered:=false;
+ if curtail(tags,'}')>0 then delete1(tags,1);
+ repeat s:=getNextWord(tags,',',dummy);
+ if s='' then exit;
+ if isNumberedLyricsParagraph(s) then
+ begin anyTagNumbered:=true; exit; end;
+ until false;
+end;
+
+{ Save the tag in the numberedParagraph list, stripping off braces if any }
+procedure markNumbered(tag: string);
+begin if LyrNum >= maxLyrNums then
+ begin error('Too many numbered lines in the lyrics',not print); exit; end;
+ inc(LyrNum);
+ if curtail(tag,'}')>0 then delete1(tag,1);
+ numberedParagraph[LyrNum] := tag;
+end;
+
+{ --- end of procedures to keep track of verse numbering --- }
+
+procedure lyricsParagraph;
+ var first, w: string;
+ l, line: paragraph_index0;
+ i, nother: other_index0;
+ other: array[other_index] of string[lyrtaglength];
+ numbered: boolean;
+begin if not doLyrics then exit;
+ if para_len<2 then fatalerror('empty lyrics paragraph');
+ w:=NextWord(P[1],blank,dummy); l:=length(w); line_no := orig_line_no[1];
+ if w[l]<>'}' then w:=w+'}';
+ first:=GetNextWord(w,dummy,'}'); nother:=0;
+ while w<>'' do
+ begin if w[1]='=' then predelete(w,1);
+ if w[1]<>'{' then w:='{'+w;
+ inc(nother); other[nother]:=GetNextWord(w,dummy,'}');
+ end;
+ if beVerbose then
+ begin write('---- Paragraph ', paragraph_no, ' starting at line ', line_no,
+ ' has lyrics headed ',first);
+ for i:=1 to nother do write('=',other[i]); writeln;
+ end;
+ TeXtype2(comment+' Paragraph '+toString(paragraph_no)+' line '+
+ toString(line_no)+' bar '+toString(bar_no));
+ TeXtype2('\mtxSetLyrics'+first+'{%');
+ for line:=2 to para_len do
+ begin lyrTranslate(P[line],numbered);
+ if numbered then if (line>2) then warning(
+ 'Verse number not in first line of paragraph treated as lyrics',print)
+ else
+ begin markNumbered(first); for i:=1 to nother do markNumbered(other[i]);
+ end;
+ line_no:=orig_line_no[line];
+ if (length(P[line])>max_lyrics_line_length) and pmx_preamble_done
+ then error('Lyrics line too long',print);
+ if pmx_preamble_done then
+ if line=2 then put('\\\:'+P[line],putspace)
+ else put('\\\ ' + P[line],putspace)
+ else put(P[line],putspace);
+ if line<para_len then
+ if pmx_preamble_done then putLine(' %\')
+ else putLine(' %')
+ else if pmx_preamble_done then putLine('}\')
+ else putLine('}')
+ end;
+ for i:=1 to nother do TeXtype2('\mtxCopyLyrics'+first+other[i]);
+end;
+
+function songraise(voice: voice_index): string;
+ var s: string;
+begin with tag[voice] do with lyrinfo[voice] do
+ if (initialized=virgin) and (lyr_adjust=0) then songraise:='' else
+ begin
+ if auxiliary=aux then s:='Aux' else s:='';
+ songraise:='\mtx'+s+'LyricsAdjust{'+toString(PMXinstr(voiceStave(voice)))
+ +'}{'+toString(lyr_adjust)+'}';
+ end;
+end;
+
+function lyricsReport (voice: voice_index): string;
+ var l: string;
+begin with tag[voice] do
+ if (has_lyrics=nolyr) or (lyrsource=none_given) and (tags='') then
+ lyricsReport := ' but has no own lyrics'
+ else begin
+ l := ' with ';
+ if auxiliary=aux then l := l + 'auxiliary ';
+ l := l + 'lyrics ';
+ if lyrsource=local_lyrics then l:= l + 'locally defined as "'
+ else l := l + 'labelled "';
+ l := l + tags + '"';
+ if anyTagNumbered(tags) then l := l + ' with verse numbers';
+ lyricsReport := l;
+ end;
+end;
+
+procedure initLyrics; { at the start only }
+ var stave: stave_index;
+ voice: voice_index;
+begin for voice:=1 to nvoices do
+ with lyrinfo[voice] do with tag[voice] do
+ begin has_lyrics:=nolyr; lyr_adjust:=lyr_adjust_undef;
+ melisma:=''; slur_level:=0; beam_level:=0; auxiliary:=aux;
+ lyrsource:=none_given; new_assign := asbefore; initialized := virgin;
+ end;
+ for stave:=1 to nstaves do oldlyrmodealter[stave] := false;
+end;
+
+procedure registerLyrics (voice: voice_index; w: string);
+begin
+ with tag[voice] do
+ begin oldtag[voice].tags:=tags;
+ oldtag[voice].lyrsource:=lyrsource;
+ lyrsource:=global_lyrics;
+ case length(w) of
+ 0: tags := '';
+ 1: FatalError('M-Tx system error in registerLyrics');
+ else tags := w;
+ end;
+ end;
+end;
+
+procedure extractLyrtag (voice: voice_index; var note: string);
+ { inline lyrics change }
+begin with tag[voice] do
+ if has_lyrics=nolyr then
+ error3(voice,'Inline lyrics change on no-lyrics line')
+ else begin registerLyrics(voice,note); { was: ''); }
+ note:='\mtxAssignLyrics{'+toString(PMXinstr(voiceStave(voice)))+'}'+note;
+ if auxiliary=aux then note:='\mtxAuxLyr{'+note+'}\' else note:=note+'\';
+ end;
+end;
+
+procedure clearTags; { at start of paragraph analyis }
+ var voice: voice_index;
+begin
+ oldtag:=tag;
+ for voice:=1 to nvoices do with tag[voice] do
+ begin
+ lyrsource:=none_given; tags := ''; linecount:=0;
+ end;
+end;
+
+procedure maybeLyrics (voice: voice_index; parline: paragraph_index;
+ w: string);
+ { during paragraph analysis, parline had L:, already stripped }
+ var k: voice_index0;
+ procedure convertlyrics(var lyn: string; voice: voice_index; mx: auxtype);
+ const setlyr: string = '%%\\\mtxSetLyrics';
+ maxlyrlen = PMXlinelength-15;
+ var btag, thistag, w: string;
+ numbered: boolean;
+ begin
+ w:=NextWord(lyn,blank,dummy); with tag[voice] do
+ begin
+ if w='' then tags:=''
+ else begin
+ has_lyrics:=haslyr; auxiliary:=mx;
+ if w[1]='{' then registerLyrics(voice,w)
+ else begin lyrsource:=local_lyrics;
+ inc(linecount); thistag:=toString(10*voice+linecount);
+ btag := '{'+thistag+'}';
+ if tags='' then tags:=btag
+ else begin tags[length(tags)]:=','; tags:=tags+thistag+'}'; end;
+ trim(lyn); lyrTranslate(lyn,numbered);
+ if numbered then markNumbered(thistag);
+ if length(lyn)+length(btag)>maxlyrlen then
+ lyn := setlyr + btag + '{\'^J'\\\:' + lyn +'}\'
+ else lyn:= setlyr + btag + '{' + lyn +'}\';
+ end;
+ end;
+ end;
+ end;
+begin if not dolyrics then exit;
+ if (length(w)=1) and (voice=0) then
+ warning('Lyrics line above top voice should be labelled',print);
+ if length(w)=1 then {* Standard lyrics line -------- }
+ begin k:=voice; if k=0 then k:=1; convertlyrics(P[parline],k,normal);
+ end
+ else {* Labelled lyrics line -- }
+ begin predelete(w,1); k:=findVoice(w);
+ if k=0 then error('Lyrics line belongs to unknown voice',print)
+ else convertlyrics(P[parline],k,aux);
+ end;
+end;
+
+procedure reviseLyrics; { after paragraph analysis }
+ var voice : voice_index;
+ stave : stave_index;
+begin
+ for voice:=1 to nvoices do with tag[voice] do
+ begin if (oldtag[voice].lyrsource=global_lyrics) and
+ (lyrsource=none_given) then
+ begin tags:=oldtag[voice].tags; lyrsource:=global_lyrics; end;
+ new_assign :=
+ assigntype(ord((has_lyrics=haslyr) and (tags<>oldtag[voice].tags)));
+ if tags='' then has_lyrics := nolyr;
+ oldtag[voice].tags := tags;
+ oldtag[voice].lyrsource := lyrsource;
+ end;
+ for stave:=1 to nstaves do with tag[first_on_stave[stave]] do
+ lyrmodealter[stave] := not aloneOnStave(stave) and
+ (has_lyrics=haslyr) and (auxiliary=normal);
+end;
+
+procedure assignLyrics(stave: stave_index; var lyrassign: string);
+ { at start of new block }
+ var atag, instr, l: string;
+ v1, v2, voice: voice_index;
+ begin lyrassign:=''; instr := toString(pmxinstr(stave));
+ v1:=first_on_stave[stave]; v2:=v1+number_on_stave[stave]-1;
+ if v1<v2 then { don't reassign if other voice takes over };
+ if (tag[v1].auxiliary=tag[v2].auxiliary) and
+ (tag[v1].has_lyrics<>tag[v2].has_lyrics) then
+ for voice:=v1 to v2 do with tag[voice] do
+ if new_assign=newassign then new_assign:=assigntype(has_lyrics);
+ for voice:=v1 to v2 do lyrinfo[voice].numbered:=false;
+ for voice:=v1 to v2 do
+ with tag[voice] do if new_assign=newassign then
+ begin atag:=tags; if atag='' then atag:='{}';
+ l := '\mtxAssignLyrics{' + instr + '}' + atag;
+ if auxiliary=aux then l:='\mtxAuxLyr{' + l + '}';
+ lyrassign := lyrassign + l;
+ if tags='' then has_lyrics:=nolyr;
+ if (has_lyrics=haslyr) and (initialized=virgin) then
+ with lyrinfo[voice] do
+ begin if (auxiliary=aux) and upper(voice) then
+ lyr_adjust:=interstave else lyr_adjust:=0;
+ lyrassign := lyrassign + songraise(voice);
+ initialized := active;
+ end;
+ if anyTagNumbered(atag) then lyrinfo[voice].numbered:=true;
+ end;
+ if lyrmodealter[stave]<>oldlyrmodealter[stave] then
+ begin if lyrmodealter[stave] then
+ lyrassign := lyrassign + '\mtxLyrModeAlter{' + instr + '}'
+ else lyrassign := lyrassign + '\mtxLyrModeNormal{' + instr + '}';
+ oldlyrmodealter[stave] := lyrmodealter[stave];
+ end;
+ end;
+
+procedure lyricsAdjust (voice: voice_index; var note: string);
+ { inline at-word }
+ var adj: integer;
+ force, put_above, put_below: boolean;
+begin with lyrinfo[voice] do with tag[voice] do
+ begin predelete(note,1);
+ force:=note[1]='='; if force then predelete(note,1);
+ put_above:=note[1]='^'; if put_above then predelete(note,1);
+ put_below:=note[1]='v'; if put_below then predelete(note,1);
+ if note<>'' then getNum(note,adj) else adj:=0;
+ if has_lyrics=nolyr then begin note:=''; exit; end;
+ if put_above then lyr_adjust:=interstave
+ else if put_below then lyr_adjust:=0;
+ if force then lyr_adjust:=adj else inc(lyr_adjust,adj);
+ note:=songraise(voice); if note<>'' then note:='\\'+note+'\';
+ end
+end;
+
+procedure lyrTranslate(var P: string; var numbered: boolean);
+ var k, l, number: integer;
+ Q, w: string;
+begin { Test for starting number } w:=NextWord(P,blank,dummy);
+ numbered:=false;
+ if endsWith(w,'.') then begin getNum(w,number); numbered:=number<>0 end;
+ {Translate lyrics link } Q := ''; l:=length(P);
+ for k:=1 to l-1 do
+ if (P[k]<>'_') or (P[k+1]='_') or (P[k+1]=' ') or (pos1(P[k+1],digits)>0)
+ then Q := Q+P[k]
+ else if (k>1) and (P[k-1]='\') then Q := Q+'mtxLowLyrlink '
+ else Q := Q+'\mtxLyrlink ';
+ Q:=Q+P[l];
+ P := Q;
+end;
+
+type melismaEnd = (beam, slur);
+
+function removeLast(var s: string; t: string): char;
+ var i,l: integer;
+begin l:=length(s);
+ for i:=l downto 1 do if pos1(s[i],t)>0 then
+ begin removeLast:=s[i]; delete1(s,i); exit; end;
+ removeLast := dummy;
+end;
+
+function OpenMelisma(s: string): boolean;
+begin OpenMelisma := (pos1(slur_melisma,s)>0) or (pos1(beam_melisma,s)>0);
+end;
+
+{ Append mtxBM or mtxEM to pretex when appropriate }
+procedure getSyllable(voice: voice_index; var pretex: string);
+ var BM, EM: boolean;
+ procedure startMelismas (t: string);
+ var open_before, open_now: boolean;
+ i, k: integer;
+ begin k:=length(t);
+ for i:=1 to k do with lyrinfo[voice] do
+ begin open_before := OpenMelisma(melisma);
+ melisma := melisma + t[i];
+ open_now := OpenMelisma(melisma);
+ BM := BM or (open_now and not open_before)
+ end;
+ end;
+ function endMelisma(voice: integer): boolean;
+ var found: char;
+ i: integer;
+ count: array[melismaEnd] of integer;
+ t: melismaEnd;
+ begin EM := false;
+ count[slur] := -lyrinfo[voice].slur_change;
+ count[beam] := -lyrinfo[voice].beam_change;
+ for t:=beam to slur do for i:=1 to count[t] do with lyrinfo[voice] do
+ begin
+ case t of
+ slur: found := removeLast(melisma,slur_melisma+inhibit_slur_melisma);
+ beam: found := removeLast(melisma,beam_melisma+inhibit_beam_melisma);
+ end;
+ if found=dummy then
+ error3(voice,'Ending a melisma that was never started');
+ EM := EM or (not openMelisma(melisma)
+ and (pos1(found,slur_melisma+beam_melisma)>0))
+ end;
+ endMelisma := EM
+ end;
+ procedure startSlurMelisma(voice: voice_index);
+ const start: array[boolean] of char = (slur_melisma,inhibit_slur_melisma);
+ var slurs: string;
+ k: integer;
+ begin slurs:='';
+ for k:=1 to lyrinfo[voice].slur_change do
+ slurs:=start[noSlurMelisma(voice,1-k)]+slurs;
+ startMelismas(slurs)
+ end;
+ procedure startBeamMelisma(voice: voice_index);
+ const start: array[boolean] of char = (beam_melisma,inhibit_beam_melisma);
+ var beams: string;
+ k: integer;
+ begin beams:='';
+ for k:=1 to lyrinfo[voice].beam_change do
+ beams:=start[noBeamMelisma(voice)]+beams;
+ startMelismas(beams)
+ end;
+ function startMelisma(voice: integer): boolean;
+ begin BM:=false; startSlurMelisma(voice); startBeamMelisma(voice);
+ startMelisma := BM
+ end;
+ var t: integer;
+begin with tag[voice] do with lyrinfo[voice] do
+ begin if has_lyrics<>haslyr then exit;
+ t:=slur_level; slur_level:=slurLevel(voice); slur_change:=slur_level-t;
+ t:=beam_level; beam_level:=beamLevel(voice); beam_change:=beam_level-t;
+ if startMelisma(voice) then if auxiliary=aux
+ then pretex:=pretex+'\mtxAuxBM' else pretex:=pretex+'\mtxBM';
+ if endMelisma(voice) then if auxiliary=aux
+ then pretex:=pretex+'\mtxAuxEM' else pretex:=pretex+'\mtxEM'
+ end
+end;
+
+procedure getSyllable1(voice: voice_index; var pretex: string);
+begin with lyrinfo[voice] do
+ begin
+ writeln('voice=',voice, ', slurchange=',slur_change,
+ ', melisma=',melisma, ', beamchange=', beam_change)
+ end;
+ getSyllable1(voice,pretex);
+ if pretex<>'' then writeln('pretex = ',pretex)
+end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/mtx.c b/Build/source/utils/m-tx/mtx-src/mtx.c
new file mode 100644
index 00000000000..6271b2094c5
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/mtx.c
@@ -0,0 +1,483 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "mtx.pas" */
+
+
+#include "p2c.h"
+
+
+#define MTX_G
+#include "mtx.h"
+
+
+#ifndef CONTROL_H
+#include "control.h"
+#endif
+
+#ifndef MTXLINE_H
+#include "mtxline.h"
+#endif
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+#ifndef STATUS_H
+#include "status.h"
+#endif
+
+#ifndef NOTES_H
+#include "notes.h"
+#endif
+
+
+#define flagged "8136"
+
+
+typedef boolean sticky['z' + 1 - 'a'];
+
+
+Static sticky note_attrib[maxvoices], rest_attrib[maxvoices];
+
+
+Static short logTwo(short denom)
+{
+ short l = 0;
+
+ while (denom > 1) {
+ l++;
+ denom /= 2;
+ }
+ return l;
+}
+
+
+Local boolean dotted(short n)
+{
+ boolean Result;
+
+/* p2c: mtx.pas: Note: Eliminated unused assignment statement [338] */
+ if (n == 0)
+ return false;
+ if (n != n / 3 * 3)
+ return false;
+ n /= 3;
+ while ((n & 1) == 0)
+ n /= 2;
+ return (n == 1);
+}
+
+
+/* RESTS should have a third parameter OFFSET. At present we in effect
+ assume OFFSET+LENGTH to be a multiple of METERDENOM. */
+Char *rests(Char *Result, short len, short meterdenom, boolean blind)
+{
+ Char r[256], bl[256];
+ Char STR1[256];
+
+ if (blind)
+ strcpy(bl, "b");
+ else
+ *bl = '\0';
+ if (len == 0)
+ return strcpy(Result, "");
+ else {
+ if (len == meterdenom * 128) {
+ sprintf(Result, "r9%s ", bl);
+ return Result;
+ } else {
+ if (dotted(len)) {
+ rests(r, len - len / 3, meterdenom, false);
+ r[2] = 'd';
+ sprintf(Result, "%s%s ", r, bl);
+ return Result;
+ } else if (len >= 64 / meterdenom) {
+ sprintf(Result, "%sr%c%s ",
+ rests(STR1, len - 64 / meterdenom, meterdenom, blind),
+ durations[whole + logTwo(meterdenom) - 1], bl);
+ return Result;
+ } else
+ return (rests(Result, len, meterdenom * 2, blind));
+ }
+ }
+}
+
+
+Local Char *attribs(Char *Result, Char *note)
+{
+ Char a[256];
+ short i = 2;
+ short l;
+ Char n;
+
+ *a = '\0';
+ l = strlen(note);
+ while (i <= l) {
+ n = note[i-1];
+ if (n == 'x')
+ i = l;
+ else if (islower(n))
+ sprintf(a + strlen(a), "%c", n);
+ i++;
+ }
+ return strcpy(Result, a);
+}
+
+
+Static void checkSticky(Char *note, boolean *attrib)
+{
+ short i = 2;
+ short l;
+ Char c;
+ Char a[256];
+
+ if (*note == '\0')
+ return;
+ l = strlen(note);
+ while (i <= l) {
+ c = note[i-1];
+ if (islower(c)) {
+ if (i < l && note[i] == ':') {
+ delete1(note, i + 1);
+ l--;
+ attrib[c - 'a'] = !attrib[c - 'a'];
+ } else
+ attrib[c - 'a'] = false;
+ }
+ i++;
+ }
+ attribs(a, note);
+ for (c = 'z'; c >= 'a'; c--) {
+ if (attrib[c - 'a'] && pos1(c, a) == 0)
+ insertChar(c, note, 3);
+ }
+}
+
+
+/* Routine was patched by Hiroaki Morimoto, revised 2003/08/15.
+ Rewritten by DPL 2004/05/16 to be more understandable.
+ octaveCode returns octave adjustments in the order
+ [absolute or =],[relative] */
+void checkOctave(voice_index voice, Char *note)
+{
+ Char code;
+
+ code = octaveCode(note);
+ if (code == '=') {
+ setOctave(voice);
+ removeOctaveCode(code, note);
+ }
+ if (octave(voice) == blank)
+ return;
+ code = octaveCode(note);
+ if (isdigit(code)) {
+ resetOctave(voice);
+ return;
+ }
+ while (code == '+' || code == '-') {
+ newOctave(voice, code);
+ removeOctaveCode(code, note);
+ code = octaveCode(note);
+ }
+ if (code != ' ')
+ error3(voice, "You may have only one absolute octave assignment");
+ insertOctaveCode(octave(voice), note);
+ checkRange(voice, note);
+ resetOctave(voice);
+}
+
+
+void markDebeamed(voice_index voice, Char *note)
+{
+ if (isVocal(voice) && afterSlur(voice) == 0 && unbeamVocal() &&
+ pos1(duration(voice), flagged) > 0)
+ insertChar('a', note, 2);
+}
+
+
+Static short barLength(Char *meter)
+{
+ short n1, n2, pn1, pn2;
+
+ getMeter(meter, &n1, &n2, &pn1, &pn2);
+ return (n1 * (64 / n2));
+}
+
+
+Static boolean isMultiBarRest(Char *rest_)
+{
+ boolean Result;
+
+/* p2c: mtx.pas: Note: Eliminated unused assignment statement [338] */
+ if (strlen(rest_) < 3)
+ return false;
+ if (rest_[1] != 'm')
+ return false;
+ if (*multi_bar_rest != '\0')
+ error("Only one multibar rest allowed per line", print);
+ strcpy(multi_bar_rest, rest_);
+ return true;
+}
+
+
+/* Double-length in xtuplet detected by a brute search for D anywhere.
+ Could be more elegant. */
+
+Static short macro_length[20];
+
+Static Char macro_ID[20][3] = {
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14",
+ "15", "16", "17", "18", "19", "20"
+};
+
+
+/* Local variables for scanMusic: */
+struct LOC_scanMusic {
+ voice_index voice;
+ Char note[256];
+ boolean doublex, store_macro;
+ short bar, old_length, bar_length, count, l, mlen, ngrace, nmulti, macroID,
+ playID;
+ Char macro_type;
+} ;
+
+Local void decmulti(struct LOC_scanMusic *LINK)
+{
+ if (LINK->doublex)
+ LINK->nmulti -= 2;
+ else
+ LINK->nmulti--;
+}
+
+/* Local variables for countIt: */
+struct LOC_countIt {
+ struct LOC_scanMusic *LINK;
+} ;
+
+Local void incbar(short nl, struct LOC_countIt *LINK)
+{
+ LINK->LINK->bar_length += nl;
+ if (LINK->LINK->bar_length > LINK->LINK->bar && meternum > 0)
+ error3(LINK->LINK->voice, "Bar end occurs in mid-note");
+}
+
+Local void countIt(struct LOC_scanMusic *LINK)
+{
+ struct LOC_countIt V;
+
+ V.LINK = LINK;
+ if (LINK->ngrace > 0) {
+ LINK->ngrace--;
+ return;
+ }
+ if (LINK->nmulti > 0) {
+ decmulti(LINK);
+ return;
+ }
+ if (LINK->count % 3 != 0 &&
+ (LINK->note[0] != rest && note_attrib[LINK->voice-1]['d' - 'a'] ||
+ LINK->note[0] == rest && rest_attrib[LINK->voice-1]['d' - 'a']))
+ LINK->count += LINK->count / 2;
+/* p2c: mtx.pas, line 150:
+ * Note: Using % for possibly-negative arguments [317] */
+ incbar(LINK->count, &V);
+ LINK->l = pos1(multi_group, LINK->note);
+ if (LINK->l <= 0)
+ return;
+ predelete(LINK->note, LINK->l);
+ getNum(LINK->note, &LINK->nmulti);
+ decmulti(LINK);
+}
+
+Local void maybeGroup(struct LOC_scanMusic *LINK)
+{
+ if (LINK->note[0] != grace_group)
+ return;
+ if (strlen(LINK->note) == 1)
+ LINK->ngrace = 1;
+ else
+ LINK->ngrace = pos1(LINK->note[1], digits);
+ /* bug if ngrace>9 */
+ if (LINK->ngrace > 0)
+ LINK->ngrace--;
+}
+
+Local short identifyMacro(Char *s_, struct LOC_scanMusic *LINK)
+{
+ Char s[256];
+ short k;
+
+ strcpy(s, s_);
+ predelete(s, 2);
+ for (k = 1; k <= 20; k++) {
+ if (!strcmp(s, macro_ID[k-1]))
+ return k;
+ }
+ return 0;
+}
+
+Local void examineMacro(struct LOC_scanMusic *LINK)
+{
+ if (!countMacro())
+ return;
+ if (debugMode())
+ printf("%s: ", LINK->note);
+ if (strlen(LINK->note) == 1) {
+ LINK->mlen = LINK->bar_length - LINK->old_length;
+ if (LINK->macroID < 1 || LINK->macroID > 20)
+ error3(LINK->voice, "Invalid macro ID");
+ macro_length[LINK->macroID-1] = LINK->mlen;
+ if (debugMode())
+ printf("Ending macro %d of type %c, length=%d\n",
+ LINK->macroID, LINK->macro_type, LINK->mlen);
+ if (LINK->macro_type == 'S')
+ LINK->bar_length = LINK->old_length;
+ LINK->store_macro = false;
+ return;
+ }
+ LINK->playID = identifyMacro(LINK->note, LINK);
+ if (LINK->playID < 1 || LINK->playID > 20)
+ error3(LINK->voice, "Invalid macro ID");
+ if (LINK->note[1] == 'P') {
+ if (debugMode())
+ printf("Playing macro %d of length %d\n",
+ LINK->playID, macro_length[LINK->playID-1]);
+ LINK->bar_length += macro_length[LINK->playID-1];
+ return;
+ }
+ if (pos1(LINK->note[1], "SR") <= 0)
+ return;
+ LINK->old_length = LINK->bar_length;
+ LINK->macro_type = LINK->note[1];
+ LINK->macroID = LINK->playID;
+ LINK->store_macro = true;
+ if (debugMode())
+ printf("Defining macro %d of type %c\n", LINK->macroID, LINK->note[1]);
+}
+
+
+void scanMusic(voice_index voice_, short *left_over)
+{
+ struct LOC_scanMusic V;
+ Char buf[256], enote[256], xnote[256];
+ boolean has_next = false, done = false;
+ Char dur1, lastdur;
+ music_word nscan;
+ Char STR1[256];
+
+ V.voice = voice_;
+ strcpy(terminators, "d.x");
+ resetInfo(V.voice, buf);
+ *left_over = 0;
+ V.store_macro = false;
+ V.bar = full_bar;
+ V.bar_length = 0;
+ V.ngrace = 0;
+ V.nmulti = 0;
+ if (meternum == 0)
+ V.bar = 32000;
+ dur1 = duration(V.voice);
+ lastdur = dur1;
+ do {
+ getNextMusWord(buf, V.note, &nscan);
+ if (*V.note == '\0')
+ break;
+ V.count = 0;
+ /* if isNoteOrRest(note) and not (isPause(note) or isMultibarRest(note))
+ then note:=toStandard(note); */
+ V.doublex = (pos1('D', V.note) > 0 || pos1('F', V.note) > 0);
+ if (nscan == mword) {
+ if (*V.note == '\0')
+ error3(V.voice, "You may not end a line with a meter change");
+ if (V.bar_length > 0)
+ error3(V.voice, "Meter change only allowed at start of bar");
+ else
+ V.bar = barLength(V.note);
+ } else if (nscan == rword) {
+ if (!(isPause(V.note) || isMultiBarRest(V.note) ||
+ V.ngrace + V.nmulti > 0))
+ { /*0.63: allow rests in xtuples*/
+ processNote(V.note, xnote, dur1, &lastdur, &V.count);
+ checkSticky(V.note, rest_attrib[V.voice-1]);
+ }
+ }
+ if (*V.note != '\0')
+ appendNote(V.voice, nscan);
+ strcpy(enote, V.note);
+ if (nscan == macro || nscan == endmacro)
+ examineMacro(&V);
+ if (nscan == abcdefg) {
+ if (*multi_bar_rest == '\0' && V.ngrace + V.nmulti == 0) {
+ processNote(enote, xnote, dur1, &lastdur, &V.count);
+ if (*xnote != '\0') {
+ checkSticky(enote, note_attrib[V.voice-1]);
+ appendToLine(V.voice, enote);
+ appendNote(V.voice, nscan);
+ strcpy(enote, xnote);
+ }
+ checkSticky(enote, note_attrib[V.voice-1]);
+ }
+ }
+ appendToLine(V.voice, enote);
+ if (*V.note == '\0') /* !!! else word_bound[here]:=length(line); */
+ done = true;
+ sprintf(STR1, "%c", barsym);
+ if (!strcmp(V.note, STR1)) {
+ if (meternum == 0)
+ error3(V.voice, "You may not use bar lines in barless music");
+ else if (V.bar_length == 0)
+ markBar(V.voice);
+ else if (numberOfBars(V.voice) == 0 && V.bar_length < V.bar) {
+ if (has_next)
+ has_next = false; /*TODO Should check whether pickups are equal*/
+ else if (*left_over > 0)
+ error3(V.voice, "Bar is too short");
+ *left_over = V.bar_length;
+ V.bar_length = 0;
+ }
+ }
+ if (nscan == nextvoice) {
+ if (V.bar_length > 0)
+ error3(V.voice, "Next voice before bar is full");
+ else
+ barForward(V.voice, -1);
+ has_next = true;
+ } else if (isPause(V.note))
+ V.bar_length += V.bar;
+ else if (*multi_bar_rest == '\0') { /*do nothing*/
+ if (!done && isNoteOrRest(V.note))
+ countIt(&V);
+ else
+ maybeGroup(&V);
+ }
+ dur1 = lastdur;
+ if (V.bar_length >= V.bar && V.ngrace + V.nmulti == 0 && !V.store_macro) {
+ if (debugMode())
+ printf("%d %d\n", V.voice, V.bar_length);
+ barForward(V.voice, V.bar_length / V.bar);
+ V.bar_length %= V.bar;
+/* p2c: mtx.pas, line 269:
+ * Note: Using % for possibly-negative arguments [317] */
+ }
+ } while (!done);
+ setExtraLength(V.voice, V.bar_length);
+ resetDuration(V.voice, dur1);
+ regroup(V.voice);
+}
+
+
+void initMTX(void)
+{
+ voice_index i;
+ Char j;
+
+ for (i = 0; i <= maxvoices - 1; i++) {
+ for (j = 'a'; j <= 'z'; j++)
+ note_attrib[i][j - 'a'] = false;
+ }
+ memcpy(rest_attrib, note_attrib, maxvoices * sizeof(sticky));
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/mtx.h b/Build/source/utils/m-tx/mtx-src/mtx.h
new file mode 100644
index 00000000000..a056afd9b3a
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/mtx.h
@@ -0,0 +1,30 @@
+/* Header for module mtx, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef MTX_H
+#define MTX_H
+
+
+/* Details of M-Tx -> PMX translation */
+
+#ifndef GLOBALS_H
+#include "globals.h"
+#endif
+
+
+#ifdef MTX_G
+# define vextern
+#else
+# define vextern extern
+#endif
+
+extern void scanMusic(voice_index voice, short *left_over);
+extern void markDebeamed(voice_index voice, Char *note);
+extern void checkOctave(voice_index voice, Char *note);
+extern Char *rests(Char *Result, short len, short meterdenom, boolean blind);
+extern void initMTX(void);
+
+
+#undef vextern
+
+#endif /*MTX_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/mtx.pas b/Build/source/utils/m-tx/mtx-src/mtx.pas
new file mode 100644
index 00000000000..7fc12ec554c
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/mtx.pas
@@ -0,0 +1,283 @@
+unit mtx;
+{ Details of M-Tx -> PMX translation }
+
+interface uses globals;
+
+procedure scanMusic(voice: voice_index; var left_over: integer);
+procedure markDebeamed(voice: voice_index; var note: string);
+procedure checkOctave(voice: voice_index; var note: string);
+function rests (len, meterdenom: integer; blind: boolean): string;
+procedure initMTX;
+
+implementation uses control, mtxline, strings, status, notes;
+
+const flagged = '8136';
+
+type sticky = array['a'..'z'] of boolean;
+
+var note_attrib, rest_attrib: array[voice_index] of sticky;
+
+function logTwo(denom: integer): integer;
+ var l: integer;
+begin l:=0; while denom>1 do begin inc(l); denom:=denom div 2; end;
+ logtwo:=l;
+end;
+
+{ RESTS should have a third parameter OFFSET. At present we in effect
+ assume OFFSET+LENGTH to be a multiple of METERDENOM. }
+function rests (len, meterdenom: integer; blind: boolean): string;
+ var r, bl: string;
+ function dotted(n: integer): boolean;
+ begin dotted:=false; if n=0 then exit;
+ if n<>3*(n div 3) then exit;
+ n:=n div 3; while n mod 2 = 0 do n:=n div 2;
+ dotted := n=1;
+ end;
+ begin if blind then bl:='b' else bl:='';
+ if len=0 then rests:='' else
+ if len=128*meterdenom then rests:='r9'+bl+' ' else
+ if dotted(len) then
+ begin r:=rests(len-len div 3,meterdenom,false);
+ r[3]:='d'; rests:=r+bl+' ';
+ end
+ else if len>=64 div meterdenom then
+ rests:=rests(len-64 div meterdenom,meterdenom,blind)+'r'
+ +durations[whole+logtwo(meterdenom)]+bl+' '
+ else rests:=rests(len,meterdenom*2,blind);
+ end;
+
+procedure checkSticky(var note: string; var attrib: sticky);
+ var i,l: integer;
+ c: char;
+ a: string;
+ function attribs(note: string): string;
+ var a: string;
+ i,l: integer;
+ n: char;
+ begin a:=''; i:=2; l:=length(note);
+ while i<=l do
+ begin n:=note[i];
+ if n='x' then i:=l else if (n>='a') and (n<='z') then a:=a+n;
+ inc(i);
+ end;
+ attribs:=a;
+ end;
+begin if note='' then exit;
+ l:=length(note); i:=2;
+ while i<=l do
+ begin c:=note[i];
+ if (c>='a') and (c<='z') then
+ if (i<l) and (note[i+1]=':') then
+ begin delete1(note,i+1); dec(l); attrib[c]:=not attrib[c]; end
+ else attrib[c]:=false;
+ inc(i);
+ end;
+ a:=attribs(note);
+ for c:='z' downto 'a' do
+ if attrib[c] and (pos1(c,a)=0) then insertchar(c,note,3);
+end;
+
+{ Routine was patched by Hiroaki Morimoto, revised 2003/08/15.
+ Rewritten by DPL 2004/05/16 to be more understandable.
+ octaveCode returns octave adjustments in the order
+ [absolute or =],[relative] }
+procedure checkOctave(voice: voice_index; var note: string);
+ var code: char;
+begin
+ code:=octaveCode(note);
+ if code='=' then begin setOctave(voice); removeOctaveCode(code,note); end;
+ if octave(voice)=blank then exit;
+ code:=octaveCode(note);
+ if (code>='0') and (code<='9') then begin resetOctave(voice); exit end;
+ while (code='+') or (code='-') do
+ begin
+ newOctave(voice,code); removeOctaveCode(code,note); code:=octaveCode(note)
+ end;
+ if code<>' ' then error3(voice,'You may have only one absolute octave assignment');
+ insertOctaveCode(octave(voice),note);
+ checkRange(voice,note);
+ resetOctave(voice)
+end;
+
+procedure markDebeamed(voice: voice_index; var note: string);
+begin
+ if isVocal(voice) and (afterSlur(voice)=0) and unbeamVocal
+ and (pos1(duration(voice),flagged)>0) then insertchar('a',note,2);
+end;
+
+function barLength (meter: string): integer;
+ var n1, n2, pn1, pn2: integer;
+begin
+ getMeter(meter,n1,n2,pn1,pn2); barLength := n1*(64 div n2);
+end;
+
+function isMultiBarRest(rest: string): boolean;
+begin isMultibarRest:=false; if length(rest)<3 then exit;
+ if rest[2]<>'m' then exit;
+ if multi_bar_rest<>'' then error(
+ 'Only one multibar rest allowed per line',print);
+ multi_bar_rest := rest; isMultibarRest:=true;
+end;
+
+{ Double-length in xtuplet detected by a brute search for D anywhere.
+ Could be more elegant. }
+
+var macro_length: array[1..20] of integer;
+const macro_ID: array[1..20] of string[2]=('1','2','3','4','5','6','7','8',
+ '9','10','11','12','13','14','15','16','17','18','19','20');
+
+procedure scanMusic(voice: voice_index; var left_over: integer);
+ var buf, note, enote, xnote: string;
+ has_next, done, doublex, store_macro: boolean;
+ bar, old_length, bar_length, count, l, mlen, ngrace, nmulti,
+ macroID, playID: integer;
+ dur1, lastdur, macro_type: char;
+ nscan: music_word;
+
+ procedure decmulti;
+ begin if doublex then dec(nmulti,2) else dec(nmulti)
+ end;
+
+ procedure countIt;
+ procedure incbar(nl: integer);
+ begin inc(bar_length,nl);
+ if (bar_length>bar) and (meternum>0)
+ then error3(voice,'Bar end occurs in mid-note');
+ end;
+ begin
+ if ngrace>0 then dec(ngrace) else
+ if nmulti>0 then decmulti else
+ begin if (count mod 3<>0) and (
+ (note[1]<>rest) and note_attrib[voice,'d'] or
+ (note[1]=rest) and rest_attrib[voice,'d']) then
+ inc(count,count div 2);
+ incbar(count);
+ l := pos1(multi_group,note);
+ if l>0 then
+ begin predelete(note,l); getNum(note,nmulti); decmulti;
+ end;
+ end
+ end;
+
+ procedure maybeGroup;
+ begin if note[1]=grace_group then
+ begin if length(note)=1 then ngrace:=1
+ else ngrace := pos1(note[2],digits); (* bug if ngrace>9 *)
+ if ngrace>0 then dec(ngrace);
+ end;
+ end;
+
+ function identifyMacro(s: string): integer;
+ var k: integer;
+ begin predelete(s,2); for k:=1 to 20 do if s=macro_ID[k] then
+ begin identifyMacro:=k; exit end;
+ identifyMacro:=0
+ end;
+
+ procedure examineMacro;
+ begin if not countMacro then exit;
+ if debugMode then write(note,': '); if length(note)=1 then
+ begin
+ mlen:=bar_length-old_length;
+ if (macroID<1) or (macroID>20) then error3(voice,'Invalid macro ID');
+ macro_length[macroID]:=mlen;
+ if debugMode then
+ writeln('Ending macro ',macroID,' of type ',macro_type,', length=', mlen);
+ if macro_type='S' then bar_length:=old_length; store_macro:=false
+ end
+ else begin playID:=identifyMacro(note);
+ if (playID<1) or (playID>20) then error3(voice,'Invalid macro ID');
+ if note[2]='P' then
+ begin if debugMode then
+ writeln('Playing macro ',playID,' of length ',
+ macro_length[playID]);
+ inc(bar_length,macro_length[playID])
+ end
+ else if pos1(note[2],'SR')>0 then
+ begin old_length:=bar_length; macro_type:=note[2]; macroID:=playID;
+ store_macro:=true;
+ if debugMode then writeln('Defining macro ',macroID,' of type ',note[2])
+ end
+ end
+ end;
+
+begin
+ terminators:='d.x';
+ resetInfo(voice, buf); has_next := false; left_over:=0; store_macro:=false;
+ bar:=full_bar; bar_length:=0; ngrace:=0; nmulti:=0;
+ if meternum=0 then bar:=32000;
+ dur1:=duration(voice); lastdur:=dur1;
+ done:=false;
+ repeat GetNextMusWord(buf,note,nscan); if length(note)=0 then break; count:=0;
+{ if isNoteOrRest(note) and not (isPause(note) or isMultibarRest(note))
+ then note:=toStandard(note); }
+ doublex := (pos1('D',note)>0) or (pos1('F',note)>0);
+ if nscan=mword then
+ begin
+ if length(note)=0 then
+ Error3(voice,'You may not end a line with a meter change');
+ if bar_length>0 then
+ error3(voice,'Meter change only allowed at start of bar')
+ else bar:=barLength(note);
+ end
+ else if nscan=rword then
+ if not (isPause(note) or isMultiBarRest(note)
+ or (ngrace + nmulti > 0)) then {0.63: allow rests in xtuples}
+ begin
+ processNote(note,xnote,dur1,lastdur,count);
+ checkSticky(note,rest_attrib[voice]);
+ end;
+ if note<>'' then appendNote(voice,nscan);
+ enote := note;
+ if (nscan=macro) or (nscan=endMacro) then examineMacro;
+ if nscan=abcdefg then
+ if (multi_bar_rest='') and (ngrace + nmulti = 0) then
+ begin
+ processNote(enote,xnote,dur1,lastdur,count);
+ if xnote<>'' then
+ begin
+ checkSticky(enote,note_attrib[voice]);
+ appendToLine(voice,enote);
+ appendNote(voice,nscan); enote := xnote;
+ end;
+ checkSticky(enote,note_attrib[voice]);
+ end;
+ appendToLine(voice,enote);
+ if note='' then done:=true; { !!! else word_bound[here]:=length(line); }
+ if note=barsym then
+ if meternum=0 then
+ error3(voice,'You may not use bar lines in barless music')
+ else if bar_length=0 then markBar(voice)
+ else if (numberOfBars(voice)=0) and (bar_length<bar) then
+ begin if has_next then
+ has_next:=false {TODO Should check whether pickups are equal}
+ else if left_over>0 then error3(voice,'Bar is too short');
+ left_over:=bar_length; bar_length := 0;
+ end;
+ if nscan=nextvoice then
+ begin if bar_length>0 then error3(voice, 'Next voice before bar is full')
+ else barForward(voice,-1); has_next := true;
+ end
+ else if isPause(note) then inc(bar_length,bar)
+ else if multi_bar_rest<>'' then {do nothing}
+ else if not done and isNoteOrRest(note) then countIt
+ else maybeGroup;
+ dur1:=lastdur;
+ if (bar_length>=bar) and (ngrace+nmulti=0) and not store_macro then
+ begin if debugMode then writeln(voice,' ',bar_length);
+ barForward(voice,bar_length div bar); bar_length:=bar_length mod bar
+ end;
+ until done;
+ setExtraLength(voice,bar_length);
+ resetDuration(voice,dur1);
+ regroup(voice)
+end;
+
+procedure initMTX;
+ var i: voice_index; j: char;
+begin for i:=1 to maxvoices do for j:='a' to 'z' do
+ note_attrib[i,j] := false;
+ rest_attrib := note_attrib;
+end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/mtx.test b/Build/source/utils/m-tx/mtx-src/mtx.test
new file mode 100644
index 00000000000..9705cdd87aa
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/mtx.test
@@ -0,0 +1,16 @@
+#! /bin/sh -vx
+
+# Copyright (C) 2012 Peter Breitenlohner <tex-live@tug.org>
+# You may freely use, modify and/or distribute this file.
+
+rm -f mozart*
+
+cp $srcdir/tests/mozart.mtx .
+
+set -x
+
+./prepmx mozart \
+ && diff mozart.pmx $srcdir/tests/mozart.pmx \
+ || exit 1
+
+exit 0
diff --git a/Build/source/utils/m-tx/mtx-src/mtxline.c b/Build/source/utils/m-tx/mtx-src/mtxline.c
new file mode 100644
index 00000000000..c815d69387c
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/mtxline.c
@@ -0,0 +1,855 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "mtxline.pas" */
+
+
+#include "p2c.h"
+
+
+#define MTXLINE_G
+#include "mtxline.h"
+
+
+boolean bind_left[22] = {
+ false, false, true, false, false, true, true, false, true, true, true,
+ false, true, false, true, false, true, false, false, false, false, false
+};
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+#ifndef CONTROL_H
+#include "control.h"
+#endif
+
+#ifndef NOTES_H
+#include "notes.h"
+#endif
+
+#ifndef UTILITY_H
+#include "utility.h"
+#endif
+
+
+typedef music_word word_scan[max_words];
+
+typedef struct line_info {
+ word_index0 here, nword;
+ bar_index0 nbar;
+ paragraph_index0 voice_pos, voice_stave, mus, chord;
+ short extra;
+ boolean vocal;
+ word_index0 bar_bound[max_bars + 1];
+ short word_bound[max_words + 1], orig_word_bound[max_words + 1];
+ word_scan scan;
+} line_info;
+
+
+Static Char name[22][10] = {
+ "?", "note", "znote", "lyricsTag", "(", ")", ")(", "[", "]", "_", "PMX<",
+ "macro", "endMacro", "meter", "ornament", "rest", "//", "BAR", "TeX", "@",
+ "firstonly", "ERROR"
+};
+
+Static line_info info[maxvoices];
+
+
+/* ------------------------------------------------------------- */
+
+short beatsPerLine(void)
+{
+ short Result;
+ voice_index voice, FORLIM;
+ line_info *WITH;
+
+ FORLIM = nvoices;
+ for (voice = 1; voice <= FORLIM; voice++) {
+ WITH = &info[voice-1];
+ if (WITH->nbar > 0 || WITH->extra > 0) {
+ if (WITH->extra % one_beat > 0) {
+/* p2c: mtxline.pas, line 99:
+ * Note: Using % for possibly-negative arguments [317] */
+ error3(voice, "Line length not an integer number of beats");
+ }
+ Result = WITH->nbar * meternum + WITH->extra / one_beat;
+ }
+ }
+ return Result;
+}
+
+
+void skipChordBar(voice_index voice)
+{
+ line_info *WITH;
+ Char STR1[256];
+
+ WITH = &info[voice-1];
+ if (WITH->chord > 0) {
+ sprintf(STR1, "%c", barsym);
+ if (!strcmp(P[WITH->chord - 1], STR1))
+ predelete(P[WITH->chord - 1], 1);
+ }
+}
+
+
+Char *getBar(Char *Result, voice_index voice, short bar)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ return (substr_(Result, P[WITH->mus - 1],
+ WITH->word_bound[WITH->bar_bound[bar-1]] + 1,
+ WITH->word_bound[WITH->bar_bound[bar]] -
+ WITH->word_bound[WITH->bar_bound[bar-1]]));
+}
+
+
+Char *musicLine(Char *Result, voice_index voice)
+{
+ return strcpy(Result, P[musicLineNo(voice) - 1]);
+}
+
+
+paragraph_index0 musicLineNo(voice_index voice)
+{
+ return (info[voice-1].mus);
+}
+
+
+void setMusicLineNo(voice_index voice, paragraph_index lno)
+{
+ info[voice-1].mus = lno;
+}
+
+
+paragraph_index0 chordLineNo(voice_index voice)
+{
+ return (info[voice-1].chord);
+}
+
+
+void setChordLineNo(voice_index voice, paragraph_index lno)
+{
+ info[voice-1].chord = lno;
+}
+
+
+void setVocal(voice_index voice, boolean voc)
+{
+ info[voice-1].vocal = voc;
+}
+
+
+boolean isVocal(voice_index voice)
+{
+ return (info[voice-1].vocal);
+}
+
+
+void setStavePos(voice_index voice, stave_index stave, stave_index pos)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ WITH->voice_pos = pos;
+ WITH->voice_stave = stave;
+}
+
+
+stave_index voiceStave(voice_index voice)
+{
+ return (info[voice-1].voice_stave);
+}
+
+
+stave_index voicePos(voice_index voice)
+{
+ return (info[voice-1].voice_pos);
+}
+
+
+voice_index companion(voice_index voice)
+{
+ short s;
+
+ s = info[voice-1].voice_stave;
+ if (number_on_stave[s-1] == 1)
+ return voice;
+ else if (info[voice-1].voice_pos == 1)
+ return (voice + 1);
+ else
+ return (voice - 1);
+}
+
+
+void regroup(voice_index voice)
+{
+ word_index0 i, j;
+ word_index0 j2 = 0;
+ line_info *WITH;
+ word_index0 FORLIM;
+
+ WITH = &info[voice-1];
+ if (debugMode())
+ printf("Voice %d has %d bars at ", voice, WITH->nbar);
+ if (debugMode()) {
+ FORLIM = WITH->nbar + 1;
+ for (i = 1; i <= FORLIM; i++)
+ printf("%d ", WITH->bar_bound[i]);
+ }
+ FORLIM = WITH->nbar;
+ for (i = 1; i <= FORLIM; i++) {
+ j2 = WITH->bar_bound[i];
+ j = j2 + 1;
+ while (j <= WITH->here &&
+ (bind_left[(long)WITH->scan[j-1]] || WITH->scan[j-1] == barword)) {
+ WITH->bar_bound[i]++;
+ j++;
+ }
+ }
+ if (WITH->extra > 0)
+ WITH->bar_bound[WITH->nbar + 1] = WITH->here;
+ if (debugMode()) {
+ printf(" regrouped to ");
+ FORLIM = WITH->nbar + 1;
+ for (i = 1; i <= FORLIM; i++)
+ printf("%d ", WITH->bar_bound[i]);
+ }
+ if (debugMode())
+ putchar('\n');
+ WITH->nword = WITH->here;
+}
+
+
+void resetInfo(voice_index voice, Char *buf)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ strcpy(buf, P[WITH->mus - 1]);
+ *P[WITH->mus - 1] = '\0';
+ WITH->bar_bound[0] = 0;
+ WITH->word_bound[0] = 0;
+ WITH->orig_word_bound[0] = 0;
+ WITH->nbar = 0;
+ WITH->here = 0;
+}
+
+
+void clearLabels(void)
+{
+ voice_index voice, FORLIM;
+ line_info *WITH;
+
+ FORLIM = nvoices;
+ for (voice = 0; voice <= FORLIM - 1; voice++) {
+ WITH = &info[voice];
+ WITH->chord = 0;
+ WITH->mus = 0;
+ }
+}
+
+
+void appendNote(voice_index voice, music_word nscan)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ WITH->here++;
+ if (WITH->here > max_words)
+ error3(voice, "Words per line limit exceeded");
+ WITH->scan[WITH->here - 1] = nscan;
+}
+
+
+void appendToLine(voice_index voice, Char *note)
+{
+ line_info *WITH;
+
+ if (*note == '\0')
+ return;
+ WITH = &info[voice-1];
+ sprintf(P[WITH->mus - 1] + strlen(P[WITH->mus - 1]), "%s%c", note, blank);
+ WITH->word_bound[WITH->here] = strlen(P[WITH->mus - 1]);
+ WITH->orig_word_bound[WITH->here] = nextWordBound(orig_P[WITH->mus - 1],
+ note[0], WITH->orig_word_bound[WITH->here - 1]);
+}
+
+
+void markBar(voice_index voice)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ if (WITH->nbar == 0)
+ error3(voice, "Empty bar");
+ else
+ WITH->bar_bound[WITH->nbar] = WITH->here;
+}
+
+
+short numberOfBars(voice_index voice)
+{
+ return (info[voice-1].nbar);
+}
+
+
+void barForward(voice_index voice, short nbars)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ if (WITH->nbar + nbars < 0)
+ error3(voice, "Next voice before bar is full");
+ if (WITH->nbar + nbars > max_bars)
+ error3(voice, "Bars per line limit exceeded");
+ WITH->nbar += nbars;
+ if (nbars > 0)
+ WITH->bar_bound[WITH->nbar] = WITH->here;
+}
+
+
+void setExtraLength(voice_index voice, short ext)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ WITH->extra = ext;
+ WITH->scan[WITH->here] = other;
+}
+
+
+short ExtraLength(voice_index voice)
+{
+ return (info[voice-1].extra);
+}
+
+
+voice_index0 findVoice(Char *w_)
+{
+ voice_index0 Result = 0;
+ Char w[256];
+ short i, FORLIM;
+
+ strcpy(w, w_);
+ curtail(w, ':');
+ FORLIM = nvoices;
+ for (i = 1; i <= FORLIM; i++) {
+ if (!strcmp(w, voice_label[i-1]))
+ return i;
+ }
+ getNum(w, &i);
+ if (i == 0)
+ return Result;
+ if (i > 0 && i <= nvoices)
+ return i;
+ error("Numeric label outside range 1..nvoices", print);
+ return Result;
+}
+
+
+Static void info3(voice_index voice)
+{
+ short p;
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ printf("In voice \"%s\" near word %d:\n", voice_label[voice-1], WITH->here);
+ p = WITH->orig_word_bound[WITH->here - 1] - 1;
+ if (p < 0)
+ p = 0;
+ printf("%*cV\n", p, ' ');
+}
+
+
+void error3(voice_index voice, Char *message)
+{
+ Char STR1[256];
+
+ info3(voice);
+ sprintf(STR1, " %s", message);
+ error(STR1, print);
+}
+
+
+void warning3(voice_index voice, Char *message)
+{
+ Char STR1[256];
+
+ info3(voice);
+ sprintf(STR1, " %s", message);
+ warning(STR1, print);
+}
+
+
+Char *nextMusicWord(Char *Result, voice_index voice)
+{
+ return (MusicWord(Result, voice, info[voice-1].here));
+}
+
+
+Char *MusicWord(Char *Result, short voice, short n)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ if (n > 0 && n <= WITH->nword)
+ return (substr_(Result, P[WITH->mus - 1], WITH->word_bound[n-1] + 1,
+ WITH->word_bound[n] - WITH->word_bound[n-1] - 1));
+ else
+ return strcpy(Result, "");
+}
+
+
+music_word thisNote(voice_index voice)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ return (WITH->scan[WITH->here - 2]);
+}
+
+
+music_word nextNote(voice_index voice)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ return (WITH->scan[WITH->here - 1]);
+}
+
+
+boolean endOfBar(voice_index voice, short bar_no)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ return (WITH->here > WITH->bar_bound[bar_no]);
+}
+
+
+void gotoBar(voice_index voice, short bar_no)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ WITH->here = WITH->bar_bound[bar_no-1] + 1;
+}
+
+
+Char *getMusicWord(Char *Result, voice_index voice)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ line_no = orig_line_no[WITH->mus - 1];
+ MusicWord(Result, voice, WITH->here);
+ WITH->here++;
+ return Result;
+}
+
+
+boolean maybeMusicLine(Char *l_)
+{
+ Char l[256];
+ Char w[256];
+ music_word nscan;
+
+ strcpy(l, l_);
+ GetNextWord(w, l, blank, dummy);
+/* p2c: mtxline.pas: Note: Eliminated unused assignment statement [338] */
+ if (pos1(w[0], "abcdefgr()[]{}CMm") == 0)
+ return false;
+ if (pos1(':', w) == 0)
+ return true;
+ getNextMusWord(w, l, &nscan);
+ return (nscan == abcdefg);
+}
+
+
+#define nmacros 99
+
+
+Static boolean macro_initialized = false;
+Static Char macro_text[nmacros][256];
+
+
+Static void macroInit(void)
+{
+ short i;
+
+ if (macro_initialized)
+ return;
+ macro_initialized = true;
+ for (i = 0; i <= nmacros - 1; i++)
+ *macro_text[i] = '\0';
+}
+
+
+Static short identifyMacro(Char *s_)
+{
+ Char s[256];
+ short k;
+
+ strcpy(s, s_);
+ predelete(s, 2);
+ getNum(s, &k);
+ return k;
+}
+
+
+/* Local variables for getNextMusWord: */
+struct LOC_getNextMusWord {
+ Char *buf, *note;
+} ;
+
+Local void expandThisMacro(struct LOC_getNextMusWord *LINK)
+{
+ Char playtag[11];
+ short playID;
+ Char w[256];
+ Char STR1[72];
+ Char STR2[42];
+ Char STR3[68];
+ Char STR4[54];
+ Char STR5[256], STR7[256];
+
+ macroInit();
+ if (strlen(LINK->note) == 1)
+ error("Can't terminate a macro that has not been started", print);
+ playID = identifyMacro(LINK->note);
+ toString(playtag, playID);
+/* p2c: mtxline.pas, line 317:
+ * Note: Possible string truncation in assignment [145] */
+ if (playID < 1 || playID > 99) {
+ sprintf(STR2, "Macro ID %s is not in range 1..99", playtag);
+ error(STR2, print);
+ }
+ if (LINK->note[1] == 'P') {
+ if (*macro_text[playID-1] == '\0') {
+ sprintf(STR3,
+ "Macro %s inserts empty text: did you define it before use?",
+ playtag);
+ warning(STR3, print);
+ }
+ if (strlen(macro_text[playID-1]) + strlen(LINK->buf) <= 255) {
+ if (debugMode()) {
+ printf("Inserting macro %s text \"%s\"\n",
+ playtag, macro_text[playID-1]);
+ printf("Buffer before insert: %s\n", LINK->buf);
+ }
+ sprintf(LINK->buf, "%s%s",
+ macro_text[playID-1], strcpy(STR5, LINK->buf));
+ return;
+ }
+ sprintf(STR4, "Expansion of macro %s causes buffer overflow", playtag);
+ error(STR4, print);
+ }
+ if (pos1(LINK->note[1], "SR") == 0) {
+ sprintf(STR4, "Second character %c of macro word should be in \"PRS\"",
+ LINK->note[1]);
+ error(STR4, print);
+ }
+ *macro_text[playID-1] = '\0';
+ do {
+ GetNextWord(w, LINK->buf, blank, dummy);
+ if (*w == '\0') {
+ sprintf(STR1,
+ "Macro definition %s should be terminated on the same input line",
+ playtag);
+ error(STR1, print);
+ }
+ if (!strcmp(w, "M")) {
+ if (debugMode())
+ printf("Macro %s is: %s\n", playtag, macro_text[playID-1]);
+ break;
+ }
+ if (w[0] == 'M' && strlen(w) > 1) {
+ if (w[1] != 'P' || identifyMacro(w) == playID) {
+ sprintf(STR7, "%s not allowed inside macro definition %s", w, playtag);
+ error(STR7, print);
+ }
+ }
+ sprintf(macro_text[playID-1] + strlen(macro_text[playID-1]), "%s ", w);
+ } while (true);
+ if (LINK->note[1] == 'R') {
+ LINK->note[1] = 'P';
+ sprintf(LINK->buf, "%s %s", LINK->note, strcpy(STR7, LINK->buf));
+ }
+}
+
+
+void getNextMusWord(Char *buf_, Char *note_, music_word *nscan)
+{
+ struct LOC_getNextMusWord V;
+ Char maybe_error[256];
+ Char STR2[256];
+
+ V.buf = buf_;
+ V.note = note_;
+ GetNextWord(V.note, V.buf, blank, dummy);
+ if (*V.note == '\0')
+ return;
+ if (V.note[0] == 'M' && expandMacro()) {
+ expandThisMacro(&V);
+ getNextMusWord(V.buf, V.note, nscan);
+ return;
+ }
+ if (V.note[0] == '\\') {
+ *maybe_error = '\0';
+ if (V.note[strlen(V.note) - 1] != '\\')
+ strcpy(maybe_error, V.note);
+ while (*V.buf != '\0' && V.note[strlen(V.note) - 1] != '\\')
+ sprintf(V.note + strlen(V.note), " %s",
+ GetNextWord(STR2, V.buf, blank, dummy));
+ if (V.note[strlen(V.note) - 1] != '\\')
+ error("Unterminated TeX literal", print);
+ *nscan = texword;
+ if (*maybe_error != '\0') {
+ sprintf(STR2, "Possible unterminated TeX literal: %s", maybe_error);
+ warning(STR2, print);
+ }
+ return;
+ }
+ if (solfaNoteNames()) {
+ translateSolfa(V.note);
+ if (V.note[0] == '"')
+ predelete(V.note, 1);
+ }
+ switch (V.note[0]) {
+
+ case '_':
+ *nscan = pmxprefix;
+ delete1(V.note, 1);
+ break;
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ *nscan = abcdefg;
+ break;
+
+ case 'z':
+ *nscan = zword;
+ break;
+
+ case '(':
+ *nscan = lparen;
+ break;
+
+ case '{':
+ if (V.note[strlen(V.note) - 1] == '}')
+ *nscan = lyrtag;
+ else
+ *nscan = lparen;
+ break;
+
+ case ')':
+ if (pos1('(', V.note) == 0)
+ *nscan = rparen;
+ else
+ *nscan = rlparen;
+ break;
+
+ case '}':
+ if (pos1('{', V.note) == 0)
+ *nscan = rparen;
+ else
+ *nscan = rlparen;
+ break;
+
+ case '[':
+ *nscan = lbrac;
+ break;
+
+ case ']':
+ if (!strcmp(V.note, "]["))
+ *nscan = other;
+ else
+ *nscan = rbrac;
+ break;
+
+ case '@':
+ *nscan = atword;
+ break;
+
+ case 'm':
+ *nscan = mword;
+ break;
+
+ case 'r':
+ *nscan = rword;
+ break;
+
+ case '#':
+ case '-':
+ case 'n':
+ case 'x':
+ case '?':
+ case 's':
+ case 't':
+ case 'D':
+ *nscan = pmxl;
+ break;
+
+ case 'M':
+ if (!strcmp(V.note, "M"))
+ *nscan = endmacro;
+ else
+ *nscan = macro;
+ break;
+
+ case 'G':
+ if (pos1('A', V.note) > 0)
+ *nscan = pmxl;
+ else
+ *nscan = other;
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (pos1('/', V.note) > 0)
+ *nscan = mword;
+ else
+ *nscan = pmxl;
+ break;
+
+ case 'o':
+ *nscan = oword;
+ break;
+
+ case 'A':
+ case 'V':
+ *nscan = FirstOnly;
+ break;
+
+ case '/':
+ if (!strcmp(V.note, "//"))
+ *nscan = nextvoice;
+ else if (!strcmp(V.note, "/")) {
+ strcpy(V.note, "//");
+ warning("/ changed to //", print);
+ *nscan = nextvoice;
+ } else {
+ error("Word starts with /: do you mean \\?", print);
+ *nscan = err;
+ }
+ break;
+
+ default:
+ if (pos1('|', V.note) > 0)
+ *nscan = barword;
+ else
+ *nscan = other;
+ break;
+ }
+}
+
+
+boolean upper(voice_index voice)
+{
+ line_info *WITH;
+
+ WITH = &info[voice-1];
+ if (WITH->voice_pos == 1 && voice < nvoices)
+ return (WITH->voice_stave == info[voice].voice_stave);
+ else
+ return false;
+}
+
+
+void describeVoice(voice_index voice, Char *describe_lyr)
+{
+ short bar, w;
+ line_info *WITH;
+ Char STR1[256];
+ line_info *WITH1;
+ short FORLIM;
+
+ WITH = &info[voice-1];
+ printf("Voice `%s' is on line %d", voice_label[voice-1], WITH->mus);
+ if (WITH->vocal) {
+ printf(", is vocal");
+ puts(describe_lyr);
+ } else {
+ if (WITH->chord > 0)
+ printf(" and has chords on line %d", WITH->chord);
+ putchar('\n');
+ }
+ if (!debugMode())
+ return;
+ WITH1 = &info[voice-1];
+ printf("Line has %d bars", WITH1->nbar);
+ if (WITH1->extra > 0)
+ printf(" + %d/64 notes\n", WITH1->extra);
+ else
+ putchar('\n');
+ printf("Bars:");
+ FORLIM = WITH1->nbar;
+ for (bar = 1; bar <= FORLIM; bar++)
+ printf(" %s ", getBar(STR1, voice, bar));
+ printf("\nWord types:");
+ FORLIM = WITH1->nword;
+ for (w = 0; w <= FORLIM - 1; w++)
+ printf(" %s", name[(long)WITH1->scan[w]]);
+ putchar('\n');
+}
+
+
+boolean aloneOnStave(stave_index stave)
+{
+ voice_index v;
+
+ if (number_on_stave[stave-1] != 2)
+ return true;
+ else {
+ v = first_on_stave[stave-1];
+ return (info[v-1].mus == 0 || info[v].mus == 0);
+ }
+}
+
+
+void selectVoices(Char *line_)
+{
+ Char line[256];
+ short i = 0;
+ short k;
+ Char word[256];
+ short FORLIM;
+
+ strcpy(line, line_);
+ FORLIM = nvoices;
+ for (k = 0; k <= FORLIM - 1; k++)
+ selected[k] = false;
+ printf("Voice change to: %s = ", line);
+ while (i < nvoices) {
+ GetNextWord(word, line, blank, dummy);
+ if (*word == '\0') {
+ putchar('\n');
+ return;
+ }
+ i++;
+ printf("%s ", word);
+ k = findVoice(word);
+ if (k == 0)
+ error("This voice is not in the style", print);
+ selected[k-1] = true;
+ }
+ putchar('\n');
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/mtxline.h b/Build/source/utils/m-tx/mtx-src/mtxline.h
new file mode 100644
index 00000000000..23fc05be32c
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/mtxline.h
@@ -0,0 +1,83 @@
+/* Header for module mtxline, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef MTXLINE_H
+#define MTXLINE_H
+
+
+/* Break input up into words, classify them. Supply words and
+ information about them. */
+
+#ifndef GLOBALS_H
+#include "globals.h"
+#endif
+
+
+#ifdef MTXLINE_G
+# define vextern
+#else
+# define vextern extern
+#endif
+
+
+typedef enum {
+ other, abcdefg, zword, lyrtag, lparen, rparen, rlparen, lbrac, rbrac,
+ pmxprefix, pmxl, macro, endmacro, mword, oword, rword, nextvoice, barword,
+ texword, atword, FirstOnly, err
+} music_word;
+
+
+extern boolean bind_left[22];
+
+/* changed bind_left[barword] to false */
+
+vextern boolean selected[maxvoices];
+
+
+extern void error3(voice_index voice, Char *message);
+extern void warning3(voice_index voice, Char *message);
+extern void getNextMusWord(Char *buf, Char *note, music_word *nscan);
+extern Char *MusicWord(Char *Result, short voice, short n);
+extern Char *nextMusicWord(Char *Result, voice_index voice);
+extern music_word thisNote(voice_index voice);
+extern music_word nextNote(voice_index voice);
+extern Char *getMusicWord(Char *Result, voice_index voice);
+extern void gotoBar(voice_index voice, short bar_no);
+extern boolean endOfBar(voice_index voice, short bar_no);
+extern Char *getBar(Char *Result, voice_index voice, short bar);
+extern boolean upper(voice_index voice);
+extern void clearLabels(void);
+extern voice_index0 findVoice(Char *w);
+extern void selectVoices(Char *line);
+extern void resetInfo(voice_index voice, Char *buf);
+extern void setVocal(voice_index voice, boolean voc);
+extern boolean isVocal(voice_index voice);
+extern void setStavePos(voice_index voice, stave_index stave, stave_index pos);
+extern stave_index voiceStave(voice_index voice);
+extern stave_index voicePos(voice_index voice);
+extern boolean aloneOnStave(stave_index stave);
+extern voice_index companion(voice_index voice);
+extern void appendNote(voice_index voice, music_word nscan);
+extern void appendToLine(voice_index voice, Char *note);
+extern void markBar(voice_index voice);
+extern short numberOfBars(voice_index voice);
+extern void barForward(voice_index voice, short nbars);
+extern void regroup(voice_index voice);
+
+extern short beatsPerLine(void);
+extern void setExtraLength(voice_index voice, short ext);
+extern short ExtraLength(voice_index voice);
+extern paragraph_index0 musicLineNo(voice_index voice);
+extern void setMusicLineNo(voice_index voice, paragraph_index lno);
+extern paragraph_index0 chordLineNo(voice_index voice);
+extern void setChordLineNo(voice_index voice, paragraph_index lno);
+extern void skipChordBar(voice_index voice);
+
+extern void describeVoice(voice_index voice, Char *describe_lyr);
+extern boolean maybeMusicLine(Char *l);
+extern Char *musicLine(Char *Result, voice_index voice);
+
+
+#undef vextern
+
+#endif /*MTXLINE_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/mtxline.pas b/Build/source/utils/m-tx/mtx-src/mtxline.pas
new file mode 100644
index 00000000000..9f567da5e2b
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/mtxline.pas
@@ -0,0 +1,457 @@
+unit mtxline;
+{ Break input up into words, classify them. Supply words and
+ information about them. }
+
+interface uses globals;
+
+type
+ music_word = (other, abcdefg, zword, lyrtag,
+ lparen, rparen, rlparen, lbrac, rbrac,
+ pmxprefix, pmxl, macro, endmacro, mword, oword, rword, nextvoice,
+ barword, texword, atword, FirstOnly, err );
+
+const
+ bind_left: array[music_word] of boolean = (
+ false, false, true, false,
+ false, true, true, false, true,
+ true, true, false, true, false, true, false, true,
+ false, false, false, false, false );
+{ changed bind_left[barword] to false }
+
+var selected: array[voice_index] of boolean;
+
+procedure error3(voice: voice_index; message: string );
+procedure warning3(voice: voice_index; message: string );
+procedure getNextMusWord (var buf, note: string; var nscan: music_word);
+function MusicWord(voice, n: integer): string;
+function nextMusicWord(voice: voice_index): string;
+function thisNote(voice: voice_index): music_word;
+function nextNote(voice: voice_index): music_word;
+function getMusicWord(voice: voice_index): string;
+procedure gotoBar(voice: voice_index; bar_no: integer);
+function endOfBar(voice: voice_index; bar_no: integer): boolean;
+function getBar(voice:voice_index; bar: integer): string;
+function upper(voice: voice_index): boolean;
+procedure clearLabels;
+function findVoice(w: string): voice_index0;
+procedure selectVoices(line: string);
+procedure resetInfo(voice: voice_index; var buf: string);
+procedure setVocal(voice: voice_index; voc: boolean);
+function isVocal(voice: voice_index): boolean;
+procedure setStavePos(voice: voice_index; stave, pos: stave_index);
+function voiceStave(voice: voice_index): stave_index;
+function voicePos(voice: voice_index): stave_index;
+function aloneOnStave(stave: stave_index): boolean;
+function companion(voice: voice_index): voice_index;
+procedure appendNote(voice: voice_index; nscan: music_word);
+procedure appendToLine(voice: voice_index; note: string);
+procedure markBar(voice: voice_index);
+function numberOfBars(voice: voice_index): integer;
+procedure barForward(voice: voice_index; nbars: integer);
+procedure regroup(voice: voice_index);
+
+function beatsPerLine: integer;
+procedure setExtraLength(voice: voice_index; ext: integer);
+function ExtraLength(voice: voice_index): integer;
+function musicLineNo(voice: voice_index): paragraph_index0;
+procedure setMusicLineNo(voice: voice_index; lno: paragraph_index);
+function chordLineNo(voice: voice_index): paragraph_index0;
+procedure setChordLineNo(voice: voice_index; lno: paragraph_index);
+procedure skipChordBar(voice: voice_index);
+
+procedure describeVoice(voice: voice_index; describe_lyr: string);
+function maybeMusicLine(l: string): boolean;
+function musicLine(voice: voice_index): string;
+
+implementation uses strings, notes, control, utility;
+
+const
+
+ name: array[music_word] of string[9] = (
+ '?', 'note', 'znote', 'lyricsTag',
+ '(', ')', ')(', '[', ']',
+ '_','PMX<', 'macro', 'endMacro', 'meter', 'ornament', 'rest', '//',
+ 'BAR', 'TeX', '@', 'firstonly', 'ERROR');
+
+type
+ word_scan = array[1..max_words] of music_word;
+
+ line_info = record
+ here, nword: word_index0;
+ nbar: bar_index0;
+ voice_pos, voice_stave, mus, chord: paragraph_index0;
+ extra: integer;
+ vocal: boolean;
+ bar_bound: array[bar_index0] of word_index0;
+ word_bound, orig_word_bound: array[word_index0] of integer;
+ scan: word_scan;
+ end;
+
+var info: array[voice_index] of line_info;
+
+{ ------------------------------------------------------------- }
+
+function beatsPerLine: integer;
+ var voice: voice_index;
+begin for voice:=1 to nvoices do with info[voice] do
+ if (nbar>0) or (extra>0) then
+ begin
+ if extra mod one_beat > 0
+ then error3(voice,'Line length not an integer number of beats');
+ beatsPerLine := nbar*meternum + extra div one_beat;
+ end;
+end;
+
+procedure skipChordBar(voice: voice_index);
+begin with info[voice] do
+ if chord>0 then if P[chord]=barsym then predelete(P[chord],1);
+end;
+
+function getBar(voice: voice_index; bar: integer): string;
+begin with info[voice] do
+ getBar := substr(P[mus],word_bound[bar_bound[bar-1]]+1,
+ word_bound[bar_bound[bar]]-word_bound[bar_bound[bar-1]]);
+end;
+
+function musicLine(voice: voice_index): string;
+begin musicLine:=P[musicLineNo(voice)]; end;
+
+function musicLineNo(voice: voice_index): paragraph_index0;
+begin musicLineNo := info[voice].mus; end;
+
+procedure setMusicLineNo(voice: voice_index; lno: paragraph_index);
+begin info[voice].mus := lno; end;
+
+function chordLineNo(voice: voice_index): paragraph_index0;
+begin chordLineNo := info[voice].chord; end;
+
+procedure setChordLineNo(voice: voice_index; lno: paragraph_index);
+begin info[voice].chord := lno; end;
+
+procedure setVocal(voice: voice_index; voc: boolean);
+begin info[voice].vocal:=voc; end;
+
+function isVocal(voice: voice_index): boolean;
+begin isVocal := info[voice].vocal; end;
+
+procedure setStavePos(voice: voice_index; stave, pos: stave_index);
+begin with info[voice] do begin voice_pos:=pos; voice_stave:=stave; end;
+end;
+
+function voiceStave(voice: voice_index): stave_index;
+begin voiceStave:=info[voice].voice_stave; end;
+
+function voicePos(voice: voice_index): stave_index;
+begin voicePos:=info[voice].voice_pos; end;
+
+function companion(voice: voice_index): voice_index;
+ var s: integer;
+begin s:=info[voice].voice_stave;
+ if number_on_stave[s]=1 then companion:=voice
+ else if info[voice].voice_pos=1 then companion:=voice+1
+ else companion:=voice-1;
+end;
+
+procedure regroup(voice: voice_index);
+ var i, j, j2: word_index0;
+begin j2 := 0; with info[voice] do
+ begin if debugMode then write('Voice ',voice,' has ',nbar,' bars at ');
+ if debugMode then for i:=1 to nbar+1 do write(bar_bound[i],' ');
+ for i:=1 to nbar do
+ begin j2:=bar_bound[i]; j:=j2+1;
+ while (j<=here) and (bind_left[scan[j]] or (scan[j]=barword)) do
+ begin inc(bar_bound[i]); inc(j) end;
+ end;
+ if extra>0 then bar_bound[nbar+1]:=here;
+ if debugMode then
+ begin write(' regrouped to ');
+ for i:=1 to nbar+1 do write(bar_bound[i],' ')
+ end;
+ if debugMode then writeln;
+ nword := here
+ end;
+end;
+
+procedure resetInfo(voice: voice_index; var buf: string);
+begin with info[voice] do
+ begin buf := P[mus]; P[mus]:='';
+ bar_bound[0]:=0; word_bound[0]:=0; orig_word_bound[0]:=0;
+ nbar:=0; here := 0;
+ end;
+end;
+
+procedure clearLabels;
+ var voice: voice_index;
+begin for voice:=1 to nvoices do with info[voice] do
+ begin chord:=0; mus:=0; end;
+end;
+
+procedure appendNote(voice: voice_index; nscan: music_word);
+begin with info[voice] do
+ begin inc(here); if here>max_words then
+ error3(voice,'Words per line limit exceeded');
+ scan[here]:=nscan; end;
+end;
+
+procedure appendToLine(voice: voice_index; note: string);
+begin if note<>'' then with info[voice] do
+ begin P[mus]:=P[mus]+note+blank; word_bound[here]:=length(P[mus]);
+ orig_word_bound[here]:=nextWordBound(orig_P[mus],note[1],
+ orig_word_bound[here-1]);
+ end;
+end;
+
+procedure markBar(voice: voice_index);
+begin with info[voice] do
+ if nbar=0 then error3(voice,'Empty bar') else bar_bound[nbar]:=here
+end;
+
+function numberOfBars(voice: voice_index): integer;
+begin numberOfBars := info[voice].nbar; end;
+
+procedure barForward(voice: voice_index; nbars: integer);
+begin with info[voice] do
+ begin
+ if (nbar+nbars<0) then error3(voice, 'Next voice before bar is full');
+ if nbar+nbars>max_bars then error3(voice,'Bars per line limit exceeded');
+ inc(nbar,nbars);
+ if nbars>0 then bar_bound[nbar]:=here;
+ end;
+end;
+
+procedure setExtraLength(voice: voice_index; ext: integer);
+begin with info[voice] do begin extra:=ext; scan[here+1]:=other; end;
+end;
+
+function ExtraLength(voice: voice_index): integer;
+begin ExtraLength := info[voice].extra; end;
+
+function findVoice(w: string): voice_index0;
+ var i: integer;
+begin curtail(w,':'); findVoice:=0;
+ for i:=1 to nvoices do
+ if w=voice_label[i] then begin findVoice:=i; exit end;
+ getNum(w,i); if i=0 then exit;
+ if (i>0) and (i<=nvoices) then findVoice:=i
+ else error('Numeric label outside range 1..nvoices',print);
+end;
+
+procedure info3(voice: voice_index);
+ var p: integer;
+begin with info[voice] do
+ begin
+ writeln ('In voice "', voice_label[voice], '" near word ', here, ':');
+ p:=orig_word_bound[here-1]-1;
+ if p<0 then p:=0;
+ writeln(' ':p,'V')
+ end
+end;
+
+procedure error3(voice: voice_index; message: string );
+begin info3(voice); error(' '+message,print) end;
+
+procedure warning3(voice: voice_index; message: string );
+begin info3(voice); warning(' '+message,print) end;
+
+function nextMusicWord(voice: voice_index): string;
+begin nextMusicWord := MusicWord(voice,info[voice].here); end;
+
+function MusicWord(voice, n: integer): string;
+ begin with info[voice] do if (n>0) and (n<=nword) then
+ MusicWord := substr(P[mus],word_bound[n-1]+1,
+ word_bound[n]-word_bound[n-1]-1)
+ else MusicWord := '';
+ end;
+
+function thisNote(voice: voice_index): music_word;
+begin with info[voice] do thisNote := scan[here-1]; end;
+
+function nextNote(voice: voice_index): music_word;
+begin with info[voice] do nextNote := scan[here]; end;
+
+function endOfBar(voice: voice_index; bar_no: integer): boolean;
+begin with info[voice] do endOfBar := here > bar_bound[bar_no]; end;
+
+procedure gotoBar(voice: voice_index; bar_no: integer);
+begin with info[voice] do here := bar_bound[bar_no-1]+1; end;
+
+function getMusicWord(voice: voice_index): string;
+begin with info[voice] do
+ begin line_no := orig_line_no[mus];
+ GetMusicWord := MusicWord(voice,here); inc(here);
+ end
+end;
+
+function maybeMusicLine(l: string): boolean;
+ var w: string;
+ nscan: music_word;
+begin w:=GetNextWord(l,blank,dummy); maybeMusicLine := false;
+ if pos1(w[1],'abcdefgr()[]{}CMm')=0 then begin maybeMusicLine := false; exit end;
+ if pos1(':',w)=0 then begin maybeMusicLine := true; exit end;
+ GetNextMusWord(w,l,nscan); maybeMusicLine := nscan=abcdefg;
+end;
+
+const macro_initialized: boolean=false;
+ nmacros = 99;
+var macro_text: array[1..nmacros] of string;
+procedure macroInit;
+ var i: integer;
+begin if macro_initialized then exit else macro_initialized:=true;
+ for i:=1 to nmacros do macro_text[i]:=''
+end;
+
+function identifyMacro(s: string): integer;
+ var k: integer;
+begin predelete(s,2); getNum(s,k); identifyMacro:=k
+end;
+
+procedure GetNextMusWord (var buf, note: string; var nscan: music_word);
+ var maybe_error: string;
+
+ procedure expandThisMacro;
+ var playtag: string[10];
+ playID: integer;
+ w: string;
+ begin macroInit; if length(note)=1 then
+ error('Can''t terminate a macro that has not been started',print);
+ playID:=identifyMacro(note); playtag:=toString(playID);
+ if (playID<1) or (playID>99) then
+ error('Macro ID '+playtag+' is not in range 1..99',print);
+ if note[2]='P' then
+ begin if macro_text[playID]='' then
+ warning('Macro '+playtag+
+ ' inserts empty text: did you define it before use?',print);
+ if length(macro_text[playID])+length(buf)>255
+ then error('Expansion of macro '+playtag+' causes buffer overflow',print)
+ else begin if debugMode then
+ begin writeln('Inserting macro '+playtag+' text "'
+ +macro_text[playID]+'"');
+ writeln('Buffer before insert: ',buf)
+ end;
+ buf:=macro_text[playID]+buf; exit
+ end
+ end;
+ if pos1(note[2],'SR')=0 then error('Second character '+note[2]+
+ ' of macro word should be in "PRS"',print);
+ macro_text[playID]:='';
+ repeat w:=getNextWord(buf,blank,dummy);
+ if w='' then error('Macro definition '+playtag+
+ ' should be terminated on the same input line',print);
+ if w='M' then begin
+ if debugMode then writeln('Macro '+playtag+' is: '+macro_text[playID]);
+ break
+ end;
+ if (w[1]='M') and (length(w)>1) then
+ if (w[2]<>'P') or (identifyMacro(w)=playID) then
+ error(w+' not allowed inside macro definition '+playtag,print);
+ macro_text[playID]:=macro_text[playID]+w+' '
+ until false;
+ if note[2]='R' then begin note[2]:='P'; buf:=note+' '+buf end
+ end;
+
+ begin note:=GetNextWord(buf,blank,dummy);
+ if note='' then exit;
+ if (note[1]='M') and expandMacro then
+ begin expandThisMacro; GetNextMusWord(buf,note,nscan); exit end;
+ if note[1]='\' then
+ begin maybe_error:='';
+ if note[length(note)]<>'\' then maybe_error:=note;
+ while (buf<>'') and (note[length(note)]<>'\') do
+ note:=note+' '+GetNextWord(buf,blank,dummy);
+ if note[length(note)]<>'\' then
+ error('Unterminated TeX literal',print);
+ nscan:=texword;
+ if maybe_error<>'' then
+ warning('Possible unterminated TeX literal: '+maybe_error,print);
+ exit;
+ end;
+ if solfaNoteNames then
+ begin translateSolfa(note[1]); if note[1]='"' then predelete(note,1);
+ end;
+ case note[1] of
+'_': begin nscan:=pmxprefix;delete1(note,1); end;
+'a'..'g': nscan:=abcdefg;
+'z': nscan:=zword;
+'(': nscan:=lparen;
+'{': if note[length(note)]='}' then nscan:=lyrtag else nscan:=lparen;
+')': if pos1('(',note)=0 then nscan:=rparen else nscan:=rlparen;
+'}': if pos1('{',note)=0 then nscan:=rparen else nscan:=rlparen;
+'[': nscan:=lbrac;
+']': if note='][' then nscan:=other else nscan:=rbrac;
+'@': nscan:=atword;
+'m': nscan:=mword;
+'r': nscan:=rword;
+'#','-','n','x','?','s','t','D': nscan:=pmxl;
+'M': if note='M' then nscan:=endMacro else nscan:=macro;
+'G': if pos1('A',note)>0 then nscan:=pmxl else nscan:=other;
+'1'..'9': if pos1('/',note)>0 then nscan:=mword else nscan:=pmxl;
+'o': nscan:=oword;
+'A', 'V': nscan:=FirstOnly;
+'/': if note='//' then nscan:=nextvoice
+ else if note='/' then
+ begin note:='//'; warning('/ changed to //',print); nscan:=nextvoice;
+ end
+ else begin error('Word starts with /: do you mean \?',print);
+ nscan:=err;
+ end;
+ else if pos1('|',note)>0 then nscan:=barword else
+ nscan:=other;
+ end;
+ end;
+
+function upper(voice: voice_index): boolean;
+begin with info[voice] do
+ if (voice_pos=1) and (voice<nvoices) then
+ upper:=(voice_stave=info[voice+1].voice_stave)
+ else upper:=false;
+end;
+
+procedure describeVoice(voice: voice_index; describe_lyr: string);
+ var bar, w: integer;
+begin with info[voice] do
+ begin write('Voice `',voice_label[voice],''' is on line ',mus);
+ if vocal then
+ begin write(', is vocal'); writeln(describe_lyr); end
+ else
+ begin if chord>0 then write(' and has chords on line ',chord);
+ writeln;
+ end;
+ if debugMode then with info[voice] do
+ begin write('Line has ', nbar, ' bars');
+ if extra>0 then writeln(' + ', extra, '/64 notes') else writeln;
+ write('Bars:');
+ for bar:=1 to nbar do write(' ',getBar(voice,bar),' ');
+ writeln; write('Word types:');
+ for w:=1 to nword do write(' ',name[scan[w]]); writeln;
+ end;
+ end;
+end;
+
+function aloneOnStave(stave: stave_index): boolean;
+ var v: voice_index;
+begin
+ if number_on_stave[stave]<>2 then aloneOnStave:=true else
+ begin v:=first_on_stave[stave];
+ aloneOnStave:= (info[v].mus=0) or (info[v+1].mus=0)
+ end
+end;
+
+procedure selectVoices(line: string);
+ var i, k: integer;
+ word: string;
+ begin
+ for k:=1 to nvoices do selected[k]:=false;
+ write('Voice change to: ',line,' = ');
+ i:=0;
+ while i<nvoices do
+ begin word:=GetNextWord(line,blank,dummy);
+ if word='' then begin writeln; exit; end;
+ inc(i); write(word,' ');
+ k:=findVoice(word);
+ if k=0 then error('This voice is not in the style',print);
+ selected[k]:=true;
+ end;
+ writeln;
+ end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/multfile.c b/Build/source/utils/m-tx/mtx-src/multfile.c
new file mode 100644
index 00000000000..31b9c204f8a
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/multfile.c
@@ -0,0 +1,235 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "multfile.pas" */
+
+
+#include "p2c.h"
+
+
+#define MULTFILE_G
+#include "multfile.h"
+
+
+Char nextData[256] = "";
+
+
+typedef struct filenode {
+ Char name[256];
+ FILE *actualfile;
+ struct filenode *prev;
+ short lineno;
+ Char actualfile_NAME[_FNSIZE];
+} filenode;
+
+
+Static filenode *current = NULL;
+Static short last_valid_line_no = 0;
+Static boolean inputerror = false;
+Static short reportitem = reportnewfile + reportoldfile + reporterror +
+ reportrecursive;
+
+
+void report(short items)
+{
+ reportitem = items;
+}
+
+
+Static boolean recursive(Char *filename)
+{
+ boolean Result;
+ filenode *previous;
+
+ if (current == NULL)
+ return false;
+ previous = current;
+/* p2c: multfile.pas: Note: Eliminated unused assignment statement [338] */
+ while (previous != NULL) {
+ if (!strcmp(filename, previous->name))
+ return true;
+ previous = previous->prev;
+ }
+ return false;
+}
+
+
+void pushFile(Char *filename)
+{
+ filenode *newnode;
+ Char STR3[256];
+
+ if (recursive(filename)) {
+ printf("===! Ignoring recursive include of file %s\n", filename);
+ return;
+ }
+ newnode = Malloc(sizeof(filenode));
+ newnode->actualfile = NULL;
+ strcpy(newnode->name, filename);
+ newnode->prev = current;
+ newnode->lineno = 0;
+ strcpy(newnode->actualfile_NAME, filename);
+ if (newnode->actualfile != NULL)
+ newnode->actualfile = freopen(newnode->actualfile_NAME, "r",
+ newnode->actualfile);
+ else
+ newnode->actualfile = fopen(newnode->actualfile_NAME, "r");
+ _SETIO(newnode->actualfile != NULL, FileNotFound);
+ inputerror = (P_ioresult != 0);
+ if (inputerror)
+ Free(newnode);
+ else
+ current = newnode;
+ if (!inputerror && (reportitem & reportnewfile) > 0)
+ printf("==>> Input from file %s\n", currentFilename(STR3));
+ if (inputerror && (reportitem & reporterror) > 0)
+ printf("==!! Could not open file %s\n", filename);
+}
+
+
+void popFile(void)
+{
+ filenode *previous;
+ Char STR2[256];
+ Char STR3[256];
+
+ if (current == NULL)
+ return;
+ if ((reportitem & reportclose) > 0)
+ printf("==>> Closing file %s at line number %d\n",
+ currentFilename(STR2), currentLineNo());
+ if (current->actualfile != NULL)
+ fclose(current->actualfile);
+ current->actualfile = NULL;
+ previous = current->prev;
+ Free(current);
+ current = previous;
+ if (current != NULL && (reportitem & reportoldfile) > 0)
+ printf("==>> Resuming input from file %s at line number %d\n",
+ currentFilename(STR3), currentLineNo());
+}
+
+
+void closeAll(void)
+{
+ do {
+ popFile();
+ } while (current != NULL);
+}
+
+
+boolean eofCurrent(void)
+{
+ return P_eof(current->actualfile);
+}
+
+
+Char *readLine(Char *Result)
+{
+ Char s[256];
+ Char *TEMP;
+ Char STR2[256];
+
+ if (*nextData != '\0') {
+ strcpy(Result, nextData);
+ *nextData = '\0';
+ return Result;
+ }
+ if (eofAll())
+ return strcpy(Result, "");
+ _SETIO(fgets(s, 256, current->actualfile) != NULL, EndOfFile);
+ TEMP = strchr(s, '\n');
+ if (TEMP != NULL)
+ *TEMP = 0;
+ strcpy(Result, s);
+ inputerror = (P_ioresult != 0);
+ if (!inputerror) {
+ current->lineno++;
+ last_valid_line_no = current->lineno;
+ }
+ if (inputerror && (reportitem & reporterror) > 0)
+ printf("==!! Could not read from file %s\n", currentFilename(STR2));
+ return Result;
+}
+
+
+boolean isEmpty(Char *s)
+{
+ short i, FORLIM;
+
+ if (*s == '\0')
+ return true;
+ FORLIM = strlen(s);
+ for (i = 0; i <= FORLIM - 1; i++) {
+ if (s[i] != ' ')
+ return false;
+ }
+ return true;
+}
+
+
+Char *readData(Char *Result)
+{
+ Char s[256];
+
+ if (!isEmpty(nextData)) {
+ strcpy(Result, nextData);
+ *nextData = '\0';
+ return Result;
+ }
+ while (!eofAll()) {
+ readLine(s);
+ if (!isEmpty(s))
+ return strcpy(Result, s);
+ }
+ return strcpy(Result, "");
+}
+
+
+void skipBlanks(void)
+{
+ while (*nextData == '\0') {
+ readData(nextData);
+ if (eofAll())
+ return;
+ }
+}
+
+
+boolean eofAll(void)
+{
+ boolean Result;
+
+/* p2c: multfile.pas: Note: Eliminated unused assignment statement [338] */
+ if (current == NULL)
+ return true;
+ if (eofCurrent()) {
+ popFile();
+ return (eofAll());
+ }
+ return false;
+}
+
+
+short currentLineNo(void)
+{
+ return last_valid_line_no;
+}
+
+
+Char *currentFilename(Char *Result)
+{
+ if (current == NULL)
+ return strcpy(Result, "No file open yet");
+ else
+ return strcpy(Result, current->name);
+}
+
+
+boolean fileError(void)
+{
+ return inputerror;
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/multfile.h b/Build/source/utils/m-tx/mtx-src/multfile.h
new file mode 100644
index 00000000000..01c8a06e0b7
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/multfile.h
@@ -0,0 +1,87 @@
+/* Header for module multfile, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef MULTFILE_H
+#define MULTFILE_H
+
+
+#ifdef MULTFILE_G
+# define vextern
+#else
+# define vextern extern
+#endif
+/* DPL 2004-03-06, 2015-01-16
+(* Support for including files into an input stream.
+(* Intended for an application that does not require Pascal formatting,
+(* but reads complete lines one at a time.
+(* You never actually work with any files, except by supplying the
+( filename when the file is opened.
+(* At any stage, you can switch the input to a new file.
+(* When the new file is at EOF, and a "read" is issued, the file is
+(* closed and the previous one resumed transparently. This inclusion
+(* can be nested to any level, memory permitting.
+(* --- Normal mode of operation, replacing the usual Pascal style ---
+ Instead of: assign(textfile,filename); reset(textfile)
+ use: pushFile(filename)
+ When another file should be included before the current file is done,
+ use: pushFile(newfilename)
+ Instead of: readln(textfile,line)
+ use: line:=readLine
+ Instead of: eof(textfilen)
+ or: eofAll; {Are all files at EOF?}
+(* --- Abnormal mode of operation ---
+ To abort a file before EOF is reached:
+ use: popFile;
+ To abort all files:
+ use: closeAll;
+ To test whether only the current file is at EOF:
+ use: eofCurrent;
+(* Additional features:
+ fileError: boolean function, was there an error during file open or read?
+ currentFilename: string function, name of current file
+ currentLineNo: integer function, number of line just read from current file
+ isEmpty(var s: string): boolean function, is s empty?
+ readData: string function, like readLine, but continue reading until
+ a non-blank line is found, return blank only at EOF
+ skipBlanks: skip blank lines in input: next call to readLine will be
+ non-blank unless EOF is encountered
+ report(items): procedure to control which messages are printed,
+ "items" is the sum of the following options
+ (constants with the appropriate values are defined in the interface)
+ 1: reportnewfile - file is opened
+ 2: reportoldfile - file is resumed
+ 4: reportclose - file is closed
+ 8: reporterror - a file error is encountered
+ 16: reportrecursive - there is a recursive include
+ The default value is items=27 (all the above except reportclose)
+ At present you cannot turn reportrecursive off.
+ */
+
+extern void pushFile(Char *filename);
+extern void popFile(void);
+extern void closeAll(void);
+extern void report(short items);
+extern Char *currentFilename(Char *Result);
+extern boolean eofAll(void);
+extern boolean eofCurrent(void);
+extern boolean fileError(void);
+extern Char *readLine(Char *Result);
+extern Char *readData(Char *Result);
+extern boolean isEmpty(Char *s);
+extern short currentLineNo(void);
+extern void skipBlanks(void);
+
+
+#define reportnewfile 1
+#define reportoldfile 2
+#define reportclose 4
+#define reporterror 8
+#define reportrecursive 16
+
+
+extern Char nextData[256];
+
+
+#undef vextern
+
+#endif /*MULTFILE_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/multfile.pas b/Build/source/utils/m-tx/mtx-src/multfile.pas
new file mode 100644
index 00000000000..fb89cca89e0
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/multfile.pas
@@ -0,0 +1,199 @@
+unit multfile; (* DPL 2004-03-06, 2015-01-16
+(* Support for including files into an input stream.
+(* Intended for an application that does not require Pascal formatting,
+(* but reads complete lines one at a time.
+(* You never actually work with any files, except by supplying the
+( filename when the file is opened.
+(* At any stage, you can switch the input to a new file.
+(* When the new file is at EOF, and a "read" is issued, the file is
+(* closed and the previous one resumed transparently. This inclusion
+(* can be nested to any level, memory permitting.
+(* --- Normal mode of operation, replacing the usual Pascal style ---
+ Instead of: assign(textfile,filename); reset(textfile)
+ use: pushFile(filename)
+ When another file should be included before the current file is done,
+ use: pushFile(newfilename)
+ Instead of: readln(textfile,line)
+ use: line:=readLine
+ Instead of: eof(textfilen)
+ or: eofAll; {Are all files at EOF?}
+(* --- Abnormal mode of operation ---
+ To abort a file before EOF is reached:
+ use: popFile;
+ To abort all files:
+ use: closeAll;
+ To test whether only the current file is at EOF:
+ use: eofCurrent;
+(* Additional features:
+ fileError: boolean function, was there an error during file open or read?
+ currentFilename: string function, name of current file
+ currentLineNo: integer function, number of line just read from current file
+ isEmpty(var s: string): boolean function, is s empty?
+ readData: string function, like readLine, but continue reading until
+ a non-blank line is found, return blank only at EOF
+ skipBlanks: skip blank lines in input: next call to readLine will be
+ non-blank unless EOF is encountered
+ report(items): procedure to control which messages are printed,
+ "items" is the sum of the following options
+ (constants with the appropriate values are defined in the interface)
+ 1: reportnewfile - file is opened
+ 2: reportoldfile - file is resumed
+ 4: reportclose - file is closed
+ 8: reporterror - a file error is encountered
+ 16: reportrecursive - there is a recursive include
+ The default value is items=27 (all the above except reportclose)
+ At present you cannot turn reportrecursive off.
+ *)
+interface
+
+ procedure pushFile(filename: string);
+ procedure popFile;
+ procedure closeAll;
+ procedure report(items: integer);
+ function currentFilename: string;
+ function eofAll: boolean;
+ function eofCurrent: boolean;
+ function fileError: boolean;
+ function readLine: string;
+ function readData: string;
+ function isEmpty(var s: string): boolean;
+ function currentLineNo: integer;
+ procedure skipBlanks;
+ const nextData: string = '';
+
+const
+ reportnewfile = 1;
+ reportoldfile = 2;
+ reportclose = 4;
+ reporterror = 8;
+ reportrecursive = 16;
+
+implementation
+
+ type
+ pfilenode = ^filenode;
+ filenode = record
+ name: string;
+ actualfile: text;
+ prev: pfilenode;
+ lineno: integer;
+ end;
+
+ const current: pfilenode = NIL;
+ last_valid_line_no: integer = 0;
+ inputerror: boolean = false;
+ reportitem: integer = reportnewfile + reportoldfile
+ + reporterror + reportrecursive;
+
+ procedure report(items: integer); begin reportitem := items end;
+
+ function recursive (filename: string): boolean;
+ var previous: pfilenode;
+ begin if current=NIL then begin recursive:=false; exit; end;
+ previous := current; recursive:=true;
+ while previous <> NIL do
+ begin
+ if filename=previous^.name then exit;
+ previous := previous^.prev;
+ end;
+ recursive:=false
+ end;
+
+ procedure pushFile(filename: string);
+ var newnode: pfilenode;
+ begin
+ if recursive(filename) then
+ begin writeln('===! Ignoring recursive include of file ',filename); exit;
+ end;
+ new(newnode); newnode^.name := filename; newnode^.prev := current;
+ newnode^.lineno := 0;
+{$I-}
+ assign(newnode^.actualfile,filename); reset(newnode^.actualfile);
+{$I+}
+ inputerror := ioresult<>0;
+ if inputerror then dispose(newnode) else current := newnode;
+ if not inputerror and ((reportitem and reportnewfile)>0) then writeln
+ ('==>> Input from file ',currentFilename);
+ if inputerror and ((reportitem and reporterror)>0) then writeln
+ ('==!! Could not open file ',filename);
+ end;
+
+ procedure popFile;
+ var previous: pfilenode;
+ begin if current=NIL then exit;
+ if (reportitem and reportclose)>0 then writeln
+ ('==>> Closing file ',currentFilename,' at line number ', currentLineNo:1);
+ close(current^.actualfile); previous := current^.prev; dispose(current);
+ current := previous;
+ if (current<>NIL) and ((reportitem and reportoldfile)>0) then writeln
+ ('==>> Resuming input from file ',currentFilename,' at line number ',
+ currentLineNo:1);
+ end;
+
+ procedure closeAll; begin repeat popFile until current=NIL; end;
+
+ function eofCurrent: boolean;
+ begin eofCurrent := eof(current^.actualfile);
+ end;
+
+ function readLine: string;
+ var s: string;
+ begin if nextData<>'' then
+ begin readLine:=nextData; nextData:=''; exit end;
+ if eofAll then begin readLine:=''; exit end;
+{$I-}
+ readln(current^.actualfile,s); readLine:=s;
+{$I+}
+ inputerror := ioresult<>0;
+ if not inputerror then
+ begin inc(current^.lineno);
+ last_valid_line_no := current^.lineno
+ end;
+ if inputerror and ((reportitem and reporterror)>0) then writeln
+ ('==!! Could not read from file ',currentFilename);
+ end;
+
+ function isEmpty(var s: string): boolean;
+ var i: integer;
+ begin if length(s)=0 then begin isEmpty:=true; exit; end;
+ for i:=1 to length(s) do if s[i]<>' ' then
+ begin isEmpty:=false; exit; end;
+ isEmpty:=true
+ end;
+
+ function readData: string;
+ var s: string;
+ begin if not isEmpty(nextData) then
+ begin readData:=nextData; nextData:=''; exit end;
+ while not eofAll do
+ begin s:=readLine;
+ if not isEmpty(s) then begin readData:=s; exit end;
+ end;
+ readData:='';
+ end;
+
+ procedure skipBlanks;
+ begin while nextData='' do
+ begin nextData:=readData; if eofAll then exit
+ end
+ end;
+
+ function eofAll: boolean;
+ begin eofAll := true;
+ if current=NIL then exit else
+ if eofCurrent then begin popFile; eofAll:=eofAll; exit end;
+ eofAll:=false
+ end;
+
+ function currentLineNo: integer;
+ begin currentLineNo := last_valid_line_no
+ end;
+
+ function currentFilename: string;
+ begin if current = NIL then currentFilename := 'No file open yet'
+ else currentFilename := current^.name;
+ end;
+
+ function fileError: boolean; begin fileError := inputerror; end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/notes.c b/Build/source/utils/m-tx/mtx-src/notes.c
new file mode 100644
index 00000000000..3d4c445ba13
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/notes.c
@@ -0,0 +1,511 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "notes.pas" */
+
+
+#include "p2c.h"
+
+
+#define NOTES_G
+#include "notes.h"
+
+
+short count64['9' + 1 - '0'] = {
+ 64, 4, 32, 2, 16, 0, 1, 0, 8, 128
+};
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+#ifndef GLOBALS_H
+#include "globals.h"
+#endif
+
+
+typedef struct parsedNote {
+ Char name;
+ Char duration[2];
+ Char octave[9];
+ Char accidental[17], whatever[17], dotgroup[17], xtuplet[17];
+ Char shortcut[33];
+} parsedNote;
+
+
+Static void printNote(parsedNote n)
+{
+ printf("%c|%s|%s|%s|%s|%s|%s|%s\n",
+ n.name, n.duration, n.octave, n.accidental, n.whatever, n.dotgroup,
+ n.xtuplet, n.shortcut);
+}
+
+
+/* If rearrangeNote is TRUE, translate original note to the following form:
+ 1. Note name.
+ 2. Duration.
+ 3. Octave adjustments.
+ 4. Everything except the other six items.
+ 5. Accidental with adjustments (rest: height adjustment)
+ 6. Dot with adjustments.
+ 7. Xtuplet group.
+*/
+
+void translateSolfa(Char *nt)
+{
+ short k;
+
+ if (!solfaNoteNames())
+ return;
+ k = pos1(*nt, solfa_names);
+ if (k > 0)
+ *nt = has_duration[k-1];
+}
+
+
+Char durationCode(Char *note)
+{
+ Char Result = unspecified;
+ Char code;
+
+ if (strlen(note) <= 1)
+ return Result;
+ code = note[1];
+ if (pos1(code, durations) > 0)
+ return code;
+ return Result;
+}
+
+
+Static Char half(Char dur)
+{
+ Char Result;
+ short k;
+ Char STR1[20];
+ Char STR2[24];
+
+ k = pos1(dur, durations);
+ Result = dur;
+ if (k == 0) {
+ sprintf(STR1, "Invalid duration %c", dur);
+ error(STR1, print);
+ return Result;
+ }
+ if (k <= ndurs)
+ return (durations[k]);
+ sprintf(STR2, "%c is too short to halve", dur);
+ error(STR2, print);
+ return Result;
+}
+
+
+Static void addDuration(Char *note, Char dur)
+{
+ if (insertDuration())
+ insertChar(dur, note, 2);
+}
+
+
+/* Extract procedures. All of these remove part of "note" (sometimes
+ the part is empty) and put it somewhere else. The part may be anywhere
+ in "note", except when otherwise specified.*/
+
+/* Unconditionally extracts the first character. */
+
+Static void extractFirst(Char *note, Char *first)
+{
+ *first = note[0];
+ predelete(note, 1);
+}
+
+
+/* Extracts at most one of the characters in "hits". */
+
+Static void extractOneOf(Char *note, Char *hits, Char *hit)
+{
+ short i, l;
+
+ l = strlen(note);
+ *hit = '\0';
+ for (i = 1; i <= l; i++) {
+ if (pos1(note[i-1], hits) > 0) {
+ sprintf(hit, "%c", note[i-1]);
+ delete1(note, i);
+ return;
+ }
+ }
+}
+
+
+/* Extracts contiguous characters in "hits" until no more are found.
+ There may be more later. */
+
+Static void extractContiguous(Char *note, Char *hits, Char *hit)
+{
+ short i, l, len;
+
+ l = strlen(note);
+ len = l;
+ *hit = '\0';
+ for (i = 1; i <= l; i++) {
+ if (pos1(note[i-1], hits) > 0) {
+ do {
+ if (pos1(note[i-1], hits) == 0)
+ return;
+ sprintf(hit + strlen(hit), "%c", note[i-1]);
+ delete1(note, i);
+ len--;
+ } while (len >= i);
+ return;
+ }
+ }
+}
+
+
+/* Extracts the specified character and everything after it. */
+
+Static void extractAfter(Char *note, Char delim, Char *tail)
+{
+ short newlen;
+
+ newlen = pos1(delim, note);
+ *tail = '\0';
+ if (newlen == 0)
+ return;
+ newlen--;
+ strcpy(tail, note);
+ predelete(tail, newlen);
+ note[(long)((int)newlen)] = '\0';
+/* p2c: notes.pas, line 109:
+ * Note: Modification of string length may translate incorrectly [146] */
+}
+
+
+/* Extracts the dot shortcut part of a note: comma shortcut is no problem
+ because a comma cannot be part of a number. */
+
+Static void extractDotShortcut(Char *note, Char *tail)
+{
+ Char names[256], tail2[256];
+ short l = 1;
+ short lt;
+ Char ch;
+
+ extractAfter(note, '.', tail);
+ lt = strlen(tail);
+ if (l < lt && tail[1] == '.')
+ l = 2;
+ if (solfaNoteNames())
+ strcpy(names, solfa_names);
+ else
+ strcpy(names, has_duration);
+ if (l < lt && pos1(tail[l], names) > 0) {
+ translateSolfa(&tail[l]);
+ return;
+ }
+ if (l == 2)
+ error("\"..\" followed by non-note", print);
+ if (l >= lt) {
+ strcat(note, tail);
+ *tail = '\0';
+ return;
+ }
+ ch = tail[0];
+ predelete(tail, 1);
+ extractDotShortcut(tail, tail2);
+ sprintf(note + strlen(note), "%c%s", ch, tail);
+ strcpy(tail, tail2);
+}
+
+
+/* Extracts a signed number. */
+
+Static void extractSignedNumber(Char *note, Char *number)
+{
+ short k;
+ Char note0[256];
+
+ k = pos1('+', note);
+ if (k == 0)
+ k = pos1('-', note);
+ *number = '\0';
+ if (k == 0)
+ return;
+ strcpy(note0, note);
+ do {
+ sprintf(number + strlen(number), "%c", note[k-1]);
+ delete1(note, k);
+ } while (k <= strlen(note) &&
+ (note[k-1] == '0' || pos1(note[k-1], digits) != 0));
+ if (strlen(number) == 1) {
+ strcpy(note, note0);
+ *number = '\0';
+ }
+}
+
+
+/* Local variables for extractGroup: */
+struct LOC_extractGroup {
+ Char *group;
+ short gl, k;
+ boolean probe, nonumber;
+} ;
+
+Local void tryMore(struct LOC_extractGroup *LINK)
+{
+ while (LINK->k <= LINK->gl && LINK->group[LINK->k-1] == LINK->group[0])
+ LINK->k++;
+}
+
+Local void try_(Char *s, struct LOC_extractGroup *LINK)
+{
+ LINK->probe = (LINK->k < LINK->gl && pos1(LINK->group[LINK->k-1], s) > 0);
+ if (LINK->probe)
+ LINK->k++;
+}
+
+Local void tryNumber(struct LOC_extractGroup *LINK)
+{
+ boolean dot_ = false;
+
+ LINK->nonumber = true;
+ while (LINK->k <= LINK->gl && pos1(LINK->group[LINK->k-1], digitsdot) > 0) {
+ LINK->k++;
+ if (LINK->group[LINK->k-1] == '.') {
+ if (dot_)
+ error("Extra dot in number", print);
+ else
+ dot_ = true;
+ } else
+ LINK->nonumber = false;
+ }
+}
+
+
+/* Extracts a symbol followed by optional +- or <> shift indicators */
+
+Static void extractGroup(Char *note, Char delim, Char *group_)
+{
+ struct LOC_extractGroup V;
+ short k0;
+ Char tail[256];
+
+ V.group = group_;
+ extractAfter(note, delim, V.group);
+ if (*V.group == '\0')
+ return;
+ V.gl = strlen(V.group);
+ V.k = 2;
+ if (V.gl > 1 && V.group[1] == ':')
+ V.k = 3;
+ else {
+ tryMore(&V);
+ k0 = V.k;
+ try_("+-<>", &V);
+ if (V.probe)
+ tryNumber(&V);
+ if (V.nonumber)
+ V.k = k0;
+ k0 = V.k;
+ try_("+-<>", &V);
+ if (V.probe)
+ tryNumber(&V);
+ if (V.nonumber)
+ V.k = k0;
+ }
+ strcpy(tail, V.group);
+ V.k--;
+ V.group[(long)((int)V.k)] = '\0';
+/* p2c: notes.pas, line 170:
+ * Note: Modification of string length may translate incorrectly [146] */
+ predelete(tail, V.k);
+ strcat(note, tail);
+}
+
+
+Static void parseNote(Char *note_, parsedNote *pnote)
+{
+ Char note[256];
+ Char onlymidi[256];
+ Char STR1[256];
+ Char STR2[10];
+
+ strcpy(note, note_);
+ *pnote->shortcut = '\0';
+ *pnote->xtuplet = '\0';
+ *pnote->accidental = '\0';
+ *pnote->dotgroup = '\0';
+ *pnote->duration = '\0';
+ *pnote->octave = '\0';
+ *onlymidi = '\0';
+ extractFirst(note, &pnote->name);
+ extractAfter(note, 'x', pnote->xtuplet);
+ extractAfter(note, ',', pnote->shortcut);
+ if (*pnote->shortcut == '\0')
+ extractDotShortcut(note, pnote->shortcut);
+ if (pnote->name != rest) {
+ extractGroup(note, 's', pnote->accidental);
+ if (*pnote->accidental == '\0')
+ extractGroup(note, 'f', pnote->accidental);
+ if (*pnote->accidental == '\0')
+ extractGroup(note, 'n', pnote->accidental);
+ }
+ /* Look for 'i' or 'c' anywhere in what is left of note.*/
+ if (*pnote->accidental != '\0') {
+ extractOneOf(note, "ic", onlymidi);
+ strcat(pnote->accidental, onlymidi);
+/* p2c: notes.pas, line 192:
+ * Note: Possible string truncation in assignment [145] */
+ }
+ extractGroup(note, 'd', pnote->dotgroup);
+ if (pnote->name == rest)
+ extractSignedNumber(note, pnote->accidental);
+ extractOneOf(note, durations, pnote->duration);
+ sprintf(STR1, "%c", rest);
+ if (strcmp(note, STR1))
+ extractContiguous(note, "=+-", pnote->octave);
+ if (*note != '\0' && isdigit(note[0])) {
+ sprintf(STR2, "%c%s", note[0], pnote->octave);
+ strcpy(pnote->octave, STR2);
+/* p2c: notes.pas, line 198:
+ * Note: Possible string truncation in assignment [145] */
+ delete1(note, 1);
+ }
+ strcpy(pnote->whatever, note);
+/* p2c: notes.pas, line 200:
+ * Note: Possible string truncation in assignment [145] */
+}
+
+
+/* On input: "note" is a note word; "dur1" is the default duration.
+ On output: "note" has possibly been modified;
+ possibly been split into two parts, the second being "shortcut";
+ "dur" is the suggested new default duration;
+ "count" is the count of the total of "note" and "shortcut" */
+void processNote(Char *note, Char *xnote, Char dur1, Char *dur, short *count)
+{
+ Char sc[3], origdur[3];
+ short multiplicity, l;
+ parsedNote pnote;
+ Char STR1[36];
+ Char STR3[256];
+
+ *xnote = '\0';
+ *dur = dur1;
+ if (*note == '\0' || !isNoteOrRest(note) || isPause(note))
+ return;
+ parseNote(note, &pnote);
+ if (debugMode()) {
+ printf("%s => ", note);
+ printNote(pnote);
+ }
+ if (pos1('.', pnote.whatever) > 0) {
+ sprintf(STR3, "Suspicious dot in word %s", note);
+ warning(STR3, print);
+ }
+ strcpy(origdur, pnote.duration);
+ if (*pnote.duration == '\0')
+ *dur = dur1;
+ else
+ *dur = pnote.duration[0];
+ *count = count64[*dur - '0'];
+ if (*pnote.dotgroup != '\0') {
+ *count += *count / 2;
+ if (startsWith(pnote.dotgroup, "dd"))
+ *count += *count / 6;
+ }
+ sprintf(pnote.duration, "%c", *dur);
+ if (*pnote.shortcut != '\0') {
+ if (*pnote.dotgroup != '\0')
+ error("You may not explicitly dot a note with a shortcut", print);
+ sprintf(sc, "%c", pnote.shortcut[0]);
+ predelete(pnote.shortcut, 1);
+ if (!strcmp(sc, ".")) {
+ multiplicity = 1;
+ if (pnote.shortcut[0] == '.') {
+ multiplicity++;
+ predelete(pnote.shortcut, 1);
+ strcat(sc, ".");
+/* p2c: notes.pas, line 234:
+ * Note: Possible string truncation in assignment [145] */
+ }
+ *count += *count;
+ dur1 = pnote.duration[0];
+ for (l = 1; l <= multiplicity; l++) {
+ sprintf(pnote.dotgroup + strlen(pnote.dotgroup), "%c", dotcode);
+/* p2c: notes.pas, line 237:
+ * Note: Possible string truncation in assignment [145] */
+ dur1 = half(dur1);
+ }
+ addDuration(pnote.shortcut, dur1);
+ } else {
+ addDuration(pnote.shortcut, half(pnote.duration[0]));
+ *count += *count / 2;
+ }
+ }
+ if (!insertDuration()) {
+ strcpy(pnote.duration, origdur);
+/* p2c: notes.pas, line 244:
+ * Note: Possible string truncation in assignment [145] */
+ }
+ if (rearrangeNote())
+ sprintf(note, "%c%s%s%s%s%s%s",
+ pnote.name, pnote.duration, pnote.octave, pnote.whatever,
+ pnote.accidental, pnote.dotgroup, pnote.xtuplet);
+ else
+ strcpy(pnote.shortcut, " ");
+ if (!insertDuration() && *pnote.shortcut != '\0') {
+ sprintf(STR1, "%s%s", sc, pnote.shortcut);
+ strcpy(pnote.shortcut, STR1);
+/* p2c: notes.pas, line 249:
+ * Note: Possible string truncation in assignment [145] */
+ }
+ strcpy(xnote, pnote.shortcut);
+}
+
+
+Char octaveCode(Char *note)
+{ /*if debugMode then write('Octave code in note "',note,'" is ');*/
+ parsedNote pnote;
+
+ parseNote(note, &pnote);
+ /*if debugMode then writeln('"',octave,'"');*/
+ if (*pnote.octave == '\0')
+ return ' ';
+ else
+ return (pnote.octave[0]);
+}
+
+
+void removeOctaveCode(Char code, Char *note)
+{ /*if debugMode then writeln('remove ',code,' from ',note);*/
+ short k, l;
+
+ l = strlen(note);
+ for (k = 1; k <= l; k++) {
+ if (note[k-1] == code) {
+ if (k == l || note[k] < '0' || note[k] > '9') {
+ delete1(note, k);
+ return;
+ }
+ }
+ }
+ fatalerror("Code not found in note");
+}
+
+
+void insertOctaveCode(Char code, Char *note)
+{ /*if debugMode then writeln('insert ',code,' into ',note); */
+ short l;
+
+ l = strlen(note);
+ if (l < 2 || note[1] < '0' || note[1] > '9')
+ fatalerror("Trying to insert octave into note without duration");
+ if (l <= 2 || note[2] < '0' || note[2] > '9')
+ insertChar(code, note, 3);
+ else
+ printf("Not inserting \"%c\", note already has octave code\"\n", code);
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/notes.h b/Build/source/utils/m-tx/mtx-src/notes.h
new file mode 100644
index 00000000000..8806ef868cc
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/notes.h
@@ -0,0 +1,36 @@
+/* Header for module notes, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef NOTES_H
+#define NOTES_H
+
+
+/*$V-*/
+
+#ifndef CONTROL_H
+#include "control.h"
+#endif
+
+
+#ifdef NOTES_G
+# define vextern
+#else
+# define vextern extern
+#endif
+
+
+extern short count64['9' + 1 - '0'];
+
+
+extern void processNote(Char *note, Char *xnote, Char dur1, Char *dur,
+ short *count);
+extern Char durationCode(Char *note);
+extern Char octaveCode(Char *note);
+extern void removeOctaveCode(Char code, Char *note);
+extern void insertOctaveCode(Char code, Char *note);
+extern void translateSolfa(Char *nt);
+
+
+#undef vextern
+
+#endif /*NOTES_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/notes.pas b/Build/source/utils/m-tx/mtx-src/notes.pas
new file mode 100644
index 00000000000..2f6a01505f5
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/notes.pas
@@ -0,0 +1,281 @@
+unit notes;
+{$V-}
+
+interface uses control;
+
+const count64: array['0'..'9'] of integer =
+ ( 64, 4, 32, 2, 16, 0, 1, 0, 8, 128 );
+
+procedure processNote(var note, xnote: string; dur1: char; var dur: char;
+ var count: integer);
+function durationCode (note: string): char;
+function octaveCode (note: string): char;
+procedure removeOctaveCode(code: char; var note: string);
+procedure insertOctaveCode(code: char; var note: string);
+procedure translateSolfa(var nt: char);
+
+implementation uses strings, globals;
+
+type
+
+parsedNote = record
+ name: char;
+ duration: string[1];
+ octave: string[8];
+ accidental, whatever, dotgroup, xtuplet: string[16];
+ shortcut: string[32];
+end;
+
+procedure printNote(n: parsedNote);
+begin with n do writeln(name,'|',duration,'|',octave,'|',accidental,'|',
+ whatever,'|',dotgroup,'|',xtuplet,'|',shortcut)
+end;
+
+{ If rearrangeNote is TRUE, translate original note to the following form:
+ 1. Note name.
+ 2. Duration.
+ 3. Octave adjustments.
+ 4. Everything except the other six items.
+ 5. Accidental with adjustments (rest: height adjustment)
+ 6. Dot with adjustments.
+ 7. Xtuplet group.
+}
+
+procedure translateSolfa(var nt: char);
+ var k: integer;
+begin if solfaNoteNames then
+ begin k:=pos1(nt,solfa_names); if k>0 then nt:=has_duration[k]
+ end
+end;
+
+function durationCode (note: string): char;
+ var code: char;
+ begin durationCode:=unspecified; if length(note)>1 then
+ begin code:=note[2]; if pos1(code,durations)>0 then durationCode:=code
+ end
+ end;
+
+function half ( dur: char ) : char;
+ var k: integer;
+ begin k:= pos1 (dur, durations ); half := dur;
+ if k=0 then error ('Invalid duration '+dur,print)
+ else if k>ndurs then error (dur+' is too short to halve',print)
+ else half := durations[k+1];
+ end;
+
+procedure addDuration ( var note: string; dur: char);
+begin if insertDuration then insertchar(dur,note,2); end;
+
+{ Extract procedures. All of these remove part of "note" (sometimes
+ the part is empty) and put it somewhere else. The part may be anywhere
+ in "note", except when otherwise specified.}
+
+{ Unconditionally extracts the first character. }
+
+procedure extractFirst(var note: string; var first: char);
+begin first:=note[1]; predelete(note,1)
+end;
+
+{ Extracts at most one of the characters in "hits". }
+
+procedure extractOneOf(var note: string; hits: string; var hit: string);
+ var i, l: integer;
+begin l:=length(note); hit:='';
+ for i:=1 to l do if pos1(note[i],hits)>0 then
+ begin hit:=note[i]; delete1(note,i); exit;
+ end;
+end;
+
+{ Extracts contiguous characters in "hits" until no more are found.
+ There may be more later. }
+
+procedure extractContiguous(var note: string; hits: string; var hit: string);
+ var i, l, len: integer;
+begin l:=length(note); len:=l; hit:='';
+ for i:=1 to l do if pos1(note[i],hits)>0 then
+ begin
+ repeat if pos1(note[i],hits)=0 then exit;
+ hit:=hit+note[i]; delete1(note,i); dec(len)
+ until len<i;
+ exit;
+ end;
+end;
+
+{ Extracts the specified character and everything after it. }
+
+procedure extractAfter(var note: string; delim: char; var tail: string);
+ var newlen: integer;
+begin newlen:=pos1(delim,note); tail:=''; if newlen=0 then exit;
+ dec(newlen); tail:=note; predelete(tail,newlen); note[0]:=char(newlen);
+end;
+
+{ Extracts the dot shortcut part of a note: comma shortcut is no problem
+ because a comma cannot be part of a number. }
+
+procedure extractDotShortcut(var note: string; var tail: string);
+ var names, tail2: string;
+ l, lt: integer;
+ ch: char;
+begin extractAfter(note,'.',tail); l:=1; lt:=length(tail);
+ if (l<lt) and (tail[2]='.') then l:=2;
+ if solfaNoteNames then names:=solfa_names else names:=has_duration;
+ if (l<lt) and (pos1(tail[l+1],names)>0) then
+ begin translateSolfa(tail[l+1]); exit end;
+ if l=2 then error('".." followed by non-note',print);
+ if l>=lt then begin note:=note+tail; tail:=''; exit end;
+ ch:=tail[1]; predelete(tail,1);
+ extractDotShortcut(tail,tail2); note:=note+ch+tail; tail:=tail2;
+end;
+
+{ Extracts a signed number. }
+
+procedure extractSignedNumber(var note, number: string);
+ var k: integer;
+ note0: string;
+begin k:=pos1('+',note); if k=0 then k:=pos1('-',note);
+ number:=''; if k=0 then exit;
+ note0:=note;
+ repeat number:=number+note[k]; delete1(note,k)
+ until (k>length(note)) or (note[k]<>'0') and (pos1(note[k],digits)=0);
+ if length(number)=1 then begin note:=note0; number:='' end
+end;
+
+{ Extracts a symbol followed by optional +- or <> shift indicators }
+
+procedure extractGroup(var note: string; delim: char; var group: string);
+ var gl, k, k0: integer;
+ probe, nonumber: boolean;
+ tail: string;
+ procedure tryMore;
+ begin while (k<=gl) and (group[k]=group[1]) do inc(k) end;
+ procedure try(s: string);
+ begin probe:=(k<gl) and (pos1(group[k],s)>0); if probe then inc(k)
+ end;
+ procedure tryNumber;
+ var dot: boolean;
+ begin nonumber:=true; dot:=false;
+ while (k<=gl) and (pos1(group[k],digitsdot)>0) do
+ begin inc(k); if group[k]='.' then
+ if dot then error('Extra dot in number',print) else dot:=true
+ else nonumber:=false
+ end
+ end;
+begin extractAfter(note,delim,group); if group='' then exit;
+ gl:=length(group); k:=2;
+ if (gl>1) and (group[2]=':') then k:=3 else
+ begin tryMore;
+ k0:=k; try('+-<>'); if probe then tryNumber; if nonumber then k:=k0;
+ k0:=k; try('+-<>'); if probe then tryNumber; if nonumber then k:=k0;
+ end;
+ tail:=group; dec(k); group[0]:=char(k); predelete(tail,k);
+ note:=note+tail
+end;
+
+procedure parseNote(note: string; var pnote: parsedNote);
+var onlymidi: string;
+begin with pnote do
+ begin
+ shortcut:=''; xtuplet:=''; accidental:=''; dotgroup:='';
+ duration:=''; octave:=''; onlymidi:='';
+ extractFirst(note,name);
+ extractAfter(note,'x',xtuplet);
+ extractAfter(note,',',shortcut);
+ if shortcut='' then extractDotShortcut(note,shortcut);
+ if name<>rest then
+ begin extractGroup(note,'s',accidental);
+ if accidental='' then extractGroup(note,'f',accidental);
+ if accidental='' then extractGroup(note,'n',accidental);
+ end;
+{ Look for 'i' or 'c' anywhere in what is left of note.}
+ if accidental<>'' then
+ begin extractOneOf(note,'ic',onlymidi); accidental:=accidental+onlymidi
+ end;
+ extractGroup(note,'d',dotgroup);
+ if name=rest then extractSignedNumber(note,accidental);
+ extractOneOf(note,durations,duration);
+ if note<>rest then extractContiguous(note,'=+-',octave);
+ if (length(note)>0) and (note[1]>='0') and (note[1]<='9')
+ then begin octave:=note[1]+octave; delete1(note,1) end;
+ whatever := note
+ end
+end;
+
+{ On input: "note" is a note word; "dur1" is the default duration.
+ On output: "note" has possibly been modified;
+ possibly been split into two parts, the second being "shortcut";
+ "dur" is the suggested new default duration;
+ "count" is the count of the total of "note" and "shortcut" }
+procedure processNote(var note, xnote: string; dur1: char; var dur: char;
+ var count: integer);
+var sc, origdur: string[2];
+ multiplicity, l: integer;
+ pnote: parsedNote;
+begin xnote:=''; dur:=dur1;
+ if (note='') or not isNoteOrRest(note) or isPause(note) then exit;
+ parseNote(note, pnote);
+ if debugMode then begin write(note,' => '); printNote(pnote) end;
+ with pnote do
+ begin
+ if pos1('.',whatever)>0 then warning('Suspicious dot in word '+note,print);
+ origdur := duration;
+ if duration='' then dur:=dur1 else dur:=duration[1];
+ count:=count64[dur]; if dotgroup<>'' then
+ begin inc(count,count div 2);
+ if startswith(dotgroup,'dd') then inc(count,count div 6)
+ end;
+ duration:=dur; if shortcut<>'' then
+ begin
+ if dotgroup<>'' then
+ error('You may not explicitly dot a note with a shortcut',print);
+ sc:=shortcut[1]; predelete(shortcut,1);
+ if sc='.' then
+ begin multiplicity:=1;
+ if shortcut[1]='.' then
+ begin inc(multiplicity); predelete(shortcut,1); sc:=sc+'.' end;
+ inc(count,count); dur1:=duration[1];
+ for l:=1 to multiplicity do
+ begin dotgroup:=dotgroup+dotcode; dur1:=half(dur1) end;
+ addDuration(shortcut,dur1);
+ end else
+ begin addDuration(shortcut,half(duration[1]));
+ inc(count,count div 2)
+ end
+ end;
+ if not insertDuration then duration := origdur;
+ if rearrangeNote
+ then note := name + duration + octave + whatever
+ + accidental + dotgroup + xtuplet
+ else shortcut:=' ';
+ if not insertDuration and (shortcut<>'') then shortcut:=sc+shortcut;
+ xnote:=shortcut
+ end
+end;
+
+function octaveCode (note: string): char;
+ var pnote: parsedNote;
+begin {if debugMode then write('Octave code in note "',note,'" is ');}
+ parseNote(note,pnote); with pnote do
+ begin {if debugMode then writeln('"',octave,'"');}
+ if octave='' then octaveCode:=' ' else octaveCode:=octave[1]; end
+end;
+
+procedure removeOctaveCode(code: char; var note: string);
+ var k, l: integer;
+begin {if debugMode then writeln('remove ',code,' from ',note);} l:=length(note);
+ for k:=1 to l do if note[k]=code then
+ if (k=l) or (note[k+1]<'0') or (note[k+1]>'9') then
+ begin delete1(note,k); exit end;
+ fatalError('Code not found in note')
+end;
+
+procedure insertOctaveCode(code: char; var note: string);
+ var l: integer;
+begin {if debugMode then writeln('insert ',code,' into ',note); }
+ l:=length(note);
+ if (l<2) or (note[2]<'0') or (note[2]>'9') then
+ fatalError('Trying to insert octave into note without duration');
+ if (l<=2) or (note[3]<'0') or (note[3]>'9') then insertChar(code,note,3)
+ else writeln('Not inserting "',code,'", note already has octave code"')
+end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/preamble.c b/Build/source/utils/m-tx/mtx-src/preamble.c
new file mode 100644
index 00000000000..4a7da2e5449
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/preamble.c
@@ -0,0 +1,1212 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "preamble.pas" */
+
+
+#include "p2c.h"
+
+
+#define PREAMBLE_G
+#include "preamble.h"
+
+
+#ifndef CONTROL_H
+#include "control.h"
+#endif
+
+#ifndef MTXLINE_H
+#include "mtxline.h"
+#endif
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+#ifndef MULTFILE_H
+#include "multfile.h"
+#endif
+
+#ifndef FILES_H
+#include "files.h"
+#endif
+
+#ifndef STATUS_H
+#include "status.h"
+#endif
+
+#ifndef UTILITY_H
+#include "utility.h"
+#endif
+
+
+#define blank_ ' '
+#define colon_ ':'
+#define semicolon ';'
+#define comma_ ','
+
+#define max_styles 24
+
+
+typedef enum {
+ none, title, composer, pmx, tex, options, msize, bars, shortnote, style,
+ sharps, flats, meter, space, pages, systems, width, height, enable, disable,
+ range, name, indent, poet, part, only, octave_, start
+} command_type;
+
+typedef enum {
+ unknown, colon_line, command_line, comment_line, plain_line
+} line_type;
+
+typedef char style_index;
+
+typedef char style_index0;
+
+
+#define c1 title
+#define cn start
+
+
+Static short known_styles = 12;
+Static boolean warn_redefine = false;
+
+Static Char commands[28][17] = {
+ "NONE", "TITLE", "COMPOSER", "PMX", "TEX", "OPTIONS", "SIZE", "BARS/LINE",
+ "SHORT", "STYLE", "SHARPS", "FLATS", "METER", "SPACE", "PAGES", "SYSTEMS",
+ "WIDTH", "HEIGHT", "ENABLE", "DISABLE", "RANGE", "NAME", "INDENT", "POET",
+ "PART", "ONLY", "OCTAVE", "START"
+};
+
+/* short */
+/* systems */
+
+Static Char cline[28][256] = {
+ "", "", "", "", "", "", "", "", "1/4", "", "0", "", "C", "", "1", "1",
+ "190mm", "260mm", "", "", "", "", "", "", "", "", "", ""
+};
+
+Static boolean redefined[28] = {
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false
+};
+
+/** Known styles */
+
+Static Char known_style[max_styles][256] = {
+ "SATB: Voices S,A T,B; Choral; Clefs G F",
+ "SATB4: Voices S A T B; Choral; Clefs G G G8 F",
+ "SINGER: Voices Voice; Vocal; Clefs G",
+ "PIANO: Voices RH LH; Continuo; Clefs G F",
+ "ORGAN: Voices RH LH Ped; Continuo; Clefs G F F",
+ "SOLO: Voices V; Clefs G", "DUET: Voices V1 Vc; Clefs G F",
+ "TRIO: Voices V1 Va Vc; Clefs G C F",
+ "QUARTET: Voices V1 V2 Va Vc; Clefs G G C F",
+ "QUINTET: Voices V1 V2 Va Vc1 Vc2; Clefs G G C F F",
+ "SEXTET: Voices V1 V2 Va1 Va2 Vc1 Vc2; Clefs G G C C F F",
+ "SEPTET: Voices V1 V2 Va1 Va2 Vc1 Vc2 Cb; Clefs G G C C F F F", "", "", "",
+ "", "", "", "", "", "", "", "", ""
+};
+
+Static style_index old_known_styles;
+Static boolean style_used[max_styles];
+Static boolean omit_line[lines_in_paragraph];
+Static style_index0 orig_style_line[max_styles];
+Static short orig_range_line;
+
+Static short nclefs, n_pages, n_systems, n_sharps, ngroups;
+Static Char part_line[256], title_line[256], composer_line[256],
+ pmx_line[256], options_line[256], start_line[256], voices[256],
+ clefs[256];
+Static short group_start[maxgroups], group_stop[maxgroups];
+Static Char instr_name[maxstaves][41];
+Static boolean style_supplied;
+
+
+/* ------------------ Styles ------------------ */
+
+Static voice_index0 voiceCount(Char *s_)
+{
+ Char s[256];
+ short i, l;
+
+ strcpy(s, s_);
+ l = strlen(s);
+ for (i = 0; i <= l - 1; i++) {
+ if (s[i] == comma_)
+ s[i] = blank_;
+ }
+ return (wordCount(s));
+}
+
+
+Static style_index0 findStyle(Char *s_)
+{
+ style_index0 Result = 0;
+ Char s[256];
+ style_index0 i = 0;
+
+ strcpy(s, s_);
+ sprintf(s + strlen(s), "%c", colon_);
+ while (i < known_styles) {
+ i++;
+ if (startsWithIgnoreCase(known_style[i-1], s))
+ return i;
+ }
+ return Result;
+}
+
+
+Static void addStyle(Char *S)
+{
+ style_index0 sn;
+ Char STR1[256];
+
+ sn = findStyle(NextWord(STR1, S, colon_, dummy));
+ if (sn > 0) {
+ strcpy(known_style[sn-1], S);
+ return;
+ }
+ if (known_styles < max_styles) {
+ known_styles++;
+ strcpy(known_style[known_styles-1], S);
+ } else
+ error("Can't add another style - table full", print);
+}
+
+
+Static void readStyles(void)
+{
+ boolean eofstyle;
+ Char S[256];
+ style_index0 l = 0;
+ Char *TEMP;
+
+ if (styleFileFound())
+ eofstyle = true;
+ else
+ eofstyle = P_eof(stylefile);
+ while (!eofstyle) {
+ fgets(S, 256, stylefile);
+ TEMP = strchr(S, '\n');
+ if (TEMP != NULL)
+ *TEMP = 0;
+ if (*S != '\0') {
+ addStyle(S);
+ l++;
+ orig_style_line[known_styles-1] = l;
+ }
+ eofstyle = P_eof(stylefile);
+ }
+}
+
+
+Static void applyStyle(Char *s_, Char *stylename, stave_index first_inst,
+ stave_index first_stave)
+{
+ Char s[256];
+ Char clef[256], subline[256], subcommand[256];
+ stave_index0 i, last_inst, last_stave;
+ boolean continuo = false, toosoon = false, vocal = false;
+ Char STR2[256];
+
+ strcpy(s, s_);
+ last_inst = first_inst - 1;
+ GetNextWord(subline, s, blank_, colon_);
+ while (*s != '\0') {
+ GetNextWord(subline, s, semicolon, dummy);
+ i = curtail(subline, semicolon);
+ GetNextWord(subcommand, subline, blank_, dummy);
+ if (equalsIgnoreCase(subcommand, "VOICES")) {
+ sprintf(voices + strlen(voices), " %s", subline);
+ last_stave = first_stave + wordCount(subline) - 1;
+ last_inst = first_inst + voiceCount(subline) - 1;
+ } else if (equalsIgnoreCase(subcommand, "CLEFS")) {
+ strcpy(clef, subline);
+ sprintf(clefs + strlen(clefs), " %s", clef);
+ } else if (equalsIgnoreCase(subcommand, "VOCAL")) {
+ if (last_inst < first_inst)
+ toosoon = true;
+ else {
+ some_vocal = true;
+ vocal = true;
+ for (i = first_inst; i <= last_inst; i++)
+ setVocal(i, true);
+ }
+ } else if (equalsIgnoreCase(subcommand, "CHORAL") ||
+ equalsIgnoreCase(subcommand, "GROUP")) {
+ if (last_inst < first_inst)
+ toosoon = true;
+ else {
+ if (equalsIgnoreCase(subcommand, "CHORAL")) {
+ some_vocal = true;
+ vocal = true;
+ for (i = first_inst; i <= last_inst; i++)
+ setVocal(i, true);
+ }
+ if (ngroups == maxgroups)
+ error("Too many groups", print);
+ else {
+ ngroups++;
+ group_start[ngroups-1] = first_stave;
+ group_stop[ngroups-1] = last_stave;
+ }
+ }
+ } else if (equalsIgnoreCase(subcommand, "CONTINUO"))
+ continuo = true;
+ else {
+ sprintf(STR2, "Subcommand %s in STYLE unknown", subcommand);
+ error(STR2, print);
+ }
+ if (toosoon) {
+ sprintf(STR2, "You must first give VOICES before specifying %s",
+ subcommand);
+ error(STR2, print);
+ }
+ }
+ if (vocal && continuo)
+ error("A continuo instrument may not be vocal", print);
+ if (wordCount(clef) != last_stave - first_stave + 1)
+ error("Number of clefs does not match number of voices", print);
+ if (first_stave == last_stave || continuo) {
+ strcpy(instr_name[first_stave-1], stylename);
+/* p2c: preamble.pas, line 185:
+ * Note: Possible string truncation in assignment [145] */
+ } else {
+ for (i = first_stave - 1; i <= last_stave - 1; i++)
+ *instr_name[i] = '\0';
+ }
+ if (continuo) {
+ ninstr++;
+ stave[ninstr-1] = first_stave;
+ for (i = first_stave - 1; i <= last_stave - 1; i++)
+ instr[i] = ninstr;
+ return;
+ }
+ for (i = first_stave; i <= last_stave; i++) {
+ ninstr++;
+ stave[ninstr-1] = i;
+ instr[i-1] = ninstr;
+ }
+}
+
+
+Static void applyStyles(void)
+{
+ short n1, n2, sn;
+ Char s[256];
+ Char STR2[256];
+
+ *voices = '\0';
+ *clefs = '\0';
+ ninstr = 0;
+ while (*cline[(long)style] != '\0') {
+ n1 = voiceCount(voices) + 1;
+ n2 = wordCount(voices) + 1;
+ GetNextWord(s, cline[(long)style], blank_, comma_);
+ curtail(s, comma_);
+ sn = findStyle(s);
+ if (sn == 0) {
+ sprintf(STR2, "Style %s unknown", s);
+ error(STR2, print);
+ }
+ line_no = orig_style_line[sn-1];
+ applyStyle(known_style[sn-1], s, n1, n2);
+ style_used[sn-1] = true;
+ }
+}
+
+
+/* ------------------------------------------------------------- */
+
+Static void wipeCommands(void)
+{
+ command_type c;
+
+ for (c = c1; c <= cn; c = (command_type)((long)c + 1))
+ *cline[(long)c] = '\0';
+}
+
+
+boolean omitLine(paragraph_index line)
+{
+ return (line > 0 && omit_line[line-1]);
+}
+
+
+Static void setName(void)
+{
+ short i, FORLIM;
+
+ if (!redefined[(long)name])
+ return;
+ setFeature("instrumentNames", true);
+ FORLIM = ninstr;
+ for (i = 0; i <= FORLIM - 1; i++) {
+ GetNextWord(instr_name[i], cline[(long)name], blank_, dummy);
+/* p2c: preamble.pas, line 226:
+ * Note: Possible string truncation in assignment [145] */
+ }
+}
+
+
+Static void setIndent(void)
+{
+ if (redefined[(long)indent])
+ strcpy(fracindent, cline[(long)indent]);
+}
+
+
+Static void setInitOctave(void)
+{
+ if (redefined[(long)octave_])
+ initOctaves(cline[(long)octave_]);
+}
+
+
+Local void checkLabel(Char *w)
+{
+ voice_index j, FORLIM;
+ Char STR1[256], STR2[256];
+
+ FORLIM = nvoices;
+ for (j = 0; j <= FORLIM - 1; j++) {
+ if (!strcmp(w, voice_label[j])) {
+ sprintf(STR2, "Voice label %s not unique", w);
+ warning(STR2, print);
+ return;
+ }
+ }
+ if (strlen(w) > 2)
+ return;
+ if (pos1(w[0], "CLU") > 0) {
+ if (strlen(w) > 1) {
+ if (pos1(w[1], "123456789") == 0)
+ return;
+ }
+ } else if (pos1(w[0], "123456789") == 0)
+ return;
+ sprintf(STR1, "Voice label %s conflicts with reserved label", w);
+ error(STR1, print);
+}
+
+
+Static void setVoices(Char *line)
+{
+ short k;
+ Char s[256], w[256];
+ Char STR1[256];
+ short FORLIM;
+
+ nvoices = 0;
+ nstaves = 0;
+ do {
+ GetNextWord(s, line, blank_, dummy);
+ if (*s != '\0') {
+ nstaves++;
+ k = 0;
+ first_on_stave[nstaves-1] = nvoices + 1;
+ do {
+ GetNextWord(w, s, blank_, comma_);
+ curtail(w, comma_);
+ if (*w != '\0') {
+ k++;
+ if (k <= 2) {
+ nvoices++;
+ checkLabel(w);
+ strcpy(voice_label[nvoices-1], w);
+ if (*instr_name[nstaves-1] == '\0') {
+ strcpy(instr_name[nstaves-1], w);
+/* p2c: preamble.pas, line 266:
+ * Note: Possible string truncation in assignment [145] */
+ }
+ setStavePos(nvoices, nstaves, k);
+ }
+ }
+ } while (*w != '\0');
+ if (k > 2) {
+ sprintf(STR1, "More than two voices per stave: %s", s);
+ error(STR1, print);
+ }
+ if (k == 2) {
+ sprintf(instr_name[nstaves-1], "\\mtxTwoInstruments{%s}{%s}",
+ voice_label[nvoices-2], voice_label[nvoices-1]);
+/* p2c: preamble.pas, line 273:
+ * Note: Possible string truncation in assignment [145] */
+ }
+ number_on_stave[nstaves-1] = k;
+ }
+ } while (*line != '\0');
+ FORLIM = nvoices;
+ for (k = 0; k <= FORLIM - 1; k++)
+ selected[k] = true;
+}
+
+
+Static void setClefs(Char *line_)
+{
+ Char line[256];
+ Char s[256];
+
+ strcpy(line, line_);
+ nclefs = 0;
+ do {
+ GetNextWord(s, line, blank_, dummy);
+ if (*s != '\0') {
+ nclefs++;
+ if (strlen(s) == 1)
+ clef[nclefs-1] = s[0];
+ else
+ clef[nclefs-1] = s[1];
+ }
+ } while (*s != '\0');
+}
+
+
+Static void setDimension(Char *line_, command_type lno)
+{
+ Char line[256];
+ short l;
+ short n = 0, p = 0;
+ Char STR1[256];
+
+ strcpy(line, line_);
+ if (*line == '\0')
+ return;
+ l = strlen(line);
+ do {
+ n++;
+ if (line[n-1] == '.')
+ p++;
+ } while (n <= l && (line[n-1] == '.' || isdigit(line[n-1])));
+ if (n == p || p > 1 ||
+ line[n-1] != 'i' && line[n-1] != 'm' && line[n-1] != 'p')
+ error("Dimension must be a number followed by in, mm or pt", print);
+ sprintf(cline[(long)lno], "w%s", substr_(STR1, line, 1, n));
+}
+
+
+Static void setSize(Char *line_)
+{
+ Char line[256];
+ stave_index0 i = 0;
+ Char word[256];
+ stave_index0 FORLIM;
+
+ strcpy(line, line_);
+ while (i < ninstr) {
+ GetNextWord(word, line, blank_, dummy);
+ if (*word == '\0')
+ break;
+ i++;
+ getNum(word, &musicsize);
+ stave_size[i-1] = musicsize;
+ }
+ if ((unsigned)musicsize >= 32 || ((1L << musicsize) & 0x110000L) == 0) {
+ FORLIM = ninstr;
+ for (i = 0; i <= FORLIM - 1; i++) {
+ if (stave_size[i] == unspec)
+ stave_size[i] = musicsize;
+ }
+ }
+ if (musicsize < 16)
+ musicsize = 16;
+ else if (musicsize > 20)
+ musicsize = 20;
+}
+
+
+Static command_type findCommand(Char *command)
+{
+ command_type j;
+
+ curtail(command, ':');
+ if (equalsIgnoreCase(command, "STYLE"))
+ style_supplied = true;
+ for (j = c1; j <= cn; j = (command_type)((long)j + 1)) {
+ if (equalsIgnoreCase(command, commands[(long)j]))
+ return j;
+ }
+ return none;
+}
+
+
+boolean isCommand(Char *command_)
+{
+ Char command[256];
+
+ strcpy(command, command_);
+ return (findCommand(command) != none);
+}
+
+
+Static boolean mustAppend(command_type command)
+{
+ return (command == tex);
+}
+
+
+Static void doEnable(Char *line, boolean choice)
+{
+ Char word[256];
+ Char STR1[256];
+
+ do {
+ GetNextWord(word, line, blank_, dummy);
+ if (*word != '\0') {
+ if (!setFeature(word, choice)) {
+ sprintf(STR1, "No such feature: %s", word);
+ error(STR1, !print);
+ }
+ }
+ } while (*word != '\0');
+}
+
+
+Static void setRange(Char *line_)
+{
+ Char line[256];
+ short v, p;
+ Char vl[256];
+ short FORLIM;
+ Char STR1[256], STR2[256];
+
+ strcpy(line, line_);
+ line_no = orig_range_line;
+ FORLIM = nvoices;
+ for (v = 1; v <= FORLIM; v++) {
+ strcpy(vl, voice_label[v-1]);
+ sprintf(STR1, "%s=", vl);
+ p = strpos2(line, STR1, 1);
+ if (p > 0) {
+ if (strlen(line) < p + 6) {
+ sprintf(STR2, "At least five characters must follow \"%s=\"", vl);
+ error(STR2, print);
+ }
+ defineRange(v, substr_(STR2, line, p + strlen(vl) + 1, 5));
+ } else {
+ sprintf(STR2, "No range defined for voice %s", vl);
+ warning(STR2, print);
+ defineRange(v, "");
+ }
+ }
+}
+
+
+/* TODO: This procedure should test for assertions in a comment
+ or be removed */
+Static boolean isAssertion(Char *line)
+{
+ return false;
+}
+
+
+Static line_type doCommand(Char *line_)
+{
+ line_type Result;
+ Char line[256];
+ Char command[256];
+ command_type last_command;
+ boolean starts_with_note;
+ Char STR1[256];
+ Char STR3[70];
+ Char STR4[256];
+
+ strcpy(line, line_);
+ if (line[0] == comment && !isAssertion(line))
+ return comment_line;
+ starts_with_note = maybeMusicLine(line);
+ GetNextWord(command, line, blank_, colon_);
+ sprintf(STR1, "%c", colon_);
+ if (endsWith(command, STR1)) {
+ last_command = findCommand(command);
+ Result = command_line;
+ if (last_command == enable)
+ doEnable(line, true);
+ else if (last_command == disable)
+ doEnable(line, false);
+ else if (last_command == range)
+ orig_range_line = line_no;
+ if (last_command != none) {
+ if (mustAppend(last_command) && redefined[(long)last_command]) {
+ if (strlen(cline[(long)last_command]) + strlen(line) > 254) {
+ sprintf(STR3,
+ "Total length of preamble command %s must not exceed 255",
+ commands[(long)last_command]);
+ error(STR3, !print);
+ }
+ sprintf(cline[(long)last_command] + strlen(cline[(long)last_command]),
+ "\n%s", line);
+ } else {
+ strcpy(cline[(long)last_command], line);
+ if (warn_redefine && redefined[(long)last_command]) {
+ sprintf(STR4, "You have redefined preamble command %s", command);
+ warning(STR4, print);
+ }
+ }
+ if (last_command == start)
+ strcpy(start_line, line);
+ redefined[(long)last_command] = true;
+ return Result;
+ }
+ Result = colon_line;
+ sprintf(STR4, "%s%c %s", command, colon_, line);
+ addStyle(STR4);
+ orig_style_line[known_styles-1] = line_no;
+ return Result;
+ } else if (starts_with_note)
+ return plain_line;
+ else
+ return unknown;
+ return Result;
+}
+
+
+void setOnly(Char *line_)
+{
+ Char line[256];
+ short num, num1, num2, l;
+ Char s[256];
+ Char STR1[256];
+
+ strcpy(line, line_);
+ if (*line == '\0')
+ return;
+ if (startsWithIgnoreCase(line, "only"))
+ GetNextWord(STR1, line, colon_, dummy);
+ for (l = 0; l <= lines_in_paragraph - 1; l++)
+ omit_line[l] = true;
+ do {
+ GetNextWord(s, line, blank_, comma_);
+ if (*s == '\0')
+ return;
+ curtail(s, comma_);
+ if (pos1('-', s) == 0) {
+ getNum(s, &num);
+ if (num > 0 && num <= lines_in_paragraph)
+ omit_line[num-1] = false;
+ else
+ warning("Invalid line number in Only: is skipped", print);
+ } else {
+ getTwoNums(s, &num1, &num2);
+ if (num1 > 0 && num2 <= lines_in_paragraph) {
+ for (num = num1 - 1; num <= num2 - 1; num++)
+ omit_line[num] = false;
+ } else
+ warning("Invalid line range in Only: is skipped", print);
+ }
+ } while (true);
+}
+
+
+void interpretCommands(void)
+{
+ short i, num, den, nbars;
+ Char STR2[256];
+ short FORLIM;
+
+ strcpy(title_line, cline[(long)title]);
+ strcpy(part_line, cline[(long)part]);
+ if (*cline[(long)poet] != '\0' || *cline[(long)composer] != '\0')
+ sprintf(composer_line, "\\mtxComposerLine{%s}{%s}",
+ cline[(long)poet], cline[(long)composer]);
+ else
+ *composer_line = '\0';
+ strcpy(pmx_line, cline[(long)pmx]);
+ GetNextWord(options_line, cline[(long)options], blank_, dummy);
+ FORLIM = known_styles;
+ for (i = 0; i <= FORLIM - 1; i++)
+ style_used[i] = false;
+ applyStyles();
+ setVoices(voices);
+ FORLIM = known_styles;
+ for (i = old_known_styles; i <= FORLIM - 1; i++) {
+ if (!style_used[i]) {
+ warning("The following style was supplied but not used", !print);
+ puts(known_style[i]);
+ }
+ }
+ setClefs(clefs);
+ if (!redefined[(long)meter]) {
+ sprintf(STR2, "You have not defined Meter, assuming \"%s\" ",
+ cline[(long)meter]);
+ warning(STR2, !print);
+ }
+ getMeter(cline[(long)meter], &meternum, &meterdenom, &pmnum, &pmdenom);
+ setDefaultDuration(meterdenom);
+ if (meternum == 0 &&
+ !(redefined[(long)pages] || redefined[(long)systems] ||
+ redefined[(long)bars])) {
+ strcpy(cline[(long)bars], "1");
+ redefined[(long)bars] = true;
+ }
+ if (redefined[(long)pages] || redefined[(long)systems]) {
+ if (redefined[(long)bars])
+ warning("BARS/LINE ignored since you specified PAGES or SYSTEMS", print);
+ if (redefined[(long)systems])
+ getNum(cline[(long)systems], &n_systems);
+ else
+ warning("PAGES specified but not SYSTEMS", !print);
+ if (redefined[(long)pages])
+ getNum(cline[(long)pages], &n_pages);
+ else
+ warning("SYSTEMS specified but not PAGES", !print);
+ } else if (redefined[(long)bars]) {
+ getNum(cline[(long)bars], &nbars);
+ if (nbars > 0) {
+ n_pages = 0;
+ n_systems = nbars;
+ }
+ }
+ getNum(cline[(long)sharps], &n_sharps);
+ setSpace(cline[(long)space]);
+ setSize(cline[(long)msize]);
+ getTwoNums(cline[(long)shortnote], &num, &den);
+ if (den == 0)
+ den = 1;
+ short_note = num * 64 / den;
+ if (*cline[(long)flats] != '\0') {
+ getNum(cline[(long)flats], &n_sharps);
+ n_sharps = -n_sharps;
+ }
+ setName();
+ setIndent();
+ setInitOctave();
+ setOnly(cline[(long)only]);
+ setRange(cline[(long)range]);
+ setDimension(cline[(long)width], width);
+ setDimension(cline[(long)height], height);
+ if (*options_line != '\0') {
+ warning("\"Options\" is cryptic and obsolescent.", !print);
+ printf(" Use \"Enable\" and \"Disable\" instead.\n");
+ }
+ FORLIM = strlen(options_line);
+ for (i = 0; i <= FORLIM - 1; i++)
+ processOption(options_line[i]);
+}
+
+
+void preambleDefaults(void)
+{
+ short i;
+
+ xmtrnum0 = 0.0;
+ strcpy(fracindent, "0");
+ musicsize = 20;
+ *start_line = '\0';
+ some_vocal = false;
+ ngroups = 0;
+ style_supplied = false;
+ for (i = 1; i <= maxvoices; i++)
+ setVocal(i, false);
+ for (i = 0; i <= maxstaves - 1; i++)
+ stave_size[i] = unspec;
+ for (i = 0; i <= maxstaves; i++)
+ nspace[i] = unspec;
+ /* next line seems to be spurious. 0.63a RDT */
+ /* begin nspace[i]:=unspec; stave_size[i]:=unspec; end; */
+ n_pages = 1;
+ n_systems = 1;
+ readStyles();
+ old_known_styles = known_styles;
+ for (i = 0; i <= lines_in_paragraph - 1; i++)
+ omit_line[i] = false;
+}
+
+
+Static void preambleGuess(voice_index maybe_voices)
+{
+ switch (maybe_voices) {
+
+ case 1:
+ strcpy(cline[(long)style], "Solo");
+ break;
+
+ case 2:
+ strcpy(cline[(long)style], "Duet");
+ break;
+
+ case 3:
+ strcpy(cline[(long)style], "Trio");
+ break;
+
+ case 4:
+ strcpy(cline[(long)style], "Quartet");
+ break;
+
+ case 5:
+ strcpy(cline[(long)style], "Quintet");
+ break;
+
+ case 6:
+ strcpy(cline[(long)style], "Sextet");
+ break;
+
+ case 7:
+ strcpy(cline[(long)style], "Septet");
+ break;
+
+ default:
+ error("I cannot guess a style", !print);
+ return;
+ break;
+ }
+ printf("I guess this piece is a %s for strings in C major.\n",
+ cline[(long)style]);
+ printf(" Why not provide a STYLE in the setup paragraph to make sure?\n");
+}
+
+
+/* ------------------------------------------------------------------ */
+
+void nonMusic(void)
+{
+ paragraph_index i, FORLIM;
+
+ FORLIM = para_len;
+ for (i = 0; i <= FORLIM - 1; i++)
+ doCommand(P[i]);
+ setOnly(cline[(long)only]);
+ wipeCommands();
+}
+
+
+boolean thisCase(void)
+{
+ boolean Result;
+
+/* p2c: preamble.pas: Note: Eliminated unused assignment statement [338] */
+ if (!startsWithIgnoreCase(P[0], "case:"))
+ return true;
+ Result = (choice != ' ' && pos1(choice, P[0]) > 0);
+ strcpy(P[0], "%");
+ return Result;
+}
+
+
+void augmentPreamble(boolean control_para)
+{
+ paragraph_index i;
+ line_type l;
+ short s[5];
+ paragraph_index FORLIM;
+
+ if (!thisCase())
+ return;
+ for (l = unknown; l <= plain_line; l = (line_type)((long)l + 1))
+ s[(long)l] = 0;
+ FORLIM = para_len;
+ for (i = 0; i <= FORLIM - 1; i++) {
+ line_no = orig_line_no[i];
+ l = doCommand(P[i]);
+ s[(long)l]++;
+ if (l == comment_line && P[i][1] == comment) {
+ predelete(P[i], 2);
+ putLine(P[i]);
+ }
+ if (!control_para && l == unknown)
+ error("Unidentifiable line", print);
+ }
+ if (!control_para && s[(long)command_line] > 0 && s[(long)plain_line] > 0)
+ error("Mixture of preamble commands and music", !print);
+}
+
+
+void doPreamble(void)
+{
+ paragraph_index i;
+ voice_index0 maybe_voices = 0;
+ paragraph_index FORLIM;
+
+ if (style_supplied) /*augmentPreamble(not known);*/
+ return;
+ if (true)
+ warning("No STYLE supplied", !print);
+ FORLIM = para_len;
+ for (i = 0; i <= FORLIM - 1; i++) {
+ if (maybeMusicLine(P[i]))
+ maybe_voices++;
+ }
+ if (maybe_voices > 0)
+ preambleGuess(maybe_voices);
+ else
+ error("No voices found", !print);
+}
+
+
+void respace(void)
+{
+ stave_index i, j;
+ Char STR1[256];
+ Char STR2[256], STR3[256];
+
+ for (i = ninstr; i >= 2; i--) {
+ j = ninstr - i + 1;
+ if (nspace[j] != unspec) {
+ sprintf(STR3, "\\mtxInterInstrument{%s}{%s}",
+ toString(STR1, i - 1), toString(STR2, nspace[j]));
+ TeXtype2(STR3);
+ }
+ }
+ if (nspace[ninstr] != unspec) {
+ sprintf(STR3, "\\mtxStaffBottom{%s}", toString(STR1, nspace[ninstr]));
+ TeXtype2(STR3);
+ }
+ must_respace = false;
+}
+
+
+void restyle(void)
+{
+ must_restyle = false;
+}
+
+
+Static short clefno(Char cl)
+{
+ short Result;
+ Char STR2[44];
+
+ switch (cl) {
+
+ case 'G':
+ case '0':
+ case 't':
+ case '8':
+ Result = 0;
+ break;
+
+ case 's':
+ case '1':
+ Result = 1;
+ break;
+
+ case 'm':
+ case '2':
+ Result = 2;
+ break;
+
+ case 'a':
+ case '3':
+ Result = 3;
+ break;
+
+ case 'n':
+ case '4':
+ Result = 4;
+ break;
+
+ case 'r':
+ case '5':
+ Result = 5;
+ break;
+
+ case 'F':
+ case 'b':
+ case '6':
+ Result = 6;
+ break;
+
+ case 'C':
+ Result = 3;
+ break;
+
+ default:
+ sprintf(STR2, "Unknown clef code \"%c\" - replaced by treble", cl);
+ warning(STR2, print);
+ Result = 0;
+ break;
+ }
+ return Result;
+}
+
+
+Static void doTenorClefs(void)
+{
+ voice_index i;
+ Char c;
+ voice_index FORLIM;
+ Char STR1[256];
+ Char STR3[256];
+
+ FORLIM = nclefs;
+ for (i = 1; i <= FORLIM; i++) {
+ c = clef[i-1];
+ if (c == '8' || c == 't') {
+ sprintf(STR3, "\\\\mtxTenorClef{%s}\\", toString(STR1, PMXinstr(i)));
+ putLine(STR3);
+ }
+ }
+}
+
+
+Static void insertTeX(void)
+{
+ if (redefined[(long)tex])
+ TeXtype2(cline[(long)tex]);
+}
+
+
+Local Char *pmxMeter(Char *Result)
+{
+ short denom, num;
+ Char STR1[256], STR3[256], STR4[256], STR5[256];
+
+ if (meternum == 0) {
+ num = beatsPerLine(); /** denom := 0; **/
+ meterChange(old_meter_word, num, meterdenom, true);
+ } else
+ num = meternum; /** denom := pmdenom; **/
+ /* CMO: unconditonally assign value of pmdenom to denom */
+ denom = pmdenom;
+ sprintf(Result, "%s %s %s %s",
+ toString(STR1, num), toString(STR3, PMXmeterdenom(meterdenom)),
+ toString(STR4, pmnum), toString(STR5, denom));
+ return Result;
+}
+
+Local Char *sizecode(Char *Result, short k)
+{
+ strcpy(Result, "\\mtxNormalSize");
+ switch (k) {
+
+ case 13:
+ if (musicsize == 20)
+ strcpy(Result, "\\mtxTinySize");
+ else
+ strcpy(Result, "\\mtxSmallSize");
+ break;
+
+ case 16:
+ if (musicsize == 20)
+ strcpy(Result, "\\mtxSmallSize");
+ break;
+
+ case 20:
+ if (musicsize == 16)
+ strcpy(Result, "\\mtxLargeSize");
+ break;
+
+ case 24:
+ if (musicsize == 20)
+ strcpy(Result, "\\mtxLargeSize");
+ else
+ strcpy(Result, "\\mtxHugeSize");
+ break;
+
+ case 29:
+ strcpy(Result, "\\mtxHugeSize");
+ break;
+
+ default:
+ error("Valid sizes are 13, 16, 20, 24, 29", print);
+ break;
+ }
+ return Result;
+}
+
+
+void doPMXpreamble(void)
+{
+ static Char clefcode[9] = "0123456";
+ short i, j;
+ Char clefs[256];
+ Char STR1[256], STR2[256];
+ Char STR3[58];
+ short FORLIM;
+ Char STR5[256];
+
+ if (*composer_line != '\0')
+ putLine(composer_line);
+ if (*title_line != '\0') {
+ sprintf(STR2, "\\mtxTitleLine{%s}", title_line);
+ putLine(STR2);
+ }
+ putLine("---");
+ if (instrumentNames() && !redefined[(long)indent])
+ strcpy(fracindent, "0.12");
+ fprintf(outfile, "%d", nstaves);
+ fprintf(outfile, " %d", -ninstr);
+ stave[ninstr] = nstaves + 1;
+ for (j = ninstr; j >= 1; j--)
+ fprintf(outfile, " %d", stave[j] - stave[j-1]);
+ fprintf(outfile, " %s %8.5f %d %d %d %d %s\n",
+ pmxMeter(STR1), xmtrnum0, n_sharps, n_pages, n_systems, musicsize,
+ fracindent);
+ FORLIM = ninstr;
+ for (i = 1; i <= FORLIM; i++) {
+ if (!instrumentNames())
+ putLine("");
+ else {
+ sprintf(STR3, "\\mtxInstrName{%s}", instr_name[ninstr - i]);
+ putLine(STR3);
+ }
+ }
+ *clefs = '\0';
+ for (i = nclefs - 1; i >= 0; i--)
+ sprintf(clefs + strlen(clefs), "%c", clefcode[clefno(clef[i])]);
+ putLine(clefs);
+ if (*texdir == '\0')
+ strcpy(texdir, "./");
+ putLine(texdir);
+
+ pmx_preamble_done = true;
+ insertTeX();
+ respace();
+
+ FORLIM = ngroups;
+ for (j = 1; j <= FORLIM; j++)
+ fprintf(outfile, "\\\\mtxGroup{%s}{%s}{%s}\\\n",
+ toString(STR1, j), toString(STR2, ninstr - group_start[j-1] + 1),
+ toString(STR5, ninstr - group_stop[j-1] + 1));
+ FORLIM = ninstr;
+ for (j = 1; j <= FORLIM; j++) {
+ if (stave_size[j-1] != unspec) {
+ sprintf(STR5, "\\\\mtxSetSize{%s}{%s}\\",
+ toString(STR1, ninstr - j + 1),
+ sizecode(STR2, stave_size[j-1]));
+ putLine(STR5);
+ }
+ }
+ if (*part_line != '\0') {
+ putLine("Ti");
+ putLine(part_line);
+ }
+ if (*composer_line != '\0') {
+ putLine("Tc");
+ putLine("\\mtxPoetComposer");
+ }
+ if (*title_line != '\0') {
+ fprintf(outfile, "Tt");
+ if (nspace[0] != unspec)
+ fputs(toString(STR1, nspace[0]), outfile);
+ putc('\n', outfile);
+ putLine("\\mtxTitle");
+ }
+ if (*pmx_line != '\0')
+ putLine(pmx_line);
+ doTenorClefs();
+ if (*cline[(long)width] != '\0')
+ putLine(cline[(long)width]);
+ wipeCommands();
+}
+
+
+Char *startString(Char *Result, voice_index0 voice)
+{
+ Char s[256], w[256];
+ voice_index j;
+
+ strcpy(s, start_line);
+ for (j = 1; j <= voice; j++)
+ GetNextWord(w, s, dummy, ';');
+ curtail(w, ';');
+ if (*w != '\0') {
+ sprintf(Result, "%s ", w);
+ return Result;
+ } else
+ return strcpy(Result, w);
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/preamble.h b/Build/source/utils/m-tx/mtx-src/preamble.h
new file mode 100644
index 00000000000..6b6c4090e6f
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/preamble.h
@@ -0,0 +1,42 @@
+/* Header for module preamble, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef PREAMBLE_H
+#define PREAMBLE_H
+
+
+/*$X+*/
+/* Interpret preamble paragraph, compose PMX preamble */
+
+#ifndef GLOBALS_H
+#include "globals.h"
+#endif
+
+
+#ifdef PREAMBLE_G
+# define vextern
+#else
+# define vextern extern
+#endif
+
+extern boolean thisCase(void);
+extern void preambleDefaults(void);
+extern void interpretCommands(void);
+extern void doPreamble(void);
+extern void doPMXpreamble(void);
+extern void respace(void);
+extern void restyle(void);
+extern Char *startString(Char *Result, voice_index0 voice);
+extern void augmentPreamble(boolean control_para);
+extern boolean omitLine(paragraph_index line);
+extern void nonMusic(void);
+extern void setOnly(Char *line);
+extern boolean isCommand(Char *command);
+
+
+#define known true
+
+
+#undef vextern
+
+#endif /*PREAMBLE_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/preamble.pas b/Build/source/utils/m-tx/mtx-src/preamble.pas
new file mode 100644
index 00000000000..c27b9f7054f
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/preamble.pas
@@ -0,0 +1,706 @@
+unit preamble;
+{$X+}
+{ Interpret preamble paragraph, compose PMX preamble }
+
+interface uses globals;
+
+function thisCase: boolean;
+procedure preambleDefaults;
+procedure interpretCommands;
+procedure doPreamble;
+procedure doPMXpreamble;
+procedure respace;
+procedure restyle;
+function startString(voice: voice_index0): string;
+procedure augmentPreamble(control_para: boolean);
+function omitLine(line: paragraph_index): boolean;
+procedure nonMusic;
+procedure setOnly(line: string);
+function isCommand(command: string): boolean;
+
+const known = true;
+
+implementation uses control, mtxline, strings, files, status, utility;
+
+const blank = ' ';
+ colon = ':';
+ semicolon = ';';
+ comma = ',';
+ known_styles: integer = 12;
+ max_styles = 24;
+ warn_redefine: boolean = false;
+
+type command_type =
+ ( none, title, composer, pmx, tex, options, msize, bars, shortnote,
+ style, sharps, flats, meter, space, pages, systems, width, height,
+ enable, disable, range, name, indent,
+ poet, part, only, octave, start );
+
+ line_type = ( unknown, colon_line, command_line, comment_line,
+ plain_line );
+
+ style_index = 1..max_styles;
+ style_index0 = 0..max_styles;
+
+const c1 = title; cn = start;
+ commands: array[command_type] of string[16] =
+ ( 'NONE', 'TITLE', 'COMPOSER', 'PMX', 'TEX', 'OPTIONS',
+ 'SIZE', 'BARS/LINE', 'SHORT',
+ 'STYLE', 'SHARPS', 'FLATS', 'METER', 'SPACE', 'PAGES', 'SYSTEMS', 'WIDTH',
+ 'HEIGHT', 'ENABLE', 'DISABLE', 'RANGE',
+ 'NAME', 'INDENT', 'POET', 'PART', 'ONLY', 'OCTAVE', 'START');
+ cline: array[command_type] of string =
+ ( '', '', '', '', '', '', '', '', '1/4', (* short *)
+ '', '0', '', 'C', '', '1', '1', (* systems *)
+ '190mm', '260mm', '', '', '', '', '', '', '', '', '', '' );
+ redefined: array[command_type] of boolean =
+ ( false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false );
+
+(** Known styles *)
+ known_style: array[style_index] of string = (
+'SATB: Voices S,A T,B; Choral; Clefs G F',
+'SATB4: Voices S A T B; Choral; Clefs G G G8 F',
+'SINGER: Voices Voice; Vocal; Clefs G',
+'PIANO: Voices RH LH; Continuo; Clefs G F',
+'ORGAN: Voices RH LH Ped; Continuo; Clefs G F F',
+'SOLO: Voices V; Clefs G',
+'DUET: Voices V1 Vc; Clefs G F',
+'TRIO: Voices V1 Va Vc; Clefs G C F',
+'QUARTET: Voices V1 V2 Va Vc; Clefs G G C F',
+'QUINTET: Voices V1 V2 Va Vc1 Vc2; Clefs G G C F F',
+'SEXTET: Voices V1 V2 Va1 Va2 Vc1 Vc2; Clefs G G C C F F',
+'SEPTET: Voices V1 V2 Va1 Va2 Vc1 Vc2 Cb; Clefs G G C C F F F',
+'', '', '', '', '', '', '', '', '', '', '', '');
+
+var old_known_styles: style_index;
+ style_used: array[style_index] of boolean;
+ omit_line: array[paragraph_index] of boolean;
+ orig_style_line: array[style_index] of style_index0;
+ orig_range_line: integer;
+
+var nclefs, n_pages, n_systems, n_sharps, ngroups: integer;
+ part_line, title_line, composer_line, pmx_line, options_line,
+ start_line, voices, clefs: string;
+ group_start, group_stop: array[1..maxgroups] of integer;
+ instr_name: array[stave_index] of string[40];
+ style_supplied: boolean;
+
+{ ------------------ Styles ------------------ }
+
+function voiceCount(s: string): voice_index0;
+ var i, l: integer;
+ begin l:=length(s); for i:=1 to l do if s[i]=comma then s[i]:=blank;
+ voiceCount:=wordCount(s);
+ end;
+
+function findStyle(s: string): style_index0;
+ var i: style_index0;
+begin
+ i:=0; s:=s+colon; findStyle:=0;
+ while i<known_styles do
+ begin inc(i);
+ if startsWithIgnoreCase(known_style[i],s) then
+ begin findStyle:=i; exit; end;
+ end;
+end;
+
+procedure addStyle (S: string);
+ var sn: style_index0;
+begin
+ sn:=findStyle(NextWord(S,colon,dummy));
+ if sn>0 then known_style[sn] := S
+ else if known_styles < max_styles then
+ begin inc(known_styles);
+ known_style[known_styles] := S;
+ end
+ else error('Can''t add another style - table full',print);
+end;
+
+procedure readStyles;
+ var eofstyle: boolean;
+ S: string;
+ l: style_index0;
+begin if styleFileFound then eofstyle:=true else eofstyle := eof(stylefile);
+ l:=0;
+ while not eofstyle do
+ begin readln(stylefile,S); if S<>'' then
+ begin addStyle(S); inc(l); orig_style_line[known_styles]:=l; end;
+ eofstyle := eof(stylefile);
+ end;
+end;
+
+procedure applyStyle(s, stylename: string;
+ first_inst, first_stave: stave_index);
+ var clef, subline, subcommand: string;
+ i, last_inst, last_stave: stave_index0;
+ continuo, toosoon, vocal: boolean;
+ begin last_inst:=first_inst-1;
+ toosoon := false; continuo:=false; vocal := false;
+ subline:=GetNextWord(s,blank,colon);
+ while s<>'' do
+ begin subline:=GetNextWord(s,semicolon,dummy);
+ i:=curtail(subline,semicolon);
+ subcommand:=GetNextWord(subline,blank,dummy);
+ if equalsIgnoreCase(subcommand,'VOICES') then
+ begin voices:=voices+' '+subline;
+ last_stave := first_stave + wordCount(subline) - 1;
+ last_inst := first_inst + voiceCount(subline) - 1;
+ end
+ else if equalsIgnoreCase(subcommand,'CLEFS')
+ then
+ begin clef:=subline; clefs:=clefs+' '+clef; end
+ else if equalsIgnoreCase(subcommand,'VOCAL') then
+ if last_inst<first_inst then toosoon:=true
+ else begin some_vocal := true; vocal := true;
+ for i:=first_inst to last_inst do setVocal(i,true);
+ end
+ else if equalsIgnoreCase(subcommand,'CHORAL') or
+ equalsIgnoreCase(subcommand,'GROUP') then
+ if last_inst<first_inst then toosoon:=true
+ else begin
+ if equalsIgnoreCase(subcommand,'CHORAL') then
+ begin some_vocal := true; vocal := true;
+ for i:=first_inst to last_inst do setVocal(i,true);
+ end;
+ if ngroups=maxgroups then error('Too many groups',print)
+ else begin inc(ngroups);
+ group_start[ngroups] := first_stave;
+ group_stop[ngroups] := last_stave;
+ end
+ end
+ else if equalsIgnoreCase(subcommand,'CONTINUO') then continuo := true
+ else error('Subcommand ' + subcommand + ' in STYLE unknown',print);
+ if toosoon then
+ error('You must first give VOICES before specifying ' + subcommand,
+ print);
+ end;
+ if vocal and continuo then error(
+ 'A continuo instrument may not be vocal',print);
+ if wordCount(clef)<>last_stave-first_stave+1 then error(
+ 'Number of clefs does not match number of voices',print);
+ if (first_stave=last_stave) or continuo
+ then instr_name[first_stave]:=stylename
+ else for i:=first_stave to last_stave do instr_name[i]:='';
+ if continuo then
+ begin inc(ninstr); stave[ninstr] := first_stave;
+ for i:=first_stave to last_stave do instr[i]:=ninstr;
+ end
+ else for i:=first_stave to last_stave do
+ begin inc(ninstr); stave[ninstr] := i; instr[i] := ninstr;
+ end;
+ end;
+
+procedure applyStyles;
+ var n1, n2, sn: integer;
+ s: string;
+ begin voices:=''; clefs:=''; ninstr:=0;
+ while cline[style]<>'' do
+ begin n1:=voiceCount(voices)+1;
+ n2:=wordCount(voices)+1;
+ s:=GetNextWord(cline[style],blank,comma);
+ curtail(s,comma);
+ sn:=findStyle(s); if sn=0 then error ('Style ' + s +' unknown',print);
+ line_no := orig_style_line[sn]; applyStyle(known_style[sn],s,n1,n2);
+ style_used[sn] := true;
+ end;
+ end;
+
+{ ------------------------------------------------------------- }
+
+procedure wipeCommands;
+ var c: command_type;
+begin for c:=c1 to cn do cline[c]:='';
+end;
+
+function omitLine(line: paragraph_index): boolean;
+begin omitLine := (line>0) and omit_line[line]
+end;
+
+procedure setName;
+ var i: integer;
+begin if not redefined[name] then exit;
+ setFeature('instrumentNames',true);
+ for i:=1 to ninstr do
+ instr_name[i] := getNextWord(cline[name],blank,dummy);
+end;
+
+procedure setIndent;
+begin if redefined[indent] then fracindent := cline[indent];
+end;
+
+procedure setInitOctave;
+begin if redefined[octave] then initOctaves(cline[octave]);
+end;
+
+procedure setVoices(var line: string);
+ var k: integer;
+ s, w: string;
+ procedure checkLabel(w: string);
+ var j: voice_index;
+ begin
+ for j:=1 to nvoices do if w=voice_label[j] then
+ begin warning('Voice label '+w+' not unique',print); exit;
+ end;
+ if length(w)>2 then exit;
+ if pos1(w[1],'CLU')>0 then
+ if length(w)>1 then if pos1(w[2],'123456789')=0 then exit
+ else
+ else
+ else if pos1(w[1],'123456789')=0 then exit;
+ error('Voice label '+w+' conflicts with reserved label',print);
+ end;
+begin nvoices:=0; nstaves:=0;
+ repeat s:=GetNextWord(line,blank,dummy);
+ if length(s)>0 then
+ begin inc(nstaves); k:=0;
+ first_on_stave[nstaves] := nvoices + 1;
+ repeat
+ w:=GetNextWord(s,blank,comma); curtail(w, comma);
+ if w<>'' then
+ begin
+ inc(k); if k<=2 then
+ begin inc(nvoices); checkLabel(w);
+ voice_label[nvoices]:=w;
+ if instr_name[nstaves]='' then instr_name[nstaves]:=w;
+ setStavePos(nvoices,nstaves,k);
+ end
+ end;
+ until w='';
+ if k>2 then error('More than two voices per stave: ' + s,print);
+ if k=2 then instr_name[nstaves]:='\mtxTwoInstruments{'
+ + voice_label[nvoices-1] + '}{'+ voice_label[nvoices] + '}';
+ number_on_stave[nstaves] := k;
+ end
+ until length(line)=0;
+ for k:=1 to nvoices do selected[k]:=true;
+end;
+
+procedure setClefs(line: string);
+ var s: string;
+begin
+ nclefs:=0;
+ repeat
+ s:=getnextword(line,blank,dummy);
+ if s<>'' then
+ begin inc(nclefs);
+ if length(s)=1 then clef[nclefs]:=s[1] else clef[nclefs]:=s[2];
+ end;
+ until s='';
+end;
+
+procedure setDimension(line: string; lno: command_type);
+ var l, n, p: integer;
+begin
+ if line = '' then exit;
+ l := length(line);
+ n := 0;
+ p := 0;
+ repeat n := n+1;
+ if line[n]='.' then p:=p+1;
+ until (n>l) or not ((line[n]='.') or (line[n]>='0') and (line[n]<='9'));
+ if (n=p) or (p>1) or
+ not ((line[n]='i') or (line[n]='m') or (line[n]='p')) then
+ error('Dimension must be a number followed by in, mm or pt',print);
+ cline[lno] := 'w' + substr(line,1,n);
+end;
+
+procedure setSize(line: string);
+ var i: stave_index0;
+ word: string;
+ begin i:=0;
+ while i<ninstr do
+ begin word:=GetNextWord(line,blank,dummy);
+ if word='' then break;
+ inc(i); getNum(word,musicsize);
+ stave_size[i] := musicsize;
+ end;
+ if not (musicsize in [16,20]) then
+ for i:=1 to ninstr do
+ if stave_size[i] = unspec then stave_size[i] := musicsize;
+ if musicsize<16 then musicsize:=16
+ else if musicsize>20 then musicsize:=20;
+ end;
+
+function findCommand(var command: string): command_type;
+ var j: command_type;
+begin curtail(command,':');
+ if equalsIgnoreCase(command,'STYLE') then style_supplied := true;
+ for j:=c1 to cn do if equalsIgnoreCase(command,commands[j]) then
+ begin findCommand:=j; exit; end;
+ findCommand:=none;
+end;
+
+function isCommand(command: string): boolean;
+begin isCommand:=findCommand(command)<>none end;
+
+function mustAppend(command: command_type): boolean;
+begin mustAppend := command=tex end;
+
+procedure doEnable(var line: string; choice: boolean);
+ var word: string;
+begin
+ repeat word:=GetNextWord(line,blank,dummy);
+ if word<>'' then if not setFeature(word,choice) then
+ Error('No such feature: '+word,not print)
+ until word=''
+end;
+
+procedure setRange(line: string);
+ var v,p: integer;
+ vl: string;
+begin
+ line_no := orig_range_line;
+ for v:=1 to nvoices do
+ begin vl := voice_label[v];
+ p:=pos(vl+'=',line);
+ if p>0 then
+ begin
+ if length(line)<p+6 then
+ error('At least five characters must follow "'+vl+'="',
+ print);
+ defineRange(v,substr(line,p+1+length(vl),5));
+ end
+ else begin
+ warning('No range defined for voice '+vl,print);
+ defineRange(v,'');
+ end
+ end;
+end;
+
+{ TODO: This procedure should test for assertions in a comment
+ or be removed }
+function isAssertion(var line: string): boolean;
+begin
+ isAssertion := false
+end;
+
+function doCommand(line: string): line_type;
+ var command: string;
+ last_command: command_type;
+ starts_with_note: boolean;
+begin
+ if (line[1]=comment) and not isAssertion(line) then
+ begin doCommand:=comment_line; exit; end;
+ starts_with_note := maybeMusicLine(line);
+ command:=GetNextWord(line,blank,colon);
+ if endsWith(command,colon) then
+ begin last_command:=findCommand(command);
+ doCommand:=command_line;
+ if last_command = enable then doEnable(line,true)
+ else if last_command = disable then doEnable(line,false)
+ else if last_command = range then orig_range_line := line_no;
+ if last_command<>none then
+ begin
+ if mustAppend(last_command) and redefined[last_command] then
+ begin
+ if length(cline[last_command])+length(line)>254 then
+ error('Total length of preamble command '+commands[last_command]+
+ ' must not exceed 255',not print);
+ cline[last_command]:=cline[last_command]+#10+line
+ end
+ else
+ begin cline[last_command]:=line;
+ if warn_redefine and redefined[last_command] then
+ warning('You have redefined preamble command '+command,print);
+ end;
+ if last_command=start then start_line:=line;
+ redefined[last_command]:=true;
+ end
+ else begin doCommand:=colon_line; addStyle(command+colon+' '+line);
+ orig_style_line[known_styles] := line_no;
+ end
+ end
+ else if starts_with_note then doCommand:=plain_line
+ else doCommand:=unknown;
+end;
+
+procedure setOnly(line: string);
+ var num, num1, num2, l: integer;
+ s: string;
+begin if line='' then exit;
+ if startsWithIgnoreCase(line,'only') then GetNextWord(line,colon,dummy);
+ for l:=1 to lines_in_paragraph do omit_line[l]:=true;
+ repeat s:=GetNextWord(line,blank,comma); if s='' then exit;
+ curtail(s, comma);
+ if pos1('-',s)=0 then
+ begin getNum(s,num);
+ if (num>0) and (num<=lines_in_paragraph) then omit_line[num]:=false
+ else warning('Invalid line number in Only: is skipped',print);
+ end else
+ begin getTwoNums(s,num1,num2);
+ if (num1>0) and (num2<=lines_in_paragraph) then
+ for num:=num1 to num2 do omit_line[num]:=false
+ else warning('Invalid line range in Only: is skipped',print);
+ end;
+ until false;
+end;
+
+procedure interpretCommands;
+ var i, num, den, nbars: integer;
+begin
+ title_line := cline[title];
+ part_line := cline[part];
+ if (cline[poet]<>'') or (cline[composer]<>'') then
+ composer_line:='\mtxComposerLine{'+cline[poet]+'}{'+cline[composer]+'}'
+ else composer_line:='';
+ pmx_line := cline[pmx];
+ options_line := GetNextWord(cline[options],blank,dummy);
+ for i:=1 to known_styles do style_used[i] := false;
+ applyStyles; setVoices(voices);
+ for i:=old_known_styles+1 to known_styles do
+ if not style_used[i] then
+ begin warning('The following style was supplied but not used',not print);
+ writeln(known_style[i]);
+ end;
+ setClefs(clefs);
+ if not redefined[meter] then warning(
+ 'You have not defined Meter, assuming "'+cline[meter]+'" ',not print);
+ getMeter(cline[meter],meternum, meterdenom, pmnum, pmdenom);
+ setDefaultDuration(meterdenom);
+ if (meternum=0) and
+ not (redefined[pages] or redefined[systems] or redefined[bars])
+ then begin cline[bars] := '1'; redefined[bars]:=true; end;
+ if redefined[pages] or redefined[systems] then
+ begin if redefined[bars] then
+ warning('BARS/LINE ignored since you specified PAGES or SYSTEMS',print);
+ if redefined[systems] then getNum(cline[systems],n_systems)
+ else warning('PAGES specified but not SYSTEMS',not print);
+ if redefined[pages] then getNum(cline[pages],n_pages)
+ else warning('SYSTEMS specified but not PAGES',not print);
+ end
+ else if redefined[bars] then
+ begin getNum(cline[bars],nbars); if nbars>0 then
+ begin n_pages:=0; n_systems:=nbars end;
+ end;
+ getNum(cline[sharps],n_sharps);
+ setSpace(cline[space]);
+ setSize(cline[msize]);
+ getTwoNums(cline[shortnote],num, den); if den=0 then den:=1;
+ short_note := (num*64) div den;
+ if cline[flats]<>'' then
+ begin getNum(cline[flats],n_sharps); n_sharps:=-n_sharps; end;
+ setName; setIndent; setInitOctave; setOnly(cline[only]);
+ setRange(cline[range]);
+ setDimension(cline[width],width);
+ setDimension(cline[height],height);
+ if options_line <>'' then begin
+ warning('"Options" is cryptic and obsolescent.', not print);
+ writeln(' Use "Enable" and "Disable" instead.')
+ end;
+ for i:=1 to length(options_line) do processOption(options_line[i]);
+end;
+
+procedure preambleDefaults;
+ var i: integer;
+begin
+ xmtrnum0:=0; fracindent:='0'; musicsize:=20; start_line:='';
+ some_vocal:=false; ngroups:=0;
+ style_supplied := false;
+ for i:=1 to maxvoices do setVocal(i,false);
+ for i:=1 to maxstaves do stave_size[i]:=unspec;
+ for i:=0 to maxstaves do nspace[i]:=unspec;
+ { next line seems to be spurious. 0.63a RDT }
+ { begin nspace[i]:=unspec; stave_size[i]:=unspec; end; }
+ n_pages:=1; n_systems:=1;
+ readStyles; old_known_styles := known_styles;
+ for i:=1 to lines_in_paragraph do omit_line[i]:=false;
+end;
+
+procedure preambleGuess(maybe_voices: voice_index);
+begin
+ case maybe_voices of
+ 1: cline[style] := 'Solo';
+ 2: cline[style] := 'Duet';
+ 3: cline[style] := 'Trio';
+ 4: cline[style] := 'Quartet';
+ 5: cline[style] := 'Quintet';
+ 6: cline[style] := 'Sextet';
+ 7: cline[style] := 'Septet';
+ else begin error('I cannot guess a style',not print); exit; end;
+ end;
+ writeln('I guess this piece is a ',cline[style],
+ ' for strings in C major.');
+ writeln(' Why not provide a STYLE in the setup paragraph to make sure?');
+end;
+
+{ ------------------------------------------------------------------ }
+
+procedure nonMusic;
+ var i: paragraph_index;
+begin for i:=1 to para_len do doCommand(P[i]);
+ setOnly(cline[only]); wipeCommands;
+end;
+
+function thisCase: boolean;
+begin thisCase:=true;
+ if not startsWithIgnoreCase(P[1],'case:') then exit;
+ thisCase:=(choice<>' ') and (pos1(choice,P[1])>0); P[1]:='%';
+end;
+
+procedure augmentPreamble(control_para: boolean);
+ var i: paragraph_index;
+ l: line_type;
+ s: array[line_type] of integer;
+begin
+ if not thisCase then exit;
+ for l:=unknown to plain_line do s[l]:=0;
+ for i:=1 to para_len do
+ begin line_no:=orig_line_no[i]; l:=doCommand(P[i]);
+ inc(s[l]);
+ if (l=comment_line) and (P[i,2]=comment)
+ then begin predelete(P[i],2); putLine(P[i]); end;
+ if not control_para and (l=unknown) then
+ error('Unidentifiable line',print);
+ end;
+ if not control_para and (s[command_line]>0) and (s[plain_line]>0)
+ then error('Mixture of preamble commands and music',not print);
+end;
+
+procedure doPreamble;
+ var i: paragraph_index;
+ maybe_voices: voice_index0;
+begin maybe_voices:=0;
+ if not style_supplied then
+ begin {augmentPreamble(not known);}
+ if not style_supplied then warning('No STYLE supplied',not print);
+ for i:=1 to para_len do if maybeMusicLine(P[i]) then
+ inc(maybe_voices);
+ if maybe_voices>0 then preambleGuess(maybe_voices)
+ else error('No voices found',not print);
+ end
+end;
+
+procedure respace;
+ var i, j: stave_index;
+ begin
+ for i:=ninstr downto 2 do
+ begin j:=ninstr-i+1;
+ if nspace[j]<>unspec then TeXtype2('\mtxInterInstrument{'+toString(i-1)+
+ '}{'+toString(nspace[j])+'}');
+ end;
+ if nspace[ninstr]<>unspec then TeXtype2('\mtxStaffBottom{'+
+ toString(nspace[ninstr])+'}');
+ must_respace:=false;
+ end;
+
+procedure restyle;
+begin
+ must_restyle:=false;
+end;
+
+function clefno ( cl: char ): integer;
+begin
+ case cl of
+'G','0','t','8': clefno:=0;
+'s','1': clefno:=1;
+'m','2': clefno:=2;
+'a','3': clefno:=3;
+'n','4': clefno:=4;
+'r','5': clefno:=5;
+'F','b','6': clefno:=6;
+'C': clefno:=3;
+ else
+ begin warning('Unknown clef code "' + cl + '" - replaced by treble',print);
+ clefno:=0;
+ end;
+ end
+end;
+
+procedure doTenorClefs;
+ var i: voice_index;
+ c: char;
+begin for i:=1 to nclefs do
+ begin
+ c:=clef[i]; if (c='8') or (c='t') then
+ putLine('\\mtxTenorClef{' + toString(PMXinstr(i)) + '}\' );
+ end;
+end;
+
+procedure insertTeX;
+begin
+ if redefined[tex] then TeXtype2(cline[tex]);
+end;
+
+procedure doPMXpreamble;
+ const clefcode: string[8]='0123456';
+ var i, j: integer;
+ clefs: string;
+ function pmxMeter: string;
+ var denom, num: integer;
+ begin if meternum=0 then
+ begin num := beatsPerLine; {* denom := 0; *}
+ old_meter_word := meterChange(num,meterdenom,true);
+ end
+ else begin num := meternum; {* denom := pmdenom; *} end;
+ { CMO: unconditonally assign value of pmdenom to denom }
+ denom := pmdenom;
+ pmxMeter := toString(num) + ' ' + toString(PMXmeterdenom(meterdenom)) +
+ ' ' + toString(pmnum) + ' ' + toString(denom);
+ end;
+ function sizecode(k: integer): string;
+ begin sizecode:='\mtxNormalSize';
+ case k of
+13: if musicsize=20 then sizecode:='\mtxTinySize' else sizecode:='\mtxSmallSize';
+16: if musicsize=20 then sizecode:='\mtxSmallSize';
+20: if musicsize=16 then sizecode:='\mtxLargeSize';
+24: if musicsize=20 then sizecode:='\mtxLargeSize' else sizecode:='\mtxHugeSize';
+29: sizecode:='\mtxHugeSize';
+ else error('Valid sizes are 13, 16, 20, 24, 29',print);
+ end;
+ end;
+begin
+ if composer_line <> '' then putline(composer_line);
+ if title_line <> '' then putline('\mtxTitleLine{'+title_line+'}');
+ putLine('---');
+ if instrumentNames and not redefined[indent] then fracindent:='0.12';
+ write(outfile, nstaves);
+ write(outfile, ' ', -ninstr);
+ stave[ninstr+1]:=nstaves+1;
+ for j:=ninstr downto 1 do write(outfile, ' ', stave[j+1] - stave[j]);
+ writeln(outfile, ' ', pmxMeter, ' ',xmtrnum0:8:5, ' ',n_sharps,
+ ' ', n_pages, ' ',n_systems, ' ',musicsize, ' ',fracindent);
+ for i:=1 to ninstr do if not instrumentNames then putLine('')
+ else putLine('\mtxInstrName{'+instr_name[ninstr+1-i]+'}');
+ clefs:='';
+ for i:=nclefs downto 1 do clefs:=clefs+clefcode[1+clefno(clef[i])];
+ putLine(clefs);
+ if texdir='' then texdir := './';
+ putLine(texdir);
+
+ pmx_preamble_done:=true; insertTeX; respace;
+
+ for j:=1 to ngroups do
+ writeln(outfile,'\\mtxGroup{'+toString(j)+'}{'
+ +toString(ninstr+1-group_start[j])+'}{'
+ +toString(ninstr+1-group_stop[j])+'}\');
+ for j:=1 to ninstr do
+ if (stave_size[j]<>unspec) then
+ putLine(
+ '\\mtxSetSize{'+toString(ninstr+1-j)+'}{'+sizecode(stave_size[j])+'}\');
+ if part_line <> '' then
+ begin putLine('Ti'); putLine(part_line); end;
+ if composer_line <> '' then
+ begin putLine('Tc'); putLine('\mtxPoetComposer'); end;
+ if title_line <> '' then
+ begin write(outfile,'Tt');
+ if nspace[0] <> unspec then write(outfile,toString(nspace[0]));
+ writeln(outfile);
+ putLine('\mtxTitle');
+ end;
+ if pmx_line <> '' then putLine(pmx_line);
+ doTenorClefs;
+ if cline[width] <> '' then putLine(cline[width]);
+ wipeCommands;
+end;
+
+function startString(voice: voice_index0): string;
+ var s, w: string;
+ j: voice_index;
+begin s:=start_line;
+ for j:=1 to voice do w:=getNextWord(s,dummy,';');
+ curtail(w,';'); if w<>'' then startString:=w+' ' else startString:=w;
+end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/prepmx.c b/Build/source/utils/m-tx/mtx-src/prepmx.c
new file mode 100644
index 00000000000..a3d37070c27
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/prepmx.c
@@ -0,0 +1,809 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "prepmx.pas" */
+
+
+#include "p2c.h"
+
+
+#ifndef CONTROL_H
+#include "control.h"
+#endif
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+#ifndef GLOBALS_H
+#include "globals.h"
+#endif
+
+#ifndef PREAMBLE_H
+#include "preamble.h"
+#endif
+
+#ifndef LYRICS_H
+#include "lyrics.h"
+#endif
+
+#ifndef MTX_H
+#include "mtx.h"
+#endif
+
+#ifndef ANALYZE_H
+#include "analyze.h"
+#endif
+
+#ifndef MTXLINE_H
+#include "mtxline.h"
+#endif
+
+#ifndef STATUS_H
+#include "status.h"
+#endif
+
+#ifndef UPTEXT_H
+#include "uptext.h"
+#endif
+
+#ifndef NOTES_H
+#include "notes.h"
+#endif
+
+#ifndef MULTFILE_H
+#include "multfile.h"
+#endif
+
+#ifndef FILES_H
+#include "files.h"
+#endif
+
+#ifndef UTILITY_H
+#include "utility.h"
+#endif
+
+
+/* CMO: addition/change by Christian Mondrup */
+
+/** M-Tx preprocessor to PMX Dirk Laurie */
+
+#define version "0.63a"
+#define version_date "<8 April 2018>"
+
+/** See file "Corrections" for updates */
+
+/** To do next:
+{* Current bugs:
+{* Old bugs:
+ Does not check PMX syntax
+{* Weaknesses that may later cause bugs:
+ Decisions sometimes made on note, sometimes on scan
+ Can 'here' overrun?
+ Where does one note stop and the next begin?
+ See comment on '!' in uptext
+*/
+
+#define chord_flat 't'
+#define chord_left 'l'
+
+#define blind true
+#define visible false
+
+
+Static boolean last_bar;
+Static Char repeat_sign[256];
+/*, bars_of_rest*/
+Static short bar_of_line;
+
+
+/* --------------- Bars and rests --------------- */
+
+Static void writeRepeat(Char *bar)
+{
+ Char repcode[256];
+ Char STR1[256];
+
+ if (*bar == '\0')
+ return;
+ *repcode = '\0';
+ if (!strcmp(bar, "||"))
+ strcpy(repcode, "Rd");
+ else if (!strcmp(bar, "|]"))
+ strcpy(repcode, "RD");
+ else if (!strcmp(bar, "|:"))
+ strcpy(repcode, "Rl");
+ else if (!strcmp(bar, ":|:"))
+ strcpy(repcode, "Rlr");
+ else if (!strcmp(bar, ":|"))
+ strcpy(repcode, "Rr");
+ else if (last_bar && !strcmp(bar, "|"))
+ strcpy(repcode, "Rb");
+ if (*repcode != '\0') {
+ sprintf(STR1, " %s", repcode);
+ putLine(STR1);
+ }
+ *bar = '\0';
+}
+
+
+Static void supplyRests(voice_index voice)
+{
+ Char STR2[4];
+ Char STR3[256];
+
+ if (bar_of_line == 1 && pedanticWarnings()) {
+ printf("Bar %d Voice %d", bar_no, voice);
+ warning(" Filling missing voice with rests", !print);
+ }
+ if (pickup > 0)
+ put(rests(STR3, pickup, meterdenom, visible), nospace);
+ sprintf(STR2, "%s ", pause);
+ put(STR2, putspace);
+}
+
+
+/* Local variables for processLine: */
+struct LOC_processLine {
+ voice_index voice;
+ Char chords[256], note[256], cutnote[256], pretex[256];
+ short ngrace, nmulti;
+ boolean no_chords, no_uptext;
+
+ short l;
+ boolean in_group;
+} ;
+
+Local void output(Char *note_, struct LOC_processLine *LINK)
+{
+ Char note[256];
+ Char STR2[256];
+
+ strcpy(note, note_);
+ if (*note != '\0')
+ { /* pretex is saved up until a spacing note or rest comes */
+ if (endsWith(note, "\\") && note[1] != '\\') {
+ curtail(note, '\\');
+ strcat(LINK->pretex, note);
+ *note = '\0';
+ return;
+ }
+ if (*LINK->pretex != '\0' && isNoteOrRest(note)) {
+ sprintf(note, "%s\\ %s", LINK->pretex, strcpy(STR2, note));
+ *LINK->pretex = '\0';
+ }
+ if (outlen > 0 && note[0] != ' ')
+ sprintf(note, " %s", strcpy(STR2, note));
+ put(note, nospace);
+ }
+ if (thisNote(LINK->voice) == nextvoice)
+ putLine("");
+}
+
+Local void maybeDotted(Char *note, struct LOC_processLine *LINK)
+{
+ if (strlen(note) < 2)
+ return;
+ if (note[1] == '"') {
+ note[1] = note[0];
+ strcat(LINK->pretex, "\\mtxDotted");
+ }
+}
+
+/* Local variables for addChords: */
+struct LOC_addChords {
+ struct LOC_processLine *LINK;
+ Char nt[256], labels[256];
+ boolean tieme;
+ Char lab;
+ int5 pitches;
+} ;
+
+Local void outChord(struct LOC_addChords *LINK)
+{
+ short k;
+ Char STR2[256];
+ short FORLIM;
+
+ if (*LINK->nt == '\0')
+ return;
+ LINK->tieme = (LINK->nt[0] == '{');
+ if (LINK->tieme)
+ predelete(LINK->nt, 1);
+ if (*LINK->nt == '\0' || LINK->nt[0] < 'a' || LINK->nt[0] > 'g') {
+ sprintf(STR2, "Must have a note name at the start of \"%s\", not \"%c\"",
+ LINK->nt, LINK->nt[0]);
+ error(STR2, print);
+ }
+ renewChordPitch(LINK->LINK->voice, LINK->nt);
+ sprintf(LINK->LINK->chords + strlen(LINK->LINK->chords), " z%s", LINK->nt);
+ *LINK->nt = '\0';
+ FORLIM = strlen(LINK->labels);
+ for (k = 0; k <= FORLIM - 1; k++) {
+ if (chordPitch(LINK->LINK->voice) == LINK->pitches[k]) {
+ sprintf(LINK->LINK->chords + strlen(LINK->LINK->chords), " s%ct",
+ LINK->labels[k]);
+ LINK->labels[k] = ' ';
+ }
+ }
+ if (LINK->tieme) {
+ chordTie(LINK->LINK->voice, &LINK->lab);
+ sprintf(LINK->LINK->chords + strlen(LINK->LINK->chords), " s%ct",
+ LINK->lab);
+ }
+}
+
+Local void addChords(struct LOC_processLine *LINK)
+{
+ struct LOC_addChords V;
+ Char w[256];
+ short j = 1;
+ short mus_line;
+ paragraph_index0 chord_line;
+ boolean arpeggio;
+ Char STR1[256];
+ short FORLIM;
+
+ V.LINK = LINK;
+ saveStatus(LINK->voice);
+ getChordTies(LINK->voice, V.pitches, V.labels);
+ *LINK->chords = '\0';
+ chord_line = chordLineNo(LINK->voice);
+ if (chord_line == 0)
+ LINK->no_chords = true;
+ if (LINK->no_chords)
+ return;
+ GetNextWord(w, P[chord_line-1], blank, dummy);
+ sprintf(STR1, "%c", barsym);
+ if (!strcmp(w, STR1) || *w == '\0')
+ LINK->no_chords = true;
+ sprintf(STR1, "%c", tilde);
+ if (!strcmp(w, STR1) || LINK->no_chords)
+ return;
+ mus_line = line_no;
+ line_no = orig_line_no[chord_line-1];
+ arpeggio = (w[0] == '?');
+ if (arpeggio) {
+ strcpy(LINK->chords, " ?");
+ predelete(w, 1);
+ }
+ *V.nt = '\0';
+ while (j <= strlen(w)) {
+ if (w[j-1] == '{' || strcmp(V.nt, "{") && w[j-1] >= 'a' && w[j-1] <= 'g')
+ outChord(&V);
+ else if (w[j-1] == chord_flat)
+ w[j-1] = 'f';
+ else if (w[j-1] == chord_left)
+ w[j-1] = 'e';
+ sprintf(V.nt + strlen(V.nt), "%c", w[j-1]);
+ j++;
+ }
+ if (*V.nt != '\0')
+ outChord(&V);
+ if (arpeggio)
+ strcat(LINK->chords, " ?");
+ strcat(LINK->note, LINK->chords);
+ FORLIM = strlen(V.labels);
+ for (j = 0; j <= FORLIM - 1; j++) {
+ if (V.labels[j] != ' ')
+ error("Tie on chord note started but not finished", print);
+ }
+ line_no = mus_line;
+}
+
+Local Char *processOther(Char *Result, Char *note_,
+ struct LOC_processLine *LINK)
+{
+ Char note[256];
+
+ strcpy(note, note_);
+ switch (thisNote(LINK->voice)) {
+
+ case other:
+ if (note[0] == grace_group) {
+ if (strlen(note) == 1)
+ LINK->ngrace = 1;
+ else
+ LINK->ngrace = pos1(note[1], digits);
+ if (LINK->ngrace > 0)
+ LINK->ngrace--;
+ }
+ break;
+
+ /* For a zword, take note of pitch but do not change the contents */
+ /* Add spurious duration because repitch expects duration to be present */
+ case zword:
+ strcpy(LINK->cutnote, note);
+ predelete(LINK->cutnote, 1);
+ insertChar('4', LINK->cutnote, 2);
+ checkOctave(LINK->voice, LINK->cutnote);
+ renewPitch(LINK->voice, LINK->cutnote);
+ break;
+
+ case lyrtag:
+ extractLyrtag(LINK->voice, note);
+ break;
+
+ case rbrac:
+ endBeam(LINK->voice);
+ break;
+
+ case rparen:
+ case rlparen:
+ endSlur(LINK->voice, note);
+ break;
+
+ case lbrac:
+ beginBeam(LINK->voice, note);
+ break;
+
+ case lparen:
+ maybeDotted(note, LINK);
+ beginSlur(LINK->voice, note);
+ break;
+
+ case mword:
+ error3(LINK->voice, "Meter change must be the first word of its bar");
+ break;
+
+ case atword:
+ lyricsAdjust(LINK->voice, note);
+ break;
+ }
+ return strcpy(Result, note);
+}
+
+Local void lookahead(struct LOC_processLine *LINK)
+{
+ Char STR2[256];
+ Char STR3[256];
+
+ while (bind_left[(long)nextNote(LINK->voice)])
+ sprintf(LINK->note + strlen(LINK->note), " %s",
+ processOther(STR2, getMusicWord(STR3, LINK->voice), LINK));
+}
+
+Local void processUsual(struct LOC_processLine *LINK)
+{
+ if (hasVerseNumber(LINK->voice))
+ strcat(LINK->pretex, "\\mtxVerse");
+ LINK->l = pos1(multi_group, LINK->note);
+ if (LINK->l > 0)
+ scan1(LINK->note, LINK->l + 1, &LINK->nmulti);
+ activateBeamsAndSlurs(LINK->voice);
+ LINK->in_group = false;
+ if (LINK->ngrace > 0) {
+ LINK->in_group = true;
+ LINK->ngrace--;
+ } else {
+ if (LINK->nmulti > 0) {
+ LINK->in_group = true;
+ LINK->nmulti--;
+ }
+ }
+ checkOctave(LINK->voice, LINK->note);
+ renewPitch(LINK->voice, LINK->note);
+ if (!LINK->in_group) {
+ resetDuration(LINK->voice, durationCode(LINK->note));
+ markDebeamed(LINK->voice, LINK->note);
+ }
+ lookahead(LINK);
+ getSyllable(LINK->voice, LINK->pretex);
+ addUptext(LINK->voice, &LINK->no_uptext, LINK->pretex);
+ addChords(LINK);
+}
+
+
+/* ---------------------------------------------------------------- */
+
+Static void processLine(voice_index voice_, short bar_no)
+{
+ struct LOC_processLine V;
+ paragraph_index par_line;
+ Char STR1[256];
+
+ V.voice = voice_;
+ *V.pretex = '\0';
+ V.no_chords = false;
+ V.no_uptext = false;
+ par_line = musicLineNo(V.voice);
+ V.nmulti = 0;
+ V.ngrace = 0;
+ line_no = orig_line_no[par_line-1];
+ do {
+ getMusicWord(V.note, V.voice);
+ if (*V.note == '\0')
+ return;
+ /* if debugMode then writeln(voice,' ',note); */
+ switch (thisNote(V.voice)) {
+
+ case rword:
+ if (*multi_bar_rest != '\0') {
+ if (uptextOnRests())
+ addUptext(V.voice, &V.no_uptext, V.pretex);
+ } else {
+ V.l = pos1(multi_group, V.note);
+ if (V.l > 0)
+ scan1(V.note, V.l + 1, &V.nmulti);
+ if (V.nmulti > 0) {
+ V.in_group = true;
+ V.nmulti--;
+ }
+ if (uptextOnRests())
+ addUptext(V.voice, &V.no_uptext, V.pretex);
+ if (!(isPause(V.note) || V.in_group))
+ /*0.63: allow rests in xtuples*/
+ resetDuration(V.voice, durationCode(V.note));
+ }
+ break;
+
+ case abcdefg:
+ processUsual(&V);
+ break;
+
+ case barword:
+ if (V.voice == nvoices) {
+ if (endOfBar(V.voice, bar_no))
+ strcpy(repeat_sign, V.note);
+ else
+ writeRepeat(V.note);
+ }
+ sprintf(STR1, "%c", barsym);
+ if (strcmp(V.note, STR1))
+ *V.note = '\0';
+ V.no_chords = false;
+ break;
+
+ case FirstOnly:
+ if (V.voice != nvoices)
+ *V.note = '\0';
+ else
+ strcpy(V.note, processOther(STR1, V.note, &V));
+ break;
+
+ default:
+ strcpy(V.note, processOther(STR1, V.note, &V));
+ break;
+ }
+ output(V.note, &V);
+ } while (!endOfBar(V.voice, bar_no));
+ if (!V.no_chords)
+ skipChordBar(V.voice);
+}
+
+
+/* ------------------------------------------------------------------- */
+
+Static void getMeterChange(voice_index voice, Char *new_meter)
+{
+ short pn1, pn2;
+ Char w[256], new_command[256];
+
+ if (nextNote(voice) != mword)
+ return;
+ getMusicWord(w, voice);
+ getMeter(w, &meternum, &meterdenom, &pn1, &pn2);
+ full_bar = meternum * (64 / meterdenom);
+ /* CMO: process denominator value with function PMXmeterdenom */
+ meterWord(new_command, meternum, PMXmeterdenom(meterdenom), pn1, pn2);
+ if (*new_meter != '\0' && strcmp(new_meter, new_command))
+ error3(voice, "The same meter change must appear in all voices");
+ strcpy(new_meter, new_command);
+}
+
+
+/* Local variables for musicParagraph: */
+struct LOC_musicParagraph {
+ Char new_meter[256];
+} ;
+
+Local void putPMXlines(struct LOC_musicParagraph *LINK)
+{
+ paragraph_index i, FORLIM;
+
+ FORLIM = para_len;
+ for (i = 0; i <= FORLIM - 1; i++) {
+ if (startsWith(P[i], double_comment)) {
+ predelete(P[i], 2);
+ putLine(P[i]);
+ strcpy(P[i], "%");
+ }
+ }
+}
+
+Local void processOneBar(struct LOC_musicParagraph *LINK)
+{
+ paragraph_index0 m, cm;
+ voice_index voice, cvoice;
+ boolean ignore_voice;
+ boolean wrote_repeat = false;
+ boolean alone;
+ Char STR2[256];
+ Char STR3[256];
+
+ if (bar_of_line > 1) {
+ sprintf(STR3, "%cBar %s", comment, toString(STR2, bar_no));
+ putLine(STR3);
+ }
+ last_bar = (bar_of_line == nbars && final_paragraph);
+ if (last_bar && !strcmp(repeat_sign, "|"))
+ *repeat_sign = '\0';
+ writeRepeat(repeat_sign);
+ *LINK->new_meter = '\0';
+ for (voice = nvoices; voice >= 1; voice--) {
+ if (musicLineNo(voice) > 0) {
+ gotoBar(voice, bar_of_line);
+ getMeterChange(voice, LINK->new_meter);
+ }
+ }
+ if (last_bar && *LINK->new_meter == '\0' && nleft > pickup && meternum > 0)
+ meterChange(LINK->new_meter, nleft, 64, true);
+ if (*LINK->new_meter != '\0')
+ putLine(LINK->new_meter);
+ for (voice = nvoices; voice >= 1; voice--) {
+ ignore_voice = !selected[voice-1];
+ cvoice = companion(voice);
+ m = musicLineNo(voice);
+ cm = musicLineNo(cvoice);
+ alone = (voice == cvoice || m > 0 && cm == 0 ||
+ m == 0 && cm == 0 && voice < cvoice || !selected[cvoice-1]);
+ if (selected[voice-1]) {
+ if (m > 0)
+ processLine(voice, bar_of_line);
+ else if (alone)
+ supplyRests(voice);
+ else
+ ignore_voice = true;
+ if (last_bar && *repeat_sign != '\0' && !wrote_repeat) {
+ writeRepeat(repeat_sign);
+ wrote_repeat = true;
+ }
+ if (!ignore_voice) {
+ if (alone || voicePos(voice) == 1)
+ putLine(" /");
+ else
+ putLine(" //");
+ }
+ }
+ }
+ bar_no++;
+ pickup = 0;
+ putLine("");
+}
+
+Local void putMeter(Char *new_meter_word, struct LOC_musicParagraph *LINK)
+{
+ if (strcmp(new_meter_word, old_meter_word))
+ putLine(new_meter_word);
+ strcpy(old_meter_word, new_meter_word);
+}
+
+Local void processMBR(struct LOC_musicParagraph *LINK)
+{
+ short s, bars_of_rest;
+ Char mbr[256];
+ short FORLIM;
+ Char STR1[256];
+ Char STR3[256];
+
+ strcpy(mbr, multi_bar_rest);
+ predelete(mbr, 2);
+ getNum(mbr, &bars_of_rest);
+ bar_no += bars_of_rest;
+ FORLIM = nstaves;
+ for (s = 1; s <= FORLIM; s++) {
+ if (pickup > 0)
+ put(rests(STR1, pickup, meterdenom, visible), nospace);
+ sprintf(STR3, "rm%s /", toString(STR1, bars_of_rest));
+ putLine(STR3);
+ }
+ putLine("");
+}
+
+
+Static void musicParagraph(void)
+{
+ struct LOC_musicParagraph V;
+ voice_index0 j, nvoice;
+ Char lyrassign[256];
+ Char STR1[256];
+ Char STR2[256];
+ Char STR3[256], STR4[256], STR5[256];
+ voice_index0 FORLIM;
+ short FORLIM1;
+
+ paragraphSetup(&nvoice);
+ if (nvoice == 0) {
+ nonMusic();
+ return;
+ }
+ if (nvoice > nvoices) {
+ if (nvoice == 0)
+ error("No voices! Did you remember to to supply a Style?", !print);
+ sprintf(STR4, "Paragraph has %s voices but Style allows only %s",
+ toString(STR1, nvoice), toString(STR2, nvoices));
+ error(STR4, !print);
+ return;
+ }
+ if (first_paragraph)
+ includeStartString();
+ if (pmx_preamble_done && (!final_paragraph || nvoice > 0)) {
+ sprintf(STR5, "%c Paragraph %s line %s bar %s",
+ comment, toString(STR1, paragraph_no),
+ toString(STR2, orig_line_no[0]), toString(STR3, bar_no));
+ putLine(STR5);
+ }
+ testParagraph();
+ rememberDurations();
+ if (beVerbose())
+ describeParagraph();
+ /* ---- Knowing the score, we can start setting music ---------------- */
+ if (!pmx_preamble_done) {
+ doPMXpreamble();
+ sprintf(STR3, "%c Paragraph %s line %s bar ",
+ comment, toString(STR1, paragraph_no),
+ toString(STR2, orig_line_no[0]));
+ put(STR3, putspace);
+ if (pickup > 0)
+ putLine("0");
+ else
+ putLine("1");
+ }
+ putPMXlines(&V);
+ if (must_restyle)
+ restyle();
+ if (some_vocal && (nvoice > 0 || !final_paragraph)) {
+ FORLIM = ninstr;
+ for (j = 1; j <= FORLIM; j++) {
+ assignLyrics(j, lyrassign);
+ if (*lyrassign != '\0') {
+ sprintf(STR2, "\\\\%s\\", lyrassign);
+ putLine(STR2);
+ }
+ }
+ }
+ if (must_respace)
+ respace();
+ if (meternum == 0)
+ putMeter(meterChange(STR2, beatsPerLine(), meterdenom, true), &V);
+ if (nleft > 0)
+ nbars++;
+ if (nbars == 0 && *multi_bar_rest != '\0')
+ processMBR(&V);
+ else {
+ FORLIM1 = nbars;
+ for (bar_of_line = 1; bar_of_line <= FORLIM1; bar_of_line++)
+ processOneBar(&V);
+ }
+ restoreDurations();
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+Static boolean no_commands_yet;
+
+
+Static void doMusic(void)
+{
+ Char STR1[256], STR2[256];
+ Char STR4[256];
+
+ first_paragraph = true;
+ pmx_preamble_done = false;
+ bar_no = 1;
+ *repeat_sign = '\0';
+ must_respace = false;
+ must_restyle = false;
+ do {
+ final_paragraph = endOfInfile();
+ memcpy(orig_P, P, sizeof(paragraph));
+ if (para_len > 0 && !ignore_input && thisCase()) {
+ if (no_commands_yet) {
+ interpretCommands();
+ printFeatures(false);
+ one_beat = 64 / meterdenom;
+ full_bar = meternum * one_beat;
+ if (nvoices > standardPMXvoices) {
+ sprintf(STR4, "You have %s voices; standard PMX can only handle %s",
+ toString(STR1, nvoices), toString(STR2, standardPMXvoices));
+ warning(STR4, !print);
+ }
+ initMTX();
+ initUptext();
+ initStatus();
+ initLyrics();
+ no_commands_yet = false;
+ }
+ if (startsWithBracedWord(P[0]))
+ lyricsParagraph();
+ else {
+ musicParagraph();
+ first_paragraph = false;
+ writeRepeat(repeat_sign);
+ }
+ }
+ readParagraph(P, orig_line_no, &para_len);
+ } while (para_len != 0);
+}
+
+
+Static boolean control_paragraph, no_report_errors;
+
+
+Static boolean isControlParagraph(Char (*P)[256], paragraph_index para_len)
+{
+ paragraph_index0 commands = 0, labels = 0, voices = 0, guff = 0;
+ paragraph_index0 i;
+ Char w[256];
+
+/* p2c: prepmx.pas: Note: Eliminated unused assignment statement [338] */
+ for (i = 0; i <= para_len - 1; i++) {
+ if (!startsWith(P[i], "%")) {
+ NextWord(w, P[i], ' ', ':');
+ if (!endsWith(w, ":"))
+ guff++;
+ else if (strlen(w) < 3 || findVoice(w) > 0)
+ voices++;
+ else if (isCommand(w))
+ commands++;
+ else
+ labels++;
+ }
+ }
+ if (voices + guff > commands)
+ return false;
+ return true;
+}
+
+
+Static void topOfPMXfile(void)
+{
+ Char STR2[24];
+ Char STR3[30];
+
+ putLine("---");
+ sprintf(STR2, "\\def\\mtxversion{%s}", version);
+ putLine(STR2);
+ sprintf(STR3, "\\def\\mtxdate{%s}", version_date);
+ putLine(STR3);
+ putLine("\\input mtx");
+}
+
+
+main(int argc, Char *argv[])
+{ /* ---- Main program ------------------------ */
+ PASCAL_MAIN(argc, argv);
+ strcpy(this_version, version);
+ strcpy(this_version_date, version_date);
+ printf("==> This is M-Tx %s (Music from TeXt) %s\n", version, version_date);
+
+ mtxLevel(version);
+ OpenFiles();
+ no_commands_yet = true;
+ preambleDefaults();
+ no_report_errors = false;
+ topOfPMXfile();
+ do {
+ readParagraph(P, orig_line_no, &para_len);
+ control_paragraph = isControlParagraph(P, para_len);
+ if (control_paragraph) {
+ augmentPreamble(no_report_errors);
+ no_report_errors = true;
+ if (para_len == 0)
+ error("No music paragraphs!", !print);
+ }
+ } while (control_paragraph);
+ doPreamble();
+ doMusic();
+ if (!pmx_preamble_done)
+ error("No music paragraphs!", !print);
+ putLine("% Coded by M-Tx");
+ CloseFiles();
+ printf("PrePMX done. Now run PMX.\n");
+ _Escape(0);
+ exit(EXIT_SUCCESS);
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/prepmx.pas b/Build/source/utils/m-tx/mtx-src/prepmx.pas
new file mode 100644
index 00000000000..f6b472ea6ff
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/prepmx.pas
@@ -0,0 +1,419 @@
+program prepmx;
+uses control, strings, globals, preamble, lyrics, mtx, analyze,
+ mtxline, status, uptext, notes, files, utility;
+
+{ CMO: addition/change by Christian Mondrup }
+
+{* M-Tx preprocessor to PMX Dirk Laurie }
+const version = '0.63a';
+ version_date = '<8 April 2018>';
+
+{* See file "Corrections" for updates }
+
+{* To do next:
+{* Current bugs:
+{* Old bugs:
+ Does not check PMX syntax
+{* Weaknesses that may later cause bugs:
+ Decisions sometimes made on note, sometimes on scan
+ Can 'here' overrun?
+ Where does one note stop and the next begin?
+ See comment on '!' in uptext
+}
+ chord_flat = 't';
+ chord_left = 'l';
+ blind = true;
+ visible = false;
+
+var
+ last_bar: boolean;
+ repeat_sign: string;
+ bar_of_line{, bars_of_rest}: integer;
+
+{ --------------- Bars and rests --------------- }
+
+procedure writeRepeat(var bar: string);
+ var repcode: string;
+ begin if bar='' then exit;
+ repcode:='';
+ if bar='||' then repcode:='Rd'
+ else if (bar='|]') then repcode:='RD'
+ else if bar='|:' then repcode:='Rl'
+ else if bar=':|:' then repcode:='Rlr'
+ else if bar=':|' then repcode:='Rr'
+ else if last_bar and (bar='|') then repcode:='Rb';
+ if repcode<>'' then putLine(' '+repcode);
+ bar:='';
+ end;
+
+procedure supplyRests(voice: voice_index);
+begin
+ if (bar_of_line=1) and pedanticWarnings then
+ begin write('Bar ', bar_no, ' Voice ', voice);
+ warning(' Filling missing voice with rests',not print);
+ end;
+ if pickup>0 then
+ put(rests(pickup,meterdenom,visible),nospace);
+ put(pause+' ',putspace);
+end;
+
+{ ---------------------------------------------------------------- }
+
+procedure processLine(voice: voice_index; bar_no: integer);
+ var chords, note, cutnote, pretex: string;
+ par_line: paragraph_index;
+ ngrace, nmulti: integer;
+ no_chords, no_uptext: boolean;
+
+ procedure output(note: string);
+ begin if note<>'' then
+ begin { pretex is saved up until a spacing note or rest comes }
+ if endsWith(note,'\') and (note[2]<>'\') then
+ begin curtail(note,'\'); pretex:=pretex+note; note:=''; exit end;
+ if (pretex<>'') and isNoteOrRest(note) then
+ begin note:=pretex+'\ '+note; pretex:='' end;
+ if (outlen>0) and (note[1]<>' ') then note:=' '+note;
+ put(note,nospace);
+ end;
+ if thisNote(voice)=nextvoice then putLine('');
+ end;
+
+ procedure maybeDotted(var note: string);
+ begin if length(note)<2 then exit;
+ if note[2]='"' then
+ begin note[2]:=note[1]; pretex:=pretex+'\mtxDotted' end
+ end;
+
+ procedure addChords;
+ var w, nt, labels: string;
+ j, mus_line: integer;
+ chord_line: paragraph_index0;
+ arpeggio, tieme: boolean;
+ lab: char;
+ pitches: int5;
+ procedure outChord;
+ var k: integer;
+ begin if nt='' then exit; tieme:=nt[1]='{'; if tieme then predelete(nt,1);
+ if (nt='') or (nt[1]<'a') or (nt[1]>'g') then
+ error('Must have a note name at the start of "'+nt
+ +'", not "'+nt[1]+'"',print);
+ renewChordPitch(voice,nt);
+ chords := chords+' z'+nt; nt:='';
+ for k:=1 to length(labels) do if chordPitch(voice)=pitches[k] then
+ begin chords:=chords+' s'+labels[k]+'t'; labels[k]:=' ' end;
+ if tieme then begin chordTie(voice,lab); chords:=chords+' s'+lab+'t' end
+ end;
+ begin saveStatus(voice);
+ getChordTies(voice, pitches, labels);
+ chords:=''; chord_line:=chordLineNo(voice);
+ if chord_line=0 then no_chords:=true;
+ if no_chords then exit;
+ w := getNextWord(P[chord_line],blank,dummy);
+ if (w=barsym) or (w='') then no_chords:=true;
+ if (w=tilde) or no_chords then exit;
+ mus_line:=line_no; line_no:=orig_line_no[chord_line];
+ arpeggio := w[1]='?'; if arpeggio then
+ begin chords:=' ?'; predelete(w,1); end;
+ j:=1; nt:='';
+ while j<=length(w) do
+ begin
+ if (w[j]='{') or ((nt<>'{') and (w[j]>='a') and (w[j]<='g')) then outChord
+ else if w[j]=chord_flat then w[j]:='f'
+ else if w[j]=chord_left then w[j]:='e';
+ nt:=nt+w[j]; j:=j+1
+ end;
+ if nt<>'' then outChord; if arpeggio then chords:=chords+' ?';
+ note:=note+chords;
+ for j:=1 to length(labels) do if labels[j]<>' ' then
+ error('Tie on chord note started but not finished',print);
+ line_no:=mus_line;
+ end;
+
+ function processOther(note: string): string;
+ begin
+ case thisNote(voice) of
+other: if note[1]=grace_group then
+ begin if length(note)=1 then ngrace:=1
+ else ngrace := pos1(note[2],digits);
+ if ngrace>0 then dec(ngrace);
+ end;
+{ For a zword, take note of pitch but do not change the contents }
+{ Add spurious duration because repitch expects duration to be present }
+zword: begin cutnote:=note; predelete(cutnote,1); insertchar('4',cutnote,2);
+ checkOctave(voice,cutnote); renewPitch(voice,cutnote)
+ end;
+lyrtag: extractLyrtag(voice,note);
+rbrac: endBeam(voice);
+rparen, rlparen: endSlur(voice,note);
+lbrac: beginBeam(voice,note);
+lparen: begin maybeDotted(note); beginSlur(voice,note); end;
+mword: error3(voice,'Meter change must be the first word of its bar');
+atword: lyricsAdjust(voice, note);
+ end;
+ processOther:=note;
+ end;
+
+ procedure lookahead;
+ begin while bind_left[nextNote(voice)] do
+ note:=note+' '+processOther(getMusicWord(voice));
+ end;
+
+ var l: integer;
+ in_group: boolean;
+
+ procedure processUsual;
+ begin
+ begin if hasVerseNumber(voice) then pretex:=pretex+'\mtxVerse';
+ l := pos1(multi_group,note);
+ if l>0 then scan1(note,l+1,nmulti);
+ activateBeamsAndSlurs(voice);
+ in_group:=false;
+ if ngrace>0 then begin in_group:=true; dec(ngrace) end else
+ if nmulti>0 then begin in_group:=true; dec(nmulti); end;
+ checkOctave(voice,note); renewPitch(voice,note);
+ if not in_group then
+ begin resetDuration(voice,durationCode(note)); markDebeamed(voice,note) end;
+ lookahead; getSyllable(voice,pretex);
+ addUptext(voice, no_uptext, pretex);
+ addChords;
+ end;
+ end;
+
+begin
+ pretex:=''; no_chords:=false; no_uptext := false;
+ par_line:=musicLineNo(voice);
+ nmulti :=0; ngrace := 0; line_no:=orig_line_no[par_line];
+ repeat note:=getMusicWord(voice); if note='' then exit;
+ { if debugMode then writeln(voice,' ',note); }
+ case thisNote(voice) of
+ rword: begin if multi_bar_rest<>'' then
+ begin if uptextOnRests then
+ addUptext(voice, no_uptext, pretex);
+ end
+ else begin
+ l := pos1(multi_group,note);
+ if l>0 then scan1(note,l+1,nmulti);
+ if nmulti>0 then begin in_group:=true; dec(nmulti); end;
+ if uptextOnRests then
+ addUptext(voice, no_uptext, pretex);
+ if not (isPause(note) or in_group) {0.63: allow rests in xtuples}
+ then resetDuration(voice,durationCode(note));
+ end
+ end;
+ abcdefg: processUsual;
+ barword: begin
+ if voice=nvoices then
+ if endOfBar(voice,bar_no) then repeat_sign := note
+ else writeRepeat(note);
+ if note<>barsym then note:='';
+ no_chords:=false;
+ end;
+ FirstOnly: if voice<>nvoices then note:='' else
+ note:=processOther(note);
+ else note:=processOther(note);
+ end;
+ output(note);
+ until endOfBar(voice,bar_no);
+ if not no_chords then skipChordBar(voice);
+end;
+
+{ ------------------------------------------------------------------- }
+
+procedure getMeterChange(voice: voice_index; var new_meter: string);
+ var pn1, pn2: integer;
+ w, new_command: string;
+begin if nextNote(voice)<>mword then exit;
+ w:=getMusicWord(voice);
+ getMeter(w, meternum, meterdenom, pn1, pn2);
+ full_bar := meternum*(64 div meterdenom);
+ { CMO: process denominator value with function PMXmeterdenom }
+ new_command := meterWord(meternum, PMXmeterdenom(meterdenom), pn1, pn2);
+ if (new_meter<>'') and (new_meter<>new_command)
+ then error3(voice,'The same meter change must appear in all voices');
+ new_meter:=new_command;
+end;
+
+procedure musicParagraph;
+ var j, nvoice: voice_index0;
+ new_meter, lyrassign: string;
+
+ procedure putPMXlines;
+ var i: paragraph_index;
+ begin for i:=1 to para_len do
+ if startsWith(P[i],double_comment) then
+ begin predelete(P[i],2); putLine(P[i]); P[i]:='%'; end;
+ end;
+
+ procedure processOneBar;
+ var m, cm: paragraph_index0;
+ voice, cvoice: voice_index;
+ ignore_voice, wrote_repeat, alone: boolean;
+ begin
+ if bar_of_line>1 then putLine(comment+'Bar '+toString(bar_no));
+ last_bar := (bar_of_line=nbars) and final_paragraph;
+ if last_bar and (repeat_sign='|') then repeat_sign:='';
+ writeRepeat(repeat_sign); new_meter := '';
+ for voice:=nvoices downto 1 do
+ if musicLineNo(voice)>0 then
+ begin gotoBar(voice,bar_of_line); getMeterChange(voice,new_meter);
+ end;
+ if last_bar and (new_meter='') and (nleft>pickup) and (meternum>0) then
+ new_meter := meterChange(nleft,64,true);
+ if new_meter<>'' then putLine(new_meter);
+ wrote_repeat := false;
+ for voice:=nvoices downto 1 do
+ begin ignore_voice:=not selected[voice]; cvoice:=companion(voice);
+ m:=musicLineNo(voice); cm:=musicLineNo(cvoice);
+ alone:=(voice=cvoice) or ((m>0) and (cm=0))
+ or ((m=0) and (cm=0) and (voice<cvoice)) or not selected[cvoice];
+ if selected[voice] then
+ begin
+ if m>0 then processLine(voice,bar_of_line)
+ else if alone then supplyRests(voice) else ignore_voice:=true;
+ if last_bar and (repeat_sign<>'') and not wrote_repeat then
+ begin writeRepeat(repeat_sign); wrote_repeat := true; end;
+ if not ignore_voice then
+ if alone or (voicePos(voice)=1) then putLine(' /')
+ else putLine(' //');
+ end;
+ end;
+ inc(bar_no); pickup:=0; putLine('');
+ end;
+
+ procedure putMeter(new_meter_word: string);
+ begin if new_meter_word<>old_meter_word then putLine(new_meter_word);
+ old_meter_word := new_meter_word;
+ end;
+
+ procedure processMBR;
+ var s, bars_of_rest: integer;
+ mbr: string;
+ begin
+ mbr := multi_bar_rest;
+ predelete(mbr,2); getNum(mbr,bars_of_rest);
+ bar_no := bar_no + bars_of_rest;
+ for s:=1 to nstaves do
+ begin
+ if pickup>0 then put(rests(pickup,meterdenom,visible),nospace);
+ putLine('rm' + toString(bars_of_rest) + ' /')
+ end;
+ putLine('')
+ end;
+
+begin
+ paragraphSetup(nvoice);
+ if nvoice=0 then begin nonMusic; exit end
+ else if nvoice>nvoices then
+ begin if nvoice=0 then
+ error('No voices! Did you remember to to supply a Style?',not print);
+ error('Paragraph has '+toString(nvoice)+
+ ' voices but Style allows only '+toString(nvoices),not print); exit;
+ end;
+ if first_paragraph then includeStartString;
+ if pmx_preamble_done and (not final_paragraph or (nvoice>0)) then
+ putLine(comment +' Paragraph ' + toString(paragraph_no) +
+ ' line ' + toString(orig_line_no[1]) + ' bar ' + toString(bar_no));
+ testParagraph; rememberDurations;
+ if beVerbose then describeParagraph;
+ { ---- Knowing the score, we can start setting music ---------------- }
+ if not pmx_preamble_done then
+ begin doPMXpreamble;
+ put( comment + ' Paragraph ' + toString(paragraph_no) + ' line ' +
+ toString(orig_line_no[1]) + ' bar ',putspace);
+ if pickup>0 then putLine('0') else putLine('1');
+ end;
+ putPMXlines;
+ if must_restyle then restyle;
+ if some_vocal and ((nvoice>0) or not final_paragraph) then
+ for j:=1 to ninstr do
+ begin assignLyrics(j,lyrassign);
+ if lyrassign<>'' then putLine('\\'+lyrassign+'\');
+ end;
+ if must_respace then respace;
+ if (meternum=0) then putMeter(meterChange(beatsPerLine,meterdenom,true));
+ if nleft > 0 then inc(nbars);
+ if (nbars=0) and (multi_bar_rest<>'') then
+ processMBR
+ else for bar_of_line:=1 to nbars do
+ processOneBar;
+ restoreDurations;
+end;
+
+{ ----------------------------------------------------------------------- }
+
+var no_commands_yet: boolean;
+
+procedure doMusic;
+begin first_paragraph:=true; pmx_preamble_done:=false; bar_no:=1;
+ repeat_sign:=''; must_respace:=false; must_restyle:=false;
+ repeat final_paragraph := endOfInfile;
+ orig_P := P;
+ if (para_len>0) and not ignore_input and thisCase then
+ begin if no_commands_yet then
+ begin interpretCommands; printFeatures(false);
+ one_beat := 64 div meterdenom; full_bar := meternum*one_beat;
+ if nvoices>standardPMXvoices then warning('You have '
+ +toString(nvoices)+' voices; standard PMX can only handle '
+ +toString(standardPMXvoices),not print);
+ initMTX; initUptext; initStatus; initLyrics;
+ no_commands_yet:=false
+ end;
+ if startsWithBracedWord(P[1]) then lyricsParagraph else
+ begin
+ musicParagraph; first_paragraph:=false;
+ writeRepeat(repeat_sign);
+ end
+ end;
+ readParagraph(P,orig_line_no,para_len);
+ until para_len=0;
+end;
+
+var control_paragraph, no_report_errors: boolean;
+
+function isControlParagraph (var P: paragraph; para_len: paragraph_index)
+ : boolean;
+ var commands, labels, voices, guff, i: paragraph_index0;
+ w: string;
+begin isControlParagraph:=true; commands:=0; labels:=0; voices:=0; guff:=0;
+ for i:=1 to para_len do
+ if not (startsWith(P[i],'%')) then
+ begin w:=nextWord(P[i],' ',':');
+ if not endsWith(w,':') then inc(guff)
+ else if (length(w)<3) or (findVoice(w)>0) then inc(voices)
+ else if isCommand(w) then inc(commands)
+ else inc(labels)
+ end;
+ if (voices+guff>commands) then isControlParagraph:=false
+end;
+
+procedure topOfPMXfile;
+begin
+ putLine('---');
+ putLine('\def\mtxversion{'+version+'}');
+ putline('\def\mtxdate{'+version_date+'}');
+ putline('\input mtx');
+end;
+
+begin { ---- Main program ------------------------ }
+ this_version := version; this_version_date := version_date;
+ writeln ('==> This is M-Tx ' + version + ' (Music from TeXt) ' +
+ version_date );
+
+ mtxLevel(version); OpenFiles; no_commands_yet:=true; preambleDefaults;
+ no_report_errors:=false;
+ topOfPMXfile;
+ repeat readParagraph(P,orig_line_no,para_len);
+ control_paragraph:=isControlParagraph(P,para_len);
+ if control_paragraph then
+ begin augmentPreamble(no_report_errors);
+ no_report_errors:=true;
+ if para_len=0 then error('No music paragraphs!',not print)
+ end
+ until not control_paragraph;
+ doPreamble; doMusic;
+ if not pmx_preamble_done then error('No music paragraphs!',not print);
+ putline('% Coded by M-Tx');
+ CloseFiles;
+ writeln ('PrePMX done. Now run PMX.'); halt(0);
+end.
+
diff --git a/Build/source/utils/m-tx/mtx-src/status.c b/Build/source/utils/m-tx/mtx-src/status.c
new file mode 100644
index 00000000000..d991022c0ab
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/status.c
@@ -0,0 +1,666 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "status.pas" */
+
+
+#include "p2c.h"
+
+
+#define STATUS_G
+#include "status.h"
+
+
+#ifndef GLOBALS_H
+#include "globals.h"
+#endif
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+#ifndef MTXLINE_H
+#include "mtxline.h"
+#endif
+
+#ifndef CONTROL_H
+#include "control.h"
+#endif
+
+#ifndef UTILITY_H
+#include "utility.h"
+#endif
+
+#ifndef NOTES_H
+#include "notes.h"
+#endif
+
+
+#define lowest_pitch (-9)
+#define highest_pitch 61
+
+
+typedef struct line_status {
+ short pitch, chord_pitch, octave_adjust, beam_level, slur_level, after_slur;
+ Char octave, lastnote, chord_lastnote, duration, slurID, tieID;
+ boolean beamnext, beamed, slurnext, slurred, no_beam_melisma;
+ boolean no_slur_melisma[12];
+ int5 chord_tie_pitch;
+ Char chord_tie_label[6];
+} line_status;
+
+
+Static Char init_oct[256] = "";
+
+Static Char range_name[56][256] = {
+ "0c", "0d", "0e", "0f", "0g", "0a", "0b", "1c", "1d", "1e", "1f", "1g",
+ "1a", "1b", "2c", "2d", "2e", "2f", "2g", "2a", "2b", "3c", "3d", "3e",
+ "3f", "3g", "3a", "3b", "4c", "4d", "4e", "4f", "4g", "4a", "4b", "5c",
+ "5d", "5e", "5f", "5g", "5a", "5b", "6c", "6d", "6e", "6f", "6g", "6a",
+ "6b", "7c", "7d", "7e", "7f", "7g", "7a", "7b"
+/* p2c: status.pas, line 76:
+ * Note: Line breaker spent 0.0 seconds, 5000 tries on line 58 [251] */
+};
+
+Static line_status current[maxvoices];
+Static Char lastdur[maxvoices];
+Static Char voice_range[maxvoices][256], range_low[maxvoices][256],
+ range_high[maxvoices][256];
+
+
+/* Range limits are user-specified as e.g. 3c. To make comparisons
+meaningful, a and b (which come after g) are translated to h and i. */
+
+void checkRange(short voice, Char *note_)
+{
+ Char note[256];
+ Char orig_note[256];
+ Char STR1[4];
+ Char STR3[256];
+
+ strcpy(note, note_);
+ if (*voice_range[voice-1] == '\0')
+ return;
+ strcpy(orig_note, note);
+ if (strlen(note) > 2) { /* assume usual PMX form with octave */
+ sprintf(STR1, "%c%c", note[2], note[0]);
+ strcpy(note, STR1);
+ }
+ if (note[1] == 'a')
+ note[1] = 'h';
+ if (note[1] == 'b')
+ note[1] = 'i';
+ if (strcmp(note, range_low[voice-1]) < 0 ||
+ strcmp(note, range_high[voice-1]) > 0) {
+ sprintf(STR3, "%s is out of range, specified as %s",
+ orig_note, voice_range[voice-1]);
+ error3(voice, STR3);
+ }
+}
+
+
+void defineRange(short voice, Char *range_)
+{
+ Char range[256];
+ Char STR2[256];
+
+ strcpy(range, range_);
+ strcpy(voice_range[voice-1], range);
+ if (*range == '\0')
+ return;
+ if ('0' > range[0] || range[0] > '7' || 'a' > range[1] || range[1] > 'g' ||
+ range[2] != '-' || '0' > range[3] || range[3] > '7' || 'a' > range[4] ||
+ range[4] > 'g') {
+ sprintf(STR2,
+ "Badly formatted range \"%s\" for voice %s, must be e.g. 3c-4a",
+ range, voice_label[voice-1]);
+ error(STR2, print);
+ }
+ if (range[1] == 'a')
+ range[1] = 'h';
+ if (range[1] == 'b')
+ range[1] = 'i';
+ if (range[4] == 'a')
+ range[4] = 'h';
+ if (range[4] == 'b')
+ range[4] = 'i';
+ substr_(range_low[voice-1], range, 1, 2);
+ substr_(range_high[voice-1], range, 4, 2);
+}
+
+
+void chordTie(short voice, Char *lab)
+{
+ short n;
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ n = strlen(WITH->chord_tie_label);
+ if (n == 5)
+ error3(voice, "Only five slur ties allowed per voice");
+ if (n == 0)
+ *lab = 'T';
+ else
+ *lab = WITH->chord_tie_label[n-1];
+ (*lab)++;
+ sprintf(WITH->chord_tie_label + strlen(WITH->chord_tie_label), "%c", *lab);
+/* p2c: status.pas, line 115:
+ * Note: Possible string truncation in assignment [145] */
+ n++;
+ WITH->chord_tie_pitch[n-1] = WITH->chord_pitch;
+}
+
+
+void getChordTies(short voice, short *pitches, Char *labels)
+{
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ memcpy(pitches, WITH->chord_tie_pitch, sizeof(int5));
+ strcpy(labels, WITH->chord_tie_label);
+ *WITH->chord_tie_label = '\0';
+}
+
+
+void rememberDurations(void)
+{
+ voice_index v, FORLIM;
+
+ FORLIM = nvoices;
+ for (v = 1; v <= FORLIM; v++)
+ lastdur[v-1] = duration(v);
+}
+
+
+void restoreDurations(void)
+{
+ voice_index v, FORLIM;
+
+ FORLIM = nvoices;
+ for (v = 1; v <= FORLIM; v++)
+ resetDuration(v, lastdur[v-1]);
+}
+
+
+Char duration(short voice)
+{
+ return (current[voice-1].duration);
+}
+
+
+void resetDuration(short voice, Char dur)
+{
+ if (pos1(dur, durations) == 0) {
+ printf("Trying to set duration to %c; ", dur);
+ error3(voice, "M-Tx system error: resetDuration");
+ }
+ current[voice-1].duration = dur;
+}
+
+
+void activateBeamsAndSlurs(short voice)
+{
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ if (WITH->beamnext) {
+ WITH->beamed = true;
+ WITH->beamnext = false;
+ }
+ if (WITH->slurnext) {
+ WITH->slurred = true;
+ WITH->slurnext = false;
+ }
+ if (WITH->slurred)
+ WITH->after_slur++;
+}
+
+
+void saveStatus(short voice)
+{
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ WITH->chord_pitch = WITH->pitch;
+ WITH->chord_lastnote = WITH->lastnote;
+}
+
+
+boolean noBeamMelisma(short voice)
+{
+ return (current[voice-1].no_beam_melisma);
+}
+
+
+short afterSlur(short voice)
+{
+ short Result;
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ Result = WITH->after_slur;
+ if (WITH->after_slur > 0 && WITH->slur_level < 1)
+ error3(voice, "M-Tx system error: afterSlur and slur_level incompatible)");
+ return Result;
+}
+
+
+Char octave(short voice)
+{
+ return (current[voice-1].octave);
+}
+
+
+void resetOctave(short voice)
+{
+ current[voice-1].octave = ' ';
+}
+
+
+void initOctaves(Char *octaves)
+{
+ short i = 1;
+
+ strcpy(init_oct, octaves);
+ while (i <= strlen(init_oct)) {
+ if (init_oct[i-1] == ' ')
+ delete1(init_oct, i);
+ else
+ i++;
+ }
+}
+
+
+Static Char initOctave(stave_index voice_stave)
+{
+ if (voice_stave > strlen(init_oct)) {
+ if (pos1(clef[voice_stave-1], "Gt08") > 0)
+ return '4';
+ else
+ return '3';
+ } else
+ return (init_oct[voice_stave-1]);
+}
+
+
+void setOctave(short voice)
+{
+ current[voice-1].octave = initOctave(voiceStave(voice));
+}
+
+
+void newOctave(short voice, Char dir)
+{
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ switch (dir) {
+
+ case '+':
+ WITH->octave++;
+ break;
+
+ case '-':
+ WITH->octave--;
+ break;
+ }
+}
+
+
+Static short newPitch(short voice, Char *note_, short pitch, Char lastnote)
+{
+ Char note[256];
+ short interval, npitch;
+ Char oct;
+
+ strcpy(note, note_);
+ oct = octaveCode(note);
+ if (oct == '=')
+ oct = initOctave(voiceStave(voice));
+ if (isdigit(oct)) {
+ pitch = (oct - '0') * 7 - 3;
+ lastnote = 'f';
+ removeOctaveCode(oct, note);
+ oct = octaveCode(note);
+ }
+ interval = note[0] - lastnote;
+ if (interval > 3)
+ interval -= 7;
+ if (interval < -3)
+ interval += 7;
+ npitch = pitch + interval;
+ while (oct != ' ') {
+ if (oct == '+')
+ npitch += 7;
+ else if (oct == '-')
+ npitch -= 7;
+ removeOctaveCode(oct, note);
+ oct = octaveCode(note);
+ }
+ return npitch;
+}
+
+
+Local void delins(Char *note, Char c1, Char c2, short l)
+{
+ short i, n;
+
+ n = strlen(note);
+ i = pos1(c1, note);
+ if (i == 0)
+ i = n + 1;
+ while (l > 0 && i <= n) {
+ delete1(note, i);
+ n--;
+ l--;
+ }
+ i = pos1(c2, note);
+ if (i == 0) {
+ if (strlen(note) < 2)
+ error("M-Tx program error", print);
+ else
+ i = 3;
+ }
+ while (l > 0) {
+ insertChar(c2, note, i);
+ l--;
+ }
+}
+
+
+Static void repitch(Char *note, short diff)
+{
+ diff /= 7;
+ if (diff > 0)
+ delins(note, '-', '+', diff);
+ else
+ delins(note, '+', '-', -diff);
+}
+
+
+void setUnbeamed(short voice)
+{
+ current[voice-1].beamed = false;
+}
+
+
+void setUnslurred(short voice)
+{
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ WITH->slurred = false;
+ WITH->after_slur = 0;
+}
+
+
+void beginBeam(short voice, Char *note)
+{
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ if (WITH->beamed)
+ error3(voice, "Starting a forced beam while another is open");
+ if (WITH->beam_level > 0)
+ error3(voice,
+ "Starting a forced beam while another is open (beamlevel>0)");
+ WITH->beam_level++;
+ WITH->beamnext = true;
+ WITH->no_beam_melisma = startsWith(note, "[[");
+ if (WITH->no_beam_melisma)
+ predelete(note, 1);
+}
+
+
+void endBeam(short voice)
+{
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ if (WITH->beam_level < 1)
+ error3(voice, "Closing a beam that was never opened");
+ WITH->beam_level--;
+ setUnbeamed(voice);
+}
+
+
+short slurLevel(short voice)
+{
+ return (current[voice-1].slur_level);
+}
+
+
+short beamLevel(short voice)
+{
+ return (current[voice-1].beam_level);
+}
+
+
+boolean noSlurMelisma(short voice, short history)
+{
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ return (WITH->no_slur_melisma[WITH->slur_level + history - 1]);
+}
+
+
+Static Char *slurLabel(Char *Result, short voice, Char *note)
+{
+ Char sl;
+
+ if (*note == '\0')
+ return strcpy(Result, "");
+ if (strlen(note) < 2)
+ return strcpy(Result, " ");
+ if (note[1] >= '0' && note[1] <= 'Z')
+ sl = note[1];
+ else
+ sl = ' ';
+ if (sl >= 'I' && sl <= 'T')
+ warning3(voice, "Slur label in the range I..T may cause conflict");
+ sprintf(Result, "%c", sl);
+ return Result;
+}
+
+
+Static void labelSlur(short voice, Char *note)
+{
+ Char sl;
+ line_status *WITH;
+
+ if (*note == '\0')
+ return;
+ WITH = &current[voice-1];
+ if (note[0] == ')')
+ WITH->slurID += 2;
+ else if (note[0] == '}')
+ WITH->tieID += 2;
+ /** CMO 0.60a: replace assigning tieID to sl by space charater
+ if (note[1]='(') or (note[1]=')') then sl:=slurID else sl:=tieID; */
+ if (note[0] == '(' || note[0] == ')')
+ sl = WITH->slurID;
+ else
+ sl = ' ';
+ /** CMO 0.60d: omit insertchar in case of tie
+ insertchar(sl,note,2); */
+ if (note[0] == '(' || note[0] == ')')
+ insertChar(sl, note, 2);
+ if (note[0] == '(')
+ WITH->slurID -= 2;
+ else if (note[0] == '{')
+ WITH->tieID -= 2;
+ if (WITH->slurID < 'I')
+ warning3(voice, "Too many nested slurs may cause conflict");
+ if (WITH->tieID < 'I')
+ warning3(voice, "Too many nested ties may cause conflict");
+}
+
+
+void beginSlur(short voice, Char *note)
+{
+ short posblind;
+ line_status *WITH;
+ Char STR1[256], STR2[256];
+
+ WITH = &current[voice-1];
+ WITH->slur_level++;
+ if (WITH->slur_level > 12)
+ error3(voice, "Too many open slurs");
+ WITH->no_slur_melisma[WITH->slur_level - 1] = (startsWith(note, "((") ||
+ startsWith(note, "{{"));
+ if (WITH->no_slur_melisma[WITH->slur_level - 1])
+ predelete(note, 1);
+ if (!strcmp(slurLabel(STR1, voice, note), "0"))
+ delete1(note, 2);
+ else {
+ if (!strcmp(slurLabel(STR2, voice, note), " "))
+ labelSlur(voice, note);
+ }
+ posblind = pos1('~', note);
+ if (posblind > 0) {
+ if (hideBlindSlurs())
+ *note = '\0';
+ else
+ delete1(note, posblind);
+ }
+ WITH->slurnext = true;
+}
+
+
+void endSlur(short voice, Char *note)
+{
+ short poscontinue, posblind;
+ Char contslur[256];
+ line_status *WITH;
+ Char STR1[256], STR2[256];
+
+ WITH = &current[voice-1];
+ *contslur = '\0';
+ if (WITH->slur_level < 1)
+ error3(voice, "Ending a slur that was never started");
+ if (note[0] == ')')
+ poscontinue = pos1('(', note);
+ else if (note[0] == '}')
+ poscontinue = pos1('{', note);
+ if (poscontinue == 0)
+ WITH->slur_level--;
+ else {
+ poscontinue--;
+ strcpy(contslur, note);
+ predelete(contslur, poscontinue);
+ shorten(note, poscontinue);
+ }
+ if (WITH->slur_level == 0)
+ setUnslurred(voice);
+ if (!strcmp(slurLabel(STR1, voice, note), "0"))
+ delete1(note, 2);
+ else {
+ if (!strcmp(slurLabel(STR2, voice, note), " "))
+ labelSlur(voice, note);
+ }
+ if (!strcmp(slurLabel(STR1, voice, contslur), "0"))
+ delete1(contslur, 2);
+ else {
+ if (!strcmp(slurLabel(STR2, voice, contslur), " "))
+ labelSlur(voice, contslur);
+ }
+ if (poscontinue > 0) {
+ if (note[0] == '}')
+ strcat(note, "t");
+ note[0] = 's';
+ if (contslur[0] == '{')
+ strcat(contslur, "t");
+ contslur[0] = 's';
+ }
+ posblind = pos1('~', note);
+ if (posblind > 0) {
+ if (hideBlindSlurs())
+ *note = '\0';
+ else
+ delete1(note, posblind);
+ }
+ if (*note != '\0' && *contslur != '\0')
+ sprintf(note + strlen(note), " %s", contslur);
+}
+
+
+/* This is the routine called by prepmx.pas for every normal and chordal
+note, immediately after checkOctave. It does two things: adjusts pitch
+of notes following a C: chord to what it would have been without that
+chord, and checks for pitch overruns. */
+void renewPitch(short voice, Char *note)
+{
+ short pstat;
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ pstat = newPitch(voice, note, WITH->chord_pitch, WITH->chord_lastnote);
+ WITH->pitch = newPitch(voice, note, WITH->pitch, WITH->lastnote);
+ if (WITH->pitch != pstat)
+ repitch(note, WITH->pitch - pstat);
+ checkRange(voice, range_name[WITH->pitch + 6]);
+ if (WITH->pitch < lowest_pitch && checkPitch()) {
+ printf("Pitch of note %s following %c reported as %d",
+ note, WITH->lastnote, WITH->pitch);
+ error3(voice, "Pitch too low");
+ }
+ if (WITH->pitch > highest_pitch && checkPitch()) {
+ printf("Pitch of note %s following %c reported as %d",
+ note, WITH->lastnote, WITH->pitch);
+ error3(voice, "Pitch too high");
+ }
+ WITH->lastnote = note[0];
+}
+
+
+short chordPitch(short voice)
+{
+ return (current[voice-1].chord_pitch);
+}
+
+
+void renewChordPitch(short voice, Char *note)
+{
+ line_status *WITH;
+
+ WITH = &current[voice-1];
+ WITH->chord_pitch = newPitch(voice, note, WITH->chord_pitch,
+ WITH->chord_lastnote);
+ if (WITH->chord_pitch < lowest_pitch)
+ error3(voice, "Pitch in chord too low");
+ if (WITH->chord_pitch > highest_pitch)
+ error3(voice, "Pitch in chord too high");
+ WITH->chord_lastnote = note[0];
+}
+
+
+void initStatus(void)
+{
+ short voice, FORLIM;
+ line_status *WITH;
+
+ FORLIM = nvoices;
+ for (voice = 1; voice <= FORLIM; voice++) {
+ WITH = &current[voice-1];
+ WITH->duration = default_duration;
+ WITH->octave_adjust = 0;
+ WITH->slur_level = 0;
+ WITH->beam_level = 0;
+ WITH->beamed = false;
+ WITH->beamnext = false;
+ WITH->slurred = false;
+ WITH->slurnext = false;
+ WITH->after_slur = 0;
+ WITH->octave = initOctave(voiceStave(voice));
+ WITH->slurID = 'S';
+ WITH->tieID = 'T';
+ WITH->lastnote = 'f';
+ WITH->pitch = (WITH->octave - '0') * 7 - 3;
+ *WITH->chord_tie_label = '\0';
+ saveStatus(voice);
+ }
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/status.h b/Build/source/utils/m-tx/mtx-src/status.h
new file mode 100644
index 00000000000..3acebe3dabe
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/status.h
@@ -0,0 +1,59 @@
+/* Header for module status, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef STATUS_H
+#define STATUS_H
+
+
+#ifdef STATUS_G
+# define vextern
+#else
+# define vextern extern
+#endif
+/* Keep track of duration, octave, slur and beam status. */
+
+
+extern void initStatus(void);
+extern void saveStatus(short voice);
+
+extern void resetDuration(short voice, Char dur);
+extern Char duration(short voice);
+
+extern short slurLevel(short voice);
+extern short beamLevel(short voice);
+extern boolean noBeamMelisma(short voice);
+extern boolean noSlurMelisma(short voice, short history);
+extern short afterSlur(short voice);
+extern void setUnbeamed(short voice);
+extern void setUnslurred(short voice);
+extern void beginBeam(short voice, Char *note);
+extern void endBeam(short voice);
+extern void beginSlur(short voice, Char *note);
+extern void endSlur(short voice, Char *note);
+extern void activateBeamsAndSlurs(short voice);
+
+extern void setOctave(short voice);
+extern void resetOctave(short voice);
+extern Char octave(short voice);
+extern void newOctave(short voice, Char dir);
+extern void initOctaves(Char *octaves);
+
+extern void renewPitch(short voice, Char *note);
+extern short chordPitch(short voice);
+extern void renewChordPitch(short voice, Char *note);
+extern void defineRange(short voice, Char *range);
+extern void checkRange(short voice, Char *note);
+extern void rememberDurations(void);
+extern void restoreDurations(void);
+extern void chordTie(short voice, Char *lab);
+
+
+typedef short int5[5];
+
+
+extern void getChordTies(short voice, short *pitches, Char *labels);
+
+
+#undef vextern
+
+#endif /*STATUS_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/status.pas b/Build/source/utils/m-tx/mtx-src/status.pas
new file mode 100644
index 00000000000..cc45dbc0373
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/status.pas
@@ -0,0 +1,398 @@
+unit status;
+{ Keep track of duration, octave, slur and beam status. }
+
+interface
+
+procedure initStatus;
+procedure saveStatus(voice: integer);
+
+procedure resetDuration (voice: integer; dur: char);
+function duration(voice: integer): char;
+
+function slurLevel(voice: integer): integer;
+function beamLevel(voice: integer): integer;
+function noBeamMelisma(voice: integer): boolean;
+function noSlurMelisma(voice, history: integer): boolean;
+function afterSlur(voice: integer): integer;
+procedure setUnbeamed(voice: integer);
+procedure setUnslurred(voice: integer);
+procedure beginBeam(voice: integer; var note: string);
+procedure endBeam(voice: integer);
+procedure beginSlur(voice: integer; var note: string);
+procedure endSlur(voice: integer; var note: string);
+procedure activateBeamsAndSlurs(voice: integer);
+
+procedure setOctave(voice: integer);
+procedure resetOctave(voice: integer);
+function octave(voice: integer): char;
+procedure newOctave(voice: integer; dir: char);
+procedure initOctaves(octaves: string);
+
+procedure renewPitch (voice: integer; var note: string);
+function chordPitch(voice: integer): integer;
+procedure renewChordPitch (voice: integer; note: string);
+procedure defineRange(voice: integer; range: string);
+procedure checkRange(voice: integer; note: string);
+procedure rememberDurations;
+procedure restoreDurations;
+procedure chordTie(voice: integer; var lab: char);
+type int5 = array[1..5] of integer;
+procedure getChordTies(voice: integer; var pitches: int5; var labels: string);
+
+implementation uses globals, strings, mtxline, control, utility, notes;
+
+const
+ init_oct: string = '';
+ lowest_pitch = -9;
+ highest_pitch = 61;
+ range_name: array[-6..49] of string = (
+'0c','0d','0e','0f','0g','0a','0b',
+'1c','1d','1e','1f','1g','1a','1b',
+'2c','2d','2e','2f','2g','2a','2b',
+'3c','3d','3e','3f','3g','3a','3b',
+'4c','4d','4e','4f','4g','4a','4b',
+'5c','5d','5e','5f','5g','5a','5b',
+'6c','6d','6e','6f','6g','6a','6b',
+'7c','7d','7e','7f','7g','7a','7b');
+
+type
+ line_status =
+ record
+ pitch, chord_pitch, octave_adjust, beam_level, slur_level, after_slur: integer;
+ octave, lastnote, chord_lastnote, duration, slurID, tieID: char;
+ beamnext, beamed, slurnext, slurred, no_beam_melisma: boolean;
+ no_slur_melisma: array[1..12] of boolean;
+ chord_tie_pitch: int5;
+ chord_tie_label: string[5];
+ end;
+
+var current: array[voice_index] of line_status;
+ lastdur: array[voice_index] of char;
+ voice_range, range_low, range_high: array[voice_index] of string;
+
+{ Range limits are user-specified as e.g. 3c. To make comparisons
+meaningful, a and b (which come after g) are translated to h and i. }
+
+procedure checkRange(voice: integer; note: string);
+ var orig_note: string;
+begin
+ if voice_range[voice]='' then exit;
+ orig_note := note;
+ if length(note)>2 { assume usual PMX form with octave } then
+ note := note[3]+note[1];
+ if note[2]='a' then note[2]:='h';
+ if note[2]='b' then note[2]:='i';
+ if (note<range_low[voice]) or (note>range_high[voice]) then error3(voice,
+ orig_note+' is out of range, specified as '+voice_range[voice])
+end;
+
+procedure defineRange(voice: integer; range: string);
+begin
+ voice_range[voice] := range;
+ if range='' then exit;
+ if not (
+ ('0'<=range[1]) and (range[1]<='7')
+ and ('a'<=range[2]) and (range[2]<='g')
+ and (range[3]='-')
+ and ('0'<=range[4]) and (range[4]<='7')
+ and ('a'<=range[5]) and (range[5]<='g')
+ ) then error('Badly formatted range "'+range+
+ '" for voice '+voice_label[voice]+', must be e.g. 3c-4a',print);
+ if range[2]='a' then range[2]:='h';
+ if range[2]='b' then range[2]:='i';
+ if range[5]='a' then range[5]:='h';
+ if range[5]='b' then range[5]:='i';
+ range_low[voice]:=substr(range,1,2);
+ range_high[voice]:=substr(range,4,2);
+end;
+
+procedure chordTie(voice: integer; var lab: char);
+ var n: integer;
+begin with current[voice] do
+ begin n:=length(chord_tie_label);
+ if n=5 then error3(voice,'Only five slur ties allowed per voice');
+ if n=0 then lab:='T' else lab:=chord_tie_label[n];
+ inc(lab); chord_tie_label:=chord_tie_label+lab;
+ inc(n); chord_tie_pitch[n]:=chord_pitch
+ end
+end;
+
+procedure getChordTies(voice: integer; var pitches: int5; var labels: string);
+begin with current[voice] do
+ begin pitches:=chord_tie_pitch; labels:=chord_tie_label; chord_tie_label:='' end
+end;
+
+procedure rememberDurations;
+ var v: voice_index;
+begin for v:=1 to nvoices do lastdur[v]:=duration(v) end;
+
+procedure restoreDurations;
+ var v: voice_index;
+begin for v:=1 to nvoices do resetDuration(v,lastdur[v]) end;
+
+function duration(voice: integer): char;
+begin duration := current[voice].duration; end;
+
+procedure resetDuration(voice: integer; dur: char);
+begin if pos1(dur,durations)=0 then
+ begin write('Trying to set duration to ',dur,'; ');
+ error3(voice,'M-Tx system error: resetDuration');
+ end;
+ current[voice].duration := dur
+end;
+
+
+procedure activateBeamsAndSlurs(voice: integer);
+begin with current[voice] do
+ begin
+ if beamnext then begin beamed:=true; beamnext:=false; end;
+ if slurnext then begin slurred:=true; slurnext:=false; end;
+ if slurred then inc(after_slur);
+ end
+end;
+
+procedure saveStatus(voice: integer);
+begin with current[voice] do
+ begin chord_pitch := pitch; chord_lastnote := lastnote; end;
+end;
+
+function noBeamMelisma(voice: integer): boolean;
+begin noBeamMelisma := current[voice].no_beam_melisma; end;
+
+function afterSlur(voice: integer): integer;
+begin with current[voice] do
+ begin afterSlur := after_slur; if (after_slur>0) and (slur_level<1) then
+ error3(voice,'M-Tx system error: afterSlur and slur_level incompatible)')
+ end
+end;
+
+function octave(voice: integer): char;
+begin octave := current[voice].octave; end;
+
+procedure resetOctave(voice: integer);
+begin current[voice].octave := ' '; end;
+
+procedure initOctaves(octaves: string);
+ var i: integer;
+begin init_oct:=octaves;
+ i:=1;
+ while i<=length(init_oct) do
+ if init_oct[i]=' ' then delete1(init_oct,i) else inc(i);
+end;
+
+function initOctave(voice_stave: stave_index): char;
+begin
+ if voice_stave>length(init_oct) then
+ if pos1(clef[voice_stave],'Gt08')>0
+ then initOctave:='4' else initOctave:='3'
+ else initOctave:=init_oct[voice_stave];
+end;
+
+procedure setOctave(voice: integer);
+begin current[voice].octave:=initOctave(voiceStave(voice)); end;
+
+procedure newOctave(voice: integer; dir: char);
+begin with current[voice] do case dir of
+ '+': inc(octave);
+ '-': dec(octave);
+ end;
+end;
+
+function newPitch (voice: integer; note: string; pitch: integer;
+ lastnote: char): integer;
+ var interval, npitch: integer;
+ oct: char;
+begin
+ oct:=octaveCode(note);
+ if oct='=' then oct:=initOctave(voiceStave(voice));
+ if (oct>='0') and (oct<='9') then
+ begin pitch:=7*(ord(oct)-ord('0'))-3; lastnote:='f';
+ removeOctaveCode(oct,note); oct:=octaveCode(note)
+ end;
+ interval := ord(note[1])-ord(lastnote);
+ if interval>3 then dec(interval,7);
+ if interval<-3 then inc(interval,7);
+ npitch:=pitch+interval;
+ while oct<>' ' do
+ begin if oct='+' then inc(npitch,7) else if oct='-' then dec(npitch,7);
+ removeOctaveCode(oct,note); oct:=octaveCode(note)
+ end;
+ newPitch:=npitch
+end;
+
+procedure repitch(var note: string; diff: integer);
+ procedure delins(var note: string; c1, c2: char; l: integer);
+ var i, n: integer;
+ begin n:=length(note); i:=pos1(c1,note); if i=0 then i:=n+1;
+ while (l>0) and (i<=n) do begin delete1(note,i); dec(n); dec(l); end;
+ i:=pos1(c2,note);
+ if i=0 then if length(note)<2 then error('M-Tx program error',print)
+ else i:=3;
+ while l>0 do begin insertchar(c2,note,i); dec(l); end;
+ end;
+ begin diff:=diff div 7;
+ if diff>0 then delins(note, '-','+',diff)
+ else delins(note, '+','-',-diff);
+ end;
+
+procedure setUnbeamed(voice: integer);
+begin current[voice].beamed:=false end;
+
+procedure setUnslurred(voice: integer);
+begin with current[voice] do
+ begin slurred:=false; after_slur:=0; end;
+end;
+
+procedure beginBeam(voice: integer; var note: string);
+begin with current[voice] do
+ begin if beamed then
+ error3(voice, 'Starting a forced beam while another is open');
+ if beam_level>0 then error3(voice,
+ 'Starting a forced beam while another is open (beamlevel>0)');
+ inc(beam_level);
+ beamnext := true; no_beam_melisma:=startsWith(note,'[[');
+ if no_beam_melisma then predelete(note,1);
+ end;
+end;
+
+procedure endBeam(voice: integer);
+begin with current[voice] do
+ begin if beam_level<1 then error3(voice, 'Closing a beam that was never opened');
+ dec(beam_level)
+ end;
+ setUnbeamed(voice)
+end;
+
+function slurLevel(voice: integer): integer;
+begin slurLevel := current[voice].slur_level; end;
+
+function beamLevel(voice: integer): integer;
+begin beamLevel := current[voice].beam_level; end;
+
+function noSlurMelisma(voice, history: integer): boolean;
+begin with current[voice] do
+ noSlurMelisma := no_slur_melisma[slur_level+history];
+end;
+
+function slurLabel(voice: integer; note: string): string;
+ var sl: char;
+begin if note='' then begin slurLabel:=''; exit end;
+ if length(note)<2 then begin slurLabel:=' '; exit end;
+ if (note[2]>='0') and (note[2]<='Z') then sl:=note[2] else sl:=' ';
+ if (sl>='I') and (sl<='T') then
+ warning3(voice,'Slur label in the range I..T may cause conflict');
+ slurLabel:=sl
+end;
+
+procedure labelSlur(voice: integer; var note: string);
+ var sl: char;
+begin if note='' then exit;
+ with current[voice] do
+ begin
+ if note[1]=')' then inc(slurID,2) else if note[1]='}' then inc(tieID,2);
+ {* CMO 0.60a: replace assigning tieID to sl by space charater
+ if (note[1]='(') or (note[1]=')') then sl:=slurID else sl:=tieID; }
+ if (note[1]='(') or (note[1]=')') then sl:=slurID else sl:=' ';
+ {* CMO 0.60d: omit insertchar in case of tie
+ insertchar(sl,note,2); }
+ if (note[1]='(') or (note[1]=')') then insertchar(sl,note,2);
+ if note[1]='(' then dec(slurID,2) else if note[1]='{' then dec(tieID,2);
+ if slurID<'I' then warning3(voice,'Too many nested slurs may cause conflict');
+ if tieID<'I' then warning3(voice,'Too many nested ties may cause conflict')
+ end
+end;
+
+procedure beginSlur(voice: integer; var note: string);
+ var posblind: integer;
+begin
+ with current[voice] do
+ begin
+ inc(slur_level); if slur_level>12 then Error3(voice,'Too many open slurs');
+ no_slur_melisma[slur_level] := startsWith(note,'((') or startsWith(note,'{{');
+ if no_slur_melisma[slur_level] then predelete(note,1);
+ if slurLabel(voice,note)='0' then delete1(note,2) else
+ if slurLabel(voice,note)=' ' then labelSlur(voice,note);
+ posblind:=pos1('~',note); if posblind>0 then
+ if hideBlindSlurs then note:='' else delete1(note,posblind);
+ slurnext := true;
+ end;
+end;
+
+procedure endSlur(voice: integer; var note: string);
+ var poscontinue, posblind: integer;
+ contslur: string;
+begin with current[voice] do
+ begin contslur:='';
+ if slur_level<1 then Error3(voice,'Ending a slur that was never started');
+ if note[1]=')' then poscontinue:=pos1('(',note)
+ else if note[1]='}' then poscontinue:=pos1('{',note);
+ if poscontinue=0 then dec(slur_level) else
+ begin dec(poscontinue); contslur:=note; predelete(contslur,poscontinue);
+ shorten(note,poscontinue);
+ end;
+ if slur_level=0 then setUnslurred(voice);
+ if slurLabel(voice,note)='0' then delete1(note,2) else
+ if slurLabel(voice,note)=' ' then labelSlur(voice,note);
+ if slurLabel(voice,contslur)='0' then delete1(contslur,2) else
+ if slurLabel(voice,contslur)=' ' then labelSlur(voice,contslur);
+ if poscontinue>0 then
+ begin if note[1]='}' then note:=note+'t'; note[1]:='s';
+ if contslur[1]='{' then contslur:=contslur+'t'; contslur[1]:='s';
+ end;
+ posblind:=pos1('~',note); if posblind>0 then
+ if hideBlindSlurs then note:='' else delete1(note,posblind);
+ if (note<>'') and (contslur<>'') then note := note + ' ' + contslur;
+ end;
+end;
+
+{ This is the routine called by prepmx.pas for every normal and chordal
+note, immediately after checkOctave. It does two things: adjusts pitch
+of notes following a C: chord to what it would have been without that
+chord, and checks for pitch overruns. }
+procedure renewPitch (voice: integer; var note: string);
+ var pstat: integer;
+begin with current[voice] do
+ begin
+ pstat:=newPitch (voice, note, chord_pitch, chord_lastnote);
+ pitch := newPitch (voice, note, pitch, lastnote);
+ if pitch<>pstat then repitch(note,pitch-pstat);
+ checkRange(voice,range_name[pitch]);
+ if (pitch<lowest_pitch) and checkPitch then
+ begin write('Pitch of note ',note,' following ',lastnote,' reported as ',pitch);
+ error3(voice,'Pitch too low')
+ end;
+ if (pitch>highest_pitch) and checkPitch then
+ begin write('Pitch of note ',note,' following ',lastnote,' reported as ',pitch);
+ error3(voice,'Pitch too high')
+ end;
+ lastnote:=note[1];
+ end;
+end;
+
+function chordPitch(voice: integer): integer;
+begin chordPitch:=current[voice].chord_pitch end;
+
+procedure renewChordPitch (voice: integer; note: string);
+begin with current[voice] do
+ begin chord_pitch:=newPitch(voice,note,chord_pitch,chord_lastnote);
+ if chord_pitch<lowest_pitch then error3(voice,'Pitch in chord too low');
+ if chord_pitch>highest_pitch then error3(voice,'Pitch in chord too high');
+ chord_lastnote:=note[1];
+ end
+end;
+
+procedure initStatus;
+ var voice: integer;
+begin for voice:=1 to nvoices do with current[voice] do
+ begin duration:=default_duration;
+ octave_adjust:=0; slur_level:=0; beam_level:=0;
+ beamed:=false; beamnext:=false;
+ slurred:=false; slurnext:=false; after_slur:=0;
+ octave:=initOctave(voiceStave(voice)); slurID:='S'; tieID:='T';
+ lastnote:='f'; pitch:=7*(ord(octave)-ord('0'))-3;
+ chord_tie_label:='';
+ saveStatus(voice);
+ end;
+end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/strings.h b/Build/source/utils/m-tx/mtx-src/strings.h
new file mode 100644
index 00000000000..3b8e7f4a539
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/strings.h
@@ -0,0 +1,36 @@
+/* Header for module strings, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef STRINGS_H
+#define STRINGS_H
+
+
+#ifdef STRINGS_G
+# define vextern
+#else
+# define vextern extern
+#endif
+/* String handling primitives. */
+/* These should be recoded in C instead of using the p2c code. */
+
+
+extern void scan1(Char *s, short p, short *n);
+/* Read an integer at position p of s */
+extern boolean startsWith(Char *s1, Char *s2);
+extern short pos1(Char c, Char *s);
+extern short posNot(Char c, Char *s);
+extern void insertChar(Char c, Char *s, short p);
+extern Char *substr_(Char *Result, Char *s, short start, short count);
+extern void getNum(Char *line, short *k);
+extern void getTwoNums(Char *line, short *k1, short *k2);
+extern void toUpper(Char *s);
+extern void delete1(Char *s, short p);
+extern void predelete(Char *s, short l);
+extern void shorten(Char *s, short new_length);
+extern short nextWordBound(Char *s, Char trigger, short p);
+/* find end of first word starting with trigger after s[p] */
+
+
+#undef vextern
+
+#endif /*STRINGS_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/strings.pas b/Build/source/utils/m-tx/mtx-src/strings.pas
new file mode 100644
index 00000000000..9f7deabd183
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/strings.pas
@@ -0,0 +1,109 @@
+unit strings; { String handling primitives. }
+ { These should be recoded in C instead of using the p2c code. }
+
+interface
+
+procedure scan1 (s: string; p: integer; var n: integer);
+ { Read an integer at position p of s }
+function startsWith (s1, s2: string): boolean;
+function pos1(c: char; s: string): integer;
+function posNot (c: char; var s: string): integer;
+procedure insertChar (c: char; var s: string; p: integer);
+function substr (var s: string; start, count: integer): string;
+procedure getNum(line: string; var k: integer);
+procedure getTwoNums(var line: string; var k1, k2: integer);
+procedure toUpper(var s: string);
+procedure delete1 (var s: string; p: integer);
+procedure predelete (var s: string; l: integer);
+procedure shorten (var s: string; new_length: integer);
+function nextWordBound(s: string; trigger: char; p: integer): integer;
+ { find end of first word starting with trigger after s[p] }
+
+implementation
+
+procedure scan1 (s: string; p: integer; var n: integer);
+ begin if length(s)<p then
+ writeln('scan1: string too short');
+ predelete(s,p-1); getNum(s,n);
+ end;
+
+function pos1(c: char; s: string): integer;
+ begin pos1:= pos(c, s); end;
+
+procedure delete1 (var s: string; p: integer);
+ begin if length(s)<p then
+ writeln('delete1: string too short');
+ delete(s,p,1);
+ end;
+
+procedure predelete (var s: string; l: integer);
+ begin if length(s)<l then
+ writeln('predelete: string too short');
+ delete(s,1,l);
+ end;
+
+procedure shorten (var s: string; new_length: integer);
+ begin if length(s)<new_length then
+ writeln('shorten: string too short');
+ s[0] := char(new_length);
+ end;
+
+function posNot(c: char; var s: string): integer;
+ var i, l: integer;
+begin l:=length(s);
+ for i:=1 to l do if s[i]<>c then
+ begin posnot:=i; exit; end;
+ posnot:=0;
+end;
+
+procedure strval(line: string; var num, p: integer);
+ begin val(line,num,p); end;
+
+procedure getNum(line: string; var k: integer);
+ var code: integer;
+begin strval(line,k,code);
+ if code>0 then strval(copy(line,1,code-1),k,code);
+end;
+
+procedure getTwoNums(var line: string; var k1, k2: integer);
+ var num, code, p: integer;
+begin
+ strval(line,num,p); strval(copy(line,1,p-1),k1,code);
+ strval(copy(line,p+1,255),k2,code);
+ if code>0 then strval(copy(line,1,code-1),k2,code);
+end;
+
+procedure toUpper (var s: string);
+ var i: integer;
+begin
+ for i:=1 to length(s) do s[i]:=upcase(s[i]);
+end;
+
+function startsWith (s1, s2: string): boolean;
+ var i, l1, l2: integer;
+ begin l1:=length(s1); l2:=length(s2);
+ startsWith := false; if l1<l2 then exit;
+ for i:=1 to l2 do if s1[i]<>s2[i] then exit;
+ startsWith := true;
+ end;
+
+procedure insertChar (c: char; var s: string; p: integer);
+ begin if length(s)<p-1 then
+ writeln('insertchar: string too short');
+ insert(c,s,p);
+ end;
+
+function substr (var s: string; start, count: integer): string;
+ begin if length(s)<start+count-1 then
+ writeln('insertchar: string too short');
+ substr := copy(s,start,count);
+ end;
+
+function nextWordBound(s: string; trigger: char; p: integer): integer;
+ begin
+ repeat p:=p+1 until (p>length(s)) or (s[p]=trigger);
+ while (p<length(s)) and (s[p+1]<>' ') do p:=p+1;
+ nextWordBound:=p;
+end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/uptext.c b/Build/source/utils/m-tx/mtx-src/uptext.c
new file mode 100644
index 00000000000..19a222ddb6a
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/uptext.c
@@ -0,0 +1,270 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "uptext.pas" */
+
+
+#include "p2c.h"
+
+
+#define UPTEXT_G
+#include "uptext.h"
+
+
+#ifndef GLOBALS_H
+#include "globals.h"
+#endif
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+#ifndef MTXLINE_H
+#include "mtxline.h"
+#endif
+
+#ifndef UTILITY_H
+#include "utility.h"
+#endif
+
+
+typedef struct uptext_info {
+ short uptext, uptext_adjust, uptext_lcz;
+ Char uptext_font[256];
+} uptext_info;
+
+
+Static uptext_info U[maxvoices];
+
+
+short uptextLineNo(short voice)
+{
+ return (U[voice-1].uptext);
+}
+
+
+void setUptextLineNo(short voice, short lno)
+{
+ U[voice-1].uptext = lno;
+}
+
+
+void clearUptext(void)
+{
+ voice_index voice, FORLIM;
+
+ FORLIM = nvoices;
+ for (voice = 0; voice <= FORLIM - 1; voice++)
+ U[voice].uptext = 0;
+}
+
+
+void initUptext(void)
+{
+ voice_index voice, FORLIM;
+ uptext_info *WITH;
+
+ FORLIM = nvoices;
+ for (voice = 0; voice <= FORLIM - 1; voice++) {
+ WITH = &U[voice];
+ WITH->uptext_adjust = 0;
+ WITH->uptext_lcz = 3;
+ *WITH->uptext_font = '\0';
+ }
+}
+
+
+Static void textTranslate(Char *uptext, Char *font)
+{
+ short k;
+ Char STR1[256], STR2[256], STR3[256], STR4[256];
+ short FORLIM;
+
+ if (*uptext == '\0')
+ return;
+ do {
+ k = pos1('%', uptext);
+ if (k > 0) {
+ sprintf(STR4, "%s{\\mtxFlat}%s",
+ substr_(STR1, uptext, 1, k - 1),
+ substr_(STR3, uptext, k + 1, strlen(uptext) - k));
+ strcpy(uptext, STR4);
+ }
+ } while (k != 0);
+ do {
+ k = pos1('#', uptext);
+ if (k > 0) {
+ sprintf(STR2, "%s{\\mtxSharp}%s",
+ substr_(STR1, uptext, 1, k - 1),
+ substr_(STR4, uptext, k + 1, strlen(uptext) - k));
+ strcpy(uptext, STR2);
+ }
+ } while (k != 0);
+ switch (uptext[0]) {
+
+ case '<':
+ if (!strcmp(uptext, "<"))
+ strcpy(uptext, "\\mtxIcresc");
+ else if (!strcmp(uptext, "<."))
+ strcpy(uptext, "\\mtxTcresc");
+ else {
+ predelete(uptext, 1);
+ sprintf(uptext, "\\mtxCresc{%s}", strcpy(STR4, uptext));
+ }
+ break;
+
+ case '>':
+ if (!strcmp(uptext, ">"))
+ strcpy(uptext, "\\mtxIdecresc");
+ else if (!strcmp(uptext, ">."))
+ strcpy(uptext, "\\mtxTdecresc");
+ else {
+ predelete(uptext, 1);
+ sprintf(uptext, "\\mtxDecresc{%s}", strcpy(STR1, uptext));
+ }
+ break;
+
+ default:
+ FORLIM = strlen(uptext);
+ for (k = 0; k <= FORLIM - 1; k++) {
+ if (pos1(uptext[k], "mpfzrs~") == 0)
+ return;
+ }
+ break;
+ }
+ strcpy(font, "\\mtxPF");
+}
+
+
+#define default_ 10
+#define under (-14)
+
+
+/* Local variables for addUptext: */
+struct LOC_addUptext {
+ short voice;
+ Char w[256];
+ short adj;
+} ;
+
+Local void adjustUptext(struct LOC_addUptext *LINK)
+{
+ Char letter;
+ boolean force = false;
+ uptext_info *WITH1;
+
+ delete1(LINK->w, 1);
+ while (*LINK->w != '\0') {
+/* p2c: uptext.pas: Note: Eliminated unused assignment statement [338] */
+ letter = LINK->w[0];
+ delete1(LINK->w, 1);
+ WITH1 = &U[LINK->voice-1];
+ switch (letter) {
+
+ case '<':
+ if (WITH1->uptext_lcz > 1)
+ WITH1->uptext_lcz--;
+ break;
+
+ case '>':
+ if (WITH1->uptext_lcz < 3)
+ WITH1->uptext_lcz++;
+ break;
+
+ case '^':
+ WITH1->uptext_adjust = 0;
+ break;
+
+ case 'v':
+ WITH1->uptext_adjust = under;
+ break;
+
+ case '=':
+ force = true;
+ break;
+
+ case '+':
+ case '-':
+ if (*LINK->w != '\0')
+ getNum(LINK->w, &LINK->adj);
+ else
+ LINK->adj = 0;
+ if (letter == '-')
+ LINK->adj = -LINK->adj;
+ if (force)
+ WITH1->uptext_adjust = LINK->adj;
+ else
+ WITH1->uptext_adjust += LINK->adj;
+ *LINK->w = '\0';
+ break;
+
+ default:
+ error3(LINK->voice, "Unknown uptext adjustment");
+ break;
+ }
+ }
+ strcpy(LINK->w, "!");
+}
+
+
+void addUptext(short voice_, boolean *no_uptext, Char *pretex)
+{
+ struct LOC_addUptext V;
+ Char font[256];
+ static Char lcz[4] = "lcz";
+ uptext_info *WITH;
+ Char STR1[256], STR2[256], STR3[256];
+
+ V.voice = voice_;
+ WITH = &U[V.voice-1];
+ if (WITH->uptext == 0)
+ *no_uptext = true;
+ if (*no_uptext)
+ return;
+ do {
+ GetNextWord(V.w, P[WITH->uptext - 1], blank, dummy);
+ sprintf(STR1, "%c", barsym);
+ if (!strcmp(V.w, STR1) || *V.w == '\0')
+ *no_uptext = true;
+ sprintf(STR1, "%c", tilde);
+ if (!strcmp(V.w, STR1) || *no_uptext)
+ return;
+ if (V.w[0] == '!') {
+ strcpy(WITH->uptext_font, V.w);
+ WITH->uptext_font[0] = '\\';
+ }
+ if (V.w[0] == '@')
+ adjustUptext(&V);
+ } while (V.w[0] == '!'); /* ! is a kludge, will get me in trouble later */
+ strcpy(font, WITH->uptext_font);
+ textTranslate(V.w, font);
+ if (*font != '\0')
+ sprintf(V.w, "%s{%s}", font, strcpy(STR1, V.w));
+ switch (lcz[WITH->uptext_lcz - 1]) {
+
+ case 'l':
+ sprintf(V.w, "\\mtxLchar{%s}{%s}",
+ toString(STR1, default_ + WITH->uptext_adjust),
+ strcpy(STR3, V.w));
+ break;
+
+ case 'c':
+ sprintf(V.w, "\\mtxCchar{%s}{%s}",
+ toString(STR1, default_ + WITH->uptext_adjust),
+ strcpy(STR2, V.w));
+ break;
+
+ case 'z':
+ sprintf(V.w, "\\mtxZchar{%s}{%s}",
+ toString(STR1, default_ + WITH->uptext_adjust),
+ strcpy(STR3, V.w));
+ break;
+ }
+ strcat(pretex, V.w);
+}
+
+#undef default_
+#undef under
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/uptext.h b/Build/source/utils/m-tx/mtx-src/uptext.h
new file mode 100644
index 00000000000..00fc6646a0a
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/uptext.h
@@ -0,0 +1,25 @@
+/* Header for module uptext, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef UPTEXT_H
+#define UPTEXT_H
+
+
+#ifdef UPTEXT_G
+# define vextern
+#else
+# define vextern extern
+#endif
+/* Insert and translate uptext */
+
+
+extern void initUptext(void);
+extern void clearUptext(void);
+extern short uptextLineNo(short voice);
+extern void setUptextLineNo(short voice, short lno);
+extern void addUptext(short voice, boolean *no_uptext, Char *pretex);
+
+
+#undef vextern
+
+#endif /*UPTEXT_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/uptext.pas b/Build/source/utils/m-tx/mtx-src/uptext.pas
new file mode 100644
index 00000000000..16bebc7556f
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/uptext.pas
@@ -0,0 +1,119 @@
+unit uptext;
+{ Insert and translate uptext }
+
+interface
+
+procedure initUptext;
+procedure clearUptext;
+function uptextLineNo(voice: integer): integer;
+procedure setUptextLineNo(voice, lno: integer);
+procedure addUptext(voice: integer; var no_uptext: boolean;
+ var pretex: string);
+
+implementation uses globals, strings, mtxline, utility;
+
+type uptext_info = record
+ uptext, uptext_adjust, uptext_lcz: integer;
+ uptext_font: string;
+ end;
+
+var U: array[voice_index] of uptext_info;
+
+function uptextLineNo(voice: integer): integer;
+begin uptextLineNo := U[voice].uptext; end;
+
+procedure setUptextLineNo(voice, lno: integer);
+begin U[voice].uptext := lno; end;
+
+procedure clearUptext;
+ var voice: voice_index;
+begin for voice:=1 to nvoices do U[voice].uptext:=0; end;
+
+procedure initUptext;
+ var voice: voice_index;
+begin for voice:=1 to nvoices do with U[voice] do
+ begin
+ uptext_adjust:=0; uptext_lcz:=3; uptext_font:='';
+ end;
+end;
+
+procedure textTranslate(var uptext, font: string);
+ var k: integer;
+begin
+ if uptext='' then exit;
+ repeat k := pos1('%',uptext);
+ if k>0 then uptext:=
+ substr(uptext,1,k-1)+'{\mtxFlat}'+substr(uptext,k+1,length(uptext)-k);
+ until k=0;
+ repeat k := pos1('#',uptext);
+ if k>0 then uptext:=
+ substr(uptext,1,k-1)+'{\mtxSharp}'+substr(uptext,k+1,length(uptext)-k);
+ until k=0;
+ case uptext[1] of
+ '<': if uptext='<' then uptext:='\mtxIcresc'
+ else if uptext='<.' then uptext:='\mtxTcresc'
+ else begin
+ predelete(uptext,1); uptext:='\mtxCresc{'+uptext+'}'
+ end;
+ '>': if uptext='>' then uptext:='\mtxIdecresc'
+ else if uptext='>.' then uptext:='\mtxTdecresc'
+ else begin
+ predelete(uptext,1); uptext:='\mtxDecresc{'+uptext+'}'
+ end;
+ else for k:=1 to length(uptext) do if pos1(uptext[k],'mpfzrs~')=0 then exit;
+ end;
+ font:='\mtxPF';
+end;
+
+procedure addUptext(voice: integer; var no_uptext: boolean;
+ var pretex: string);
+ var w, font: string;
+ adj: integer;
+ const default = 10; under = -14;
+ lcz: string[3] = 'lcz';
+ procedure adjustUptext;
+ var letter: char;
+ force: boolean;
+ begin delete1(w,1); force:=false;
+ while w<>'' do with U[voice] do
+ begin letter:=w[1]; delete1(w,1); with U[voice] do
+ case letter of
+ '<': if uptext_lcz>1 then dec(uptext_lcz);
+ '>': if uptext_lcz<3 then inc(uptext_lcz);
+ '^': uptext_adjust:=0;
+ 'v': uptext_adjust:=under;
+ '=': force:=true;
+'+','-': begin if w<>'' then getNum(w,adj) else adj:=0;
+ if letter = '-' then adj := -adj;
+ if force then uptext_adjust := adj else inc(uptext_adjust,adj);
+ w:='';
+ end;
+ else error3(voice,'Unknown uptext adjustment');
+ end;
+ end;
+ w:='!';
+ end;
+
+ begin
+ with U[voice] do begin
+ if uptext=0 then no_uptext := true;
+ if no_uptext then exit;
+ repeat
+ w := GetNextWord(P[uptext],blank,dummy);
+ if (w=barsym) or (w='') then no_uptext:=true;
+ if (w=tilde) or no_uptext then exit;
+ if w[1]='!' then begin uptext_font:=w; uptext_font[1]:='\'; end;
+ if w[1]='@' then adjustUptext;
+ until w[1]<>'!'; { ! is a kludge, will get me in trouble later }
+ font:=uptext_font; textTranslate(w,font);
+ if font<>'' then w:=font+'{'+w+'}';
+ case lcz[uptext_lcz] of
+'l': w:='\mtxLchar{' + toString(default+uptext_adjust) + '}{' + w + '}';
+'c': w:='\mtxCchar{' + toString(default+uptext_adjust) + '}{' + w + '}';
+'z': w:='\mtxZchar{' + toString(default+uptext_adjust) + '}{' + w + '}';
+ end;
+ pretex:=pretex+w;
+ end;
+ end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/utility.c b/Build/source/utils/m-tx/mtx-src/utility.c
new file mode 100644
index 00000000000..079bfdda116
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/utility.c
@@ -0,0 +1,365 @@
+/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
+/* From input file "utility.pas" */
+
+
+#include "p2c.h"
+
+
+#define UTILITY_G
+#include "utility.h"
+
+
+#ifndef STRINGS_H
+#include "strings.h"
+#endif
+
+
+#define blank ' '
+#define dummy '\0'
+
+
+short wordCount(Char *s)
+{
+ short i, n, FORLIM;
+
+ if (*s == '\0')
+ return 0;
+ if (s[0] == blank)
+ n = 0;
+ else
+ n = 1;
+ FORLIM = strlen(s);
+ for (i = 1; i <= FORLIM - 1; i++) {
+ if (s[i-1] == blank && s[i] != blank)
+ n++;
+ }
+ return n;
+}
+
+
+Char *GetNextWord(Char *Result, Char *s, Char Delim, Char Term)
+{
+ /* A delimiter is a character that separates words, but forms no part
+ of them. A terminator is a character that appears at the end of
+ a word. */
+ short n = 1;
+ short start, last;
+
+ last = strlen(s);
+ while (n <= last && s[n-1] == Delim)
+ n++;
+ start = n;
+ while (n <= last && s[n-1] != Term && s[n-1] != Delim)
+ n++;
+ if (n <= last && s[n-1] == Term)
+ n++;
+ substr_(Result, s, start, n - start);
+ while (n <= last && s[n-1] == Delim)
+ n++;
+ predelete(s, n - 1);
+ return Result;
+}
+
+
+Char *NextWord(Char *Result, Char *s_, Char Delim, Char Term)
+{
+ Char s[256];
+
+ strcpy(s, s_);
+ return (GetNextWord(Result, s, Delim, Term));
+}
+
+
+Char *plural(Char *Result, short n)
+{
+ if (n == 1)
+ return strcpy(Result, "");
+ else
+ return strcpy(Result, "s");
+}
+
+
+short curtail(Char *s, Char c)
+{
+ short Result = 0;
+ short l;
+
+ l = strlen(s);
+ if (s[l-1] == c) {
+ shorten(s, l - 1);
+ return l;
+ }
+ return Result;
+}
+
+
+Char *toString(Char *Result, short n)
+{
+ Char s[256];
+
+ sprintf(s, "%d", n);
+ return strcpy(Result, s);
+}
+
+
+short digit(Char c)
+{
+ return (c - '0');
+}
+
+
+boolean equalsIgnoreCase(Char *s1_, Char *s2_)
+{
+ Char s1[256], s2[256];
+
+ strcpy(s1, s1_);
+ strcpy(s2, s2_);
+ toUpper(s1);
+ toUpper(s2);
+ return (strcmp(s1, s2) == 0);
+}
+
+
+boolean startsWithIgnoreCase(Char *s1_, Char *s2_)
+{
+ Char s1[256], s2[256];
+
+ strcpy(s1, s1_);
+ strcpy(s2, s2_);
+ toUpper(s1);
+ toUpper(s2);
+ return (startsWith(s1, s2));
+}
+
+
+boolean startsWithBracedWord(Char *P_)
+{
+ Char P[256];
+ Char w[256];
+
+ strcpy(P, P_);
+ GetNextWord(w, P, blank, dummy);
+ return (w[0] == '{' && w[strlen(w) - 1] == '}');
+}
+
+
+void trim(Char *s)
+{
+ short k;
+
+ k = posNot(blank, s);
+ if (k > 1)
+ predelete(s, k - 1);
+ else if (k == 0)
+ *s = '\0';
+}
+
+
+boolean endsWith(Char *s1_, Char *s2)
+{
+ Char s1[256];
+ short l1, l2;
+
+ strcpy(s1, s1_);
+ l1 = strlen(s1);
+ l2 = strlen(s2);
+ if (l1 < l2)
+ return false;
+ predelete(s1, l1 - l2);
+ return (strcmp(s1, s2) == 0);
+}
+
+
+/* Local variables for grep: */
+struct LOC_grep {
+ Char *source, *pattern;
+ short p1[10], p2[10];
+ short i, p, s, index;
+ boolean matching;
+} ;
+
+Local void remember(short s1, short s2, struct LOC_grep *LINK)
+{
+ if (LINK->index > 9)
+ _Escape(9999);
+ LINK->p1[LINK->index] = s1;
+ LINK->p2[LINK->index] = s2;
+ LINK->s = s2 + 1;
+ LINK->index++;
+}
+
+Local void matchnum(struct LOC_grep *LINK)
+{
+ boolean allowsign = false, allowpoint = false, quit = false;
+ short s0;
+
+ LINK->matching = false;
+ s0 = LINK->s;
+ if (LINK->p < strlen(LINK->pattern)) {
+ if (LINK->pattern[LINK->p] == '#') {
+ LINK->p++;
+ allowsign = true;
+ if (LINK->p < strlen(LINK->pattern)) {
+ if (LINK->pattern[LINK->p] == '#') {
+ LINK->p++;
+ allowpoint = true;
+ }
+ }
+ }
+ }
+ if (allowsign &&
+ (LINK->source[LINK->s-1] == '-' || LINK->source[LINK->s-1] == '+')) {
+ LINK->s++;
+ if (LINK->s > strlen(LINK->source))
+ return;
+ }
+ while (!quit && LINK->s <= strlen(LINK->source)) {
+ if (LINK->source[LINK->s-1] == '.') {
+ if (!allowpoint)
+ quit = true;
+ else {
+ LINK->s++;
+ allowpoint = false;
+ }
+ }
+ if (isdigit(LINK->source[LINK->i-1])) {
+ LINK->s++;
+ LINK->matching = true;
+ } else
+ quit = true;
+ }
+ if (LINK->matching)
+ remember(s0, LINK->s - 1, LINK);
+}
+
+Local void matchmeta(struct LOC_grep *LINK)
+{
+ if (LINK->p < strlen(LINK->pattern))
+ LINK->p++;
+ if (LINK->source[LINK->s-1] == LINK->pattern[LINK->p-1]) {
+ LINK->s++;
+ LINK->p++;
+ } else
+ LINK->matching = false;
+}
+
+Local void subgrep(struct LOC_grep *LINK)
+{
+ LINK->matching = true;
+ if (LINK->pattern[LINK->p-1] == '*') {
+ remember(LINK->s, strlen(LINK->source), LINK);
+ LINK->p++;
+ return;
+ }
+ if (LINK->pattern[LINK->p-1] == '?') {
+ remember(LINK->s, LINK->s, LINK);
+ LINK->p++;
+ return;
+ }
+ if (LINK->pattern[LINK->p-1] == '#') {
+ matchnum(LINK);
+ return;
+ }
+ if (LINK->pattern[LINK->p-1] == '\\') {
+ matchmeta(LINK);
+ return;
+ }
+ if (LINK->source[LINK->s-1] == LINK->pattern[LINK->p-1]) {
+ LINK->s++;
+ LINK->p++;
+ } else
+ LINK->matching = false;
+}
+
+
+/*--- Match/Replace package --- */
+
+/* Search and replace. Stops when pattern no longer matches source.
+ Pattern wildcards:
+ ? Any single character
+ * Any string
+ # An unsigned integer
+ ## A signed integer
+ ### A signed number maybe with a decimal part
+ Pattern metacharacters:
+ \x where x is any character, stands for that character
+ Target wildcards
+ \0 to \9 Value of corresponding source wildcard
+ Target metacharacters
+ \ When not followed by 0..9 or \, stands for itself
+ \\ Backslash
+*/
+void grep(Char *source_, Char *pattern_, Char *target)
+{
+ struct LOC_grep V;
+ short j, t, reg;
+ Char product[256];
+ boolean trigger = false;
+ short FORLIM, FORLIM1;
+ Char STR2[256];
+
+ V.source = source_;
+ V.pattern = pattern_;
+ V.index = 0;
+ V.s = 1;
+ V.p = 1;
+ for (V.i = 0; V.i <= 9; V.i++) {
+ V.p1[V.i] = 1;
+ V.p2[V.i] = 0;
+ }
+ while (V.matching && V.p <= strlen(V.pattern) && V.s <= strlen(V.source))
+ subgrep(&V);
+ *product = '\0';
+ FORLIM = strlen(target);
+ for (t = 0; t <= FORLIM - 1; t++) {
+ if (trigger) {
+ reg = digit(target[t]);
+ if ((unsigned)reg <= 9) {
+ FORLIM1 = V.p2[reg];
+ for (j = V.p1[reg] - 1; j <= FORLIM1 - 1; j++)
+ sprintf(product + strlen(product), "%c", V.source[j]);
+ } else if (target[t] == '\\')
+ strcat(product, "\\");
+ else
+ sprintf(product + strlen(product), "\\%c", target[t]);
+ trigger = false;
+ } else if (target[t] == '\\' && t + 1 < strlen(target))
+ trigger = true;
+ else
+ sprintf(product + strlen(product), "%c", target[t]);
+ }
+ strcpy(V.source, substr_(STR2, V.source, V.s, strlen(V.source)));
+ strcpy(V.pattern, substr_(STR2, V.pattern, V.p, strlen(V.pattern)));
+ strcpy(target, product);
+}
+
+
+/* "match" tests whether the source matches the pattern exactly */
+boolean match(Char *source_, Char *pattern_)
+{
+ Char source[256], pattern[256];
+ static Char target[256] = "";
+
+ strcpy(source, source_);
+ strcpy(pattern, pattern_);
+ grep(source, pattern, target);
+ return (*source == '\0' && *pattern == '\0');
+}
+
+
+/* "translate" replaces the pattern by the target in the source. */
+Char *translate(Char *Result, Char *source_, Char *pattern_, Char *target_)
+{
+ Char source[256], pattern[256], target[256];
+
+ strcpy(source, source_);
+ strcpy(pattern, pattern_);
+ strcpy(target, target_);
+ grep(source, pattern, target);
+ return strcpy(Result, target);
+}
+
+
+
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/utility.h b/Build/source/utils/m-tx/mtx-src/utility.h
new file mode 100644
index 00000000000..2faeb292ffa
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/utility.h
@@ -0,0 +1,41 @@
+/* Header for module utility, generated by p2c 1.21alpha-07.Dec.93 */
+#ifndef UTILITY_H
+#define UTILITY_H
+
+
+#ifdef UTILITY_G
+# define vextern
+#else
+# define vextern extern
+#endif
+/* DPL 2004-03-22 */
+
+/* Utilities, mainly aids to parsing */
+
+
+extern boolean equalsIgnoreCase(Char *s1, Char *s2);
+extern boolean startsWithIgnoreCase(Char *s1, Char *s2);
+extern boolean endsWith(Char *s1, Char *s2);
+extern boolean startsWithBracedWord(Char *P);
+extern Char *GetNextWord(Char *Result, Char *s, Char Delim, Char Term);
+extern Char *NextWord(Char *Result, Char *s, Char Delim, Char Term);
+extern short wordCount(Char *s);
+extern Char *plural(Char *Result, short n);
+extern short curtail(Char *s, Char c);
+/* Remove last character if it equals c and return its position;
+ otherwise return 0 */
+extern Char *toString(Char *Result, short n);
+extern void trim(Char *s);
+extern short digit(Char c);
+extern boolean match(Char *source, Char *pattern);
+extern Char *translate(Char *Result, Char *source, Char *pattern,
+ Char *target);
+extern void grep(Char *source, Char *pattern, Char *target);
+/* See Implementation for what this currently does. */
+
+
+#undef vextern
+
+#endif /*UTILITY_H*/
+
+/* End. */
diff --git a/Build/source/utils/m-tx/mtx-src/utility.pas b/Build/source/utils/m-tx/mtx-src/utility.pas
new file mode 100644
index 00000000000..42cc76d15d5
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/utility.pas
@@ -0,0 +1,194 @@
+unit utility; { DPL 2004-03-22 }
+
+{ Utilities, mainly aids to parsing }
+
+interface
+
+function equalsIgnoreCase(s1, s2: string): boolean;
+function startsWithIgnoreCase(s1, s2: string): boolean;
+function endsWith(s1, s2: string): boolean;
+function startsWithBracedWord (P: string): boolean;
+function GetNextWord (var s: string; Delim, Term: char): string;
+function NextWord (s: string; Delim, Term: char): string;
+function wordCount (s: string): integer;
+function plural (n: integer): string;
+function curtail (var s: string; c: char): integer;
+ { Remove last character if it equals c and return its position;
+ otherwise return 0 }
+function toString(n: integer): string;
+procedure trim(var s: string);
+function digit(c: char): integer;
+function match(source, pattern: string): boolean;
+function translate(source, pattern, target: string): string;
+procedure grep(var source, pattern, target: string);
+ { See Implementation for what this currently does. }
+
+implementation uses strings;
+
+const blank = ' '; dummy = #0;
+
+function wordCount (s: string): integer;
+ var i, n: integer;
+ begin if length(s)=0 then
+ begin wordCount:=0; exit; end;
+ if s[1]=blank then n:=0 else n:=1;
+ for i:=1 to length(s)-1 do
+ if (s[i]=blank) and (s[i+1]<>blank) then inc(n);
+ wordCount:=n;
+ end;
+
+function GetNextWord (var s: string; Delim, Term: char): string;
+{ A delimiter is a character that separates words, but forms no part
+ of them. A terminator is a character that appears at the end of
+ a word. }
+ var n, start, last: integer;
+begin last:=length(s); n:=1;
+ while (n<=last) and (s[n] = Delim) do inc(n);
+ start:=n;
+ while (n<=last) and not (s[n] in [Delim,Term]) do inc(n);
+ if (n<=last) and (s[n] = Term) then inc(n);
+ GetNextWord:=substr(s,start,n-start);
+ while (n<=last) and (s[n] = Delim) do inc(n);
+ predelete(s,n-1);
+end;
+
+function NextWord (s: string; Delim, Term: char): string;
+ begin NextWord:=GetNextWord(s,Delim,Term); end;
+
+function plural (n: integer): string;
+ begin if n=1 then plural:='' else plural:='s'; end;
+
+function curtail (var s: string; c: char): integer;
+ var l: integer;
+ begin l:=length(s); curtail:=0;
+ if s[l]=c then begin shorten(s,l-1); curtail:=l; end;
+ end;
+
+function toString(n: integer): string;
+ var s: string;
+begin str(n,s); toString:=s; end;
+
+function digit(c: char): integer;
+ begin digit:=ord(c)-ord('0'); end;
+
+function equalsIgnoreCase(s1, s2: string): boolean;
+begin toUpper(s1); toUpper(s2); equalsIgnoreCase:=s1=s2;
+end;
+
+function startsWithIgnoreCase(s1, s2: string): boolean;
+begin toUpper(s1); toUpper(s2); startsWithIgnoreCase:=startsWith(s1,s2);
+end;
+
+function startsWithBracedWord (P: string): boolean;
+ var w: string;
+begin w := getNextWord(P,blank,dummy);
+ startsWithBracedWord := (w[1]='{') and (w[length(w)]='}');
+end;
+
+procedure trim(var s: string);
+ var k: integer;
+ begin k:=posnot(blank,s);
+ if k>1 then predelete(s,k-1) else if k=0 then s:='';
+ end;
+
+function endsWith(s1, s2: string): boolean;
+ var l1, l2: integer;
+begin l1:=length(s1); l2:=length(s2);
+ if l1<l2 then begin endsWith:=false; exit end;
+ predelete(s1,l1-l2); endsWith:=s1=s2
+end;
+
+{--- Match/Replace package --- }
+
+{ Search and replace. Stops when pattern no longer matches source.
+ Pattern wildcards:
+ ? Any single character
+ * Any string
+ # An unsigned integer
+ ## A signed integer
+ ### A signed number maybe with a decimal part
+ Pattern metacharacters:
+ \x where x is any character, stands for that character
+ Target wildcards
+ \0 to \9 Value of corresponding source wildcard
+ Target metacharacters
+ \ When not followed by 0..9 or \, stands for itself
+ \\ Backslash
+}
+procedure grep(var source, pattern, target: string);
+ var p1, p2: array[0..9] of integer;
+ i, j, p, s, t, index, reg: integer;
+ product: string;
+ trigger, matching: boolean;
+ procedure remember(s1, s2: integer);
+ begin if index>9 then halt(9999);
+ p1[index] := s1; p2[index] := s2; s := s2+1; inc(index)
+ end;
+ procedure matchnum;
+ var allowsign, allowpoint, quit: boolean;
+ s0: integer;
+ begin allowsign := false; allowpoint := false; matching := false; s0 := s;
+ if p<length(pattern) then if pattern[p+1]='#' then
+ begin inc(p); allowsign := true;
+ if p<length(pattern) then if pattern[p+1]='#' then
+ begin inc(p); allowpoint := true end
+ end;
+ if allowsign and ((source[s]='-') or (source[s]='+')) then
+ begin inc(s); if s>length(source) then exit end;
+ quit := false;
+ while (not quit) and (s<=length(source)) do
+ begin if source[s]='.' then if not allowpoint then quit := true else
+ begin inc(s); allowpoint := false end;
+ if (source[i]>='0') and (source[i]<='9') then
+ begin inc(s); matching := true end
+ else quit := true
+ end;
+ if matching then remember(s0,s-1)
+ end;
+ procedure matchmeta;
+ begin if p<length(pattern) then inc(p);
+ if source[s]=pattern[p] then begin inc(s); inc(p) end
+ else matching := false
+ end;
+ procedure subgrep;
+ begin matching := true;
+ if pattern[p]='*' then begin remember(s,length(source)); inc(p) end
+ else if pattern[p]='?' then begin remember(s,s); inc(p) end
+ else if pattern[p]='#' then matchnum
+ else if pattern[p]='\' then matchmeta
+ else if source[s]=pattern[p] then begin inc(s); inc(p) end
+ else matching := false
+ end;
+begin
+ index := 0; s := 1; p := 1;
+ for i:=0 to 9 do begin p1[i]:=1; p2[i]:=0 end;
+ while matching and (p<=length(pattern)) and (s<=length(source)) do subgrep;
+ product := ''; trigger := false;
+ for t:=1 to length(target) do if trigger then
+ begin reg := digit(target[t]); if (reg>=0) and (reg<=9) then
+ for j:=p1[reg] to p2[reg] do product := product + source[j]
+ else if target[t]='\' then product := product + '\'
+ else product := product + '\' + target[t];
+ trigger := false
+ end
+ else if (target[t]='\') and (t<length(target)) then trigger := true
+ else product := product + target[t];
+ source := substr(source,s,length(source));
+ pattern := substr(pattern,p,length(pattern));
+ target := product
+end;
+
+
+{ "match" tests whether the source matches the pattern exactly }
+function match(source, pattern: string): boolean;
+ const target: string = '';
+begin grep(source, pattern, target);
+ match := (source='') and (pattern='')
+end;
+
+{ "translate" replaces the pattern by the target in the source. }
+function translate(source, pattern, target: string): string;
+begin grep(source, pattern, target); translate := target;
+end;
+
+end.
diff --git a/Build/source/utils/m-tx/mtx-src/version.ac b/Build/source/utils/m-tx/mtx-src/version.ac
new file mode 100644
index 00000000000..61c3423259d
--- /dev/null
+++ b/Build/source/utils/m-tx/mtx-src/version.ac
@@ -0,0 +1,11 @@
+dnl
+dnl Copyright (C) 2012 Peter Breitenlohner <tex-live@tug.org>
+dnl
+dnl This file is free software; the copyright holder
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl --------------------------------------------------------
+dnl
+dnl m4-include this file to define the current mtx version
+m4_define([mtx_version], [0.63])