/*###################################################################################
#
#   Embperl - Copyright (c) 1997-1999 Gerald Richter / ECOS
#
#   You may distribute under the terms of either the GNU General Public
#   License or the Artistic License, as specified in the Perl README file.
#   For use with Apache httpd and mod_perl, see also Apache copyright.
#
#   THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
#   IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
#   WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
###################################################################################*/



#ifdef EP2
/*-----------------------------------------------------------------*/
/*								   */
/*  cache Options						   */
/*								   */
/*-----------------------------------------------------------------*/

typedef enum tCacheOptions
    {
    ckoptCarryOver = 1,   /* use result from CacheKeyCV of preivious step if any */
    ckoptPathInfo  = 2,   /* include the PathInfo into CacheKey */
    ckoptQueryInfo = 4,	  /* include the QueryInfo into CacheKey */
    ckoptDontCachePost = 8,	  /* don't cache POST requests */
    ckoptDefault    = 15,	  /* default is all options set */
    } tCacheOptions ;


/*-----------------------------------------------------------------*/
/*								   */
/*  Processor							   */
/*								   */
/*-----------------------------------------------------------------*/


typedef struct tProcessor
    {
    int nProcessorNo ;
    const char *    sName ;
    int (* pPreCompiler)            (/*in*/  tReq *	  r,
				     /*in*/  struct tProcessor * pProcessor,
				     /*in*/  tDomTree **  ppDomTree,
				     /*in*/  SV **        ppPreCompResult,
				     /*out*/ SV **        ppCompResult) ;
    int (* pCompiler)               (/*in*/  tReq *	  r,
				     /*in*/  struct tProcessor * pProcessor,
				     /*in*/  tDomTree **  ppDomTree,
				     /*in*/  SV **        ppPreCompResult,
				     /*out*/ SV **        ppCompResult) ;
    int (* pPreExecuter)            (/*in*/  tReq *	  r,
				     /*in*/  struct tProcessor * pProcessor,
				     /*in*/  tDomTree **  pDomTree,
				     /*in*/  SV **        ppPreCompResult,
				     /*in*/  SV **        ppCompResult) ;
    int (* pExecuter)               (/*in*/  tReq *	  r,
				     /*in*/  struct tProcessor * pProcessor,
				     /*in*/  tDomTree **  pDomTree,
				     /*in*/  SV **        ppPreCompResult,
				     /*in*/  SV **        ppCompResult,
				     /*out*/ SV **        ppExecResult) ;

    const char *    sCacheKey ;	    /* literal to add to key for cache */
    CV *	    pCacheKeyCV ;   /* CV to call and add result to key for cache */
    tCacheOptions   bCacheKeyOptions ;
    double          nOutputExpiresIn ;
    CV *            pOutputExpiresCV ;

    struct tProcessor * pNext ;
    } tProcessor ;

/*-----------------------------------------------------------------*/
/*								   */
/*  RequestPhases						   */
/*								   */
/*-----------------------------------------------------------------*/

typedef enum 
    {
    phInit,
    phParse,
    phCompile,
    phRunAfterCompile,
    phPerlCompile,
    phRun,
    phTerm
    } tPhase ;
    
/*-----------------------------------------------------------------*/
/*								   */
/*  Parser data structures 	            			   */
/*								   */
/*-----------------------------------------------------------------*/

typedef   unsigned char tCharMap [256/(sizeof(unsigned char)*8)]   ;

struct tToken
    {
    const char *	    sText ;	/* string of token (MUST be first item!) */
    const char *	    sName ;	/* name of token (only for description) */
    int			    nTextLen ;	/* len of string */
    const char *	    sEndText ;	/* string which ends the block */
    const char *	    sNodeName;	/* name of the node to create */
    int			    nNodeName ;	/* index in string table of node name */
    enum tNodeType	    nNodeType ;	/* type of the node that should be created */
    enum tNodeType	    nCDataType ;/* type for sub nodes that contains text */
    enum tNodeType	    nForceType ;/* force this type for sub nodes */
    int			    bUnescape ;	/* translate input?  */
    unsigned char *	    pContains ;	/* chars that could be contained in the string */
    struct tTokenTable *    pFollowedBy;/* table of tokens that can follow this one */
    struct tTokenTable *    pInside ;	/* table of tokens that can apear inside this one */
    struct tToken      *    pStartTag ;	/* token that contains definition for the start of the current token */
    struct tToken      *    pEndTag ;	/* token that contains definition for the end of the current token */
    const char *	    sParseTimePerlCode ; /* perl code that is executed when this token is parsed, %% is replaced by the value of the current attribute */
    } ;        

struct tTokenTable
    {
    void *	    pCompilerInfo ; /* stores tables of the compiler , must be first item */
    const char *    sName ;	    /* name of syntax */
    tCharMap	    cStartChars ;   /* for every vaild start char there is one bit set */
    tCharMap	    cAllChars   ;   /* for every vaild char there is one bit set */
    struct tToken * pTokens ;	    /* table with all tokens */
    int             numTokens ;	    /* number of tokens in above table */
    int		    bLSearch ;	    /* when set perform a linear, instead of a binary search */
    struct tToken * pContainsToken ;/* pointer to the token that has a pContains defined (could be only one per table) */
    } ;

typedef struct tTokenTable tTokenTable ;
    
#else

typedef void * tTokenTable ;


#endif



/*-----------------------------------------------------------------*/
/*								   */
/*  Per (directory) configuration data				   */
/*								   */
/*-----------------------------------------------------------------*/


typedef struct tConf
    {
    int     bDebug ;	    /* Debugging options */
    int     bOptions ;	    /* Options */
    char *  sPackage ;	    /* Packagename */
    char *  sLogFilename ;  /* name of logfile */
    char *  sVirtLogURI ;      /* uri for access virtual log file */
    SV *    pOpcodeMask ;   /* Opcode mask (if any) */
    int     nEscMode ;      /* default escape mode */
    char *  sCookieName ;   /* Name to use for cookie */
    char *  sCookieExpires ; /* cookie expiration time */
    char *  sCookieDomain ; /* domain patter for which the cookie should be returned */
    char *  sCookiePath ;   /* path to which cookie should be returned */
    char    cMultFieldSep ;
    char *  pOpenBracket  ;
    char *  pCloseBracket ;
#ifdef EP2
    bool    bEP1Compat ;    /* run in Embperl 1.x compatible mode */
    tProcessor ** pProcessor ;   /* [array] processors used to process the file */
    char *  sCacheKey ;    /* Key used to store expires setting */
    CV *	    pCacheKeyCV ;   /* CV to call and add result to key for cache */
    tCacheOptions   bCacheKeyOptions ;
    double  nExpiresIn ;   /* Data expiers at */
    CV *    pExpiresCV ;   /* sub that is called to determinate expiration */
#endif    
    char *  sPath ;	    /* file search path */
    char *  sReqFilename ;  /* filename of original request */
    } tConf ;

/*-----------------------------------------------------------------*/
/*								   */
/*  Per sourcefile data 					   */
/*								   */
/*-----------------------------------------------------------------*/


typedef struct tFile
    {
    char *  sSourcefile ;   /* Name of sourcefile */
    double  mtime ;	    /* last modification time of file */
    size_t  nFilesize ;	    /* size of File */
    SV *    pBufSV ;        /* SV that contains the file content */
    bool    bKeep ;	    /* set true if you want to keep file in memory */
    
    HV *    pCacheHash ;    /* Hash containing CVs to precompiled subs */

    char *  sCurrPackage ;  /* Package of file  */
    STRLEN  nCurrPackage ;  /* Package of file (length) */
    HV *    pExportHash ;   /* exportable Macros */

    int	    nFirstLine ;    /* First line number of sourcefile */

    struct tFile * pNext2Free ;  /* Next file that has to be freed after the request */
    } tFile ;

/*-----------------------------------------------------------------*/
/*								   */
/*  Per sourcebuffer data 					   */
/*								   */
/*-----------------------------------------------------------------*/


typedef struct tSrcBuf
    {
    tFile * pFile ;             /* pointer source file/package specific data */
    char *  pBuf ;	        /* Buffer which holds the html source file */
    char *  pCurrPos ;	        /* Current position in html file */
    char *  pCurrStart ;        /* Current start position of html tag / eval expression */
    char *  pEndPos ;	        /* end of html file */
    int     nBlockNo ;          /* Block number where we are currently */
    char *  pCurrTag ;	        /* Current start position of html tag */
    int     nSourceline ;       /* Currentline in sourcefile */
    char *  pSourcelinePos ;    /* Positon of nSourceline in sourcefile */
    char *  pLineNoCurrPos ;    /* save pCurrPos for line no calculation */
    char *  sEvalPackage ;      /* Package for eval (normaly same sCurrPackage,
			           differs when running in a safe namespace */
    STRLEN  nEvalPackage ;      /* Package for eval (length) */
    } tSrcBuf ;
    

/*-----------------------------------------------------------------*/
/*								   */
/*  Commandtypes         					   */
/*								   */
/*-----------------------------------------------------------------*/
   
enum tCmdType
    {
    cmdNorm     = 1,
    cmdIf       = 2,
    cmdEndif    = 4,
    cmdWhile    = 8,
    cmdTable    = 16,
    cmdTablerow = 32,
    cmdTextarea = 64,
    cmdDo       = 128,
    cmdForeach  = 256,
    cmdSub      = 512,

    cmdAll      = 1023
    } ;

enum tCmdNo
    {
    cnNop,       
    cnTable,
    cnTr,
    cnDir,
    cnMenu,
    cnOl,
    cnUl,
    cnDl,
    cnSelect,
    cnDo,
    cnForeach
    } ;

/*-----------------------------------------------------------------*/
/*								   */
/*  Commands             					   */
/*								   */
/*-----------------------------------------------------------------*/
   

typedef struct tCmd
    {
    const char *    sCmdName ;     /* Commandname */
    int            ( *pProc)(/*i/o*/ register req * r, /*in*/ const char *   sArg) ;   /* pointer to the procedure */
    bool            bPush ;         /* Push current state? */
    bool            bPop ;          /* Pop last state? */
    enum tCmdType   nCmdType ;      /* Type of the command  */
    bool            bScanArg ;      /* is it nessesary to scan the command arg */
    bool            bSaveArg ;      /* is it nessesary to save the command arg for later use */
    enum tCmdNo     nCmdNo ;        /* number of command to catch mismatch in start/end */
    int             bDisableOption ; /* option bit which disables this cmd */
    bool            bHtml ;          /* this is an html tag */
    } tCmd ;


/*-----------------------------------------------------------------*/
/*								   */
/*  Command/HTML-Stack         					   */
/*								   */
/*-----------------------------------------------------------------*/
   

typedef struct tStackEntry
    {
    enum tCmdType   nCmdType ;      /* Type of the command which the pushed the entry on the stack */
    char *          pStart ;        /* Startposition for loops */
    int             nBlockNo ;      /* Block number where the startposition is */
    long            bProcessCmds ;  /* Process corresponding cmds */
    int             nResult ;       /* Result of Command which starts the block */
    char *          sArg ;          /* Argument of Command which starts the block */
    SV *            pSV ;           /* Additional Data */
    SV *            pSV2 ;          /* Additional Data */
    struct tBuf *   pBuf;          /* Output buf for table rollback          */
    struct tCmd *   pCmd ;          /* pointer to command infos */
    struct tStackEntry * pNext ;      /* pointer to next one on stack/free list */
    } tStackEntry ;


/*-----------------------------------------------------------------*/
/*								   */
/*  Table-Stack         					   */
/*								   */
/*-----------------------------------------------------------------*/
   

typedef struct tTableStackEntry
    {
    int             nResult ;       /* Result of Command which starts the block */
    int             nCount ;        /* Count for tables, lists etc */
    int             nCountUsed ;    /* Count for tables, lists is used in Table  */
    int             nRow ;          /* Row Count for tables, lists etc */
    int             nRowUsed ;      /* Row Count for tables, lists is used in Table  */
    int             nCol ;          /* Column Count for tables, lists etc */
    int             nColUsed ;      /* Column Count for tables, lists is used in Table  */
    int             nMaxRow ;       /* maximum rows */
    int             nMaxCol ;       /* maximum columns */
    int             nTabMode;      /* table mode */
    int             bHead ;         /* this row contains a heading */
    int             bRowHead ;      /* the entire row is made of th tags */
    struct tTableStackEntry * pNext ;      /* pointer to next one on stack/free list */
    } tTableStackEntry ;

/*-----------------------------------------------------------------*/
/*								   */
/*  Stack-Pointer         					   */
/*								   */
/*-----------------------------------------------------------------*/


typedef struct tStackPointer

    {
    struct tStackEntry * pStack  ;      /* pointer to stacked entrys */
    struct tStackEntry * pStackFree  ;  /* pointer to currently unused entrys */

    struct tStackEntry State ;	        /* top of stack */
    } tStackPointer ;


typedef struct tTableStackPointer

    {
    struct tTableStackEntry * pStack  ;      /* pointer to stacked entrys */
    struct tTableStackEntry * pStackFree  ;  /* pointer to currently unused entrys */

    struct tTableStackEntry State ;	        /* top of stack */
    } tTableStackPointer ;

   
/*-----------------------------------------------------------------*/
/*								   */
/*  Per request data						   */
/*								   */
/*-----------------------------------------------------------------*/

#define ERRDATLEN 1024

#ifdef WIN32
#define pid_t int
#endif


struct tReq
    {
    SV *          pReqSV ;      /* The perl reference to this request structure */

    #ifdef APACHE
    request_rec * pApacheReq ;	/* apache request record */
    SV *          pApacheReqSV ;
    #endif

    pid_t nPid ;                /* process/thread id */
    
    tConf * pConf ;             /* pointer to configuration data */

    bool    bReqRunning  ;	/* we are inside of a request */
    int     bDebug ;		/* Debugging options */
    int     bOptions ;		/* Options */
    int     nIOType ;
    bool    bSubReq ;           /* This is a sub request (called inside an Embperl page) */
    char *  sSubName ;          /* subroutine to call */
    int	    nSessionMgnt ;	/* how to retrieve the session id */
    int	    nInsideSub ;	/* Are we inside of a sub? */
    int	    bExit ;		/* We should exit the page */
    int	    nPathNdx ;		/* gives the index in the path where the current file is found */
#ifdef EP2
    bool    bEP1Compat ;	/* run in Embperl 1.x compatible mode */    
    tPhase  nPhase ;		/* which phase of the request we are in */

    char *  sPathInfo ;
    char *  sQueryInfo ;
    
    /* --- DomTree ---*/

    tNode	xDocument ;
    tNode	xCurrNode ;
    tIndex	xCurrDomTree ;
#endif
    tTokenTable *  pTokenTable ;


    /* --- Source in memory --- */

    tSrcBuf   Buf ;            /* Buffer */
    tSrcBuf * pBufStack  ;     /* pointer to buffer stack */
    tSrcBuf * pBufStackFree  ; /* pointer to buffer stack free list*/

    tFile * pFiles2Free ;	/* files that has to be freed after the request (only valid in main request) */

    /* --- command handling --- */

    tCmd *              pCurrCmd ;	/* Current cmd which is excuted */

    /* --- Stacks --- */

    tStackPointer       CmdStack  ;      /* Stack for if, while, etc. */
    tStackPointer       HtmlStack ;      /* Stack for table etc. */
    tTableStackPointer  TableStack ;     /* Stack for table */

    /* --- Tablehandling --- */

    int nTabMode    ;	 /* mode for next table (only takes affect after next <TABLE> */
    int nTabMaxRow  ;	 /* maximum rows for next table (only takes affect after next <TABLE> */
    int nTabMaxCol  ;	 /* maximum columns for next table (only takes affect after next <TABLE> */

    /* --- Escaping --- */

    struct tCharTrans * pCurrEscape ;   /* pointer to current escape table */
    struct tCharTrans * pNextEscape ;   /* pointer to next escape table (after end of block) */
    int                 nEscMode ;      /* escape mode set by the user */
    int                 nCurrEscMode ;  /* current active escape mode */
    int                 bEscModeSet ;   /* escape mode already set in this block */
    int                 bEscInUrl ;     /* we are inside an url */
    
    /* --- memory management --- */

    size_t nAllocSize ;             /*  Alloced memory for debugging */

    /* --- buffering output */

    struct tBuf *   pFirstBuf  ;    /* First buffer */
    struct tBuf *   pLastBuf   ;    /* Last written buffer */
    struct tBuf *   pFreeBuf   ;    /* List of unused buffers */
    struct tBuf *   pLastFreeBuf ;  /* End of list of unused buffers */

    char *          pMemBuf ;	    /* temporary output */
    char *          pMemBufPtr ;    /* temporary output */
    size_t          nMemBufSize ;   /* size of pMemBuf */
    size_t          nMemBufSizeFree;/* remaining space in pMemBuf */

    int     nMarker ;               /*  Makers for rollback output */

    /* --- i/o filehandles --- */

    #ifdef PerlIO
    PerlIO *  ifd  ;    /* input file */
    PerlIO *  ofd  ;    /* output file */
    PerlIO *  lfd  ;    /* log file */
    #else
    FILE *  ifd  ;      /* input file */
    FILE *  ofd  ;      /* output file */
    FILE *  lfd  ;      /* log file */
    #endif

    long    nLogFileStartPos ; /* file position of logfile, when logfile started */
    char *  sOutputfile ;      /* name of output file */
    bool    bAppendToMainReq ; /* append output to main request */
    bool    bDisableOutput ;   /* no output is generated */

    SV *    pOutData ;
    SV *    pInData ;
    
    /* ------------------------ */

    tReq *  pNext ;  /* Next free one */
    tReq *  pLastReq ;  /* Request from which this one is called */

    /* ------------------------ */
    
    /* --- keep track of errors --- */

    bool    bError  ;		/* Error has occured somewhere */
    I32     nLastErrFill  ;	/* last size of error array */
    int     bLastErrState ;	/* last state of error flag */
    AV *    pErrArray ; 	/* Errors to show on Error response */
    AV *    pErrFill ;		/* AvFILL of pErrArray, index is nMarker */
    AV *    pErrState ; 	/* bError, index is nMarker  */

    /* Everything after here will not automaticly set to zero */
    int     zeroend ;

    char    errdat1 [ERRDATLEN] ; /* Additional error information */
    char    errdat2 [ERRDATLEN] ;
    char    lastwarn [ERRDATLEN] ; /* last warning */

    /* --- Embperl special hashs/arrays --- */

    HV *    pEnvHash ;	 /* environement from CGI Script */
    HV *    pFormHash ;  /* Formular data */
    HV *    pFormSplitHash ;  /* Formular data split up at \t */
    HV *    pInputHash ; /* Data of input fields */
    AV *    pFormArray ; /* Fieldnames */
    HV *    pUserHash ;  /* User data */
    HV *    pModHash ;   /* Module data */
    HV *    pHeaderHash ;/* http headers */
#ifdef EP2
    AV *    pDomTreeAV ; /* holds all DomTrees alocated during the request */
    AV *    pCleanupAV ; /* set all sv's that are conatined in that array to undef after the whole request */
#endif

    /* --- for statistics --- */

    clock_t startclock ;
    I32     stsv_count ;
    I32     stsv_objcount ;
    I32     lstsv_count ;
    I32     lstsv_objcount  ;
    int     numEvals ;
    int     numCacheHits ;

    /* --- more infos for eval --- */

    int  bStrict ; /* aply use strict in each eval */

    char op_mask_buf[MAXO + 100]; /* save buffer for opcode mask - maxo shouldn't differ from MAXO but leave room anyway (see BOOT:)	*/

    HV *  pImportStash ;	/* stash for package, where new macros should be imported */

#ifdef EP2
    
    char * * pProg ;            /* pointer into currently compiled code */
    char * pProgRun ;           /* pointer into currently compiled run code */
    char * pProgDef ;           /* pointer into currently compiled define code */

    SV *   pCodeSV ;		/* contains currently compiled line */
#endif

    } ;




#define EPMAINSUB   "_ep_main"
