mirror of
https://github.com/MaSzyna-EU07/StarterNG.git
synced 2026-11-13 20:03:19 +01:00
fix: an include in other letter case is no fault, as eu07 opens it
eu07 now finds files whatever the case of their names on Linux too (MaSzyna-EU07/maszyna#362), so the starter no longer folds an include or a scenery's .sbt to lower case to judge whether the simulator opens it: it looks them up through CaseInsensitivePaths. The IncludeLetterCase fault and its texts go, being a false alarm now, and the parser takes a plain yes or no for each include.
This commit is contained in:
@@ -273,7 +273,7 @@ public class ScenerySyntaxTests
|
|||||||
include koniec.scm
|
include koniec.scm
|
||||||
""";
|
""";
|
||||||
|
|
||||||
var scenery = TestScenery.Parser().Parse("scenery/x.scn", scn, _ => new IncludeLookup(true));
|
var scenery = TestScenery.Parser().Parse("scenery/x.scn", scn, _ => true);
|
||||||
|
|
||||||
Assert.Empty(scenery.Faults);
|
Assert.Empty(scenery.Faults);
|
||||||
Assert.Equal("td/rozklad", Assert.Single(scenery.Trainsets).Name);
|
Assert.Equal("td/rozklad", Assert.Single(scenery.Trainsets).Name);
|
||||||
@@ -326,7 +326,7 @@ public class ScenerySyntaxTests
|
|||||||
endoptional
|
endoptional
|
||||||
""";
|
""";
|
||||||
|
|
||||||
var faults = TestScenery.Parser().Parse("scenery/x.scn", scn, name => new IncludeLookup(name is "tory.scm" or "budynek.inc")).Faults;
|
var faults = TestScenery.Parser().Parse("scenery/x.scn", scn, name => name is "tory.scm" or "budynek.inc").Faults;
|
||||||
|
|
||||||
Assert.Equal((SceneryFaultKind.MissingInclude, "x.scn", 2, null, "brak.scm"), Seen(Assert.Single(faults)));
|
Assert.Equal((SceneryFaultKind.MissingInclude, "x.scn", 2, null, "brak.scm"), Seen(Assert.Single(faults)));
|
||||||
}
|
}
|
||||||
@@ -347,9 +347,9 @@ public class ScenerySyntaxTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void An_include_on_disk_only_in_other_letter_case_is_what_linux_misses()
|
public void An_include_on_disk_in_other_letter_case_is_no_fault()
|
||||||
{
|
{
|
||||||
// The simulator folds the name to lower case and opens it so.
|
// The simulator finds the file whatever the case of its letters, on Linux too.
|
||||||
var files = new InMemoryFileSystem(caseSensitive: true)
|
var files = new InMemoryFileSystem(caseSensitive: true)
|
||||||
.WithLegacyFile("game/scenery/braniewo_szeroki.scn",
|
.WithLegacyFile("game/scenery/braniewo_szeroki.scn",
|
||||||
"include braniewo/base.ctr end\ninclude Braniewo/Tory.SCM end\n")
|
"include braniewo/base.ctr end\ninclude Braniewo/Tory.SCM end\n")
|
||||||
@@ -357,21 +357,20 @@ public class ScenerySyntaxTests
|
|||||||
.WithFile("game/scenery/braniewo/tory.scm", "");
|
.WithFile("game/scenery/braniewo/tory.scm", "");
|
||||||
var repository = TestScenery.Repository(files);
|
var repository = TestScenery.Repository(files);
|
||||||
|
|
||||||
var faults = repository.Load("game/scenery/braniewo_szeroki.scn")!.Faults;
|
Assert.Empty(repository.Load("game/scenery/braniewo_szeroki.scn")!.Faults);
|
||||||
|
|
||||||
Assert.Equal((SceneryFaultKind.IncludeLetterCase, "braniewo_szeroki.scn", 1, "Braniewo/Base.ctr", "braniewo/base.ctr"),
|
|
||||||
Seen(Assert.Single(faults)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(true)]
|
[InlineData(null)]
|
||||||
[InlineData(false)]
|
[InlineData("lk2_sandbox.sbt")]
|
||||||
public void A_missing_terrain_file_is_no_fault_while_the_scenery_has_its_own_sbt(bool sbt)
|
[InlineData("Lk2_Sandbox.SBT")]
|
||||||
|
public void A_missing_terrain_file_is_no_fault_while_the_scenery_has_its_own_sbt(string? sbtOnDisk)
|
||||||
{
|
{
|
||||||
|
bool sbt = sbtOnDisk is not null;
|
||||||
var files = new InMemoryFileSystem(caseSensitive: true)
|
var files = new InMemoryFileSystem(caseSensitive: true)
|
||||||
.WithLegacyFile("game/scenery/Lk2_Sandbox.scn", "include nmt/nmt100_mazowieckie_ter.scm end\nFirstInit\n");
|
.WithLegacyFile("game/scenery/Lk2_Sandbox.scn", "include nmt/nmt100_mazowieckie_ter.scm end\nFirstInit\n");
|
||||||
if (sbt)
|
if (sbt)
|
||||||
files.WithFile("game/scenery/lk2_sandbox.sbt", "EU07");
|
files.WithFile("game/scenery/" + sbtOnDisk, "EU07");
|
||||||
var repository = TestScenery.Repository(files);
|
var repository = TestScenery.Repository(files);
|
||||||
|
|
||||||
var scenery = repository.Load("game/scenery/Lk2_Sandbox.scn")!;
|
var scenery = repository.Load("game/scenery/Lk2_Sandbox.scn")!;
|
||||||
|
|||||||
@@ -61,13 +61,6 @@ public enum SceneryFaultKind
|
|||||||
/// <summary>An include whose file is not there; <see cref="SceneryFault.Token"/> names it.</summary>
|
/// <summary>An include whose file is not there; <see cref="SceneryFault.Token"/> names it.</summary>
|
||||||
MissingInclude,
|
MissingInclude,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An include whose file is there only under a name in other letter case: the
|
|
||||||
/// simulator looks for it in lower case, which on Linux misses it. The
|
|
||||||
/// <see cref="SceneryFault.Subject"/> holds the name on disk.
|
|
||||||
/// </summary>
|
|
||||||
IncludeLetterCase,
|
|
||||||
|
|
||||||
/// <summary>An include with no <c>end</c>, which swallows what follows it.</summary>
|
/// <summary>An include with no <c>end</c>, which swallows what follows it.</summary>
|
||||||
IncludeNotClosed,
|
IncludeNotClosed,
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,6 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace StarterNG.Domain.Sceneries;
|
namespace StarterNG.Domain.Sceneries;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// What the simulator makes of an include: whether it opens the file - and when
|
|
||||||
/// it does not, the file that is there under a name differing only in letter case.
|
|
||||||
/// </summary>
|
|
||||||
public readonly record struct IncludeLookup(bool Opens, string? OnDisk = null);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Goes through a scenery's text for the parts the starter reads - trainsets,
|
/// Goes through a scenery's text for the parts the starter reads - trainsets,
|
||||||
/// vehicles, includes - finding where each trainset and loose vehicle is, and
|
/// vehicles, includes - finding where each trainset and loose vehicle is, and
|
||||||
@@ -35,17 +29,17 @@ public static class ScenerySyntax
|
|||||||
|
|
||||||
/// <param name="text">The scenery's text, its includes put in place.</param>
|
/// <param name="text">The scenery's text, its includes put in place.</param>
|
||||||
/// <param name="file">The scenery's file name, for faults in its own text.</param>
|
/// <param name="file">The scenery's file name, for faults in its own text.</param>
|
||||||
/// <param name="findInclude">
|
/// <param name="opensInclude">
|
||||||
/// What the simulator makes of an include, named as the include names it; null
|
/// Whether the simulator opens an include, named as the include names it; null
|
||||||
/// leaves includes unchecked.
|
/// leaves includes unchecked.
|
||||||
/// </param>
|
/// </param>
|
||||||
public static Result Scan(string text, string file, Func<string, IncludeLookup>? findInclude = null)
|
public static Result Scan(string text, string file, Func<string, bool>? opensInclude = null)
|
||||||
{
|
{
|
||||||
string code = SceneryCode.Mask(text, out int unclosed);
|
string code = SceneryCode.Mask(text, out int unclosed);
|
||||||
var tokens = SceneryCode.Tokens(code);
|
var tokens = SceneryCode.Tokens(code);
|
||||||
var lines = new SceneryLines(text, file);
|
var lines = new SceneryLines(text, file);
|
||||||
|
|
||||||
var simulator = new Reading(tokens, lines, findInclude, asSimulator: true);
|
var simulator = new Reading(tokens, lines, opensInclude, asSimulator: true);
|
||||||
simulator.Run();
|
simulator.Run();
|
||||||
var author = new Reading(tokens, lines, null, asSimulator: false);
|
var author = new Reading(tokens, lines, null, asSimulator: false);
|
||||||
author.Run();
|
author.Run();
|
||||||
@@ -116,7 +110,7 @@ public static class ScenerySyntax
|
|||||||
}
|
}
|
||||||
|
|
||||||
private sealed class Reading(
|
private sealed class Reading(
|
||||||
List<SceneryCode.Token> tokens, SceneryLines lines, Func<string, IncludeLookup>? findInclude, bool asSimulator)
|
List<SceneryCode.Token> tokens, SceneryLines lines, Func<string, bool>? opensInclude, bool asSimulator)
|
||||||
{
|
{
|
||||||
public readonly List<(int Start, int End, string Name)> Trainsets = new();
|
public readonly List<(int Start, int End, string Name)> Trainsets = new();
|
||||||
public readonly List<(int, int)> Loose = new();
|
public readonly List<(int, int)> Loose = new();
|
||||||
@@ -375,13 +369,8 @@ public static class ScenerySyntax
|
|||||||
return stop < tokens.Count && tokens[stop].Is("end") ? stop : stop - 1;
|
return stop < tokens.Count && tokens[stop].Is("end") ? stop : stop - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (findInclude is not null && Plain(name) && findInclude(name) is { Opens: false } lookup)
|
if (opensInclude is not null && Plain(name) && !opensInclude(name))
|
||||||
{
|
Fault(SceneryFaultKind.MissingInclude, token.Index, token: name);
|
||||||
if (lookup.OnDisk is { } onDisk)
|
|
||||||
Fault(SceneryFaultKind.IncludeLetterCase, token.Index, onDisk, name);
|
|
||||||
else
|
|
||||||
Fault(SceneryFaultKind.MissingInclude, token.Index, token: name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The simulator takes its parameters up to the word "end", written just so,
|
// The simulator takes its parameters up to the word "end", written just so,
|
||||||
// whatever comes before it.
|
// whatever comes before it.
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ public sealed class SceneryParser
|
|||||||
_random = random;
|
_random = random;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <param name="findInclude">
|
/// <param name="opensInclude">
|
||||||
/// What the simulator makes of an include, as the include names it; null leaves
|
/// Whether the simulator opens an include, as the include names it; null leaves
|
||||||
/// includes unchecked.
|
/// includes unchecked.
|
||||||
/// </param>
|
/// </param>
|
||||||
public Scenery Parse(string path, string content, Func<string, IncludeLookup>? findInclude = null)
|
public Scenery Parse(string path, string content, Func<string, bool>? opensInclude = null)
|
||||||
{
|
{
|
||||||
string original = content;
|
string original = content;
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ public sealed class SceneryParser
|
|||||||
|
|
||||||
// Read from the text with its optional includes blanked, which keeps every
|
// Read from the text with its optional includes blanked, which keeps every
|
||||||
// place where it was, so a fault's line is the line in the file.
|
// place where it was, so a fault's line is the line in the file.
|
||||||
var syntax = ScenerySyntax.Scan(content, System.IO.Path.GetFileName(path), findInclude);
|
var syntax = ScenerySyntax.Scan(content, System.IO.Path.GetFileName(path), opensInclude);
|
||||||
var faults = syntax.Faults.ToList();
|
var faults = syntax.Faults.ToList();
|
||||||
var inlined = SceneryIncludes.Ranges(content);
|
var inlined = SceneryIncludes.Ranges(content);
|
||||||
|
|
||||||
|
|||||||
@@ -80,10 +80,8 @@ public sealed class SceneryRepository : ISceneryRepository
|
|||||||
// With its own .sbt the scenery's terrain comes from it, and the simulator
|
// With its own .sbt the scenery's terrain comes from it, and the simulator
|
||||||
// passes its terrain includes over without opening them.
|
// passes its terrain includes over without opening them.
|
||||||
bool binaryTerrain = Opens(Path.GetFileNameWithoutExtension(path) + ".sbt");
|
bool binaryTerrain = Opens(Path.GetFileNameWithoutExtension(path) + ".sbt");
|
||||||
IncludeLookup FindInclude(string name) =>
|
bool OpensInclude(string name) =>
|
||||||
Opens(name) || (binaryTerrain && SimulatorNames.Lower(name).Contains("_ter.scm"))
|
Opens(name) || (binaryTerrain && SimulatorNames.Lower(name).Contains("_ter.scm"));
|
||||||
? new IncludeLookup(true)
|
|
||||||
: new IncludeLookup(false, ResolveInclude(name));
|
|
||||||
|
|
||||||
(string File, string Text)? ReadInclude(string name)
|
(string File, string Text)? ReadInclude(string name)
|
||||||
{
|
{
|
||||||
@@ -100,7 +98,7 @@ public sealed class SceneryRepository : ISceneryRepository
|
|||||||
|
|
||||||
string own = LegacyText.Decode(_files.ReadAllBytes(path), out var ownEncoding);
|
string own = LegacyText.Decode(_files.ReadAllBytes(path), out var ownEncoding);
|
||||||
string text = SceneryIncludes.Inline(own, ReadInclude);
|
string text = SceneryIncludes.Inline(own, ReadInclude);
|
||||||
var scenery = _parser.Parse(path, text, FindInclude);
|
var scenery = _parser.Parse(path, text, OpensInclude);
|
||||||
scenery.HasCompanionTimetable = binaryTerrain;
|
scenery.HasCompanionTimetable = binaryTerrain;
|
||||||
scenery.Sources = sources;
|
scenery.Sources = sources;
|
||||||
scenery.TextEncoding = ownEncoding;
|
scenery.TextEncoding = ownEncoding;
|
||||||
@@ -115,11 +113,11 @@ public sealed class SceneryRepository : ISceneryRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the simulator opens a file of the scenery folder named so: by the
|
/// Whether the simulator opens a file of the scenery folder named so: whatever the
|
||||||
/// name in lower case, which on Linux has to be how it is named on disk.
|
/// case of its letters, on Linux too. A shade more lenient than eu07 there, which
|
||||||
|
/// folds only the letters A to Z and of two folders named alike takes the first.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool Opens(string name) =>
|
private bool Opens(string name) => ResolveInclude(name) is not null;
|
||||||
_files.FileExists(Path.Combine(_paths.Scenery, SimulatorNames.Lower(name.Replace('\\', '/'))));
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An include's file as it is named on disk, from the scenery folder, whatever
|
/// An include's file as it is named on disk, from the scenery folder, whatever
|
||||||
|
|||||||
@@ -742,7 +742,6 @@
|
|||||||
<String key="SyntaxVehicleOutsideTrainset">Vozidlo {0} stojí mimo soupravu: chybí záhlaví trainset?</String>
|
<String key="SyntaxVehicleOutsideTrainset">Vozidlo {0} stojí mimo soupravu: chybí záhlaví trainset?</String>
|
||||||
<String key="SyntaxNotANumber">{0}: „{1}“ místo čísla</String>
|
<String key="SyntaxNotANumber">{0}: „{1}“ místo čísla</String>
|
||||||
<String key="SyntaxMissingInclude">Soubor {1} nenalezen (include)</String>
|
<String key="SyntaxMissingInclude">Soubor {1} nenalezen (include)</String>
|
||||||
<String key="SyntaxIncludeLetterCase">Soubor {1} je na disku jako {0}: linuxový eu07 ho nenačte</String>
|
|
||||||
<String key="SyntaxIncludeNotClosed">include {1} bez end</String>
|
<String key="SyntaxIncludeNotClosed">include {1} bez end</String>
|
||||||
<String key="SyntaxTrainsetUnreadable">Soupravu {0} se nepodařilo načíst</String>
|
<String key="SyntaxTrainsetUnreadable">Soupravu {0} se nepodařilo načíst</String>
|
||||||
<String key="SyntaxVehicleUnreadable">Vozidlo {0} se nepodařilo načíst</String>
|
<String key="SyntaxVehicleUnreadable">Vozidlo {0} se nepodařilo načíst</String>
|
||||||
|
|||||||
@@ -772,7 +772,6 @@
|
|||||||
<String key="SyntaxVehicleOutsideTrainset">Vehicle {0} stands outside a trainset: header missing?</String>
|
<String key="SyntaxVehicleOutsideTrainset">Vehicle {0} stands outside a trainset: header missing?</String>
|
||||||
<String key="SyntaxNotANumber">{0}: “{1}” instead of a number</String>
|
<String key="SyntaxNotANumber">{0}: “{1}” instead of a number</String>
|
||||||
<String key="SyntaxMissingInclude">File {1} not found (include)</String>
|
<String key="SyntaxMissingInclude">File {1} not found (include)</String>
|
||||||
<String key="SyntaxIncludeLetterCase">File {1} is on disk as {0}: the Linux eu07 will not load it</String>
|
|
||||||
<String key="SyntaxIncludeNotClosed">include {1} without end</String>
|
<String key="SyntaxIncludeNotClosed">include {1} without end</String>
|
||||||
<String key="SyntaxTrainsetUnreadable">Trainset {0} could not be read</String>
|
<String key="SyntaxTrainsetUnreadable">Trainset {0} could not be read</String>
|
||||||
<String key="SyntaxVehicleUnreadable">Vehicle {0} could not be read</String>
|
<String key="SyntaxVehicleUnreadable">Vehicle {0} could not be read</String>
|
||||||
|
|||||||
@@ -742,7 +742,6 @@
|
|||||||
<String key="SyntaxVehicleOutsideTrainset">A(z) {0} jármű szerelvényen kívül áll: hiányzik a trainset fejléc?</String>
|
<String key="SyntaxVehicleOutsideTrainset">A(z) {0} jármű szerelvényen kívül áll: hiányzik a trainset fejléc?</String>
|
||||||
<String key="SyntaxNotANumber">{0}: „{1}” szám helyett</String>
|
<String key="SyntaxNotANumber">{0}: „{1}” szám helyett</String>
|
||||||
<String key="SyntaxMissingInclude">A(z) {1} fájl nem található (include)</String>
|
<String key="SyntaxMissingInclude">A(z) {1} fájl nem található (include)</String>
|
||||||
<String key="SyntaxIncludeLetterCase">A(z) {1} fájl a lemezen {0} néven van: a linuxos eu07 nem tölti be</String>
|
|
||||||
<String key="SyntaxIncludeNotClosed">include {1} end nélkül</String>
|
<String key="SyntaxIncludeNotClosed">include {1} end nélkül</String>
|
||||||
<String key="SyntaxTrainsetUnreadable">A(z) {0} szerelvényt nem sikerült beolvasni</String>
|
<String key="SyntaxTrainsetUnreadable">A(z) {0} szerelvényt nem sikerült beolvasni</String>
|
||||||
<String key="SyntaxVehicleUnreadable">A(z) {0} járművet nem sikerült beolvasni</String>
|
<String key="SyntaxVehicleUnreadable">A(z) {0} járművet nem sikerült beolvasni</String>
|
||||||
|
|||||||
@@ -769,7 +769,6 @@
|
|||||||
<String key="SyntaxVehicleOutsideTrainset">Pojazd {0} stoi poza składem: brak nagłówka trainset?</String>
|
<String key="SyntaxVehicleOutsideTrainset">Pojazd {0} stoi poza składem: brak nagłówka trainset?</String>
|
||||||
<String key="SyntaxNotANumber">{0}: „{1}” zamiast liczby</String>
|
<String key="SyntaxNotANumber">{0}: „{1}” zamiast liczby</String>
|
||||||
<String key="SyntaxMissingInclude">Brak pliku {1} (include)</String>
|
<String key="SyntaxMissingInclude">Brak pliku {1} (include)</String>
|
||||||
<String key="SyntaxIncludeLetterCase">Plik {1} jest na dysku jako {0}: linuksowy eu07 go nie wczyta</String>
|
|
||||||
<String key="SyntaxIncludeNotClosed">include {1} bez end</String>
|
<String key="SyntaxIncludeNotClosed">include {1} bez end</String>
|
||||||
<String key="SyntaxTrainsetUnreadable">Nie udało się odczytać składu {0}</String>
|
<String key="SyntaxTrainsetUnreadable">Nie udało się odczytać składu {0}</String>
|
||||||
<String key="SyntaxVehicleUnreadable">Nie udało się odczytać pojazdu {0}</String>
|
<String key="SyntaxVehicleUnreadable">Nie udało się odczytać pojazdu {0}</String>
|
||||||
|
|||||||
@@ -742,7 +742,6 @@
|
|||||||
<String key="SyntaxVehicleOutsideTrainset">Транспорт {0} стоит вне состава: нет заголовка trainset?</String>
|
<String key="SyntaxVehicleOutsideTrainset">Транспорт {0} стоит вне состава: нет заголовка trainset?</String>
|
||||||
<String key="SyntaxNotANumber">{0}: «{1}» вместо числа</String>
|
<String key="SyntaxNotANumber">{0}: «{1}» вместо числа</String>
|
||||||
<String key="SyntaxMissingInclude">Файл {1} не найден (include)</String>
|
<String key="SyntaxMissingInclude">Файл {1} не найден (include)</String>
|
||||||
<String key="SyntaxIncludeLetterCase">Файл {1} на диске назван {0}: eu07 на Linux его не загрузит</String>
|
|
||||||
<String key="SyntaxIncludeNotClosed">include {1} без end</String>
|
<String key="SyntaxIncludeNotClosed">include {1} без end</String>
|
||||||
<String key="SyntaxTrainsetUnreadable">Не удалось прочитать состав {0}</String>
|
<String key="SyntaxTrainsetUnreadable">Не удалось прочитать состав {0}</String>
|
||||||
<String key="SyntaxVehicleUnreadable">Не удалось прочитать единицу {0}</String>
|
<String key="SyntaxVehicleUnreadable">Не удалось прочитать единицу {0}</String>
|
||||||
|
|||||||
Reference in New Issue
Block a user