/*
**      $VER: Funcs.c 1.0
**
**      Library functions for C source datatype
*/

#define __USE_SYSBASE

#include <exec/types.h>
#include <exec/memory.h>

#include <proto/exec.h>
#include <proto/dos.h>

#include <string.h>

#include "ixdt.h"

/*
** Every iX Datatype has three functions:
**
** DTF_Identify() which performs some tests on given file
** to determine if that file should be read by this datatype.
** Function returns an integer value between 0 and 9.
** Value of 9 means that file is recogized 100%.
** Value of 0 means that file is not recognized.
** Value of e.g. 5 means that datatype is about 50% sure that
** file is of required type.
** Value of e.g. 8 means that datatype is almost 100% sure that
** file is of required type etc.
**
** DTF_FileStruct() which is used to determine begin-end of
** some logical parts of file.
** For example, AmigaGuide database is made up of nodes, and this
** function should find begin, end and name of every node.
**  
** DTF_ProcessChunk() which reads one part of file and returns
** information on that part in iX_ChunkInfo form readable by iX-Guide
*/

long ec,ecc;

ULONG __saveds __asm DTF_Identify(register __a0 STRPTR name)
{
/*
** very primitive : we just check if extension is .c or .h which means
** it is C source, otherwise we return 0.
*/
char *chp;
long nl;
 
 nl=strlen(name);
 if (nl>2)
  {
   chp=name+nl;
   chp-=2;
   if ((stricmp(chp,".c")==0) || (stricmp(chp,".h")==0))
     return(9L); // yes, it is C source
  };
 return(0L);
}

struct iX_Node * __saveds __asm DTF_FileStruct(register __a0 BPTR fh,
                                               register __d0 long from,
                                               register __a1 BOOL *save_index)
{
 struct iX_Node *nd=NULL;
 
 *save_index = FALSE;   // we don't want iX-Guide to save node index
                        // since we have only one node
 
 if (!from)             // if from is 0 which means we are at the begining
                        // of file, we build our node, otherwise we are called
                        // for a second time and we return NULL since we have
                        // only one node  
 {
   nd = AllocVec(sizeof(struct iX_Node),MEMF_CLEAR);
   nd->name = AllocVec(5,0);
   strcpy(nd->name,"main");  // "main" node will be loaded first
   nd->node_begin=0L;        // node begin is actually begining of file
   Seek(fh,0L,OFFSET_END);
   nd->node_end=Seek(fh,0L,OFFSET_CURRENT); // node end is end of file
 };
 
 return(nd);
}

/************ support functions ************/
void *Realloc(void *oldptr,long newsz,long oldsz)
{
 void *mempt;
 
 mempt = AllocVec(newsz,MEMF_ANY);
 CopyMem(oldptr,mempt,oldsz);
 FreeVec(oldptr);

 return(mempt);
}
BOOL CheckMemory(struct iX_ChunkInfo *tpp,long *chunk_c,long entry_c,long ParserECS)
{
     if (*chunk_c==ParserECS)
       {
        *chunk_c=0;
        tpp->ci_entry=Realloc(tpp->ci_entry,entry_c+ParserECS,entry_c);
        tpp->cie_position=Realloc(tpp->cie_position,4*entry_c+ParserECS*4,4*entry_c);
        tpp->cie_length=Realloc(tpp->cie_length,2*entry_c+ParserECS*2,2*entry_c);
       };

if (!tpp->ci_entry || !tpp->cie_position || !tpp->cie_length) return(FALSE);
}

void PaintWord(long wlen,long color,struct iX_ChunkInfo *tpp,long PECS,char *dpp)
{
 tpp->ci_entry[ec]=ET_TAG;ec++;ecc++;CheckMemory(tpp,&ecc,ec,PECS);
 tpp->ci_entry[ec]=ET_FG;ec++;ecc++;CheckMemory(tpp,&ecc,ec,PECS);
 tpp->ci_entry[ec]=ET_ATTR;
 tpp->cie_position[ec]=color * 7;
 tpp->cie_length[ec]=7;ec++;ecc++;CheckMemory(tpp,&ecc,ec,PECS);
 tpp->ci_entry[ec]=ET_WORD;
 tpp->cie_position[ec]=dpp-tpp->ci_data;
 tpp->cie_length[ec]=wlen;ec++;ecc++;CheckMemory(tpp,&ecc,ec,PECS);
 tpp->ci_entry[ec]=ET_TAG;ec++;ecc++;CheckMemory(tpp,&ecc,ec,PECS);
 tpp->ci_entry[ec]=ET_FG;ec++;ecc++;CheckMemory(tpp,&ecc,ec,PECS);
 tpp->ci_entry[ec]=ET_ATTR;
 tpp->cie_position[ec]=35;
 tpp->cie_length[ec]=4;ec++;ecc++;CheckMemory(tpp,&ecc,ec,PECS);
}
/********************************/
struct iX_ChunkInfo * __saveds __asm DTF_ProcessChunk(register __a0 STRPTR name,
                                                      register __d0 long from,
                                                      register __d1 long to,
                                                      register __d2 BOOL head)
{
  struct iX_ChunkInfo *ci=NULL;
  BPTR fhan;
  char *author="Created by CSource datatype V12.26"; // this will show up
                                                     // in iXG INFO window
  char *dp;
  long ParserECS=1000;
    
  if (head)          // iX-Guide wants header of database
   {
    ci = AllocVec(sizeof(struct iX_ChunkInfo),MEMF_CLEAR);
    ci->ci_data = AllocVec(strlen(author)+strlen(name)+2,MEMF_CLEAR);
    strcpy(ci->ci_data,author);strcat(ci->ci_data,name);
    ci->ci_datalen=strlen(author)+strlen(name)+2;
    ci->ci_entrynum=9;
    ci->ci_entry=AllocVec(9,MEMF_CLEAR);
    ci->ci_entry[0]=ET_STAG;ci->ci_entry[1]=ET_DATABASE;
    ci->ci_entry[2]=ET_ATTR;ci->ci_entry[3]=ET_RTRN;
    ci->ci_entry[4]=ET_STAG;ci->ci_entry[5]=ET_AUTHOR;
    ci->ci_entry[6]=ET_ATTR;ci->ci_entry[7]=ET_RTRN;
    ci->ci_entry[8]=ET_END;
    ci->cie_position=AllocVec(9*4,MEMF_CLEAR);
    ci->cie_position[2] = strlen(author);ci->cie_position[6] = 0L;
    ci->cie_length=AllocVec(9*2,MEMF_CLEAR);
    ci->cie_length[2] = strlen(name); ci->cie_length[6]=strlen(author);
   }
  else  // process chunk
   {
    if ((to-from) > 50000) ParserECS=5000;
    else if ((to-from) > 20000) ParserECS=3000;
    
    ci = AllocVec(sizeof(struct iX_ChunkInfo),MEMF_CLEAR);
    ci->ci_entry = AllocVec(ParserECS,MEMF_ANY);
    ci->cie_position = AllocVec(ParserECS*4,MEMF_ANY);
    ci->cie_length = AllocVec(ParserECS*2,MEMF_ANY);
    ci->ci_data = AllocVec(to-from+2+39,MEMF_ANY);

    if (!ci || !ci->ci_entry || !ci->cie_position || !ci->cie_length || !ci->ci_data)
      return(NULL);
    
    if (fhan=Open(name,MODE_OLDFILE))
       {
        ci->ci_datalen=39;
        strcpy(ci->ci_data,"#00ff00#ff0000#0000ff#ffffff#ffff00TEXT");
                         //  green   red   blue  white  yellow  default
                         
        Seek(fhan,from,OFFSET_BEGINING);
        ci->ci_datalen += FRead(fhan,ci->ci_data+39,1,to-from+1);
        ci->ci_data[ci->ci_datalen] = 0;
        
        dp = ci->ci_data+39;
        ec=0;ecc=0;
      while(*dp)
       {
         if (strnicmp(dp,"#include ",9)==0)
           {
            PaintWord(9,0,ci,ParserECS,dp);
            dp+=9;
           }
          else
          if (strnicmp(dp,"#define ",8)==0)
           {
            PaintWord(8,4,ci,ParserECS,dp);
            dp+=8;
           }
          else
          if ((strnicmp(dp,"if(",3)==0) || (strnicmp(dp,"if ",3)==0)
              || (strnicmp(dp,"do{",3)==0) || (strnicmp(dp,"do ",3)==0))
           {
            PaintWord(2,1,ci,ParserECS,dp);
            dp+=2;
           }
          else
          if ((strnicmp(dp,"for(",4)==0) || (strnicmp(dp,"for ",4)==0))
           {
            PaintWord(3,1,ci,ParserECS,dp);
            dp+=3;
           }
          else
          if ((strnicmp(dp,"else{",5)==0) || (strnicmp(dp,"else ",5)==0))
           {
            PaintWord(4,1,ci,ParserECS,dp);
            dp+=4;
           }
          else
          if ((strnicmp(dp,"while(",6)==0) || (strnicmp(dp,"while ",6)==0))
           {
            PaintWord(5,1,ci,ParserECS,dp);
            dp+=5;
           }
          else
          if ((strnicmp(dp,"ULONG ",6)==0) || (strnicmp(dp,"UWORD ",6)==0)
              || (strnicmp(dp,"UBYTE ",6)==0))
           {
            PaintWord(5,2,ci,ParserECS,dp);
            dp+=5;
           }
           else
           if (strnicmp(dp,"int ",4)==0)
           {
            PaintWord(3,2,ci,ParserECS,dp);
            dp+=3;
           }
           else
           if ((strnicmp(dp,"long ",5)==0) || (strnicmp(dp,"BOOL ",5)==0)
               || (strnicmp(dp,"byte ",5)==0) || (strnicmp(dp,"char ",5)==0)
               || (strnicmp(dp,"word ",5)==0) || (strnicmp(dp,"void ",5)==0)
               || (strnicmp(dp,"VOID ",5)==0) || (strnicmp(dp,"APTR ",5)==0))
           {
            PaintWord(4,2,ci,ParserECS,dp);
            dp+=4;
           }
           else
           if ((strnicmp(dp,"switch ",7)==0) || (strnicmp(dp,"switch(",7)==0))
           {
            PaintWord(6,1,ci,ParserECS,dp);
            dp+=6;
           }
           else
           if (strnicmp(dp,"case ",5)==0)
           {
            PaintWord(4,4,ci,ParserECS,dp);
            dp+=4;
           }
           else
           if (strnicmp(dp,"struct ",7)==0)
           {
            PaintWord(6,2,ci,ParserECS,dp);
            dp+=6;
           };
           
         if (*dp)
         {
          if (*dp=='\n')
            {
              ci->ci_entry[ec]=ET_RTRN;
              *dp=' ';ec++;ecc++;CheckMemory(ci,&ecc,ec,ParserECS);
              dp++;
            }
           else if (*dp==' ')
             {
               ci->ci_entry[ec]=ET_SPC;
               ci->cie_length[ec]=0;
               while(*dp && (*dp==' ')) {dp++;ci->cie_length[ec]++;};
               ec++;ecc++;CheckMemory(ci,&ecc,ec,ParserECS); 
             } else {
                     ci->ci_entry[ec]=ET_WORD;
                     ci->cie_position[ec]=dp-ci->ci_data;
                     ci->cie_length[ec]=0;
                     while(*dp && (*dp!=' ') && (*dp!='\n')) {dp++;ci->cie_length[ec]++;};
                     ec++;ecc++;CheckMemory(ci,&ecc,ec,ParserECS);
                    };

         };
       };  
       
       ci->ci_entry[ec]=ET_END;
       ci->ci_entrynum=ec;
        Close(fhan);
       };
   };
   
  return(ci);
}
