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