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