6d27861c0a147b13bb2185771502e3accb0f60aa
[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);
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
148 public bool MoveFile(const char * source, const char * dest)
149 {
150    return System_MoveFile(source, dest);
151 }
152
153 public bool RenameFile(const char * oldName, const char * newName)
154 {
155    return System_RenameFile(oldName, newName);
156 }
157
158 #undef DeleteFile
159
160 public bool DeleteFile(const char * fileName)
161 {
162    return System_DeleteFile(fileName);
163 }
164
165 public bool MakeDir(const char * path)
166 {
167    return System_MakeDir(path);
168 }
169
170 public bool RemoveDir(const char * path)
171 {
172    return System_RemoveDir(path);
173 }
174
175 public char * GetWorkingDir(char * buf, int size)
176 {
177    return System_GetWorkingDir(buf, size);
178 }
179
180 public bool ChangeWorkingDir(const char * buf)
181 {
182    return System_ChangeWorkingDir(buf);
183 }
184
185 public char * GetEnvironment(const char * envName, char * envValue, int max)
186 {
187    return System_GetEnvironment(envName, envValue, max);
188 }
189
190 public void SetEnvironment(const char * envName, const char * envValue)
191 {
192    System_SetEnvironment(envName, envValue);
193 }
194
195 public void UnsetEnvironment(const char * envName)
196 {
197    System_UnsetEnvironment(envName);
198 }
199
200 public bool Execute(const char * command, ...)
201 {
202    bool result;
203    va_list args;
204    va_start(args, command);
205    result = System_Execute(null, command, args, false);
206    va_end(args);
207    return result;
208 }
209
210 public bool ExecuteWait(const char * command, ...)
211 {
212    bool result;
213    va_list args;
214    va_start(args, command);
215    result = System_Execute(null, command, args, true);
216    va_end(args);
217    return result;
218 }
219
220 public bool ExecuteEnv(const char * env, const char * command, ...)
221 {
222    bool result;
223    va_list args;
224    va_start(args, command);
225    result = System_Execute(env, command, args, false);
226    va_end(args);
227    return result;
228 }
229
230 public bool ShellOpen(const char * fileName, ...)
231 {
232    bool result;
233    va_list args;
234    va_start(args, fileName);
235    result = System_ShellOpen(fileName, args);
236    va_end(args);
237    return result;
238 }
239
240 public void GetFreeSpace(const char * path, FileSize64 * size)
241 {
242    System_GetFreeSpace(path, size);
243 }
244
245 // --- Uncagotegorized Functions ---
246 public void Logf(const char * format, ...)
247 {
248    va_list args;
249    char string[MAX_F_STRING];
250    va_start(args, format);
251    vsnprintf(string, sizeof(string), format, args);
252    string[sizeof(string)-1] = 0;
253    Log(string);
254    va_end(args);
255 }
256
257 public void Log(const char * text)
258 {
259    switch(globalSystem.errorLoggingMode)
260    {
261       case debug:
262 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
263       {
264          uint16 * _wtext = UTF8toUTF16(text, null);
265          OutputDebugString(_wtext);
266          delete _wtext;
267          break;
268       }
269 #endif
270       case stdOut:
271          fputs(text, eC_stdout());
272          fflush(eC_stdout());
273          break;
274       case stdErr:
275          fputs(text, eC_stderr());
276          fflush(eC_stderr());
277          break;
278       case logFile:
279       {
280          File f;
281          if((f = FileOpen(globalSystem.logFile, append)))
282          {
283             f.Puts(text);
284             delete f;
285          }
286          break;
287       }
288       case buffer:
289       case msgBox:
290          strcat(globalSystem.errorBuffer, text);
291          break;
292    }
293 }
294
295 public void DumpErrors(bool display)
296 {
297    if(globalSystem.errorBuffer && globalSystem.errorBuffer[0])
298    {
299       if(display)
300       {
301 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
302          if(globalSystem.errorLoggingMode == buffer)
303             printf(globalSystem.errorBuffer);
304          else
305          {
306             char title[1024];
307             sprintf(title, "%s - Error Log", guiApp.appName);
308             MessageBoxA(HWND_DESKTOP, globalSystem.errorBuffer, title, MB_OK|MB_ICONWARNING);
309          }
310 #else
311          printf("%s", globalSystem.errorBuffer);
312 #endif
313       }
314       globalSystem.errorBuffer[0] = '\0';
315    }
316 }
317
318 public void LogErrorCode(ErrorCode errorCode, const char * details)
319 {
320    if(errorCode.level <= globalSystem.errorLevel)
321    {
322       int cat = (errorCode.code & 0xF00) >> 8;
323       int code = errorCode.code & 0xFF;
324       if(details)
325          Logf("System Error [%d]: %s (%s).\n",
326             errorCode.level,
327             errorMessages[cat][code],
328             details);
329       else
330          Logf("System Error [%d]: %s.\n",
331             errorCode.level,
332             errorMessages[cat][code]);
333    }
334    globalSystem.lastErrorCode = errorCode;
335 }
336
337 public uint GetLastErrorCode()
338 {
339    return globalSystem.lastErrorCode;
340 }
341
342 public void ResetError()
343 {
344    globalSystem.lastErrorCode = 0;
345 }
346
347 public void SetErrorLevel(ErrorLevel level)
348 {
349    globalSystem.errorLevel = level;
350 }
351
352 public void SetLoggingMode(LoggingMode mode, void * where)
353 {
354    globalSystem.errorLoggingMode = mode;
355
356    if(mode == logFile)
357    {
358       File file;
359       strcpy(globalSystem.logFile, where);
360       file = FileOpen(globalSystem.logFile, write);
361       delete file;
362    }
363    else if(mode == buffer || mode == msgBox)
364    {
365       if(!globalSystem.errorBuffer)
366       {
367          globalSystem.errorBufferSize = DEFAULT_BUFFER_SIZE;
368          globalSystem.errorBuffer = new char[DEFAULT_BUFFER_SIZE];
369       }
370       globalSystem.errorBuffer[0] = 0;
371    }
372    else if(mode == debug)
373    {
374 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
375       uint16 * _wappName = UTF8toUTF16(guiApp.appName, null);
376       OutputDebugString(L"\n");
377       OutputDebugString(_wappName);
378       OutputDebugString(L" - Logging Errors...\n");
379       delete _wappName;
380 #endif
381    }
382    if(mode == 0)
383    {
384       DumpErrors(true);
385       if(globalSystem.errorBuffer)
386       {
387          delete globalSystem.errorBuffer;
388          globalSystem.errorBufferSize = 0;
389       }
390    }
391 }
392
393 static define errorLogMsg = $"\n\nWould you like to view the error log?";
394 /*
395 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
396 static DWORD REAL_ExceptionHandler(EXCEPTION_POINTERS *exception)
397 {
398    EXCEPTION_RECORD * record = exception->ExceptionRecord;
399    char exceptionString[1024] = "", title[1024];
400
401    switch(record->ExceptionCode)
402    {
403       case EXCEPTION_ACCESS_VIOLATION:
404          if(record->ExceptionInformation[0])
405             sprintf(exceptionString, "Access Violation Writing to 0x%p", (void *)record->ExceptionInformation[1]);
406          else
407             sprintf(exceptionString, "Access Violation Reading from 0x%p", (void *)record->ExceptionInformation[1]);
408          break;
409       case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
410          sprintf(exceptionString, "Array Bounds Exceeded");
411          break;
412       case EXCEPTION_BREAKPOINT:
413          sprintf(exceptionString, "Breakpoint Encountered");
414          break;
415       case EXCEPTION_DATATYPE_MISALIGNMENT:
416          sprintf(exceptionString, "Data Type Misalignment");
417          break;
418       case EXCEPTION_FLT_DENORMAL_OPERAND:
419          sprintf(exceptionString, "Floating-Point Denormal Operand");
420          break;
421       case EXCEPTION_FLT_DIVIDE_BY_ZERO:
422          sprintf(exceptionString, "Floating-Point Divide by Zero");
423          break;
424       case EXCEPTION_FLT_INEXACT_RESULT:
425          sprintf(exceptionString, "Floating-Point Inexact Result");
426          break;
427       case EXCEPTION_FLT_INVALID_OPERATION:
428          sprintf(exceptionString, "Floating-Point Invalid Operation");
429          break;
430       case EXCEPTION_FLT_OVERFLOW:
431          sprintf(exceptionString, "Floating-Point Overflow");
432          break;
433       case EXCEPTION_FLT_STACK_CHECK:
434          sprintf(exceptionString, "Floating-Point Stack Check");
435          break;
436       case EXCEPTION_FLT_UNDERFLOW:
437          sprintf(exceptionString, "Floating-Point Underflow");
438          break;
439       case EXCEPTION_ILLEGAL_INSTRUCTION:
440          sprintf(exceptionString, "Illegal Instruction");
441          break;
442       case EXCEPTION_IN_PAGE_ERROR:
443          sprintf(exceptionString, "In Page Error");
444          break;
445       case EXCEPTION_INT_DIVIDE_BY_ZERO:
446          sprintf(exceptionString, "Integer Divide by Zero");
447          break;
448       case EXCEPTION_INT_OVERFLOW:
449          sprintf(exceptionString, "Integer Overflow");
450          break;
451       case EXCEPTION_INVALID_DISPOSITION:
452          sprintf(exceptionString, "Invalid Disposition");
453          break;
454       case EXCEPTION_NONCONTINUABLE_EXCEPTION:
455          sprintf(exceptionString, "Non Continuable Exception");
456          break;
457       case EXCEPTION_PRIV_INSTRUCTION:
458          sprintf(exceptionString, "Unallowed Instruction");
459          break;
460       case EXCEPTION_SINGLE_STEP:
461          sprintf(exceptionString, "Single Step Exception");
462          break;
463       case EXCEPTION_STACK_OVERFLOW:
464          return EXCEPTION_CONTINUE_SEARCH;
465          //sprintf(exceptionString, "Stack Overflow");
466          //break;
467    }
468
469    sprintf(title, "%s - Fatal Error", guiApp.appName);
470
471    if(globalSystem.errorBuffer && globalSystem.errorBuffer[0])
472    {
473       strcat(exceptionString, errorLogMsg);
474       if(MessageBoxA(HWND_DESKTOP, exceptionString, title, MB_YESNO|MB_ICONERROR) == IDYES)
475          DumpErrors(true);
476    }
477    else
478       MessageBoxA(HWND_DESKTOP, exceptionString, title, MB_OK|MB_ICONERROR);
479
480    return EXCEPTION_EXECUTE_HANDLER;
481 }
482 #endif
483 */
484
485 private struct System
486 {
487    LoggingMode errorLoggingMode;
488    char * errorBuffer;
489    int errorBufferSize;
490    char logFile[MAX_LOCATION];
491    ErrorCode lastErrorCode;
492    ErrorLevel errorLevel;
493
494 #ifndef ECERE_BOOTSTRAP
495 #if !defined(__EMSCRIPTEN__)
496    Semaphore eventSemaphore;
497 #endif
498
499    //FileSystem fileSystems;
500
501    // File Monitor
502    OldList fileMonitors;
503 #if !defined(__EMSCRIPTEN__)
504    Mutex fileMonitorMutex;
505    Thread fileMonitorThread;
506 #endif
507    bool systemTerminate;
508 #endif
509 };
510
511 System globalSystem;