1 #include "Core.h"
2
GetLocalDir()3 String GetLocalDir()
4 {
5 return ConfigFile("UppLocal");
6 }
7
LocalPath(const String & filename)8 String LocalPath(const String& filename)
9 {
10 return AppendFileName(GetLocalDir(), filename);
11 }
12
IgnoreList()13 Vector<String> IgnoreList()
14 {
15 Vector<String> ignore;
16 const Workspace& wspc = GetIdeWorkspace();
17 for(int i = 0; i < wspc.GetCount(); i++) {
18 const Package& pk = wspc.GetPackage(i);
19 for(int j = 0; j < pk.GetCount(); j++)
20 if(!pk[j].separator && pk[j] == "ignorelist") {
21 FileIn in(SourcePath(wspc[i], pk[j]));
22 while(in && !in.IsEof()) {
23 String s = in.GetLine();
24 if(!s.IsEmpty())
25 ignore.Add(s);
26 }
27 }
28 }
29 return ignore;
30 }
31
FollowCygwinSymlink(const String & file)32 String FollowCygwinSymlink(const String& file) {
33 for(String fn = file;;) {
34 if(fn.IsEmpty())
35 return fn;
36 FileIn fi(fn);
37 if(!fi.IsOpen())
38 return fn;
39 char buffer[10];
40 if(!fi.GetAll(buffer, 10) || memcmp(buffer, "!<symlink>", 10))
41 return fn;
42 fn = NormalizePath(LoadStream(fi), GetFileDirectory(fn));
43 }
44 }
45
SplitDirs(const char * s)46 Vector<String> SplitDirs(const char *s) {
47 return Split(s, ';');
48 }
49
50 static String varsname = "default";
51
GetVarsName()52 String GetVarsName()
53 {
54 return varsname;
55 }
56
VarFilePath(String name)57 String VarFilePath(String name) {
58 return ConfigFile(name + ".var");
59 }
60
VarFilePath()61 String VarFilePath() {
62 String p = varsname;
63 if(IsFullPath(varsname))
64 return varsname;
65 return VarFilePath(GetVarsName());
66 }
67
SaveVarFile(const char * filename,const VectorMap<String,String> & var)68 bool SaveVarFile(const char *filename, const VectorMap<String, String>& var)
69 {
70 FileOut out(filename);
71 for(int i = 0; i < var.GetCount(); i++)
72 out << var.GetKey(i) << " = " << AsCString(var[i]) << ";\n";
73 out.Close();
74 return !out.IsError();
75 }
76
LoadVarFile(const char * name,VectorMap<String,String> & _var)77 bool LoadVarFile(const char *name, VectorMap<String, String>& _var)
78 {
79 try {
80 VectorMap<String, String> var;
81 String env = LoadFile(name);
82 try {
83 CParser p(env);
84 while(!p.IsEof()) {
85 String v = p.ReadId();
86 p.Char('=');
87 if(p.IsString())
88 var.GetAdd(v) = p.ReadString();
89 else {
90 String ln;
91 while(p.PeekChar() != '\r' && p.PeekChar() != '\n' && p.PeekChar() != ';')
92 ln.Cat(p.GetChar());
93 var.GetAdd(v) = ln;
94 p.Spaces();
95 }
96 p.Char(';');
97 }
98 }
99 catch(CParser::Error) {}
100 _var = pick(var);
101 return true;
102 }
103 catch(...) {
104 return false;
105 }
106 }
107
Save(const char * path)108 bool Nest::Save(const char *path)
109 {
110 return SaveVarFile(path, var);
111 }
112
Load(const char * path)113 bool Nest::Load(const char *path)
114 {
115 InvalidatePackageCache();
116 return LoadVarFile(path, var);
117 }
118
Get(const String & id)119 String Nest::Get(const String& id)
120 {
121 return var.Get(id, String());
122 }
123
Set(const String & id,const String & val)124 void Nest::Set(const String& id, const String& val)
125 {
126 var.GetAdd(id) = val;
127 InvalidatePackageCache();
128 }
129
PackagePath0(const String & name)130 String Nest::PackagePath0(const String& name)
131 {
132 String uppfile = NativePath(name);
133 if(IsFullPath(uppfile)) return NormalizePath(uppfile);
134 Vector<String> d = GetUppDirs();
135 String p;
136 for(int i = 0; i < d.GetCount(); i++) {
137 p = NormalizePath(AppendFileName(AppendFileName(d[i], uppfile),
138 GetFileName(uppfile)) + ".upp");
139 if(FileExists(p)) return p;
140 }
141 return d.GetCount() ? NormalizePath(AppendFileName(AppendFileName(d[0], uppfile),
142 GetFileName(uppfile)) + ".upp") : "";
143 }
144
InvalidatePackageCache()145 void Nest::InvalidatePackageCache()
146 {
147 package_cache.Clear();
148 }
149
PackagePath(const String & name)150 String Nest::PackagePath(const String& name)
151 {
152 int q = package_cache.Find(name);
153 if(q < 0) {
154 String h = PackagePath0(name);
155 package_cache.Add(name, h);
156 return h;
157 }
158 return package_cache[q];
159 }
160
MainNest()161 Nest& MainNest()
162 {
163 return Single<Nest>();
164 }
165
SaveVars(const char * name)166 bool SaveVars(const char *name)
167 {
168 if(!MainNest().Save(VarFilePath(name)))
169 return false;
170 varsname = name;
171 return true;
172 }
173
LoadVars(const char * name)174 bool LoadVars(const char *name) {
175 varsname = (name && *name ? name : "default");
176 return MainNest().Load(VarFilePath());
177 }
178
GetVar(const String & var)179 String GetVar(const String& var) {
180 return MainNest().Get(var);
181 }
182
SetVar(const String & var,const String & val,bool save)183 void SetVar(const String& var, const String& val, bool save) {
184 MainNest().Set(var, val);
185 if(save)
186 SaveVars(GetVarsName());
187 }
188
GetUppDirs()189 Vector<String> GetUppDirs() {
190 return SplitDirs(GetVar("UPP"));
191 }
192
GetUppDir()193 String GetUppDir() {
194 Vector<String> s = GetUppDirs();
195 #ifdef PLATFORM_WIN32
196 return s.GetCount() == 0 ? GetFileFolder(GetExeFilePath()) : s[0];
197 #endif
198 #ifdef PLATFORM_POSIX
199 return s.GetCount() == 0 ? GetHomeDirectory() : s[0];
200 #endif
201 }
202
IsCSourceFile(const char * path)203 bool IsCSourceFile(const char *path)
204 {
205 String ext = ToLower(GetFileExt(path));
206 return ext == ".cpp" || ext == ".c" || ext == ".cc" || ext == ".cxx"
207 || ext == ".m" || ext == ".mm" || ext == ".icpp";
208 }
209
IsCHeaderFile(const char * path)210 bool IsCHeaderFile(const char *path)
211 {
212 String ext = ToLower(GetFileExt(path));
213 return ext == ".h" || ext == ".hpp" || ext == ".hh" || ext == ".hxx";
214 }
215
IsFullDirectory(const String & d)216 bool IsFullDirectory(const String& d) {
217 if(IsFullPath(d)) {
218 FindFile ff(d);
219 if(ff) return ff.IsDirectory();
220 }
221 return false;
222 }
223
IsFolder(const String & path)224 bool IsFolder(const String& path)
225 {
226 if(IsNull(path) || *path.Last() == '\\' || *path.Last() == '/' || *path.Last() == ':')
227 return true;
228 if(path.Find('?') >= 0 || path.Find('*') >= 0)
229 return false;
230 FindFile ff(path);
231 return ff && ff.IsDirectory();
232 }
233
InvalidatePackageCache()234 void InvalidatePackageCache()
235 {
236 MainNest().InvalidatePackageCache();
237 }
238
PackagePath(const String & name)239 String PackagePath(const String& name)
240 {
241 return MainNest().PackagePath(name);
242 }
243
GetPackagePathNest(const String & path)244 String GetPackagePathNest(const String& path)
245 {
246 String h = UnixPath(NormalizePath(path));
247 for(auto dir : GetUppDirs())
248 if(h.StartsWith(UnixPath(NormalizePath(dir)) + '/'))
249 return dir;
250 return Null;
251 }
252
SourcePath(const String & package,const String & file)253 String SourcePath(const String& package, const String& file) {
254 if(IsFullPath(file)) return NativePath(file);
255 return NormalizePath(AppendFileName(GetFileFolder(PackagePath(package)), file));
256 }
257
IsNestReadOnly(const String & path)258 bool IsNestReadOnly(const String& path)
259 {
260 Vector<String> d = GetUppDirs();
261 for(int i = 0; i < d.GetCount(); i++)
262 if(path.StartsWith(d[i]) && FileExists(AppendFileName(d[i], "readonly")))
263 return true;
264 return false;
265 }
266
GetAnyFileName(const char * path)267 String GetAnyFileName(const char *path)
268 {
269 const char *p = path;
270 for(char c; (c = *path++) != 0;)
271 if(c == '\\' || c == '/' || c == ':')
272 p = path;
273 return p;
274 }
275
GetAnyFileTitle(const char * path)276 String GetAnyFileTitle(const char *path)
277 {
278 String fn = GetAnyFileName(path);
279 const char *p = fn;
280 const char *e = p;
281 while(*e && *e != '.')
282 e++;
283 return String(p, e);
284 }
285
CatAnyPath(String path,const char * more)286 String CatAnyPath(String path, const char *more)
287 {
288 if(!more || !*more)
289 return path;
290 if(!path.IsEmpty() && *path.Last() != '\\' && *path.Last() != '/' &&
291 *more != '\\' && *more != '/')
292 #ifdef PLATFORM_WIN32
293 path.Cat('\\');
294 #else
295 path.Cat('/');
296 #endif
297 path.Cat(more);
298 return path;
299 }
300
301
SplitHostName(const char * hostname,String & host,int & port)302 void SplitHostName(const char *hostname, String& host, int& port) {
303 enum { DEFAULT_REMOTE_PORT = 2346 };
304 const char *p = hostname;
305 while(p && *p != ':')
306 p++;
307 host = String(hostname, p);
308 if(*p++ == ':' && IsDigit(*p))
309 port = stou(p);
310 else
311 port = DEFAULT_REMOTE_PORT;
312 }
313
SplitFlags0(const char * flags)314 Vector<String> SplitFlags0(const char *flags) {
315 return Split(flags, CharFilterWhitespace);
316 }
317
SplitFlags(const char * flags,bool main,const Vector<String> & accepts)318 Vector<String> SplitFlags(const char *flags, bool main, const Vector<String>& accepts)
319 {
320 Vector<String> v = SplitFlags0(flags);
321 Vector<String> h;
322 for(int i = 0; i < v.GetCount(); i++)
323 if(v[i][0] == '.') {
324 String f = v[i].Mid(1);
325 if(main || FindIndex(accepts, f) >= 0)
326 h.Add(v[i].Mid(1));
327 }
328 else
329 h.Add(v[i]);
330 if(main)
331 h.Add("MAIN");
332 return h;
333 }
334
SplitFlags(const char * flags,bool main)335 Vector<String> SplitFlags(const char *flags, bool main)
336 {
337 Vector<String> dummy;
338 return SplitFlags(flags, main, dummy);
339 }
340
HasFlag(const Vector<String> & conf,const char * flag)341 bool HasFlag(const Vector<String>& conf, const char *flag) {
342 return FindIndex(conf, flag) >= 0;
343 }
344
Combine(const Vector<String> & conf,const char * flags)345 Vector<String> Combine(const Vector<String>& conf, const char *flags) {
346 Vector<String> cfg(conf, 1);
347 try {
348 CParser p(flags);
349 while(!p.IsEof()) {
350 bool isnot = p.Char('!');
351 if(!p.IsId()) break;
352 String flg = p.ReadId();
353 int i = FindIndex(cfg, flg);
354 if(isnot) {
355 if(i >= 0) cfg.Remove(i);
356 }
357 else
358 if(i < 0) cfg.Add(flg);
359 }
360 }
361 catch(CParser::Error) {}
362 return cfg;
363 }
364
Gather(const Array<OptItem> & set,const Vector<String> & conf,bool nospace)365 String Gather(const Array<OptItem>& set, const Vector<String>& conf, bool nospace) {
366 String s;
367 for(int i = 0; i < set.GetCount(); i++)
368 if(MatchWhen(set[i].when, conf)) {
369 if(!nospace && !s.IsEmpty()) s.Cat(' ');
370 s.Cat(set[i].text);
371 }
372 return s;
373 }
374
GetType(const Vector<String> & conf,const char * flags)375 int GetType(const Vector<String>& conf, const char *flags) {
376 Vector<String> f = SplitFlags(flags);
377 int q = FLAG_UNDEFINED;
378 for(int i = 0; i < f.GetCount(); i++)
379 if(HasFlag(conf, f[i])) {
380 if(q == FLAG_UNDEFINED)
381 q = i;
382 else
383 q = FLAG_MISMATCH;
384 }
385 return q;
386 }
387
RemoveType(Vector<String> & conf,const char * flags)388 String RemoveType(Vector<String>& conf, const char *flags)
389 {
390 String old;
391 Index<String> f(SplitFlags(flags));
392 for(int i = conf.GetCount(); --i >= 0;)
393 if(f.Find(conf[i]) >= 0)
394 {
395 old = conf[i];
396 conf.Remove(i);
397 }
398 return old;
399 }
400
GetType(const Vector<String> & conf,const char * flags,int def)401 int GetType(const Vector<String>& conf, const char *flags, int def) {
402 int q = GetType(conf, flags);
403 return q == FLAG_UNDEFINED ? def : q;
404 }
405
GetFlag(const Vector<String> & conf,const char * flag)406 bool GetFlag(const Vector<String>& conf, const char *flag) {
407 return FindIndex(conf, flag) >= 0;
408 }
409
AddLoad(const String & name,bool match,const Vector<String> & flag)410 void Workspace::AddLoad(const String& name, bool match, const Vector<String>& flag)
411 {
412 package.Add(name).Load(PackagePath(name));
413 }
414
AddUses(Package & p,bool match,const Vector<String> & flag)415 void Workspace::AddUses(Package& p, bool match, const Vector<String>& flag)
416 {
417 int q = package.GetCount();
418 for(int i = 0; i < p.uses.GetCount(); i++) {
419 String uses = UnixPath(p.uses[i].text);
420 if((!match || MatchWhen(p.uses[i].when, flag)) && package.Find(uses) < 0)
421 AddLoad(uses, match, flag);
422 }
423 for(int i = q; i < package.GetCount(); i++)
424 AddUses(package[i], match, flag);
425 }
426
Scan(const char * prjname)427 void Workspace::Scan(const char *prjname) {
428 package.Clear();
429 AddLoad(prjname, false, Vector<String>());
430 AddUses(package[0], false, Vector<String>());
431 }
432
Scan(const char * prjname,const Vector<String> & flag)433 void Workspace::Scan(const char *prjname, const Vector<String>& flag) {
434 package.Clear();
435 AddLoad(prjname, true, flag);
436 AddUses(package[0], true, flag);
437 }
438
Dump()439 void Workspace::Dump() {
440 for(int i = 0; i < package.GetCount(); i++) {
441 Package& prj = package[i];
442 LOG("Package " << package.GetKey(i));
443 LOG(" file ");
444 for(int i = 0; i < prj.file.GetCount(); i++)
445 LOG("\t" << prj.file[i]);
446 }
447 }
448
GetAllAccepts(int pk) const449 Vector<String> Workspace::GetAllAccepts(int pk) const
450 {
451 Index<String> accepts;
452 Index<int> pkg;
453 pkg.Add(pk);
454 for(int i = 0; i < pkg.GetCount(); i++) {
455 const Package& p = package[pkg[i]];
456 FindAppend(accepts, p.accepts);
457 for(int u = 0; u < p.uses.GetCount(); u++) {
458 int f = package.Find(UnixPath(p.uses[u].text));
459 if(f >= 0)
460 pkg.FindAdd(f);
461 }
462 }
463 return accepts.PickKeys();
464 }
465