From 003024d282c6b76f6934d3a7e5e4db77680c7f66 Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Sat, 1 Jun 2024 10:12:08 +0300 Subject: [PATCH] 110 glob (#111) * Fixed the glob-handling for virtual files. This pull-request closes #110 by fixing the handling of globs for our virtual files. We've updated to use the single routine for file matching, and fixed the issues that made that broken. --- fcb/fcb.go | 78 +++++++------------------------------------------ fcb/fcb_test.go | 61 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 70 deletions(-) diff --git a/fcb/fcb.go b/fcb/fcb.go index 858b6c4..a654e71 100644 --- a/fcb/fcb.go +++ b/fcb/fcb.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strings" + "unicode" ) // SIZE contains the size of the FCB structure @@ -90,11 +91,13 @@ func (f *FCB) GetType() string { t := "" for _, c := range f.Type { - if c != 0x00 { + if unicode.IsPrint(rune(c)) { t += string(c) + } else { + t += " " } } - return strings.TrimSpace(t) + return t } // AsBytes returns the entry of the FCB in a format suitable @@ -276,10 +279,6 @@ func FromBytes(bytes []uint8) FCB { // DoesMatch returns true if the filename specified matches the pattern in the FCB. func (f *FCB) DoesMatch(name string) bool { - t := string(f.Type[0]) + string(f.Type[1]) + string(f.Type[2]) - if t == "" || t == " " { - t = "???" - } // Having a .extension is fine, but if the // suffix is longer than three characters we're @@ -311,7 +310,7 @@ func (f *FCB) DoesMatch(name string) bool { // Repeat for the suffix. for i, c := range f.Type { - if (t[i] != c) && (t[i] != '?') { + if (tmp.Type[i] != c) && (f.Type[i] != '?') { return false } } @@ -327,11 +326,6 @@ func (f *FCB) DoesMatch(name string) bool { func (f *FCB) GetMatches(prefix string) ([]FCBFind, error) { var ret []FCBFind - t := string(f.Type[0]) + string(f.Type[1]) + string(f.Type[2]) - if t == "" || t == " " { - t = "???" - } - // Find files in the directory files, err := os.ReadDir(prefix) if err != nil { @@ -346,65 +340,15 @@ func (f *FCB) GetMatches(prefix string) ([]FCBFind, error) { continue } - // Create the new record, in case this entry matches. - var ent FCBFind - - // Populate the host-path before we do anything else. - ent.Host = filepath.Join(prefix, file.Name()) - - // Name needs to be upper-cased name := strings.ToUpper(file.Name()) + if f.DoesMatch(name) { - // is the name too long? - if len(name) > 8+3 { - continue - } - - // Having a .extension is fine, but if the - // suffix is longer than three characters we're - // not going to use it. - parts := strings.Split(name, ".") - if len(parts) == 2 { - // filename is over 8 characters - if len(parts[0]) > 8 { - continue - } - // suffix is over 3 characters - if len(parts[1]) > 3 { - continue - } - } - - // Default to included the file, now the basics - // have matched - filename/extension lengths and - // being a non-directory. - include := true - - // OK make an fcb - tmp := FromString(name) - - // Now test if the name we've got matches that in the - // search-pattern: Name. - // - // Either a literal match, or a wildcard match with "?". - for i, c := range tmp.Name { - if (f.Name[i] != c) && (f.Name[i] != '?') { - include = false - } - } - - // Repeat for the suffix. - for i, c := range tmp.Type { - if (t[i] != c) && (t[i] != '?') { - include = false - } - } + var ent FCBFind - // Does it match? Then add the entry, with the - // CP/M visible name. - if include { + // Populate the host-path before we do anything else. + ent.Host = filepath.Join(prefix, file.Name()) - // populate + // populate the name, but note it needs to be upper-cased ent.Name = name // append diff --git a/fcb/fcb_test.go b/fcb/fcb_test.go index 69fd25e..ed29b09 100644 --- a/fcb/fcb_test.go +++ b/fcb/fcb_test.go @@ -5,6 +5,7 @@ import ( "testing" ) +// TestFCBSize ensures our size matches expectations. func TestFCBSize(t *testing.T) { x := FromString("blah") b := x.AsBytes() @@ -70,7 +71,7 @@ func TestFCBFromString(t *testing.T) { if f.GetName() != "FOO" { t.Fatalf("name wrong, got '%v'", f.GetName()) } - if f.GetType() != "" { + if f.GetType() != " " { t.Fatalf("unexpected suffix '%v'", f.GetType()) } @@ -82,7 +83,7 @@ func TestFCBFromString(t *testing.T) { if f.GetName() != "THIS-IS-" { t.Fatalf("name wrong, got '%v'", f.GetName()) } - if f.GetType() != "" { + if f.GetType() != " " { t.Fatalf("unexpected suffix '%v'", f.GetType()) } @@ -99,13 +100,16 @@ func TestFCBFromString(t *testing.T) { } // wildcard - f = FromString("c:steve*") + f = FromString("c:steve*.*") if f.Drive != 2 { t.Fatalf("drive wrong") } if f.GetName() != "STEVE???" { t.Fatalf("name wrong, got '%v'", f.GetName()) } + if f.GetType() != "???" { + t.Fatalf("type wrong, got '%v'", f.GetName()) + } f = FromString("c:test.C*") if f.Drive != 2 { @@ -119,3 +123,54 @@ func TestFCBFromString(t *testing.T) { } } + +func TestDoesMatch(t *testing.T) { + + type testcase struct { + // pattern contains a pattern + pattern string + + // yes contains a list of filenames that should match that pattern + yes []string + + // no contains a list of filenames that should NOT match that pattern + no []string + } + + tests := []testcase{ + { + pattern: "*.com", + yes: []string{"A.COM", "B:FOO.COM"}, + no: []string{"A", "BOB", "C.GO"}, + }, + { + pattern: "A*", + yes: []string{"ANIMAL", "B:AUGUST"}, + no: []string{"ANIMAL.COM", "BOB", "AURORA.COM"}, + }, + { + pattern: "A*.*", + yes: []string{"ANIMAL.com", "B:AUGUST.com", "AURORA"}, + no: []string{"Test", "BOB"}, + }, + } + + for _, test := range tests { + + f := FromString(test.pattern) + + for _, ei := range test.no { + + if f.DoesMatch(ei) { + t.Fatalf("file %s matched pattern %s and it should not have done", ei, test.pattern) + } + } + + for _, joo := range test.yes { + + if !f.DoesMatch(joo) { + t.Fatalf("file %s did not match pattern %s and it should have done", joo, test.pattern) + } + } + } +}