/*----------------------------------------------------------*/
/*   Turbo Vision TVEDIT source file                        */
/*----------------------------------------------------------*/

// That's the first include because is used to configure the editor.
#include "ceditint.h"

#define Uses_TApplication
#define Uses_TDeskTop
#define Uses_TRect
#define Uses_TFileDialog
#define Uses_TChDirDialog
#define Uses_TStringCollection
#define Uses_fpstream
#define Uses_MsgBox
#define Uses_TCollection
#define Uses_TPalette
#define Uses_TCommandSet
#define Uses_TSortedListBox
#define Uses_TButton
#define Uses_TListBox
#define Uses_TScrollBar
#include <tv.h>

#define Uses_TCEditor
#define Uses_TCFileEditor
#define Uses_TCEditWindow
#include "ceditor.h"

#ifdef RHIDE
#define Uses_TEditorApp
#include "tvedit.h"
#else
#include "tvedit2.h"
#endif

#ifndef BIOS_KEYBOARD
#include "keyboard.h"
#endif

#include <stdlib.h>
#include <stdarg.h>
#include <iomanip.h>
#include <stdio.h>
#include <sys/stat.h>

#ifdef STANDALONE
#include "inf.h"
#include "edhelp.h"
#else
#define cInfColor
#define cInfBlackWhite
#define cInfMonochrome
#endif

#ifdef __GNUC__
#include <signal.h>
// #include <conio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <locale.h>
#define DESKTOP_FILE "TCEDIT.DST"
#else
#define DESKTOP_FILE "TVEDIT.DST"
//#define TEST_SPLINES
#endif

#ifdef USE_TSTRCOL
TStrCol *ReservedWords;
TStrCol *UserWords;
TStrCol *PascalRWords;
TStrCol *ClipperRWords;
#else
TStringCollection *ReservedWords;
TStringCollection *UserWords;
TStringCollection *PascalRWords;
TStringCollection *ClipperRWords;
#endif

#ifdef STANDALONE
void RemoveFromEditorsHelper(TCEditWindow *p);
void AddToEditorsHelper(TCEditWindow *p, int SelectHL=0);
int IsAnEditor(void *p);
TCEditWindow *IsAllreadyOnDesktop(char *fileName);
void BringListOfWindows(void);

class TEditorCollection;
TEditorCollection *edHelper=NULL;
const EditorsDelta=10;

void fexpand(char *);

TDskWinHelp *InfManager=NULL;
#endif

//#define DEBUG_HEAP
#ifdef DEBUG_HEAP
#include <conio.h>
#define TOLERATE_FREE_NULL
void *operator new(size_t size)
{
 void * p;

 size = size ? size : 1;
 p = malloc(size);
 if (p==NULL)
   {
    printf(_("Error memory exhausted!!!\n"));
    getch();
    exit(1);
   }
 memset(p,1,size);

 return p;
}

void operator delete(void *p)
{
 if (p==NULL)
   {
#ifndef TOLERATE_FREE_NULL
    printf(_("Error: pointer is NULL!!!\n"));
    getch();
    long pp=((long *)p)[0];
    printf("%lX\n",pp);
#endif
   }
 else
    free(p);
}
#endif

TEditorApp *editorApp;

#ifdef STANDALONE
//
// closeView() function
//

static void closeView(TView *p, void *p1)
{
    message(p, evCommand, cmClose, p1);
}
#endif

TCEditWindow *clipWindow;

#ifdef TEST_SPLINES
int spLines[]={10-1,15-1,20-1,splEndOfList};
#endif

// Palette support by Robert
#define _cpColor \
    "\x71\x70\x78\x74\x20\x28\x24\x17\x1F\x1A\x31\x31\x1E\x71\x00" \
    "\x37\x3F\x3A\x13\x13\x3E\x21\x00\x70\x7F\x7A\x13\x13\x70\x7F\x00" \
    "\x70\x7F\x7A\x13\x13\x70\x70\x7F\x7E\x20\x2B\x2F\x78\x2E\x70\x30" \
    "\x3F\x3E\x1F\x2F\x1A\x20\x72\x31\x31\x30\x2F\x3E\x31\x13\x00\x00" \
    "\x1E\x71" \
    "\x17\x12\x1E\x1F\x1B\x15\x16\x3F\x2B\x1D" "\x1A\x2C\x13\x00\x00\x1C" \
    "\x1E\x71" \
    "\x17\x12\x1E\x1F\x1B\x15\x16\x3F\x2B\x1D\x1A\x2C\x13\x00\x00\x1C" \
    "\x1E\x71" \
    "\x17\x12\x1E\x1F\x1B\x15\x16\x3F\x2B\x1D\x1A\x2C\x13\x00\x00\x1C" \
    /* cCrossCur, cStatusLi, cMPHighL, cRectSel */ \
    "\x70\x7C\x5F\x67\xF0\xF0\xF0\xF0\xF0\xF0" \
    cInfColor

#define _cpBlackWhite \
    "\x70\x70\x78\x7F\x07\x07\x0F\x07\x0F\x07\x70\x70\x07\x70\x00" \
    "\x07\x0F\x07\x70\x70\x07\x70\x00\x70\x7F\x7F\x70\x07\x70\x07\x00" \
    "\x70\x7F\x7F\x70\x07\x70\x70\x7F\x7F\x07\x0F\x0F\x78\x0F\x78\x07" \
    "\x0F\x0F\x0F\x70\x0F\x07\x70\x70\x70\x07\x70\x0F\x07\x07\x00\x00" \
    "\x1E\x71" \
    "\x17\x12\x1E\x1F\x1B\x15\x16\x3F\x2B\x1D\x1A\x2C\x13\x00\x00\x1C" \
    "\x1E\x71" \
    "\x17\x12\x1E\x1F\x1B\x15\x16\x3F\x2B\x1D\x1A\x2C\x13\x00\x00\x1C" \
    "\x1E\x71" \
    "\x17\x12\x1E\x1F\x1B\x15\x16\x3F\x2B\x1D\x1A\x2C\x13\x00\x00\x1C"\
    /* cCrossCur, cStatusLi, cMPHighL, cRectSel */ \
    "\x70\x7C\x5F\x67\xF0\xF0\xF0\xF0\xF0\xF0" \
    cInfBlackWhite

#define _cpMonochrome \
    "\x70\x07\x07\x0F\x70\x70\x70\x07\x0F\x07\x70\x70\x07\x70\x00" \
    "\x07\x0F\x07\x70\x70\x07\x70\x00\x70\x70\x70\x07\x07\x70\x07\x00" \
    "\x70\x70\x70\x07\x07\x70\x70\x70\x0F\x07\x07\x0F\x70\x0F\x70\x07" \
    "\x0F\x0F\x07\x70\x07\x07\x70\x07\x07\x07\x70\x0F\x07\x07\x00\x00" \
    "\x1E\x71" \
    "\x17\x12\x1E\x1F\x1B\x15\x16\x3F\x2B\x1D\x1A\x2C\x13\x00\x00\x1C" \
    "\x1E\x71" \
    "\x17\x12\x1E\x1F\x1B\x15\x16\x3F\x2B\x1D\x1A\x2C\x13\x00\x00\x1C" \
    "\x1E\x71" \
    "\x17\x12\x1E\x1F\x1B\x15\x16\x3F\x2B\x1D\x1A\x2C\x13\x00\x00\x1C"\
    /* cCrossCur, cStatusLi, cMPHighL, cRectSel */ \
    "\x70\x7C\x5F\x67\xF0\xF0\xF0\xF0\xF0\xF0" \
    cInfMonochrome


TPalette& TEditorApp::getPalette() const
{
    static TPalette color ( _cpColor, sizeof( _cpColor )-1 );
    static TPalette blackwhite( _cpBlackWhite, sizeof( _cpBlackWhite )-1 );
    static TPalette monochrome( _cpMonochrome, sizeof( _cpMonochrome )-1 );
    static TPalette *palettes[] =
        {
        &color,
        &blackwhite,
        &monochrome
        };
    return *(palettes[appPalette]);
}


#if !defined(STANDALONE) && !defined(RHIDE)
void OpenFileFromEditor(char *fullName)
{
}
#endif

TCEditWindow *TEditorApp::openEditor( char *fileName, Boolean visible )
{
#ifdef STANDALONE
    TCEditWindow *ain=NULL;
    if (visible && fileName)
       ain=IsAllreadyOnDesktop(fileName);
    TRect r = deskTop->getExtent();
    TView *p;

    if (ain)
      {
       ain->select();
       p=(TView *)ain;
      }
    else
      {
       p = validView( new TCEditWindow( r, fileName, wnNoNumber ) );
       if ( visible )
          AddToEditorsHelper((TCEditWindow *)p,1);
       else
          p->hide();
       deskTop->insert( p );
      }

#else
    TRect r = deskTop->getExtent();
    TView *p = validView( new TCEditWindow( r, fileName, wnNoNumber ) );
    if( !visible )
        p->hide();

    deskTop->insert( p );
#endif

    return (TCEditWindow *)p;
}

TEditorApp::TEditorApp() :
    TProgInit( TEditorApp::initStatusLine,
               TEditorApp::initMenuBar,
               TEditorApp::initDeskTop
             ),
    TApplication()
{

    TCommandSet ts;
    ts.enableCmd( cmSave );
    ts.enableCmd( cmSaveAs );
    ts.enableCmd( cmcCut );
    ts.enableCmd( cmcCopy );
    ts.enableCmd( cmcPaste );
    ts.enableCmd( cmcClear );
    ts.enableCmd( cmcUndo );
    ts.enableCmd( cmcRedo );
    ts.enableCmd( cmcFind );
    ts.enableCmd( cmcReplace );
    ts.enableCmd( cmcSearchAgain );
    disableCommands( ts );

    TCEditor::editorDialog = doEditDialog;
#ifdef STANDALONE
    // The clipboard is created during the load of the DeskTop
    clipWindow=0;
#else
    createClipBoard();
#endif
}


void TEditorApp::createClipBoard(void)
{
 clipWindow = openEditor( 0, False );
 if ( clipWindow != 0 )
   {
    TCEditor::clipboard = clipWindow->editor;
    TCEditor::clipboard->canUndo = False;
   }
}


void TEditorApp::fileOpen()
{
    char fileName[PATH_MAX];
    strcpy( fileName, "*.*" );

    if( execDialog( new TFileDialog( "*.*", _("Open file"),
            _("~N~ame"), fdOpenButton, 100 ), fileName) != cmCancel )
        openEditor( fileName, True );
}

void TEditorApp::fileNew()
{
    openEditor( 0, True );
}

void TEditorApp::changeDir()
{
    execDialog( new TChDirDialog( cdNormal, 0 ), 0 );
}

void TEditorApp::dosShell()
{
#ifndef BIOS_KEYBOARD
    remove_keyboard();
#endif
    suspend();
    system("cls");
    cout << _("Type EXIT to return...");
    system( getenv( "COMSPEC"));
    resume();
#ifndef BIOS_KEYBOARD
    install_keyboard();
#endif
    redraw();
}

void TEditorApp::showClip()
{
    clipWindow->select();
    clipWindow->show();
}

void TEditorApp::tile()
{
    deskTop->tile( deskTop->getExtent() );
}

void TEditorApp::cascade()
{
    deskTop->cascade( deskTop->getExtent() );
}

#ifdef STANDALONE
void CopyHelp2Clip(char *b, long l)
{
 if (clipWindow)
    clipWindow->editor->insertBuffer( b,0,(unsigned)l,False,True);
}
#endif

void TEditorApp::handleEvent( TEvent& event )
{
    TApplication::handleEvent( event );
    if( event.what != evCommand )
        return;
    else
        switch( event.message.command )
            {
            case cmOpen:
                fileOpen();
                break;

            case cmNew:
                fileNew();
                break;

            case cmChangeDrct:
                changeDir();
                break;

            case cmDosShell:
                dosShell();
                break;

            case cmShowClip:
                showClip();
                break;

            case cmTile:
                tile();
                break;

            case cmCascade:
                cascade();
                break;

#ifdef STANDALONE
            case cmInfView:
                 InfManager->Goto("editor","");
                 InfManager->window->select();
                 InfManager->window->show();
                 break;

            case cmLastHelp:
                 InfManager->window->select();
                 InfManager->window->show();
                 break;

            case cmListWin:
                 BringListOfWindows();
                 break;

            case cmUserScreen:
                 ShowUserScreen(event);
                 break;

#endif
#if defined(STANDALONE) || defined(RHIDE)
            case cmCalculator:
                 executeCalc();
                 break;
#endif

            default:
                return ;
            }
    clearEvent( event );
}

#ifdef __DJGPP__
#include <conio.h>

static void PasarAC(int Sig)
{
 Sig=0;
 ungetch('C');
}

void CtrlCOff(void)
{
 signal(SIGINT,PasarAC);
}
#endif


#ifdef STANDALONE
void TEditorApp::ShowUserScreen( TEvent &event )
{
 TProgram::deskTop->setState(sfVisible,False);
 TProgram::application->suspend();
 do
   {
    clearEvent(event);
    event.getKeyEvent();
   }
 while ((event.what & (evKeyDown)) == 0);
 clearEvent(event);
 TProgram::application->resume();
 TProgram::deskTop->setState(sfVisible,True);

 TProgram::deskTop->redraw();
 TProgram::application->redraw();
}
#endif

#ifdef STANDALONE
/*****************************************************************************

  The following routines are designed to save and retreive the desktop.
  Comes from TVDemo.cpp

*****************************************************************************/

//
// retrieveDesktop() function ( restores the previously stored Desktop )
//

void TEditorApp::retrieveDesktop()
{
 struct stat st;

 if (stat(DESKTOP_FILE, &st) == 0)
   {
#ifndef __GNUC__
    fpstream *f = new fpstream(DESKTOP_FILE, ios::in|ios::binary);
#else
    // In this way to avoid the destruction of the file
#ifdef __DJGPP__
    int h=open(DESKTOP_FILE, O_RDONLY | O_BINARY);
#else
    int h=open(DESKTOP_FILE, O_RDONLY);
#endif // __DJGPP__
    fpstream *f = new fpstream(h);
#endif
    if ( !f )
       messageBox(_("Could not open desktop file"), mfOKButton | mfError);
    else
      {
       TEditorApp::loadDesktop(*f);
       if ( !f )
          messageBox(_("Error reading desktop file"), mfOKButton | mfError);
      }
    delete f;
   }

 // Create all the necesary things if there is no desktop file
 if (!edHelper)
    edHelper=new TEditorCollection(EditorsDelta*2,EditorsDelta);

 if (!clipWindow)
   {
    createClipBoard();
    if (clipWindow)
       edHelper->addNonEditor(new TDskWinClipboard(clipWindow));
   }

 if (!InfManager)
   {
    InfManager=new TDskWinHelp("editor","");
    if (InfManager && InfManager->window)
      {
       deskTop->insert(InfManager->window);
       edHelper->addNonEditor(InfManager);
      }
   }
}

//
// saveDesktop() function ( saves the DeskTop by calling storeDesktop function )
//

void TEditorApp::saveDesktop()
{
#ifndef __GNUC__
 fpstream *f = new fpstream(DESKTOP_FILE, ios::out|ios::binary);
#else
 fpstream *f = new fpstream(DESKTOP_FILE, ios::out|ios::bin);
#endif

 if ( f )
   {
    TEditorApp::storeDesktop(*f);
    if ( !f )
      {
       messageBox(_("Could not create " DESKTOP_FILE "."), mfOKButton | mfError);
       delete f;
       ::remove(DESKTOP_FILE);
       return;
      }
   }
 delete f;
}

//
// storeDesktop() function ( stores the Desktop in a resource file )
//

static char *Signature="TEditorApp desktop file\x1A";

void TEditorApp::storeDesktop(fpstream& s)
{
  // Save a signature to identify the file
  s.writeString(Signature);
  // Save the version
  s << TCEDITOR_VERSION;
  s << TCEditor::staticTabSize << uchar(TCEditor::staticAutoIndent) <<
       uchar(TCEditor::staticIntelIndent) << uchar(TCEditor::staticUseTabs) <<
       uchar(TCEditor::staticPersistentBlocks);
  int i,j=historyCount(10);
  s << j;
  for (i=0; i<j; i++)
     s.writeString(historyStr(10,i));
  s << edHelper;
  s << 0;
}

//
// loadDesktop() function
//

void TEditorApp::loadDesktop(fpstream &s)
{
    TView  *p;
    char buffer[80];
    unsigned long ver;

    s.readString(buffer,80);
    if (strcmp(buffer,Signature)!=0)
      {
       messageBox(_("Wrong desktop file."), mfOKButton | mfError);
       return;
      }
    s >> ver;
    if (ver<0x20A)
      {
       messageBox(_("The desktop file belongs to another version."), mfOKButton | mfError);
       return;
      }
    s >> TCEditor::staticTabSize;
    uchar aux;
    s >> aux;
    TCEditor::staticAutoIndent  = (aux) ? True : False;
    s >> aux;
    TCEditor::staticIntelIndent = (aux) ? True : False;
    s >> aux;
    TCEditor::staticUseTabs     = (aux) ? True : False;
    s >> aux;
    TCEditor::staticPersistentBlocks = (aux) ? True : False;
    int i,j;
    char *sp;
    s >> j;
    for (i=0; i<j; i++)
       {
        s.readString(buffer,80);
        sp = new char[strlen(buffer)+1];
        strcpy(sp,buffer);
        historyAdd(10,sp);
       }

    if (deskTop->valid(cmClose))
       deskTop->forEach(::closeView, 0);  // Clear the desktop

    if (ver>=0x215)
       s >> edHelper;
    else
       edHelper=new TEditorCollection(EditorsDelta*2,EditorsDelta);

    if (ver<0x215)
    if (deskTop->valid(cmClose))
      {
       do
        {
         s >> p;
         if (p!=NULL)
           {
            // If the view is outside the screen put in inside
            if ((p->origin.x>=deskTop->size.x) || (p->origin.y>=deskTop->size.y))
               p->origin.x=p->origin.y=0;
            AddToEditorsHelper((TCEditWindow *)p);
           }
         deskTop->insertBefore(validView(p), deskTop->last);
        }
       while (p != 0);
      }
}
/******************** End of save/retrieve desktop functions ****************/




extern char *LoadKeyForTCEditorError(void);
extern int LoadKeysForTCEditor(char *file);

__link( RBackground )
#ifdef RHIDE
__link( RCEditWindow )
__link( RInfWindow )
#endif

/************************** EditorsHelper ********************************/
// The following routines are for numbering the windows and to save it in
// the right order

const char *TEditorCollection::name="TEdCol";
const char *TDskWinEditor::name="TDskWinEditor";
const char *TDskWinClosed::name="TDskWinClosed";
const char *TDskWinClipboard::name="TDskWinClipboard";
const char *TDskWinHelp::name="TDskWinHelp";

void TListEditors::getText(char *dest, CCINDEX item, short maxLen)
{
 TEditorCollection *lista=(TEditorCollection *)list();
 lista->getText(dest,item,maxLen);
}

TEditorCollection::TEditorCollection(ccIndex aLimit, ccIndex aDelta)
 : TCollection(aLimit,aDelta)
{
 Editors=Closed=nonEditors=0;
}

void TEditorCollection::write( opstream& os )
{
 os << Closed << nonEditors << Editors << delta;
 for ( ccIndex idx = 0; idx < count; idx++ )
     writeItem( items[idx], os );
}

void *TEditorCollection::readItem( ipstream& is )
{
 TDskWin *p;
 is >> p;
 return p;
}

void TEditorCollection::writeItem( void *p, opstream &os )
{
 if (((TDskWin *)p)->CanBeSaved)
    os << (TDskWin *)p;
}

TStreamable *TEditorCollection::build()
{
 return new TEditorCollection( streamableInit );
}

TStreamable *TDskWinEditor::build()
{
 return new TDskWinEditor( streamableInit );
}

TStreamable *TDskWinClosed::build()
{
 return new TDskWinClosed( streamableInit );
}

TStreamable *TDskWinClipboard::build()
{
 return new TDskWinClipboard( streamableInit );
}

TStreamable *TDskWinHelp::build()
{
 return new TDskWinHelp( streamableInit );
}

void *TEditorCollection::read( ipstream& is )
{
 is >> Closed >> nonEditors >> Editors >> delta;
 count=Closed+nonEditors+Editors;
 setLimit(0);
 for ( ccIndex idx = 0; idx < count; idx++ )
     items[idx] = readItem( is );

 // Now insert the views in the correct order
 int c=count;
 ccIndex i=0;
 TDskWin *p;
 int max=0;

 editorApp->deskTop->lock();
 while (c)
   {
    p=(TDskWin *)at(i);
    c--;
    if (p->view)
      {
       editorApp->deskTop->insert(p->view);
       if (p->ZOrder>max)
          max=p->ZOrder;
      }
    i++;
   }

 while (max)
   {
    c=count; i=0;
    do
      {
       p=(TDskWin *)at(i);
       if (p->view)
         {
          if (p->ZOrder==max)
            {
             p->view->select();
             break;
            }
         }
       i++;
      }
    while (--c);
    max--;
   }
 editorApp->deskTop->unlock();

 return this;
}

void TDskWinClosed::write( opstream& os )
{
 os.writeString(Name);
 os << origin << size << cursor;
}

void *TDskWinClosed::read( ipstream& is )
{
 char fileName[PATH_MAX];
 is.readString(fileName,PATH_MAX);
 Name=strdup(fileName);
 is >> origin >> size >> cursor;
 ZOrder=-1;
 view=0;

 return this;
}



void TDskWinClipboard::write( opstream& os )
{
 os << edw->origin << edw->size << (int)(edw->state & sfVisible)
    << (int)(TProgram::deskTop->indexOf(edw));
}

void *TDskWinClipboard::read( ipstream& is )
{
 TPoint aux;

 // Create a default clipboard
 TRect r = TProgram::deskTop->getExtent();
 TCEditWindow *p;

 p = (TCEditWindow *)editorApp->validView( new TCEditWindow( r, 0, wnNoNumber ) );
 p->hide();

 edw=clipWindow=p;
 if ( clipWindow )
   {
    TCEditor::clipboard = clipWindow->editor;
    TCEditor::clipboard->canUndo = False;
   }

 // Now restore the last settings
 is >> aux;
 clipWindow->moveTo(aux.x,aux.y);
 is >> aux;
 clipWindow->growTo(aux.x,aux.y);
 int vis;
 is >> vis;
 if (vis)
    edw->show();
 is >> ZOrder;
 view=edw;

 return this;
}


void TDskWinHelp::Goto(char *File, char *Node)
{
 char aux[MAX_NODE_NAME*2];
 aux[0]='(';
 aux[1]=0;
 strcat(aux,File);
 strcat(aux,")");
 strcat(aux,Node);
 window->viewer->switchToTopic(aux);
}

void TDskWinHelp::write( opstream& os )
{
#ifdef OLD_TINFVIEW
 os.writeString(file->NameOfFile);
 os.writeString(window->viewer->topic->Node);
 os << window->origin << window->size << (int)(window->state & sfVisible)
    << (int)(TProgram::deskTop->indexOf(window)) << window->isTheOne;
#else
 os << window << (int)(TProgram::deskTop->indexOf(window));
#endif
}

void *TDskWinHelp::read( ipstream& is )
{
#ifdef OLD_TINFVIEW
 char File[MAX_NODE_NAME];
 char Node[MAX_NODE_NAME];

 is.readString(File,MAX_NODE_NAME);
 is.readString(Node,MAX_NODE_NAME);

 Create(File,Node);

 TPoint aux;

 is >> aux;
 window->moveTo(aux.x,aux.y);
 is >> aux;
 window->growTo(aux.x,aux.y);
 int vis;
 is >> vis;
 if (vis)
    window->show();

 is >> ZOrder;

 int aux2;
 is >> aux2;
 window->isTheOne=aux2 ? True : False;
 window->options&=~(ofCenterX | ofCenterY);

 if (aux2)
    InfManager=this;
#else
 is >> window >> ZOrder;

 // Set up the alias pointers
 file=window->viewer->hFile;
 view=window;

 // Set-Up the paste
 window->viewer->InsertRoutine=CopyHelp2Clip;

 if (window->isTheOne)
    InfManager=this;
#endif

 return this;
}


void TDskWinEditor::write( opstream& os )
{
 os << number << edw << (int)(TProgram::deskTop->indexOf(edw));
}

void *TDskWinEditor::read( ipstream& is )
{
 is >> number >> edw >> ZOrder;
 edw=(TCEditWindow *)editorApp->validView(edw);
 if (edw)
   {
    edw->number=number;
    edw->show();
   }
 view=edw;

 return this;
}



void TEditorCollection::getText(char *dest, CCINDEX item, short maxLen)
{
 TDskWin *p=(TDskWin *)at(item);
 p->GetText(dest,maxLen);
}

char *TDskWinEditor::GetText(char *dest, short maxLen)
{
 TCFileEditor *ed=edw->editor;
 sprintf(dest,"%2d%c",number,ed->modified ? '*' : ' ');
 return TDskWin::GetText(dest,ed->fileName,maxLen);
}

char *TDskWinClosed::GetText(char *dest, short maxLen)
{
 strcpy(dest,_("   Closed: "));
 return TDskWin::GetText(dest,Name,maxLen);
}

char *TDskWinClipboard::GetText(char *dest, short )
{
 sprintf(dest,_("   Clipboard (%d bytes)"),edw->editor->bufLen);
 return dest;
}

char *TDskWinHelp::GetText(char *dest, short maxLen)
{
 char aux[MAX_NODE_NAME*2];

 aux[0]='(';
 aux[1]=0;
 strcat(aux,file->NameOfFile);
 strcat(aux,")");
 strcat(aux,window->viewer->topic->Node);

 strcpy(dest,_("   InfView "));
 return TDskWin::GetText(dest,aux,maxLen);
}

char *TDskWin::GetText(char *dest,char *s, short maxLen)
{
 int max=maxLen-strlen(dest);
 int l=strlen(s);
 if (l>=max)
   {
    strncat(dest,s,max);
    dest[maxLen]=0;
   }
 else
    strcat(dest,s);

 return dest;
}

static char *TakeExtention(char *file)
{
 char *s=file,*e=NULL;
 int wasExt=0;

 for (; *s; s++)
     if (*s=='/' || *s=='\\')
        wasExt=0;
     else
        if (*s=='.')
          {
           wasExt=1;
           e=s;
          }
 return wasExt ? e+1 : (char *)NULL;
}

static char *extSyntaxTable[] =
{
 "c","i",
 "cc","cpp","cxx","ii",
 "h","hpp",
 "p","pas",
 "prg"
};

static shlState typeSyntaxTable[] =
{
 shlCSyntax,shlCSyntax,
 shlCSyntax,shlCSyntax,shlCSyntax,shlCSyntax,shlCSyntax,
 shlCSyntax,shlCSyntax,
 shlPascalSyntax,shlPascalSyntax,
 shlClipperSyntax
};

const lenSyntaxTable = sizeof(extSyntaxTable)/sizeof(char *);

void TEditorCollection::addEditor(TCEditWindow *p, int SelectHL)
{
 int i=Editors;
 int number=1;
 ccIndex ind=0;
 TDskWinEditor *st;

 // Correct the name
 int l=strlen(p->editor->fileName)-1;
 if (p->editor->fileName[l]=='.')
    p->editor->fileName[l]=0;
 while (i)
   {
    st=(TDskWinEditor *)at(ind);
    i--;
    if (st->number!=number)
       break;
    number++;
    ind++;
   }
 Editors++;
 st=new TDskWinEditor(p,number);
 p->number=number;
 atInsert(ind,st);

 // If there is a closed for it kill him
 ind=search(p->editor->fileName,dktClosed);
 if (ind!=-1)
   {
    TDskWinClosed *p=(TDskWinClosed *)at(ind);
    atRemove(ind);
    Closed--;
    delete p;
   }

 if (SelectHL)
   {
    char *ext=TakeExtention(p->editor->fileName);
    if (ext==NULL)
       p->editor->SetHighlightTo(shlNoSyntax);
    else
      {
       int i,found=0;
       for (i=0; i<lenSyntaxTable && !found; i++)
          {
           if (strcasecmp(extSyntaxTable[i],ext)==0)
             {
              p->editor->SetHighlightTo(typeSyntaxTable[i]);
              found=1;
             }
          }
       if (!found)
          p->editor->SetHighlightTo(shlNoSyntax);
      }
   }
}

ccIndex TEditorCollection::search(void *p,int type)
{
 ccIndex pos=0;
 TDskWin *st;

 while (pos<count)
   {
    st=(TDskWin *)at(pos);
    if (st->Compare(p,type))
       return pos;
    pos++;
   }
 return -1;
}


void TEditorCollection::removeEditor(TCEditWindow *p)
{
 ccIndex pos=search(p,dktEditor);

 if (pos<0) return;
 TDskWinEditor *st=(TDskWinEditor *)at(pos);
 atRemove(pos);
 Editors--;

 TDskWinClosed *nuevo=new TDskWinClosed(st->edw);
 atInsert(Editors+nonEditors,nuevo);
 delete st;
 Closed++;

 // Don't keep more than 40 closed, Laci needs much ;-)
 if (Closed>40)
   {
    pos=Editors+nonEditors+--Closed;
    TDskWin *p=(TDskWin *)at(pos);
    atRemove(pos);
    delete p;
   }
#if 1
 //   That's a modified version of the Laszlo's idea to keep the closed windows
 // sorted that of course sorts the old desktop files.
 TDskWinClosed *closedwins[40],*tmp;
 ccIndex       ic,jc;
 int           sorted=0,need_change=0;

 for (ic=0; ic<Closed; ic++)
     closedwins[ic]=(TDskWinClosed *)at(ic+Editors+nonEditors);
 for (ic=0; ic<Closed-1 && !sorted; ic++)
     for (jc=ic+1,sorted=1; jc<Closed; jc++)
        {
         if (strcmp(closedwins[ic]->Name,closedwins[jc]->Name) > 0)
           {
            tmp=closedwins[ic];
            closedwins[ic]=closedwins[jc];
            closedwins[jc]=tmp;
            sorted=0;
            need_change=1;
           }
        }
 if (need_change)
   {
    for (ic=0; ic<Closed; ic++)
        atRemove(Editors+nonEditors);
    for (ic=0; ic<Closed; ic++)
        atInsert(Editors+nonEditors+ic,closedwins[ic]);
   }
#endif
}

TDskWinClosed::TDskWinClosed(TCEditWindow *edw)
{
 Name=strdup(edw->editor->fileName);
 origin=edw->origin;
 size=edw->size;
 cursor=edw->editor->curPos;
 type=dktClosed;
 CanBeSaved=1;
 view=0;
}

TDskWinClipboard::TDskWinClipboard(TCEditWindow *EdW)
{
 view=edw=EdW;
 type=dktClipboard;
 CanBeSaved=1;
}

void TDskWinHelp::Create(char *File, char *Node)
{
 file = new TInfFile(File);
 window = new TInfWindow(file,Node,NULL,CopyHelp2Clip,True);
 if ((window=(TInfWindow *)editorApp->validView(window))!=0)
    window->hide();
 view=window;
}

TDskWinHelp::TDskWinHelp(char *File, char *Node)
{
 Create(File,Node);
 type=dktHelp;
 CanBeSaved=1;
}

TDskWinHelp::~TDskWinHelp()
{
 if (file)
    delete file;
 if (window)
    delete window;
}


TDskWinClosed::~TDskWinClosed()
{
 delete Name;
}

ccIndex TEditorCollection::searchEditorName(char *name)
{
 int i=Editors;
 ccIndex ind=0;
 TDskWin *st;
 int l;

 // If the name
 l=strlen(name)-1;
 if (name[l]=='.')
    name[l]=0;
 while (i)
   {
    st=(TDskWin *)at(ind);
    if (st->type==dktEditor)
      {
       i--;
       if (strcasecmp(((TDskWinEditor *)st)->edw->editor->fileName,name)==0)
          return ind;
      }
    ind++;
   }

 return -1;
}

void AddToEditorsHelper(TCEditWindow *p, int SelectHL)
{
 edHelper->addEditor(p,SelectHL);
}

void RemoveFromEditorsHelper(TCEditWindow *p)
{
 edHelper->removeEditor(p);
}

int IsAnEditor(void *p)
{
 return edHelper->search(p,dktEditor)>=0;
}

TCEditWindow *IsAllreadyOnDesktop(char *fileName)
{
 ccIndex pos=edHelper->searchEditorName(fileName);
 if (pos<0)
    return NULL;
 TDskWinEditor *st=(TDskWinEditor *)edHelper->at(pos);
 return st->edw;
}

class TListWindowsDiag : public TDialog
{
public:
 TListWindowsDiag(TRect sizeDkt);
 void handleEvent(TEvent &event);
 TListEditors *tl;
};

TListWindowsDiag::TListWindowsDiag(TRect sizeDkt) :
 TDialog(sizeDkt,_("Windows List")),
 TWindowInit(TListWindowsDiag::initFrame)
{
 helpCtx = hcListWin;

 int h=sizeDkt.b.y-sizeDkt.a.y;
 int w=sizeDkt.b.x-sizeDkt.a.x;

 TScrollBar *sb = new TScrollBar( TRect(w-3,2,w-2,h-4) );
 insert(sb);
 tl = new TListEditors(TRect(2,2,w-3,h-4),1,sb);
 tl->newList(edHelper);
 insert(tl);

 TRect r(3,h-3,15,h-1);
 insert( new TButton(r,_("~G~o"),cmGo,bfDefault) );
 r.move(14,0);
 insert( new TButton(r,_("~D~elete"),cmDelete,bfNormal) );
 r.move(14,0);
 insert( new TButton(r,_("Cancel"),cmCancel,bfNormal) );

 selectNext( False );
 options |= ofCentered;
}

TView *setFocusTo;
Boolean focusChanged;

void TListWindowsDiag::handleEvent(TEvent &event)
{
 TDialog::handleEvent(event);
 switch (event.what)
   {
    case evCommand:
        {
         CCINDEX pos = tl->focused;
         TDskWin *obj = (TDskWin *)(edHelper->at(pos));

         switch( event.message.command )
           {
            case cmGo:
                 if (obj->GoAction(pos))
                    delete obj;
                 tl->setRange(edHelper->getCount());
                 break;

            case cmDelete:
                 if (obj->DeleteAction(pos))
                    delete obj;
                 tl->setRange(edHelper->getCount());
                 break;

            default:
                 return;
           }
         if (state & sfModal)
           {
            endModal(event.message.command);
            clearEvent(event);
           }
        }
         break;
   }
}

int TDskWinEditor::GoAction(CCINDEX )
{
 TProgram::deskTop->lock();
 setFocusTo=edw;
 focusChanged=True;

 return 0;
}

int TDskWinClosed::GoAction(CCINDEX i)
{
 TCEditWindow *ed;

 // Remove from the closed list
 edHelper->atRemove(i);
 edHelper->Closed--;
 // Lock the desktop to avoid lotz redraws
 TProgram::deskTop->lock();
 // Reopen the file
 ed=editorApp->openEditor(Name,True);
 // Indicate the new Top editor
 setFocusTo=(TView *)ed;
 focusChanged=True;
 // Restore the last settings
 ed->moveTo(origin.x,origin.y);
 ed->growTo(size.x,size.y);
 ed->editor->MoveCursorTo(cursor.x,cursor.y);
 ed->editor->trackCursor(True);

 return 1;
}

int TDskWinClipboard::GoAction(CCINDEX )
{
 TProgram::deskTop->lock();
 setFocusTo=edw;
 focusChanged=True;

 return 0;
}

int TDskWinHelp::GoAction(CCINDEX )
{
 TProgram::deskTop->lock();
 setFocusTo=window;
 focusChanged=True;

 return 0;
}


int TDskWinEditor::DeleteAction(CCINDEX )
{
 closeView(edw,NULL);

 return 0;
}

int TDskWinClosed::DeleteAction(CCINDEX i)
{
 edHelper->atRemove(i);
 edHelper->Closed--;

 return 1;
}

int TDskWinClipboard::DeleteAction(CCINDEX )
{
 edw->hide();

 return 0;
}

int TDskWinHelp::DeleteAction(CCINDEX )
{
 window->hide();

 return 0;
}


void BringListOfWindows(void)
{
 TRect r=TApplication::deskTop->getExtent();
 r.b.x-=10;
 r.b.y-=6;

 TListWindowsDiag *d=new TListWindowsDiag(r);

 focusChanged=False;
 int i;

 do
  {
   TProgram::deskTop->insert(d);
   d->setState(sfModal,True);
   i = d->execute();
   TProgram::deskTop->remove(d);
  }
 while (i==cmDelete);
 delete d;

 if (focusChanged)
   {
    setFocusTo->select();
    setFocusTo->show();
    TProgram::deskTop->unlock();
   }
}

/*********************** End of EditorsHelper *****************************/

#ifdef __GNUC__
static char PathOrig[PATH_MAX];
#else
static char PathOrig[MAXPATH];
#endif
static char *PathOrigPos;

char *ExpandFileNameToThePointWhereTheProgramWasLoaded(char *s)
{
 if (PathOrigPos!=NULL)
   {
    *PathOrigPos=0;
    strcat(PathOrig,s);
   }
 else
    strcpy(PathOrig,s);

 return PathOrig;
}

static int TestForFile(char *name)
{
 struct stat st;

 if (stat(name,&st)==0)
    return S_ISREG(st.st_mode);
 return 0;
}


int FindFile(const char * name,char * & fullName)
{
 char *base;

 if (strlen(name)>=PATH_MAX)
    return 0;
 fullName=new char[PATH_MAX];
 if (!fullName)
    return 0;
 strcpy(fullName,name);
 if (!TestForFile(fullName))
   {
    base=getenv("DJDIR");
    if (!base)
      {
       delete fullName;
       return 0;
      }
    strcpy(fullName,base);
    strcat(fullName,"/include/");
    strcat(fullName,name);
    if (!TestForFile(fullName))
      {
       delete fullName;
       return 0;
      }
   }
 fexpand(fullName);
 return 1;
}

void OpenFileFromEditor(char *fullName)
{
 editorApp->openEditor(fullName,True);
}

extern void RestoreScreen();
char argv0[PATH_MAX];

int main(int argc, char *argv[])
{
 #if 0
 RestoreScreen(); // Just force a mouse reinitialization
 #endif
 strcpy(argv0,argv[0]);
 #ifdef __GNUC__
 PathOrigPos=strrchr(argv0,'/');
 #else
 PathOrigPos=strrchr(argv0,'\\');
 #endif
 if (PathOrigPos)
   {
    PathOrigPos++;
    *PathOrigPos=0;
    strcpy(PathOrig,argv0);
    PathOrigPos=PathOrig+(int)(PathOrigPos-argv0);
   }
 else
    PathOrig[0]=0;

 #ifdef USE_TSTRCOL
 ReservedWords = new TStrCol(20,5);
 UserWords     = new TStrCol(20,5);
 PascalRWords  = new TStrCol(20,5);
 ClipperRWords = new TStrCol(20,5);
 #else
 ReservedWords = new TStringCollection(20,5);
 UserWords     = new TStringCollection(20,5);
 PascalRWords  = new TStringCollection(20,5);
 ClipperRWords = new TStringCollection(20,5);
 #endif

 ReservedWords->insert("int");
 ReservedWords->insert("char");
 ReservedWords->insert("unsigned");
 ReservedWords->insert("signed");
 ReservedWords->insert("float");
 ReservedWords->insert("double");
 ReservedWords->insert("short");
 ReservedWords->insert("long");
 ReservedWords->insert("void");

 ReservedWords->insert("for");
 ReservedWords->insert("while");
 ReservedWords->insert("do");
 ReservedWords->insert("if");
 ReservedWords->insert("else");
 ReservedWords->insert("return");
 ReservedWords->insert("continue");
 ReservedWords->insert("goto");

 ReservedWords->insert("static");
 ReservedWords->insert("const");
 ReservedWords->insert("enum");
 ReservedWords->insert("struct");
 ReservedWords->insert("extern");
 ReservedWords->insert("sizeof");
 ReservedWords->insert("union");
 ReservedWords->insert("typedef");
 ReservedWords->insert("inline");
 ReservedWords->insert("register");
 ReservedWords->insert("volatile");

 ReservedWords->insert("switch");
 ReservedWords->insert("case");
 ReservedWords->insert("default");
 ReservedWords->insert("break");

 ReservedWords->insert("new");
 ReservedWords->insert("delete");

 ReservedWords->insert("class");
 ReservedWords->insert("private");
 ReservedWords->insert("protected");
 ReservedWords->insert("public");
 ReservedWords->insert("this");
 ReservedWords->insert("template");
 ReservedWords->insert("throw");
 ReservedWords->insert("catch");
 ReservedWords->insert("virtual");
 ReservedWords->insert("friend");
 ReservedWords->insert("operator");
 ReservedWords->insert("try");

 UserWords->insert("uchar");
 UserWords->insert("ushort");
 UserWords->insert("uint16");
 UserWords->insert("uint32");

 // List of reserved words for Turbo Pascal 5.0, if some of them isn't
 // reserved in GPC please comment this line.
 PascalRWords->insert("absolute");
 PascalRWords->insert("and");
 PascalRWords->insert("array");
 PascalRWords->insert("begin");
 PascalRWords->insert("case");
 PascalRWords->insert("const");
 PascalRWords->insert("div");
 PascalRWords->insert("do");
 PascalRWords->insert("downto");
 PascalRWords->insert("else");
 PascalRWords->insert("end");
 PascalRWords->insert("external");
 PascalRWords->insert("file");
 PascalRWords->insert("for");
 PascalRWords->insert("forward");
 PascalRWords->insert("function");
 PascalRWords->insert("goto");
 PascalRWords->insert("if");
 PascalRWords->insert("implementation");
 PascalRWords->insert("in");
 PascalRWords->insert("inline");
 PascalRWords->insert("interface");
 PascalRWords->insert("interrupt");
 PascalRWords->insert("label");
 PascalRWords->insert("mod");
 PascalRWords->insert("nil");
 PascalRWords->insert("not");
 PascalRWords->insert("of");
 PascalRWords->insert("or");
 PascalRWords->insert("packed");
 PascalRWords->insert("procedure");
 PascalRWords->insert("program");
 PascalRWords->insert("record");
 PascalRWords->insert("repeat");
 PascalRWords->insert("set");
 PascalRWords->insert("shl");
 PascalRWords->insert("shr");
 PascalRWords->insert("string");
 PascalRWords->insert("then");
 PascalRWords->insert("to");
 PascalRWords->insert("type");
 PascalRWords->insert("unit");
 PascalRWords->insert("until");
 PascalRWords->insert("uses");
 PascalRWords->insert("var");
 PascalRWords->insert("while");
 PascalRWords->insert("with");
 PascalRWords->insert("xor");

 // Taked from the Clipper.EXE 5.2e
 ClipperRWords->insert("announce");
 ClipperRWords->insert("begin");
 ClipperRWords->insert("break");
 ClipperRWords->insert("call");
 ClipperRWords->insert("case");
 ClipperRWords->insert("declare");
 ClipperRWords->insert("do");
 ClipperRWords->insert("else");
 ClipperRWords->insert("elseif");
 ClipperRWords->insert("endcase");
 ClipperRWords->insert("enddo");
 ClipperRWords->insert("endif");
 ClipperRWords->insert("exit");
 ClipperRWords->insert("external");
 ClipperRWords->insert("field");
 ClipperRWords->insert("for");
 ClipperRWords->insert("function");
 ClipperRWords->insert("if");
 ClipperRWords->insert("iif");
 ClipperRWords->insert("in");
 ClipperRWords->insert("init");
 ClipperRWords->insert("local");
 ClipperRWords->insert("loop");
 ClipperRWords->insert("memvar");
 ClipperRWords->insert("next");
 ClipperRWords->insert("otherwise");
 ClipperRWords->insert("parameters");
 ClipperRWords->insert("private");
 ClipperRWords->insert("procedure");
 ClipperRWords->insert("public");
 ClipperRWords->insert("recover");
 ClipperRWords->insert("return");
 ClipperRWords->insert("sequence");
 ClipperRWords->insert("static");
 ClipperRWords->insert("step");
 ClipperRWords->insert("text");
 ClipperRWords->insert("to");
 ClipperRWords->insert("then");
 ClipperRWords->insert("using");
 ClipperRWords->insert("with");
 ClipperRWords->insert("while");


 if (LoadKeysForTCEditor(ExpandFileNameToThePointWhereTheProgramWasLoaded("keybind.txt")))
   {
    char dummy;
    cout << LoadKeyForTCEditorError() << endl;
    cin >> dummy;
   }

 #ifndef BIOS_KEYBOARD
 install_keyboard();
 atexit(allegro_exit);
 #endif

 #ifdef __DJGPP__
 CtrlCOff();

 // International support
 char *locale_dir,localedir[256];
 setlocale(LC_ALL, "");
 // Use the LOCALEDIR var for the directory
 locale_dir = getenv("LOCALEDIR");

 if (!locale_dir)
   {
    // if LOCALEDIR doesn't exists use DJDIR
    locale_dir = getenv("DJDIR");
    if (locale_dir)
       strcpy(localedir,locale_dir);
    else
      {
       // if DJDIR doesn't exists use .
       // That's only to avoid a GPF in the strcpy and add a little facility
       localedir[0]='.';
       localedir[1]=0;
      }
    strcat(localedir,"/data/locale");
   }
  else
   {
    strcpy(localedir,locale_dir);
   }

 BINDTEXTDOMAIN("editor",localedir);
 TEXTDOMAIN("editor");

 #endif

 //InitEditorsHelper();
 editorApp = new TEditorApp();
 editorApp->retrieveDesktop();
 //clipWindow->editor->CacheColors();

 int count=argc;
 char tmpPath[PATH_MAX];
 while (count>1)
   {
    strcpy(tmpPath,argv[--count]);
    fexpand(tmpPath);
    editorApp->openEditor( tmpPath , True );
   }

 editorApp->run();
 editorApp->saveDesktop();

 if (InfManager)
    delete InfManager;

 return 0;
}
#endif

