ecere/sys/ECON: Fixed ECON parsing bug with : inside string
[sdk] / ecere / src / sys / System.ec
1 namespace sys;
2
3 #define _Noreturn
4
5 #if defined(ECERE_BOOTSTRAP)
6 #undef __WIN32__
7 #undef __unix__
8 #undef __APPLE__
9 #endif
10
11 default:
12 #define uint _uint
13 #define set _set
14
15 #if defined(__WIN32__)
16
17 #define WIN32_LEAN_AND_MEAN
18 #define UNICODE
19 #define GetFreeSpace _GetFreeSpace
20 #define String String_
21 #include <windows.h>
22 #undef String
23 #undef GetFreeSpace
24
25 #elif defined(__unix__) || defined(__APPLE__)
26
27 #include <sys/time.h>
28 #include <unistd.h>
29
30 #endif
31
32 #undef __BLOCKS__
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #undef uint
37 #undef set
38
39 import "Array"
40 import "i18n"
41 import "File"
42 import "TempFile"
43 import "memory"
44
45 default:
46 FILE *eC_stdout(void);
47 FILE *eC_stderr(void);
48
49 // IMPLEMENTED IN _System.c
50 bool System_MoveFile(const char * source, const char * dest, uint replaceAndFlush);
51 bool System_RenameFile(const char * oldName, const char * newName);
52 bool System_DeleteFile(const char * fileName);
53 bool System_MakeDir(const char * path);
54 bool System_RemoveDir(const char * path);
55 char * System_GetWorkingDir(char * buf, int size);
56 bool System_ChangeWorkingDir(const char * buf);
57 char * System_GetEnvironment(const char * envName, char * envValue, int max);
58 void System_SetEnvironment(const char * envName, const char * envValue);
59 void System_UnsetEnvironment(const char * envName);
60 bool System_Execute(const char * env, const char * command, va_list args, bool wait);
61 bool System_ShellOpen(const char * fileName, va_list args);
62 void System_GetFreeSpace(const char * path, FileSize64 * size);
63
64 private:
65
66 #if !defined(ECERE_BOOTSTRAP)
67 import "units"
68 import "Time"
69 //#if !defined(__EMSCRIPTEN__)
70 import "Mutex"
71 import "Semaphore"
72 import "FileMonitor"
73 import "Thread"
74 //#endif
75 import "Archive"
76 import "EARArchive"
77 import "Date"
78 import "unicode"
79 import "GuiApplication"
80 #endif
81
82 public enum LoggingMode { noLogging, stdOut, stdErr, debug, logFile, msgBox, buffer };
83
84 // GENERAL ERROR CODES
85 public enum ErrorLevel
86 {
87    veryFatal = 0,
88    fatal = 1,
89    major = 2,
90    minor = 3
91 };
92
93 public define AllErrors = ErrorLevel::minor;
94
95 public class ErrorCode
96 {
97 public:
98    ErrorLevel level:2:12;
99    uint code:12:0;
100 };
101
102 // TODO: Support enums resolved in compiling pass to allow moving this to GuiApplication.ec
103 public enum SysErrorCode : ErrorCode
104 {
105    allocationFailed = ErrorCode { fatal, 0x001 },
106    nameInexistant   = ErrorCode { fatal, 0x002 },
107    nameExists       = ErrorCode { fatal, 0x003 },
108    missingLibrary   = ErrorCode { fatal, 0x004 },
109    fileNotFound     = ErrorCode { minor, 0x005 },
110    writeFailed      = ErrorCode { major, 0x006 }
111 };
112
113 public enum GuiErrorCode : ErrorCode
114 {
115    driverNotSupported      = ErrorCode { veryFatal, 0x101 },
116    windowCreationFailed    = ErrorCode { veryFatal, 0x102 },
117    graphicsLoadingFailed   = ErrorCode { veryFatal, 0x103 },
118    modeSwitchFailed        = ErrorCode { veryFatal, 0x104 }
119 };
120
121 static define DEFAULT_BUFFER_SIZE = 100 * MAX_F_STRING;
122
123 static Array<const String> sysErrorMessages
124 { [
125    $"No error",
126    $"Memory allocation failed",
127    $"Inexistant string identifier specified",
128    $"Identic string identifier already exists",
129    $"Shared library loading failed",
130    $"File not found",
131    $"Couldn't write to file"
132 ] };
133
134 static Array<const String> guiErrorMessages
135 { [
136    $"No error",
137    $"Graphics driver not supported by any user interface system",
138    $"Window creation failed",
139    $"Window graphics loading failed",
140    $"Driver/Mode switch failed"
141 ] };
142
143 static Array<Array<const String>> errorMessages { [ sysErrorMessages, guiErrorMessages ] };
144
145 // --- File, directory & environment manipulation ---
146 #undef MoveFile
147 #undef MoveFileEx
148
149 public bool MoveFile(const char * source, const char * dest)
150 {
151    return System_MoveFile(source, dest, 0);
152 }
153
154 public class MoveFileOptions : uint32 { public: bool overwrite:1; bool sync:1; };
155
156 public bool MoveFileEx(const char * source, const char * dest, MoveFileOptions options)
157 {
158    return System_MoveFile(source, dest, options);
159 }
160
161 public bool RenameFile(const char * oldName, const char * newName)
162 {
163    return System_RenameFile(oldName, newName);
164 }
165
166 #undef DeleteFile
167
168 public bool DeleteFile(const char * fileName)
169 {
170    return System_DeleteFile(fileName);
171 }
172
173 public bool MakeDir(const char * path)
174 {
175    return System_MakeDir(path);
176 }
177
178 public bool RemoveDir(const char * path)
179 {
180    return System_RemoveDir(path);
181 }
182
183 public char * GetWorkingDir(char * buf, int size)
184 {
185    return System_GetWorkingDir(buf, size);
186 }
187
188 public bool ChangeWorkingDir(const char * buf)
189 {
190    return System_ChangeWorkingDir(buf);
191 }
192
193 public char * GetEnvironment(const char * envName, char * envValue, int max)
194 {
195    return System_GetEnvironment(envName, envValue, max);
196 }
197
198 public void SetEnvironment(const char * envName, const char * envValue)
199 {
200    System_SetEnvironment(envName, envValue);
201 }
202
203 public void UnsetEnvironment(const char * envName)
204 {
205    System_UnsetEnvironment(envName);
206 }
207
208 public bool Execute(const char * command, ...)
209 {
210    bool result;
211    va_list args;
212    va_start(args, command);
213    result = System_Execute(null, command, args, false);
214    va_end(args);
215    return result;
216 }
217
218 public bool ExecuteWait(const char * command, ...)
219 {
220    bool result;
221    va_list args;
222    va_start(args, command);
223    result = System_Execute(null, command, args, true);
224    va_end(args);
225    return result;
226 }
227
228 public bool ExecuteEnv(const char * env, const char * command, ...)
229 {
230    bool result;
231    va_list args;
232    va_start(args, command);
233    result = System_Execute(env, command, args, false);
234    va_end(args);
235    return result;
236 }
237
238 public bool ShellOpen(const char * fileName, ...)
239 {
240    bool result;
241    va_list args;
242    va_start(args, fileName);
243    result = System_ShellOpen(fileName, args);
244    va_end(args);
245    return result;
246 }
247
248 public void GetFreeSpace(const char * path, FileSize64 * size)
249 {
250    System_GetFreeSpace(path, size);
251 }
252
253 // --- Uncagotegorized Functions ---
254 public void Logf(const char * format, ...)
255 {
256    va_list args;
257    char string[MAX_F_STRING];
258    va_start(args, format);
259    vsnprintf(string, sizeof(string), format, args);
260    string[sizeof(string)-1] = 0;
261    Log(string);
262    va_end(args);
263 }
264
265 public void Log(const char * text)
266 {
267    switch(globalSystem.errorLoggingMode)
268    {
269       case debug:
270 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
271       {
272          uint16 * _wtext = UTF8toUTF16(text, null);
273          OutputDebugString(_wtext);
274          delete _wtext;
275          break;
276       }
277 #endif
278       case stdOut:
279          fputs(text, eC_stdout());
280          fflush(eC_stdout());
281          break;
282       case stdErr:
283          fputs(text, eC_stderr());
284          fflush(eC_stderr());
285          break;
286       case logFile:
287       {
288          File f;
289          if((f = FileOpen(globalSystem.logFile, append)))
290          {
291             f.Puts(text);
292             delete f;
293          }
294          break;
295       }
296       case buffer:
297       case msgBox:
298          strcat(globalSystem.errorBuffer, text);
299          break;
300    }
301 }
302
303 public void DumpErrors(bool display)
304 {
305    if(globalSystem.errorBuffer && globalSystem.errorBuffer[0])
306    {
307       if(display)
308       {
309 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
310          if(globalSystem.errorLoggingMode == buffer)
311             printf(globalSystem.errorBuffer);
312          else
313          {
314             char title[1024];
315             sprintf(title, "%s - Error Log", guiApp.appName);
316             MessageBoxA(HWND_DESKTOP, globalSystem.errorBuffer, title, MB_OK|MB_ICONWARNING);
317          }
318 #else
319          printf("%s", globalSystem.errorBuffer);
320 #endif
321       }
322       globalSystem.errorBuffer[0] = '\0';
323    }
324 }
325
326 public void LogErrorCode(ErrorCode errorCode, const char * details)
327 {
328    if(errorCode.level <= globalSystem.errorLevel)
329    {
330       int cat = (errorCode.code & 0xF00) >> 8;
331       int code = errorCode.code & 0xFF;
332       if(details)
333          Logf("System Error [%d]: %s (%s).\n",
334             errorCode.level,
335             errorMessages[cat][code],
336             details);
337       else
338          Logf("System Error [%d]: %s.\n",
339             errorCode.level,
340             errorMessages[cat][code]);
341    }
342    globalSystem.lastErrorCode = errorCode;
343 }
344
345 public uint GetLastErrorCode()
346 {
347    return globalSystem.lastErrorCode;
348 }
349
350 public void ResetError()
351 {
352    globalSystem.lastErrorCode = 0;
353 }
354
355 public void SetErrorLevel(ErrorLevel level)
356 {
357    globalSystem.errorLevel = level;
358 }
359
360 public void SetLoggingMode(LoggingMode mode, void * where)
361 {
362    globalSystem.errorLoggingMode = mode;
363
364    if(mode == logFile)
365    {
366       File file;
367       strcpy(globalSystem.logFile, where);
368       file = FileOpen(globalSystem.logFile, write);
369       delete file;
370    }
371    else if(mode == buffer || mode == msgBox)
372    {
373       if(!globalSystem.errorBuffer)
374       {
375          globalSystem.errorBufferSize = DEFAULT_BUFFER_SIZE;
376          globalSystem.errorBuffer = new char[DEFAULT_BUFFER_SIZE];
377       }
378       globalSystem.errorBuffer[0] = 0;
379    }
380    else if(mode == debug)
381    {
382 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
383       uint16 * _wappName = UTF8toUTF16(guiApp.appName, null);
384       OutputDebugString(L"\n");
385       OutputDebugString(_wappName);
386       OutputDebugString(L" - Logging Errors...\n");
387       delete _wappName;
388 #endif
389    }
390    if(mode == 0)
391    {
392       DumpErrors(true);
393       if(globalSystem.errorBuffer)
394       {
395          delete globalSystem.errorBuffer;
396          globalSystem.errorBufferSize = 0;
397       }
398    }
399 }
400
401 static define errorLogMsg = $"\n\nWould you like to view the error log?";
402 /*
403 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
404 static DWORD REAL_ExceptionHandler(EXCEPTION_POINTERS *exception)
405 {
406    EXCEPTION_RECORD * record = exception->ExceptionRecord;
407    char exceptionString[1024] = "", title[1024];
408
409    switch(record->ExceptionCode)
410    {
411       case EXCEPTION_ACCESS_VIOLATION:
412          if(record->ExceptionInformation[0])
413             sprintf(exceptionString, "Access Violation Writing to 0x%p", (void *)record->ExceptionInformation[1]);
414          else
415             sprintf(exceptionString, "Access Violation Reading from 0x%p", (void *)record->ExceptionInformation[1]);
416          break;
417       case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
418          sprintf(exceptionString, "Array Bounds Exceeded");
419          break;
420       case EXCEPTION_BREAKPOINT:
421          sprintf(exceptionString, "Breakpoint Encountered");
422          break;
423       case EXCEPTION_DATATYPE_MISALIGNMENT:
424          sprintf(exceptionString, "Data Type Misalignment");
425          break;
426       case EXCEPTION_FLT_DENORMAL_OPERAND:
427          sprintf(exceptionString, "Floating-Point Denormal Operand");
428          break;
429       case EXCEPTION_FLT_DIVIDE_BY_ZERO:
430          sprintf(exceptionString, "Floating-Point Divide by Zero");
431          break;
432       case EXCEPTION_FLT_INEXACT_RESULT:
433          sprintf(exceptionString, "Floating-Point Inexact Result");
434          break;
435       case EXCEPTION_FLT_INVALID_OPERATION:
436          sprintf(exceptionString, "Floating-Point Invalid Operation");
437          break;
438       case EXCEPTION_FLT_OVERFLOW:
439          sprintf(exceptionString, "Floating-Point Overflow");
440          break;
441       case EXCEPTION_FLT_STACK_CHECK:
442          sprintf(exceptionString, "Floating-Point Stack Check");
443          break;
444       case EXCEPTION_FLT_UNDERFLOW:
445          sprintf(exceptionString, "Floating-Point Underflow");
446          break;
447       case EXCEPTION_ILLEGAL_INSTRUCTION:
448          sprintf(exceptionString, "Illegal Instruction");
449          break;
450       case EXCEPTION_IN_PAGE_ERROR:
451          sprintf(exceptionString, "In Page Error");
452          break;
453       case EXCEPTION_INT_DIVIDE_BY_ZERO:
454          sprintf(exceptionString, "Integer Divide by Zero");
455          break;
456       case EXCEPTION_INT_OVERFLOW:
457          sprintf(exceptionString, "Integer Overflow");
458          break;
459       case EXCEPTION_INVALID_DISPOSITION:
460          sprintf(exceptionString, "Invalid Disposition");
461          break;
462       case EXCEPTION_NONCONTINUABLE_EXCEPTION:
463          sprintf(exceptionString, "Non Continuable Exception");
464          break;
465       case EXCEPTION_PRIV_INSTRUCTION:
466          sprintf(exceptionString, "Unallowed Instruction");
467          break;
468       case EXCEPTION_SINGLE_STEP:
469          sprintf(exceptionString, "Single Step Exception");
470          break;
471       case EXCEPTION_STACK_OVERFLOW:
472          return EXCEPTION_CONTINUE_SEARCH;
473          //sprintf(exceptionString, "Stack Overflow");
474          //break;
475    }
476
477    sprintf(title, "%s - Fatal Error", guiApp.appName);
478
479    if(globalSystem.errorBuffer && globalSystem.errorBuffer[0])
480    {
481       strcat(exceptionString, errorLogMsg);
482       if(MessageBoxA(HWND_DESKTOP, exceptionString, title, MB_YESNO|MB_ICONERROR) == IDYES)
483          DumpErrors(true);
484    }
485    else
486       MessageBoxA(HWND_DESKTOP, exceptionString, title, MB_OK|MB_ICONERROR);
487
488    return EXCEPTION_EXECUTE_HANDLER;
489 }
490 #endif
491 */
492
493 private struct System
494 {
495    LoggingMode errorLoggingMode;
496    char * errorBuffer;
497    int errorBufferSize;
498    char logFile[MAX_LOCATION];
499    ErrorCode lastErrorCode;
500    ErrorLevel errorLevel;
501
502 #ifndef ECERE_BOOTSTRAP
503 #if !defined(__EMSCRIPTEN__)
504    Semaphore eventSemaphore;
505 #endif
506
507    //FileSystem fileSystems;
508
509    // File Monitor
510    OldList fileMonitors;
511 #if !defined(__EMSCRIPTEN__)
512    Mutex fileMonitorMutex;
513    Thread fileMonitorThread;
514 #endif
515    bool systemTerminate;
516 #endif
517 };
518
519 System globalSystem;