/* bastard.c : part of The Bastard disassembly environment ====================
 *
 * Contains initialization code, signal handlers, and the command line
 * interpreter [using the readline library]
 */


#include <cli/bastard_main.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <config.h>

char *cmd;
int caught_sig_kill;

int command_loop( struct DISASM_ENV *e, struct DISASM_PREFS *p) {
   while (! (e->flags & QUIT_NOW) ) {
      if (! (p->options & QUIET)) cmd = readline(e->p1);
      else cmd = readline("");
      add_history(cmd);
      
      if (! ProcessCommand(cmd) )
            ExecMacroLine(cmd);
      if (cmd) free(cmd);
   }
   return(0);
}
//______________________________________________________________user_kill()
void user_kill( int sig) {
   if ( cmd != NULL) free(cmd);
   if (! caught_sig_kill ) {
      caught_sig_kill = 1;
      printf("GodDAMNIT! I can't do ANYTHING!\n");
      if ( GetEnvFlag(IN_EIC) ) {
         InitInterpreter(); /* restart EiC */
         caught_sig_kill = 0;
         SetEnvFlag(IN_EIC);
         command_loop(GetBastardEnv(), GetBastardPrefs());
      } else { 
         cmdQUIT(0, NULL, NULL);
         /* execution should never reach here */
         printf("bastard! killed by signal %d\n", sig);
         if ( GetEnvFlag(QUIET))  pclose(  popen("stty echo", "r") );
         SetEnvFlag( QUIT_NOW );
         exit(sig);
      }
   }
}
//______________________________________________________________ReadPrefs()
void ReadPrefs( char* filename ){
   /* to be written :P */
   FILE *f;
   char group[64] = {0}, name[256], buf[256];
   f = fopen(filename, "r");
   /* allow comments  and GROUP.NAME=VALUE lines */
   while ( fscanf(f, "%[# ]%[^\n]\n", name, buf) > 0 ||
         fscanf(f, "%[^.].%[^ =] = %s\n", group, name, buf) > 0){
      if (  group[0] &&
          ! SetBastardSetting(group, name, buf) &&
          ! SetBastardOption(name) ){
         printf("Invalid Option %s.%s = %s\n", group, name, buf);
      }
      group[0] = '\0';
   }
   fclose(f);
   return;
}

void GetCommandHistory(){
   FILE *f;
   char *c, buf[256];

   sprintf(buf, "%s/.bastard/cmd_history", getenv("HOME"));
   if ( f = fopen(buf, "r") ) {
      while (fgets(buf, 256, f)){
         if ( c = strrchr(buf, '\n')) *c = '\0';
         add_history(buf);
      }
   }
}
//___________________________________________________________________main()
int main (int argc, char* argv[]){
   int x, retVal = 0;
   FILE *fTemp, *oldIN, *oldOUT, *oldERR, *newSTR;
   char tmpBuf[128], *tmp, *script;
   struct stat tmpStat;
   struct DISASM_ENV *disasm_env;
   struct DISASM_PREFS *disasm_prefs;
   struct DISASM_TGT *target;

   /* prepare bastard-settings structure pointers */
   disasm_env = GetBastardEnv();
   disasm_prefs = GetBastardPrefs();
   target = GetBastardTgt();
   caught_sig_kill = 0;


   /* ----------------- Setup Operations Environment -------------- */
   /* + Get the location of bastard [for .bdb, libs, etc] */
   /* the key to our patented 'Run Anywhere' technology ;) */
   if ( !(tmp = getenv("BASTARD_HOME")) ){
      tmp = tmpBuf;
      if (strchr(argv[0], '/') != NULL) {
         strncpy(tmp, argv[0], sizeof(tmpBuf) -1);
      } else {
         fTemp = popen("which bastard", "r");
         if (! fTemp ) {
            printf("Which is broken! Use Explicit Path Names!\n");
            return(-1);
         } else {
            fgets(tmp, sizeof(tmpBuf), fTemp);
            pclose(fTemp);
            x = strlen(tmp) - 1;
            while( isspace(tmp[x]) ) {
               /* strip carriage return and other nonsense */
               tmp[x] = 0;
               x--;
            }
         }
      }
      /* handle symbolic links to the bastard */
      if (lstat( tmp, &tmpStat) == -1) {
         printf("Fatal error %s: lstat %s\n",strerror(errno), tmp);
         return(-1);
      }
      if (S_ISLNK(tmpStat.st_mode)){
         if (readlink( tmp, tmp, 128) == -1) {
             printf("Fatal Error %X: readlink %s\n", errno, tmp);
            return(-1);
         }
      } 
   }
   strncpy((char *)disasm_env->home, tmp, (strrchr(tmp, '/') - tmp ));
//printf("home before%s\n", disasm_env->home);
   /* + Set some non-vital defaults */
   Init(disasm_env->home); /* set defaults, start DB && interpreter */
//printf("home after %s\n", disasm_env->home);
   oldIN = stdin; oldOUT = stdout; oldERR = stderr;

   /* + Apply settings in RC scripts */
   if ( ! stat("/etc/bastard.rc", &tmpStat)) ReadPrefs("/etc/bastard.rc");
   sprintf(tmpBuf, "%s/.bastard/bastard.rc", getenv("HOME"));
   if ( ! stat(tmpBuf, &tmpStat)) ReadPrefs(tmpBuf);

   /* + Trap User Signals */
   signal( SIGKILL, user_kill);
   signal( SIGABRT, user_kill);
   signal( SIGINT, user_kill);
   signal( SIGTERM, user_kill);
   signal( SIGSEGV, user_kill);
   signal( SIGPIPE, SIG_IGN);
   
   /* ------------------- Command Line Options  -------------------- */
   for (x = 1; x < argc; x++) {
      if (argv[x][0] == '-' ) {
         switch (argv[x][1]) {
            case 'i': /* redirect STDIN */
                  newSTR = fopen(argv[x+1], "r");
                  if(newSTR == NULL) {
                        SetLastError(1010);
                        PrintErrorMsg( GetLastError());
                        return(-1);
                  }
                  stdin = newSTR;
                  //fclose(stdin);
                  //open(argv[x+1],  O_NONBLOCK | O_RDONLY);
                  x++; /* advance argument past parameter */
                  break;
            case 'o': /* redirect STDOUT */
                  newSTR = fopen(argv[x+1], "w");
                  if(newSTR == NULL) {
                        SetLastError(1011);
                        PrintErrorMsg( GetLastError());
                        return(-1);
                  }
                  stdout = newSTR;
                  x++; 
                  break;
            case 'e': /* redirect STDERR */
                  newSTR = fopen(argv[x+1], "w");
                  if(newSTR == NULL) {
                        SetLastError(1012);
                        PrintErrorMsg( GetLastError());
                        return(-1);
                  }
                  stderr = newSTR;
                  x++; 
                  break;
            case 's': /* run specified script on target */
                  script = argv[x+1];
                  //runandquit = 1;
                  x++;
                  break;
            case 'p': /* set prompt */
                  strncpy(disasm_env->p1, argv[x+1], 15);
                  x++; 
                  break;
            case 'a': /* annoy user */
                  disasm_prefs->override |= ANNOY_USER;
                  break;
            case 'q': /* suppress useless output */
                  disasm_prefs->override |= QUIET;
                  pclose(  popen("stty -echo", "r") );
                  break;
            case 'd': /* debug mode */
                  disasm_prefs->override |= DEBUG_TIME;
                  break;
            case 'c': /* colorize output */
                  disasm_prefs->override |= COLOR_TTY;
                  break;
            case '-': /* read file from stdin */
                  //tmpnam(target.name);
                  //TODO : RunAndQuit();
                  //runandquit = 1;
                  break;
            case 'h': case '?': default:
                  printf("Usage: %s %s [-i in] [-o out] [-e err]"
                              " [-p p1] [filename]\n",
                              argv[0], "[-aqdch?]");
                  return(-1);
         }
      /* All non-hyphenated parameters are assumed to be the target */
      } else {
            strncpy( target->name, argv[x], sizeof(target->name));
      }      
   }
   /* save command-line option overrides in global var */
   disasm_prefs->options |= disasm_prefs->override;

   /* ------------------------ Get Started  ------------------------- */
   if ( !(disasm_prefs->options & QUIET) ) {
      printf("==========================================================="
             "=====================\n");
      printf("   B A S T A R D                    disassembly environment\n");
      printf("   brought to you by the proud folks at the HCU linux forum\n");
   }

   GetCommandHistory();
   command_loop( disasm_env, disasm_prefs );   

   /* ------------------------ Final Cleanup ----------------------- */
      //if ( stdin != oldIN)   { fclose(stdin); stdin = oldIN; }
      //if ( stdout != oldOUT) { fclose(stdout); stdout = oldOUT; }
      //if ( stderr != oldERR) { fclose(stderr); stderr = oldERR; }

   if ( cmd != NULL) free(cmd);
   if ( ! (disasm_prefs->options & QUIET)) printf("\nYou bastard!\n");
   else pclose(  popen("stty echo", "r") );
   return(0);
}
