Subversion Repositories spk

Rev

Rev 344 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 344 Rev 345
Line 3... Line 3...
3
#include "WString.h"
3
#include "WString.h"
4
#include "WStringList.h"
4
#include "WStringList.h"
5
#include "../File_IO.h"
5
#include "../File_IO.h"
6
#include "../DirIO.h"
6
#include "../DirIO.h"
7
 
7
 
8
#include <set>
8
#include <bitset>
-
 
9
#include <cwctype>
-
 
10
#include <filesystem>
9
 
11
 
10
#ifdef _WIN32
12
#ifdef _WIN32
11
#include <windows.h>
13
#include <windows.h>
12
#include <direct.h>
14
#include <direct.h>
13
#include <shlobj.h>
15
#include <shlobj.h>
14
#else
16
#else
15
#include <dirent.h> 
17
#include <dirent.h>
16
#include <sys/types.h> 
18
#include <sys/types.h>
17
#include <sys/param.h> 
19
#include <sys/param.h>
18
#include <sys/stat.h> 
20
#include <sys/stat.h>
19
#include <unistd.h> 
21
#include <unistd.h>
-
 
22
#include <cstdlib>
20
#endif
23
#endif
21
 
24
 
22
namespace Utils
25
namespace Utils
23
{
26
{
-
 
27
	namespace fs = std::filesystem;
-
 
28
 
24
	class CommandLine
29
	class CommandLine
25
	{
30
	{
26
	private:
31
	private:
27
		std::shared_ptr<CFileIO> _file;
32
		std::shared_ptr<CFileIO> _file;
28
		Utils::WStringList		_options;
33
		Utils::WStringList		_options;
29
		CDirIO 					_myDoc;
34
		CDirIO 					_myDoc;
30
		CDirIO 					_tempDir;
35
		CDirIO 					_tempDir;
31
		std::vector<Utils::WString> _args;
36
		std::vector<Utils::WString> _args;
32
		std::set<unsigned char> _flags;
37
		std::bitset<256>		_flags{};
33
		CPackages				_p;
38
		CPackages				_p;
34
 
39
 
35
	public:
40
	public:
36
		CommandLine(int argc, char* argv[], bool doFlags = false)
41
		explicit CommandLine(int argc, char* argv[], bool doFlags = false)
37
		{
42
		{
38
			_file = std::make_shared<CFileIO>(argv[0]);
43
			_file = std::make_shared<CFileIO>(argv[0]);
39
 
44
 
40
			for (int i = 1; i < argc; i++)
45
			for (int i = 1; i < argc; ++i)
41
			{
46
			{
42
				Utils::WString arg(argv[i]);
47
				Utils::WString arg(argv[i]);
43
				doCommandLine(arg, doFlags);
48
				doCommandLine(std::move(arg), doFlags);
44
			}
49
			}
45
 
50
 
46
			finaliseCommandLine();
51
			finaliseCommandLine();
47
		}
52
		}
-
 
53
 
48
		CommandLine(int argc, wchar_t* argv[], bool doFlags = false)
54
		explicit CommandLine(int argc, wchar_t* argv[], bool doFlags = false)
49
		{
55
		{
50
			_file = std::make_shared<CFileIO>(argv[0]);
56
			_file = std::make_shared<CFileIO>(argv[0]);
51
 
57
 
52
			for (int i = 1; i < argc; i++)
58
			for (int i = 1; i < argc; ++i)
53
			{
59
			{
54
				Utils::WString arg(argv[i]);
60
				Utils::WString arg(argv[i]);
55
				doCommandLine(arg, doFlags);
61
				doCommandLine(std::move(arg), doFlags);
56
			}
62
			}
57
 
63
 
58
			finaliseCommandLine();
64
			finaliseCommandLine();
59
		}
65
		}
60
 
66
 
61
		const std::shared_ptr<CFileIO> file() const
67
		const std::shared_ptr<CFileIO>& file() const noexcept
62
		{
68
		{
63
			return _file;
69
			return _file;
64
		}
70
		}
65
 
71
 
66
		const Utils::WString& cmdName() const
72
		const Utils::WString& cmdName() const noexcept
67
		{
73
		{
68
			return _file->filename();
74
			return _file->filename();
69
		}
75
		}
70
 
76
 
71
		const Utils::WString& cmdDir() const
77
		const Utils::WString& cmdDir() const noexcept
72
		{
78
		{
73
			return _file->dir();
79
			return _file->dir();
74
		}
80
		}
75
 
81
 
76
		const Utils::WString& tempDir() const
82
		const Utils::WString& tempDir() const noexcept
77
		{
83
		{
78
			return _tempDir.dir();
84
			return _tempDir.dir();
79
		}
85
		}
80
 
86
 
81
		const Utils::WString& myDoc() const
87
		const Utils::WString& myDoc() const noexcept
82
		{
88
		{
83
			return _myDoc.dir();
89
			return _myDoc.dir();
84
		}
90
		}
85
 
91
 
86
		const Utils::WStringList options() const
92
		const Utils::WStringList& options() const noexcept
87
		{
93
		{
88
			return _options;
94
			return _options;
89
		}
95
		}
90
 
96
 
91
		const std::vector<Utils::WString>& args() const
97
		const std::vector<Utils::WString>& args() const noexcept
92
		{
98
		{
93
			return _args;
99
			return _args;
94
		}
100
		}
95
 
101
 
96
		size_t argCount() const
102
		size_t argCount() const noexcept
97
		{
103
		{
98
			return _args.size();
104
			return _args.size();
99
		}
105
		}
100
 
106
 
101
		Utils::WString arg(size_t i) const
107
		Utils::WString arg(size_t i) const
102
		{
108
		{
103
			if(i >= _args.size())
109
			if (i >= _args.size())
104
				return Utils::WString::Null();
110
				return Utils::WString::Null();
105
			return _args[i];
111
			return _args[i];
106
		}
112
		}
107
 
113
 
108
		bool hasSwitch(const Utils::WString& s) const
114
		bool hasSwitch(const Utils::WString& s) const noexcept
109
		{
115
		{
110
			return _options.contains(s);
116
			return _options.contains(s);
111
		}
117
		}
-
 
118
 
112
		bool hasFlag(unsigned char s) const
119
		bool hasFlag(unsigned char s) const noexcept
113
		{
120
		{
114
			return _flags.find(s) != _flags.end();
121
			return _flags.test(s);
115
		}
122
		}
116
 
123
 
117
		Utils::WString switchData(const Utils::WString& s) const
124
		Utils::WString switchData(const Utils::WString& s, const Utils::WString& defaultValue = Utils::WString::Null()) const
118
		{
125
		{
119
			if (_options.contains(s))
126
			if (_options.contains(s))
120
				return _options[s]->data;
127
				return _options[s]->data;
121
			return Utils::WString::Null();
128
			return defaultValue;
122
		}
129
		}
123
 
130
 
124
		const CPackages& packages() const
131
		const CPackages& packages() const noexcept
125
		{
132
		{
126
			return _p;
133
			return _p;
127
		}
134
		}
128
 
135
 
129
		CPackages& packages()
136
		CPackages& packages() noexcept
130
		{
137
		{
131
			return _p;
138
			return _p;
132
		}
139
		}
133
 
140
 
134
		const CDirIO& dirIO() const
141
		const CDirIO& dirIO() const noexcept
135
		{
142
		{
136
			return _file->dirIO();
143
			return _file->dirIO();
137
		}
144
		}
138
 
145
 
139
		Utils::WString fullFilename(const Utils::WString& s) const
146
		Utils::WString fullFilename(const Utils::WString& s) const
140
		{
147
		{
-
 
148
			// Keep simple cross-platform detection: recognize drive/protocols and path separators.
-
 
149
			if (s.contains(L":") || s.contains(L"/") || s.contains(L"\\"))
-
 
150
				return s;
141
			return (s.contains(L":")) ? s : _file->dirIO().file(s);
151
			return _file->dirIO().file(s);
142
		}
152
		}
143
 
153
 
144
	private:
154
	private:
145
		void doCommandLine(Utils::WString& arg, bool doFlags)
155
		void doCommandLine(Utils::WString arg, bool doFlags)
146
		{
156
		{
147
			if (arg.startsWith(L"--"))
157
			if (arg.startsWith(L"--"))
148
			{
158
			{
149
				arg = arg.substr(2);
159
				arg = arg.substr(2);
150
 
160
 
Line 153... Line 163...
153
					Utils::WString a = arg.token(L":", 1);
163
					Utils::WString a = arg.token(L":", 1);
154
					Utils::WString b = arg.tokens(L":", 2);
164
					Utils::WString b = arg.tokens(L":", 2);
155
					_options.pushBack(a, b);
165
					_options.pushBack(a, b);
156
				}
166
				}
157
				else
167
				else
-
 
168
				{
158
					_options.pushBack(arg);
169
					_options.pushBack(arg);
-
 
170
				}
159
			}
171
			}
160
			else
172
			else
161
			{
173
			{
162
				if (doFlags)
174
				if (doFlags)
163
				{
175
				{
164
					if (arg.startsWith(L"-") && !arg.startsWith(L"--"))
176
					if (arg.startsWith(L"-") && !arg.startsWith(L"--"))
165
					{
177
					{
166
						Utils::WString flags = arg.substr(1);
178
						Utils::WString flags = arg.substr(1);
167
						for (size_t is = 0; is < flags.length(); is++)
179
						for (size_t is = 0; is < flags.length(); ++is)
168
						{
180
						{
169
							unsigned char flag = std::toupper(flags[static_cast<int>(is)]);
181
							wchar_t ch = flags[static_cast<int>(is)];
170
							if (flag >= 'a' && flag <= 'z')
-
 
171
								flag -= 32; // convert to uppercase
182
							wchar_t upper = std::towupper(ch);
-
 
183
 
172
							if (flag >= 'A' && flag <= 'Z')
184
							if (upper >= L'A' && upper <= L'Z')
173
							{
185
							{
174
								if (_flags.size() < 256)
186
								unsigned char idx = static_cast<unsigned char>(upper & 0xFF);
175
									_flags.insert(flag);
187
								_flags.set(idx);
176
								else
-
 
177
									wprintf(L"Warning: Too many flags, ignoring %c\n", flag);
-
 
178
							}
188
							}
179
						}
189
						}
180
						return;
190
						return;
181
					}
191
					}
182
				}
192
				}
Line 184... Line 194...
184
			}
194
			}
185
		}
195
		}
186
 
196
 
187
		void finaliseCommandLine()
197
		void finaliseCommandLine()
188
		{
198
		{
-
 
199
			// Ensure command directory is a usable path; prefer std::filesystem current_path.
-
 
200
			const Utils::WString fileDir = _file->dir();
-
 
201
			bool looksLikePath = (!fileDir.empty() && (fileDir.contains(L"/") || fileDir.contains(L"\\") || fileDir.contains(L":")));
189
			if (_file->dir().empty() || !_file->dir().contains("/"))
202
			if (_file->dir().empty() || !looksLikePath)
190
			{
203
			{
191
				Utils::WString d;
204
				Utils::WString d;
-
 
205
				try
-
 
206
				{
-
 
207
					fs::path cwd = fs::current_path();
192
#ifdef _WIN32
208
#ifdef _WIN32
193
				d = Utils::WString(_getcwd(NULL, 0));
209
					d = Utils::WString(cwd.wstring().c_str());
194
#else
210
#else
195
				d = Utils::WString(getcwd(NULL, 0));
211
					d = Utils::WString(cwd.string().c_str());
196
#endif
212
#endif
-
 
213
				}
-
 
214
				catch (...)
-
 
215
				{
-
 
216
					// fallback
-
 
217
#ifdef _WIN32
-
 
218
					d = Utils::WString(_getcwd(NULL, 0));
-
 
219
#else
-
 
220
					d = Utils::WString(getcwd(NULL, 0));
-
 
221
#endif
-
 
222
				}
-
 
223
 
197
				if (d.empty())
224
				if (d.empty())
198
					d = L"./";
225
					d = L"./";
199
				_file->setDir(d);
226
				_file->setDir(d);
200
			}
227
			}
201
 
228
 
-
 
229
			// my documents
202
			Utils::WString myDoc = L".";
230
			Utils::WString myDoc = L".";
-
 
231
 
203
#ifdef _WIN32
232
#ifdef _WIN32
204
			TCHAR pszPath[MAX_PATH];
233
			TCHAR pszPath[MAX_PATH];
205
			if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, pszPath)))
234
			if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, pszPath)))
206
			{
235
			{
207
				myDoc = pszPath;
236
				myDoc = pszPath;
208
			}
237
			}
-
 
238
#else
-
 
239
			// on POSIX try HOME, else leave '.',
-
 
240
			const char* home = std::getenv("HOME");
-
 
241
			if (home && *home)
-
 
242
			{
-
 
243
				myDoc = Utils::WString(home);
-
 
244
			}
209
#endif
245
#endif
210
			_myDoc.setDir(myDoc);
246
			_myDoc.setDir(myDoc);
211
			_tempDir.setDir(L".");
-
 
212
 
247
 
-
 
248
			// temp dir via filesystem (fallbacks included)
-
 
249
			Utils::WString tmp = L".";
-
 
250
			try
-
 
251
			{
-
 
252
				fs::path t = fs::temp_directory_path();
213
#ifdef _WIN32
253
#ifdef _WIN32
214
			TCHAR szPath[MAX_PATH + 1];
-
 
215
			DWORD result = GetTempPath(MAX_PATH + 1, szPath);
254
				tmp = Utils::WString(t.wstring().c_str());
216
			if (result > 0)
255
#else
217
				_tempDir.setDir(szPath);
256
				tmp = Utils::WString(t.string().c_str());
218
#endif
257
#endif
-
 
258
			}
-
 
259
			catch (...)
-
 
260
			{
-
 
261
#ifdef _WIN32
-
 
262
				TCHAR szPath[MAX_PATH + 1];
-
 
263
				DWORD result = GetTempPath(MAX_PATH + 1, szPath);
-
 
264
				if (result > 0)
-
 
265
					tmp = Utils::WString(szPath);
-
 
266
#else
-
 
267
				// leave as "."
-
 
268
#endif
-
 
269
			}
-
 
270
			_tempDir.setDir(tmp);
219
 
271
 
220
			_p.startup(L".", _tempDir.dir(), _myDoc.dir());
272
			_p.startup(L".", _tempDir.dir(), _myDoc.dir());
221
		}
273
		}
222
	};
274
	};
223
}
275
}
224
276