1
2
3
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>& files, bool 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>& names, const ustring& pattern, Context& context)
47 {
48 List<string> matchingNames;
49 Nfa nfa = CompileFilePattern(context, pattern);
50 for (const string& name : names)
51 {
52 ustring nm = ToUtf32(name);
53 if (PatternMatch(nm, nfa))
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(), components, context);
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& prefix, const List<string>& components, Context& 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(pre, comp, context);
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(prefix, suffix, context);
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& prefix, const ustring& pattern, Context& 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(names, pattern, context);
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(prefix, name));
157 }
158 }
159 return expanded;
160 }
161 }