/* api_system.c : part of The Bastard disassembly environment 
 *
 */
#include <api/api_main.h>
#include <api/api_error.h>
#include <extension.h>
#include <config.h>

extern struct DISASM_TGT target;
extern struct DISASM_ENV disasm_env;
extern struct DISASM_PREFS disasm_prefs;

/*    API section:
 *
 *    17. System Interaction   :: Various utility functions
 * /

/* ------------------------------------------------------System Interaction */
   void Init(char *home) {
      SetEnvDefaults();
      DEBUG_Print("Initializing Interpreter\n");
      InitInterpreter();
      DEBUG_Print("Initializing RDBMS\n");
      InitDB();
      /* set up DB linked list */
      db_head = db_current = db_target;
      db_target->db_id = -1;
      /*DEBUG_Print("Loading Config DB\n");
      db_head = db_current = db_target->prev = db_config;
      db_config->next = db_target;
      db_config->db_id = db_target->db_id = -1;

      LoadConfigDB(NULL);*/
      DEBUG_Print("Initializing Extensions\n");
      InitExtensions();
      ReInit(home);
      return;
   }
   
   void ReInit(char *home) {
      char *user, name[PATH_MAX];
      
      
      DEBUG_Print("Resetting Environment\n");
      /* set all structs to 0 and set defaults */
      memset(&target, 0, sizeof(struct DISASM_TGT));
      SetEnvDefaults();
      SetTargetDefaults();
      SetPrefDefaults();

      /* set up pseudovirtualmachine */
      DEBUG_Print("Initializing VM\n");
      InitVM();

      /* load default extensions */
      DEBUG_Print("Loading Default Extensions\n");
      sprintf(name, "%s/arch/lib%s.so", disasm_env.home, target.arch);
      DEBUG_PrintVar( name, "%s");
      DEBUG_PrintVar( disasm_env.home, "%s");
      DEBUG_PrintVar( target.arch, "%s");
      LoadExtension( EXT_ARCH, name, ext_arch);
      sprintf(name, "%s/asm/lib%s.so", disasm_env.home, target.assembler);
      DEBUG_PrintVar( name, "%s");
      DEBUG_PrintVar( target.assembler, "%s");
      LoadExtension( EXT_ASM, name, ext_asm);
      sprintf(name, "%s/formats/%s.bc", disasm_env.home, target.format);
      DEBUG_PrintVar( name, "%s");
      DEBUG_PrintVar( target.format, "%s");
      LoadExtension( EXT_FORMAT, name, ext_format);
      sprintf(name, "%s/lang/lib%s.so", disasm_env.home, target.lang);
      DEBUG_PrintVar( name, "%s");
      DEBUG_PrintVar( target.lang, "%s");
      LoadExtension( EXT_LANG, name, ext_lang);

      /* load history for previous user */
      DEBUG_Print("Loading User Profile\n");
      user = getenv("USER");
      //LoadProfile(PROFILE_ENV, user);
      //LoadProfile(PROFILE_PREF, user);

      /* override everything with command-line options etc */
      disasm_prefs.options |= disasm_prefs.override;
      if ( disasm_prefs.options & COLOR_TTY) 
         disasm_env.output = ASM_OUTPUT_TTY_COLOR;
      
      return;
   }
   void Message( const char *str) {
   /* Print a message unless QUIET is flag is set 
    */
      if (! (disasm_prefs.options & QUIET))  printf("%s", str);
      return;
   }

   void ErrorMsg( int num, const char *str) {
   /* Print a message and error code, regardless of QUIET */
      printf("Error %d: %s\n", num, str);
      return;
   }

   void Quit(void) {
      char *user = getenv("USER");

      DEBUG_Print("Quitting...\n");
      if ( disasm_env.flags ) CloseDB();
      /* DEBUG_Print("Updating user profile\n");
      //UpdateProfile(PROFILE_ENV, user);
      //UpdateProfile(PROFILE_PREF, user);
      UnloadConfigDB(); */
      CleanupVM(); 
      DEBUG_Print("Cleaning Up Extensions\n");
      CleanupExtensions();
      SetEnvFlag( QUIT_NOW );
   }

   int Exec( char *args ){
      char buf[256];
      sprintf( buf, ".bdb/%s %s", target.name, args); 
      return(system(buf));
   }

   int Debug(void) {
      char buf[256];
      sprintf( buf, "%s .bdb/%s", disasm_prefs.debugger, target.name); 
      return(system(buf));
   }

   int Core(void) {
   /* start target in new process w/ core dumps enabled */
   /* wait for user to hit key */
   /* send a sig_core to target PID */
      Message("Core not yet supported!\n");
      return(-1);
   }

   int Panic(void) {
   /* Similar to 'core' */
   /* Get a kernel dump w/o killing the kernel, if possible */
   /* ... the idea is to get a snapshot of the kernel as a target is
    * running */
      Message("Panic not yet supported!\n");
      return(-1);
   }

/* ----------------------------------------------- Error Handling */
   int _last_bastard_error;

   int SetLastError( int errnum ){
   /* This returns 0 so that you can do a `return(SetLastError(#));` */
      _last_bastard_error = errnum;
      return(0);
   }

   char* GetErrorString( int errnum ){
      int x;
   
      for (x=0; _bastard_error_table[x].errnum != 0; x++)
         if (_bastard_error_table[x].errnum == errnum)
            return( _bastard_error_table[x].errstr);
      return( NULL ) ;   
   }

   int GetLastError(){
      return( _last_bastard_error );
   }

   char* GetLastErrorString( ){
      return( GetErrorString( _last_bastard_error) );
   }

   void PrintErrorMsg(int errnum){
      char *msg;
   
      ErrorMsg( errnum, GetErrorString(errnum));
      return;
   }
   void SprintErrorMsg(char *buf, int errnum){
      if (! buf) 
         return;
      strcpy( buf, GetErrorString(errnum) );
      return;
   }

/* ---------------------- byte ordering crap */
/* byte order */
int GetAddrInt(char *buf);
int GetAddrShort(char *buf);
/* no byte order */
int GetAddrDataRaw();
/* byte order */
int GetAddrBytes();
/* no byte order */
int GetAddrBytesRaw();
