Fixed VESA scrolling bug
[tpg/acess2.git] / Kernel / system.c
index 463b4e0..546b2d8 100644 (file)
@@ -6,6 +6,9 @@
 #define DEBUG  0
 #include <acess.h>
 
+#define N_VARIABLES    16
+#define N_MAX_ARGS     BITS
+
 // === TYPES ===
 typedef struct
 {
@@ -18,6 +21,15 @@ typedef struct
         int    nLines;
        tConfigLine     Lines[];
 }      tConfigFile;
+typedef struct
+{
+       char    *Name;          // Name
+        int    MinArgs;        // Minimum number of arguments
+        int    MaxArgs;        // Maximum number of arguments
+       Uint    IntArgs;        // Bitmap of arguments that should be treated as integers
+       void    *Func;          // Function pointer
+       Uint    OptDefaults[N_MAX_ARGS];        // Default values for optional arguments
+}      tConfigCommand;
 
 // === IMPORTS ===
 extern int     Modules_LoadBuiltins();
@@ -34,22 +46,39 @@ void        System_ParseSetting(char *Arg);
 void   System_ExecuteScript();
 tConfigFile    *System_Int_ParseFile(char *File);
 
+// === CONSTANTS ===
+const tConfigCommand   caConfigCommands[] = {
+       {"module", 1,2, 0, Module_LoadFile, {(Uint)"",0}},      // Load a module from a file
+       {"spawn", 1,1, 0, Proc_Spawn, {0}},             // Spawn a process
+       // --- VFS ---
+       {"mount", 3,4, 0, VFS_Mount, {(Uint)"",0}},             // Mount a device
+       {"symlink", 2,2, 0, VFS_Symlink, {0}},  // Create a Symbolic Link
+       {"mkdir", 1,1, 0, VFS_MkDir, {0}},              // Create a Directory
+       {"open", 1,2, 0, VFS_Open, {VFS_OPENFLAG_READ,0}},      // Open a file
+       {"close", 1,1, 0x1, VFS_Close, {0}},    // Close an open file
+       {"ioctl", 3,3, 0x3, VFS_IOCtl, {0}},    // Call an IOCtl
+       
+       {"", 0,0, 0, NULL, {0}}
+};
+#define NUM_CONFIG_COMMANDS    (sizeof(caConfigCommands)/sizeof(caConfigCommands[0]))
+
 // === GLOBALS ===
 char   *gsConfigScript = "/Acess/Conf/BootConf.cfg";
 
 // === CODE ===
 void System_Init(char *ArgString)
-{      
-       // Set the debug to be echoed to the terminal
-       StartupPrint("Kernel now echoes to VT7 (Ctrl-Alt-F8)");
-       Debug_SetKTerminal("/Devices/VTerm/7");
+{
        
        // - Parse Kernel's Command Line
        System_ParseCommandLine(ArgString);
        
        // - Execute the Config Script
-       Log("Executing config script...");
+       Log_Log("Config", "Executing config script...");
        System_ExecuteScript();
+       
+       // Set the debug to be echoed to the terminal
+       Log_Log("Config", "Kernel now echoes to VT7 (Ctrl-Alt-F8)");
+       Debug_SetKTerminal("/Devices/VTerm/7");
 }
 
 /**
@@ -63,7 +92,7 @@ void System_ParseCommandLine(char *ArgString)
         int    i;
        char    *str;
        
-       Log("Kernel Command Line: \"%s\"", ArgString);
+       Log_Log("Config", "Kernel Invocation \"%s\"", ArgString);
        
        // --- Get Arguments ---
        str = ArgString;
@@ -114,7 +143,7 @@ void System_ParseVFS(char *Arg)
        
        // Check if the equals was found
        if( *value == '\0' ) {
-               Warning("Expected '=' in the string '%s'", Arg);
+               Log_Warning("Config", "Expected '=' in the string '%s'", Arg);
                return ;
        }
        
@@ -125,7 +154,7 @@ void System_ParseVFS(char *Arg)
        // - Symbolic Link <link>=<destination>
        if(value[0] == '/')
        {
-               Log("Symbolic link '%s' pointing to '%s'", Arg, value);
+               Log_Log("Config", "Symbolic link '%s' pointing to '%s'", Arg, value);
                VFS_Symlink(Arg, value);
        }
        // - Mount <mountpoint>=<fs>:<device>
@@ -140,13 +169,13 @@ void System_ParseVFS(char *Arg)
                }
                // Create Mountpoint
                if( (fd = VFS_Open(Arg, 0)) == -1 ) {
-                       Log("Creating directory '%s'", Arg, value);
+                       Log_Log("Config", "Creating directory '%s'", Arg, value);
                        VFS_MkDir( Arg );
                } else {
                        VFS_Close(fd);
                }
                // Mount
-               Log("Mounting '%s' to '%s' ('%s')", dev, Arg, value);
+               Log_Log("Config", "Mounting '%s' to '%s' ('%s')", dev, Arg, value);
                VFS_Mount(dev, Arg, value, "");
        }
 }
@@ -168,7 +197,7 @@ void System_ParseSetting(char *Arg)
        {
                //if(strcmp(Arg, "") == 0) {
                //} else {
-                       Warning("Kernel flag '%s' is not recognised", Arg);
+                       Log_Warning("Config", "Kernel flag '%s' is not recognised", Arg);
                //}
        }
        else
@@ -177,10 +206,13 @@ void System_ParseSetting(char *Arg)
                value ++;       // and eat it's position
                
                if(strcmp(Arg, "SCRIPT") == 0) {
-                       Log("Config Script: '%s'", value);
-                       gsConfigScript = value;
+                       Log_Log("Config", "Config Script: '%s'", value);
+                       if(strlen(value) == 0)
+                               gsConfigScript = NULL;
+                       else
+                               gsConfigScript = value;
                } else {
-                       Warning("Kernel config setting '%s' is not recognised", Arg);
+                       Log_Warning("Config", "Kernel config setting '%s' is not recognised", Arg);
                }
                
        }
@@ -193,15 +225,20 @@ void System_ExecuteScript()
 {
         int    fp;
         int    fLen = 0;
-        int    i;
+        int    i, j, k;
+        int    val;
+        int    result = 0;
+        int    variables[N_VARIABLES];
+        int    bReplaced[N_MAX_ARGS];
        char    *fData;
+       char    *jmpTarget;
        tConfigFile     *file;
        tConfigLine     *line;
        
        // Open Script
        fp = VFS_Open(gsConfigScript, VFS_OPENFLAG_READ);
        if(fp == -1) {
-               Warning("[CFG] Passed script '%s' does not exist", gsConfigScript);
+               Log_Warning("Config", "Passed script '%s' does not exist", gsConfigScript);
                return;
        }
        
@@ -215,7 +252,6 @@ void System_ExecuteScript()
        VFS_Close(fp);
        
        
-       
        // Parse File
        file = System_Int_ParseFile(fData);
        
@@ -225,90 +261,149 @@ void System_ExecuteScript()
                line = &file->Lines[i];
                if( line->nParts == 0 ) continue;       // Skip blank
                
-               // Mount Device
-               if( strcmp(line->Parts[0], "mount") == 0 )
-               {
-                       if( line->nParts != 4 ) {
-                               Warning("Configuration command 'mount' requires 3 arguments, %i given",
-                                       line->nParts-1);
-                               continue;
+               if(line->Parts[0][0] == ':')    continue;       // Ignore labels
+               
+               // Prescan and eliminate variables
+               for( j = 1; j < line->nParts; j++ ) {
+                       Log_Debug("Config", "Arg #%i is '%s'", j, line->Parts[j]);
+                       bReplaced[j] = 0;
+                       if( line->Parts[j][0] != '$' )  continue;
+                       if( line->Parts[j][1] == '?' ) {
+                               val = result;
                        }
-                       //Log("[CFG ] Mount '%s' to '%s' (%s)",
-                       //      line->Parts[1], line->Parts[2], line->Parts[3]);
-                       //! \todo Use an optional 4th argument for the options string
-                       VFS_Mount(line->Parts[1], line->Parts[2], line->Parts[3], "");
-               }
-               // Load a Module
-               else if(strcmp(line->Parts[0], "module") == 0)
-               {
-                       if( line->nParts < 2 || line->nParts > 3 ) {
-                               Warning("Configuration command 'module' requires 1 or 2 arguments, %i given",
-                                       line->nParts-1);
-                               continue;
+                       else {
+                               val = atoi( &line->Parts[j][1] );
+                               if( val < 0 || val > N_VARIABLES )      continue;
+                               val = variables[ val ];
                        }
-                       if( line->nParts == 3 )
-                               Module_LoadFile(line->Parts[1], line->Parts[2]);
-                       else
-                               Module_LoadFile(line->Parts[1], "");
+                       Log_Debug("Config", "Replaced arg %i ('%s') with 0x%x", j, line->Parts[j], val);
+                       line->Parts[j] = malloc( BITS/8+2+1 );
+                       sprintf(line->Parts[j], "0x%x", val);
+                       bReplaced[j] = 1;
                }
-               // Load a UDI Module
-               else if(strcmp(line->Parts[0], "udimod") == 0)
+               
+               for( j = 0; j < NUM_CONFIG_COMMANDS; j++ )
                {
-                       if( line->nParts != 2 ) {
-                               Warning("Configuration command 'udimod' requires 1 argument, %i given",
-                                       line->nParts-1);
-                               continue;
+                       Uint    args[N_MAX_ARGS];
+                       if(strcmp(line->Parts[0], caConfigCommands[j].Name) != 0)       continue;
+                       
+                       Log_Debug("Config", "Command '%s', %i args passed", line->Parts[0], line->nParts-1);
+                       
+                       if( line->nParts - 1 < caConfigCommands[j].MinArgs ) {
+                               Log_Warning("Config",
+                                       "Configuration command '%s' requires at least %i arguments, %i given",
+                                       caConfigCommands[j].Name, caConfigCommands[j].MinArgs, line->nParts-1
+                                       );
+                               break;
                        }
-                       Log("[CFG  ] Load UDI Module '%s'", line->Parts[1]);
-                       Module_LoadFile(line->Parts[1], "");
-               }
-               // Load a EDI Module
-               else if(strcmp(line->Parts[0], "edimod") == 0)
-               {
-                       if( line->nParts != 2 ) {
-                               Warning("Configuration command 'edimod' requires 1 argument, %i given",
-                                       line->nParts-1);
-                               continue;
+                       
+                       if( line->nParts - 1 > caConfigCommands[j].MaxArgs ) {
+                               Log_Warning("Config",
+                                       "Configuration command '%s' takes at most %i arguments, %i given",
+                                       caConfigCommands[j].Name, caConfigCommands[j].MaxArgs, line->nParts-1
+                                       );
+                               break;
+                       }
+                       
+                       for( k = caConfigCommands[j].MaxArgs-1; k > line->nParts - 1; k-- ) {
+                               args[k] = caConfigCommands[j].OptDefaults[k];
+                       }
+                       
+                       for( k = line->nParts-1; k--; )
+                       {
+                               if( caConfigCommands[j].IntArgs & (1 << k) ) {
+                                       args[k] = atoi(line->Parts[k+1]);
+                               }
+                               else {
+                                       args[k] = (Uint)line->Parts[k+1];
+                               }
+                               Log_Debug("Config", "args[%i] = 0x%x", k, args[k]);
                        }
-                       Log("[CFG  ] Load EDI Module '%s'", line->Parts[1]);
-                       Module_LoadFile(line->Parts[1], "");
+                       result = CallWithArgArray(caConfigCommands[j].Func, caConfigCommands[j].MaxArgs, args);
+                       Log_Debug("Config", "result = %i", result);
+                       break;
                }
-               // Create a Symbolic Link
-               else if(strcmp(line->Parts[0], "symlink") == 0)
+               if( j < NUM_CONFIG_COMMANDS )   continue;
+                       
+               // --- State and Variables ---
+               if(strcmp(line->Parts[0], "set") == 0)
                {
-                       if( line->nParts != 3 ) {
-                               Warning("Configuration command 'symlink' requires 2 arguments, %i given",
+                        int    to, value;
+                       if( line->nParts-1 != 2 ) {
+                               Log_Warning("Config", "Configuration command 'set' requires 2 arguments, %i given",
                                        line->nParts-1);
                                continue;
                        }
-                       Log("[CFG  ] Symlink '%s' pointing to '%s'",
-                               line->Parts[1], line->Parts[2]);
-                       VFS_Symlink(line->Parts[1], line->Parts[2]);
+                       
+                       to = atoi(line->Parts[1]);
+                       value = atoi(line->Parts[2]);
+                       
+                       variables[to] = value;
+                       result = value;
                }
-               // Create a Directory
-               else if(strcmp(line->Parts[0], "mkdir") == 0)
+               // if <val1> <op> <val2> <dest>
+               else if(strcmp(line->Parts[0], "if") == 0)
                {
-                       if( line->nParts != 2 ) {
-                               Warning("Configuration command 'mkdir' requires 1 argument, %i given",
+                       if( line->nParts-1 != 4 ) {
+                               Log_Warning("Config", "Configuration command 'if' requires 4 arguments, %i given",
                                        line->nParts-1);
-                               continue;
                        }
-                       Log("[CFG  ] New Directory '%s'", line->Parts[1]);
-                       VFS_MkDir(line->Parts[1]);
+                       
+                       result = atoi(line->Parts[1]);
+                       val = atoi(line->Parts[3]);
+                       
+                       jmpTarget = line->Parts[4];
+                       
+                       Log_Log("Config", "IF 0x%x %s 0x%x THEN GOTO %s",
+                               result, line->Parts[2], val, jmpTarget);
+                       
+                       if( strcmp(line->Parts[2], "<" ) == 0 ) {
+                               if( result < val )      goto jumpToLabel;
+                       }
+                       else if( strcmp(line->Parts[2], "<=") == 0 ) {
+                               if( result <= val )     goto jumpToLabel;
+                       }
+                       else if( strcmp(line->Parts[2], ">" ) == 0 ) {
+                               if (result > val )      goto jumpToLabel;
+                       }
+                       else if( strcmp(line->Parts[2], ">=") == 0 ) {
+                               if( result >= val )     goto jumpToLabel;
+                       }
+                       else if( strcmp(line->Parts[2],  "=") == 0 ) {
+                               if( result == val )     goto jumpToLabel;
+                       }
+                       else if( strcmp(line->Parts[2], "!=") == 0 ) {
+                               if( result != val )     goto jumpToLabel;
+                       }
+                       else {
+                               Log_Warning("Config", "Unknown comparision '%s' in `if`", line->Parts[2]);
+                       }
+                       
                }
-               // Spawn a process
-               else if(strcmp(line->Parts[0], "spawn") == 0)
-               {
-                       if( line->nParts != 2 ) {
-                               Warning("Configuration command 'spawn' requires 1 argument, %i given",
+               else if(strcmp(line->Parts[0], "goto") == 0) {
+                       if( line->nParts-1 != 1 ) {
+                               Log_Warning("Config", "Configuration command 'goto' requires 1 arguments, %i given",
                                        line->nParts-1);
-                               continue;
                        }
-                       Log("[CFG  ] Starting '%s' as a new task", line->Parts[1]);
-                       Proc_Spawn(line->Parts[1]);
+                       jmpTarget = line->Parts[1];
+               
+               jumpToLabel:
+                       for( j = 0; j < file->nLines; j ++ )
+                       {
+                               if(file->Lines[j].nParts == 0)
+                                       continue;
+                               if(file->Lines[j].Parts[0][0] != ':')
+                                       continue;
+                               if( strcmp(file->Lines[j].Parts[0]+1, jmpTarget) == 0)
+                                       break;
+                       }
+                       if( j == file->nLines )
+                               Log_Warning("Config", "Unable to find label '%s'", jmpTarget);
+                       else
+                               i = j;
                }
                else {
-                       Warning("Unknown configuration command '%s' on line %i",
+                       Log_Warning("Config", "Unknown configuration command '%s' on line %i",
                                line->Parts[0],
                                line->TrueLine
                                );
@@ -318,6 +413,10 @@ void System_ExecuteScript()
        // Clean up after ourselves
        for( i = 0; i < file->nLines; i++ ) {
                if( file->Lines[i].nParts == 0 )        continue;       // Skip blank
+               for( j = 0; j < file->Lines[i].nParts; j++ ) {
+                       if(IsHeap(file->Lines[i].Parts[j]))
+                               free(file->Lines[i].Parts[j]);
+               }
                free( file->Lines[i].Parts );
        }
        free( file );
@@ -438,6 +537,7 @@ tConfigFile *System_Int_ParseFile(char *FileData)
                        // Quoted
                        if( *ptr == '"' ) {
                                ptr ++;
+                               ret->Lines[i].Parts[j] = ptr;
                                while( *ptr && !(*ptr == '"' && ptr[-1] == '\\') && *ptr != '\n' )
                                        ptr++;
                        }

UCC git Repository :: git.ucc.asn.au