1 // =================================
  2 // Copyright (c) 2022 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Collections;
  8 using System.IO;
  9 using System.RegularExpressions;
 10 using System.Os;
 11 
 12 namespace paths
 13 {
 14     public List<FileType> GetFileTypes(const List<string>& filesbool recursive)
 15     {
 16         List<FileType> fileTypes;
 17         for (const string& file : files)
 18         {
 19             FileStatus status;
 20             Stat(file.Chars()status);
 21             if (status.fileType == FileType.directory)
 22             {
 23                 if (!recursive)
 24                 {
 25                     throw Exception("'" + file + "' is directory and not --recursive specified");
 26                 }
 27             }
 28             else if (status.fileType != FileType.regular)
 29             {
 30                 throw Exception("'" + file + "' not regular or directory");
 31             }
 32             fileTypes.Add(status.fileType);
 33         }
 34         return fileTypes;
 35     }
 36 
 37     public bool ContainsPatternChar(const ustring& str)
 38     {
 39         for (uchar c : str)
 40         {
 41             if (c == '*' || c == '?' || c == '[') return true;
 42         }
 43         return false;
 44     }
 45 
 46     public List<string> GetMatchingNames(const List<string>& namesconst ustring& patternContext& context)
 47     {
 48         List<string> matchingNames;
 49         Nfa nfa = CompileFilePattern(contextpattern);
 50         for (const string& name : names)
 51         {
 52             ustring nm = ToUtf32(name);
 53             if (PatternMatch(nmnfa))
 54             {
 55                 matchingNames.Add(name);
 56             }
 57         }
 58         return matchingNames;
 59     }
 60 
 61     public List<string> Expand(const List<string>& pathNames)
 62     {
 63         Context context;
 64         List<string> expanded;
 65         for (const string& pathName : pathNames)
 66         {
 67             List<string> components = pathName.Split('/');
 68             List<string> paths = Combine(string()componentscontext);
 69             for (const string& path : paths)
 70             {
 71                 expanded.Add(path);
 72             }
 73         }
 74         return expanded;
 75     }
 76 
 77     public List<string> Combine(const string& prefixconst List<string>& componentsContext& context)
 78     {
 79         List<string> allCombinations;
 80         string pre = prefix;
 81         bool expanded = false;
 82         long n = components.Count();
 83         for (long i = 0; i < n; ++i;)
 84         {
 85             if (prefix.IsEmpty() && i == 0 && components[i].IsEmpty())
 86             {
 87                 pre.Append('/');
 88             }
 89             else
 90             {
 91                 ustring comp = ToUtf32(components[i]);
 92                 if (ContainsPatternChar(comp))
 93                 {
 94                     List<string> prefixes = Expand(precompcontext);
 95                     List<string> suffix;
 96                     for (long j = i + 1; j < n; ++j;)
 97                     {
 98                         suffix.Add(components[j]);
 99                     }
100                     for (const string& prefix : prefixes)
101                     {
102                         List<string> combinations = Combine(prefixsuffixcontext);
103                         for (const string& c : combinations)
104                         {
105                             allCombinations.Add(c);
106                         }
107                     }
108                     expanded = true;
109                 }
110                 else if (pre.IsEmpty() || pre[pre.Length() - 1] == '/')
111                 {
112                     pre.Append(components[i]);
113                 }
114                 else
115                 {
116                     pre.Append('/').Append(components[i]);
117                 }
118             }
119         }
120         if (!expanded)
121         {
122             allCombinations.Add(pre);
123         }
124         return allCombinations;
125     }
126 
127     public List<string> Expand(const string& prefixconst ustring& patternContext& context)
128     {
129         string dirPath = prefix;
130         if (dirPath.IsEmpty())
131         {
132             dirPath = ".";
133         }
134         List<string> names;
135         DirectoryEntry entry;
136         DirectoryReader reader(dirPath);
137         while (reader.Read(entry))
138         {
139             if (entry.IsDot() || entry.IsDotDot())
140             {
141                 continue;
142             }
143             names.Add(entry.name);
144         }
145         List<string> matchingNames = GetMatchingNames(namespatterncontext);
146         Sort(matchingNames);
147         List<string> expanded;
148         for (const string& name : matchingNames)
149         {
150             if (prefix.IsEmpty())
151             {
152                 expanded.Add(name);
153             }
154             else
155             {
156                 expanded.Add(Path.Combine(prefixname));
157             }
158         }
159         return expanded;
160     }
161 }