/* Copyright (C) 1996,1997 Robert H”hne, see COPYING.RH for details */
/* This file is part of RHIDE. */
#define Uses_TApplication
#define Uses_TMenu
#define Uses_TSubMenu
#define Uses_TMenuBar
#define Uses_TMenuItem
#define Uses_TStatusLine
#define Uses_TStatusItem
#define Uses_TStatusDef
#define Uses_TStaticText
#define Uses_TKeys
#define Uses_editCommands
#define Uses_TDeskTop
#define Uses_TView
#define Uses_fpstream
#define Uses_TDialog
#define Uses_MsgBox
#define Uses_TScreen
#define Uses_TMouse
#define Uses_TPalette
#define Uses_TFileDialog
#define Uses_TFileInputLine
#define Uses_TEditorApp
#define Uses_TScreen
#define Uses_TDisplay
#define Uses_TValidator
#define Uses_TDirList
#define Uses_TButton
#define Uses_TEventQueue
#define Uses_TFileViewer
#define Uses_TSortedListBox
#define Uses_TStringCollection

#define Uses_TProject
#define Uses_TOptions
#define Uses_TDepCollection
#define Uses_TMemInfo
#define Uses_IDEConst
#define Uses_RawKeys
#define Uses_TIDEEditWindow
#define Uses_TIDEFileEditor
#define Uses_ideFunctions
#define Uses_ideCommands
#include <libide.h>

#ifdef INTERNAL_DEBUGGER
#include <librhgdb.h>

#define Uses_tvgdbFunctions
#include <libtvgdb.h>
#include <tvgdbhis.h>
#endif

#define Uses_TSCollection
#define Uses_TWindowList
#define Uses_tvutilFunctions
#define Uses_tvutilCommands
#define Uses_TCheckDialog
#define Uses_THintStatusLine
#include <libtvuti.h>

#include <rhide.h>
#include <rhidehis.h>

#include <libtvdem.h>

#define Uses_TEditorApp
#include <tvedit.h>
#include <ideapp.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <locale.h>
#include <inf.h>
#include <time.h>
#include <glob.h>

#ifdef __DJGPP__
#include <go32.h>
#include <sys/farptr.h>
#include <sys/exceptn.h>
#include <crt0.h>
#include <conio.h>
#endif

#include "pal.c"

void SaveScreen();
void RestoreScreen();

const char *_cpIDEColor = cpIDEColor;
const char *_cpIDEBlackWhite = cpIDEBlackWhite;
const char *_cpIDEMono = cpIDEMono;
int cpColorSize = sizeof(cpIDEColor)-1;
int cpBlackWhiteSize = sizeof(cpIDEBlackWhite)-1;
int cpMonoSize = sizeof(cpIDEMono)-1;

static int last_palette = -1;

TPalette & IDE::getPalette() const
{
  static TPalette color(_cpIDEColor,cpColorSize);
  static TPalette bw(_cpIDEBlackWhite,cpBlackWhiteSize);
  static TPalette mono(_cpIDEMono,cpMonoSize);
  if (last_palette != appPalette)
  {
    last_palette = appPalette;
    TIDEFileEditor::colorsCached = 0;
  }
  return appPalette == apBlackWhite ? bw :
         appPalette == apMonochrome ? mono : color;
}

void IDE::resume()
{
  TEditorApp::resume();
  initScreen();
}

#define DELTA(x) (*((long *)(x)))

int global_argc = 0;
char **global_argv = NULL;

TIDEMemInfo *mem_info = NULL;

static void start_mem_info()
{
  TRect r = TProgram::menuBar->getExtent();
  r.a.x = r.b.x - 8;
  mem_info = new TIDEMemInfo(r);
  mem_info->growMode = gfGrowLoX;
  TProgram::application->insert(mem_info);
}

static void end_mem_info()
{
  TProgram::application->remove(mem_info);
  destroy(mem_info);
  mem_info = NULL;
}

void update_mem(int force = 0)
{
  if (!project) return;
  if (!ShowMem && mem_info)
  {
    end_mem_info();
  }
  if (ShowMem)
  {
    if (!mem_info)
    {
      start_mem_info();
    }
    mem_info->update(force);
  }
}

TCEditWindow *IDE::openEditor( char *fileName, Boolean visible )
{
    TRect r = deskTop->getExtent();
    TCEditWindow *p;
    r.b.y -= 7;
    p = new TIDEEditWindow(r, fileName, wnNoNumber);
    if( !visible )
      p->hide();
    AddWindow((TWindow *)p);
#if 0
    SetGlobalEditorOptions(p);
#endif
    TimeOfFile(((TCEditWindow *)p)->getTitle(100),True); // this removes the file from the hashtable
    p->growMode = gfGrowHiX | gfGrowHiY;
    return p;
}

static void update_words()
{
  int i,count,repaint=0;
  if (c_words_changed)
  {
    if (ReservedWords) destroy(ReservedWords);
    count = CReservedWords->getCount();
    ReservedWords = new TStringCollection(count,1);
    for (i=0;i<count;i++)
    {
      ReservedWords->insert(strdup((char *)CReservedWords->at(i)));
    }
    repaint = 1; 
  }
  if (gpc_words_changed)
  {
    if (PascalRWords) destroy(PascalRWords);
    count = GPCReservedWords->getCount();
    PascalRWords = new TStringCollection(count,1);
    for (i=0;i<count;i++)
    {
      char *tmp = strdup((char *)GPCReservedWords->at(i));
      string_down(tmp);
      PascalRWords->insert(tmp);
    }
    repaint = 1; 
  }
  if (gpc_words_changed)
  {
    repaint = 1; 
  }
  if (user_words_changed)
  {
    if (UserWords) destroy(UserWords);
    count = RHIDEUserWords->getCount();
    UserWords = new TStringCollection(count,1);
    for (i=0;i<count;i++)
    {
      UserWords->insert(strdup((char *)RHIDEUserWords->at(i)));
    } 
    repaint = 1; 
  }
  if (c_words_changed || gpc_words_changed || user_words_changed)
  {
    CreateSHShortCutTables();
  }
  c_words_changed =
  gpc_words_changed =
  user_words_changed = 0;
  if (repaint) Repaint();
}

int external_program_executed = 0;

void check_for_external_modifications()
{
  if (windows)
  {
    int count = windows->getCount();
    int i;
    TWindow *window;
    for (i=0;i<count;i++)
    {
      TEvent event;
      window = DESKTOPWINDOW(i);
      event.what = evBroadcast;
      event.message.command = cmEditorAnswer;
      window->handleEvent(event);
      if (event.what == evNothing)
      {
        unsigned long ft;
#define IE ((TIDEFileEditor *)(((TCEditWindow *)window)->editor))
        ft = time_of_file(IE->fileName);
        if (ft != IE->edittime)
        {
          if (messageBox(mfYesNoCancel | mfInformation,
              _("%s has been modified! Reload it?"),
              IE->fileName) == cmYes)
          {
            IE->lock();
            IE->loadFile();
            IE->update(ufView);
            IE->edittime = ft;
            already_maked = 0;
            IE->unlock();
          }
        }
#undef IE
      }
    }
  }
}

#define D(x) disableCommand(x)
#define E(x) enableCommand(x)

static int should_update = 1;
static clock_t last_clock;

void IDE::update()
{
  unsigned i;
  struct {
    unsigned _has_editors:1;
    unsigned _has_project:1;
    unsigned _current_is_editor:1;
    unsigned _current_is_clip:1;
    unsigned _current_is_fileview:1;
    unsigned _current_is_project:1;
    unsigned _target_is_exec:1;
    unsigned _current_is_help:1;
    unsigned _dummy:24;
  } _flags;
  *((uint32 *)&_flags) = 0;
#define has_editors _flags._has_editors
#define has_project _flags._has_project
#define current_is_editor _flags._current_is_editor
#define current_is_clip _flags._current_is_clip
#define current_is_fileview _flags._current_is_fileview
#define current_is_project _flags._current_is_project
#define target_is_exec _flags._target_is_exec
#define current_is_help _flags._current_is_help
  unsigned project_count=0;
  unsigned has_windows=0;
  TEvent event;
  update_mem();
  clock_t _clock = clock();
  if (!should_update)
  {
    if (_clock > CLOCKS_PER_SEC)
    {
      usleep(1000); // 1 ms
    }
    return;
  }
  else last_clock = _clock;
  update_words();

  if (windows) has_windows = windows->getCount();
  if (has_windows)
  {
    for (i=0;i<has_windows;i++)
    {
      event.what = evBroadcast;
      event.message.command = cmEditorAnswer;
      DESKTOPWINDOW(i)->handleEvent(event);
      if (event.what == evNothing)
      {
        has_editors = 1;
      }
    }
    // clipwindow ???
    if ((TView *)TProgram::deskTop->current == (TView *)clipWindow)
      current_is_clip = 1;
    else
    if ((TView *)TProgram::deskTop->current == (TView *)InfWindow)
      current_is_help = 1;
    else
    if ((TView *)TProgram::deskTop->current == (TView *)project_window)
      current_is_project = 1;
    else
    {
      event.what = evBroadcast;
      event.message.command = cmEditorAnswer;
      TProgram::deskTop->current->handleEvent(event);
      if (event.what == evNothing) current_is_editor = 1;
      else
      {
        event.what = evBroadcast;
        event.message.command = cmFileViewAnswer;
        TProgram::deskTop->current->handleEvent(event);
        if (event.what == evNothing) current_is_fileview = 1;
      }
    }
  }
  if (Project.dest_file_type == FILE_COFF ||
      Project.dest_file_type == FILE_EXE)
    target_is_exec = 1;
  if (project_name)
  {
    has_project = 1;
    if (Project.dependencies)
      project_count = Project.dependencies->getCount();
  }

  if (!has_project)
  {
    D(cmCloseProject);
    D(cmAddProjectItem);
    D(cmDelProjectItem);
    D(cmLocalOptions);
    D(cmShowIncludes);
    D(cmClearDependencies);
    D(cmMakeClear);
    D(cmShowProject);
    D(cmWriteMake);
  }
  else
  {
    E(cmShowProject);
    E(cmCloseProject);
    E(cmAddProjectItem);
    E(cmWriteMake);
    if (!project_count)
    {
      D(cmDelProjectItem);
      D(cmLocalOptions);
      D(cmShowIncludes);
      D(cmClearDependencies);
      D(cmMakeClear);
    }
    else
    {
      E(cmDelProjectItem);
      E(cmLocalOptions);
      E(cmShowIncludes);
      E(cmClearDependencies);
      E(cmMakeClear);
    }
  }

  if (!has_windows)
  {
    D(cmTile);
    D(cmCascade);
    D(cmNext);
    D(cmPrev);
    D(cmShowWindowList);
  }
  else
  {
    E(cmTile);
    E(cmCascade);
    E(cmNext);
    E(cmPrev);
    E(cmShowWindowList);
  }

  if (!target_is_exec)
  {
    D(cmRun);
    D(cmStep);
    D(cmTrace);
    D(cmGoto);
    D(cmStepNo);
    D(cmTraceNo);
    D(cmGotoNo);
    D(cmReset);
    D(cmProgArgs);
    D(cmToggleBreak);
    D(cmAddWatchEntry);
    D(cmBreakPoints);
    D(cmFunctionList);
    D(cmCallStack);
  }
  else
  {
    if (current_is_editor)
    {
      E(cmToggleBreak);
      E(cmGoto);
      E(cmGotoNo);
      E(cmcProfileEditor);
    }
    else
    {
      D(cmToggleBreak);
      D(cmGoto);
      D(cmGotoNo);
      D(cmcProfileEditor);
    }
    if (!has_project && !has_editors)
    {
      D(cmAddWatchEntry);
      D(cmBreakPoints);
      D(cmRun);
      D(cmStep);
      D(cmTrace);
      D(cmGoto);
      D(cmStepNo);
      D(cmTraceNo);
      D(cmGotoNo);
      D(cmReset);
      D(cmProgArgs);
      D(cmFunctionList);
    }
    else
    {
      E(cmAddWatchEntry);
      E(cmBreakPoints);
      E(cmRun);
      E(cmStep);
      E(cmTrace);
      E(cmGoto);
      E(cmStepNo);
      E(cmTraceNo);
      E(cmGotoNo);
      E(cmReset);
      E(cmProgArgs);
      E(cmFunctionList);
      E(cmCallStack);
    }
  }

  if ((!has_project && !has_editors) || (has_project && !project_count))
  {
    D(cmMake);
    D(cmBuild);
    D(cmLink);
    D(cmRun);
    D(cmGDB);
    D(cmFSDB);
  }
  else
  {
    E(cmMake);
    E(cmBuild);
    E(cmLink);
    if (!target_is_exec)
    {
      D(cmRun);
      D(cmGDB);
      D(cmFSDB);
    }
    else
    {
      E(cmRun);
      E(cmGDB);
      E(cmFSDB);
    }
  }

  if (current_is_editor || current_is_fileview )
  {
    E(cmSave);
  }
  else
  {
    D(cmSave);
  }

  if (current_is_editor || current_is_clip)
  {
    E(cmSyntaxHelp);
    E(cmcExpandAllTabs);
    E(cmcCompactBuffer);
    E(cmcFind);
    E(cmcReplace);
    E(cmcSearchAgain);
    E(cmGotoLine);
    E(cmcJumpToFunction);
    E(cmcRecordMacro);
    E(cmcStopMacro);
    E(cmcPlayMacro);
    if (clipWindow->editor->hasSelection())
    {
      E(cmcPaste);
    }
    else
    {
      D(cmcPaste);
    }
    if (((TCEditWindow *)TProgram::deskTop->current)->editor->hasSelection())
    {
      E(cmcCut);
      E(cmcCopy);
      E(cmcClear);
    }
    else
    {
      D(cmcCut);
      D(cmcCopy);
      D(cmcClear);
    }
  }
  else
  {
    D(cmSyntaxHelp);
    D(cmcExpandAllTabs);
    D(cmcCompactBuffer);
    D(cmcFind);
    D(cmcReplace);
    D(cmcSearchAgain);
    D(cmGotoLine);
    D(cmcJumpToFunction);
    D(cmcRecordMacro);
    D(cmcStopMacro);
    D(cmcPlayMacro);
    D(cmcPaste);
    D(cmcCut);
    D(cmcCopy);
    D(cmcClear);
  }

  if (current_is_help)
  {
#define IW (((TInfWindow *)InfWindow)->viewer)
    if (IW->selRowEnd > IW->selRowStart ||
        (IW->selRowEnd == IW->selRowStart &&
         IW->selColEnd >  IW->selColStart))
#undef IW
    {
      E(cmcCopy);
    }
    else
    {
      D(cmcCopy);
    }
    E(cmcFind);
  }

  if (has_editors)
  {
    E(cmSaveAll);
  }
  else
  {
    D(cmSaveAll);
    D(cmcUndo);
    D(cmcRedo);
  }

  if (msg_window)
  {
    E(cmNextMessage);
    E(cmPrevMessage);
  }
  else
  {
    D(cmNextMessage);
    D(cmPrevMessage);
  }

  if (current_is_editor || (current_is_project && project_count))
  {
    E(cmCompile);
  }
  else
  {
    D(cmCompile);
  }

  if (dual_display)
  {
    D(cmUserScreen);
  }
  else
  {
    E(cmUserScreen);
  }
  if (external_program_executed)
  {
    external_program_executed = 0;
    check_for_external_modifications();
  }
  should_update = 0;
}

#undef D
#undef E

int update_flag = 1;

void IDE::idle()
{
  TEditorApp::idle();
  if (update_flag > 0) update();
}

void SetMainTargetName(const char *name,TProject *_prj)
{
  TProject *prj = _prj ? _prj : project;
  if ((!_prj) && (!prj->dest_name || strcmp(name,FName(prj->dest_name))))
    already_maked = 0;
  if (prj->dest_name)
    delete prj->dest_name;
  InitFName(prj->dest_name,name);
  prj->dest_file_type = get_file_type(name);
  if (prj->source_name)
  {
    prj->source_file_type = get_file_type(FName(prj->source_name));
    prj->compile_id = how_to_compile(prj->source_file_type,
                                     prj->dest_file_type);
    return;
  }
  prj->source_file_type = FILE_UNKNOWN;
  prj->compile_id = how_to_compile(FILE_OBJECT,
                                   prj->dest_file_type);
}

void TargetName()
{
  char buffer[256];
  strcpy(buffer,FName(Project.dest_name));
  if (HistinputBox(_("Name of the main target"),_("~N~ame"),
      buffer,255,RHIDE_History_main_targetname) == cmOK)
  {
    SetMainTargetName(buffer);
  }
}

static void GotoLine(TCFileEditor *editor)
{
  int line=editor->curPos.y+1;
  char temp[10];
  if (editor->IslineInEdition)
    editor->MakeEfectiveLineInEdition();
//  if (editor->limit.y == 0) return;
  sprintf(temp,"%d",line);
  if (ValidInputBox(_("Goto the line"),_("line ~n~umber"),
                 temp,10
                 ,new TRangeValidator(1,editor->limit.y == 0?
                      1:editor->limit.y)) == cmOK)
  {
    sscanf(temp,"%d",&line);
    editor->lock();
    editor->MoveCursorTo(editor->curPos.x,line-1);
    editor->trackCursor(True);
    editor->unlock();
  }
}

void Repaint()
{
  if (NoShadows) DisableShadows();
  else EnableShadows();
//  TProgram::deskTop->redraw();
  TProgram::application->Redraw();
//  message(TProgram::application,evBroadcast,cmRedraw,NULL);
  update_mem(1);
}

void IDE::dosShell()
{
  char *directory;
  if (!SaveAll())
    return;
  if (!SaveProjectOnlyWhenClosing) SaveProject();
  App->suspend();
  directory = getcwd(NULL,PATH_MAX);
#ifdef __DJGPP__
  if (debug_commands)
  {
    fprintf(stderr,"%s: %s\n",_("executing: "),"calling system(NULL)");
  }
  system(NULL); // let system() choose the correct shell
#else
  char *sh = expand_spec("$(SHELL)");
  if (!*sh) sh = string_dup("/bin/sh");
  // I hope any usual shell accepts the -i switch
  string_cat(sh," -i");
  if (debug_commands)
  {
    fprintf(stderr,"%s: %s\n",_("executing: "),sh);
  }
  system(sh);
  string_free(sh);
#endif
  chdir(directory);
  free(directory);
  App->resume();
  check_for_external_modifications();
  Repaint();
  ClearFileHash();
  ClearFindCache();
  already_maked = 0;
}

static void About()
{
  TDialog *dialog;
  TStaticText *text;
  char buffer[1000];
  dialog = new TDialog(TRect(0,0,60,16),_("About RHIDE"));
  dialog->options |= ofCentered;
  sprintf(buffer,"\003%s\n"
                 "\003(%s)\n"
       "\003\n"
       "\003%s\n"
       "\003%s\n\003\n"
       "\003%s\n",
       IDEVersion,
                 build_date,
       _("RHIDE is an Integrated Development Environment"),
#ifdef __DJGPP__
       _("for developing DJGPP apps"),
#endif
#ifdef __linux__
       _("for developing Linux apps"),
#endif
       _("Copyright (C) by Robert H”hne, 1996,1997"));
  text = new TStaticText(TRect(0,0,50,9),buffer);
  text->options |= ofCentered;
  dialog->insert(text);
  dialog->insert(new TButton(TRect(25,11,35,13),_("~O~K"),cmOK,bfDefault));
  TProgram::deskTop->execView(dialog);
  destroy(dialog);
}

static int help_request = 0;
static ushort help_ctx;

void IDE::getEvent(TEvent & event)
{
  TEditorApp::getEvent(event);
  if (help_request && event.what == evNothing)
  {
    event.what = evCommand;
    event.message.command = cmHelp;
  }
  switch (event.what)
  {
    case evCommand:
      switch (event.message.command)
      {
        case cmEnter:
          event.what = evKeyDown;
          event.keyDown.keyCode = RawkbSpace;
          break;
        case cmHelp:
//          if (InfWindow) break;
          if (help_request)
          {
            help_request = 0;
            Help(help_ctx);
          }
          else
          {
            help_request = 1;
            help_ctx = getHelpCtx();
            event.message.command = 0xFFFF;
            break;
          }
          clearEvent(event);
          break;
        default:
          break;
      }
    default:
      break;
  }
  if (event.what != evNothing &&
      event.what != evMouseMove)
    should_update = 1;
}

#define SC(command)\
   case cm##command:\
     command();\
     clearEvent(event);\
     break

#define SC2(command,function)\
   case cm##command:\
     function();\
     clearEvent(event);\
     break

#define SC3(command,function)\
   case cm##command:\
     function;\
     clearEvent(event);\
     break

/*
Return NULL or an allocated string.
*/

char *WUC()
{
  char *word;
  TEvent event;
  if (!TProgram::deskTop->current) return NULL;
  event.what = evBroadcast;
  event.message.command = cmEditorAnswer;
  TProgram::deskTop->current->handleEvent(event);
  if (event.what != evNothing) return NULL;
#define E ((TCEditWindow *)TProgram::deskTop->current)->editor
  word = E->WordUnderCursor();
  if (!word) // try to get the word before the cursor
  {
    int x = E->curPos.x;
    if (x > 0)
    {
      E->MoveCursorTo(x-1,E->curPos.y);
      word = E->WordUnderCursor();
      E->MoveCursorTo(x,E->curPos.y);
    }
  }
#undef E
  return word;
}

unsigned long hasmodified = 0;

int SaveAll()
{
  int i;
  int failed = 0;
  TEvent event;
  if (hasmodified && windows) 
  {
    int count = windows->getCount();
    TWindow *window;
    for (i=0;i<count;i++)
    {
      window = DESKTOPWINDOW(i);
      event.what = evBroadcast;
      event.message.command = cmEditorAnswer;
      window->handleEvent(event);
      if (event.what == evNothing)
      {
        event.what = evCommand;
        event.message.command = cmSave;
        window->handleEvent(event);
        if (((TCEditWindow *)window)->editor->modified == True)
        // it was not saved
          failed++;
      }
    }
    if (!failed)
    {
      hasmodified = 0;
      // If the user calls this function direct, I should remember,
      // that the project should remake
      already_maked = 0;
    }
  }
  if (failed)
    return 0;
  else
    return 1;
}

static void ShowEditor(char *name,int line,Boolean only_focus,char *msg)
{
  TCEditWindow *ewindow;
  ewindow = is_on_desktop(name,False);
  if (!ewindow && only_focus == True) return;
  if (!ewindow)
  {
    ewindow = OpenEditor(name,True);
  }
  TProgram::deskTop->lock();
  TView *c = TProgram::deskTop->current;
  ewindow->select();
  if (only_focus == True)
    c->select();
  TProgram::deskTop->unlock();
  goto_line(ewindow->editor,line);
  if (only_focus == False && msg)
  {
    ewindow->editor->setStatusLine(msg);
  }
}

#ifdef __DJGPP__
static char *nl2crlf(char *t)
{
  int nl_count = 0;
  char *s=t;
  while ((s = strchr(s,'\n')) != NULL)
  {
    s++;
    nl_count++;
  }
  if (!nl_count)
    return t;
  s = (char *)malloc(strlen(t)+nl_count+1);
  char *tt = t;
  char *ss = s;
  while (*tt)
  {
    if (*tt == '\n')
      *ss++ = '\r';
    *ss++ = *tt++;
  }
  *ss = 0;
  free(t);
  return s;
}
#endif

static void BugReport(int full=1)
{
  TCheckDialog *d = new TCheckDialog(TRect(10,5,40,10),_("Please wait"));
  TProgram::deskTop->insert(d);
  d->update(_("Creating the Bug report"));
  TProgram::deskTop->lock();
  TCEditWindow *ew = App->openEditor(NULL, True);
  TCEditor *e = ew->editor;
  char *_text = create_bug_report(full);
#ifdef __DJGPP__
  _text = nl2crlf(_text);
#endif
  e->insertText(_text,strlen(_text),False);
  string_free(_text);
  e->trackCursor(True);
  TProgram::deskTop->unlock();
  destroy(d);
}

#ifdef INTERNAL_DEBUGGER
static void MainFunction()
{
  char buffer[256];
  if (Project.main_function) strcpy(buffer,Project.main_function);
  else buffer[0] = 0;
  if (inputBox(_("Name of the main function"),_("~N~ame"),
      buffer,255) == cmOK)
  {
    string_free(Project.main_function);
    string_dup(Project.main_function,buffer);
  }
}
#endif

void IDE::handleEvent(TEvent & event)
{
  static char *callstack_name = NULL;
  static char *WindowMsg = NULL;
  static Boolean Focus;
  switch (event.what)
  {
    case evMouseDown:
      switch (event.mouse.buttons)
      {
        case mbRightButton:
          event.mouse.buttons = mbLeftButton;
          handleEvent(event);
          if (TProgram::deskTop->current && InfWindow &&
              (TView *)TProgram::deskTop->current == (TView *)InfWindow)
          {
            event.what = evKeyDown;
            event.keyDown.keyCode = kbCtrlS;
          }
          else
          {
            if (TProgram::deskTop->current)
            {
              event.what = evBroadcast;
              event.message.command = cmEditorAnswer;
              TProgram::deskTop->current->handleEvent(event);
              if (event.what == evNothing)
              {
                event.what = evCommand;
                event.message.command = cmSyntaxHelp;
              }
              else
                clearEvent(event);
            }
            else
              clearEvent(event);
          }
          break;
        default:
          break;
      }
      break;
    case evBroadcast:
      switch (event.message.command)
      {
        case cmFocusWindow:
          Focus = True;
        case cmOpenWindow:
          string_dup(callstack_name,(char *)event.message.infoPtr);
          clearEvent(event);
          break;
        case cmShowWindowMsg:
          string_dup(WindowMsg,(char *)event.message.infoPtr);
          clearEvent(event);
          break;
        case cmGotoWindowLine:
          if (!callstack_name) break;
          ShowEditor(callstack_name,event.message.infoInt,Focus,WindowMsg);
          string_free(callstack_name);
          string_free(WindowMsg);
          Focus = False;
          clearEvent(event);
          break;
        case cmEditorFilenameChanged:
        {
          TIDEFileEditor *e = (TIDEFileEditor *)event.message.infoPtr;
          UpdateWindow((TWindow *)e->owner); // update the windowlist
          TimeOfFile(e->fileName,True);
          clearEvent(event);
          break;
        }
        case cmEditorModified:
          hasmodified = (unsigned long)event.message.infoLong;
          clearEvent(event);
          break;
        default:
          break;
      }
      break;
    case evCommand:
      switch (event.message.command)
      {
        case cmEnter:
          event.what = evKeyDown;
          event.keyDown.keyCode = RawkbSpace;
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
  TEditorApp::handleEvent(event);
  switch (event.what)
  {
    case evCommand:
      switch (event.message.command)
      {
        case cmSetGlobalOptions:
          TCEditor::SetGlobalOptions();
          clearEvent(event);
          break;
        case cmAscii:
          if (!AsciiWindow)
          {
            Ascii();
            AddWindow(AsciiWindow,&AsciiWindow);
          }
          AsciiWindow->select();
          clearEvent(event);
          break;
        case cmPuzzle:
          if (!PuzzleWindow)
          {
            Puzzle();
            AddWindow(PuzzleWindow,&PuzzleWindow);
          }
          PuzzleWindow->select();
          clearEvent(event);
          break;
        case cmCalendar:
          if (!CalendarWindow)
          {
            Calendar();
            AddWindow(CalendarWindow,&CalendarWindow);
          }
          CalendarWindow->select();
          clearEvent(event);
          break;
        SC(SyntaxIndex);
        SC(SyntaxOptions);
        SC(BugReport);
        case cmBugReportSmall:
          BugReport(0);
          clearEvent(event);
          break;
        SC(MouseDlg);
        SC(SaveOptions);
        SC(LoadOptions);
        SC(FSDB);
        SC(GDB);
        SC(EditReserved);
        SC(EditGPCReserved);
        SC(About);
        SC(EditCFlags);
        SC(EditCXXFlags);
        SC(EditPascalFlags);
        SC(EditFortranFlags);
        SC(EditOptFlags);
        SC(EditWarnFlags);
        SC(EditDebugFlags);
        SC(Preferences);
        SC(GREP);
        SC(Repaint);
        SC(Colors);
        SC(WriteMake);
        SC(Libraries);
        SC(WarningFlags);
        SC(OptimizationFlags);
        SC(DebugFlags);
        SC(CFlags);
        SC(CXXFlags);
        SC(PascalFlags);
        SC(FortranFlags);
        SC(AddProjectItem);
        SC(DelProjectItem);
        SC(ShowProject);
        SC(TargetName);
        SC(ShowIncludes);
        SC(LocalOptions);
        SC(LinkerOptions);
        SC(CompilerOptions);
        SC(Make);
        SC(Build);
        SC(EditUserWords);
        SC(ClearDependencies);
        SC(MakeClear);
        SC(HelpIndex);
        SC(SaveAll);
#ifdef INTERNAL_DEBUGGER
        case cmCallStack:
          ShowCallStackWindow();
          clearEvent(event);
          break;
        SC2(Trace,TRACE);
        SC2(Step,STEP);
        SC2(Goto,GOTO);
        SC3(TraceNo,TRACE(0));
        SC3(StepNo,STEP(0));
        SC3(GotoNo,GOTO(0));
        SC2(Reset,RESET);
        SC(MainFunction);
        case cmBreakPoints:
          BreakDialog();
          Repaint();
          break;
        SC(ToggleBreak);
        case cmEvaluate:
          Evaluate(WUC());
          clearEvent(event);
          break;
        case cmAddWatchEntry:
          AddWatchEntry(WUC());
          clearEvent(event);
          break;
        case cmFunctionList:
        {
          char regex[256];
          function_entry *func;
          regex[0] = 0;
          if (HistinputBox(_("Regular expression to list functions"),
                 _("~E~xpression"),regex,255,tvgdb_History_Break_Function)
                       == cmOK)
          {
            if (SelectFunction(_("List of functions"),regex,NULL,NULL,&func)
                == cmOK)
            {
              TCEditWindow *ew = is_on_desktop(func->file_name);
              if (!ew)
              {
                char *full_name;
                if (FindFile(func->file_name,full_name) == False)
                {
                  messageBox(mfError | mfOKButton,
                    _("Could not find the source file %s."),func->file_name);
                  string_free(full_name);
                  full_name = (char *)malloc(PATH_MAX);
                  TFileDialog *dialog;
                  InitHistoryID(RHIDE_History_source_file);
                  dialog = new TFileDialog(func->file_name,_("Open a file"),
                         _("~N~ame"),fdOpenButton,RHIDE_History_source_file);
                  if (TProgram::deskTop->execView(dialog) != cmCancel)
                  {
                    dialog->getData(full_name);
                    FExpand(full_name);
                  }
                  else full_name = NULL;
                }
                if (full_name) ew = OpenEditor(full_name,False);
              }
              if (ew)
              {
                goto_line(ew->editor,func->line_number);
                ew->select();
              }
            } 
          }
          clearEvent(event);
          break;
        }
#endif
        case cmShowWindowList:
          ShowWindowList(_("WindowList"));
          clearEvent(event);
          break;
        case cmSelectProject:
        {
          char *dir,*name,*ext,*prj;
          TDependency *dep = (TDependency *)event.message.infoPtr;
          split_fname(FName(dep->dest_name),dir,name,ext);
          string_dup(prj,FName(dep->source_name));
          if (*dir)
            dir[strlen(dir)-1] = 0;
          AddToStack();
          CloseProject();
          chdir(dir);
          string_free(dir);
          string_free(name);
          string_free(ext);
          OpenProject(prj);
          string_free(prj);
          clearEvent(event);
          break;
        }
        case cmSyntaxHelp:
        {
          char *word = WUC();
          if (word) SyntaxHelp(word,NULL);
          else SyntaxHelp("",NULL);
          if (word) string_free(word);
          clearEvent(event);
          break;
        }
        case cmGotoLine:
        {
          TView *ew = TProgram::deskTop->current;
          event.what = evBroadcast;
          event.message.command = cmEditorAnswer;
          if (ew != NULL)
          {
            ew->handleEvent(event);
            if (event.what == evNothing)
              GotoLine(((TCEditWindow *)ew)->editor);
          }
          clearEvent(event);
          break;
        }
        case cmNextMessage:
          event.message.command = cmNextMsg;
          if (msg_window) msg_window->handleEvent(event);
          break;
        case cmPrevMessage:
          event.message.command = cmPrevMsg;
          if (msg_window) msg_window->handleEvent(event);
          break;
        case cmRun:
        if (DEBUGGER_STARTED())
        {
          CONTINUE();
          clearEvent(event);
          break;
        }
        else
        {
          TView *lasteditor = NULL;
               TView *v = TProgram::deskTop->current;
               if (v)
               {
            event.what = evBroadcast;
               event.message.command = cmEditorAnswer;
            v->handleEvent(event);
            if (event.what == evNothing)
            {
              if (v->state & sfSelected)
              {
                lasteditor = TProgram::deskTop->current;
              }
                 }
          }
          ShowMessages(NULL,True);
          if (Make(False) == True)
          {
            RunMainTarget();
                 if (!DEBUGGER_STARTED() && lasteditor != NULL &&
                     !ShowStderr && !ShowStdout)
                   lasteditor->select();
          }
          clearEvent(event);
          break;
        }
        case cmCompile:
         if (DEBUGGER_STARTED()) RESET();
         ShowMessages(NULL,True);
         Compile();
         clearEvent(event);
         break;
       case cmLink:
         if (DEBUGGER_STARTED()) RESET();
         ShowMessages(NULL,True);
         Compile(project);
         clearEvent(event);
         break;
       case cmStandardIncludeDir:
         EditDirList(Options.StdInc,_("Standard Include Directories"),
                          RHIDE_History_standard_include_directories);
         clearEvent(event);
         break;
       case cmIncludeDir:
         EditDirList(Options.include_path,_("Include Directories"),
                          RHIDE_History_include_directories);
         clearEvent(event);
         break;
       case cmLibDir:
         EditDirList(Options.library_path,_("Library Directories"),
                          RHIDE_History_library_directories);
         clearEvent(event);
         break;
       case cmObjDir:
         EditDirList(Options.ObjDirs,_("Object Directories"),
                          RHIDE_History_object_directories);
         clearEvent(event);
         break;
       case cmSrcDir:
         EditDirList(Options.SrcDirs,_("Source Directories"),
                          RHIDE_History_source_directories);
         clearEvent(event);
         break;
            case cmSyntaxFiles:
         EditParamList(Project.info_files,_("INFO files for syntaxhelp"),
                            RHIDE_History_info_files);
         clearEvent(event);
         break;
       case cmProgArgs:
         EditParamList(Options.ProgArgs,_("Program arguments"),
                            RHIDE_History_arguments);
         clearEvent(event);
         break;
       case cmOpenProject:
       {
         ushort result;
         TFileDialog *dialog;
         char *fileName = NULL,*dir;
         InitHistoryID(RHIDE_History_project_file);
         dialog = new TFileDialog("*"PROJECT_EXT,_("Select a project"),
                       _("~N~ame"),fdOpenButton,RHIDE_History_project_file);
         TProgram::deskTop->insert(dialog);
         dialog->setState(sfModal,True);
         result = dialog->execute();
         if( result != cmCancel )
         {
           string_dup(fileName,dialog->fileName->data);
           string_dup(dir,dialog->directory);
         }
         TProgram::deskTop->remove(dialog);
         destroy(dialog);
         if (result != cmCancel )
         {
           CloseProject();
           chdir(dir);
           string_free(dir);
           OpenProject(fileName);
           string_free(fileName);
         }
         clearEvent(event);
         break;
       }
       case cmCloseProject:
         CloseProject();
         if (!OpenFromStack()) OpenProject(NULL);
         clearEvent(event);
         break;
       case cmUserScreen:
       {
         TMouse::suspend();
         update_flag--;
#ifdef __DJGPP__
         TScreen::suspend();
#else
         RestoreScreen();
#endif
         do
         {
           clearEvent(event);
           event.getKeyEvent();
         } while (event.what == evNothing);
         clearEvent(event);
#ifdef __DJGPP__
         TScreen::resume();
#endif
         update_flag++;
         TMouse::resume();
         Repaint();
         break;
       }
       case cmLibcHelp:
         SyntaxHelp("Top","libc");
         clearEvent(event);
         break;
       case cmHelpHelp:
         SyntaxHelp("Top","infview");
         clearEvent(event);
         break;
       case cmPrimaryFile:
       {
         char buffer[256];
         if (Project.source_name) strcpy(buffer,FName(Project.source_name));
         else buffer[0] = 0;
         if (inputBox(_("Name of the main target"),_("~N~ame"),
             buffer,255) == cmOK)
         {
           if (strlen(buffer) > 0 &&
               get_file_type(buffer) != FILE_PASCAL_SOURCE)
           {
             messageBox(_("You can give here only a valid "
                          "filename for a Pascal source file"),
                        mfError|mfOKButton);
           }
           else
           {
             if (!Project.source_name && strlen(buffer) > 0 ||
                 Project.source_name && strcmp(FName(Project.source_name),buffer))
               already_maked = 0;
             if (Project.source_name)
             {
               delete Project.source_name;
               Project.source_name = NULL;
             }
             if (strlen(buffer) > 0) InitFName(Project.source_name,buffer);
             SetMainTargetName(FName(Project.dest_name));
           }
         }
         break;
       }
       default:
         break;
     }
     break;
  }
}

IDE *App;

static char * PRJNAME = NULL;
static char * EDITNAME = NULL;

static void usage() __attribute__((noreturn));
static void usage()
{
  TEventQueue::suspend();
  TScreen::suspend();
  fprintf(stderr,_("usage: %s [options] [project-file] [edit-file]\n"),RHIDE_NAME);
  fprintf(stderr,_("options:    -d[actdf]\n"));
#ifdef __DJGPP__
  fprintf(stderr,_("            -c : show filename exactly (no case conversion)\n"));
  fprintf(stderr,_("            -y : force to use long filenames (Windows 95)\n"));
  fprintf(stderr,_("            -n : do not use long filenames (Windows 95)\n"));
  fprintf(stderr,_("            -b : use BIOS calls for toggle the blinkstate\n"));
  fprintf(stderr,_("            -p : do not convert the numpad keys\n"));
  fprintf(stderr,_("            -G num : Use methode <num> for screen swapping\n"));
  fprintf(stderr,_("            -K : Use the BIOS for keyboard input\n"));
  fprintf(stderr,_("            -M : Do not install the mouse handler\n"));
  fprintf(stderr,_("            -S : use slower (safer) screen output\n"));
#endif
#ifdef __linux__
  fprintf(stderr,_("            -K : Do not patch the keytable\n"));
  fprintf(stderr,_("            -H : Do not install console switch handler\n"));
#endif
  fprintf(stderr,_("            -L LANGUAGE : use language LANGUAGE\n"));
  fprintf(stderr,_("            -h : show this help\n"));
  fprintf(stderr,_("            -k KEY_FILE : use KEY_FILE for key bindings\n"));
  fprintf(stderr,_("            -E : Output all env. variables and exit\n"));
  fflush(stderr);
  exit(-1);
}

char *ExpandFileNameToThePointWhereTheProgramWasLoaded(char *s);
static char *keybindings=NULL;

static char *next_option(char *&option,char *option_end,int &current_argc,
                         int argc,char *argv[])
{
  static char arg[256];
  if (option && *option && option <= option_end)
  {
    char *tmp = arg;
    while (option <= option_end && *option != ' ')
    {
      *tmp++ = *option++;
    }
    *tmp = 0;
    option++;
    return arg;
  }
  if (current_argc >= argc) return NULL;
  current_argc++;
  return argv[current_argc-1];
}

static int call_usage = 0;
static int dump_env = 0;

#define Usage() do { call_usage = 1; return; } while (0)

static void parse_commandline(int argc,char *argv[])
{
  /* At first look for an environment variable $(RHIDEOPT) and
     use the options from that variable as they were put at the
     beginning of the commandline, so they can be overwritten */
  char *_rhide_opt = expand_spec("$(RHIDEOPT)",NULL);
  char *rhide_opt = NULL;
  if (*_rhide_opt)
  {
    rhide_opt = (char *)alloca(strlen(_rhide_opt));
    strcpy(rhide_opt,_rhide_opt);
  }
  string_free(_rhide_opt);
  char *rhide_opt_end=NULL;
  int i=1;
  char *tmp,*a="a";
  char *arg;
  if (rhide_opt && *rhide_opt)
  {
    // strip leading whitespaces
    while (*rhide_opt == ' ') rhide_opt++;
    if (*rhide_opt)
    {
      // skip trailing whitespaces
      rhide_opt_end = rhide_opt + strlen(rhide_opt) - 1;
      while (*rhide_opt_end == ' ') rhide_opt_end--;
    }
  }
  while ((arg = next_option(rhide_opt,rhide_opt_end,i,argc,argv)) != NULL)
  {
    if (arg[0] == '-')
    {
      switch (arg[1])
      {
        case 'H':
#ifdef __linux__
          extern int install_console_sigs;
          install_console_sigs = 0;
#endif
          break;
        case 'S':
#ifdef __DJGPP__
          extern int slow_screen;
          slow_screen = 1;
#endif
          break;
        case 'E':
          dump_env = 1;
          break;
        case 'M':
#ifdef __DJGPP__
          extern int use_mouse_handler;
          use_mouse_handler = 0;
#endif
          break;
        case 'K':
#if defined( __DJGPP__ ) || defined( __linux__ )
          extern int use_real_keyboard_bios;
          use_real_keyboard_bios = 1;
#endif
          break;
        case 'G':
#ifdef __DJGPP__
          extern int screen_saving;
          arg = next_option(rhide_opt,rhide_opt_end,i,argc,argv);
          if (!arg) Usage();
          screen_saving = atoi(arg);
#endif
          break;
        case 'p':
          extern int convert_num_pad;
          convert_num_pad = 0;
          break;
        case 'k':
          arg = next_option(rhide_opt,rhide_opt_end,i,argc,argv);
          if (!arg) Usage();
          keybindings =
            ExpandFileNameToThePointWhereTheProgramWasLoaded(arg);
          break;
        case 'b':
        {
          extern int blink_use_bios;
          blink_use_bios = 1;
          break;
        }
        case 'c':
#ifdef __DJGPP__
          _crt0_startup_flags |= _CRT0_FLAG_PRESERVE_FILENAME_CASE;
#endif
          break;
        case 'y':
#ifdef __DJGPP__
          putenv("LFN=y");
#endif
          break;
        case 'n':
#ifdef __DJGPP__
          putenv("LFN=n");
          _crt0_startup_flags |= _CRT0_FLAG_NO_LFN;
#endif
          break;
        case 'L':
        {
          static char language[256];
          arg = next_option(rhide_opt,rhide_opt_end,i,argc,argv);
          if (!arg) Usage();
          strcpy(language,"LANGUAGE=");
          strcat(language,arg);
          putenv(language);
          break;
        }
        case 'h':
          Usage();
        case 'd':
          if (!arg[2]) tmp = a;
          else tmp = &arg[2];
          while (*tmp)
          {
            switch (*tmp)
            {
              case 'f':
                debug_files = 1;
                break;
              case 'd':
                debug_dependencies = 1;
                break;
              case 'a':
                debug_dependencies = 1;
                debug_commands = 1;
                debug_tempfiles = 1;
                debug_files = 1;
                break;
              case 'c':
                debug_commands = 1;
                break;
              case 't':
                debug_tempfiles = 1;
                break;
              default:
                Usage();
            }
            tmp++;
          }
          break;
        default:
          Usage();
      }
    }
    else
    {
      char *dir,*file,*ext;
      string_dup(PRJNAME,arg);
      split_fname(PRJNAME,dir,file,ext);
      string_free(PRJNAME);
      if (!ext || !*ext || strcasecmp(ext,PROJECT_EXT) == 0)
      {
        string_dup(PRJNAME,dir);
        string_cat(PRJNAME,file);
        string_cat(PRJNAME,PROJECT_EXT);
      }
      else
      {
        string_dup(EDITNAME,arg);
        FExpand(EDITNAME);
      }
      string_free(dir);
      string_free(file);
      string_free(ext);
    }
  }
}

static void find_project()
{
// I can assume, that PRJNAME == NULL, when calling this
#if 0
  struct ffblk ff;
  int result;
  result = findfirst("*"PROJECT_EXT,&ff,FA_RDONLY | FA_ARCH);
  if (result != 0) return;
  string_dup(PRJNAME,ff.ff_name);
#else // I'm using now glob
  glob_t found;
  // I must initialize that, because I call glob NOT with GLOB_NOCHECK
  // and so glob can return without finding any. But globfree assumes,
  // that gl_pathv == NULL, if there is nothing found
  found.gl_pathv = NULL;
  found.gl_pathc = 0;
  glob("*"PROJECT_EXT,0,NULL,&found);
  if (found.gl_pathc == 1)  // only one was found
    string_dup(PRJNAME,found.gl_pathv[0]);
  globfree(&found);
  if (!PRJNAME) return;
#endif
#if 0 // Is this realy needed ??
  /* The two functions below convert the name to the correct case */
  FExpand(PRJNAME);
  BaseName(PRJNAME);
#endif
#if 0 // only when using findfirst
  if (findnext(&ff) != 0) return;
  string_free(PRJNAME);
  PRJNAME = NULL;
#endif
}

static char *tmpdir = NULL;

static
void set_tmpdir()
{
  char temp_mask[256] = "RHXXXXXX";
#ifndef __DJGPP__
  char buf[256];
  time_t curtime;
  time(&curtime);
  strftime(buf,256,"%Y%m%d%H%M%S",localtime(&curtime));
  sprintf(temp_mask,"RHIDE.%s.%d",buf,getpid());
#endif
  tmpdir = expand_spec("$(TMPDIR)",NULL);
  if (!*tmpdir)
  {
    string_free(tmpdir);
    tmpdir = expand_spec("$(TEMP)",NULL);
  }
  if (!*tmpdir)
  {
    string_free(tmpdir);
    tmpdir = expand_spec("$(TMP)",NULL);
  }
  if (!*tmpdir)
  {
    string_free(tmpdir);
#ifdef __DJGPP__
    tmpdir = NULL;
    tmpdir = getcwd(NULL,PATH_MAX);
#else
    string_dup(tmpdir,"/tmp");
#endif
  }
  BackslashToSlash(tmpdir);
  if (tmpdir[strlen(tmpdir)-1] != '/') string_cat(tmpdir,"/");
  string_cat(tmpdir,temp_mask);
#ifdef __DJGPP__
  mktemp(tmpdir);
#endif
  if (mkdir(tmpdir,0755) != 0)
  {
    string_free(tmpdir);
    tmpdir = getcwd(NULL,PATH_MAX);
    string_cat(tmpdir,"/");
    string_cat(tmpdir,temp_mask);
    mktemp(tmpdir);
    mkdir(tmpdir,0755);
  }
  char *tempdir = string_dup("TMPDIR=");
  string_cat(tempdir,tmpdir);
  putenv(tempdir);
  if (debug_tempfiles)
  {
    fprintf(stderr,_("using %s as temp directory\n"),tmpdir);
  }
}

static __attribute__ (( __destructor__ ))
void remove_tmpdir()
{
  if (!debug_tempfiles && tmpdir) rmdir(tmpdir);
}

static void setup_argv0()
{
  char *tmp;
  string_dup(tmp,global_argv[0]);
  FExpand(tmp);
  split_fname(tmp,RHIDE_DIR,RHIDE_NAME,RHIDE_EXT);
}

static char startup_directory[256];

int DebuggerFormatLine(TCEditor *editor,
                       void *DrawBuf,
                       unsigned LinePtr,
                       int Width,
                       unsigned short Colors,
                       unsigned lineLen,
                       unsigned short Attr,
                       unsigned LineNo);

#ifdef __DJGPP__
extern char **environ;
#endif

static void dump_environment() __attribute__((noreturn));
static void dump_environment()
{
  TMouse::suspend();
  TScreen::suspend();
  char **env = environ;
  dump_rhide_environment(stderr);
  while (*env)
  {
    fprintf(stderr,"%s\n",*env);
    env++;
  }
  exit(0);
}

#ifdef __DJGPP__
extern int __crt0_argc;
extern char **__crt0_argv;

static __attribute__ (( __constructor__ ))
void init_rhide(void)
#else
static
void init_rhide(int _argc, char **_argv)
#define __crt0_argc _argc
#define __crt0_argv _argv
#endif
{
#ifdef __DJGPP__
  __system_flags |= __system_allow_multiple_cmds;
  __crt0_load_environment_file("rhide"); // when the exe has an other name
                                         // than rhide force to load the
                                         // variables for RHIDE
  __crt0_load_environment_file("info");  // To get the INFO-path for bug-report
#endif
  rhide_load_environment_file("rhide","rhide.env");
  set_tmpdir();
  char *locale_dir = expand_spec("$(LOCALEDIR)",NULL);
#ifndef __DJGPP__
  if (!*locale_dir)
  {
    string_free(locale_dir);
    // get the system default localedir
    char *_locale_dir = BINDTEXTDOMAIN("rhide",NULL);
    if (_locale_dir)
      locale_dir = string_dup(_locale_dir);
    else
      locale_dir = string_dup("");
  }
#endif
  if (!*locale_dir)
  {
    string_free(locale_dir);
    locale_dir = expand_spec("$(DJDIR)",NULL);
    if (*locale_dir)
    {
      string_cat(locale_dir,"/share/locale");
    }
    else
    {
      string_free(locale_dir);
      locale_dir = string_dup("/usr/local/share/locale");
    }
  }
  setlocale(LC_ALL,"");
  BINDTEXTDOMAIN("rhide",locale_dir);
  string_free(locale_dir);
  TEXTDOMAIN("rhide");
  extern int convert_num_pad;
  convert_num_pad = 1;

  global_argv = __crt0_argv;
  global_argc = __crt0_argc;
  setup_argv0();

  parse_commandline(__crt0_argc,__crt0_argv);
#ifndef __DJGPP__
#if 1
  TEventQueue::suspend();
  TScreen::suspend();
#endif
#endif
  fprintf(stderr,_("This is %s. Copyright (c) 1996,1997 by Robert H”hne\n"),IDEVersion);
  fprintf(stderr,"             (%s %s)\n",build_date,build_time);
#ifndef __DJGPP__
#if 1
  TScreen::resume();
  TEventQueue::resume();
#endif
#endif
}

/*
   This string should not translated, because it is used, when there is
   something wrong.
*/

const char msg[] =
"RHIDE internal error. Please send a description of this situation\r\n"
"as most as possible detailed to the author together with the version\r\n"
"you are using."
#ifdef __DJGPP__
" AND VERY IMPORTANT IS THE NEXT TRACEBACK!!!!"
#endif
"\r\n\r\n";

static jmp_buf abort_jmp;

extern "C" __attribute__ (( __noreturn__ ))
void abort()
{
  char *bug;
  // call at least TEventQueue::resume() to clear the mouse hook
  TEventQueue::suspend();
  TScreen::suspend();
  bug = create_bug_report(0);
  write(STDERR_FILENO, bug, strlen(bug));
  write(STDERR_FILENO, msg, sizeof(msg)-1);
  setjmp(abort_jmp);
#ifdef __DJGPP__
  __djgpp_exception_state_ptr = &abort_jmp;
#endif
  raise(SIGABRT);
  _exit(1);
}

char *LoadKeyForTCEditorError(void);
int LoadKeysForTCEditor(char *file);
char *ExpandFileNameToThePointWhereTheProgramWasLoaded(char *s);

static void LoadKeys()
{
  if (!keybindings) keybindings =
    ExpandFileNameToThePointWhereTheProgramWasLoaded("keybind.txt");
  if (LoadKeysForTCEditor(keybindings))
  {
#if 0
  /* That's not real an error. */
    TScreen::suspend();
    fprintf(stderr,_("Error while loading the keybinding file %s\n"),
      keybindings);
    fprintf(stderr,_("The Error was: %s\n"),LoadKeyForTCEditorError());
    TScreen::resume();
#endif
  }
}

static void rhide_sig(int signo)
{
  static int intr_in_progress = 0;
  switch (signo)
  {
    case SIGINT:
      if (intr_in_progress)
        return;
      intr_in_progress = 1;
      if (messageBox(_("Do you really want to interrupt RHIDE?"),
             mfConfirmation|mfYesButton|mfNoButton) == cmYes)
      {
        destroy(App);
        chdir(startup_directory);
        exit(-1);
      }
      intr_in_progress = 0;
#ifdef __DJGPP__
      if (kbhit()) getch();
#endif
      signal(SIGINT,rhide_sig);
      break;
#ifndef __DJGPP__
    case SIGWINCH:
      signal(SIGWINCH,rhide_sig);
      TProgram::application->setScreenMode(TScreen::screenMode);
      Repaint();
      break;
    case SIGSEGV:
      remove_tmpdir();
      signal(SIGSEGV,SIG_DFL);
      // Try the best to restore all to default (keyboard, screen, mouse )
      destroy(App);
      chdir(startup_directory);
      raise(signo);
      break;
    case SIGTSTP:
      TProgram::application->suspend();
      signal(SIGTSTP,SIG_DFL);
      signal(SIGCONT,rhide_sig);
      raise(signo);
      break;
    case SIGCONT:
      chdir(project_directory);
      TProgram::application->resume();
      check_for_external_modifications();
      Repaint();
      ClearFileHash();
      ClearFindCache();
      already_maked = 0;
      signal(SIGCONT,SIG_DFL);
      signal(SIGTSTP,rhide_sig);
      raise(signo);
      break;
#endif
    default:
      break;
  }
}

static void init_signals()
{
  signal(SIGINT,rhide_sig);
#ifndef __DJGPP__
  signal(SIGTSTP,rhide_sig);
  signal(SIGTTOU,SIG_IGN);
  signal(SIGSEGV,rhide_sig);
  signal(SIGWINCH,rhide_sig);
#endif
}

#ifndef __DJGPP__
int main(int argc, char **argv)
{
  init_rhide(argc,argv);
#else
int main(int ,char **)
{
#endif
  if (call_usage)
    usage();
  if (dump_env)
    dump_environment();
  LoadKeys();
  getcwd(startup_directory,255);
#ifdef INTERNAL_DEBUGGER
  InitDebuggerInterface();
  TIDEFileEditor::externalFormatLine = DebuggerFormatLine;
#endif
  App = new IDE();
  init_signals();
  if (!PRJNAME) find_project();
#if 0 // The error is handled in OpenProject
  if (OpenProject(PRJNAME) == True)
#else
  OpenProject(PRJNAME);
#endif
  {
    if (!PRJNAME)
    {
      if (!EDITNAME) About();
      if (EDITNAME) App->openEditor(EDITNAME,True);
    }
    App->run();
    CloseProject();
  }
#ifndef __DJGPP__
  signal(SIGSTOP,SIG_DFL);
  signal(SIGINT,SIG_DFL);
  signal(SIGWINCH,SIG_DFL);
#endif
  destroy(App);
  chdir(startup_directory);
  return 0;
}

void IDE::fileOpen()
{
  ushort result;
  TFileDialog *dialog;
  InitHistoryID(RHIDE_History_source_file);
  dialog = FileOpenDialog(Project.defaultprojectmask,
                          _("Open a file"),_("~N~ame"),fdOpenButton|fdHelpButton,
                          RHIDE_History_source_file,default_directory);
  dialog->helpCtx = hcOpen;
  TProgram::deskTop->insert(dialog);
  dialog->setState(sfModal,True);
  result = dialog->execute();
  if( result != cmCancel )
  {
    char fileName[PATH_MAX];
    string_free(Project.defaultprojectmask);
    string_free(default_directory);
    string_dup(default_directory,dialog->directory);
    string_dup(Project.defaultprojectmask,dialog->wildCard);
    dialog->getData(fileName);
    TCEditWindow *win = is_on_desktop(fileName);
    if (win != NULL) win->select();
    else openEditor(fileName,True);
  }
  TProgram::deskTop->remove(dialog);
  destroy(dialog);
}


