diff --git a/.circleci/scripts/install-linux-dotnet.sh b/.circleci/scripts/install-linux-dotnet.sh index 035ffdaf6..1e23257e4 100755 --- a/.circleci/scripts/install-linux-dotnet.sh +++ b/.circleci/scripts/install-linux-dotnet.sh @@ -15,5 +15,5 @@ echo "done installing .Net SDK" # we need to build the runtime before test run, since we used "--no-dependencies" # when we call dotnet cli for restore and build, in order to speed up echo "building runtime..." -dotnet build -c Release -f netstandard2.0 runtime/CSharp/Antlr4.csproj +dotnet build -c Release -f netstandard2.0 runtime/CSharp/src/Antlr4.csproj echo "done building runtime" diff --git a/.travis/run-tests-dotnet.sh b/.travis/run-tests-dotnet.sh index a7780c49a..2b3f615b7 100755 --- a/.travis/run-tests-dotnet.sh +++ b/.travis/run-tests-dotnet.sh @@ -7,7 +7,7 @@ export PATH=$PATH:/Users/travis/.dotnet # we need to build the runtime before test run, since we used "--no-dependencies" # when we call dotnet cli for restore and build, in order to speed up -dotnet build -c Release -f netstandard2.0 ../runtime/CSharp/Antlr4.csproj +dotnet build -c Release -f netstandard2.0 ../runtime/CSharp/src/Antlr4.csproj # call test diff --git a/appveyor.yml b/appveyor.yml index 11fbd4eaa..8bcec2bd9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,9 +12,9 @@ install: - cinst -y dart-sdk --version=2.8.4 build_script: - mvn -DskipTests install --batch-mode - - dotnet build runtime/CSharp/Antlr4.csproj -c Release + - dotnet build runtime/CSharp/src/Antlr4.csproj -c Release after_build: - - dotnet pack runtime/CSharp/Antlr4.csproj -c Release + - dotnet pack runtime/CSharp/src/Antlr4.csproj -c Release test_script: - mvn install -Dantlr-php-php="C:\tools\php\php.exe" -Dantlr-dart-dart="C:\tools\dart-sdk\bin\dart.exe" -Dantlr-dart-pub="C:\tools\dart-sdk\bin\pub.bat" -Dantlr-dart-dart2native="C:\tools\dart-sdk\bin\dart2native.bat" -Dantlr-python2-python="C:\Python27\python.exe" -Dantlr-python3-python="C:\Python35\python.exe" --batch-mode artifacts: diff --git a/doc/antlr-project-testing.md b/doc/antlr-project-testing.md index 1ff46aae9..3e14eac73 100644 --- a/doc/antlr-project-testing.md +++ b/doc/antlr-project-testing.md @@ -57,11 +57,9 @@ $ mvn install -DskipTests=true # make sure all artifacts are visible on this m Now, make sure C# runtime is built and installed locally. ```bash -cd ~/antlr/code/antlr4/runtime/CSharp/runtime/CSharp -# kill previous ones manually as "xbuild /t:Clean" didn't seem to do it -find . -name '*.dll' -exec rm {} \; -# build -xbuild /p:Configuration=Release Antlr4.Runtime/Antlr4.Runtime.mono.csproj +cd ~/antlr/code/antlr4/runtime/CSharp/src +rm -rf `find . -name '{obj,bin}'` +dotnet build -c Release runtime/CSharp/src/Antlr4.csproj ``` C++ test rig automatically builds C++ runtime during tests. Others don't need a prebuilt lib. diff --git a/doc/building-antlr.md b/doc/building-antlr.md index 494bea81d..15ff6ff8e 100644 --- a/doc/building-antlr.md +++ b/doc/building-antlr.md @@ -25,6 +25,22 @@ Checking connectivity... done. Checking out files: 100% (1427/1427), done. ``` +# Check your environment + +If you are starting from a clean, minimum Ubuntu OS, check your environment. + + +```bash +$ sudo apt-get update +$ # Get Java +$ java > /dev/null 2>&1 +$ if [[ "$?" != "0" ]]; then sudo apt install -y openjdk-11-jre-headless; fi +$ # Get Mvn +$ mvn > /dev/null 2>&1 +$ if [[ "$?" != "0" ]]; then sudo apt install -y maven; fi + +``` + # Compile ```bash diff --git a/doc/releasing-antlr.md b/doc/releasing-antlr.md index 7323376b2..53fac7320 100644 --- a/doc/releasing-antlr.md +++ b/doc/releasing-antlr.md @@ -54,7 +54,7 @@ Edit the repository looking for 4.5 or whatever and update it. Bump version in t * runtime/Python2/src/antlr4/Recognizer.py * runtime/Python3/setup.py * runtime/Python3/src/antlr4/Recognizer.py - * runtime/CSharp/Antlr4.csproj + * runtime/CSharp/src/Antlr4.csproj * runtime/PHP/src/RuntimeMetaData.php * runtime/JavaScript/package.json * runtime/JavaScript/src/antlr4/Recognizer.js @@ -80,8 +80,8 @@ Here is a simple script to display any line from the critical files with, say, ` ```bash mvn clean -rm -rf runtime/CSharp/bin -rm -rf runtime/CSharp/obj +rm -rf runtime/CSharp/src/bin +rm -rf runtime/CSharp/src/obj rm -rf runtime/gen find tool runtime -type f -exec grep -l '4\.9' {} \; find runtime runtime -type f -exec grep -l '4\.9' {} \; @@ -322,10 +322,10 @@ Of course you need Mono and `nuget` to be installed. On mac: From @kvanTTT: Install `dotnet` on any platform (see https://dotnet.microsoft.com/download) and run the following command on any OS (Win, Linux, macOS): -* building: `dotnet build runtime/CSharp/Antlr4.csproj -c Release` - Output `.dll` will be in `runtime/CSharp/bin/Release/netstandard2.0` or in `runtime/CSharp/bin/Release/netstandard2.1` -* packing: `dotnet pack runtime/CSharp/Antlr4.csproj -c Release` - Output `.nupkg` will be in `runtime/CSharp/bin/Release/Antlr4.Runtime.Standard.4.9.0.nupkg` +* building: `dotnet build runtime/CSharp/src/Antlr4.csproj -c Release` + Output `.dll` will be in `runtime/CSharp/src/bin/Release/netstandard2.0` or in `runtime/CSharp/src/bin/Release/netstandard2.1` +* packing: `dotnet pack runtime/CSharp/src/Antlr4.csproj -c Release` + Output `.nupkg` will be in `runtime/CSharp/src/bin/Release/Antlr4.Runtime.Standard.4.9.1.nupkg` Alternatively, you can install Visual Studio 2017 and make sure to check boxes with .NET Core SDK. diff --git a/runtime-testsuite/test/org/antlr/v4/test/runtime/csharp/BaseCSharpTest.java b/runtime-testsuite/test/org/antlr/v4/test/runtime/csharp/BaseCSharpTest.java index f6c4ab5c5..e1c713eb7 100644 --- a/runtime-testsuite/test/org/antlr/v4/test/runtime/csharp/BaseCSharpTest.java +++ b/runtime-testsuite/test/org/antlr/v4/test/runtime/csharp/BaseCSharpTest.java @@ -195,7 +195,7 @@ public class BaseCSharpTest extends BaseRuntimeTestSupport implements RuntimeTes // find runtime package final ClassLoader loader = Thread.currentThread().getContextClassLoader(); - final URL runtimeProj = loader.getResource("CSharp/Antlr4.csproj"); + final URL runtimeProj = loader.getResource("CSharp/src/Antlr4.csproj"); if (runtimeProj == null) { throw new RuntimeException("C# runtime project file not found!"); } diff --git a/runtime/CSharp/Antlr4.csproj b/runtime/CSharp/src/Antlr4.csproj similarity index 97% rename from runtime/CSharp/Antlr4.csproj rename to runtime/CSharp/src/Antlr4.csproj index 0a7b1e006..fb19e0173 100644 --- a/runtime/CSharp/Antlr4.csproj +++ b/runtime/CSharp/src/Antlr4.csproj @@ -3,7 +3,7 @@ The ANTLR Organization 4.9.1 en-US - netstandard2.0;netstandard2.1 + netstandard2.0 $(NoWarn);CS1591;CS1574;CS1580 true Antlr4.Runtime.Standard diff --git a/runtime/CSharp/Antlr4.snk b/runtime/CSharp/src/Antlr4.snk similarity index 100% rename from runtime/CSharp/Antlr4.snk rename to runtime/CSharp/src/Antlr4.snk diff --git a/runtime/CSharp/AntlrFileStream.cs b/runtime/CSharp/src/AntlrFileStream.cs similarity index 100% rename from runtime/CSharp/AntlrFileStream.cs rename to runtime/CSharp/src/AntlrFileStream.cs diff --git a/runtime/CSharp/AntlrInputStream.cs b/runtime/CSharp/src/AntlrInputStream.cs similarity index 100% rename from runtime/CSharp/AntlrInputStream.cs rename to runtime/CSharp/src/AntlrInputStream.cs diff --git a/runtime/CSharp/Atn/ATN.cs b/runtime/CSharp/src/Atn/ATN.cs similarity index 100% rename from runtime/CSharp/Atn/ATN.cs rename to runtime/CSharp/src/Atn/ATN.cs diff --git a/runtime/CSharp/Atn/ATNConfig.cs b/runtime/CSharp/src/Atn/ATNConfig.cs similarity index 100% rename from runtime/CSharp/Atn/ATNConfig.cs rename to runtime/CSharp/src/Atn/ATNConfig.cs diff --git a/runtime/CSharp/Atn/ATNConfigSet.cs b/runtime/CSharp/src/Atn/ATNConfigSet.cs similarity index 100% rename from runtime/CSharp/Atn/ATNConfigSet.cs rename to runtime/CSharp/src/Atn/ATNConfigSet.cs diff --git a/runtime/CSharp/Atn/ATNDeserializationOptions.cs b/runtime/CSharp/src/Atn/ATNDeserializationOptions.cs similarity index 100% rename from runtime/CSharp/Atn/ATNDeserializationOptions.cs rename to runtime/CSharp/src/Atn/ATNDeserializationOptions.cs diff --git a/runtime/CSharp/Atn/ATNDeserializer.cs b/runtime/CSharp/src/Atn/ATNDeserializer.cs similarity index 100% rename from runtime/CSharp/Atn/ATNDeserializer.cs rename to runtime/CSharp/src/Atn/ATNDeserializer.cs diff --git a/runtime/CSharp/Atn/ATNSimulator.cs b/runtime/CSharp/src/Atn/ATNSimulator.cs similarity index 100% rename from runtime/CSharp/Atn/ATNSimulator.cs rename to runtime/CSharp/src/Atn/ATNSimulator.cs diff --git a/runtime/CSharp/Atn/ATNState.cs b/runtime/CSharp/src/Atn/ATNState.cs similarity index 100% rename from runtime/CSharp/Atn/ATNState.cs rename to runtime/CSharp/src/Atn/ATNState.cs diff --git a/runtime/CSharp/Atn/ATNType.cs b/runtime/CSharp/src/Atn/ATNType.cs similarity index 100% rename from runtime/CSharp/Atn/ATNType.cs rename to runtime/CSharp/src/Atn/ATNType.cs diff --git a/runtime/CSharp/Atn/AbstractPredicateTransition.cs b/runtime/CSharp/src/Atn/AbstractPredicateTransition.cs similarity index 100% rename from runtime/CSharp/Atn/AbstractPredicateTransition.cs rename to runtime/CSharp/src/Atn/AbstractPredicateTransition.cs diff --git a/runtime/CSharp/Atn/ActionTransition.cs b/runtime/CSharp/src/Atn/ActionTransition.cs similarity index 100% rename from runtime/CSharp/Atn/ActionTransition.cs rename to runtime/CSharp/src/Atn/ActionTransition.cs diff --git a/runtime/CSharp/Atn/AmbiguityInfo.cs b/runtime/CSharp/src/Atn/AmbiguityInfo.cs similarity index 75% rename from runtime/CSharp/Atn/AmbiguityInfo.cs rename to runtime/CSharp/src/Atn/AmbiguityInfo.cs index fbe0bd7e8..7017db797 100644 --- a/runtime/CSharp/Atn/AmbiguityInfo.cs +++ b/runtime/CSharp/src/Atn/AmbiguityInfo.cs @@ -41,6 +41,9 @@ namespace Antlr4.Runtime.Atn /// 4.3 public class AmbiguityInfo : DecisionEventInfo { + /** The set of alternative numbers for this decision event that lead to a valid parse. */ + public BitSet ambigAlts; + /// /// Constructs a new instance of the /// @@ -48,19 +51,30 @@ namespace Antlr4.Runtime.Atn /// specified detailed ambiguity information. /// /// The decision number - /// - /// The final simulator state identifying the ambiguous + /// The final configuration set identifying the ambiguous /// alternatives for the current input /// + /// The set of alternatives in the decision that lead to a valid parse. + /// The predicted alt is the min(ambigAlts) + /// /// The input token stream /// The start index for the current prediction /// /// The index at which the ambiguity was identified during /// prediction /// - public AmbiguityInfo(int decision, SimulatorState state, ITokenStream input, int startIndex, int stopIndex) - : base(decision, state, input, startIndex, stopIndex, state.useContext) + /// @code true} if the ambiguity was identified during LL + /// prediction; otherwise, {@code false} if the ambiguity was identified + /// during SLL prediction + /// + public AmbiguityInfo(int decision, + ATNConfigSet configs, + BitSet ambigAlts, + ITokenStream input, int startIndex, int stopIndex, + bool fullCtx) + : base(decision, configs, input, startIndex, stopIndex, fullCtx) { + this.ambigAlts = ambigAlts; } } } diff --git a/runtime/CSharp/Atn/ArrayPredictionContext.cs b/runtime/CSharp/src/Atn/ArrayPredictionContext.cs similarity index 100% rename from runtime/CSharp/Atn/ArrayPredictionContext.cs rename to runtime/CSharp/src/Atn/ArrayPredictionContext.cs diff --git a/runtime/CSharp/Atn/AtomTransition.cs b/runtime/CSharp/src/Atn/AtomTransition.cs similarity index 100% rename from runtime/CSharp/Atn/AtomTransition.cs rename to runtime/CSharp/src/Atn/AtomTransition.cs diff --git a/runtime/CSharp/Atn/BasicBlockStartState.cs b/runtime/CSharp/src/Atn/BasicBlockStartState.cs similarity index 100% rename from runtime/CSharp/Atn/BasicBlockStartState.cs rename to runtime/CSharp/src/Atn/BasicBlockStartState.cs diff --git a/runtime/CSharp/Atn/BasicState.cs b/runtime/CSharp/src/Atn/BasicState.cs similarity index 100% rename from runtime/CSharp/Atn/BasicState.cs rename to runtime/CSharp/src/Atn/BasicState.cs diff --git a/runtime/CSharp/Atn/BlockEndState.cs b/runtime/CSharp/src/Atn/BlockEndState.cs similarity index 100% rename from runtime/CSharp/Atn/BlockEndState.cs rename to runtime/CSharp/src/Atn/BlockEndState.cs diff --git a/runtime/CSharp/Atn/BlockStartState.cs b/runtime/CSharp/src/Atn/BlockStartState.cs similarity index 100% rename from runtime/CSharp/Atn/BlockStartState.cs rename to runtime/CSharp/src/Atn/BlockStartState.cs diff --git a/runtime/CSharp/Atn/ConflictInfo.cs b/runtime/CSharp/src/Atn/ConflictInfo.cs similarity index 100% rename from runtime/CSharp/Atn/ConflictInfo.cs rename to runtime/CSharp/src/Atn/ConflictInfo.cs diff --git a/runtime/CSharp/Atn/ContextSensitivityInfo.cs b/runtime/CSharp/src/Atn/ContextSensitivityInfo.cs similarity index 86% rename from runtime/CSharp/Atn/ContextSensitivityInfo.cs rename to runtime/CSharp/src/Atn/ContextSensitivityInfo.cs index b978c6786..454a72ef5 100644 --- a/runtime/CSharp/Atn/ContextSensitivityInfo.cs +++ b/runtime/CSharp/src/Atn/ContextSensitivityInfo.cs @@ -35,9 +35,8 @@ namespace Antlr4.Runtime.Atn /// with the specified detailed context sensitivity information. /// /// The decision number - /// - /// The final simulator state containing the unique - /// alternative identified by full-context prediction + /// The final configuration set identifying the ambiguous + /// alternatives for the current input /// /// The input token stream /// The start index for the current prediction @@ -45,8 +44,8 @@ namespace Antlr4.Runtime.Atn /// The index at which the context sensitivity was /// identified during full-context prediction /// - public ContextSensitivityInfo(int decision, SimulatorState state, ITokenStream input, int startIndex, int stopIndex) - : base(decision, state, input, startIndex, stopIndex, true) + public ContextSensitivityInfo(int decision, ATNConfigSet configs, ITokenStream input, int startIndex, int stopIndex) + : base(decision, configs, input, startIndex, stopIndex, true) { } } diff --git a/runtime/CSharp/Atn/DecisionEventInfo.cs b/runtime/CSharp/src/Atn/DecisionEventInfo.cs similarity index 77% rename from runtime/CSharp/Atn/DecisionEventInfo.cs rename to runtime/CSharp/src/Atn/DecisionEventInfo.cs index ee2098cb7..6ab88c4a1 100644 --- a/runtime/CSharp/Atn/DecisionEventInfo.cs +++ b/runtime/CSharp/src/Atn/DecisionEventInfo.cs @@ -25,15 +25,13 @@ namespace Antlr4.Runtime.Atn /// public readonly int decision; - /// - /// The simulator state containing additional information relevant to the - /// prediction state when the current event occurred, or - /// - /// if no - /// additional information is relevant or available. - /// - [Nullable] - public readonly SimulatorState state; + /// The configuration set containing additional information relevant to the + /// prediction state when the current event occurred, or {@code null} if no + /// additional information is relevant or available. + /// The configuration set containing additional information relevant to the + /// prediction state when the current event occurred, or {@code null} if no + /// additional information is relevant or available. + public readonly ATNConfigSet configs; /// The input token stream which is being parsed. /// The input token stream which is being parsed. @@ -63,14 +61,17 @@ namespace Antlr4.Runtime.Atn /// public readonly bool fullCtx; - public DecisionEventInfo(int decision, SimulatorState state, ITokenStream input, int startIndex, int stopIndex, bool fullCtx) + public DecisionEventInfo(int decision, + ATNConfigSet configs, + ITokenStream input, int startIndex, int stopIndex, + bool fullCtx) { this.decision = decision; this.fullCtx = fullCtx; this.stopIndex = stopIndex; this.input = input; this.startIndex = startIndex; - this.state = state; + this.configs = configs; } } } diff --git a/runtime/CSharp/Atn/DecisionInfo.cs b/runtime/CSharp/src/Atn/DecisionInfo.cs similarity index 100% rename from runtime/CSharp/Atn/DecisionInfo.cs rename to runtime/CSharp/src/Atn/DecisionInfo.cs diff --git a/runtime/CSharp/Atn/DecisionState.cs b/runtime/CSharp/src/Atn/DecisionState.cs similarity index 100% rename from runtime/CSharp/Atn/DecisionState.cs rename to runtime/CSharp/src/Atn/DecisionState.cs diff --git a/runtime/CSharp/Atn/EmptyPredictionContext.cs b/runtime/CSharp/src/Atn/EmptyPredictionContext.cs similarity index 100% rename from runtime/CSharp/Atn/EmptyPredictionContext.cs rename to runtime/CSharp/src/Atn/EmptyPredictionContext.cs diff --git a/runtime/CSharp/Atn/EpsilonTransition.cs b/runtime/CSharp/src/Atn/EpsilonTransition.cs similarity index 100% rename from runtime/CSharp/Atn/EpsilonTransition.cs rename to runtime/CSharp/src/Atn/EpsilonTransition.cs diff --git a/runtime/CSharp/Atn/ErrorInfo.cs b/runtime/CSharp/src/Atn/ErrorInfo.cs similarity index 72% rename from runtime/CSharp/Atn/ErrorInfo.cs rename to runtime/CSharp/src/Atn/ErrorInfo.cs index 91466fa55..93676d210 100644 --- a/runtime/CSharp/Atn/ErrorInfo.cs +++ b/runtime/CSharp/src/Atn/ErrorInfo.cs @@ -30,17 +30,18 @@ namespace Antlr4.Runtime.Atn /// specified detailed syntax error information. /// /// The decision number - /// - /// The final simulator state reached during prediction - /// prior to reaching the - /// - /// state + /// The final configuration set reached during prediction + /// prior to reaching the {@link ATNSimulator#ERROR} state /// /// The input token stream /// The start index for the current prediction /// The index at which the syntax error was identified - public ErrorInfo(int decision, SimulatorState state, ITokenStream input, int startIndex, int stopIndex) - : base(decision, state, input, startIndex, stopIndex, state.useContext) + /// {@code true} if the syntax error was identified during LL + /// prediction; otherwise, {@code false} if the syntax error was identified + /// during SLL prediction + /// + public ErrorInfo(int decision, ATNConfigSet configs, ITokenStream input, int startIndex, int stopIndex, bool fullCtx) + : base(decision, configs, input, startIndex, stopIndex, fullCtx) { } } diff --git a/runtime/CSharp/Atn/ILexerAction.cs b/runtime/CSharp/src/Atn/ILexerAction.cs similarity index 100% rename from runtime/CSharp/Atn/ILexerAction.cs rename to runtime/CSharp/src/Atn/ILexerAction.cs diff --git a/runtime/CSharp/Atn/LL1Analyzer.cs b/runtime/CSharp/src/Atn/LL1Analyzer.cs similarity index 100% rename from runtime/CSharp/Atn/LL1Analyzer.cs rename to runtime/CSharp/src/Atn/LL1Analyzer.cs diff --git a/runtime/CSharp/Atn/LexerATNConfig.cs b/runtime/CSharp/src/Atn/LexerATNConfig.cs similarity index 100% rename from runtime/CSharp/Atn/LexerATNConfig.cs rename to runtime/CSharp/src/Atn/LexerATNConfig.cs diff --git a/runtime/CSharp/Atn/LexerATNSimulator.cs b/runtime/CSharp/src/Atn/LexerATNSimulator.cs similarity index 100% rename from runtime/CSharp/Atn/LexerATNSimulator.cs rename to runtime/CSharp/src/Atn/LexerATNSimulator.cs diff --git a/runtime/CSharp/Atn/LexerActionExecutor.cs b/runtime/CSharp/src/Atn/LexerActionExecutor.cs similarity index 100% rename from runtime/CSharp/Atn/LexerActionExecutor.cs rename to runtime/CSharp/src/Atn/LexerActionExecutor.cs diff --git a/runtime/CSharp/Atn/LexerActionType.cs b/runtime/CSharp/src/Atn/LexerActionType.cs similarity index 100% rename from runtime/CSharp/Atn/LexerActionType.cs rename to runtime/CSharp/src/Atn/LexerActionType.cs diff --git a/runtime/CSharp/Atn/LexerChannelAction.cs b/runtime/CSharp/src/Atn/LexerChannelAction.cs similarity index 100% rename from runtime/CSharp/Atn/LexerChannelAction.cs rename to runtime/CSharp/src/Atn/LexerChannelAction.cs diff --git a/runtime/CSharp/Atn/LexerCustomAction.cs b/runtime/CSharp/src/Atn/LexerCustomAction.cs similarity index 100% rename from runtime/CSharp/Atn/LexerCustomAction.cs rename to runtime/CSharp/src/Atn/LexerCustomAction.cs diff --git a/runtime/CSharp/Atn/LexerIndexedCustomAction.cs b/runtime/CSharp/src/Atn/LexerIndexedCustomAction.cs similarity index 100% rename from runtime/CSharp/Atn/LexerIndexedCustomAction.cs rename to runtime/CSharp/src/Atn/LexerIndexedCustomAction.cs diff --git a/runtime/CSharp/Atn/LexerModeAction.cs b/runtime/CSharp/src/Atn/LexerModeAction.cs similarity index 100% rename from runtime/CSharp/Atn/LexerModeAction.cs rename to runtime/CSharp/src/Atn/LexerModeAction.cs diff --git a/runtime/CSharp/Atn/LexerMoreAction.cs b/runtime/CSharp/src/Atn/LexerMoreAction.cs similarity index 100% rename from runtime/CSharp/Atn/LexerMoreAction.cs rename to runtime/CSharp/src/Atn/LexerMoreAction.cs diff --git a/runtime/CSharp/Atn/LexerPopModeAction.cs b/runtime/CSharp/src/Atn/LexerPopModeAction.cs similarity index 100% rename from runtime/CSharp/Atn/LexerPopModeAction.cs rename to runtime/CSharp/src/Atn/LexerPopModeAction.cs diff --git a/runtime/CSharp/Atn/LexerPushModeAction.cs b/runtime/CSharp/src/Atn/LexerPushModeAction.cs similarity index 100% rename from runtime/CSharp/Atn/LexerPushModeAction.cs rename to runtime/CSharp/src/Atn/LexerPushModeAction.cs diff --git a/runtime/CSharp/Atn/LexerSkipAction.cs b/runtime/CSharp/src/Atn/LexerSkipAction.cs similarity index 100% rename from runtime/CSharp/Atn/LexerSkipAction.cs rename to runtime/CSharp/src/Atn/LexerSkipAction.cs diff --git a/runtime/CSharp/Atn/LexerTypeAction.cs b/runtime/CSharp/src/Atn/LexerTypeAction.cs similarity index 100% rename from runtime/CSharp/Atn/LexerTypeAction.cs rename to runtime/CSharp/src/Atn/LexerTypeAction.cs diff --git a/runtime/CSharp/Atn/LookaheadEventInfo.cs b/runtime/CSharp/src/Atn/LookaheadEventInfo.cs similarity index 67% rename from runtime/CSharp/Atn/LookaheadEventInfo.cs rename to runtime/CSharp/src/Atn/LookaheadEventInfo.cs index 2b5e3f30a..8d8da4a0f 100644 --- a/runtime/CSharp/Atn/LookaheadEventInfo.cs +++ b/runtime/CSharp/src/Atn/LookaheadEventInfo.cs @@ -19,6 +19,13 @@ namespace Antlr4.Runtime.Atn /// 4.3 public class LookaheadEventInfo : DecisionEventInfo { + /// The alternative chosen by adaptivePredict(), not necessarily + /// the outermost alt shown for a rule; left-recursive rules have + /// user-level alts that differ from the rewritten rule with a (...) block + /// and a (..)* loop. + /// + public int predictedAlt; + /// /// Constructs a new instance of the /// @@ -26,18 +33,15 @@ namespace Antlr4.Runtime.Atn /// the specified detailed lookahead information. /// /// The decision number - /// - /// The final simulator state containing the necessary - /// information to determine the result of a prediction, or - /// - /// if - /// the final state is not available + /// The final configuration set containing the necessary + /// information to determine the result of a prediction, or {@code null} if + /// the final configuration set is not available /// + /// /// The input token stream /// The start index for the current prediction /// The index at which the prediction was finally made /// - /// /// /// if the current lookahead is part of an LL /// prediction; otherwise, @@ -45,9 +49,10 @@ namespace Antlr4.Runtime.Atn /// if the current lookahead is part of /// an SLL prediction /// - public LookaheadEventInfo(int decision, SimulatorState state, ITokenStream input, int startIndex, int stopIndex, bool fullCtx) - : base(decision, state, input, startIndex, stopIndex, fullCtx) + public LookaheadEventInfo(int decision, ATNConfigSet configs, int predictedAlt, ITokenStream input, int startIndex, int stopIndex, bool fullCtx) + : base(decision, configs, input, startIndex, stopIndex, fullCtx) { + this.predictedAlt = predictedAlt; } } } diff --git a/runtime/CSharp/Atn/LoopEndState.cs b/runtime/CSharp/src/Atn/LoopEndState.cs similarity index 100% rename from runtime/CSharp/Atn/LoopEndState.cs rename to runtime/CSharp/src/Atn/LoopEndState.cs diff --git a/runtime/CSharp/Atn/MergeCache.cs b/runtime/CSharp/src/Atn/MergeCache.cs similarity index 100% rename from runtime/CSharp/Atn/MergeCache.cs rename to runtime/CSharp/src/Atn/MergeCache.cs diff --git a/runtime/CSharp/Atn/NotSetTransition.cs b/runtime/CSharp/src/Atn/NotSetTransition.cs similarity index 100% rename from runtime/CSharp/Atn/NotSetTransition.cs rename to runtime/CSharp/src/Atn/NotSetTransition.cs diff --git a/runtime/CSharp/Atn/ParseInfo.cs b/runtime/CSharp/src/Atn/ParseInfo.cs similarity index 100% rename from runtime/CSharp/Atn/ParseInfo.cs rename to runtime/CSharp/src/Atn/ParseInfo.cs diff --git a/runtime/CSharp/Atn/ParserATNSimulator.cs b/runtime/CSharp/src/Atn/ParserATNSimulator.cs similarity index 100% rename from runtime/CSharp/Atn/ParserATNSimulator.cs rename to runtime/CSharp/src/Atn/ParserATNSimulator.cs diff --git a/runtime/CSharp/Atn/PlusBlockStartState.cs b/runtime/CSharp/src/Atn/PlusBlockStartState.cs similarity index 100% rename from runtime/CSharp/Atn/PlusBlockStartState.cs rename to runtime/CSharp/src/Atn/PlusBlockStartState.cs diff --git a/runtime/CSharp/Atn/PlusLoopbackState.cs b/runtime/CSharp/src/Atn/PlusLoopbackState.cs similarity index 100% rename from runtime/CSharp/Atn/PlusLoopbackState.cs rename to runtime/CSharp/src/Atn/PlusLoopbackState.cs diff --git a/runtime/CSharp/Atn/PrecedencePredicateTransition.cs b/runtime/CSharp/src/Atn/PrecedencePredicateTransition.cs similarity index 100% rename from runtime/CSharp/Atn/PrecedencePredicateTransition.cs rename to runtime/CSharp/src/Atn/PrecedencePredicateTransition.cs diff --git a/runtime/CSharp/Atn/PredicateEvalInfo.cs b/runtime/CSharp/src/Atn/PredicateEvalInfo.cs similarity index 86% rename from runtime/CSharp/Atn/PredicateEvalInfo.cs rename to runtime/CSharp/src/Atn/PredicateEvalInfo.cs index 467ac40f2..cbc3d084d 100644 --- a/runtime/CSharp/Atn/PredicateEvalInfo.cs +++ b/runtime/CSharp/src/Atn/PredicateEvalInfo.cs @@ -49,7 +49,6 @@ namespace Antlr4.Runtime.Atn /// class with the /// specified detailed predicate evaluation information. /// - /// The simulator state /// The decision number /// The input token stream /// The start index for the current prediction @@ -68,10 +67,15 @@ namespace Antlr4.Runtime.Atn /// /// for more information. /// + /// {@code true} if the semantic context was + /// evaluated during LL prediction; otherwise, {@code false} if the semantic + /// context was evaluated during SLL prediction + /// + /// /// /// - public PredicateEvalInfo(SimulatorState state, int decision, ITokenStream input, int startIndex, int stopIndex, SemanticContext semctx, bool evalResult, int predictedAlt) - : base(decision, state, input, startIndex, stopIndex, state.useContext) + public PredicateEvalInfo(int decision, ITokenStream input, int startIndex, int stopIndex, SemanticContext semctx, bool evalResult, int predictedAlt, bool fullCtx) + : base(decision, new ATNConfigSet(), input, startIndex, stopIndex, fullCtx) { this.semctx = semctx; this.evalResult = evalResult; diff --git a/runtime/CSharp/Atn/PredicateTransition.cs b/runtime/CSharp/src/Atn/PredicateTransition.cs similarity index 100% rename from runtime/CSharp/Atn/PredicateTransition.cs rename to runtime/CSharp/src/Atn/PredicateTransition.cs diff --git a/runtime/CSharp/Atn/PredictionContext.cs b/runtime/CSharp/src/Atn/PredictionContext.cs similarity index 100% rename from runtime/CSharp/Atn/PredictionContext.cs rename to runtime/CSharp/src/Atn/PredictionContext.cs diff --git a/runtime/CSharp/Atn/PredictionContextCache.cs b/runtime/CSharp/src/Atn/PredictionContextCache.cs similarity index 100% rename from runtime/CSharp/Atn/PredictionContextCache.cs rename to runtime/CSharp/src/Atn/PredictionContextCache.cs diff --git a/runtime/CSharp/Atn/PredictionMode.cs b/runtime/CSharp/src/Atn/PredictionMode.cs similarity index 100% rename from runtime/CSharp/Atn/PredictionMode.cs rename to runtime/CSharp/src/Atn/PredictionMode.cs diff --git a/runtime/CSharp/Atn/ProfilingATNSimulator.cs b/runtime/CSharp/src/Atn/ProfilingATNSimulator.cs similarity index 87% rename from runtime/CSharp/Atn/ProfilingATNSimulator.cs rename to runtime/CSharp/src/Atn/ProfilingATNSimulator.cs index 8c5ac6b99..a88b819d9 100644 --- a/runtime/CSharp/Atn/ProfilingATNSimulator.cs +++ b/runtime/CSharp/src/Atn/ProfilingATNSimulator.cs @@ -71,7 +71,7 @@ namespace Antlr4.Runtime.Atn { decisions[decision].SLL_MaxLook = SLL_k; decisions[decision].SLL_MaxLookEvent = - new LookaheadEventInfo(decision, null/*, alt*/, input, startIndex, sllStopIndex, false); + new LookaheadEventInfo(decision, null, alt, input, startIndex, sllStopIndex, false); } if (llStopIndex >= 0) @@ -83,7 +83,7 @@ namespace Antlr4.Runtime.Atn { decisions[decision].LL_MaxLook = LL_k; decisions[decision].LL_MaxLookEvent = - new LookaheadEventInfo(decision, null/*, alt*/, input, startIndex, llStopIndex, true); + new LookaheadEventInfo(decision, null, alt, input, startIndex, llStopIndex, true); } } @@ -108,7 +108,7 @@ namespace Antlr4.Runtime.Atn if (existingTargetState == ERROR) { decisions[currentDecision].errors.Add( - new ErrorInfo(currentDecision, null /*previousD.configs*/, input, startIndex, sllStopIndex) + new ErrorInfo(currentDecision, previousD.configSet, input, startIndex, sllStopIndex, false) ); } } @@ -143,7 +143,7 @@ namespace Antlr4.Runtime.Atn else { // no reach on current lookahead symbol. ERROR. // TODO: does not handle delayed errors per getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule() decisions[currentDecision].errors.Add( - new ErrorInfo(currentDecision, null /*closure*/, input, startIndex, llStopIndex) + new ErrorInfo(currentDecision, closure, input, startIndex, llStopIndex, true) ); } } @@ -154,7 +154,7 @@ namespace Antlr4.Runtime.Atn } else { // no reach on current lookahead symbol. ERROR. decisions[currentDecision].errors.Add( - new ErrorInfo(currentDecision, null /*closure*/, input, startIndex, sllStopIndex) + new ErrorInfo(currentDecision, closure, input, startIndex, sllStopIndex, false) ); } } @@ -168,7 +168,7 @@ namespace Antlr4.Runtime.Atn bool fullContext = llStopIndex >= 0; int stopIndex = fullContext ? llStopIndex : sllStopIndex; decisions[currentDecision].predicateEvals.Add( - new PredicateEvalInfo(null , currentDecision, input, startIndex, stopIndex, pred, result, alt/*, fullCtx*/) + new PredicateEvalInfo(currentDecision, input, startIndex, stopIndex, pred, result, alt, fullCtx) ); } @@ -193,14 +193,14 @@ namespace Antlr4.Runtime.Atn if (prediction != conflictingAltResolvedBySLL) { decisions[currentDecision].contextSensitivities.Add( - new ContextSensitivityInfo(currentDecision, null /*configs*/, input, startIndex, stopIndex) + new ContextSensitivityInfo(currentDecision, configs, input, startIndex, stopIndex) ); } base.ReportContextSensitivity(dfa, prediction, configs, startIndex, stopIndex); } protected override void ReportAmbiguity(DFA dfa, DFAState D, int startIndex, int stopIndex, bool exact, - BitSet ambigAlts, ATNConfigSet configSet) + BitSet ambigAlts, ATNConfigSet configs) { int prediction; if (ambigAlts != null) @@ -208,22 +208,22 @@ namespace Antlr4.Runtime.Atn prediction = ambigAlts.NextSetBit(0); } else { - prediction = configSet.GetAlts().NextSetBit(0); + prediction = configs.GetAlts().NextSetBit(0); } - if (configSet.fullCtx && prediction != conflictingAltResolvedBySLL) + if (configs.fullCtx && prediction != conflictingAltResolvedBySLL) { // Even though this is an ambiguity we are reporting, we can // still detect some context sensitivities. Both SLL and LL // are showing a conflict, hence an ambiguity, but if they resolve // to different minimum alternatives we have also identified a // context sensitivity. - decisions[currentDecision].contextSensitivities.Add( new ContextSensitivityInfo(currentDecision, null /*configs*/, input, startIndex, stopIndex) ); + decisions[currentDecision].contextSensitivities.Add( new ContextSensitivityInfo(currentDecision, configs, input, startIndex, stopIndex) ); } decisions[currentDecision].ambiguities.Add( - new AmbiguityInfo(currentDecision, null /*configs, ambigAlts*/, - input, startIndex, stopIndex/*, configs.IsFullContext*/) + new AmbiguityInfo(currentDecision, configs, ambigAlts, + input, startIndex, stopIndex, configs.fullCtx) ); - base.ReportAmbiguity(dfa, D, startIndex, stopIndex, exact, ambigAlts, configSet); + base.ReportAmbiguity(dfa, D, startIndex, stopIndex, exact, ambigAlts, configs); } // --------------------------------------------------------------------- diff --git a/runtime/CSharp/Atn/RangeTransition.cs b/runtime/CSharp/src/Atn/RangeTransition.cs similarity index 100% rename from runtime/CSharp/Atn/RangeTransition.cs rename to runtime/CSharp/src/Atn/RangeTransition.cs diff --git a/runtime/CSharp/Atn/RuleStartState.cs b/runtime/CSharp/src/Atn/RuleStartState.cs similarity index 100% rename from runtime/CSharp/Atn/RuleStartState.cs rename to runtime/CSharp/src/Atn/RuleStartState.cs diff --git a/runtime/CSharp/Atn/RuleStopState.cs b/runtime/CSharp/src/Atn/RuleStopState.cs similarity index 100% rename from runtime/CSharp/Atn/RuleStopState.cs rename to runtime/CSharp/src/Atn/RuleStopState.cs diff --git a/runtime/CSharp/Atn/RuleTransition.cs b/runtime/CSharp/src/Atn/RuleTransition.cs similarity index 100% rename from runtime/CSharp/Atn/RuleTransition.cs rename to runtime/CSharp/src/Atn/RuleTransition.cs diff --git a/runtime/CSharp/Atn/SemanticContext.cs b/runtime/CSharp/src/Atn/SemanticContext.cs similarity index 100% rename from runtime/CSharp/Atn/SemanticContext.cs rename to runtime/CSharp/src/Atn/SemanticContext.cs diff --git a/runtime/CSharp/Atn/SetTransition.cs b/runtime/CSharp/src/Atn/SetTransition.cs similarity index 100% rename from runtime/CSharp/Atn/SetTransition.cs rename to runtime/CSharp/src/Atn/SetTransition.cs diff --git a/runtime/CSharp/Atn/SimulatorState.cs b/runtime/CSharp/src/Atn/SimulatorState.cs similarity index 100% rename from runtime/CSharp/Atn/SimulatorState.cs rename to runtime/CSharp/src/Atn/SimulatorState.cs diff --git a/runtime/CSharp/Atn/SingletonPredictionContext.cs b/runtime/CSharp/src/Atn/SingletonPredictionContext.cs similarity index 100% rename from runtime/CSharp/Atn/SingletonPredictionContext.cs rename to runtime/CSharp/src/Atn/SingletonPredictionContext.cs diff --git a/runtime/CSharp/Atn/StarBlockStartState.cs b/runtime/CSharp/src/Atn/StarBlockStartState.cs similarity index 100% rename from runtime/CSharp/Atn/StarBlockStartState.cs rename to runtime/CSharp/src/Atn/StarBlockStartState.cs diff --git a/runtime/CSharp/Atn/StarLoopEntryState.cs b/runtime/CSharp/src/Atn/StarLoopEntryState.cs similarity index 100% rename from runtime/CSharp/Atn/StarLoopEntryState.cs rename to runtime/CSharp/src/Atn/StarLoopEntryState.cs diff --git a/runtime/CSharp/Atn/StarLoopbackState.cs b/runtime/CSharp/src/Atn/StarLoopbackState.cs similarity index 100% rename from runtime/CSharp/Atn/StarLoopbackState.cs rename to runtime/CSharp/src/Atn/StarLoopbackState.cs diff --git a/runtime/CSharp/Atn/StateType.cs b/runtime/CSharp/src/Atn/StateType.cs similarity index 100% rename from runtime/CSharp/Atn/StateType.cs rename to runtime/CSharp/src/Atn/StateType.cs diff --git a/runtime/CSharp/Atn/TokensStartState.cs b/runtime/CSharp/src/Atn/TokensStartState.cs similarity index 100% rename from runtime/CSharp/Atn/TokensStartState.cs rename to runtime/CSharp/src/Atn/TokensStartState.cs diff --git a/runtime/CSharp/Atn/Transition.cs b/runtime/CSharp/src/Atn/Transition.cs similarity index 100% rename from runtime/CSharp/Atn/Transition.cs rename to runtime/CSharp/src/Atn/Transition.cs diff --git a/runtime/CSharp/Atn/TransitionType.cs b/runtime/CSharp/src/Atn/TransitionType.cs similarity index 100% rename from runtime/CSharp/Atn/TransitionType.cs rename to runtime/CSharp/src/Atn/TransitionType.cs diff --git a/runtime/CSharp/Atn/WildcardTransition.cs b/runtime/CSharp/src/Atn/WildcardTransition.cs similarity index 100% rename from runtime/CSharp/Atn/WildcardTransition.cs rename to runtime/CSharp/src/Atn/WildcardTransition.cs diff --git a/runtime/CSharp/BailErrorStrategy.cs b/runtime/CSharp/src/BailErrorStrategy.cs similarity index 100% rename from runtime/CSharp/BailErrorStrategy.cs rename to runtime/CSharp/src/BailErrorStrategy.cs diff --git a/runtime/CSharp/BaseErrorListener.cs b/runtime/CSharp/src/BaseErrorListener.cs similarity index 100% rename from runtime/CSharp/BaseErrorListener.cs rename to runtime/CSharp/src/BaseErrorListener.cs diff --git a/runtime/CSharp/BufferedTokenStream.cs b/runtime/CSharp/src/BufferedTokenStream.cs similarity index 100% rename from runtime/CSharp/BufferedTokenStream.cs rename to runtime/CSharp/src/BufferedTokenStream.cs diff --git a/runtime/CSharp/CharStreams.cs b/runtime/CSharp/src/CharStreams.cs similarity index 100% rename from runtime/CSharp/CharStreams.cs rename to runtime/CSharp/src/CharStreams.cs diff --git a/runtime/CSharp/CommonToken.cs b/runtime/CSharp/src/CommonToken.cs similarity index 100% rename from runtime/CSharp/CommonToken.cs rename to runtime/CSharp/src/CommonToken.cs diff --git a/runtime/CSharp/CommonTokenFactory.cs b/runtime/CSharp/src/CommonTokenFactory.cs similarity index 100% rename from runtime/CSharp/CommonTokenFactory.cs rename to runtime/CSharp/src/CommonTokenFactory.cs diff --git a/runtime/CSharp/CommonTokenStream.cs b/runtime/CSharp/src/CommonTokenStream.cs similarity index 100% rename from runtime/CSharp/CommonTokenStream.cs rename to runtime/CSharp/src/CommonTokenStream.cs diff --git a/runtime/CSharp/ConsoleErrorListener.cs b/runtime/CSharp/src/ConsoleErrorListener.cs similarity index 100% rename from runtime/CSharp/ConsoleErrorListener.cs rename to runtime/CSharp/src/ConsoleErrorListener.cs diff --git a/runtime/CSharp/DefaultErrorStrategy.cs b/runtime/CSharp/src/DefaultErrorStrategy.cs similarity index 100% rename from runtime/CSharp/DefaultErrorStrategy.cs rename to runtime/CSharp/src/DefaultErrorStrategy.cs diff --git a/runtime/CSharp/Dependents.cs b/runtime/CSharp/src/Dependents.cs similarity index 100% rename from runtime/CSharp/Dependents.cs rename to runtime/CSharp/src/Dependents.cs diff --git a/runtime/CSharp/Dfa/AbstractEdgeMap.cs b/runtime/CSharp/src/Dfa/AbstractEdgeMap.cs similarity index 100% rename from runtime/CSharp/Dfa/AbstractEdgeMap.cs rename to runtime/CSharp/src/Dfa/AbstractEdgeMap.cs diff --git a/runtime/CSharp/Dfa/AcceptStateInfo.cs b/runtime/CSharp/src/Dfa/AcceptStateInfo.cs similarity index 100% rename from runtime/CSharp/Dfa/AcceptStateInfo.cs rename to runtime/CSharp/src/Dfa/AcceptStateInfo.cs diff --git a/runtime/CSharp/Dfa/ArrayEdgeMap.cs b/runtime/CSharp/src/Dfa/ArrayEdgeMap.cs similarity index 100% rename from runtime/CSharp/Dfa/ArrayEdgeMap.cs rename to runtime/CSharp/src/Dfa/ArrayEdgeMap.cs diff --git a/runtime/CSharp/Dfa/DFA.cs b/runtime/CSharp/src/Dfa/DFA.cs similarity index 100% rename from runtime/CSharp/Dfa/DFA.cs rename to runtime/CSharp/src/Dfa/DFA.cs diff --git a/runtime/CSharp/Dfa/DFASerializer.cs b/runtime/CSharp/src/Dfa/DFASerializer.cs similarity index 100% rename from runtime/CSharp/Dfa/DFASerializer.cs rename to runtime/CSharp/src/Dfa/DFASerializer.cs diff --git a/runtime/CSharp/Dfa/DFAState.cs b/runtime/CSharp/src/Dfa/DFAState.cs similarity index 100% rename from runtime/CSharp/Dfa/DFAState.cs rename to runtime/CSharp/src/Dfa/DFAState.cs diff --git a/runtime/CSharp/Dfa/EmptyEdgeMap.cs b/runtime/CSharp/src/Dfa/EmptyEdgeMap.cs similarity index 100% rename from runtime/CSharp/Dfa/EmptyEdgeMap.cs rename to runtime/CSharp/src/Dfa/EmptyEdgeMap.cs diff --git a/runtime/CSharp/Dfa/IEdgeMap.cs b/runtime/CSharp/src/Dfa/IEdgeMap.cs similarity index 100% rename from runtime/CSharp/Dfa/IEdgeMap.cs rename to runtime/CSharp/src/Dfa/IEdgeMap.cs diff --git a/runtime/CSharp/Dfa/LexerDFASerializer.cs b/runtime/CSharp/src/Dfa/LexerDFASerializer.cs similarity index 100% rename from runtime/CSharp/Dfa/LexerDFASerializer.cs rename to runtime/CSharp/src/Dfa/LexerDFASerializer.cs diff --git a/runtime/CSharp/Dfa/SingletonEdgeMap.cs b/runtime/CSharp/src/Dfa/SingletonEdgeMap.cs similarity index 100% rename from runtime/CSharp/Dfa/SingletonEdgeMap.cs rename to runtime/CSharp/src/Dfa/SingletonEdgeMap.cs diff --git a/runtime/CSharp/Dfa/SparseEdgeMap.cs b/runtime/CSharp/src/Dfa/SparseEdgeMap.cs similarity index 100% rename from runtime/CSharp/Dfa/SparseEdgeMap.cs rename to runtime/CSharp/src/Dfa/SparseEdgeMap.cs diff --git a/runtime/CSharp/DiagnosticErrorListener.cs b/runtime/CSharp/src/DiagnosticErrorListener.cs similarity index 100% rename from runtime/CSharp/DiagnosticErrorListener.cs rename to runtime/CSharp/src/DiagnosticErrorListener.cs diff --git a/runtime/CSharp/FailedPredicateException.cs b/runtime/CSharp/src/FailedPredicateException.cs similarity index 100% rename from runtime/CSharp/FailedPredicateException.cs rename to runtime/CSharp/src/FailedPredicateException.cs diff --git a/runtime/CSharp/IAntlrErrorListener.cs b/runtime/CSharp/src/IAntlrErrorListener.cs similarity index 100% rename from runtime/CSharp/IAntlrErrorListener.cs rename to runtime/CSharp/src/IAntlrErrorListener.cs diff --git a/runtime/CSharp/IAntlrErrorStrategy.cs b/runtime/CSharp/src/IAntlrErrorStrategy.cs similarity index 100% rename from runtime/CSharp/IAntlrErrorStrategy.cs rename to runtime/CSharp/src/IAntlrErrorStrategy.cs diff --git a/runtime/CSharp/ICharStream.cs b/runtime/CSharp/src/ICharStream.cs similarity index 100% rename from runtime/CSharp/ICharStream.cs rename to runtime/CSharp/src/ICharStream.cs diff --git a/runtime/CSharp/IIntStream.cs b/runtime/CSharp/src/IIntStream.cs similarity index 100% rename from runtime/CSharp/IIntStream.cs rename to runtime/CSharp/src/IIntStream.cs diff --git a/runtime/CSharp/IParserErrorListener.cs b/runtime/CSharp/src/IParserErrorListener.cs similarity index 100% rename from runtime/CSharp/IParserErrorListener.cs rename to runtime/CSharp/src/IParserErrorListener.cs diff --git a/runtime/CSharp/IRecognizer.cs b/runtime/CSharp/src/IRecognizer.cs similarity index 100% rename from runtime/CSharp/IRecognizer.cs rename to runtime/CSharp/src/IRecognizer.cs diff --git a/runtime/CSharp/IToken.cs b/runtime/CSharp/src/IToken.cs similarity index 100% rename from runtime/CSharp/IToken.cs rename to runtime/CSharp/src/IToken.cs diff --git a/runtime/CSharp/ITokenFactory.cs b/runtime/CSharp/src/ITokenFactory.cs similarity index 100% rename from runtime/CSharp/ITokenFactory.cs rename to runtime/CSharp/src/ITokenFactory.cs diff --git a/runtime/CSharp/ITokenSource.cs b/runtime/CSharp/src/ITokenSource.cs similarity index 100% rename from runtime/CSharp/ITokenSource.cs rename to runtime/CSharp/src/ITokenSource.cs diff --git a/runtime/CSharp/ITokenStream.cs b/runtime/CSharp/src/ITokenStream.cs similarity index 100% rename from runtime/CSharp/ITokenStream.cs rename to runtime/CSharp/src/ITokenStream.cs diff --git a/runtime/CSharp/IVocabulary.cs b/runtime/CSharp/src/IVocabulary.cs similarity index 100% rename from runtime/CSharp/IVocabulary.cs rename to runtime/CSharp/src/IVocabulary.cs diff --git a/runtime/CSharp/IWritableToken.cs b/runtime/CSharp/src/IWritableToken.cs similarity index 100% rename from runtime/CSharp/IWritableToken.cs rename to runtime/CSharp/src/IWritableToken.cs diff --git a/runtime/CSharp/InputMismatchException.cs b/runtime/CSharp/src/InputMismatchException.cs similarity index 100% rename from runtime/CSharp/InputMismatchException.cs rename to runtime/CSharp/src/InputMismatchException.cs diff --git a/runtime/CSharp/InterpreterRuleContext.cs b/runtime/CSharp/src/InterpreterRuleContext.cs similarity index 100% rename from runtime/CSharp/InterpreterRuleContext.cs rename to runtime/CSharp/src/InterpreterRuleContext.cs diff --git a/runtime/CSharp/Lexer.cs b/runtime/CSharp/src/Lexer.cs similarity index 100% rename from runtime/CSharp/Lexer.cs rename to runtime/CSharp/src/Lexer.cs diff --git a/runtime/CSharp/LexerInterpreter.cs b/runtime/CSharp/src/LexerInterpreter.cs similarity index 100% rename from runtime/CSharp/LexerInterpreter.cs rename to runtime/CSharp/src/LexerInterpreter.cs diff --git a/runtime/CSharp/LexerNoViableAltException.cs b/runtime/CSharp/src/LexerNoViableAltException.cs similarity index 100% rename from runtime/CSharp/LexerNoViableAltException.cs rename to runtime/CSharp/src/LexerNoViableAltException.cs diff --git a/runtime/CSharp/ListTokenSource.cs b/runtime/CSharp/src/ListTokenSource.cs similarity index 100% rename from runtime/CSharp/ListTokenSource.cs rename to runtime/CSharp/src/ListTokenSource.cs diff --git a/runtime/CSharp/Misc/Args.cs b/runtime/CSharp/src/Misc/Args.cs similarity index 100% rename from runtime/CSharp/Misc/Args.cs rename to runtime/CSharp/src/Misc/Args.cs diff --git a/runtime/CSharp/Misc/ArrayList.cs b/runtime/CSharp/src/Misc/ArrayList.cs similarity index 100% rename from runtime/CSharp/Misc/ArrayList.cs rename to runtime/CSharp/src/Misc/ArrayList.cs diff --git a/runtime/CSharp/Misc/IIntSet.cs b/runtime/CSharp/src/Misc/IIntSet.cs similarity index 100% rename from runtime/CSharp/Misc/IIntSet.cs rename to runtime/CSharp/src/Misc/IIntSet.cs diff --git a/runtime/CSharp/Misc/Interval.cs b/runtime/CSharp/src/Misc/Interval.cs similarity index 100% rename from runtime/CSharp/Misc/Interval.cs rename to runtime/CSharp/src/Misc/Interval.cs diff --git a/runtime/CSharp/Misc/IntervalSet.cs b/runtime/CSharp/src/Misc/IntervalSet.cs similarity index 100% rename from runtime/CSharp/Misc/IntervalSet.cs rename to runtime/CSharp/src/Misc/IntervalSet.cs diff --git a/runtime/CSharp/Misc/MultiMap.cs b/runtime/CSharp/src/Misc/MultiMap.cs similarity index 100% rename from runtime/CSharp/Misc/MultiMap.cs rename to runtime/CSharp/src/Misc/MultiMap.cs diff --git a/runtime/CSharp/Misc/MurmurHash.cs b/runtime/CSharp/src/Misc/MurmurHash.cs similarity index 100% rename from runtime/CSharp/Misc/MurmurHash.cs rename to runtime/CSharp/src/Misc/MurmurHash.cs diff --git a/runtime/CSharp/Misc/NotNullAttribute.cs b/runtime/CSharp/src/Misc/NotNullAttribute.cs similarity index 100% rename from runtime/CSharp/Misc/NotNullAttribute.cs rename to runtime/CSharp/src/Misc/NotNullAttribute.cs diff --git a/runtime/CSharp/Misc/NullableAttribute.cs b/runtime/CSharp/src/Misc/NullableAttribute.cs similarity index 100% rename from runtime/CSharp/Misc/NullableAttribute.cs rename to runtime/CSharp/src/Misc/NullableAttribute.cs diff --git a/runtime/CSharp/Misc/Pair.cs b/runtime/CSharp/src/Misc/Pair.cs similarity index 100% rename from runtime/CSharp/Misc/Pair.cs rename to runtime/CSharp/src/Misc/Pair.cs diff --git a/runtime/CSharp/Misc/ParseCanceledException.cs b/runtime/CSharp/src/Misc/ParseCanceledException.cs similarity index 100% rename from runtime/CSharp/Misc/ParseCanceledException.cs rename to runtime/CSharp/src/Misc/ParseCanceledException.cs diff --git a/runtime/CSharp/Misc/RuleDependencyChecker.cs b/runtime/CSharp/src/Misc/RuleDependencyChecker.cs similarity index 100% rename from runtime/CSharp/Misc/RuleDependencyChecker.cs rename to runtime/CSharp/src/Misc/RuleDependencyChecker.cs diff --git a/runtime/CSharp/Misc/Utils.cs b/runtime/CSharp/src/Misc/Utils.cs similarity index 100% rename from runtime/CSharp/Misc/Utils.cs rename to runtime/CSharp/src/Misc/Utils.cs diff --git a/runtime/CSharp/NoViableAltException.cs b/runtime/CSharp/src/NoViableAltException.cs similarity index 100% rename from runtime/CSharp/NoViableAltException.cs rename to runtime/CSharp/src/NoViableAltException.cs diff --git a/runtime/CSharp/Parser.cs b/runtime/CSharp/src/Parser.cs similarity index 100% rename from runtime/CSharp/Parser.cs rename to runtime/CSharp/src/Parser.cs diff --git a/runtime/CSharp/ParserInterpreter.cs b/runtime/CSharp/src/ParserInterpreter.cs similarity index 100% rename from runtime/CSharp/ParserInterpreter.cs rename to runtime/CSharp/src/ParserInterpreter.cs diff --git a/runtime/CSharp/ParserRuleContext.cs b/runtime/CSharp/src/ParserRuleContext.cs similarity index 100% rename from runtime/CSharp/ParserRuleContext.cs rename to runtime/CSharp/src/ParserRuleContext.cs diff --git a/runtime/CSharp/Properties/AssemblyInfo.cs b/runtime/CSharp/src/Properties/AssemblyInfo.cs similarity index 100% rename from runtime/CSharp/Properties/AssemblyInfo.cs rename to runtime/CSharp/src/Properties/AssemblyInfo.cs diff --git a/runtime/CSharp/ProxyErrorListener.cs b/runtime/CSharp/src/ProxyErrorListener.cs similarity index 100% rename from runtime/CSharp/ProxyErrorListener.cs rename to runtime/CSharp/src/ProxyErrorListener.cs diff --git a/runtime/CSharp/ProxyParserErrorListener.cs b/runtime/CSharp/src/ProxyParserErrorListener.cs similarity index 100% rename from runtime/CSharp/ProxyParserErrorListener.cs rename to runtime/CSharp/src/ProxyParserErrorListener.cs diff --git a/runtime/CSharp/README.md b/runtime/CSharp/src/README.md similarity index 100% rename from runtime/CSharp/README.md rename to runtime/CSharp/src/README.md diff --git a/runtime/CSharp/RecognitionException.cs b/runtime/CSharp/src/RecognitionException.cs similarity index 100% rename from runtime/CSharp/RecognitionException.cs rename to runtime/CSharp/src/RecognitionException.cs diff --git a/runtime/CSharp/Recognizer.cs b/runtime/CSharp/src/Recognizer.cs similarity index 100% rename from runtime/CSharp/Recognizer.cs rename to runtime/CSharp/src/Recognizer.cs diff --git a/runtime/CSharp/RuleContext.cs b/runtime/CSharp/src/RuleContext.cs similarity index 100% rename from runtime/CSharp/RuleContext.cs rename to runtime/CSharp/src/RuleContext.cs diff --git a/runtime/CSharp/RuleDependencyAttribute.cs b/runtime/CSharp/src/RuleDependencyAttribute.cs similarity index 100% rename from runtime/CSharp/RuleDependencyAttribute.cs rename to runtime/CSharp/src/RuleDependencyAttribute.cs diff --git a/runtime/CSharp/RuleVersionAttribute.cs b/runtime/CSharp/src/RuleVersionAttribute.cs similarity index 100% rename from runtime/CSharp/RuleVersionAttribute.cs rename to runtime/CSharp/src/RuleVersionAttribute.cs diff --git a/runtime/CSharp/Sharpen/Arrays.cs b/runtime/CSharp/src/Sharpen/Arrays.cs similarity index 100% rename from runtime/CSharp/Sharpen/Arrays.cs rename to runtime/CSharp/src/Sharpen/Arrays.cs diff --git a/runtime/CSharp/Sharpen/AtomicReference.cs b/runtime/CSharp/src/Sharpen/AtomicReference.cs similarity index 100% rename from runtime/CSharp/Sharpen/AtomicReference.cs rename to runtime/CSharp/src/Sharpen/AtomicReference.cs diff --git a/runtime/CSharp/Sharpen/BitSet.cs b/runtime/CSharp/src/Sharpen/BitSet.cs similarity index 100% rename from runtime/CSharp/Sharpen/BitSet.cs rename to runtime/CSharp/src/Sharpen/BitSet.cs diff --git a/runtime/CSharp/Sharpen/Collections.cs b/runtime/CSharp/src/Sharpen/Collections.cs similarity index 100% rename from runtime/CSharp/Sharpen/Collections.cs rename to runtime/CSharp/src/Sharpen/Collections.cs diff --git a/runtime/CSharp/Sharpen/DictionaryExtensions.cs b/runtime/CSharp/src/Sharpen/DictionaryExtensions.cs similarity index 100% rename from runtime/CSharp/Sharpen/DictionaryExtensions.cs rename to runtime/CSharp/src/Sharpen/DictionaryExtensions.cs diff --git a/runtime/CSharp/Sharpen/ListExtensions.cs b/runtime/CSharp/src/Sharpen/ListExtensions.cs similarity index 100% rename from runtime/CSharp/Sharpen/ListExtensions.cs rename to runtime/CSharp/src/Sharpen/ListExtensions.cs diff --git a/runtime/CSharp/Sharpen/Runtime.cs b/runtime/CSharp/src/Sharpen/Runtime.cs similarity index 100% rename from runtime/CSharp/Sharpen/Runtime.cs rename to runtime/CSharp/src/Sharpen/Runtime.cs diff --git a/runtime/CSharp/Sharpen/SequenceEqualityComparer.cs b/runtime/CSharp/src/Sharpen/SequenceEqualityComparer.cs similarity index 100% rename from runtime/CSharp/Sharpen/SequenceEqualityComparer.cs rename to runtime/CSharp/src/Sharpen/SequenceEqualityComparer.cs diff --git a/runtime/CSharp/TokenStreamRewriter.cs b/runtime/CSharp/src/TokenStreamRewriter.cs similarity index 100% rename from runtime/CSharp/TokenStreamRewriter.cs rename to runtime/CSharp/src/TokenStreamRewriter.cs diff --git a/runtime/CSharp/TokenTypes.cs b/runtime/CSharp/src/TokenTypes.cs similarity index 100% rename from runtime/CSharp/TokenTypes.cs rename to runtime/CSharp/src/TokenTypes.cs diff --git a/runtime/CSharp/Tree/AbstractParseTreeVisitor.cs b/runtime/CSharp/src/Tree/AbstractParseTreeVisitor.cs similarity index 100% rename from runtime/CSharp/Tree/AbstractParseTreeVisitor.cs rename to runtime/CSharp/src/Tree/AbstractParseTreeVisitor.cs diff --git a/runtime/CSharp/Tree/ErrorNodeImpl.cs b/runtime/CSharp/src/Tree/ErrorNodeImpl.cs similarity index 100% rename from runtime/CSharp/Tree/ErrorNodeImpl.cs rename to runtime/CSharp/src/Tree/ErrorNodeImpl.cs diff --git a/runtime/CSharp/Tree/IErrorNode.cs b/runtime/CSharp/src/Tree/IErrorNode.cs similarity index 100% rename from runtime/CSharp/Tree/IErrorNode.cs rename to runtime/CSharp/src/Tree/IErrorNode.cs diff --git a/runtime/CSharp/Tree/IParseTree.cs b/runtime/CSharp/src/Tree/IParseTree.cs similarity index 100% rename from runtime/CSharp/Tree/IParseTree.cs rename to runtime/CSharp/src/Tree/IParseTree.cs diff --git a/runtime/CSharp/Tree/IParseTreeListener.cs b/runtime/CSharp/src/Tree/IParseTreeListener.cs similarity index 100% rename from runtime/CSharp/Tree/IParseTreeListener.cs rename to runtime/CSharp/src/Tree/IParseTreeListener.cs diff --git a/runtime/CSharp/Tree/IParseTreeVisitor.cs b/runtime/CSharp/src/Tree/IParseTreeVisitor.cs similarity index 100% rename from runtime/CSharp/Tree/IParseTreeVisitor.cs rename to runtime/CSharp/src/Tree/IParseTreeVisitor.cs diff --git a/runtime/CSharp/Tree/IRuleNode.cs b/runtime/CSharp/src/Tree/IRuleNode.cs similarity index 100% rename from runtime/CSharp/Tree/IRuleNode.cs rename to runtime/CSharp/src/Tree/IRuleNode.cs diff --git a/runtime/CSharp/Tree/ISyntaxTree.cs b/runtime/CSharp/src/Tree/ISyntaxTree.cs similarity index 100% rename from runtime/CSharp/Tree/ISyntaxTree.cs rename to runtime/CSharp/src/Tree/ISyntaxTree.cs diff --git a/runtime/CSharp/Tree/ITerminalNode.cs b/runtime/CSharp/src/Tree/ITerminalNode.cs similarity index 100% rename from runtime/CSharp/Tree/ITerminalNode.cs rename to runtime/CSharp/src/Tree/ITerminalNode.cs diff --git a/runtime/CSharp/Tree/ITree.cs b/runtime/CSharp/src/Tree/ITree.cs similarity index 100% rename from runtime/CSharp/Tree/ITree.cs rename to runtime/CSharp/src/Tree/ITree.cs diff --git a/runtime/CSharp/Tree/ParseTreeProperty.cs b/runtime/CSharp/src/Tree/ParseTreeProperty.cs similarity index 100% rename from runtime/CSharp/Tree/ParseTreeProperty.cs rename to runtime/CSharp/src/Tree/ParseTreeProperty.cs diff --git a/runtime/CSharp/Tree/ParseTreeWalker.cs b/runtime/CSharp/src/Tree/ParseTreeWalker.cs similarity index 100% rename from runtime/CSharp/Tree/ParseTreeWalker.cs rename to runtime/CSharp/src/Tree/ParseTreeWalker.cs diff --git a/runtime/CSharp/Tree/Pattern/Chunk.cs b/runtime/CSharp/src/Tree/Pattern/Chunk.cs similarity index 100% rename from runtime/CSharp/Tree/Pattern/Chunk.cs rename to runtime/CSharp/src/Tree/Pattern/Chunk.cs diff --git a/runtime/CSharp/Tree/Pattern/ParseTreeMatch.cs b/runtime/CSharp/src/Tree/Pattern/ParseTreeMatch.cs similarity index 100% rename from runtime/CSharp/Tree/Pattern/ParseTreeMatch.cs rename to runtime/CSharp/src/Tree/Pattern/ParseTreeMatch.cs diff --git a/runtime/CSharp/Tree/Pattern/ParseTreePattern.cs b/runtime/CSharp/src/Tree/Pattern/ParseTreePattern.cs similarity index 100% rename from runtime/CSharp/Tree/Pattern/ParseTreePattern.cs rename to runtime/CSharp/src/Tree/Pattern/ParseTreePattern.cs diff --git a/runtime/CSharp/Tree/Pattern/ParseTreePatternMatcher.cs b/runtime/CSharp/src/Tree/Pattern/ParseTreePatternMatcher.cs similarity index 100% rename from runtime/CSharp/Tree/Pattern/ParseTreePatternMatcher.cs rename to runtime/CSharp/src/Tree/Pattern/ParseTreePatternMatcher.cs diff --git a/runtime/CSharp/Tree/Pattern/RuleTagToken.cs b/runtime/CSharp/src/Tree/Pattern/RuleTagToken.cs similarity index 100% rename from runtime/CSharp/Tree/Pattern/RuleTagToken.cs rename to runtime/CSharp/src/Tree/Pattern/RuleTagToken.cs diff --git a/runtime/CSharp/Tree/Pattern/TagChunk.cs b/runtime/CSharp/src/Tree/Pattern/TagChunk.cs similarity index 100% rename from runtime/CSharp/Tree/Pattern/TagChunk.cs rename to runtime/CSharp/src/Tree/Pattern/TagChunk.cs diff --git a/runtime/CSharp/Tree/Pattern/TextChunk.cs b/runtime/CSharp/src/Tree/Pattern/TextChunk.cs similarity index 100% rename from runtime/CSharp/Tree/Pattern/TextChunk.cs rename to runtime/CSharp/src/Tree/Pattern/TextChunk.cs diff --git a/runtime/CSharp/Tree/Pattern/TokenTagToken.cs b/runtime/CSharp/src/Tree/Pattern/TokenTagToken.cs similarity index 100% rename from runtime/CSharp/Tree/Pattern/TokenTagToken.cs rename to runtime/CSharp/src/Tree/Pattern/TokenTagToken.cs diff --git a/runtime/CSharp/Tree/TerminalNodeImpl.cs b/runtime/CSharp/src/Tree/TerminalNodeImpl.cs similarity index 100% rename from runtime/CSharp/Tree/TerminalNodeImpl.cs rename to runtime/CSharp/src/Tree/TerminalNodeImpl.cs diff --git a/runtime/CSharp/Tree/Trees.cs b/runtime/CSharp/src/Tree/Trees.cs similarity index 100% rename from runtime/CSharp/Tree/Trees.cs rename to runtime/CSharp/src/Tree/Trees.cs diff --git a/runtime/CSharp/Tree/Xpath/XPath.cs b/runtime/CSharp/src/Tree/Xpath/XPath.cs similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPath.cs rename to runtime/CSharp/src/Tree/Xpath/XPath.cs diff --git a/runtime/CSharp/Tree/Xpath/XPathElement.cs b/runtime/CSharp/src/Tree/Xpath/XPathElement.cs similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPathElement.cs rename to runtime/CSharp/src/Tree/Xpath/XPathElement.cs diff --git a/runtime/CSharp/Tree/Xpath/XPathLexer.cs b/runtime/CSharp/src/Tree/Xpath/XPathLexer.cs similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPathLexer.cs rename to runtime/CSharp/src/Tree/Xpath/XPathLexer.cs diff --git a/runtime/CSharp/Tree/Xpath/XPathLexer.g4 b/runtime/CSharp/src/Tree/Xpath/XPathLexer.g4 similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPathLexer.g4 rename to runtime/CSharp/src/Tree/Xpath/XPathLexer.g4 diff --git a/runtime/CSharp/Tree/Xpath/XPathLexer.tokens b/runtime/CSharp/src/Tree/Xpath/XPathLexer.tokens similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPathLexer.tokens rename to runtime/CSharp/src/Tree/Xpath/XPathLexer.tokens diff --git a/runtime/CSharp/Tree/Xpath/XPathLexerErrorListener.cs b/runtime/CSharp/src/Tree/Xpath/XPathLexerErrorListener.cs similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPathLexerErrorListener.cs rename to runtime/CSharp/src/Tree/Xpath/XPathLexerErrorListener.cs diff --git a/runtime/CSharp/Tree/Xpath/XPathRuleAnywhereElement.cs b/runtime/CSharp/src/Tree/Xpath/XPathRuleAnywhereElement.cs similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPathRuleAnywhereElement.cs rename to runtime/CSharp/src/Tree/Xpath/XPathRuleAnywhereElement.cs diff --git a/runtime/CSharp/Tree/Xpath/XPathRuleElement.cs b/runtime/CSharp/src/Tree/Xpath/XPathRuleElement.cs similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPathRuleElement.cs rename to runtime/CSharp/src/Tree/Xpath/XPathRuleElement.cs diff --git a/runtime/CSharp/Tree/Xpath/XPathTokenAnywhereElement.cs b/runtime/CSharp/src/Tree/Xpath/XPathTokenAnywhereElement.cs similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPathTokenAnywhereElement.cs rename to runtime/CSharp/src/Tree/Xpath/XPathTokenAnywhereElement.cs diff --git a/runtime/CSharp/Tree/Xpath/XPathTokenElement.cs b/runtime/CSharp/src/Tree/Xpath/XPathTokenElement.cs similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPathTokenElement.cs rename to runtime/CSharp/src/Tree/Xpath/XPathTokenElement.cs diff --git a/runtime/CSharp/Tree/Xpath/XPathWildcardAnywhereElement.cs b/runtime/CSharp/src/Tree/Xpath/XPathWildcardAnywhereElement.cs similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPathWildcardAnywhereElement.cs rename to runtime/CSharp/src/Tree/Xpath/XPathWildcardAnywhereElement.cs diff --git a/runtime/CSharp/Tree/Xpath/XPathWildcardElement.cs b/runtime/CSharp/src/Tree/Xpath/XPathWildcardElement.cs similarity index 100% rename from runtime/CSharp/Tree/Xpath/XPathWildcardElement.cs rename to runtime/CSharp/src/Tree/Xpath/XPathWildcardElement.cs diff --git a/runtime/CSharp/UnbufferedCharStream.cs b/runtime/CSharp/src/UnbufferedCharStream.cs similarity index 100% rename from runtime/CSharp/UnbufferedCharStream.cs rename to runtime/CSharp/src/UnbufferedCharStream.cs diff --git a/runtime/CSharp/UnbufferedTokenStream.cs b/runtime/CSharp/src/UnbufferedTokenStream.cs similarity index 100% rename from runtime/CSharp/UnbufferedTokenStream.cs rename to runtime/CSharp/src/UnbufferedTokenStream.cs diff --git a/runtime/CSharp/Vocabulary.cs b/runtime/CSharp/src/Vocabulary.cs similarity index 100% rename from runtime/CSharp/Vocabulary.cs rename to runtime/CSharp/src/Vocabulary.cs diff --git a/runtime/CSharp/tests/issue-2693/ErrorListener.cs b/runtime/CSharp/tests/issue-2693/ErrorListener.cs new file mode 100644 index 000000000..1d610a3b5 --- /dev/null +++ b/runtime/CSharp/tests/issue-2693/ErrorListener.cs @@ -0,0 +1,18 @@ +using Antlr4.Runtime; +using Antlr4.Runtime.Misc; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +public class ErrorListener : ConsoleErrorListener +{ + public bool had_error; + + public override void SyntaxError(TextWriter output, IRecognizer recognizer, S offendingSymbol, int line, + int col, string msg, RecognitionException e) + { + had_error = true; + base.SyntaxError(output, recognizer, offendingSymbol, line, col, msg, e); + } +} diff --git a/runtime/CSharp/tests/issue-2693/Program.cs b/runtime/CSharp/tests/issue-2693/Program.cs new file mode 100644 index 000000000..a7b3efdb0 --- /dev/null +++ b/runtime/CSharp/tests/issue-2693/Program.cs @@ -0,0 +1,90 @@ +using Antlr4.Runtime; +using System; +using System.Linq; +using System.Text; + +public class Program +{ + static void Main(string[] args) + { + bool show_tree = false; + bool show_tokens = false; + string file_name = null; + string input = null; + for (int i = 0; i < args.Length; ++i) + { + if (args[i].Equals("-tokens")) + { + show_tokens = true; + continue; + } + else if (args[i].Equals("-tree")) + { + show_tree = true; + continue; + } + else if (args[i].Equals("-input")) + input = args[i]; + else if (args[i].Equals("-file")) + file_name = args[++i]; + } + ICharStream str = null; + if (input == null && file_name == null) + { + StringBuilder sb = new StringBuilder(); + int ch; + while ((ch = System.Console.Read()) != -1) + { + sb.Append((char)ch); + } + input = sb.ToString(); + str = CharStreams.fromString(input); + } + else if (input != null) + { + str = CharStreams.fromString(input); + } + else if (file_name != null) + { + str = CharStreams.fromPath(file_name); + } + var lexer = new asm8080Lexer(str); + if (show_tokens) + { + StringBuilder new_s = new StringBuilder(); + for (int i = 0; ; ++i) + { + var ro_token = lexer.NextToken(); + var token = (CommonToken)ro_token; + token.TokenIndex = i; + new_s.AppendLine(token.ToString()); + if (token.Type == Antlr4.Runtime.TokenConstants.EOF) + break; + } + System.Console.Error.WriteLine(new_s.ToString()); + } + lexer.Reset(); + var tokens = new CommonTokenStream(lexer); + var parser = new asm8080Parser(tokens); + var listener_lexer = new ErrorListener(); + var listener_parser = new ErrorListener(); + lexer.AddErrorListener(listener_lexer); + parser.AddErrorListener(listener_parser); + parser.Profile = true; + var tree = parser.prog(); + if (listener_lexer.had_error || listener_parser.had_error) + { + System.Console.Error.WriteLine("parse failed."); + } + else + { + System.Console.Error.WriteLine("parse succeeded."); + } + if (show_tree) + { + System.Console.Error.WriteLine(tree.ToStringTree()); + } + System.Console.Out.WriteLine(String.Join(", ", parser.ParseInfo.getDecisionInfo().Select(d => d.ToString()))); + System.Environment.Exit(listener_lexer.had_error || listener_parser.had_error ? 1 : 0); + } +} diff --git a/runtime/CSharp/tests/issue-2693/Test.csproj b/runtime/CSharp/tests/issue-2693/Test.csproj new file mode 100644 index 000000000..33b85beef --- /dev/null +++ b/runtime/CSharp/tests/issue-2693/Test.csproj @@ -0,0 +1,27 @@ + + + + net5.0 + Exe + + + + + + + + ../../../../tool/target/antlr4-*-SNAPSHOT-complete.jar + + + + + + + + + PackageReference + + + 1701;1702;3021 + + diff --git a/runtime/CSharp/tests/issue-2693/TreeOutput.cs b/runtime/CSharp/tests/issue-2693/TreeOutput.cs new file mode 100644 index 000000000..297504946 --- /dev/null +++ b/runtime/CSharp/tests/issue-2693/TreeOutput.cs @@ -0,0 +1,108 @@ + +// Template generated code from Antlr4BuildTasks.dotnet-antlr v 1.3 + +using Antlr4.Runtime; +using Antlr4.Runtime.Misc; +using Antlr4.Runtime.Tree; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +public class TreeOutput +{ + private static int changed = 0; + private static bool first_time = true; + + public static StringBuilder OutputTree(IParseTree tree, Lexer lexer, Parser parser, CommonTokenStream stream) + { + changed = 0; + first_time = true; + var sb = new StringBuilder(); + ParenthesizedAST(tree, sb, lexer, parser, stream); + return sb; + } + + private static void ParenthesizedAST(IParseTree tree, StringBuilder sb, Lexer lexer, Parser parser, CommonTokenStream stream, int level = 0) + { + if (tree as TerminalNodeImpl != null) + { + TerminalNodeImpl tok = tree as TerminalNodeImpl; + Interval interval = tok.SourceInterval; + IList inter = null; + if (tok.Symbol.TokenIndex >= 0) + inter = stream?.GetHiddenTokensToLeft(tok.Symbol.TokenIndex); + if (inter != null) + foreach (var t in inter) + { + var ty = tok.Symbol.Type; + var name = lexer.Vocabulary.GetSymbolicName(ty); + StartLine(sb, level); + sb.AppendLine("(" + name + " text = " + PerformEscapes(t.Text) + " " + lexer.ChannelNames[t.Channel]); + } + { + var ty = tok.Symbol.Type; + var name = lexer.Vocabulary.GetSymbolicName(ty); + StartLine(sb, level); + sb.AppendLine("( " + name + " i =" + tree.SourceInterval.a + + " txt =" + PerformEscapes(tree.GetText()) + + " tt =" + tok.Symbol.Type + + " " + lexer.ChannelNames[tok.Symbol.Channel]); + } + } + else + { + var x = tree as RuleContext; + var ri = x.RuleIndex; + var name = parser.RuleNames[ri]; + StartLine(sb, level); + sb.Append("( " + name); + sb.AppendLine(); + } + for (int i = 0; i= 0) + { + if (!first_time) + { + for (int j = 0; j < level; ++j) sb.Append(" "); + for (int k = 0; k < 1 + changed - level; ++k) sb.Append(") "); + sb.AppendLine(); + } + changed = 0; + first_time = false; + } + changed = level; + for (int j = 0; j < level; ++j) sb.Append(" "); + } + + private static string ToLiteral(string input) + { + using (var writer = new StringWriter()) + { + var literal = input; + literal = literal.Replace("\\", "\\\\"); + return literal; + } + } + + public static string PerformEscapes(string s) + { + StringBuilder new_s = new StringBuilder(); + new_s.Append(ToLiteral(s)); + return new_s.ToString(); + } +} diff --git a/runtime/CSharp/tests/issue-2693/asm8080.g4 b/runtime/CSharp/tests/issue-2693/asm8080.g4 new file mode 100644 index 000000000..6f22bd08d --- /dev/null +++ b/runtime/CSharp/tests/issue-2693/asm8080.g4 @@ -0,0 +1,288 @@ +/* +BSD License + +Copyright (c) 2018, Tom Everett +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of Tom Everett nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* +* http://fms.komkon.org/comp/CPUs/8080.txt +*/ + +grammar asm8080; + +prog + : (line? EOL) + + ; + +line + : lbl? (instruction | directive)? comment? + ; + +instruction + : opcode expressionlist? + ; + +opcode + : OPCODE + ; + +register_ + : REGISTER + ; + +directive + : argument? assemblerdirective expressionlist + ; + +assemblerdirective + : ASSEMBLER_DIRECTIVE + ; + +lbl + : label ':'? + ; + +expressionlist + : expression (',' expression)* + ; + +label + : name + ; + +expression + : multiplyingExpression (('+' | '-') multiplyingExpression)* + ; + +multiplyingExpression + : argument (('*' | '/') argument)* + ; + +argument + : number + | register_ + | dollar + | name + | string + | ('(' expression ')') + ; + +dollar + : '$' + ; + +string + : STRING + ; + +name + : NAME + ; + +number + : NUMBER + ; + +comment + : COMMENT + ; + + +ASSEMBLER_DIRECTIVE + : (O R G) | (E N D) | (E Q U) | (D B) | (D W) | (D S) | (I F) | (E N D I F) | (S E T) + ; + + +REGISTER + : 'A' | 'B' | 'C' | 'D' | 'E' | 'H' | 'L' | 'PC' | 'SP' + ; + + +OPCODE + : (M O V) | (M V I) | (L D A) | (S T A) | (L D A X) | (S T A X) | (L H L D) | (S H L D) | (L X I) | (P U S H) | (P O P) | (X T H L) | (S P H L) | (P C H L) | (X C H G) | (A D D) | (S U B) | (I N R) | (D C R) | (C M P) | (A N A) | (O R A) | (X R A) | (A D I) | (S U I) | (C P I) | (A N I) | (O R I) | (X R I) | (D A A) | (A D C) | (A C I) | (S B B) | (S B I) | (D A D) | (I N X) | (D C X) | (J M P) | (C A L L) | (R E T) | (R A L) | (R A R) | (R L C) | (R R C) | (I N) | (O U T) | (C M C) | (S T C) | (C M A) | (H L T) | (N O P) | (D I) | (E I) | (R S T) | (J N Z) | (J Z) | (J N C) | (J C) | (J P O) | (J P E) | (J P) | (J M) | (C N Z) | (C Z) | (C N C) | (C C) | (C P O) | (C P E) | (C P) | (C M) | (R N Z) | (R Z) | (R N C) | (R C) | (R P O) | (R P E) | (R P) | (R M) + ; + + +fragment A + : ('a' | 'A') + ; + + +fragment B + : ('b' | 'B') + ; + + +fragment C + : ('c' | 'C') + ; + + +fragment D + : ('d' | 'D') + ; + + +fragment E + : ('e' | 'E') + ; + + +fragment F + : ('f' | 'F') + ; + + +fragment G + : ('g' | 'G') + ; + + +fragment H + : ('h' | 'H') + ; + + +fragment I + : ('i' | 'I') + ; + + +fragment J + : ('j' | 'J') + ; + + +fragment K + : ('k' | 'K') + ; + + +fragment L + : ('l' | 'L') + ; + + +fragment M + : ('m' | 'M') + ; + + +fragment N + : ('n' | 'N') + ; + + +fragment O + : ('o' | 'O') + ; + + +fragment P + : ('p' | 'P') + ; + + +fragment Q + : ('q' | 'Q') + ; + + +fragment R + : ('r' | 'R') + ; + + +fragment S + : ('s' | 'S') + ; + + +fragment T + : ('t' | 'T') + ; + + +fragment U + : ('u' | 'U') + ; + + +fragment V + : ('v' | 'V') + ; + + +fragment W + : ('w' | 'W') + ; + + +fragment X + : ('x' | 'X') + ; + + +fragment Y + : ('y' | 'Y') + ; + + +fragment Z + : ('z' | 'Z') + ; + + +NAME + : [a-zA-Z] [a-zA-Z0-9."]* + ; + + +NUMBER + : '$'? [0-9a-fA-F] + ('H' | 'h')? + ; + + +COMMENT + : ';' ~ [\r\n]* -> skip + ; + + +STRING + : '\u0027' ~'\u0027'* '\u0027' + ; + + +EOL + : [\r\n] + + ; + + +WS + : [ \t] -> skip + ; diff --git a/runtime/CSharp/tests/issue-2693/cpm22.asm b/runtime/CSharp/tests/issue-2693/cpm22.asm new file mode 100644 index 000000000..28cfe03f0 --- /dev/null +++ b/runtime/CSharp/tests/issue-2693/cpm22.asm @@ -0,0 +1,3739 @@ + +;************************************************************** +;* +;* C P / M version 2 . 2 +;* +;* Reconstructed from memory image on February 27, 1981 +;* +;* by Clark A. Calkins +;* +;************************************************************** +; +; Set memory limit here. This is the amount of contigeous +; ram starting from 0000. CP/M will reside at the end of this space. +; +MEM EQU 62 ;for a 62k system (TS802 TEST - WORKS OK). +; +IOBYTE EQU 3 ;i/o definition byte. +TDRIVE EQU 4 ;current drive name and user number. +ENTRY EQU 5 ;entry point for the cp/m bdos. +TFCB EQU 5CH ;default file control block. +TBUFF EQU 80H ;i/o buffer and command line storage. +TBASE EQU 100H ;transiant program storage area. +; +; Set control character equates. +; +CNTRLC EQU 3 ;control-c +CNTRLE EQU 05H ;control-e +BS EQU 08H ;backspace +TAB EQU 09H ;tab +LF EQU 0AH ;line feed +FF EQU 0CH ;form feed +CR EQU 0DH ;carriage return +CNTRLP EQU 10H ;control-p +CNTRLR EQU 12H ;control-r +CNTRLS EQU 13H ;control-s +CNTRLU EQU 15H ;control-u +CNTRLX EQU 18H ;control-x +CNTRLZ EQU 1AH ;control-z (end-of-file mark) +DEL EQU 7FH ;rubout +; +; Set origin for CP/M +; + ORG (MEM-7)*1024 +; +CBASE JMP COMMAND ;execute command processor (ccp). + JMP CLEARBUF ;entry to empty input buffer before starting ccp. + +; +; Standard cp/m ccp input buffer. Format is (max length), +; (actual length), (char #1), (char #2), (char #3), etc. +; +INBUFF DB 127 ;length of input buffer. + DB 0 ;current length of contents. + DB 'Copyright' + DB ' 1979 (c) by Digital Research ' + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +INPOINT DW INBUFF+2;input line pointer +NAMEPNT DW 0 ;input line pointer used for error message. Points to +; ;start of name in error. +; +; Routine to print (A) on the console. All registers used. +; +PRINT MOV E,A ;setup bdos call. + MVI C,2 + JMP ENTRY +; +; Routine to print (A) on the console and to save (BC). +; +PRINTB PUSH B + CALL PRINT + POP B + RET +; +; Routine to send a carriage return, line feed combination +; to the console. +; +CRLF MVI A,CR + CALL PRINTB + MVI A,LF + JMP PRINTB +; +; Routine to send one space to the console and save (BC). +; +SPACE MVI A,' ' + JMP PRINTB +; +; Routine to print character string pointed to be (BC) on the +; console. It must terminate with a null byte. +; +PLINE PUSH B + CALL CRLF + POP H +PLINE2 MOV A,M + ORA A + RZ + INX H + PUSH H + CALL PRINT + POP H + JMP PLINE2 +; +; Routine to reset the disk system. +; +RESDSK MVI C,13 + JMP ENTRY +; +; Routine to select disk (A). +; +DSKSEL MOV E,A + MVI C,14 + JMP ENTRY +; +; Routine to call bdos and save the return code. The zero +; flag is set on a return of 0ffh. +; +ENTRY1 CALL ENTRY + STA RTNCODE ;save return code. + INR A ;set zero if 0ffh returned. + RET +; +; Routine to open a file. (DE) must point to the FCB. +; +OPEN MVI C,15 + JMP ENTRY1 +; +; Routine to open file at (FCB). +; +OPENFCB XRA A ;clear the record number byte at fcb+32 + STA FCB+32 + LXI D,FCB + JMP OPEN +; +; Routine to close a file. (DE) points to FCB. +; +CLOSE MVI C,16 + JMP ENTRY1 +; +; Routine to search for the first file with ambigueous name +; (DE). +; +SRCHFST MVI C,17 + JMP ENTRY1 +; +; Search for the next ambigeous file name. +; +SRCHNXT MVI C,18 + JMP ENTRY1 +; +; Search for file at (FCB). +; +SRCHFCB LXI D,FCB + JMP SRCHFST +; +; Routine to delete a file pointed to by (DE). +; +DELETE MVI C,19 + JMP ENTRY +; +; Routine to call the bdos and set the zero flag if a zero +; status is returned. +; +ENTRY2 CALL ENTRY + ORA A ;set zero flag if appropriate. + RET +; +; Routine to read the next record from a sequential file. +; (DE) points to the FCB. +; +RDREC MVI C,20 + JMP ENTRY2 +; +; Routine to read file at (FCB). +; +READFCB LXI D,FCB + JMP RDREC +; +; Routine to write the next record of a sequential file. +; (DE) points to the FCB. +; +WRTREC MVI C,21 + JMP ENTRY2 +; +; Routine to create the file pointed to by (DE). +; +CREATE MVI C,22 + JMP ENTRY1 +; +; Routine to rename the file pointed to by (DE). Note that +; the new name starts at (DE+16). +; +RENAM MVI C,23 + JMP ENTRY +; +; Get the current user code. +; +GETUSR MVI E,0FFH +; +; Routne to get or set the current user code. +; If (E) is FF then this is a GET, else it is a SET. +; +GETSETUC:MVI C,32 + JMP ENTRY +; +; Routine to set the current drive byte at (TDRIVE). +; +SETCDRV CALL GETUSR ;get user number + ADD A ;and shift into the upper 4 bits. + ADD A + ADD A + ADD A + LXI H,CDRIVE;now add in the current drive number. + ORA M + STA TDRIVE ;and save. + RET +; +; Move currently active drive down to (TDRIVE). +; +MOVECD LDA CDRIVE + STA TDRIVE + RET +; +; Routine to convert (A) into upper case ascii. Only letters +; are affected. +; +UPPER CPI 'a' ;check for letters in the range of 'a' to 'z'. + RC + CPI '{' + RNC + ANI 5FH ;convert it if found. + RET +; +; Routine to get a line of input. We must check to see if the +; user is in (BATCH) mode. If so, then read the input from file +; ($$$.SUB). At the end, reset to console input. +; +GETINP LDA BATCH ;if =0, then use console input. + ORA A + JZ GETINP1 +; +; Use the submit file ($$$.sub) which is prepared by a +; SUBMIT run. It must be on drive (A) and it will be deleted +; if and error occures (like eof). +; + LDA CDRIVE ;select drive 0 if need be. + ORA A + MVI A,0 ;always use drive A for submit. + CNZ DSKSEL ;select it if required. + LXI D,BATCHFCB + CALL OPEN ;look for it. + JZ GETINP1 ;if not there, use normal input. + LDA BATCHFCB+15;get last record number+1. + DCR A + STA BATCHFCB+32 + LXI D,BATCHFCB + CALL RDREC ;read last record. + JNZ GETINP1 ;quit on end of file. +; +; Move this record into input buffer. +; + LXI D,INBUFF+1 + LXI H,TBUFF ;data was read into buffer here. + MVI B,128 ;all 128 characters may be used. + CALL HL2DE ;(HL) to (DE), (B) bytes. + LXI H,BATCHFCB+14 + MVI M,0 ;zero out the 's2' byte. + INX H ;and decrement the record count. + DCR M + LXI D,BATCHFCB;close the batch file now. + CALL CLOSE + JZ GETINP1 ;quit on an error. + LDA CDRIVE ;re-select previous drive if need be. + ORA A + CNZ DSKSEL ;don't do needless selects. +; +; Print line just read on console. +; + LXI H,INBUFF+2 + CALL PLINE2 + CALL CHKCON ;check console, quit on a key. + JZ GETINP2 ;jump if no key is pressed. +; +; Terminate the submit job on any keyboard input. Delete this +; file such that it is not re-started and jump to normal keyboard +; input section. +; + CALL DELBATCH;delete the batch file. + JMP CMMND1 ;and restart command input. +; +; Get here for normal keyboard input. Delete the submit file +; incase there was one. +; +GETINP1 CALL DELBATCH;delete file ($$$.sub). + CALL SETCDRV ;reset active disk. + MVI C,10 ;get line from console device. + LXI D,INBUFF + CALL ENTRY + CALL MOVECD ;reset current drive (again). +; +; Convert input line to upper case. +; +GETINP2 LXI H,INBUFF+1 + MOV B,M ;(B)=character counter. +GETINP3 INX H + MOV A,B ;end of the line? + ORA A + JZ GETINP4 + MOV A,M ;convert to upper case. + CALL UPPER + MOV M,A + DCR B ;adjust character count. + JMP GETINP3 +GETINP4 MOV M,A ;add trailing null. + LXI H,INBUFF+2 + SHLD INPOINT ;reset input line pointer. + RET +; +; Routine to check the console for a key pressed. The zero +; flag is set is none, else the character is returned in (A). +; +CHKCON MVI C,11 ;check console. + CALL ENTRY + ORA A + RZ ;return if nothing. + MVI C,1 ;else get character. + CALL ENTRY + ORA A ;clear zero flag and return. + RET +; +; Routine to get the currently active drive number. +; +GETDSK MVI C,25 + JMP ENTRY +; +; Set the stabdard dma address. +; +STDDMA LXI D,TBUFF +; +; Routine to set the dma address to (DE). +; +DMASET MVI C,26 + JMP ENTRY +; +; Delete the batch file created by SUBMIT. +; +DELBATCH:LXI H,BATCH ;is batch active? + MOV A,M + ORA A + RZ + MVI M,0 ;yes, de-activate it. + XRA A + CALL DSKSEL ;select drive 0 for sure. + LXI D,BATCHFCB;and delete this file. + CALL DELETE + LDA CDRIVE ;reset current drive. + JMP DSKSEL +; +; Check to two strings at (PATTRN1) and (PATTRN2). They must be +; the same or we halt.... +; +VERIFY LXI D,PATTRN1;these are the serial number bytes. + LXI H,PATTRN2;ditto, but how could they be different? + MVI B,6 ;6 bytes each. +VERIFY1 LDAX D + CMP M + JNZ HALT ;jump to halt routine. + INX D + INX H + DCR B + JNZ VERIFY1 + RET +; +; Print back file name with a '?' to indicate a syntax error. +; +SYNERR CALL CRLF ;end current line. + LHLD NAMEPNT ;this points to name in error. +SYNERR1 MOV A,M ;print it until a space or null is found. + CPI ' ' + JZ SYNERR2 + ORA A + JZ SYNERR2 + PUSH H + CALL PRINT + POP H + INX H + JMP SYNERR1 +SYNERR2 MVI A,'?' ;add trailing '?'. + CALL PRINT + CALL CRLF + CALL DELBATCH;delete any batch file. + JMP CMMND1 ;and restart from console input. +; +; Check character at (DE) for legal command input. Note that the +; zero flag is set if the character is a delimiter. +; +CHECK LDAX D + ORA A + RZ + CPI ' ' ;control characters are not legal here. + JC SYNERR + RZ ;check for valid delimiter. + CPI '=' + RZ + CPI '_' + RZ + CPI '.' + RZ + CPI ':' + RZ + CPI ';' + RZ + CPI '<' + RZ + CPI '>' + RZ + RET +; +; Get the next non-blank character from (DE). +; +NONBLANK:LDAX D + ORA A ;string ends with a null. + RZ + CPI ' ' + RNZ + INX D + JMP NONBLANK +; +; Add (HL)=(HL)+(A) +; +ADDHL ADD L + MOV L,A + RNC ;take care of any carry. + INR H + RET +; +; Convert the first name in (FCB). +; +CONVFST MVI A,0 +; +; Format a file name (convert * to '?', etc.). On return, +; (A)=0 is an unambigeous name was specified. Enter with (A) equal to +; the position within the fcb for the name (either 0 or 16). +; +CONVERT LXI H,FCB + CALL ADDHL + PUSH H + PUSH H + XRA A + STA CHGDRV ;initialize drive change flag. + LHLD INPOINT ;set (HL) as pointer into input line. + XCHG + CALL NONBLANK;get next non-blank character. + XCHG + SHLD NAMEPNT ;save pointer here for any error message. + XCHG + POP H + LDAX D ;get first character. + ORA A + JZ CONVRT1 + SBI 'A'-1 ;might be a drive name, convert to binary. + MOV B,A ;and save. + INX D ;check next character for a ':'. + LDAX D + CPI ':' + JZ CONVRT2 + DCX D ;nope, move pointer back to the start of the line. +CONVRT1 LDA CDRIVE + MOV M,A + JMP CONVRT3 +CONVRT2 MOV A,B + STA CHGDRV ;set change in drives flag. + MOV M,B + INX D +; +; Convert the basic file name. +; +CONVRT3 MVI B,08H +CONVRT4 CALL CHECK + JZ CONVRT8 + INX H + CPI '*' ;note that an '*' will fill the remaining + JNZ CONVRT5 ;field with '?'. + MVI M,'?' + JMP CONVRT6 +CONVRT5 MOV M,A + INX D +CONVRT6 DCR B + JNZ CONVRT4 +CONVRT7 CALL CHECK ;get next delimiter. + JZ GETEXT + INX D + JMP CONVRT7 +CONVRT8 INX H ;blank fill the file name. + MVI M,' ' + DCR B + JNZ CONVRT8 +; +; Get the extension and convert it. +; +GETEXT MVI B,03H + CPI '.' + JNZ GETEXT5 + INX D +GETEXT1 CALL CHECK + JZ GETEXT5 + INX H + CPI '*' + JNZ GETEXT2 + MVI M,'?' + JMP GETEXT3 +GETEXT2 MOV M,A + INX D +GETEXT3 DCR B + JNZ GETEXT1 +GETEXT4 CALL CHECK + JZ GETEXT6 + INX D + JMP GETEXT4 +GETEXT5 INX H + MVI M,' ' + DCR B + JNZ GETEXT5 +GETEXT6 MVI B,3 +GETEXT7 INX H + MVI M,0 + DCR B + JNZ GETEXT7 + XCHG + SHLD INPOINT ;save input line pointer. + POP H +; +; Check to see if this is an ambigeous file name specification. +; Set the (A) register to non zero if it is. +; + LXI B,11 ;set name length. +GETEXT8 INX H + MOV A,M + CPI '?' ;any question marks? + JNZ GETEXT9 + INR B ;count them. +GETEXT9 DCR C + JNZ GETEXT8 + MOV A,B + ORA A + RET +; +; CP/M command table. Note commands can be either 3 or 4 characters long. +; +NUMCMDS EQU 6 ;number of commands +CMDTBL DB 'DIR ' + DB 'ERA ' + DB 'TYPE' + DB 'SAVE' + DB 'REN ' + DB 'USER' +; +; The following six bytes must agree with those at (PATTRN2) +; or cp/m will HALT. Why? +; +PATTRN1 DB 0,22,0,0,0,0;(* serial number bytes *). +; +; Search the command table for a match with what has just +; been entered. If a match is found, then we jump to the +; proper section. Else jump to (UNKNOWN). +; On return, the (C) register is set to the command number +; that matched (or NUMCMDS+1 if no match). +; +SEARCH LXI H,CMDTBL + MVI C,0 +SEARCH1 MOV A,C + CPI NUMCMDS ;this commands exists. + RNC + LXI D,FCB+1 ;check this one. + MVI B,4 ;max command length. +SEARCH2 LDAX D + CMP M + JNZ SEARCH3 ;not a match. + INX D + INX H + DCR B + JNZ SEARCH2 + LDAX D ;allow a 3 character command to match. + CPI ' ' + JNZ SEARCH4 + MOV A,C ;set return register for this command. + RET +SEARCH3 INX H + DCR B + JNZ SEARCH3 +SEARCH4 INR C + JMP SEARCH1 +; +; Set the input buffer to empty and then start the command +; processor (ccp). +; +CLEARBUF:XRA A + STA INBUFF+1;second byte is actual length. +; +;************************************************************** +;* +;* +;* C C P - C o n s o l e C o m m a n d P r o c e s s o r +;* +;************************************************************** +;* +COMMAND LXI SP,CCPSTACK;setup stack area. + PUSH B ;note that (C) should be equal to: + MOV A,C ;(uuuudddd) where 'uuuu' is the user number + RAR ;and 'dddd' is the drive number. + RAR + RAR + RAR + ANI 0FH ;isolate the user number. + MOV E,A + CALL GETSETUC;and set it. + CALL RESDSK ;reset the disk system. + STA BATCH ;clear batch mode flag. + POP B + MOV A,C + ANI 0FH ;isolate the drive number. + STA CDRIVE ;and save. + CALL DSKSEL ;...and select. + LDA INBUFF+1 + ORA A ;anything in input buffer already? + JNZ CMMND2 ;yes, we just process it. +; +; Entry point to get a command line from the console. +; +CMMND1 LXI SP,CCPSTACK;set stack straight. + CALL CRLF ;start a new line on the screen. + CALL GETDSK ;get current drive. + ADI 'a' + CALL PRINT ;print current drive. + MVI A,'>' + CALL PRINT ;and add prompt. + CALL GETINP ;get line from user. +; +; Process command line here. +; +CMMND2 LXI D,TBUFF + CALL DMASET ;set standard dma address. + CALL GETDSK + STA CDRIVE ;set current drive. + CALL CONVFST ;convert name typed in. + CNZ SYNERR ;wild cards are not allowed. + LDA CHGDRV ;if a change in drives was indicated, + ORA A ;then treat this as an unknown command + JNZ UNKNOWN ;which gets executed. + CALL SEARCH ;else search command table for a match. +; +; Note that an unknown command returns +; with (A) pointing to the last address +; in our table which is (UNKNOWN). +; + LXI H,CMDADR;now, look thru our address table for command (A). + MOV E,A ;set (DE) to command number. + MVI D,0 + DAD D + DAD D ;(HL)=(CMDADR)+2*(command number). + MOV A,M ;now pick out this address. + INX H + MOV H,M + MOV L,A + PCHL ;now execute it. +; +; CP/M command address table. +; +CMDADR DW DIRECT,ERASE,TYPE,SAVE + DW RENAME,USER,UNKNOWN +; +; Halt the system. Reason for this is unknown at present. +; +HALT LXI H,76F3H ;'DI HLT' instructions. + SHLD CBASE + LXI H,CBASE + PCHL +; +; Read error while TYPEing a file. +; +RDERROR LXI B,RDERR + JMP PLINE +RDERR DB 'Read error',0 +; +; Required file was not located. +; +NONE LXI B,NOFILE + JMP PLINE +NOFILE DB 'No file',0 +; +; Decode a command of the form 'A>filename number{ filename}. +; Note that a drive specifier is not allowed on the first file +; name. On return, the number is in register (A). Any error +; causes 'filename?' to be printed and the command is aborted. +; +DECODE CALL CONVFST ;convert filename. + LDA CHGDRV ;do not allow a drive to be specified. + ORA A + JNZ SYNERR + LXI H,FCB+1 ;convert number now. + LXI B,11 ;(B)=sum register, (C)=max digit count. +DECODE1 MOV A,M + CPI ' ' ;a space terminates the numeral. + JZ DECODE3 + INX H + SUI '0' ;make binary from ascii. + CPI 10 ;legal digit? + JNC SYNERR + MOV D,A ;yes, save it in (D). + MOV A,B ;compute (B)=(B)*10 and check for overflow. + ANI 0E0H + JNZ SYNERR + MOV A,B + RLC + RLC + RLC ;(A)=(B)*8 + ADD B ;.......*9 + JC SYNERR + ADD B ;.......*10 + JC SYNERR + ADD D ;add in new digit now. +DECODE2 JC SYNERR + MOV B,A ;and save result. + DCR C ;only look at 11 digits. + JNZ DECODE1 + RET +DECODE3 MOV A,M ;spaces must follow (why?). + CPI ' ' + JNZ SYNERR + INX H +DECODE4 DCR C + JNZ DECODE3 + MOV A,B ;set (A)=the numeric value entered. + RET +; +; Move 3 bytes from (HL) to (DE). Note that there is only +; one reference to this at (A2D5h). +; +MOVE3 MVI B,3 +; +; Move (B) bytes from (HL) to (DE). +; +HL2DE MOV A,M + STAX D + INX H + INX D + DCR B + JNZ HL2DE + RET +; +; Compute (HL)=(TBUFF)+(A)+(C) and get the byte that's here. +; +EXTRACT LXI H,TBUFF + ADD C + CALL ADDHL + MOV A,M + RET +; +; Check drive specified. If it means a change, then the new +; drive will be selected. In any case, the drive byte of the +; fcb will be set to null (means use current drive). +; +DSELECT XRA A ;null out first byte of fcb. + STA FCB + LDA CHGDRV ;a drive change indicated? + ORA A + RZ + DCR A ;yes, is it the same as the current drive? + LXI H,CDRIVE + CMP M + RZ + JMP DSKSEL ;no. Select it then. +; +; Check the drive selection and reset it to the previous +; drive if it was changed for the preceeding command. +; +RESETDR LDA CHGDRV ;drive change indicated? + ORA A + RZ + DCR A ;yes, was it a different drive? + LXI H,CDRIVE + CMP M + RZ + LDA CDRIVE ;yes, re-select our old drive. + JMP DSKSEL +; +;************************************************************** +;* +;* D I R E C T O R Y C O M M A N D +;* +;************************************************************** +; +DIRECT CALL CONVFST ;convert file name. + CALL DSELECT ;select indicated drive. + LXI H,FCB+1 ;was any file indicated? + MOV A,M + CPI ' ' + JNZ DIRECT2 + MVI B,11 ;no. Fill field with '?' - same as *.*. +DIRECT1 MVI M,'?' + INX H + DCR B + JNZ DIRECT1 +DIRECT2 MVI E,0 ;set initial cursor position. + PUSH D + CALL SRCHFCB ;get first file name. + CZ NONE ;none found at all? +DIRECT3 JZ DIRECT9 ;terminate if no more names. + LDA RTNCODE ;get file's position in segment (0-3). + RRC + RRC + RRC + ANI 60H ;(A)=position*32 + MOV C,A + MVI A,10 + CALL EXTRACT ;extract the tenth entry in fcb. + RAL ;check system file status bit. + JC DIRECT8 ;we don't list them. + POP D + MOV A,E ;bump name count. + INR E + PUSH D + ANI 03H ;at end of line? + PUSH PSW + JNZ DIRECT4 + CALL CRLF ;yes, end this line and start another. + PUSH B + CALL GETDSK ;start line with ('A:'). + POP B + ADI 'A' + CALL PRINTB + MVI A,':' + CALL PRINTB + JMP DIRECT5 +DIRECT4 CALL SPACE ;add seperator between file names. + MVI A,':' + CALL PRINTB +DIRECT5 CALL SPACE + MVI B,1 ;'extract' each file name character at a time. +DIRECT6 MOV A,B + CALL EXTRACT + ANI 7FH ;strip bit 7 (status bit). + CPI ' ' ;are we at the end of the name? + JNZ DRECT65 + POP PSW ;yes, don't print spaces at the end of a line. + PUSH PSW + CPI 3 + JNZ DRECT63 + MVI A,9 ;first check for no extension. + CALL EXTRACT + ANI 7FH + CPI ' ' + JZ DIRECT7 ;don't print spaces. +DRECT63 MVI A,' ' ;else print them. +DRECT65 CALL PRINTB + INR B ;bump to next character psoition. + MOV A,B + CPI 12 ;end of the name? + JNC DIRECT7 + CPI 9 ;nope, starting extension? + JNZ DIRECT6 + CALL SPACE ;yes, add seperating space. + JMP DIRECT6 +DIRECT7 POP PSW ;get the next file name. +DIRECT8 CALL CHKCON ;first check console, quit on anything. + JNZ DIRECT9 + CALL SRCHNXT ;get next name. + JMP DIRECT3 ;and continue with our list. +DIRECT9 POP D ;restore the stack and return to command level. + JMP GETBACK +; +;************************************************************** +;* +;* E R A S E C O M M A N D +;* +;************************************************************** +; +ERASE CALL CONVFST ;convert file name. + CPI 11 ;was '*.*' entered? + JNZ ERASE1 + LXI B,YESNO ;yes, ask for confirmation. + CALL PLINE + CALL GETINP + LXI H,INBUFF+1 + DCR M ;must be exactly 'y'. + JNZ CMMND1 + INX H + MOV A,M + CPI 'Y' + JNZ CMMND1 + INX H + SHLD INPOINT ;save input line pointer. +ERASE1 CALL DSELECT ;select desired disk. + LXI D,FCB + CALL DELETE ;delete the file. + INR A + CZ NONE ;not there? + JMP GETBACK ;return to command level now. +YESNO DB 'All (y/n)?',0 +; +;************************************************************** +;* +;* T Y P E C O M M A N D +;* +;************************************************************** +; +TYPE CALL CONVFST ;convert file name. + JNZ SYNERR ;wild cards not allowed. + CALL DSELECT ;select indicated drive. + CALL OPENFCB ;open the file. + JZ TYPE5 ;not there? + CALL CRLF ;ok, start a new line on the screen. + LXI H,NBYTES;initialize byte counter. + MVI M,0FFH ;set to read first sector. +TYPE1 LXI H,NBYTES +TYPE2 MOV A,M ;have we written the entire sector? + CPI 128 + JC TYPE3 + PUSH H ;yes, read in the next one. + CALL READFCB + POP H + JNZ TYPE4 ;end or error? + XRA A ;ok, clear byte counter. + MOV M,A +TYPE3 INR M ;count this byte. + LXI H,TBUFF ;and get the (A)th one from the buffer (TBUFF). + CALL ADDHL + MOV A,M + CPI CNTRLZ ;end of file mark? + JZ GETBACK + CALL PRINT ;no, print it. + CALL CHKCON ;check console, quit if anything ready. + JNZ GETBACK + JMP TYPE1 +; +; Get here on an end of file or read error. +; +TYPE4 DCR A ;read error? + JZ GETBACK + CALL RDERROR ;yes, print message. +TYPE5 CALL RESETDR ;and reset proper drive + JMP SYNERR ;now print file name with problem. +; +;************************************************************** +;* +;* S A V E C O M M A N D +;* +;************************************************************** +; +SAVE CALL DECODE ;get numeric number that follows SAVE. + PUSH PSW ;save number of pages to write. + CALL CONVFST ;convert file name. + JNZ SYNERR ;wild cards not allowed. + CALL DSELECT ;select specified drive. + LXI D,FCB ;now delete this file. + PUSH D + CALL DELETE + POP D + CALL CREATE ;and create it again. + JZ SAVE3 ;can't create? + XRA A ;clear record number byte. + STA FCB+32 + POP PSW ;convert pages to sectors. + MOV L,A + MVI H,0 + DAD H ;(HL)=number of sectors to write. + LXI D,TBASE ;and we start from here. +SAVE1 MOV A,H ;done yet? + ORA L + JZ SAVE2 + DCX H ;nope, count this and compute the start + PUSH H ;of the next 128 byte sector. + LXI H,128 + DAD D + PUSH H ;save it and set the transfer address. + CALL DMASET + LXI D,FCB ;write out this sector now. + CALL WRTREC + POP D ;reset (DE) to the start of the last sector. + POP H ;restore sector count. + JNZ SAVE3 ;write error? + JMP SAVE1 +; +; Get here after writing all of the file. +; +SAVE2 LXI D,FCB ;now close the file. + CALL CLOSE + INR A ;did it close ok? + JNZ SAVE4 +; +; Print out error message (no space). +; +SAVE3 LXI B,NOSPACE + CALL PLINE +SAVE4 CALL STDDMA ;reset the standard dma address. + JMP GETBACK +NOSPACE DB 'No space',0 +; +;************************************************************** +;* +;* R E N A M E C O M M A N D +;* +;************************************************************** +; +RENAME CALL CONVFST ;convert first file name. + JNZ SYNERR ;wild cards not allowed. + LDA CHGDRV ;remember any change in drives specified. + PUSH PSW + CALL DSELECT ;and select this drive. + CALL SRCHFCB ;is this file present? + JNZ RENAME6 ;yes, print error message. + LXI H,FCB ;yes, move this name into second slot. + LXI D,FCB+16 + MVI B,16 + CALL HL2DE + LHLD INPOINT ;get input pointer. + XCHG + CALL NONBLANK;get next non blank character. + CPI '=' ;only allow an '=' or '_' seperator. + JZ RENAME1 + CPI '_' + JNZ RENAME5 +RENAME1 XCHG + INX H ;ok, skip seperator. + SHLD INPOINT ;save input line pointer. + CALL CONVFST ;convert this second file name now. + JNZ RENAME5 ;again, no wild cards. + POP PSW ;if a drive was specified, then it + MOV B,A ;must be the same as before. + LXI H,CHGDRV + MOV A,M + ORA A + JZ RENAME2 + CMP B + MOV M,B + JNZ RENAME5 ;they were different, error. +RENAME2 MOV M,B; reset as per the first file specification. + XRA A + STA FCB ;clear the drive byte of the fcb. +RENAME3 CALL SRCHFCB ;and go look for second file. + JZ RENAME4 ;doesn't exist? + LXI D,FCB + CALL RENAM ;ok, rename the file. + JMP GETBACK +; +; Process rename errors here. +; +RENAME4 CALL NONE ;file not there. + JMP GETBACK +RENAME5 CALL RESETDR ;bad command format. + JMP SYNERR +RENAME6 LXI B,EXISTS;destination file already exists. + CALL PLINE + JMP GETBACK +EXISTS DB 'File exists',0 +; +;************************************************************** +;* +;* U S E R C O M M A N D +;* +;************************************************************** +; +USER CALL DECODE ;get numeric value following command. + CPI 16 ;legal user number? + JNC SYNERR + MOV E,A ;yes but is there anything else? + LDA FCB+1 + CPI ' ' + JZ SYNERR ;yes, that is not allowed. + CALL GETSETUC;ok, set user code. + JMP GETBACK1 +; +;************************************************************** +;* +;* T R A N S I A N T P R O G R A M C O M M A N D +;* +;************************************************************** +; +UNKNOWN CALL VERIFY ;check for valid system (why?). + LDA FCB+1 ;anything to execute? + CPI ' ' + JNZ UNKWN1 + LDA CHGDRV ;nope, only a drive change? + ORA A + JZ GETBACK1;neither??? + DCR A + STA CDRIVE ;ok, store new drive. + CALL MOVECD ;set (TDRIVE) also. + CALL DSKSEL ;and select this drive. + JMP GETBACK1;then return. +; +; Here a file name was typed. Prepare to execute it. +; +UNKWN1 LXI D,FCB+9 ;an extension specified? + LDAX D + CPI ' ' + JNZ SYNERR ;yes, not allowed. +UNKWN2 PUSH D + CALL DSELECT ;select specified drive. + POP D + LXI H,COMFILE ;set the extension to 'COM'. + CALL MOVE3 + CALL OPENFCB ;and open this file. + JZ UNKWN9 ;not present? +; +; Load in the program. +; + LXI H,TBASE ;store the program starting here. +UNKWN3 PUSH H + XCHG + CALL DMASET ;set transfer address. + LXI D,FCB ;and read the next record. + CALL RDREC + JNZ UNKWN4 ;end of file or read error? + POP H ;nope, bump pointer for next sector. + LXI D,128 + DAD D + LXI D,CBASE ;enough room for the whole file? + MOV A,L + SUB E + MOV A,H + SBB D + JNC UNKWN0 ;no, it can't fit. + JMP UNKWN3 +; +; Get here after finished reading. +; +UNKWN4 POP H + DCR A ;normal end of file? + JNZ UNKWN0 + CALL RESETDR ;yes, reset previous drive. + CALL CONVFST ;convert the first file name that follows + LXI H,CHGDRV;command name. + PUSH H + MOV A,M ;set drive code in default fcb. + STA FCB + MVI A,16 ;put second name 16 bytes later. + CALL CONVERT ;convert second file name. + POP H + MOV A,M ;and set the drive for this second file. + STA FCB+16 + XRA A ;clear record byte in fcb. + STA FCB+32 + LXI D,TFCB ;move it into place at(005Ch). + LXI H,FCB + MVI B,33 + CALL HL2DE + LXI H,INBUFF+2;now move the remainder of the input +UNKWN5 MOV A,M ;line down to (0080h). Look for a non blank. + ORA A ;or a null. + JZ UNKWN6 + CPI ' ' + JZ UNKWN6 + INX H + JMP UNKWN5 +; +; Do the line move now. It ends in a null byte. +; +UNKWN6 MVI B,0 ;keep a character count. + LXI D,TBUFF+1;data gets put here. +UNKWN7 MOV A,M ;move it now. + STAX D + ORA A + JZ UNKWN8 + INR B + INX H + INX D + JMP UNKWN7 +UNKWN8 MOV A,B ;now store the character count. + STA TBUFF + CALL CRLF ;clean up the screen. + CALL STDDMA ;set standard transfer address. + CALL SETCDRV ;reset current drive. + CALL TBASE ;and execute the program. +; +; Transiant programs return here (or reboot). +; + LXI SP,BATCH ;set stack first off. + CALL MOVECD ;move current drive into place (TDRIVE). + CALL DSKSEL ;and reselect it. + JMP CMMND1 ;back to comand mode. +; +; Get here if some error occured. +; +UNKWN9 CALL RESETDR ;inproper format. + JMP SYNERR +UNKWN0 LXI B,BADLOAD;read error or won't fit. + CALL PLINE + JMP GETBACK +BADLOAD DB 'Bad load',0 +COMFILE DB 'COM' ;command file extension. +; +; Get here to return to command level. We will reset the +; previous active drive and then either return to command +; level directly or print error message and then return. +; +GETBACK CALL RESETDR ;reset previous drive. +GETBACK1:CALL CONVFST ;convert first name in (FCB). + LDA FCB+1 ;if this was just a drive change request, + SUI ' ' ;make sure it was valid. + LXI H,CHGDRV + ORA M + JNZ SYNERR + JMP CMMND1 ;ok, return to command level. +; +; ccp stack area. +; + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +CCPSTACK:EQU $ ;end of ccp stack area. +; +; Batch (or SUBMIT) processing information storage. +; +BATCH DB 0 ;batch mode flag (0=not active). +BATCHFCB:DB 0,'$$$ SUB',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +; +; File control block setup by the CCP. +; +FCB DB 0,' ',0,0,0,0,0,' ',0,0,0,0,0 +RTNCODE DB 0 ;status returned from bdos call. +CDRIVE DB 0 ;currently active drive. +CHGDRV DB 0 ;change in drives flag (0=no change). +NBYTES DW 0 ;byte counter used by TYPE. +; +; Room for expansion? +; + DB 0,0,0,0,0,0,0,0,0,0,0,0,0 +; +; Note that the following six bytes must match those at +; (PATTRN1) or cp/m will HALT. Why? +; +PATTRN2 DB 0,22,0,0,0,0;(* serial number bytes *). +; +;************************************************************** +;* +;* B D O S E N T R Y +;* +;************************************************************** +; +FBASE JMP FBASE1 +; +; Bdos error table. +; +BADSCTR DW ERROR1 ;bad sector on read or write. +BADSLCT DW ERROR2 ;bad disk select. +RODISK DW ERROR3 ;disk is read only. +ROFILE DW ERROR4 ;file is read only. +; +; Entry into bdos. (DE) or (E) are the parameters passed. The +; function number desired is in register (C). +; +FBASE1 XCHG ;save the (DE) parameters. + SHLD PARAMS + XCHG + MOV A,E ;and save register (E) in particular. + STA EPARAM + LXI H,0 + SHLD STATUS ;clear return status. + DAD SP + SHLD USRSTACK;save users stack pointer. + LXI SP,STKAREA;and set our own. + XRA A ;clear auto select storage space. + STA AUTOFLAG + STA AUTO + LXI H,GOBACK;set return address. + PUSH H + MOV A,C ;get function number. + CPI NFUNCTS ;valid function number? + RNC + MOV C,E ;keep single register function here. + LXI H,FUNCTNS;now look thru the function table. + MOV E,A + MVI D,0 ;(DE)=function number. + DAD D + DAD D ;(HL)=(start of table)+2*(function number). + MOV E,M + INX H + MOV D,M ;now (DE)=address for this function. + LHLD PARAMS ;retrieve parameters. + XCHG ;now (DE) has the original parameters. + PCHL ;execute desired function. +; +; BDOS function jump table. +; +NFUNCTS EQU 41 ;number of functions in followin table. +; +FUNCTNS DW WBOOT,GETCON,OUTCON,GETRDR,PUNCH,LIST,DIRCIO,GETIOB + DW SETIOB,PRTSTR,RDBUFF,GETCSTS,GETVER,RSTDSK,SETDSK,OPENFIL + DW CLOSEFIL,GETFST,GETNXT,DELFILE,READSEQ,WRTSEQ,FCREATE + DW RENFILE,GETLOG,GETCRNT,PUTDMA,GETALOC,WRTPRTD,GETROV,SETATTR + DW GETPARM,GETUSER,RDRANDOM,WTRANDOM,FILESIZE,SETRAN,LOGOFF,RTN + DW RTN,WTSPECL +; +; Bdos error message section. +; +ERROR1 LXI H,BADSEC ;bad sector message. + CALL PRTERR ;print it and get a 1 char responce. + CPI CNTRLC ;re-boot request (control-c)? + JZ 0 ;yes. + RET ;no, return to retry i/o function. +; +ERROR2 LXI H,BADSEL ;bad drive selected. + JMP ERROR5 +; +ERROR3 LXI H,DISKRO ;disk is read only. + JMP ERROR5 +; +ERROR4 LXI H,FILERO ;file is read only. +; +ERROR5 CALL PRTERR + JMP 0 ;always reboot on these errors. +; +BDOSERR DB 'Bdos Err On ' +BDOSDRV DB ' : $' +BADSEC DB 'Bad Sector$' +BADSEL DB 'Select$' +FILERO DB 'File ' +DISKRO DB 'R/O$' +; +; Print bdos error message. +; +PRTERR PUSH H ;save second message pointer. + CALL OUTCRLF ;send (cr)(lf). + LDA ACTIVE ;get active drive. + ADI 'A' ;make ascii. + STA BDOSDRV ;and put in message. + LXI B,BDOSERR;and print it. + CALL PRTMESG + POP B ;print second message line now. + CALL PRTMESG +; +; Get an input character. We will check our 1 character +; buffer first. This may be set by the console status routine. +; +GETCHAR LXI H,CHARBUF;check character buffer. + MOV A,M ;anything present already? + MVI M,0 ;...either case clear it. + ORA A + RNZ ;yes, use it. + JMP CONIN ;nope, go get a character responce. +; +; Input and echo a character. +; +GETECHO CALL GETCHAR ;input a character. + CALL CHKCHAR ;carriage control? + RC ;no, a regular control char so don't echo. + PUSH PSW ;ok, save character now. + MOV C,A + CALL OUTCON ;and echo it. + POP PSW ;get character and return. + RET +; +; Check character in (A). Set the zero flag on a carriage +; control character and the carry flag on any other control +; character. +; +CHKCHAR CPI CR ;check for carriage return, line feed, backspace, + RZ ;or a tab. + CPI LF + RZ + CPI TAB + RZ + CPI BS + RZ + CPI ' ' ;other control char? Set carry flag. + RET +; +; Check the console during output. Halt on a control-s, then +; reboot on a control-c. If anything else is ready, clear the +; zero flag and return (the calling routine may want to do +; something). +; +CKCONSOL:LDA CHARBUF ;check buffer. + ORA A ;if anything, just return without checking. + JNZ CKCON2 + CALL CONST ;nothing in buffer. Check console. + ANI 01H ;look at bit 0. + RZ ;return if nothing. + CALL CONIN ;ok, get it. + CPI CNTRLS ;if not control-s, return with zero cleared. + JNZ CKCON1 + CALL CONIN ;halt processing until another char + CPI CNTRLC ;is typed. Control-c? + JZ 0 ;yes, reboot now. + XRA A ;no, just pretend nothing was ever ready. + RET +CKCON1 STA CHARBUF ;save character in buffer for later processing. +CKCON2 MVI A,1 ;set (A) to non zero to mean something is ready. + RET +; +; Output (C) to the screen. If the printer flip-flop flag +; is set, we will send character to printer also. The console +; will be checked in the process. +; +OUTCHAR LDA OUTFLAG ;check output flag. + ORA A ;anything and we won't generate output. + JNZ OUTCHR1 + PUSH B + CALL CKCONSOL;check console (we don't care whats there). + POP B + PUSH B + CALL CONOUT ;output (C) to the screen. + POP B + PUSH B + LDA PRTFLAG ;check printer flip-flop flag. + ORA A + CNZ LIST ;print it also if non-zero. + POP B +OUTCHR1 MOV A,C ;update cursors position. + LXI H,CURPOS + CPI DEL ;rubouts don't do anything here. + RZ + INR M ;bump line pointer. + CPI ' ' ;and return if a normal character. + RNC + DCR M ;restore and check for the start of the line. + MOV A,M + ORA A + RZ ;ingnore control characters at the start of the line. + MOV A,C + CPI BS ;is it a backspace? + JNZ OUTCHR2 + DCR M ;yes, backup pointer. + RET +OUTCHR2 CPI LF ;is it a line feed? + RNZ ;ignore anything else. + MVI M,0 ;reset pointer to start of line. + RET +; +; Output (A) to the screen. If it is a control character +; (other than carriage control), use ^x format. +; +SHOWIT MOV A,C + CALL CHKCHAR ;check character. + JNC OUTCON ;not a control, use normal output. + PUSH PSW + MVI C,'^' ;for a control character, preceed it with '^'. + CALL OUTCHAR + POP PSW + ORI '@' ;and then use the letter equivelant. + MOV C,A +; +; Function to output (C) to the console device and expand tabs +; if necessary. +; +OUTCON MOV A,C + CPI TAB ;is it a tab? + JNZ OUTCHAR ;use regular output. +OUTCON1 MVI C,' ' ;yes it is, use spaces instead. + CALL OUTCHAR + LDA CURPOS ;go until the cursor is at a multiple of 8 + + ANI 07H ;position. + JNZ OUTCON1 + RET +; +; Echo a backspace character. Erase the prevoius character +; on the screen. +; +BACKUP CALL BACKUP1 ;backup the screen 1 place. + MVI C,' ' ;then blank that character. + CALL CONOUT +BACKUP1 MVI C,BS ;then back space once more. + JMP CONOUT +; +; Signal a deleted line. Print a '#' at the end and start +; over. +; +NEWLINE MVI C,'#' + CALL OUTCHAR ;print this. + CALL OUTCRLF ;start new line. +NEWLN1 LDA CURPOS ;move the cursor to the starting position. + LXI H,STARTING + CMP M + RNC ;there yet? + MVI C,' ' + CALL OUTCHAR ;nope, keep going. + JMP NEWLN1 +; +; Output a (cr) (lf) to the console device (screen). +; +OUTCRLF MVI C,CR + CALL OUTCHAR + MVI C,LF + JMP OUTCHAR +; +; Print message pointed to by (BC). It will end with a '$'. +; +PRTMESG LDAX B ;check for terminating character. + CPI '$' + RZ + INX B + PUSH B ;otherwise, bump pointer and print it. + MOV C,A + CALL OUTCON + POP B + JMP PRTMESG +; +; Function to execute a buffered read. +; +RDBUFF LDA CURPOS ;use present location as starting one. + STA STARTING + LHLD PARAMS ;get the maximum buffer space. + MOV C,M + INX H ;point to first available space. + PUSH H ;and save. + MVI B,0 ;keep a character count. +RDBUF1 PUSH B + PUSH H +RDBUF2 CALL GETCHAR ;get the next input character. + ANI 7FH ;strip bit 7. + POP H ;reset registers. + POP B + CPI CR ;en of the line? + JZ RDBUF17 + CPI LF + JZ RDBUF17 + CPI BS ;how about a backspace? + JNZ RDBUF3 + MOV A,B ;yes, but ignore at the beginning of the line. + ORA A + JZ RDBUF1 + DCR B ;ok, update counter. + LDA CURPOS ;if we backspace to the start of the line, + STA OUTFLAG ;treat as a cancel (control-x). + JMP RDBUF10 +RDBUF3 CPI DEL ;user typed a rubout? + JNZ RDBUF4 + MOV A,B ;ignore at the start of the line. + ORA A + JZ RDBUF1 + MOV A,M ;ok, echo the prevoius character. + DCR B ;and reset pointers (counters). + DCX H + JMP RDBUF15 +RDBUF4 CPI CNTRLE ;physical end of line? + JNZ RDBUF5 + PUSH B ;yes, do it. + PUSH H + CALL OUTCRLF + XRA A ;and update starting position. + STA STARTING + JMP RDBUF2 +RDBUF5 CPI CNTRLP ;control-p? + JNZ RDBUF6 + PUSH H ;yes, flip the print flag filp-flop byte. + LXI H,PRTFLAG + MVI A,1 ;PRTFLAG=1-PRTFLAG + SUB M + MOV M,A + POP H + JMP RDBUF1 +RDBUF6 CPI CNTRLX ;control-x (cancel)? + JNZ RDBUF8 + POP H +RDBUF7 LDA STARTING;yes, backup the cursor to here. + LXI H,CURPOS + CMP M + JNC RDBUFF ;done yet? + DCR M ;no, decrement pointer and output back up one space. + CALL BACKUP + JMP RDBUF7 +RDBUF8 CPI CNTRLU ;cntrol-u (cancel line)? + JNZ RDBUF9 + CALL NEWLINE ;start a new line. + POP H + JMP RDBUFF +RDBUF9 CPI CNTRLR ;control-r? + JNZ RDBUF14 +RDBUF10 PUSH B ;yes, start a new line and retype the old one. + CALL NEWLINE + POP B + POP H + PUSH H + PUSH B +RDBUF11 MOV A,B ;done whole line yet? + ORA A + JZ RDBUF12 + INX H ;nope, get next character. + MOV C,M + DCR B ;count it. + PUSH B + PUSH H + CALL SHOWIT ;and display it. + POP H + POP B + JMP RDBUF11 +RDBUF12 PUSH H ;done with line. If we were displaying + LDA OUTFLAG ;then update cursor position. + ORA A + JZ RDBUF2 + LXI H,CURPOS;because this line is shorter, we must + SUB M ;back up the cursor (not the screen however) + STA OUTFLAG ;some number of positions. +RDBUF13 CALL BACKUP ;note that as long as (OUTFLAG) is non + LXI H,OUTFLAG;zero, the screen will not be changed. + DCR M + JNZ RDBUF13 + JMP RDBUF2 ;now just get the next character. +; +; Just a normal character, put this in our buffer and echo. +; +RDBUF14 INX H + MOV M,A ;store character. + INR B ;and count it. +RDBUF15 PUSH B + PUSH H + MOV C,A ;echo it now. + CALL SHOWIT + POP H + POP B + MOV A,M ;was it an abort request? + CPI CNTRLC ;control-c abort? + MOV A,B + JNZ RDBUF16 + CPI 1 ;only if at start of line. + JZ 0 +RDBUF16 CMP C ;nope, have we filled the buffer? + JC RDBUF1 +RDBUF17 POP H ;yes end the line and return. + MOV M,B + MVI C,CR + JMP OUTCHAR ;output (cr) and return. +; +; Function to get a character from the console device. +; +GETCON CALL GETECHO ;get and echo. + JMP SETSTAT ;save status and return. +; +; Function to get a character from the tape reader device. +; +GETRDR CALL READER ;get a character from reader, set status and return. + JMP SETSTAT +; +; Function to perform direct console i/o. If (C) contains (FF) +; then this is an input request. If (C) contains (FE) then +; this is a status request. Otherwise we are to output (C). +; +DIRCIO MOV A,C ;test for (FF). + INR A + JZ DIRC1 + INR A ;test for (FE). + JZ CONST + JMP CONOUT ;just output (C). +DIRC1 CALL CONST ;this is an input request. + ORA A + JZ GOBACK1 ;not ready? Just return (directly). + CALL CONIN ;yes, get character. + JMP SETSTAT ;set status and return. +; +; Function to return the i/o byte. +; +GETIOB LDA IOBYTE + JMP SETSTAT +; +; Function to set the i/o byte. +; +SETIOB LXI H,IOBYTE + MOV M,C + RET +; +; Function to print the character string pointed to by (DE) +; on the console device. The string ends with a '$'. +; +PRTSTR XCHG + MOV C,L + MOV B,H ;now (BC) points to it. + JMP PRTMESG +; +; Function to interigate the console device. +; +GETCSTS CALL CKCONSOL +; +; Get here to set the status and return to the cleanup +; section. Then back to the user. +; +SETSTAT STA STATUS +RTN RET +; +; Set the status to 1 (read or write error code). +; +IOERR1 MVI A,1 + JMP SETSTAT +; +OUTFLAG DB 0 ;output flag (non zero means no output). +STARTING:DB 2 ;starting position for cursor. +CURPOS DB 0 ;cursor position (0=start of line). +PRTFLAG DB 0 ;printer flag (control-p toggle). List if non zero. +CHARBUF DB 0 ;single input character buffer. +; +; Stack area for BDOS calls. +; +USRSTACK:DW 0 ;save users stack pointer here. +; + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +STKAREA EQU $ ;end of stack area. +; +USERNO DB 0 ;current user number. +ACTIVE DB 0 ;currently active drive. +PARAMS DW 0 ;save (DE) parameters here on entry. +STATUS DW 0 ;status returned from bdos function. +; +; Select error occured, jump to error routine. +; +SLCTERR LXI H,BADSLCT +; +; Jump to (HL) indirectly. +; +JUMPHL MOV E,M + INX H + MOV D,M ;now (DE) contain the desired address. + XCHG + PCHL +; +; Block move. (DE) to (HL), (C) bytes total. +; +DE2HL INR C ;is count down to zero? +DE2HL1 DCR C + RZ ;yes, we are done. + LDAX D ;no, move one more byte. + MOV M,A + INX D + INX H + JMP DE2HL1 ;and repeat. +; +; Select the desired drive. +; +SELECT LDA ACTIVE ;get active disk. + MOV C,A + CALL SELDSK ;select it. + MOV A,H ;valid drive? + ORA L ;valid drive? + RZ ;return if not. +; +; Here, the BIOS returned the address of the parameter block +; in (HL). We will extract the necessary pointers and save them. +; + MOV E,M ;yes, get address of translation table into (DE). + INX H + MOV D,M + INX H + SHLD SCRATCH1 ;save pointers to scratch areas. + INX H + INX H + SHLD SCRATCH2 ;ditto. + INX H + INX H + SHLD SCRATCH3 ;ditto. + INX H + INX H + XCHG ;now save the translation table address. + SHLD XLATE + LXI H,DIRBUF ;put the next 8 bytes here. + MVI C,8 ;they consist of the directory buffer + CALL DE2HL ;pointer, parameter block pointer, + LHLD DISKPB ;check and allocation vectors. + XCHG + LXI H,SECTORS ;move parameter block into our ram. + MVI C,15 ;it is 15 bytes long. + CALL DE2HL + LHLD DSKSIZE ;check disk size. + MOV A,H ;more than 256 blocks on this? + LXI H,BIGDISK + MVI M,0FFH ;set to samll. + ORA A + JZ SELECT1 + MVI M,0 ;wrong, set to large. +SELECT1 MVI A,0FFH ;clear the zero flag. + ORA A + RET +; +; Routine to home the disk track head and clear pointers. +; +HOMEDRV CALL HOME ;home the head. + XRA A + LHLD SCRATCH2;set our track pointer also. + MOV M,A + INX H + MOV M,A + LHLD SCRATCH3;and our sector pointer. + MOV M,A + INX H + MOV M,A + RET +; +; Do the actual disk read and check the error return status. +; +DOREAD CALL READ + JMP IORET +; +; Do the actual disk write and handle any bios error. +; +DOWRITE CALL WRITE +IORET ORA A + RZ ;return unless an error occured. + LXI H,BADSCTR;bad read/write on this sector. + JMP JUMPHL +; +; Routine to select the track and sector that the desired +; block number falls in. +; +TRKSEC LHLD FILEPOS ;get position of last accessed file + MVI C,2 ;in directory and compute sector #. + CALL SHIFTR ;sector #=file-position/4. + SHLD BLKNMBR ;save this as the block number of interest. + SHLD CKSUMTBL;what's it doing here too? +; +; if the sector number has already been set (BLKNMBR), enter +; at this point. +; +TRKSEC1 LXI H,BLKNMBR + MOV C,M ;move sector number into (BC). + INX H + MOV B,M + LHLD SCRATCH3;get current sector number and + MOV E,M ;move this into (DE). + INX H + MOV D,M + LHLD SCRATCH2;get current track number. + MOV A,M ;and this into (HL). + INX H + MOV H,M + MOV L,A +TRKSEC2 MOV A,C ;is desired sector before current one? + SUB E + MOV A,B + SBB D + JNC TRKSEC3 + PUSH H ;yes, decrement sectors by one track. + LHLD SECTORS ;get sectors per track. + MOV A,E + SUB L + MOV E,A + MOV A,D + SBB H + MOV D,A ;now we have backed up one full track. + POP H + DCX H ;adjust track counter. + JMP TRKSEC2 +TRKSEC3 PUSH H ;desired sector is after current one. + LHLD SECTORS ;get sectors per track. + DAD D ;bump sector pointer to next track. + JC TRKSEC4 + MOV A,C ;is desired sector now before current one? + SUB L + MOV A,B + SBB H + JC TRKSEC4 + XCHG ;not yes, increment track counter + POP H ;and continue until it is. + INX H + JMP TRKSEC3 +; +; here we have determined the track number that contains the +; desired sector. +; +TRKSEC4 POP H ;get track number (HL). + PUSH B + PUSH D + PUSH H + XCHG + LHLD OFFSET ;adjust for first track offset. + DAD D + MOV B,H + MOV C,L + CALL SETTRK ;select this track. + POP D ;reset current track pointer. + LHLD SCRATCH2 + MOV M,E + INX H + MOV M,D + POP D + LHLD SCRATCH3;reset the first sector on this track. + MOV M,E + INX H + MOV M,D + POP B + MOV A,C ;now subtract the desired one. + SUB E ;to make it relative (1-# sectors/track). + MOV C,A + MOV A,B + SBB D + MOV B,A + LHLD XLATE ;translate this sector according to this table. + XCHG + CALL SECTRN ;let the bios translate it. + MOV C,L + MOV B,H + JMP SETSEC ;and select it. +; +; Compute block number from record number (SAVNREC) and +; extent number (SAVEXT). +; +GETBLOCK:LXI H,BLKSHFT;get logical to physical conversion. + MOV C,M ;note that this is base 2 log of ratio. + LDA SAVNREC ;get record number. +GETBLK1 ORA A ;compute (A)=(A)/2^BLKSHFT. + RAR + DCR C + JNZ GETBLK1 + MOV B,A ;save result in (B). + MVI A,8 + SUB M + MOV C,A ;compute (C)=8-BLKSHFT. + LDA SAVEXT +GETBLK2 DCR C ;compute (A)=SAVEXT*2^(8-BLKSHFT). + JZ GETBLK3 + ORA A + RAL + JMP GETBLK2 +GETBLK3 ADD B + RET +; +; Routine to extract the (BC) block byte from the fcb pointed +; to by (PARAMS). If this is a big-disk, then these are 16 bit +; block numbers, else they are 8 bit numbers. +; Number is returned in (HL). +; +EXTBLK LHLD PARAMS ;get fcb address. + LXI D,16 ;block numbers start 16 bytes into fcb. + DAD D + DAD B + LDA BIGDISK ;are we using a big-disk? + ORA A + JZ EXTBLK1 + MOV L,M ;no, extract an 8 bit number from the fcb. + MVI H,0 + RET +EXTBLK1 DAD B ;yes, extract a 16 bit number. + MOV E,M + INX H + MOV D,M + XCHG ;return in (HL). + RET +; +; Compute block number. +; +COMBLK CALL GETBLOCK + MOV C,A + MVI B,0 + CALL EXTBLK + SHLD BLKNMBR + RET +; +; Check for a zero block number (unused). +; +CHKBLK LHLD BLKNMBR + MOV A,L ;is it zero? + ORA H + RET +; +; Adjust physical block (BLKNMBR) and convert to logical +; sector (LOGSECT). This is the starting sector of this block. +; The actual sector of interest is then added to this and the +; resulting sector number is stored back in (BLKNMBR). This +; will still have to be adjusted for the track number. +; +LOGICAL LDA BLKSHFT ;get log2(physical/logical sectors). + LHLD BLKNMBR ;get physical sector desired. +LOGICL1 DAD H ;compute logical sector number. + DCR A ;note logical sectors are 128 bytes long. + JNZ LOGICL1 + SHLD LOGSECT ;save logical sector. + LDA BLKMASK ;get block mask. + MOV C,A + LDA SAVNREC ;get next sector to access. + ANA C ;extract the relative position within physical block. + ORA L ;and add it too logical sector. + MOV L,A + SHLD BLKNMBR ;and store. + RET +; +; Set (HL) to point to extent byte in fcb. +; +SETEXT LHLD PARAMS + LXI D,12 ;it is the twelth byte. + DAD D + RET +; +; Set (HL) to point to record count byte in fcb and (DE) to +; next record number byte. +; +SETHLDE LHLD PARAMS + LXI D,15 ;record count byte (#15). + DAD D + XCHG + LXI H,17 ;next record number (#32). + DAD D + RET +; +; Save current file data from fcb. +; +STRDATA CALL SETHLDE + MOV A,M ;get and store record count byte. + STA SAVNREC + XCHG + MOV A,M ;get and store next record number byte. + STA SAVNXT + CALL SETEXT ;point to extent byte. + LDA EXTMASK ;get extent mask. + ANA M + STA SAVEXT ;and save extent here. + RET +; +; Set the next record to access. If (MODE) is set to 2, then +; the last record byte (SAVNREC) has the correct number to access. +; For sequential access, (MODE) will be equal to 1. +; +SETNREC CALL SETHLDE + LDA MODE ;get sequential flag (=1). + CPI 2 ;a 2 indicates that no adder is needed. + JNZ STNREC1 + XRA A ;clear adder (random access?). +STNREC1 MOV C,A + LDA SAVNREC ;get last record number. + ADD C ;increment record count. + MOV M,A ;and set fcb's next record byte. + XCHG + LDA SAVNXT ;get next record byte from storage. + MOV M,A ;and put this into fcb as number of records used. + RET +; +; Shift (HL) right (C) bits. +; +SHIFTR INR C +SHIFTR1 DCR C + RZ + MOV A,H + ORA A + RAR + MOV H,A + MOV A,L + RAR + MOV L,A + JMP SHIFTR1 +; +; Compute the check-sum for the directory buffer. Return +; integer sum in (A). +; +CHECKSUM:MVI C,128 ;length of buffer. + LHLD DIRBUF ;get its location. + XRA A ;clear summation byte. +CHKSUM1 ADD M ;and compute sum ignoring carries. + INX H + DCR C + JNZ CHKSUM1 + RET +; +; Shift (HL) left (C) bits. +; +SHIFTL INR C +SHIFTL1 DCR C + RZ + DAD H ;shift left 1 bit. + JMP SHIFTL1 +; +; Routine to set a bit in a 16 bit value contained in (BC). +; The bit set depends on the current drive selection. +; +SETBIT PUSH B ;save 16 bit word. + LDA ACTIVE ;get active drive. + MOV C,A + LXI H,1 + CALL SHIFTL ;shift bit 0 into place. + POP B ;now 'or' this with the original word. + MOV A,C + ORA L + MOV L,A ;low byte done, do high byte. + MOV A,B + ORA H + MOV H,A + RET +; +; Extract the write protect status bit for the current drive. +; The result is returned in (A), bit 0. +; +GETWPRT LHLD WRTPRT ;get status bytes. + LDA ACTIVE ;which drive is current? + MOV C,A + CALL SHIFTR ;shift status such that bit 0 is the + MOV A,L ;one of interest for this drive. + ANI 01H ;and isolate it. + RET +; +; Function to write protect the current disk. +; +WRTPRTD LXI H,WRTPRT;point to status word. + MOV C,M ;set (BC) equal to the status. + INX H + MOV B,M + CALL SETBIT ;and set this bit according to current drive. + SHLD WRTPRT ;then save. + LHLD DIRSIZE ;now save directory size limit. + INX H ;remember the last one. + XCHG + LHLD SCRATCH1;and store it here. + MOV M,E ;put low byte. + INX H + MOV M,D ;then high byte. + RET +; +; Check for a read only file. +; +CHKROFL CALL FCB2HL ;set (HL) to file entry in directory buffer. +CKROF1 LXI D,9 ;look at bit 7 of the ninth byte. + DAD D + MOV A,M + RAL + RNC ;return if ok. + LXI H,ROFILE;else, print error message and terminate. + JMP JUMPHL +; +; Check the write protect status of the active disk. +; +CHKWPRT CALL GETWPRT + RZ ;return if ok. + LXI H,RODISK;else print message and terminate. + JMP JUMPHL +; +; Routine to set (HL) pointing to the proper entry in the +; directory buffer. +; +FCB2HL LHLD DIRBUF ;get address of buffer. + LDA FCBPOS ;relative position of file. +; +; Routine to add (A) to (HL). +; +ADDA2HL ADD L + MOV L,A + RNC + INR H ;take care of any carry. + RET +; +; Routine to get the 's2' byte from the fcb supplied in +; the initial parameter specification. +; +GETS2 LHLD PARAMS ;get address of fcb. + LXI D,14 ;relative position of 's2'. + DAD D + MOV A,M ;extract this byte. + RET +; +; Clear the 's2' byte in the fcb. +; +CLEARS2 CALL GETS2 ;this sets (HL) pointing to it. + MVI M,0 ;now clear it. + RET +; +; Set bit 7 in the 's2' byte of the fcb. +; +SETS2B7 CALL GETS2 ;get the byte. + ORI 80H ;and set bit 7. + MOV M,A ;then store. + RET +; +; Compare (FILEPOS) with (SCRATCH1) and set flags based on +; the difference. This checks to see if there are more file +; names in the directory. We are at (FILEPOS) and there are +; (SCRATCH1) of them to check. +; +MOREFLS LHLD FILEPOS ;we are here. + XCHG + LHLD SCRATCH1;and don't go past here. + MOV A,E ;compute difference but don't keep. + SUB M + INX H + MOV A,D + SBB M ;set carry if no more names. + RET +; +; Call this routine to prevent (SCRATCH1) from being greater +; than (FILEPOS). +; +CHKNMBR CALL MOREFLS ;SCRATCH1 too big? + RC + INX D ;yes, reset it to (FILEPOS). + MOV M,D + DCX H + MOV M,E + RET +; +; Compute (HL)=(DE)-(HL) +; +SUBHL MOV A,E ;compute difference. + SUB L + MOV L,A ;store low byte. + MOV A,D + SBB H + MOV H,A ;and then high byte. + RET +; +; Set the directory checksum byte. +; +SETDIR MVI C,0FFH +; +; Routine to set or compare the directory checksum byte. If +; (C)=0ffh, then this will set the checksum byte. Else the byte +; will be checked. If the check fails (the disk has been changed), +; then this disk will be write protected. +; +CHECKDIR:LHLD CKSUMTBL + XCHG + LHLD ALLOC1 + CALL SUBHL + RNC ;ok if (CKSUMTBL) > (ALLOC1), so return. + PUSH B + CALL CHECKSUM;else compute checksum. + LHLD CHKVECT ;get address of checksum table. + XCHG + LHLD CKSUMTBL + DAD D ;set (HL) to point to byte for this drive. + POP B + INR C ;set or check ? + JZ CHKDIR1 + CMP M ;check them. + RZ ;return if they are the same. + CALL MOREFLS ;not the same, do we care? + RNC + CALL WRTPRTD ;yes, mark this as write protected. + RET +CHKDIR1 MOV M,A ;just set the byte. + RET +; +; Do a write to the directory of the current disk. +; +DIRWRITE:CALL SETDIR ;set checksum byte. + CALL DIRDMA ;set directory dma address. + MVI C,1 ;tell the bios to actually write. + CALL DOWRITE ;then do the write. + JMP DEFDMA +; +; Read from the directory. +; +DIRREAD CALL DIRDMA ;set the directory dma address. + CALL DOREAD ;and read it. +; +; Routine to set the dma address to the users choice. +; +DEFDMA LXI H,USERDMA;reset the default dma address and return. + JMP DIRDMA1 +; +; Routine to set the dma address for directory work. +; +DIRDMA LXI H,DIRBUF +; +; Set the dma address. On entry, (HL) points to +; word containing the desired dma address. +; +DIRDMA1 MOV C,M + INX H + MOV B,M ;setup (BC) and go to the bios to set it. + JMP SETDMA +; +; Move the directory buffer into user's dma space. +; +MOVEDIR LHLD DIRBUF ;buffer is located here, and + XCHG + LHLD USERDMA; put it here. + MVI C,128 ;this is its length. + JMP DE2HL ;move it now and return. +; +; Check (FILEPOS) and set the zero flag if it equals 0ffffh. +; +CKFILPOS:LXI H,FILEPOS + MOV A,M + INX H + CMP M ;are both bytes the same? + RNZ + INR A ;yes, but are they each 0ffh? + RET +; +; Set location (FILEPOS) to 0ffffh. +; +STFILPOS:LXI H,0FFFFH + SHLD FILEPOS + RET +; +; Move on to the next file position within the current +; directory buffer. If no more exist, set pointer to 0ffffh +; and the calling routine will check for this. Enter with (C) +; equal to 0ffh to cause the checksum byte to be set, else we +; will check this disk and set write protect if checksums are +; not the same (applies only if another directory sector must +; be read). +; +NXENTRY LHLD DIRSIZE ;get directory entry size limit. + XCHG + LHLD FILEPOS ;get current count. + INX H ;go on to the next one. + SHLD FILEPOS + CALL SUBHL ;(HL)=(DIRSIZE)-(FILEPOS) + JNC NXENT1 ;is there more room left? + JMP STFILPOS;no. Set this flag and return. +NXENT1 LDA FILEPOS ;get file position within directory. + ANI 03H ;only look within this sector (only 4 entries fit). + MVI B,5 ;convert to relative position (32 bytes each). +NXENT2 ADD A ;note that this is not efficient code. + DCR B ;5 'ADD A's would be better. + JNZ NXENT2 + STA FCBPOS ;save it as position of fcb. + ORA A + RNZ ;return if we are within buffer. + PUSH B + CALL TRKSEC ;we need the next directory sector. + CALL DIRREAD + POP B + JMP CHECKDIR +; +; Routine to to get a bit from the disk space allocation +; map. It is returned in (A), bit position 0. On entry to here, +; set (BC) to the block number on the disk to check. +; On return, (D) will contain the original bit position for +; this block number and (HL) will point to the address for it. +; +CKBITMAP:MOV A,C ;determine bit number of interest. + ANI 07H ;compute (D)=(E)=(C and 7)+1. + INR A + MOV E,A ;save particular bit number. + MOV D,A +; +; compute (BC)=(BC)/8. +; + MOV A,C + RRC ;now shift right 3 bits. + RRC + RRC + ANI 1FH ;and clear bits 7,6,5. + MOV C,A + MOV A,B + ADD A ;now shift (B) into bits 7,6,5. + ADD A + ADD A + ADD A + ADD A + ORA C ;and add in (C). + MOV C,A ;ok, (C) ha been completed. + MOV A,B ;is there a better way of doing this? + RRC + RRC + RRC + ANI 1FH + MOV B,A ;and now (B) is completed. +; +; use this as an offset into the disk space allocation +; table. +; + LHLD ALOCVECT + DAD B + MOV A,M ;now get correct byte. +CKBMAP1 RLC ;get correct bit into position 0. + DCR E + JNZ CKBMAP1 + RET +; +; Set or clear the bit map such that block number (BC) will be marked +; as used. On entry, if (E)=0 then this bit will be cleared, if it equals +; 1 then it will be set (don't use anyother values). +; +STBITMAP:PUSH D + CALL CKBITMAP;get the byte of interest. + ANI 0FEH ;clear the affected bit. + POP B + ORA C ;and now set it acording to (C). +; +; entry to restore the original bit position and then store +; in table. (A) contains the value, (D) contains the bit +; position (1-8), and (HL) points to the address within the +; space allocation table for this byte. +; +STBMAP1 RRC ;restore original bit position. + DCR D + JNZ STBMAP1 + MOV M,A ;and stor byte in table. + RET +; +; Set/clear space used bits in allocation map for this file. +; On entry, (C)=1 to set the map and (C)=0 to clear it. +; +SETFILE CALL FCB2HL ;get address of fcb + LXI D,16 + DAD D ;get to block number bytes. + PUSH B + MVI C,17 ;check all 17 bytes (max) of table. +SETFL1 POP D + DCR C ;done all bytes yet? + RZ + PUSH D + LDA BIGDISK ;check disk size for 16 bit block numbers. + ORA A + JZ SETFL2 + PUSH B ;only 8 bit numbers. set (BC) to this one. + PUSH H + MOV C,M ;get low byte from table, always + MVI B,0 ;set high byte to zero. + JMP SETFL3 +SETFL2 DCR C ;for 16 bit block numbers, adjust counter. + PUSH B + MOV C,M ;now get both the low and high bytes. + INX H + MOV B,M + PUSH H +SETFL3 MOV A,C ;block used? + ORA B + JZ SETFL4 + LHLD DSKSIZE ;is this block number within the + MOV A,L ;space on the disk? + SUB C + MOV A,H + SBB B + CNC STBITMAP;yes, set the proper bit. +SETFL4 POP H ;point to next block number in fcb. + INX H + POP B + JMP SETFL1 +; +; Construct the space used allocation bit map for the active +; drive. If a file name starts with '$' and it is under the +; current user number, then (STATUS) is set to minus 1. Otherwise +; it is not set at all. +; +BITMAP LHLD DSKSIZE ;compute size of allocation table. + MVI C,3 + CALL SHIFTR ;(HL)=(HL)/8. + INX H ;at lease 1 byte. + MOV B,H + MOV C,L ;set (BC) to the allocation table length. +; +; Initialize the bitmap for this drive. Right now, the first +; two bytes are specified by the disk parameter block. However +; a patch could be entered here if it were necessary to setup +; this table in a special mannor. For example, the bios could +; determine locations of 'bad blocks' and set them as already +; 'used' in the map. +; + LHLD ALOCVECT;now zero out the table now. +BITMAP1 MVI M,0 + INX H + DCX B + MOV A,B + ORA C + JNZ BITMAP1 + LHLD ALLOC0 ;get initial space used by directory. + XCHG + LHLD ALOCVECT;and put this into map. + MOV M,E + INX H + MOV M,D +; +; End of initialization portion. +; + CALL HOMEDRV ;now home the drive. + LHLD SCRATCH1 + MVI M,3 ;force next directory request to read + INX H ;in a sector. + MVI M,0 + CALL STFILPOS;clear initial file position also. +BITMAP2 MVI C,0FFH ;read next file name in directory + CALL NXENTRY ;and set checksum byte. + CALL CKFILPOS;is there another file? + RZ + CALL FCB2HL ;yes, get its address. + MVI A,0E5H + CMP M ;empty file entry? + JZ BITMAP2 + LDA USERNO ;no, correct user number? + CMP M + JNZ BITMAP3 + INX H + MOV A,M ;yes, does name start with a '$'? + SUI '$' + JNZ BITMAP3 + DCR A ;yes, set atatus to minus one. + STA STATUS +BITMAP3 MVI C,1 ;now set this file's space as used in bit map. + CALL SETFILE + CALL CHKNMBR ;keep (SCRATCH1) in bounds. + JMP BITMAP2 +; +; Set the status (STATUS) and return. +; +STSTATUS:LDA FNDSTAT + JMP SETSTAT +; +; Check extents in (A) and (C). Set the zero flag if they +; are the same. The number of 16k chunks of disk space that +; the directory extent covers is expressad is (EXTMASK+1). +; No registers are modified. +; +SAMEXT PUSH B + PUSH PSW + LDA EXTMASK ;get extent mask and use it to + CMA ;to compare both extent numbers. + MOV B,A ;save resulting mask here. + MOV A,C ;mask first extent and save in (C). + ANA B + MOV C,A + POP PSW ;now mask second extent and compare + ANA B ;with the first one. + SUB C + ANI 1FH ;(* only check buts 0-4 *) + POP B ;the zero flag is set if they are the same. + RET ;restore (BC) and return. +; +; Search for the first occurence of a file name. On entry, +; register (C) should contain the number of bytes of the fcb +; that must match. +; +FINDFST MVI A,0FFH + STA FNDSTAT + LXI H,COUNTER;save character count. + MOV M,C + LHLD PARAMS ;get filename to match. + SHLD SAVEFCB ;and save. + CALL STFILPOS;clear initial file position (set to 0ffffh). + CALL HOMEDRV ;home the drive. +; +; Entry to locate the next occurence of a filename within the +; directory. The disk is not expected to have been changed. If +; it was, then it will be write protected. +; +FINDNXT MVI C,0 ;write protect the disk if changed. + CALL NXENTRY ;get next filename entry in directory. + CALL CKFILPOS;is file position = 0ffffh? + JZ FNDNXT6 ;yes, exit now then. + LHLD SAVEFCB ;set (DE) pointing to filename to match. + XCHG + LDAX D + CPI 0E5H ;empty directory entry? + JZ FNDNXT1 ;(* are we trying to reserect erased entries? *) + PUSH D + CALL MOREFLS ;more files in directory? + POP D + JNC FNDNXT6 ;no more. Exit now. +FNDNXT1 CALL FCB2HL ;get address of this fcb in directory. + LDA COUNTER ;get number of bytes (characters) to check. + MOV C,A + MVI B,0 ;initialize byte position counter. +FNDNXT2 MOV A,C ;are we done with the compare? + ORA A + JZ FNDNXT5 + LDAX D ;no, check next byte. + CPI '?' ;don't care about this character? + JZ FNDNXT4 + MOV A,B ;get bytes position in fcb. + CPI 13 ;don't care about the thirteenth byte either. + JZ FNDNXT4 + CPI 12 ;extent byte? + LDAX D + JZ FNDNXT3 + SUB M ;otherwise compare characters. + ANI 7FH + JNZ FINDNXT ;not the same, check next entry. + JMP FNDNXT4 ;so far so good, keep checking. +FNDNXT3 PUSH B ;check the extent byte here. + MOV C,M + CALL SAMEXT + POP B + JNZ FINDNXT ;not the same, look some more. +; +; So far the names compare. Bump pointers to the next byte +; and continue until all (C) characters have been checked. +; +FNDNXT4 INX D ;bump pointers. + INX H + INR B + DCR C ;adjust character counter. + JMP FNDNXT2 +FNDNXT5 LDA FILEPOS ;return the position of this entry. + ANI 03H + STA STATUS + LXI H,FNDSTAT + MOV A,M + RAL + RNC + XRA A + MOV M,A + RET +; +; Filename was not found. Set appropriate status. +; +FNDNXT6 CALL STFILPOS;set (FILEPOS) to 0ffffh. + MVI A,0FFH ;say not located. + JMP SETSTAT +; +; Erase files from the directory. Only the first byte of the +; fcb will be affected. It is set to (E5). +; +ERAFILE CALL CHKWPRT ;is disk write protected? + MVI C,12 ;only compare file names. + CALL FINDFST ;get first file name. +ERAFIL1 CALL CKFILPOS;any found? + RZ ;nope, we must be done. + CALL CHKROFL ;is file read only? + CALL FCB2HL ;nope, get address of fcb and + MVI M,0E5H ;set first byte to 'empty'. + MVI C,0 ;clear the space from the bit map. + CALL SETFILE + CALL DIRWRITE;now write the directory sector back out. + CALL FINDNXT ;find the next file name. + JMP ERAFIL1 ;and repeat process. +; +; Look through the space allocation map (bit map) for the +; next available block. Start searching at block number (BC-1). +; The search procedure is to look for an empty block that is +; before the starting block. If not empty, look at a later +; block number. In this way, we return the closest empty block +; on either side of the 'target' block number. This will speed +; access on random devices. For serial devices, this should be +; changed to look in the forward direction first and then start +; at the front and search some more. +; +; On return, (DE)= block number that is empty and (HL) =0 +; if no empry block was found. +; +FNDSPACE:MOV D,B ;set (DE) as the block that is checked. + MOV E,C +; +; Look before target block. Registers (BC) are used as the lower +; pointer and (DE) as the upper pointer. +; +FNDSPA1 MOV A,C ;is block 0 specified? + ORA B + JZ FNDSPA2 + DCX B ;nope, check previous block. + PUSH D + PUSH B + CALL CKBITMAP + RAR ;is this block empty? + JNC FNDSPA3 ;yes. use this. +; +; Note that the above logic gets the first block that it finds +; that is empty. Thus a file could be written 'backward' making +; it very slow to access. This could be changed to look for the +; first empty block and then continue until the start of this +; empty space is located and then used that starting block. +; This should help speed up access to some files especially on +; a well used disk with lots of fairly small 'holes'. +; + POP B ;nope, check some more. + POP D +; +; Now look after target block. +; +FNDSPA2 LHLD DSKSIZE ;is block (DE) within disk limits? + MOV A,E + SUB L + MOV A,D + SBB H + JNC FNDSPA4 + INX D ;yes, move on to next one. + PUSH B + PUSH D + MOV B,D + MOV C,E + CALL CKBITMAP;check it. + RAR ;empty? + JNC FNDSPA3 + POP D ;nope, continue searching. + POP B + JMP FNDSPA1 +; +; Empty block found. Set it as used and return with (HL) +; pointing to it (true?). +; +FNDSPA3 RAL ;reset byte. + INR A ;and set bit 0. + CALL STBMAP1 ;update bit map. + POP H ;set return registers. + POP D + RET +; +; Free block was not found. If (BC) is not zero, then we have +; not checked all of the disk space. +; +FNDSPA4 MOV A,C + ORA B + JNZ FNDSPA1 + LXI H,0 ;set 'not found' status. + RET +; +; Move a complete fcb entry into the directory and write it. +; +FCBSET MVI C,0 + MVI E,32 ;length of each entry. +; +; Move (E) bytes from the fcb pointed to by (PARAMS) into +; fcb in directory starting at relative byte (C). This updated +; directory buffer is then written to the disk. +; +UPDATE PUSH D + MVI B,0 ;set (BC) to relative byte position. + LHLD PARAMS ;get address of fcb. + DAD B ;compute starting byte. + XCHG + CALL FCB2HL ;get address of fcb to update in directory. + POP B ;set (C) to number of bytes to change. + CALL DE2HL +UPDATE1 CALL TRKSEC ;determine the track and sector affected. + JMP DIRWRITE ;then write this sector out. +; +; Routine to change the name of all files on the disk with a +; specified name. The fcb contains the current name as the +; first 12 characters and the new name 16 bytes into the fcb. +; +CHGNAMES:CALL CHKWPRT ;check for a write protected disk. + MVI C,12 ;match first 12 bytes of fcb only. + CALL FINDFST ;get first name. + LHLD PARAMS ;get address of fcb. + MOV A,M ;get user number. + LXI D,16 ;move over to desired name. + DAD D + MOV M,A ;keep same user number. +CHGNAM1 CALL CKFILPOS;any matching file found? + RZ ;no, we must be done. + CALL CHKROFL ;check for read only file. + MVI C,16 ;start 16 bytes into fcb. + MVI E,12 ;and update the first 12 bytes of directory. + CALL UPDATE + CALL FINDNXT ;get te next file name. + JMP CHGNAM1 ;and continue. +; +; Update a files attributes. The procedure is to search for +; every file with the same name as shown in fcb (ignoring bit 7) +; and then to update it (which includes bit 7). No other changes +; are made. +; +SAVEATTR:MVI C,12 ;match first 12 bytes. + CALL FINDFST ;look for first filename. +SAVATR1 CALL CKFILPOS;was one found? + RZ ;nope, we must be done. + MVI C,0 ;yes, update the first 12 bytes now. + MVI E,12 + CALL UPDATE ;update filename and write directory. + CALL FINDNXT ;and get the next file. + JMP SAVATR1 ;then continue until done. +; +; Open a file (name specified in fcb). +; +OPENIT MVI C,15 ;compare the first 15 bytes. + CALL FINDFST ;get the first one in directory. + CALL CKFILPOS;any at all? + RZ +OPENIT1 CALL SETEXT ;point to extent byte within users fcb. + MOV A,M ;and get it. + PUSH PSW ;save it and address. + PUSH H + CALL FCB2HL ;point to fcb in directory. + XCHG + LHLD PARAMS ;this is the users copy. + MVI C,32 ;move it into users space. + PUSH D + CALL DE2HL + CALL SETS2B7 ;set bit 7 in 's2' byte (unmodified). + POP D ;now get the extent byte from this fcb. + LXI H,12 + DAD D + MOV C,M ;into (C). + LXI H,15 ;now get the record count byte into (B). + DAD D + MOV B,M + POP H ;keep the same extent as the user had originally. + POP PSW + MOV M,A + MOV A,C ;is it the same as in the directory fcb? + CMP M + MOV A,B ;if yes, then use the same record count. + JZ OPENIT2 + MVI A,0 ;if the user specified an extent greater than + JC OPENIT2 ;the one in the directory, then set record count to 0. + MVI A,128 ;otherwise set to maximum. +OPENIT2 LHLD PARAMS ;set record count in users fcb to (A). + LXI D,15 + DAD D ;compute relative position. + MOV M,A ;and set the record count. + RET +; +; Move two bytes from (DE) to (HL) if (and only if) (HL) +; point to a zero value (16 bit). +; Return with zero flag set it (DE) was moved. Registers (DE) +; and (HL) are not changed. However (A) is. +; +MOVEWORD:MOV A,M ;check for a zero word. + INX H + ORA M ;both bytes zero? + DCX H + RNZ ;nope, just return. + LDAX D ;yes, move two bytes from (DE) into + MOV M,A ;this zero space. + INX D + INX H + LDAX D + MOV M,A + DCX D ;don't disturb these registers. + DCX H + RET +; +; Get here to close a file specified by (fcb). +; +CLOSEIT XRA A ;clear status and file position bytes. + STA STATUS + STA FILEPOS + STA FILEPOS+1 + CALL GETWPRT ;get write protect bit for this drive. + RNZ ;just return if it is set. + CALL GETS2 ;else get the 's2' byte. + ANI 80H ;and look at bit 7 (file unmodified?). + RNZ ;just return if set. + MVI C,15 ;else look up this file in directory. + CALL FINDFST + CALL CKFILPOS;was it found? + RZ ;just return if not. + LXI B,16 ;set (HL) pointing to records used section. + CALL FCB2HL + DAD B + XCHG + LHLD PARAMS ;do the same for users specified fcb. + DAD B + MVI C,16 ;this many bytes are present in this extent. +CLOSEIT1:LDA BIGDISK ;8 or 16 bit record numbers? + ORA A + JZ CLOSEIT4 + MOV A,M ;just 8 bit. Get one from users fcb. + ORA A + LDAX D ;now get one from directory fcb. + JNZ CLOSEIT2 + MOV M,A ;users byte was zero. Update from directory. +CLOSEIT2:ORA A + JNZ CLOSEIT3 + MOV A,M ;directories byte was zero, update from users fcb. + STAX D +CLOSEIT3:CMP M ;if neither one of these bytes were zero, + JNZ CLOSEIT7 ;then close error if they are not the same. + JMP CLOSEIT5 ;ok so far, get to next byte in fcbs. +CLOSEIT4:CALL MOVEWORD;update users fcb if it is zero. + XCHG + CALL MOVEWORD;update directories fcb if it is zero. + XCHG + LDAX D ;if these two values are no different, + CMP M ;then a close error occured. + JNZ CLOSEIT7 + INX D ;check second byte. + INX H + LDAX D + CMP M + JNZ CLOSEIT7 + DCR C ;remember 16 bit values. +CLOSEIT5:INX D ;bump to next item in table. + INX H + DCR C ;there are 16 entries only. + JNZ CLOSEIT1;continue if more to do. + LXI B,0FFECH;backup 20 places (extent byte). + DAD B + XCHG + DAD B + LDAX D + CMP M ;directory's extent already greater than the + JC CLOSEIT6 ;users extent? + MOV M,A ;no, update directory extent. + LXI B,3 ;and update the record count byte in + DAD B ;directories fcb. + XCHG + DAD B + MOV A,M ;get from user. + STAX D ;and put in directory. +CLOSEIT6:MVI A,0FFH ;set 'was open and is now closed' byte. + STA CLOSEFLG + JMP UPDATE1 ;update the directory now. +CLOSEIT7:LXI H,STATUS;set return status and then return. + DCR M + RET +; +; Routine to get the next empty space in the directory. It +; will then be cleared for use. +; +GETEMPTY:CALL CHKWPRT ;make sure disk is not write protected. + LHLD PARAMS ;save current parameters (fcb). + PUSH H + LXI H,EMPTYFCB;use special one for empty space. + SHLD PARAMS + MVI C,1 ;search for first empty spot in directory. + CALL FINDFST ;(* only check first byte *) + CALL CKFILPOS;none? + POP H + SHLD PARAMS ;restore original fcb address. + RZ ;return if no more space. + XCHG + LXI H,15 ;point to number of records for this file. + DAD D + MVI C,17 ;and clear all of this space. + XRA A +GETMT1 MOV M,A + INX H + DCR C + JNZ GETMT1 + LXI H,13 ;clear the 's1' byte also. + DAD D + MOV M,A + CALL CHKNMBR ;keep (SCRATCH1) within bounds. + CALL FCBSET ;write out this fcb entry to directory. + JMP SETS2B7 ;set 's2' byte bit 7 (unmodified at present). +; +; Routine to close the current extent and open the next one +; for reading. +; +GETNEXT XRA A + STA CLOSEFLG;clear close flag. + CALL CLOSEIT ;close this extent. + CALL CKFILPOS + RZ ;not there??? + LHLD PARAMS ;get extent byte. + LXI B,12 + DAD B + MOV A,M ;and increment it. + INR A + ANI 1FH ;keep within range 0-31. + MOV M,A + JZ GTNEXT1 ;overflow? + MOV B,A ;mask extent byte. + LDA EXTMASK + ANA B + LXI H,CLOSEFLG;check close flag (0ffh is ok). + ANA M + JZ GTNEXT2 ;if zero, we must read in next extent. + JMP GTNEXT3 ;else, it is already in memory. +GTNEXT1 LXI B,2 ;Point to the 's2' byte. + DAD B + INR M ;and bump it. + MOV A,M ;too many extents? + ANI 0FH + JZ GTNEXT5 ;yes, set error code. +; +; Get here to open the next extent. +; +GTNEXT2 MVI C,15 ;set to check first 15 bytes of fcb. + CALL FINDFST ;find the first one. + CALL CKFILPOS;none available? + JNZ GTNEXT3 + LDA RDWRTFLG;no extent present. Can we open an empty one? + INR A ;0ffh means reading (so not possible). + JZ GTNEXT5 ;or an error. + CALL GETEMPTY;we are writing, get an empty entry. + CALL CKFILPOS;none? + JZ GTNEXT5 ;error if true. + JMP GTNEXT4 ;else we are almost done. +GTNEXT3 CALL OPENIT1 ;open this extent. +GTNEXT4 CALL STRDATA ;move in updated data (rec #, extent #, etc.) + XRA A ;clear status and return. + JMP SETSTAT +; +; Error in extending the file. Too many extents were needed +; or not enough space on the disk. +; +GTNEXT5 CALL IOERR1 ;set error code, clear bit 7 of 's2' + JMP SETS2B7 ;so this is not written on a close. +; +; Read a sequential file. +; +RDSEQ MVI A,1 ;set sequential access mode. + STA MODE +RDSEQ1 MVI A,0FFH ;don't allow reading unwritten space. + STA RDWRTFLG + CALL STRDATA ;put rec# and ext# into fcb. + LDA SAVNREC ;get next record to read. + LXI H,SAVNXT;get number of records in extent. + CMP M ;within this extent? + JC RDSEQ2 + CPI 128 ;no. Is this extent fully used? + JNZ RDSEQ3 ;no. End-of-file. + CALL GETNEXT ;yes, open the next one. + XRA A ;reset next record to read. + STA SAVNREC + LDA STATUS ;check on open, successful? + ORA A + JNZ RDSEQ3 ;no, error. +RDSEQ2 CALL COMBLK ;ok. compute block number to read. + CALL CHKBLK ;check it. Within bounds? + JZ RDSEQ3 ;no, error. + CALL LOGICAL ;convert (BLKNMBR) to logical sector (128 byte). + CALL TRKSEC1 ;set the track and sector for this block #. + CALL DOREAD ;and read it. + JMP SETNREC ;and set the next record to be accessed. +; +; Read error occured. Set status and return. +; +RDSEQ3 JMP IOERR1 +; +; Write the next sequential record. +; +WTSEQ MVI A,1 ;set sequential access mode. + STA MODE +WTSEQ1 MVI A,0 ;allow an addition empty extent to be opened. + STA RDWRTFLG + CALL CHKWPRT ;check write protect status. + LHLD PARAMS + CALL CKROF1 ;check for read only file, (HL) already set to fcb. + CALL STRDATA ;put updated data into fcb. + LDA SAVNREC ;get record number to write. + CPI 128 ;within range? + JNC IOERR1 ;no, error(?). + CALL COMBLK ;compute block number. + CALL CHKBLK ;check number. + MVI C,0 ;is there one to write to? + JNZ WTSEQ6 ;yes, go do it. + CALL GETBLOCK;get next block number within fcb to use. + STA RELBLOCK;and save. + LXI B,0 ;start looking for space from the start + ORA A ;if none allocated as yet. + JZ WTSEQ2 + MOV C,A ;extract previous block number from fcb + DCX B ;so we can be closest to it. + CALL EXTBLK + MOV B,H + MOV C,L +WTSEQ2 CALL FNDSPACE;find the next empty block nearest number (BC). + MOV A,L ;check for a zero number. + ORA H + JNZ WTSEQ3 + MVI A,2 ;no more space? + JMP SETSTAT +WTSEQ3 SHLD BLKNMBR ;save block number to access. + XCHG ;put block number into (DE). + LHLD PARAMS ;now we must update the fcb for this + LXI B,16 ;newly allocated block. + DAD B + LDA BIGDISK ;8 or 16 bit block numbers? + ORA A + LDA RELBLOCK ;(* update this entry *) + JZ WTSEQ4 ;zero means 16 bit ones. + CALL ADDA2HL ;(HL)=(HL)+(A) + MOV M,E ;store new block number. + JMP WTSEQ5 +WTSEQ4 MOV C,A ;compute spot in this 16 bit table. + MVI B,0 + DAD B + DAD B + MOV M,E ;stuff block number (DE) there. + INX H + MOV M,D +WTSEQ5 MVI C,2 ;set (C) to indicate writing to un-used disk space. +WTSEQ6 LDA STATUS ;are we ok so far? + ORA A + RNZ + PUSH B ;yes, save write flag for bios (register C). + CALL LOGICAL ;convert (BLKNMBR) over to loical sectors. + LDA MODE ;get access mode flag (1=sequential, + DCR A ;0=random, 2=special?). + DCR A + JNZ WTSEQ9 +; +; Special random i/o from function #40. Maybe for M/PM, but the +; current block, if it has not been written to, will be zeroed +; out and then written (reason?). +; + POP B + PUSH B + MOV A,C ;get write status flag (2=writing unused space). + DCR A + DCR A + JNZ WTSEQ9 + PUSH H + LHLD DIRBUF ;zero out the directory buffer. + MOV D,A ;note that (A) is zero here. +WTSEQ7 MOV M,A + INX H + INR D ;do 128 bytes. + JP WTSEQ7 + CALL DIRDMA ;tell the bios the dma address for directory access. + LHLD LOGSECT ;get sector that starts current block. + MVI C,2 ;set 'writing to unused space' flag. +WTSEQ8 SHLD BLKNMBR ;save sector to write. + PUSH B + CALL TRKSEC1 ;determine its track and sector numbers. + POP B + CALL DOWRITE ;now write out 128 bytes of zeros. + LHLD BLKNMBR ;get sector number. + MVI C,0 ;set normal write flag. + LDA BLKMASK ;determine if we have written the entire + MOV B,A ;physical block. + ANA L + CMP B + INX H ;prepare for the next one. + JNZ WTSEQ8 ;continue until (BLKMASK+1) sectors written. + POP H ;reset next sector number. + SHLD BLKNMBR + CALL DEFDMA ;and reset dma address. +; +; Normal disk write. Set the desired track and sector then +; do the actual write. +; +WTSEQ9 CALL TRKSEC1 ;determine track and sector for this write. + POP B ;get write status flag. + PUSH B + CALL DOWRITE ;and write this out. + POP B + LDA SAVNREC ;get number of records in file. + LXI H,SAVNXT;get last record written. + CMP M + JC WTSEQ10 + MOV M,A ;we have to update record count. + INR M + MVI C,2 +; +;* This area has been patched to correct disk update problem +;* when using blocking and de-blocking in the BIOS. +; +WTSEQ10 NOP ;was 'dcr c' + NOP ;was 'dcr c' + LXI H,0 ;was 'jnz wtseq99' +; +; * End of patch. +; + PUSH PSW + CALL GETS2 ;set 'extent written to' flag. + ANI 7FH ;(* clear bit 7 *) + MOV M,A + POP PSW ;get record count for this extent. +WTSEQ99 CPI 127 ;is it full? + JNZ WTSEQ12 + LDA MODE ;yes, are we in sequential mode? + CPI 1 + JNZ WTSEQ12 + CALL SETNREC ;yes, set next record number. + CALL GETNEXT ;and get next empty space in directory. + LXI H,STATUS;ok? + MOV A,M + ORA A + JNZ WTSEQ11 + DCR A ;yes, set record count to -1. + STA SAVNREC +WTSEQ11 MVI M,0 ;clear status. +WTSEQ12 JMP SETNREC ;set next record to access. +; +; For random i/o, set the fcb for the desired record number +; based on the 'r0,r1,r2' bytes. These bytes in the fcb are +; used as follows: +; +; fcb+35 fcb+34 fcb+33 +; | 'r-2' | 'r-1' | 'r-0' | +; |7 0 | 7 0 | 7 0| +; |0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0| +; | overflow | | extra | extent | record # | +; | ______________| |_extent|__number___|_____________| +; also 's2' +; +; On entry, register (C) contains 0ffh if this is a read +; and thus we can not access unwritten disk space. Otherwise, +; another extent will be opened (for writing) if required. +; +POSITION:XRA A ;set random i/o flag. + STA MODE +; +; Special entry (function #40). M/PM ? +; +POSITN1 PUSH B ;save read/write flag. + LHLD PARAMS ;get address of fcb. + XCHG + LXI H,33 ;now get byte 'r0'. + DAD D + MOV A,M + ANI 7FH ;keep bits 0-6 for the record number to access. + PUSH PSW + MOV A,M ;now get bit 7 of 'r0' and bits 0-3 of 'r1'. + RAL + INX H + MOV A,M + RAL + ANI 1FH ;and save this in bits 0-4 of (C). + MOV C,A ;this is the extent byte. + MOV A,M ;now get the extra extent byte. + RAR + RAR + RAR + RAR + ANI 0FH + MOV B,A ;and save it in (B). + POP PSW ;get record number back to (A). + INX H ;check overflow byte 'r2'. + MOV L,M + INR L + DCR L + MVI L,6 ;prepare for error. + JNZ POSITN5 ;out of disk space error. + LXI H,32 ;store record number into fcb. + DAD D + MOV M,A + LXI H,12 ;and now check the extent byte. + DAD D + MOV A,C + SUB M ;same extent as before? + JNZ POSITN2 + LXI H,14 ;yes, check extra extent byte 's2' also. + DAD D + MOV A,B + SUB M + ANI 7FH + JZ POSITN3;same, we are almost done then. +; +; Get here when another extent is required. +; +POSITN2 PUSH B + PUSH D + CALL CLOSEIT ;close current extent. + POP D + POP B + MVI L,3 ;prepare for error. + LDA STATUS + INR A + JZ POSITN4 ;close error. + LXI H,12 ;put desired extent into fcb now. + DAD D + MOV M,C + LXI H,14 ;and store extra extent byte 's2'. + DAD D + MOV M,B + CALL OPENIT ;try and get this extent. + LDA STATUS ;was it there? + INR A + JNZ POSITN3 + POP B ;no. can we create a new one (writing?). + PUSH B + MVI L,4 ;prepare for error. + INR C + JZ POSITN4 ;nope, reading unwritten space error. + CALL GETEMPTY;yes we can, try to find space. + MVI L,5 ;prepare for error. + LDA STATUS + INR A + JZ POSITN4 ;out of space? +; +; Normal return location. Clear error code and return. +; +POSITN3 POP B ;restore stack. + XRA A ;and clear error code byte. + JMP SETSTAT +; +; Error. Set the 's2' byte to indicate this (why?). +; +POSITN4 PUSH H + CALL GETS2 + MVI M,0C0H + POP H +; +; Return with error code (presently in L). +; +POSITN5 POP B + MOV A,L ;get error code. + STA STATUS + JMP SETS2B7 +; +; Read a random record. +; +READRAN MVI C,0FFH ;set 'read' status. + CALL POSITION;position the file to proper record. + CZ RDSEQ1 ;and read it as usual (if no errors). + RET +; +; Write to a random record. +; +WRITERAN:MVI C,0 ;set 'writing' flag. + CALL POSITION;position the file to proper record. + CZ WTSEQ1 ;and write as usual (if no errors). + RET +; +; Compute the random record number. Enter with (HL) pointing +; to a fcb an (DE) contains a relative location of a record +; number. On exit, (C) contains the 'r0' byte, (B) the 'r1' +; byte, and (A) the 'r2' byte. +; +; On return, the zero flag is set if the record is within +; bounds. Otherwise, an overflow occured. +; +COMPRAND:XCHG ;save fcb pointer in (DE). + DAD D ;compute relative position of record #. + MOV C,M ;get record number into (BC). + MVI B,0 + LXI H,12 ;now get extent. + DAD D + MOV A,M ;compute (BC)=(record #)+(extent)*128. + RRC ;move lower bit into bit 7. + ANI 80H ;and ignore all other bits. + ADD C ;add to our record number. + MOV C,A + MVI A,0 ;take care of any carry. + ADC B + MOV B,A + MOV A,M ;now get the upper bits of extent into + RRC ;bit positions 0-3. + ANI 0FH ;and ignore all others. + ADD B ;add this in to 'r1' byte. + MOV B,A + LXI H,14 ;get the 's2' byte (extra extent). + DAD D + MOV A,M + ADD A ;and shift it left 4 bits (bits 4-7). + ADD A + ADD A + ADD A + PUSH PSW ;save carry flag (bit 0 of flag byte). + ADD B ;now add extra extent into 'r1'. + MOV B,A + PUSH PSW ;and save carry (overflow byte 'r2'). + POP H ;bit 0 of (L) is the overflow indicator. + MOV A,L + POP H ;and same for first carry flag. + ORA L ;either one of these set? + ANI 01H ;only check the carry flags. + RET +; +; Routine to setup the fcb (bytes 'r0', 'r1', 'r2') to +; reflect the last record used for a random (or other) file. +; This reads the directory and looks at all extents computing +; the largerst record number for each and keeping the maximum +; value only. Then 'r0', 'r1', and 'r2' will reflect this +; maximum record number. This is used to compute the space used +; by a random file. +; +RANSIZE MVI C,12 ;look thru directory for first entry with + CALL FINDFST ;this name. + LHLD PARAMS ;zero out the 'r0, r1, r2' bytes. + LXI D,33 + DAD D + PUSH H + MOV M,D ;note that (D)=0. + INX H + MOV M,D + INX H + MOV M,D +RANSIZ1 CALL CKFILPOS;is there an extent to process? + JZ RANSIZ3 ;no, we are done. + CALL FCB2HL ;set (HL) pointing to proper fcb in dir. + LXI D,15 ;point to last record in extent. + CALL COMPRAND;and compute random parameters. + POP H + PUSH H ;now check these values against those + MOV E,A ;already in fcb. + MOV A,C ;the carry flag will be set if those + SUB M ;in the fcb represent a larger size than + INX H ;this extent does. + MOV A,B + SBB M + INX H + MOV A,E + SBB M + JC RANSIZ2 + MOV M,E ;we found a larger (in size) extent. + DCX H ;stuff these values into fcb. + MOV M,B + DCX H + MOV M,C +RANSIZ2 CALL FINDNXT ;now get the next extent. + JMP RANSIZ1 ;continue til all done. +RANSIZ3 POP H ;we are done, restore the stack and + RET ;return. +; +; Function to return the random record position of a given +; file which has been read in sequential mode up to now. +; +SETRAN LHLD PARAMS ;point to fcb. + LXI D,32 ;and to last used record. + CALL COMPRAND;compute random position. + LXI H,33 ;now stuff these values into fcb. + DAD D + MOV M,C ;move 'r0'. + INX H + MOV M,B ;and 'r1'. + INX H + MOV M,A ;and lastly 'r2'. + RET +; +; This routine select the drive specified in (ACTIVE) and +; update the login vector and bitmap table if this drive was +; not already active. +; +LOGINDRV:LHLD LOGIN ;get the login vector. + LDA ACTIVE ;get the default drive. + MOV C,A + CALL SHIFTR ;position active bit for this drive + PUSH H ;into bit 0. + XCHG + CALL SELECT ;select this drive. + POP H + CZ SLCTERR ;valid drive? + MOV A,L ;is this a newly activated drive? + RAR + RC + LHLD LOGIN ;yes, update the login vector. + MOV C,L + MOV B,H + CALL SETBIT + SHLD LOGIN ;and save. + JMP BITMAP ;now update the bitmap. +; +; Function to set the active disk number. +; +SETDSK LDA EPARAM ;get parameter passed and see if this + LXI H,ACTIVE;represents a change in drives. + CMP M + RZ + MOV M,A ;yes it does, log it in. + JMP LOGINDRV +; +; This is the 'auto disk select' routine. The firsst byte +; of the fcb is examined for a drive specification. If non +; zero then the drive will be selected and loged in. +; +AUTOSEL MVI A,0FFH ;say 'auto-select activated'. + STA AUTO + LHLD PARAMS ;get drive specified. + MOV A,M + ANI 1FH ;look at lower 5 bits. + DCR A ;adjust for (1=A, 2=B) etc. + STA EPARAM ;and save for the select routine. + CPI 1EH ;check for 'no change' condition. + JNC AUTOSL1 ;yes, don't change. + LDA ACTIVE ;we must change, save currently active + STA OLDDRV ;drive. + MOV A,M ;and save first byte of fcb also. + STA AUTOFLAG;this must be non-zero. + ANI 0E0H ;whats this for (bits 6,7 are used for + MOV M,A ;something)? + CALL SETDSK ;select and log in this drive. +AUTOSL1 LDA USERNO ;move user number into fcb. + LHLD PARAMS ;(* upper half of first byte *) + ORA M + MOV M,A + RET ;and return (all done). +; +; Function to return the current cp/m version number. +; +GETVER MVI A,022h ;version 2.2 + JMP SETSTAT +; +; Function to reset the disk system. +; +RSTDSK LXI H,0 ;clear write protect status and log + SHLD WRTPRT ;in vector. + SHLD LOGIN + XRA A ;select drive 'A'. + STA ACTIVE + LXI H,TBUFF ;setup default dma address. + SHLD USERDMA + CALL DEFDMA + JMP LOGINDRV;now log in drive 'A'. +; +; Function to open a specified file. +; +OPENFIL CALL CLEARS2 ;clear 's2' byte. + CALL AUTOSEL ;select proper disk. + JMP OPENIT ;and open the file. +; +; Function to close a specified file. +; +CLOSEFIL:CALL AUTOSEL ;select proper disk. + JMP CLOSEIT ;and close the file. +; +; Function to return the first occurence of a specified file +; name. If the first byte of the fcb is '?' then the name will +; not be checked (get the first entry no matter what). +; +GETFST MVI C,0 ;prepare for special search. + XCHG + MOV A,M ;is first byte a '?'? + CPI '?' + JZ GETFST1 ;yes, just get very first entry (zero length match). + CALL SETEXT ;get the extension byte from fcb. + MOV A,M ;is it '?'? if yes, then we want + CPI '?' ;an entry with a specific 's2' byte. + CNZ CLEARS2 ;otherwise, look for a zero 's2' byte. + CALL AUTOSEL ;select proper drive. + MVI C,15 ;compare bytes 0-14 in fcb (12&13 excluded). +GETFST1 CALL FINDFST ;find an entry and then move it into + JMP MOVEDIR ;the users dma space. +; +; Function to return the next occurence of a file name. +; +GETNXT LHLD SAVEFCB ;restore pointers. note that no + SHLD PARAMS ;other dbos calls are allowed. + CALL AUTOSEL ;no error will be returned, but the + CALL FINDNXT ;results will be wrong. + JMP MOVEDIR +; +; Function to delete a file by name. +; +DELFILE CALL AUTOSEL ;select proper drive. + CALL ERAFILE ;erase the file. + JMP STSTATUS;set status and return. +; +; Function to execute a sequential read of the specified +; record number. +; +READSEQ CALL AUTOSEL ;select proper drive then read. + JMP RDSEQ +; +; Function to write the net sequential record. +; +WRTSEQ CALL AUTOSEL ;select proper drive then write. + JMP WTSEQ +; +; Create a file function. +; +FCREATE CALL CLEARS2 ;clear the 's2' byte on all creates. + CALL AUTOSEL ;select proper drive and get the next + JMP GETEMPTY;empty directory space. +; +; Function to rename a file. +; +RENFILE CALL AUTOSEL ;select proper drive and then switch + CALL CHGNAMES;file names. + JMP STSTATUS +; +; Function to return the login vector. +; +GETLOG LHLD LOGIN + JMP GETPRM1 +; +; Function to return the current disk assignment. +; +GETCRNT LDA ACTIVE + JMP SETSTAT +; +; Function to set the dma address. +; +PUTDMA XCHG + SHLD USERDMA ;save in our space and then get to + JMP DEFDMA ;the bios with this also. +; +; Function to return the allocation vector. +; +GETALOC LHLD ALOCVECT + JMP GETPRM1 +; +; Function to return the read-only status vector. +; +GETROV LHLD WRTPRT + JMP GETPRM1 +; +; Function to set the file attributes (read-only, system). +; +SETATTR CALL AUTOSEL ;select proper drive then save attributes. + CALL SAVEATTR + JMP STSTATUS +; +; Function to return the address of the disk parameter block +; for the current drive. +; +GETPARM LHLD DISKPB +GETPRM1 SHLD STATUS + RET +; +; Function to get or set the user number. If (E) was (FF) +; then this is a request to return the current user number. +; Else set the user number from (E). +; +GETUSER LDA EPARAM ;get parameter. + CPI 0FFH ;get user number? + JNZ SETUSER + LDA USERNO ;yes, just do it. + JMP SETSTAT +SETUSER ANI 1FH ;no, we should set it instead. keep low + STA USERNO ;bits (0-4) only. + RET +; +; Function to read a random record from a file. +; +RDRANDOM:CALL AUTOSEL ;select proper drive and read. + JMP READRAN +; +; Function to compute the file size for random files. +; +WTRANDOM:CALL AUTOSEL ;select proper drive and write. + JMP WRITERAN +; +; Function to compute the size of a random file. +; +FILESIZE:CALL AUTOSEL ;select proper drive and check file length + JMP RANSIZE +; +; Function #37. This allows a program to log off any drives. +; On entry, set (DE) to contain a word with bits set for those +; drives that are to be logged off. The log-in vector and the +; write protect vector will be updated. This must be a M/PM +; special function. +; +LOGOFF LHLD PARAMS ;get drives to log off. + MOV A,L ;for each bit that is set, we want + CMA ;to clear that bit in (LOGIN) + MOV E,A ;and (WRTPRT). + MOV A,H + CMA + LHLD LOGIN ;reset the login vector. + ANA H + MOV D,A + MOV A,L + ANA E + MOV E,A + LHLD WRTPRT + XCHG + SHLD LOGIN ;and save. + MOV A,L ;now do the write protect vector. + ANA E + MOV L,A + MOV A,H + ANA D + MOV H,A + SHLD WRTPRT ;and save. all done. + RET +; +; Get here to return to the user. +; +GOBACK LDA AUTO ;was auto select activated? + ORA A + JZ GOBACK1 + LHLD PARAMS ;yes, but was a change made? + MVI M,0 ;(* reset first byte of fcb *) + LDA AUTOFLAG + ORA A + JZ GOBACK1 + MOV M,A ;yes, reset first byte properly. + LDA OLDDRV ;and get the old drive and select it. + STA EPARAM + CALL SETDSK +GOBACK1 LHLD USRSTACK;reset the users stack pointer. + SPHL + LHLD STATUS ;get return status. + MOV A,L ;force version 1.4 compatability. + MOV B,H + RET ;and go back to user. +; +; Function #40. This is a special entry to do random i/o. +; For the case where we are writing to unused disk space, this +; space will be zeroed out first. This must be a M/PM special +; purpose function, because why would any normal program even +; care about the previous contents of a sector about to be +; written over. +; +WTSPECL CALL AUTOSEL ;select proper drive. + MVI A,2 ;use special write mode. + STA MODE + MVI C,0 ;set write indicator. + CALL POSITN1 ;position the file. + CZ WTSEQ1 ;and write (if no errors). + RET +; +;************************************************************** +;* +;* BDOS data storage pool. +;* +;************************************************************** +; +EMPTYFCB:DB 0E5H ;empty directory segment indicator. +WRTPRT DW 0 ;write protect status for all 16 drives. +LOGIN DW 0 ;drive active word (1 bit per drive). +USERDMA DW 080H ;user's dma address (defaults to 80h). +; +; Scratch areas from parameter block. +; +SCRATCH1:DW 0 ;relative position within dir segment for file (0-3). +SCRATCH2:DW 0 ;last selected track number. +SCRATCH3:DW 0 ;last selected sector number. +; +; Disk storage areas from parameter block. +; +DIRBUF DW 0 ;address of directory buffer to use. +DISKPB DW 0 ;contains address of disk parameter block. +CHKVECT DW 0 ;address of check vector. +ALOCVECT:DW 0 ;address of allocation vector (bit map). +; +; Parameter block returned from the bios. +; +SECTORS DW 0 ;sectors per track from bios. +BLKSHFT DB 0 ;block shift. +BLKMASK DB 0 ;block mask. +EXTMASK DB 0 ;extent mask. +DSKSIZE DW 0 ;disk size from bios (number of blocks-1). +DIRSIZE DW 0 ;directory size. +ALLOC0 DW 0 ;storage for first bytes of bit map (dir space used). +ALLOC1 DW 0 +OFFSET DW 0 ;first usable track number. +XLATE DW 0 ;sector translation table address. +; +; +CLOSEFLG:DB 0 ;close flag (=0ffh is extent written ok). +RDWRTFLG:DB 0 ;read/write flag (0ffh=read, 0=write). +FNDSTAT DB 0 ;filename found status (0=found first entry). +MODE DB 0 ;I/o mode select (0=random, 1=sequential, 2=special random). +EPARAM DB 0 ;storage for register (E) on entry to bdos. +RELBLOCK:DB 0 ;relative position within fcb of block number written. +COUNTER DB 0 ;byte counter for directory name searches. +SAVEFCB DW 0,0 ;save space for address of fcb (for directory searches). +BIGDISK DB 0 ;if =0 then disk is > 256 blocks long. +AUTO DB 0 ;if non-zero, then auto select activated. +OLDDRV DB 0 ;on auto select, storage for previous drive. +AUTOFLAG:DB 0 ;if non-zero, then auto select changed drives. +SAVNXT DB 0 ;storage for next record number to access. +SAVEXT DB 0 ;storage for extent number of file. +SAVNREC DW 0 ;storage for number of records in file. +BLKNMBR DW 0 ;block number (physical sector) used within a file or logical sector. +LOGSECT DW 0 ;starting logical (128 byte) sector of block (physical sector). +FCBPOS DB 0 ;relative position within buffer for fcb of file of interest. +FILEPOS DW 0 ;files position within directory (0 to max entries -1). +; +; Disk directory buffer checksum bytes. One for each of the +; 16 possible drives. +; +CKSUMTBL:DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +; +; Extra space ? +; + DB 0,0,0,0 +; +;************************************************************** +;* +;* B I O S J U M P T A B L E +;* +;************************************************************** +; +BOOT JMP 0 ;NOTE WE USE FAKE DESTINATIONS +WBOOT JMP 0 +CONST JMP 0 +CONIN JMP 0 +CONOUT JMP 0 +LIST JMP 0 +PUNCH JMP 0 +READER JMP 0 +HOME JMP 0 +SELDSK JMP 0 +SETTRK JMP 0 +SETSEC JMP 0 +SETDMA JMP 0 +READ JMP 0 +WRITE JMP 0 +PRSTAT JMP 0 +SECTRN JMP 0 +; +;* +;****************** E N D O F C P / M ***************** +;* + diff --git a/runtime/CSharp/tests/issue-2693/test.sh b/runtime/CSharp/tests/issue-2693/test.sh new file mode 100644 index 000000000..8efb0a1e0 --- /dev/null +++ b/runtime/CSharp/tests/issue-2693/test.sh @@ -0,0 +1,11 @@ +#!/usr/bin/bash + +dotnet restore +dotnet build +dotnet run -file cpm22.asm +if [[ "$?" != "0" ]] +then + echo "Issue 2693 test failed." + exit 1 +fi +