Skip to content

Instantly share code, notes, and snippets.

@d3x0r
Last active January 23, 2021 05:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save d3x0r/8c8ab33cd7130c3c9983e12d354ad067 to your computer and use it in GitHub Desktop.
Save d3x0r/8c8ab33cd7130c3c9983e12d354ad067 to your computer and use it in GitHub Desktop.
This is portable a C preprocessor written in low level C.
// make #if conditions spanning files a warning...
// also unbalanced #endif statements....
#ifndef __GCC__
//#include <conio.h>
#endif
#if defined( _WIN32 )
// getmodulefilename
#include <windows.h>
#include <direct.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef FILEIO_DEFINED
#define FILEIO_DEFINED
#ifndef TEXT_SUPPORT
#define TEXT_SUPPORT
#include <string.h>
#ifndef MY_TYPES_INCLUDED
#define MY_TYPES_INCLUDED
#include <ctype.h>
#if defined( GCC) && !defined( __ARM__ ) && !defined( __EMSCRIPTEN__ )
# define DebugBreak() asm( "int $3\n" )
#else
# define DebugBreak()
#endif
#ifdef __WATCOMC__
# define CPROC _cdecl
#else
#define CPROC
#endif
#ifdef _MSC_VER
#define LONGEST_INT __int64
#else
#define LONGEST_INT long long
#endif
#define LONGEST_FLT double
// this is for passing FILE, LINE information to allocate
// useful during DEBUG phases only...
#ifdef _DEBUG
# define DBG_SRC , __FILE__, __LINE__
# define DBG_VOIDSRC __FILE__, __LINE__
# define DBG_VOIDPASS char *pFile, int nLine
# define DBG_PASS , char *pFile, int nLine
# define DBG_RELAY , pFile, nLine
# define DBG_FORWARD , pFile, nLine
# define DBG_FILELINEFMT "%s(%d)"
#else
# define DBG_SRC
# define DBG_VOIDSRC
# define DBG_VOIDPASS void
# define DBG_PASS
# define DBG_RELAY
# define DBG_FORWARD , __FILE__, __LINE__
# define DBG_FILELINEFMT
#endif
#ifndef FALSE
# define FALSE 0
#endif
#ifndef TRUE
# define TRUE (!FALSE)
#endif
//typedef void _0;
typedef void *P_0;
#include <stdint.h>
typedef const unsigned char *CTEXTSTR;
typedef unsigned char TEXTCHAR;
typedef TEXTCHAR *TEXTSTR;
typedef size_t INDEX;
#define INVALID_INDEX ((size_t)-1)
typedef void *POINTER;
typedef const void *CPOINTER;
typedef uint32_t LOGICAL;
#define DECLDATA(name,sz) struct {uintptr_t size; uint8_t data[sz];} name
typedef struct DataBlock {
// size is sometimes a pointer value...
uintptr_t size;
// this means bad thing when we change platforms...
// beginning of var data - this is created size+sizeof(VPA)
uint8_t data[1];
} DATA, *PDATA;
typedef struct LinkBlock
{
size_t Cnt;
uint32_t Lock;
POINTER pNode[1];
} LIST, *PLIST;
typedef struct DataListBlock
{
size_t Cnt;
size_t Size;
uint8_t data[1];
} DATALIST, *PDATALIST;
typedef struct LinkStack
{
size_t Top;
size_t Cnt;
POINTER pNode[1];
} LINKSTACK, *PLINKSTACK;
typedef struct DataListStack
{
// next avail...
size_t Top;
size_t Cnt;
size_t Size;
uint8_t data[1];
} DATASTACK, *PDATASTACK;
typedef struct LinkQueue
{
size_t Top;
size_t Bottom;
size_t Cnt;
// thread interlock using InterlockedExchange semaphore
uint32_t Lock;
// need two to have distinct empty/full conditions
POINTER pNode[2];
} LINKQUEUE, *PLINKQUEUE;
// additional step function...
typedef struct LinkStackQueue
{
size_t Top;
size_t Bottom;
size_t Next;
size_t Cnt;
// need two to have distinct empty/full conditions
POINTER pNode[2];
} LINKSTACKQUEUE, *PLINKSTACKQUEUE;
#endif
#define DEFAULT_COLOR 0xF7
// this does not change the color....
#define PRIOR_COLOR 0xF6
typedef struct format_info_tag
{
// for restoration of spaces in strings?
int spaces;
int tabs;
} FORMAT, *PFORMAT;
// declared in program data.... do NOT release
#define TF_STATIC 0x00000001
// data field extually points at PTEXT
#define TF_INDIRECT 0x00000002
// on release release indrect also...
#define TF_DEEP 0x00000004
// don't expand - define substitution handling...
#define TF_NOEXPAND 0x00010000
// these values used originally for ODBC query construction....
// these values are flags stored on the indirect following a value
// label...
// flag combinatoin which represents actual data is present even with 0 size
#define IS_DATA_FLAGS (0)
#define DECLTEXTSZ( name, size ) struct { uint32_t flags; struct text_segment_tag *Next, *Prior; FORMAT format; DECLDATA(data, size); } name
typedef struct text_segment_tag
{
// then here I could overlap with pEnt .bshadow, bmacro, btext ?
uint32_t flags;
struct text_segment_tag *Next, *Prior;
// valid if TF_FORMAT is set...
FORMAT format;
// must be last since var character data is included
DATA data;
} TEXT, *PTEXT;
#define DEFTEXT(str) {TF_STATIC,NULL,NULL,{0},{sizeof(str)-1,str}}
#define DECLTEXT(name, str) static DECLTEXTSZ( name, sizeof(str) ) = DEFTEXT(str)
extern TEXT newline;
//#define SETPRIORLINE(line,p) SetPriorLineEx( line, p DBG_SRC )
//#define SETNEXTLINE(line,p) SetNextLineEx( line, p DBG_SRC )
#define SETPRIORLINE(line,p) ((line)?(((line)->Prior) = (PTEXT)(p)):0)
#define SETNEXTLINE(line,p) ((line)?(((line)->Next ) = (PTEXT)(p)):0)
#define NEXTLINE(line) ((PTEXT)(((PTEXT)line)?(((PTEXT)line)->Next):(NULL)))
#define PRIORLINE(line) ((PTEXT)(((PTEXT)line)?(((PTEXT)line)->Prior):(NULL)))
#define SetStart(line) do { PTEXT tmp; for(; line && (tmp=PRIORLINE(line));line=tmp); } while(0)
#define SetEnd(line) do { PTEXT tmp; for(; line && (tmp=NEXTLINE(line)); line=tmp); } while (0)
// might also check to see if pseg is an indirect - setting this size would be BAD
#define SetTextSize(pseg, sz ) ((pseg)?((pseg)->data.size = (sz )):0)
PTEXT GetIndirect(PTEXT segment );
int GetTextFlags( PTEXT segment );
INDEX GetTextSize( PTEXT segment );
char *GetTextEx( PTEXT segment );
#define GetText(seg) ((seg)?((seg)->flags&TF_INDIRECT)?GetTextEx(seg):(char*)((PTEXT)(seg))->data.data:(char*)NULL)
#define SetIndirect(Seg,Where) ( (Seg)->data.size = (int)(Where) )
#define SameText( l1, l2 ) ( strcmp( GetText(l1), GetText(l2) ) )
#ifdef _WIN32
#define strncasecmp strnicmp
#endif
#define LikeText( l1, l2 ) ( strncasecmp( GetText(l1), GetText(l2), ( (GetTextSize(l1)<GetTextSize(l2)) ?GetTextSize(l1): GetTextSize(l2) ) ) )
#define TextIs(text,string) ( !stricmp( GetText(text), string ) )
#define TextLike(text,string) ( !stricmp( GetText(text), string ) )
PTEXT SegCreateEx( size_t nSize DBG_PASS );
#define SegCreate(s) SegCreateEx(s DBG_SRC)
PTEXT SegCreateFromTextEx( char *text DBG_PASS );
#define SegCreateFromText(t) SegCreateFromTextEx(t DBG_SRC)
PTEXT SegCreateIndirectEx( PTEXT pText DBG_PASS );
#define SegCreateIndirect(t) SegCreateIndirectEx(t DBG_SRC)
PTEXT SegDuplicateEx( PTEXT pText DBG_PASS);
#define SegDuplicate(pt) SegDuplicateEx( pt DBG_SRC )
PTEXT LineDuplicateEx( PTEXT pText DBG_PASS );
#define LineDuplicate(pt) LineDuplicateEx(pt DBG_SRC )
PTEXT TextDuplicateEx( PTEXT pText DBG_PASS );
#define TextDuplicate(pt) TextDuplicateEx(pt DBG_SRC )
PTEXT SegCreateFromIntEx( int value DBG_PASS );
#define SegCreateFromInt(v) SegCreateFromIntEx( v DBG_SRC )
PTEXT SegCreateFromFloatEx( float value DBG_PASS );
#define SegCreateFromFloat(v) SegCreateFromFloatEx( v DBG_SRC )
PTEXT SegAppend ( PTEXT source, PTEXT other );
// returns other instead of source
PTEXT SegAdd (PTEXT source,PTEXT other);
PTEXT SegInsert ( PTEXT what, PTEXT before );
// add last node... blank space.
PTEXT SegExpandEx (PTEXT source, int nSize DBG_PASS );
#define SegExpand(s,n) SegExpandEx( s,n DBG_SRC );
void LineReleaseEx (PTEXT *line DBG_PASS );
#define LineRelease(l) LineReleaseEx( &l DBG_SRC )
void SegReleaseEx( PTEXT seg DBG_PASS );
#define SegRelease(l) SegReleaseEx(l DBG_SRC )
PTEXT SegConcatEx (PTEXT output,PTEXT input,int32_t offset,int32_t length DBG_PASS);
#define SegConcat(out,in,ofs,len) SegConcatEx(out,in,ofs,len DBG_SRC)
PTEXT SegUnlink (PTEXT segment);
PTEXT SegBreak (PTEXT segment);
// removes seg from list, deletes seg.
PTEXT SegDeleteEx (PTEXT *segment DBG_PASS);
#define SegDelete(s) SegDeleteEx(s DBG_SRC)
// removes seg from list, returns seg.
PTEXT SegGrab (PTEXT segment);
PTEXT SegSubst ( PTEXT _this, PTEXT that );
PTEXT SegSubstRangeEx( PTEXT *_this, PTEXT end, PTEXT that DBG_PASS);
#define SegSubstRange(this,end,that) SegSubstRangeEx(this,end,that DBG_SRC)
PTEXT SegSplitEx( PTEXT *pLine, size_t nPos DBG_PASS);
#define SegSplit(line,pos) SegSplitEx( line, pos DBG_SRC )
size_t LineLength( PTEXT pt, int bSingle );
PTEXT BuildLineEx( PTEXT pt, int bSingle DBG_PASS );
#define BuildLine(from) BuildLineEx( from, FALSE DBG_SRC )
int CompareStrings( PTEXT pt1, int single1
, PTEXT pt2, int single2
, int bExact );
#define FORALLTEXT(start,var) for(var=start;var; var=NEXTLINE(var))
//-----------------------------------------------------------------------
#define TYPELIB_PROC(t,n) t n
typedef struct vartext_tag {
char *collect_text;
INDEX collect_used;
PTEXT collect;
PTEXT commit;
} VARTEXT, *PVARTEXT;
TYPELIB_PROC( void, VarTextInitEx)( PVARTEXT pvt DBG_PASS);
#define VarTextInit(pvt) VarTextInitEx( (pvt) DBG_SRC )
TYPELIB_PROC( void, VarTextEmptyEx)( PVARTEXT pvt DBG_PASS);
#define VarTextEmpty(pvt) VarTextEmptyEx( (pvt) DBG_SRC )
TYPELIB_PROC( void, VarTextAddCharacterEx)( PVARTEXT pvt, char c DBG_PASS );
#define VarTextAddCharacter(pvt,c) VarTextAddCharacterEx( (pvt),(c) DBG_SRC )
// returns true if any data was added...
// move any collected text to commit...
TYPELIB_PROC( PTEXT, VarTextEndEx)( PVARTEXT pvt DBG_PASS );
#define VarTextEnd(pvt) VarTextEndEx( (pvt) DBG_SRC )
TYPELIB_PROC( size_t, VarTextLength)( PVARTEXT pvt );
TYPELIB_PROC( PTEXT, VarTextGetEx)( PVARTEXT pvt DBG_PASS );
#define VarTextGet(pvt) VarTextGetEx( (pvt) DBG_SRC )
TYPELIB_PROC( void, VarTextExpandEx)( PVARTEXT pvt, int size DBG_PASS );
#define VarTextExpand(pvt, sz) VarTextExpandEx( (pvt), (sz) DBG_SRC )
//TYPELIB_PROC( int vtprintfEx( PVARTEXT pvt DBG_PASS, char *format, ... );
// note - don't include format - MUST have at least one parameter passed to ...
//#define vtprintf(pvt, ...) vtprintfEx( (pvt) DBG_SRC, __VA_ARGS__ )
TYPELIB_PROC( int, vtprintfEx)( PVARTEXT pvt, char *format, ... );
// note - don't include format - MUST have at least one parameter passed to ...
#define vtprintf vtprintfEx
#endif
#define __MAX_PATH__ 256
typedef struct file_tracking_tag
{
int nLine;
// if I use malloc this dynamic member failed ...
char name[__MAX_PATH__];
// if I use malloc this dynamic member failed ...
char longname[__MAX_PATH__];
FILE *file;
// last line read...
PTEXT line;
// last line parsed
PTEXT pParsed;
// next token to be used...
PTEXT pNextWord;
// stack...
struct file_tracking_tag *prior;
struct file_dependancy_tag *pFileDep;
// state remains multi-lines
int bBlockComment;
// level of ifs started when this file is opened.
int nIfLevel;
// -- state tracking per file --
/*
int nState;
int nIfLevels; // count up and down always...
int nIfLevelElse; // what level to find the else on...
*/
} FILETRACK, *PFILETRACK;
typedef struct file_dependancy_tag
{
char full_name[__MAX_PATH__];
char base_name[__MAX_PATH__];
int bAllowMultipleInclude;
// what file included this
struct file_dependancy_tag *pDependedBy
// first file this one depends on
, *pDependsOn
// next file which pDepended by depends on
, *pAlso;
} FILEDEP, *PFILEDEP;
void SetCurrentPath( char *path );
uintptr_t OpenInputFile( char *basename, char *file );
uintptr_t OpenOutputFile( char *newfile );
uintptr_t OpenStdOutputFile( void );
uintptr_t OpenNewInputFile( char *basename, char *name, char *pFile, int nLine, int bDepend, int bNext );
void CloseInputFileEx( DBG_VOIDPASS );
#define CloseInputFile() CloseInputFileEx( DBG_VOIDSRC )
PFILEDEP AddFileDepend( PFILETRACK pft, char *basename, char *filename );
LOGICAL AlreadyLoaded( char *filename );
void SetIfBegin( void );
void ClearIfBegin( void );
void GetIfBegin( char **file, int *line );
FILE *GetCurrentOutput(void);
int GetCurrentLine( void );
char *GetCurrentFileName( void );
char *GetCurrentShortFileName( void );
void GetCurrentFileLine( char *name, int *line );
// how many files deep we're processing
int CurrentFileDepth( void );
PTEXT GetCurrentWord( void );
PTEXT *GetCurrentTextLine( void );
PTEXT StepCurrentWord( void );
PTEXT GetNextWord( void );
void SetCurrentWord( PTEXT word );
char *pathrchr( char *path );
PTEXT ReadLineEx( int Append DBG_PASS );
#define ReadLine(a) ReadLineEx(a DBG_SRC)
void WriteLineInfo( char *file, int line );
void WriteCurrentLineInfo( void );
void WriteLine( size_t len, char *line );
void DumpDepends( void );
void DestoyDepends( void );
char *pathrchr( char *path );
char *pathchr( char *path );
//---------- actually is args.c; but it's only the one function......
void ParseIntoArgs( char *lpCmdLine, int *pArgc, char ***pArgv );
#endif
#ifndef PPC_MEMORY_INTERFACE_DEFINED
#define PPC_MEMORY_INTERFACE_DEFINED
#if defined __WATCOMC__
//# include "sharemem.h"
#else
#ifndef MY_TYPES_INCLUDED
#define MY_TYPES_INCLUDED
#if defined( GCC) && !defined( __ARM__ ) && !defined( __EMSCRIPTEN__ )
# define DebugBreak() asm( "int $3\n" )
#else
# define DebugBreak()
#endif
#ifdef __WATCOMC__
# define CPROC _cdecl
#else
#define CPROC
#endif
#ifdef _MSC_VER
#define LONGEST_INT __int64
#else
#define LONGEST_INT long long
#endif
#define LONGEST_FLT double
// this is for passing FILE, LINE information to allocate
// useful during DEBUG phases only...
#ifdef _DEBUG
# define DBG_SRC , __FILE__, __LINE__
# define DBG_VOIDSRC __FILE__, __LINE__
# define DBG_VOIDPASS char *pFile, int nLine
# define DBG_PASS , char *pFile, int nLine
# define DBG_RELAY , pFile, nLine
# define DBG_FORWARD , pFile, nLine
# define DBG_FILELINEFMT "%s(%d)"
#else
# define DBG_SRC
# define DBG_VOIDSRC
# define DBG_VOIDPASS void
# define DBG_PASS
# define DBG_RELAY
# define DBG_FORWARD , __FILE__, __LINE__
# define DBG_FILELINEFMT
#endif
#ifndef FALSE
# define FALSE 0
#endif
#ifndef TRUE
# define TRUE (!FALSE)
#endif
//typedef void _0;
typedef void *P_0;
typedef const unsigned char *CTEXTSTR;
typedef unsigned char TEXTCHAR;
typedef TEXTCHAR *TEXTSTR;
typedef size_t INDEX;
#define INVALID_INDEX ((size_t)-1)
typedef void *POINTER;
typedef const void *CPOINTER;
typedef uint32_t LOGICAL;
#define DECLDATA(name,sz) struct {uintptr_t size; uint8_t data[sz];} name
typedef struct DataBlock {
// size is sometimes a pointer value...
uintptr_t size;
// this means bad thing when we change platforms...
// beginning of var data - this is created size+sizeof(VPA)
uint8_t data[1];
} DATA, *PDATA;
typedef struct LinkBlock
{
size_t Cnt;
uint32_t Lock;
POINTER pNode[1];
} LIST, *PLIST;
typedef struct DataListBlock
{
size_t Cnt;
size_t Size;
uint8_t data[1];
} DATALIST, *PDATALIST;
typedef struct LinkStack
{
size_t Top;
size_t Cnt;
POINTER pNode[1];
} LINKSTACK, *PLINKSTACK;
typedef struct DataListStack
{
// next avail...
size_t Top;
size_t Cnt;
size_t Size;
uint8_t data[1];
} DATASTACK, *PDATASTACK;
typedef struct LinkQueue
{
size_t Top;
size_t Bottom;
size_t Cnt;
// thread interlock using InterlockedExchange semaphore
uint32_t Lock;
// need two to have distinct empty/full conditions
POINTER pNode[2];
} LINKQUEUE, *PLINKQUEUE;
// additional step function...
typedef struct LinkStackQueue
{
size_t Top;
size_t Bottom;
size_t Next;
size_t Cnt;
// need two to have distinct empty/full conditions
POINTER pNode[2];
} LINKSTACKQUEUE, *PLINKSTACKQUEUE;
#endif
void CPROC *AllocateEx( size_t nSize DBG_PASS );
# define Allocate(s) AllocateEx(s DBG_SRC)
void CPROC ReleaseExx( void ** DBG_PASS );
# if defined( __WATCOMC__ ) || defined( _MSC_VER )
# ifdef _DEBUG
# define ReleaseEx(p,f,l ) ReleaseExx( (void**)&p,f,l )
# else
# define ReleaseEx(p ) ReleaseExx( (void**)&p )
# endif
# else
# define ReleaseEx(... ) ReleaseExx( (void**)&__VA_ARGS__ )
# endif
#define Release(p) ReleaseExx( (void**)&p DBG_SRC)
void DumpMemory( void );
uint32_t CPROC LockedExchange( uint32_t *p, uint32_t val );
void CPROC MemSet( POINTER p, uint32_t v, size_t n);
void CPROC MemCpy( POINTER p, const void *p2, size_t n);
void DisableMemoryValidate( int bDisable );
char CPROC *StrDupEx( const char *original DBG_PASS );
#define StrDup(o) StrDupEx(o DBG_SRC )
#endif
#endif
#ifndef INPUT_DEFINED
#define INPUT_DEFINED
// must be present just to process this
PTEXT burstEx( PTEXT input DBG_PASS );
#define burst(i) burstEx(i DBG_SRC )
PTEXT GatherLineEx( PTEXT *pOutput, int *pIndex, int bInsert, int bSaveCR, int bData, PTEXT pInput );
#define GatherLine( out,idx,ins,cr,in) GatherLineEx( (out),(idx),(ins),(cr),(FALSE),(in))
PTEXT get_line(FILE *source, int *line);
#endif
#ifndef LINKSTUFF
#define LINKSTUFF
//PDATA CreateData( uint32_t size );
//PDATA CreateDataFromText( char *pData );
//PDATA ExpandData( PDATA pData, uint32_t amount );
//PDATA DuplicateData( PDATA pData );
//void ReleaseData( PDATA pd );
PLIST CreateListEx ( DBG_VOIDPASS );
PLIST DeleteListEx ( PLIST *plist DBG_PASS );
PLIST AddLinkEx ( PLIST *pList, POINTER p DBG_PASS );
PLIST SetLinkEx ( PLIST *pList, INDEX idx, POINTER p DBG_PASS );
POINTER GetLinkEx ( PLIST *pList, INDEX idx );
INDEX FindLink ( PLIST *pList, POINTER value );
int DeleteLinkEx ( PLIST *pList, POINTER value );
#define CreateList() ( CreateListEx( DBG_VOIDSRC ) )
#define DeleteList(p) ( DeleteListEx( &(p) DBG_SRC ) )
#define AddLink(p,v) ( AddLinkEx( &(p),v DBG_SRC ) )
#define SetLink(p,i,v) ( SetLinkEx( &(p),i,v DBG_SRC ) )
#define GetLink(p,i) ( GetLinkEx( &(p),i ) )
#define DeleteLink(p,v) ( DeleteLinkEx( &(p), v ) )
#define FORALL( l, i, t, v ) if(l) for( (i)=0; (i) < ((l)->Cnt) && (((v)=(t)(l)->pNode[i]),1); (i)++ ) if( v )
// sizeof data elements...
PDATASTACK CreateDataStack( INDEX size );
void DeleteDataStack( PDATASTACK *pds );
PDATASTACK PushData ( PDATASTACK *pds, POINTER pdata );
POINTER PopData ( PDATASTACK *pds );
// keeps data on stack (can be used)
POINTER PeekData ( PDATASTACK *pds );
// keeps data on stack (can be used)
POINTER PeekDataEx ( PDATASTACK *pds, int Item );
PLINKSTACK CreateLinkStack( void );
void DeleteLinkStack( PLINKSTACK pls );
PLINKSTACK PushLink ( PLINKSTACK pls, POINTER p );
#define PushLink(s,p) ((s)=PushLink((s),(p)))
POINTER PopLink ( PLINKSTACK pls );
POINTER PeekLink ( PLINKSTACK pls );
PLINKQUEUE CreateLinkQueue( void );
void DeleteLinkQueueEx( PLINKQUEUE *pplq DBG_PASS );
#define DeleteLinkQueue(pplq) DeleteLinkQueueEx( pplq DBG_SRC )
PLINKQUEUE EnqueLinkEx ( PLINKQUEUE *pplq, POINTER link DBG_PASS );
#define EnqueLink(pplq, link) EnqueLinkEx( pplq, link DBG_SRC )
//PLINKQUEUE EnqueLink ( PLINKQUEUE *pplq, POINTER link );
POINTER DequeLink ( PLINKQUEUE *pplq );
int IsQueueEmpty ( PLINKQUEUE *pplq );
#endif
LONGEST_INT ProcessExpression( void );
typedef struct define_tag
{
PTEXT pName;
// DEFINE_FILE, COMMANDLINE, etc..
int nType;
// list of parameter names
PLIST pParams;
// set if there was a ... parameter...
int bVarParams;
// content which is to be substituted
PTEXT pData;
// set to avoid circular substitution
int bUsed;
// file and line which originally made this define...
char pFile[__MAX_PATH__];
int nLine;
struct define_tag *pLesser, *pGreater, *pSame, **me;
} DEF, *PDEF;
void InitDefines( void );
void DeinitDefines( void );
void CommitDefinesToCommandLine( void );
#define IGNORE_PARAMS 0x7fff
PDEF FindDefineName( PTEXT pName, int params );
#define DEFINE_ALL 0
#define DEFINE_COMMANDLINE 1
#define DEFINE_FILE 2
#define DEFINE_INTERNAL 3
void DeleteDefine( PDEF *ppDef );
void DeleteAllDefines( int type );
void DefineDefine( char *name, char *value );
int ProcessDefine( int type );
INDEX FindArg( PLIST pArgs, PTEXT pName );
void EvalSubstitutions( PTEXT *subst, int more );
void FixQuoting( PTEXT test );
#define CPP_MAIN_SOURCE
#define stddbg g.dbgout
//stderr
# if _MSC_VER > 1500
# define mkdir _mkdir
# define fileno _fileno
# define stricmp _stricmp
# define strdup _strdup
# endif
typedef struct include_reference_tag {
struct {
uint32_t bMacros;
} flags;
char *name;
} INCLUDE_REF, *PINCLUDE_REF;
typedef struct global_tag
{
struct {
uint32_t do_trigraph : 1;
uint32_t bWriteLine : 1;
uint32_t bLineUsesLineKeyword : 1;
// when -imacro is used...
uint32_t bNoOutput : 1;
// enable normally harmless warnings.
uint32_t bAllWarnings : 1;
uint32_t bEmitUnknownPragma : 1;
uint32_t bForceBackslash : 1;
uint32_t bForceForeslash : 1;
uint32_t bStdout : 1;
uint32_t keep_comments : 1;
uint32_t keep_includes : 1;
uint32_t bWriteLineInfo : 1;
uint32_t load_once : 1;
// don't output system include headers
uint32_t bSkipSystemIncludeOut : 1;
// a status of the last processinclude
uint32_t bIncludedLastFile : 1;
uint32_t doing_system_file : 1;
uint32_t skip_define_processing : 1;
uint32_t skip_logic_processing : 1;
uint32_t config_loaded : 1;
} flags;
FILE *output;
int bDebugLog;
char pExecPath[256];
char pExecName[256];
char pWorkPath[256];
DECLTEXTSZ( pCurrentPath, 256 );
uint32_t ErrorCount;
/******************************/
// list of paths to search includes for...
PLIST pSysIncludePath;
// the include path should have appended to it the default
// system include file... this probably comes from an enviroment
// environment will be an important thing to mimic in my operation
// system...
PLIST pUserIncludePath;
// include 'system' dependancies
int AllDependancies;
// include 'system' dependancies
int bAutoDepend;
FILE *AutoDependFile;
// safe junk buffer to print into...
VARTEXT vt;
unsigned char CurrentOutName[256];
int nIfLevels;
unsigned long nAllocates;
unsigned long nReleases;
size_t nAllocSize;
// target name to reference when
unsigned char AutoTargetName[256];
//building auto depend...
PLINKSTACK pIncludeList;
FILE *dbgout;
PFILETRACK pAllFileStack;
PFILETRACK pFileStack;
} GLOBAL;
// debug Log options....
#define DEBUG_SUBST 0x02
#define DEBUG_DEFINES 0x04
#define DEBUG_READING 0x08
#define DEBUG_MEMORY 0x10
#ifndef CPP_MAIN_SOURCE
extern
#endif
GLOBAL g;
void DumpSegs( PTEXT pOp );
// this module shall have provision to read a cpp.cnf
// which will indicate system include paths, and additional symbols
// which may be defined on a per-compiler basis....
#ifndef __GCC__
// this was good during development of infinite loops but bad in production...
// maybe ifdef _DEBUG the kbhit();
#define fprintf fprintf
#else
#define fprintf fprintf
#endif
#define ARG_UNKNOWN 0
#define ARG_INCLUDE_PATH 1
#define ARG_SYS_INCLUDE_PATH 2
#define ARG_AUTODEPEND_NAME 3
#define ARG_DEFINE_DEFINE 4
#define ARG_OUT_NAME 5
#define ARG_AUTOTARGET_NAME 6
#define ARG_INCLUDE_FILE 7
#define ARG_MACRO_FILE 8
#define ARG_GEN_STDOUT 9
/******************************
/* this portion is mainly for testing the CPP program
/* defines which are not used...
/* comments in various order
/* although these must succeed...
/******************************/
//----------------------------------------------------------------------
int KillQuotes( char *string )
{
// this processing stage cannot be done at the pre-processor level
// for things like "\x02" "4" which is actually
// character to followed by ascii 4.
//return strlen( string );
// okay but yes it can be done for #pramga message
// this routine removes leading and trailing quotes.
// and only stores that which was within the quotes.
char quote = 0;
char *in = string, *out = string;
if( !string )
return 0;
while( *string )
{
if( !quote )
{
if( *string == '\"' || *string == '\'' )
{
quote = *string;
}
}
else
{
if( *string == quote )
{
quote = 0;
}
else
{
*out = *string;
out++;
}
}
string++;
}
*out = 0;
// bad form - but in never changes so this is length out.
return (int)(out - in);
}
//----------------------------------------------------------------------
int CollapseQuotes( char *string )
{
// this routine takes "thing" "another" and makes "thinganother"
// however "this" and "that" is still "this" and "that"
char quote = 0, lastquote = 0, *lastquotepos = NULL;
char *in = string, *out = string;
if( !string )
return 0;
while( *string )
{
if( !quote )
{
if( lastquote == *string )
{
out = lastquotepos;
quote = *string;
}
else
{
if( *string != ' ' && *string != '\t' )
{
lastquote = 0;
lastquotepos = NULL;
}
if( *string == '\"' || *string == '\'' )
quote = *string;
*out = *string;
out++;
}
}
else
{
if( *string == quote )
{
lastquote = quote;
lastquotepos = out;
quote = 0;
}
*out = *string;
out++;
}
string++;
}
*out = 0;
// bad form - but in never changes so this is length out.
return (int)(out - in);
}
//---------------------------------------------------------------------------
void DumpSegs( PTEXT pOp )
{
PTEXT tmp = pOp;
fprintf( stddbg, "SEG:%p", pOp );
//if( !g.bDebugLog )
// return;
while( tmp )
{
if( tmp->flags & TF_INDIRECT )
{
DumpSegs( GetIndirect( tmp ) );
}
else
{
fprintf( stddbg, "[%d%s]", tmp->format.spaces,GetText( tmp ) );
}
tmp = NEXTLINE( tmp );
}
}
//----------------------------------------------------------------------
int ProcessSystemIncludeFile( char *name, int bAllowAbsolute, int bNext )
{
char Workname[__MAX_PATH__];
PTEXT pPath;
INDEX idx;
if( bAllowAbsolute &&
OpenNewInputFile( name, name, GetCurrentFileName(), GetCurrentLine(), g.bAutoDepend || g.flags.load_once, bNext ) )
return TRUE;
{
FORALL( g.pUserIncludePath, idx, PTEXT, pPath )
{
// don't use auto path for 'system' includes.
if( !idx )
continue;
sprintf( Workname, "%s/%s", GetText( pPath ), name );
if( g.bDebugLog )
{
fprintf( stddbg, "attempting \"%s\"\n" , Workname );
}
if( OpenNewInputFile( name, Workname, GetCurrentFileName(), GetCurrentLine(), TRUE, bNext ) )
{
if( idx )
SetCurrentPath( GetText( pPath ) );
return TRUE;
}
}
FORALL( g.pSysIncludePath, idx, PTEXT, pPath )
{
sprintf( Workname, "%s/%s", GetText( pPath ), name );
if( g.bDebugLog )
{
fprintf( stddbg, "attempting <%s>\n" , Workname );
}
g.flags.doing_system_file = 1;
if( OpenNewInputFile( name, Workname, GetCurrentFileName(), GetCurrentLine(), FALSE, bNext ) )
{
g.flags.doing_system_file = 0;
SetCurrentPath( GetText( pPath ) );
return TRUE;
}
g.flags.doing_system_file = 0;
}
}
// at this point - offer to add another path...
return FALSE;
}
//----------------------------------------------------------------------
int ProcessInclude( int bNext )
{
char Workname[__MAX_PATH__];
char basename[__MAX_PATH__];
int i = 0, did_subst = 0;
PTEXT pEnd, pWord;
if( !( pEnd = pWord = GetCurrentWord() ) )
{
fprintf( stderr, "%s(%d) Error: #include without name.\n", GetCurrentFileName(), GetCurrentLine() );
g.ErrorCount++;
return TRUE;
}
g.flags.bIncludedLastFile = 0;
do
{
if( GetText( pWord )[0] == '\"' )
{
if( bNext )
{
fprintf( stderr, "Hmm warning : did not implement include next for 'user' headers.\n" );
return FALSE;
}
pEnd = NEXTLINE( GetCurrentWord() );
while( pEnd && GetText( pEnd )[0] != '\"' )
{
i += sprintf( basename + i, "%s", GetText( pEnd ) );
pEnd = NEXTLINE( pEnd );
}
basename[i] = 0;
if( !pEnd )
{
fprintf( stderr, "%s(%d) Error: Invalid name end bounding for #include \"...\n"
, GetCurrentFileName(), GetCurrentLine() );
g.ErrorCount++;
return TRUE;
}
strcpy( Workname, basename );
if( g.bDebugLog )
{
fprintf( stddbg, "attempting: \"%s\"\n", basename );
}
if( g.flags.load_once )
{
if( AlreadyLoaded( Workname ) ) {
SetCurrentWord( NEXTLINE( pEnd ) );
g.flags.bIncludedLastFile = 1;
return TRUE;
}
}
if( !OpenNewInputFile( basename, Workname, GetCurrentFileName(), GetCurrentLine(), g.bAutoDepend || g.flags.load_once, bNext ) )
{
PTEXT pPath;
INDEX idx;
int count;
char *dir = pathrchr( g.pFileStack->longname );
if( dir )
count = (int)(dir - g.pFileStack->longname);
else
count = 0;
#if( _MSC_VER && ( _MSC_VER < 1800 ) )
_snprintf( Workname, __MAX_PATH__, "%*.*s/%s", count, count, g.pFileStack->longname, basename );
#else
#if( _MSC_VER && ( _MSC_VER < 1800 ) )
_snprintf( Workname, __MAX_PATH__, "%*.*s/%s", count, count, g.pFileStack->longname, basename );
#else
snprintf( Workname, __MAX_PATH__, "%*.*s/%s", count, count, g.pFileStack->longname, basename );
#endif
#endif
if( OpenNewInputFile( basename, Workname, GetCurrentFileName(), GetCurrentLine(), TRUE, bNext ) )
{
SetCurrentWord( NEXTLINE( pEnd ) );
g.flags.bIncludedLastFile = 1;
return TRUE;
}
FORALL( g.pUserIncludePath, idx, PTEXT, pPath )
{
sprintf( Workname, "%s/%s", GetText( pPath ), basename );
if( g.bDebugLog )
{
fprintf( stddbg, "attempting \"%s\"\n" , Workname );
}
/*1234*/
if( g.flags.load_once )
{
if( AlreadyLoaded( Workname ) ) {
SetCurrentWord( NEXTLINE( pEnd ) );
g.flags.bIncludedLastFile = 1;
return TRUE;
}
}
if( OpenNewInputFile( basename, Workname, GetCurrentFileName(), GetCurrentLine(), TRUE, bNext ) )
{
if( idx )
SetCurrentPath( GetText( pPath ) );
g.flags.bIncludedLastFile = 1;
return TRUE;
}
}
fprintf( stderr, "%s(%d): Warning could not find include file \"%s\". try <%s>? I won't - but maybe...\n"
, GetCurrentFileName()
, GetCurrentLine()
, basename, basename );
return FALSE;
}
else
{
g.flags.bIncludedLastFile = 1;
return TRUE;
}
}
else if( GetText( pWord )[0] == '<' )
{
//PTEXT pPath;
//INDEX idx;
/*
if( GetText( GetCurrentWord() )[0] != '<' )
{
fprintf( stderr, "%s(%d) Error: Invalid name bounding for #INCLUDE %c\n"
, GetCurrentFileName(), GetCurrentLine()
, GetText( GetCurrentWord() )[0] );
g.ErrorCount++;
return TRUE;
}
*/
pEnd = NEXTLINE( pWord );
while( pEnd && GetText( pEnd )[0] != '>' )
{
i += sprintf( basename + i, "%s", GetText( pEnd ) );
pEnd = NEXTLINE( pEnd );
}
basename[i] = 0;
if( !pEnd )
{
fprintf( stderr, "%s(%d) Error: Invalid name end bounding for #INCLUDE <...\n"
, GetCurrentFileName(), GetCurrentLine() );
g.ErrorCount++;
return TRUE;
}
if( g.flags.load_once )
{
if( AlreadyLoaded( basename ) ) {
SetCurrentWord( NEXTLINE( pEnd ) );
g.flags.bIncludedLastFile = 1;
return TRUE;
}
}
if( ProcessSystemIncludeFile( basename, FALSE, bNext ) ) {
g.flags.bIncludedLastFile = 1;
return TRUE;
}
break;
}
else
{
PTEXT pStart = pWord;
EvalSubstitutions( &pWord, FALSE );
if( pWord != pStart ) {
SetCurrentWord( pWord );
}
else
sprintf( basename, "%s", GetText( pEnd ) );
did_subst++;
}
} while( did_subst < 2 );
if( g.flags.load_once )
{
AddFileDepend( g.pFileStack, basename, basename );
}
if( !g.flags.bSkipSystemIncludeOut )
fprintf( stderr, "%s(%d) Warning could not process include file %c%s%c\n"
, GetCurrentFileName(), GetCurrentLine()
, (pEnd!= GetCurrentWord())?GetCurrentWord()->data.data[0]:' '
, basename
, (pEnd != GetCurrentWord()) ? pEnd->data.data[0] : ' '
);
//g.ErrorCount++;
// at this point - offer to add another path...
return FALSE;
}
//----------------------------------------------------------------------
// values for nState in FILETRACK
//#define CONTINUE_DEFINE 0x000002
// if a ELSE or ENDIF at level 0 is found...
// then this is satisfied... #if type statement increment if levels
// and endif decrements the levels....
#define FIND_ELSE 0x000008
// FIND_ENDIF ... statements between are ignored until ENDIF
// even #else and #elseif type
// although #if within this block may also have a paired ENDIF
// #if type statements will increment the if levels and
// #endif will decrement until level is 0 and is an end...
#define FIND_ENDIF 0x000010
//----------------------------------------------------------------------
//----------------------------------------------------------------------
// mark this for on close message....
static char *pFileIfStart;
static int nLineIfStart;
static int nState;
static int nIfLevelElse;
//----------------------------------------------------------------------
void SetIfBegin( void )
{
g.nIfLevels++;
if( g.bDebugLog )
fprintf( stddbg, "%s(%d): Setting IF level %d finding %s%s\n"
, GetCurrentFileName()
, GetCurrentLine()
, g.nIfLevels
, nState & FIND_ELSE?"ELSE":""
, nState & FIND_ENDIF?"ENDING":""
);
if( !pFileIfStart )
{
if( g.bDebugLog )
fprintf( stddbg, "Set if starting level: %d\n", g.nIfLevels );
pFileIfStart = StrDup( GetCurrentFileName() );
nLineIfStart = GetCurrentLine();
}
}
//----------------------------------------------------------------------
void ClearIfBegin( void )
{
if( !g.nIfLevels )
{
fprintf( stddbg, "%s(%d): Extra #endif without an #if\n"
, GetCurrentFileName()
, GetCurrentLine() );
return;
}
if( g.bDebugLog )
fprintf( stddbg, "%s(%d): Clearing IF %d finding %s%s\n"
, GetCurrentFileName()
, GetCurrentLine()
, g.nIfLevels
, nState & FIND_ELSE?"ELSE":""
, nState & FIND_ENDIF?"ENDING":""
);
g.nIfLevels--;
if( !g.nIfLevels )
{
//fprintf( stderr, "--------------------------------------------\n" );
if( pFileIfStart )
Release( pFileIfStart );
pFileIfStart = NULL;
nLineIfStart = 0;
}
}
//----------------------------------------------------------------------
void GetIfBegin( char**file, int*line)
{
if( file )
*file = pFileIfStart;
if( line )
*line = nLineIfStart;
}
//----------------------------------------------------------------------
int PreProcessLine( void )
{
PTEXT pDirective = NULL;
PTEXT pFirstWord;
if( !( pFirstWord = GetCurrentWord() ) )
return FALSE;
if( g.bDebugLog )
{
fprintf( stddbg, "%s(%d): ", GetCurrentFileName(), GetCurrentLine() );
DumpSegs( GetCurrentWord() );
fprintf( stddbg, "\n" );
}
// pre-processor command processing....
if( GetText( GetCurrentWord() )[0] == '#' )
{
// pre processor directive at start of line...
pDirective = StepCurrentWord();
if( !pDirective )
return FALSE;
StepCurrentWord();
//==== ENDIF =====================================================
if( TextLike( pDirective, "endif" ) )
{
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
if( nState & FIND_ELSE )
{
if( g.nIfLevels == nIfLevelElse )
{
if( g.bDebugLog )
fprintf( stddbg, "%s(%d): Looking for an else - found endif - correct level\n"
, GetCurrentFileName(), GetCurrentLine() );
nState &= ~FIND_ELSE;
}
else if( g.bDebugLog )
fprintf( stddbg, "%s(%d): Looking for an else - found endif - wrong level\n"
, GetCurrentFileName(), GetCurrentLine() );
}
if( nState & FIND_ENDIF )
{
if( g.nIfLevels == nIfLevelElse )
{
if( g.bDebugLog )
fprintf( stddbg, "%s(%d): Looking for an endif - found endif - correct level\n"
, GetCurrentFileName(), GetCurrentLine() );
nState &= ~FIND_ENDIF;
}
else if( g.bDebugLog )
fprintf( stddbg, "%s(%d): Looking for an endif - found endif - wrong level\n"
, GetCurrentFileName(), GetCurrentLine() );
}
ClearIfBegin();
if( !g.nIfLevels )
{
if( g.bDebugLog )
fprintf( stddbg, "-------------------------------------\n" );
nState &= ~(FIND_ELSE | FIND_ENDIF);
}
return FALSE;
}
if( nState & FIND_ENDIF )
{
if( TextLike( pDirective, "ifdef" ) ||
TextLike( pDirective, "ifndef" ) ||
TextLike( pDirective, "if" ) )
{
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
SetIfBegin();
if( g.bDebugLog )
{
fprintf( stddbg, "%s(%d): Another level of ifs... coming up! (%d)\n"
, GetCurrentFileName(), GetCurrentLine()
, g.nIfLevels );
}
}
return FALSE;
}
//==== ELSE =====================================================
else if( TextLike( pDirective, "else" ) )
{
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
if( GetCurrentWord() )
{
fprintf( stderr, "%s(%d) Warning: harmless extra tokens after #ELSE\n"
, GetCurrentFileName(), GetCurrentLine() );
}
if( nState & FIND_ENDIF )
{
// if only looking for endif - continue....
if( g.bDebugLog )
fprintf( stddbg, "Still looking for endif... skipping else\n" );
return FALSE;
}
if( nState & FIND_ELSE )
{
if( g.nIfLevels == nIfLevelElse )
{
if( g.bDebugLog )
fprintf( stddbg, "%s(%d): Found an else on the correct level - let's process...\n"
, GetCurrentFileName(), GetCurrentLine() );
// is the else that we seek....
// otherwise probalby in a sub-if and need
// to wait for that #endif to complete and
// get us back to the right level to find
// and else....
nState &= ~FIND_ELSE;
}
return FALSE;
}
// was in an if - and now need to find endif...
else
{
if( g.bDebugLog )
fprintf( stddbg, "%s(%d): else termination - next to find endif this level(%d)\n"
, GetCurrentFileName(), GetCurrentLine()
, g.nIfLevels );
// if we ever hit an else that is actively processing
// then find the else... otherwise
// it would be skipped
//fprintf( stderr, "Finding the endif of the current if...\n" );
nIfLevelElse = g.nIfLevels;
nState |= FIND_ENDIF;
}
return FALSE;
}
//==== ELSEIFDEF ELIFDEF =====================================================
else if( TextLike( pDirective, "elseifdef" ) ||
TextLike( pDirective, "elifdef" ) )
{
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
if( !( nState & FIND_ELSE ) )
{
// if was processing, an else causes find endif...
nState = FIND_ENDIF;
nIfLevelElse = g.nIfLevels;
return TRUE;
}
return FALSE;
}
//==== ELSEIFNDEF ELIFNDEF =====================================================
else if( TextLike( pDirective, "elseifndef" ) ||
TextLike( pDirective, "elifndef" ) )
{
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
if( !( nState & FIND_ELSE ) )
{
// if was processing, an else causes find endif...
nState = FIND_ENDIF;
nIfLevelElse = g.nIfLevels;
return TRUE;
}
// results in find_else... else continues...
// unless
return FALSE;
}
// nothing else is valid if I'm still looking for an else or endif and it was not handled
// by the prior two conditions....
if( nState & (FIND_ELSE | FIND_ENDIF) )
{
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
if( TextLike( pDirective, "elseif" ) ||
TextLike( pDirective, "elif" ) )
{
goto SubstituteAndProcess;
}
else if( TextLike( pDirective, "ifdef" ) ||
TextLike( pDirective, "ifndef" ) ||
TextLike( pDirective, "if" ) )
{
SetIfBegin();
if( g.bDebugLog )
{
fprintf( stddbg, "%s(%d): Another level of ifs... coming up! (%d)\n"
, GetCurrentFileName(), GetCurrentLine()
, g.nIfLevels );
}
}
//fprintf( stderr, "Failing line...\n" );
return FALSE;
}
//== INCLUDE =======================================================
if( TextLike( pDirective, "include" ) )
{
//fprintf( stderr, "Include segments..." );
//DumpSegs( pDirective );
ProcessInclude( FALSE );
if( g.flags.keep_includes && !g.flags.bIncludedLastFile )
SetCurrentWord( pFirstWord );
return g.flags.keep_includes;
}
//== INCLUDE NEXT ==================================================
else if( TextLike( pDirective, "include_next" ) )
{
//fprintf( stderr, "Include segments..." );
//DumpSegs( pDirective );
if( g.flags.keep_includes )
SetCurrentWord( pFirstWord );
else {
ProcessInclude( TRUE );
if( g.flags.keep_includes && !g.flags.bIncludedLastFile )
SetCurrentWord( pFirstWord );
}
return g.flags.keep_includes;
}
//== DEFINE =======================================================
else if( TextLike( pDirective, "define" ) )
{
if( !NEXTLINE( pDirective ) )
{
fprintf( stderr, "\"#define\" keyword alone is NOT allowed..." );
// can still continue....
return FALSE;
}
if( g.flags.skip_define_processing ) {
ProcessDefine( DEFINE_ALL );
SetCurrentWord( pFirstWord );
return TRUE;
}
ProcessDefine( DEFINE_FILE );
if( g.flags.skip_logic_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
return FALSE;
}
//== UNDEF =======================================================
else if( TextLike( pDirective, "undef" ) )
{
PDEF pDef;
if( g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
pDef = FindDefineName( GetCurrentWord(), IGNORE_PARAMS );
if( pDef )
{
DeleteDefine( &pDef );
}
if( g.flags.skip_logic_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
return FALSE;
}
//== IFDEF =======================================================
else if( TextLike( pDirective, "ifdef" ) )
{
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
SetIfBegin();
if( !FindDefineName( GetCurrentWord(), IGNORE_PARAMS ) )
{
if( g.bDebugLog )
{
fprintf( stddbg, "%s(%d): ifdef %s FAILED\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( GetCurrentWord() ));
}
nState |= FIND_ELSE;
}
else
if( g.bDebugLog )
{
fprintf( stddbg, "%s(%d): ifdef %s SUCCESS\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( GetCurrentWord() ) );
}
nIfLevelElse = g.nIfLevels;
return FALSE;
}
//== IFNDEF =======================================================
else if( TextLike( pDirective, "ifndef" ) )
{
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
SetIfBegin();
if( FindDefineName( GetCurrentWord(), IGNORE_PARAMS ) )
{
if( g.bDebugLog )
{
fprintf( stddbg, "%s(%d): ifndef %s FAILED\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( GetCurrentWord() ));
}
nState |= FIND_ELSE;
}
else
if( g.bDebugLog )
fprintf( stddbg, "%s(%d): ifndef %s SUCCESS\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( GetCurrentWord() ) );
nIfLevelElse = g.nIfLevels;
// otherwise we can store these statements...
return FALSE;
}
// have to go through all words and check vs current
// defines to see if we need to substitute the data or not...
SubstituteAndProcess:
if( !g.flags.skip_define_processing && !g.flags.skip_logic_processing )
{
PTEXT line = GetCurrentWord();
EvalSubstitutions( &line, FALSE );
if( line != GetCurrentWord() )
SetCurrentWord( line );
}
//=== IF ======================================================
if( TextLike( pDirective, "if" ) )
{
PTEXT dbg;
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
SetIfBegin();
if( !ProcessExpression() )
{
nState |= FIND_ELSE;
nIfLevelElse = g.nIfLevels;
if( g.bDebugLog )
{
dbg = BuildLine( pDirective );
fprintf( stddbg, "%s(%d): %s FAILED\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText(dbg) );
LineRelease( dbg );
}
}
else
{
if( g.bDebugLog )
{
dbg = BuildLine( pDirective );
fprintf( stddbg, "%s(%d): %s SUCCESS\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText(dbg) );
LineRelease( dbg );
}
}
}
//=== ELSEIF ELIF ======================================================
else if( TextLike( pDirective, "elseif" ) ||
TextLike( pDirective, "elif" ) )
{
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
if( nState & FIND_ELSE )
{
PTEXT dbg;
if( g.nIfLevels == nIfLevelElse &&
ProcessExpression() )
{
if( g.bDebugLog )
{
dbg = BuildLine( pDirective );
fprintf( stddbg, "%s(%d): %s Success\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( dbg ) );
LineRelease( dbg );
}
nState &= ~FIND_ELSE;
}
else if( g.bDebugLog )
{
dbg = BuildLine( pDirective );
fprintf( stddbg, "%s(%d): %s Failure\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( dbg ) );
LineRelease( dbg );
}
}
// wasn't looking for else - else found - go to endif now.
else
{
nState = FIND_ENDIF;
nIfLevelElse = g.nIfLevels;
}
}
//==== PRAGMA =====================================================
else if( TextLike( pDirective, "pragma" ) )
{
// pramga message seems to be a useful thing to have...
// other pragmas need to be ignored
// pragmas occur with all data on a single line.
// evaluate substitutions... (already done)
PTEXT pOp = GetCurrentWord();
if( TextLike( pOp, "multiinclude" ) )
{
g.pFileStack->pFileDep->bAllowMultipleInclude = TRUE;
}
else if( TextLike( pOp, "message" ) )
{
PTEXT pOut;
pOut = BuildLineEx( NEXTLINE( pOp ), FALSE DBG_SRC );
pOut->data.size = CollapseQuotes( pOut->data.data );
pOut->data.size = KillQuotes( pOut->data.data );
fprintf( stderr, "%s\n", GetText( pOut ) );
//fprintf( stdout, "%s\n", GetText( pOut ) );
LineRelease( pOut );
// dump the remaining segments...
}
else if( TextLike( pOp, "systemincludepath" ) )
{
PTEXT pOut;
pOut = BuildLineEx( NEXTLINE( pOp ), FALSE DBG_SRC );
AddLink( g.pSysIncludePath, pOut );
}
else if( TextLike( pOp, "includepath" ) )
{
PTEXT pOut;
pOut = BuildLineEx( NEXTLINE( pOp ), FALSE DBG_SRC );
AddLink( g.pUserIncludePath, pOut );
}
else if( TextLike( pOp, "pack" ) )
{
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
if( g.bDebugLog )
{
PTEXT pOut;
pOut = BuildLineEx( pOp, FALSE DBG_SRC );
fprintf( stderr, "%s(%d): %s Unknown pragma: %s\n"
, GetCurrentFileName()
, GetCurrentLine()
, g.flags.bEmitUnknownPragma?"emitting":"dropping"
, GetText( pOut ) );
LineRelease( pOut );
}
SetCurrentWord( pFirstWord );
return g.flags.bEmitUnknownPragma;
}
// watcom - inline assembly junk...
else if( TextLike( pOp, "warning" )
|| TextLike( pOp, "intrinsic" )
|| TextLike( pOp, "aux" )
|| TextLike( pOp, "function" )
|| TextLike( pOp, "comment" ) )
{
if( g.bDebugLog )
{
PTEXT pOut;
pOut = BuildLineEx( pOp, FALSE DBG_SRC );
fprintf( stderr, "%s(%d): %s Unknown pragma: %s\n"
, GetCurrentFileName()
, GetCurrentLine()
, g.flags.bEmitUnknownPragma?"emitting":"dropping"
, GetText( pOut ) );
LineRelease( pOut );
}
SetCurrentWord( pFirstWord );
return g.flags.bEmitUnknownPragma;
}
// watcom - dependancy generation...
else if( TextLike( pOp, "read_only_file" ) )
{
// can't see any usefulness when using ppc to preprocess...
return FALSE;
}
else
{
PTEXT pOut;
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
pOut = BuildLineEx( pOp, FALSE DBG_SRC );
fprintf( stderr, "%s(%d): Unknown pragma: %s\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( pOut ) );
LineRelease( pOut );
// hmm - gcc processing .i files fails this.
SetCurrentWord( pFirstWord );
return g.flags.bEmitUnknownPragma;
//return TRUE; // emit this line - maybe the compiler knows...
//return FALSE;
}
}
else if( TextLike( pDirective, "warning" ) )
{
PTEXT pOut;
pOut = BuildLineEx( GetCurrentWord(), FALSE DBG_SRC );
fprintf( stderr, "%s(%d): Warning %s\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( pOut ) );
LineRelease( pOut );
}
else if( TextLike( pDirective, "error" ) )
{
PTEXT pOut;
if( g.flags.skip_logic_processing || g.flags.skip_define_processing ) {
SetCurrentWord( pFirstWord );
return TRUE;
}
pOut = BuildLineEx( GetCurrentWord(), FALSE DBG_SRC );
fprintf( stderr, "%s(%d): Error %s\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( pOut ) );
LineRelease( pOut );
g.ErrorCount++;
}
else
{
PTEXT pOut;
pOut = BuildLineEx( pDirective, FALSE DBG_SRC );
fprintf( stderr, "%s(%d): Unknown prepcessing directive: %s\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( pOut ) );
LineRelease( pOut );
}
return FALSE;
}
if( nState & ( FIND_ELSE|FIND_ENDIF ) )
{
// ignore anything on this line for output
return FALSE;
}
if( pDirective )
{
fprintf( stderr, "ERROR: Responding true to invoking a preprocessor command to output\n" );
}
if( !g.flags.skip_define_processing && !g.flags.skip_logic_processing )
{
PTEXT *line = GetCurrentTextLine();
//PTEXT reset = GetCurrentWord();
if( nState )
fprintf( stderr, "ERROR: Substituting the line...bad state %d\n", nState );
EvalSubstitutions( line, TRUE );
SetCurrentWord( pFirstWord );
}
return TRUE;
}
//----------------------------------------------------------------------------
int ProcessStatement( void )
{
return TRUE;
//ProcessEnum(); // snags enumeration symbols...
//ProcessStructUnion(); // builds union/structure space...
//ProcessArray(); // handles gathering and possible re-emmission of arrays...
}
//----------------------------------------------------------------------------
void RunProcessFile( void )
{
while( ReadLine( FALSE ) )
{
int depth = CurrentFileDepth();
if( PreProcessLine() )
{
//if( g.flags.keep_includes )
{
// if( depth > 1 )
// continue;
}
if( ProcessStatement() )
{
PTEXT pOut;
pOut = BuildLineEx( GetCurrentWord(), FALSE DBG_SRC );
if( pOut )
{
if( g.flags.bWriteLineInfo )
{
WriteCurrentLineInfo();
}
WriteLine( GetTextSize( pOut ), GetText( pOut ) );
LineRelease( pOut );
}
}
}
}
if( nState || g.nIfLevels )
{
char *file;
int line;
GetIfBegin( &file, &line );
fprintf( stderr, "Missing #endif starting at %s(%d)"
, file, line );
}
// at this point we have dumped an output file....
// the standard states
// 5. Each source character set member and escape sequence in character constants and
//string literals is converted to the corresponding member of the execution character
//set; if there is no corresponding member, it is converted to an implementationdefined
//member other than the null (wide) character.7)
// this is done above... as we are handling substitutions...
// though this will result in an inability to handle some things like...
// "\33" "3"
// 6. Adjacent string literal tokens are concatenated.
// 7. 8. ... and done :)
}
void ProcessFile( char *file );
void loadConfig( void ) {
{
char file[256];
/*g.pExecPath*/
sprintf( file, "%s/config.ppc", g.pWorkPath );
//printf( "loading defines from %s", file );
#if defined( __WATCOMC__ ) || defined (__LCC__)
{
char *includepath = getenv( "INCLUDE" );
// %WATCOM%\H\NT;%WATCOM%\H;%INCLUDE%
char *start, *end;
start = includepath;
while( start[0] && (end = strchr( start, ';' )) )
{
PTEXT pOut;
end[0] = 0;
//printf( "Adding include path: %s", start );
pOut = SegCreateFromText( start );
AddLink( g.pSysIncludePath, pOut );
start = end + 1;
}
if( start[0] )
{
PTEXT pOut;
//printf( "Adding include path: %s", start );
pOut = SegCreateFromText( start );
AddLink( g.pSysIncludePath, pOut );
}
}
#endif
ProcessFile( file );
CommitDefinesToCommandLine();
//DestoyDepends();
}
}
void ProcessFile( char *file )
{
char newname[__MAX_PATH__];
char *filestart = pathrchr( file );
if( !g.flags.config_loaded ) {
g.flags.config_loaded = 1;;
loadConfig();
}
if( !filestart )
filestart = file;
else
filestart++;
if( !OpenInputFile( filestart, file ) )
{
return;
}
if( g.CurrentOutName[0] != 0xFF )
{
if( !g.flags.bStdout )
{
if( g.CurrentOutName[0] )
strcpy( newname, g.CurrentOutName );
else
{
strcpy( newname, file );
// replace last char with i...
newname[strlen(newname)-1] = 'i';
}
if( !OpenOutputFile( newname ) )
{
CloseInputFile();
return;
}
}
else
{
if( !OpenStdOutputFile() )
{
CloseInputFile();
return;
}
}
g.CurrentOutName[0] = 0xFF;
{
PINCLUDE_REF pRef;
while( pRef = PopLink( g.pIncludeList ) )
{
g.flags.bNoOutput = pRef->flags.bMacros;
if( !ProcessSystemIncludeFile( pRef->name, TRUE, FALSE ) )
{
fprintf( stderr, "%s(%d): Warning could not process include file \'%s\'\n"
, GetCurrentFileName(), GetCurrentLine()
, pRef->name );
//g.ErrorCount++;
return;
}
Release( pRef );
}
g.flags.bNoOutput = 0;
}
}
// all files should be closed once this returns.
RunProcessFile();
}
void ReleaseIncludePaths( void )
{
INDEX idx;
PTEXT path;
FORALL( g.pSysIncludePath, idx, PTEXT, path )
Release( path );
DeleteList( g.pSysIncludePath );
FORALL( g.pUserIncludePath, idx, PTEXT, path )
{
// don't release user include directory 0 - internal use.
if( idx )
Release( path );
}
DeleteList( g.pUserIncludePath );
}
void usage( void )
{
printf( "usage: %s (options) <files...>\n", g.pExecName );
printf( "\toptions to include\n"
" ------------------------------------------\n" );
printf( "\t -[Ii]<path(s)> add include path to default\n" );
printf( "\t -[Ss][Ii]<path(s)> add include path to system default\n" );
printf( "\t -[Dd]<symbol> define additional symbols\n" );
printf( "\t -MF<file> dump out auto-depend info\n" );
printf( "\t -MT<file> use (file) as name of target in depend file\n" );
printf( "\t -L write file/line info prefixing output lines\n" );
printf( "\t -l write file/line info prefixing output lines\n" );
printf( " (without line directive)\n" );
printf( "\t -K emit unknown pragmas into output\n" );
printf( "\t -k do not emit unknown pragma (default)\n" );
printf( "\t -c keep comments in output\n" );
printf( "\t -p keep includes in output (don't output content of include)\n" );
printf( "\t -f force / into \\ in include statements with paths\n" );
printf( "\t -sd skip define processing (if,else,etc also skippped)\n" );
printf( "\t -sl skip logic processing (if,else,endif skippped; process defines for include subst)\n" );
printf( "\t -ssio Skip System Include Out;try to keep #includes that are missing as #include\n" );
printf( "\t -F force \\ into /\n" );
printf( "\t -[Oo]<file> specify the output filename; output filename must be set before input(s) are read\n" );
printf( "\t -o output \"process this file into output.c\"\n" );
printf( "\t -once only load any include once\n" );
printf( "\t -[Zz]# debug info mode. where number is in ( 1, 2, 4 )\n" );
printf( "\t @<file> any option read from a file...\n" );
printf( " Any option prefixed with a - will force the option off... --c to force not keeping comments\n" );
printf( " Option L is by default on. (line info with #line keyword)\n" );
printf( " output default is input name substituing the last character for an i...\n" );
printf( "\t\t test.cpp -> test.cpi test.c -> test.i\n" );
printf( "\t examples : \n" );
printf( "\t\tppc source_file.c\n" );
printf( "\t\t# the following is how to do an amalgamtion\n" );
printf( "\t\tppc -sd -ssio -K -c -once -Iinclude -o file_all.c file1.c file2.c file3.c\n" );
printf( "\t\tppc -sdssioKconce -Iinclude -o file_all.c file1.c file2.c file3.c\n" );
printf( "\t -? for more help\n" );
printf( " (startup directory)/config.ppc is read first. It is only read once. Usage is intended to generate\n" );
printf( " one file at a time. It IS possible to do -o file1.i file1.c -o file2.i file2.c but the config.ppc won't\n" );
printf( " be read the second time. However, symbols meant to be kept in an amalgamtion output can be define here, and\n" );
printf( " those defines will be kept.\n" );
}
void longusage( void )
{
printf( "Unimplemented yet... showing usage()\n" );
usage();
}
int ispathchr( char c )
{
if( c == '\\' || c == '/' )
return TRUE;
return FALSE;
}
char *nextchr( char *string, char *chars )
{
char *test;
if( !string || !chars )
return NULL;
while( string[0] )
{
test = chars;
while( test[0] )
{
if( string[0] == test[0] )
return string;
test++;
}
string++;
}
return NULL;
}
int processArguments( int argc, char **argv ) {
{
int i=1;
int nArgState = ARG_UNKNOWN;
for( i = 1; i < argc; i++ )
{
if( argv[i][0] == '@' ) {
FILE *file = fopen( argv[i]+1, "rt" );
if( file ) {
char buf[4096];
while( fgets( buf, 4096, file ) )
{
int tmpargc;
char **tmpargv;
int len = (int)strlen(buf);
if( buf[len-1] == '\n' )
buf[len-1] = 0;
ParseIntoArgs( buf, &tmpargc, &tmpargv );
processArguments( tmpargc+1, tmpargv-1 );
{
int n;
// be nice and cleanup memory.
for( n = 0; n < tmpargc; n++ )
Release( tmpargv[n] );
Release( tmpargv );
}
}
}
}
else if( argv[i][0] == '-' ||
//argv[i][0] == '/' ||
nArgState )
{
int n, done = 0, negarg = 0;
for( n = 1;
!done && argv[i][n];
n++ )
{
switch( nArgState )
{
case ARG_MACRO_FILE:
{
PINCLUDE_REF pRef = Allocate( sizeof( INCLUDE_REF ) );
pRef->flags.bMacros = 1;
pRef->name = argv[i];
PushLink( g.pIncludeList, pRef );
}
nArgState = ARG_UNKNOWN;
done = 1;
break;
case ARG_INCLUDE_FILE:
{
PINCLUDE_REF pRef = Allocate( sizeof( INCLUDE_REF ) );
pRef->flags.bMacros = 0;
pRef->name = argv[i];
PushLink( g.pIncludeList, pRef );
}
nArgState = ARG_UNKNOWN;
done = 1;
break;
case ARG_AUTOTARGET_NAME:
strcpy( g.AutoTargetName, argv[i] );
nArgState = ARG_UNKNOWN;
done = 1;
break;
case ARG_GEN_STDOUT:
nArgState = ARG_UNKNOWN;
done = 1;
break;
case ARG_OUT_NAME:
strcpy( g.CurrentOutName, argv[i] );
nArgState = ARG_UNKNOWN;
done = 1;
break;
case ARG_AUTODEPEND_NAME:
g.AutoDependFile = fopen( argv[i], "wt" );
if( !g.AutoDependFile )
{
fprintf( stderr, "Failed to open %s for auto depend info.", argv[i] );
}
nArgState = ARG_UNKNOWN;
done = 1;
break;
case ARG_INCLUDE_PATH:
{
char *arg, *next, *tmp;
next = arg = argv[i];
if( argv[i][0] != '-' )
{
while( ( next = nextchr( arg, ";,:" ) ) )
{
// terminate new string...
*next = 0;
next++;
tmp = arg + ( strlen( arg ) - 1 );
if( ispathchr( *tmp ) )
// terminate prior;
*tmp = 0;
AddLink( g.pUserIncludePath, SegCreateFromText( arg ) );
arg = next;
}
tmp = arg + ( strlen( arg ) - 1 );
if( ispathchr( *tmp ) )
// terminate prior;
*tmp = 0;
AddLink( g.pUserIncludePath, SegCreateFromText( arg ) );
}
else
i--;
}
nArgState = 0;
done = 1;
break;
case ARG_SYS_INCLUDE_PATH:
{
char *arg, *next, *tmp;
next = arg = argv[i];
while( ( next = nextchr( arg, ";," ) ) )
{
// terminate new string...
*next = 0;
next++;
tmp = arg + ( strlen( arg ) - 1 );
if( ispathchr( *tmp ) )
// terminate prior;
*tmp = 0;
AddLink( g.pSysIncludePath, SegCreateFromText( arg ) );
arg = next;
}
tmp = arg + ( strlen( arg ) - 1 );
if( ispathchr( *tmp ) )
// terminate prior;
*tmp = 0;
AddLink( g.pSysIncludePath, SegCreateFromText( arg ) );
}
nArgState = 0;
done = 1;
break;
case ARG_UNKNOWN:
default:
// some option to turn off/on write line info...
if( argv[i][n] == '-' )
{
negarg = 1;
}
else if( argv[i][n] == 'c' )
{
g.flags.keep_comments = 1;
}
else if( argv[i][n] == 'p' )
{
g.flags.keep_includes = 1;
}
else if( argv[i][n] == 'I' )
{
char *arg, *next, *tmp;
if( !argv[i][n+1] )
{
nArgState = ARG_INCLUDE_PATH;
done = 1;
break;
}
next = arg = argv[i] + n + 1;
while( ( next = nextchr( arg, ";," ) ) )
{
// terminate new string...
*next = 0;
next++;
tmp = arg + ( strlen( arg ) - 1 );
if( ispathchr( *tmp ) )
// terminate prior;
*tmp = 0;
AddLink( g.pUserIncludePath, SegCreateFromText( arg ) );
arg = next;
}
tmp = arg + ( strlen( arg ) - 1 );
if( ispathchr( *tmp ) )
// terminate prior;
*tmp = 0;
AddLink( g.pUserIncludePath, SegCreateFromText( arg ) );
done = 1;
break;
}
else if( argv[i][n] == 'i' )
{
if( strcmp( argv[i] + n, "include" ) == 0 )
{
//if( argv[i][n+7]
nArgState = ARG_INCLUDE_FILE;
done = 1;
break;
}
else if( strcmp( argv[i] + n + 1, "macro" ) == 0 )
{
nArgState = ARG_MACRO_FILE;
done = 1;
break;
}
else
{
fprintf( stderr, "Argument error: %s\n", argv[i] );
usage();
return 1;
}
}
else if( (argv[i][n] == 's' &&
argv[i][n + 1] == 'o') )
{
g.flags.bStdout = 1;
n += 1;
break;
}
else if( argv[i][n] == 's' && argv[i][n + 1] &&
argv[i][n + 1] == 'd' ) {
g.flags.skip_define_processing = 1;
n += 1;
break;
}
else if( argv[i][n] == 's' && argv[i][n + 1] &&
argv[i][n + 1] == 'l' ) {
g.flags.skip_logic_processing = 1;
n += 1;
break;
}
else if( argv[i][n] == 's' && argv[i][n + 1] &&
argv[i][n + 1] == 's' && argv[i][n + 2] &&
argv[i][n + 2] == 'i' && argv[i][n + 3] &&
argv[i][n + 3] == 'o'
)
{
g.flags.bSkipSystemIncludeOut = 1;
n+=3;
break;
}
else if( ( argv[i][n] == 's' ||
argv[i][n] == 'S' ) &&
( argv[i][n+1] == 'I' ||
argv[i][n+1] == 'i' ) )
{
char *arg, *next, *tmp;
if( !argv[i][n+2] )
{
nArgState = ARG_SYS_INCLUDE_PATH;
done = 1;
break;
}
next = arg = argv[i] + n + 2;
while( ( next = nextchr( arg, ";," ) ) )
{
// terminate new string...
*next = 0;
next++;
tmp = arg + ( strlen( arg ) - 1 );
if( ispathchr( *tmp ) )
// terminate prior;
*tmp = 0;
AddLink( g.pSysIncludePath, SegCreateFromText( arg ) );
arg = next;
}
tmp = arg + ( strlen( arg ) - 1 );
if( ispathchr( *tmp ) )
// terminate prior;
*tmp = 0;
AddLink( g.pSysIncludePath, SegCreateFromText( arg ) );
}
else if( strncmp( argv[i]+n, "once", 4 ) == 0 )
{
g.flags.load_once = 1;
}
else if( argv[i][n] == 'M' )
{
if( argv[i][n+1] == 'F' )
{
if( argv[i][n+2] )
{
if( g.AutoDependFile )
{
fprintf( stderr, "Reopening auto depend file?\n" );
fclose( g.AutoDependFile );
}
g.AutoDependFile = fopen( argv[i]+n+2, "wt" );
if( !g.AutoDependFile )
{
fprintf( stderr, "Failed to open %s for auto depend info.\n", argv[i]+n+2 );
}
}
else
{
nArgState = ARG_AUTODEPEND_NAME;
}
g.bAutoDepend = TRUE;
}
else if( argv[i][n+1] == 'T' )
{
if( argv[i][n+2] ) strcpy( g.AutoTargetName, argv[i]+n+2 );
else nArgState = ARG_AUTOTARGET_NAME;
}
else
goto unknown_option;
}
else if( argv[i][n] == 'o' ||
argv[i][n] == 'O' )
{
if( negarg )
{
g.CurrentOutName[0] = 0xFF;
}
else
{
if( argv[i][n+1] )
{
strcpy( g.CurrentOutName, argv[i] + n + 1 );
//printf( "Set output: %s\n", argv[i] + n + 1 );
done = 1;
}
else
{
nArgState = ARG_OUT_NAME;
}
}
}
else if( argv[i][n] == 'D' ||
argv[i][n] == 'd' )
{
if( argv[i][n+1] )
{
char *eq = strchr( argv[i]+n+1, '=' );
if( eq )
{
*eq = 0;
eq++;
}
// additional command line defines....
DefineDefine( argv[i] + n+1, eq );
}
else
{
nArgState = ARG_DEFINE_DEFINE;
}
}
else if( argv[i][n] == 'z' ||
argv[i][n] == 'Z' )
{
if( isdigit( argv[i][n+1] ) )
{
g.bDebugLog = atoi( argv[i] + n+1 );
printf( "Debug set to %d\n", g.bDebugLog );
if( g.bDebugLog )
g.dbgout = fopen( "debug.log", "wt" );
}
else
g.bDebugLog = TRUE;
}
else if( argv[i][n] == 'L' )
{
g.flags.bLineUsesLineKeyword = TRUE;
if( negarg )
g.flags.bWriteLine = FALSE;
else
{
g.flags.bWriteLine = TRUE;
}
}
else if( argv[i][n] == 'l' )
{
g.flags.bLineUsesLineKeyword = FALSE;
if( negarg )
g.flags.bWriteLine = FALSE;
else
g.flags.bWriteLine = TRUE;
}
else if( argv[i][n] == 'f' )
{
if( negarg )
g.flags.bForceBackslash = FALSE;
else
g.flags.bForceBackslash = TRUE;
}
else if( argv[i][n] == 'F' )
{
if( negarg )
g.flags.bForceForeslash = FALSE;
else
g.flags.bForceForeslash = TRUE;
}
else if( argv[i][n] == 'K' )
{
g.flags.bEmitUnknownPragma = TRUE;
}
else if( argv[i][n] == 'k' )
{
g.flags.bEmitUnknownPragma = FALSE;
}
else if( ( argv[i][n] == '?' ) || ( argv[i][n] == 'h' ) )
{
longusage();
return 0;
}
else
{
unknown_option:
fprintf( stderr, "unknown option: %s (+%d)\n", argv[i], n );
usage();
return 0;
}
done = 1;
break;
}
}
}
else
{
static int process_count;
process_count++;
if( process_count > 1 )
{
//fprintf( stderr, "Probable error! -include, -imacro directives are lost.\nMultiple sources on command line.\n" );
}
ProcessFile( argv[i] );
if( !g.flags.skip_logic_processing )
DeleteAllDefines( DEFINE_FILE );
//if( )
//g.CurrentOutName[0] = 0; // clear name.
}
}
}
return 2;
}
int main( int argc, char **argv, char **env )
{
#ifdef __LINUX__
{
/* #include unistd.h, stdio.h, string.h */
{
char buf[256], *pb;
int n;
n = readlink( "/proc/self/exe", buf, 256 );
if( n >= 0 )
{
//linux
buf[n] = 0;
if( !n )
{
strcpy( buf, "." );
// fbsd
buf[ n = readlink( "/proc/curproc/", buf, 256 ) ] = 0;
}
}
else
strcpy( buf, "." );
pb = strrchr( buf, '/' );
if( pb )
{
pb[0]=0;
pb++;
strcpy( g.pExecName, pb );
}
strcpy( g.pExecPath, buf );
}
}
getcwd( g.pWorkPath, sizeof( g.pWorkPath ) );
#elif defined( _WIN32 )
char *laststroke;
GetModuleFileName( NULL, g.pExecPath, sizeof(g.pExecPath) );
laststroke = pathrchr( g.pExecPath );
if( laststroke )
laststroke[0] = 0;
//printf( "path: %s\n", g.pExecPath );
_getcwd( g.pWorkPath, sizeof( g.pWorkPath ) );
#else
printf( "Path is not defined - probably will not work." );
#endif
#ifdef __WATCOMC__
SetMinAllocate( sizeof( TEXT ) + 16 );
#endif
DisableMemoryValidate(TRUE);
// should build this from execution path of this module
g.flags.do_trigraph = 1;
g.flags.bWriteLine = TRUE;
g.flags.bLineUsesLineKeyword = TRUE;
g.bDebugLog = FALSE;
//g.dbgout = fopen( "debug.log", "wt" );
g.CurrentOutName[0] = 0xFF;
//AddLink( g.pSysIncludePath, SegCreateFromText( "m:\\lcc\\include" ) );
AddLink( g.pUserIncludePath, (PTEXT)&g.pCurrentPath );
SetCurrentPath( "." );
if( argc == 1 ) {
usage(); return 0;
}
// set current date/time macros....
InitDefines();
if( 0 && !g.flags.skip_define_processing )
{
DefineDefine( "TRUE", "1" );
DefineDefine( "FALSE", "0" );
DefineDefine( "true", "1" );
DefineDefine( "false", "0" );
DefineDefine( "__bool_true_false_are_defined", "1" );
DefineDefine( "bool", "unsigned char" );
DefineDefine( "__PPCCPP__", "0x100" );
}
{
int r = processArguments( argc, argv );
if( r == 0 )
return 0;
if( r == 1 )
return 1;
}
VarTextEmpty( &g.vt );
if( g.bAutoDepend )
{
DumpDepends();
}
{
PINCLUDE_REF pRef;
while( pRef = PopLink( g.pIncludeList ) )
Release( pRef );
}
DestoyDepends();
DeleteAllDefines( DEFINE_ALL );
ReleaseIncludePaths();
DeinitDefines();
if( g.bDebugLog )
{
fprintf( stderr, "Allocates: %ld(%zd) Releases: %ld\n", g.nAllocates, g.nAllocSize, g.nReleases );
DumpMemory();
}
if( g.flags.skip_define_processing )
return 0;
return g.ErrorCount;
}
//#include <./types.h>
#define NewArray(a,n) (a*)Allocate( sizeof( a ) * n )
#ifndef NULL
# define NULL (void*)0
#endif
void ParseIntoArgs( char *lpCmdLine, int *pArgc, char ***pArgv )
{
char *args = lpCmdLine;
char *p;
char **pp;
// result variable, count is a temp counter...
char argc;
// result variable, pp is a temp pointer
char **argv;
char quote = 0;
int count = 0;
int lastchar;
// auto continue spaces...
lastchar = ' ';
//lprintf( "Got args: %s", args );
p = args;
while( p && p[0] )
{
//lprintf( "check character %c %c", lastchar, p[0] );
if( quote )
{
if( p[0] == quote )
{
count++;
quote = 0;
lastchar = ' ';
}
}
else
{
if( p[0] == '\"' || p[0] == '\'' )
quote = p[0];
else
{
// and there's a space
if( lastchar != ' ' && p[0] == ' ' )
{
count++;
}
else if( lastchar == ' ' && p[0] != ' ' )
{
}
}
lastchar = p[0] ;
}
p++;
}
if( quote )
// complete this argument
count++;
else if( p != args )
count++;
if( count )
{
char *start;
// auto continue spaces...
lastchar = ' ';
//lprintf( "Array is %d (+2?)", count );
pp = argv = NewArray( char*, count + 2 );
argc = count - 2;
p = args;
quote = 0;
count = 0;
//pp[count++] = StrDup( pTask->pTask ); // setup arg to equal program (needed for linux stuff)
start = NULL;
while( p[0] )
{
//lprintf( "check character %c %c", lastchar, p[0] );
if( quote )
{
if( !start )
start = p;
if( p[0] == quote )
{
p[0] = 0;
pp[count++] = StrDup( start );
p[0] = quote;
quote = 0;
start = NULL;
lastchar = ' ';
}
}
else
{
if( p[0] == '\"' || p[0] == '\'' )
quote = p[0];
else
{
// and there's a space
if( lastchar != ' ' && p[0] == ' ' )
{
p[0] = 0;
pp[count++] = StrDup( start );
start = NULL;
p[0] = ' ';
}
else if( lastchar == ' ' && p[0] != ' ' )
{
if( !start )
start = p;
}
}
lastchar = p[0] ;
}
p++;
}
//lprintf( "Setting arg %d to %s", count, start );
if( start )
pp[count++] = StrDup( start );
pp[count] = NULL;
if( pArgc )
(*pArgc) = count;
if( pArgv )
(*pArgv) = argv;
}
else
{
if( pArgc )
(*pArgc) = 0;
if( pArgv )
{
(*pArgv) = Allocate( sizeof( char*) );
(*pArgv)[0] = NULL;
}
}
}
#ifndef __MAC__
# include <malloc.h>
#endif
#include <stddef.h>
#ifndef PPC_MEMORY_INTERFACE_DEFINED
#define PPC_MEMORY_INTERFACE_DEFINED
#if defined __WATCOMC__
//# include "sharemem.h"
#else
void CPROC *AllocateEx( size_t nSize DBG_PASS );
# define Allocate(s) AllocateEx(s DBG_SRC)
void CPROC ReleaseExx( void ** DBG_PASS );
# if defined( __WATCOMC__ ) || defined( _MSC_VER )
# ifdef _DEBUG
# define ReleaseEx(p,f,l ) ReleaseExx( (void**)&p,f,l )
# else
# define ReleaseEx(p ) ReleaseExx( (void**)&p )
# endif
# else
# define ReleaseEx(... ) ReleaseExx( (void**)&__VA_ARGS__ )
# endif
#define Release(p) ReleaseExx( (void**)&p DBG_SRC)
void DumpMemory( void );
uint32_t CPROC LockedExchange( uint32_t *p, uint32_t val );
void CPROC MemSet( POINTER p, uint32_t v, size_t n);
void CPROC MemCpy( POINTER p, const void *p2, size_t n);
void DisableMemoryValidate( int bDisable );
char CPROC *StrDupEx( const char *original DBG_PASS );
#define StrDup(o) StrDupEx(o DBG_SRC )
#endif
#endif
#define MEMLOG
//#define VALIDATE
//#pragma asm
typedef struct memblock
{
short owners;
short size;
#ifdef _DEBUG
char *file;
int line;
#endif
struct memblock **me, *next;
#ifdef _DEBUG
unsigned long start_tag;
#endif
char data[1];
} MEMBLOCK, *PMEMBLOCK;
PMEMBLOCK root;
int bDisableValidate;
#ifdef VALIDATE
void ValidateMemory( void )
{
PMEMBLOCK mem = root;
while( mem )
{
if( (mem->start_tag) != 0x12345678 )
{
#ifdef _DEBUG
fprintf( stddbg, "Block %s(%d) underflowed\n", mem->file, mem->line );
#else
fprintf( stddbg, "Block %p underflowed\n", mem );
#endif
g.ErrorCount++;
exit(g.ErrorCount);
}
if( *(long*)(mem->data + mem->size ) != 0x12345678 )
{
#ifdef _DEBUG
fprintf( stddbg, "Block %s(%d) overflowed\n", mem->file, mem->line );
#else
fprintf( stddbg, "Block %p overflowed\n", mem );
#endif
g.ErrorCount++;
exit(g.ErrorCount);
}
mem = mem->next;
}
}
#endif
void DisableMemoryValidate( int bDisable )
{
bDisableValidate = bDisable;
}
void *AllocateEx( size_t size DBG_PASS ) {
PMEMBLOCK mem;
#ifdef VALIDATE
ValidateMemory();
#endif
g.nAllocates++;
g.nAllocSize += size;
#ifdef VALIDATE
// long is the type used later
# define EXTRA_SPACE sizeof( long )
#else
# define EXTRA_SPACE 0
#endif
mem = malloc(sizeof(MEMBLOCK) + EXTRA_SPACE + size);
if( !mem )
{
#ifdef _DEBUG
fprintf( stddbg, "%s(%d) Out of memory.\n", pFile, nLine );
#else
fprintf( stddbg, "Out of memory.\n" );
#endif
g.ErrorCount++;
exit(g.ErrorCount);
}
#ifdef _DEBUG
#ifdef MEMLOG
if( g.bDebugLog & DEBUG_MEMORY ) {
fprintf( stddbg, "%s(%d): Allocate %zd %p\n", pFile, nLine, size, mem->data );
fflush( stddbg );
}
#endif
#endif
if( mem->next = root )
root->me = &mem->next;
mem->me = &root;
root = mem;
mem->owners = 1;
mem->size = (short)size;
#ifdef _DEBUG
mem->file = pFile;
mem->line = nLine;
#endif
#ifdef VALIDATE
mem->start_tag = 0x12345678;
*(long*)(mem->data + size) = 0x12345678;
if( !bDisableValidate )
{
ValidateMemory( );
}
#endif
return &mem->data[0];
}
void ReleaseExx( void **pp DBG_PASS ) {
void *p = *pp;
PMEMBLOCK mem = (PMEMBLOCK)(((char*)p) - offsetof( MEMBLOCK, data ));
g.nReleases++;
#ifdef MEMLOG
if( g.bDebugLog & DEBUG_MEMORY ) {
#ifdef _DEBUG
fprintf( stddbg, "%s(%d): Release %p\n"
, pFile, nLine
, p );
fprintf( stddbg, "%s(%d): %s(%d)Release %p\n"
, pFile, nLine
, mem->file, mem->line
, p );
fflush( stddbg );
#else
fprintf( stddbg, "Release %lp\n"
, p );
#endif
}
#endif
#ifdef VALIDATE
if( !bDisableValidate )
{
ValidateMemory();
}
#endif
if( mem->owners != 1 )
{
fprintf( stddbg, "Block %p already free from: %s(%d) - or long ago freed (%d)..."
#ifdef _DEBUG
" %s(%d)"
#endif
, p
#ifdef _DEBUG
, mem->file, mem->line
#endif
, mem->owners
#ifdef _DEBUG
, pFile, nLine
#endif
);
g.ErrorCount++;
exit(g.ErrorCount);
}
#ifdef _DEBUG
#ifdef VALIDATE
if( ( *(long*)(mem->data + mem->size ) != 0x12345678 ||
mem->start_tag != 0x12345678 ) )
{
fprintf( stddbg, "Application overflowed memory.%p(%d) %s(%d)"
" %s(%d)"
, mem->data
, mem->size
, mem->file, mem->line
DBG_RELAY );
g.ErrorCount++;
exit(g.ErrorCount);
}
#endif
#endif
if( *mem->me = mem->next )
mem->next->me = mem->me;
#ifdef _DEBUG
mem->file = pFile;
mem->line = nLine;
#endif
mem->owners = 0;
free(mem);
*pp = NULL;
}
void DumpMemory( void )
{
PMEMBLOCK mem = root;
while( mem )
{
fprintf( stddbg, "Block: %d %p "
#ifdef _DEBUG
"%s(%d)"
#endif
"\n", mem->size, mem->data
#ifdef _DEBUG
,mem->file, mem->line
#endif
);
mem = mem->next;
}
}
void CPROC MemSet( void *p, uint32_t v, size_t n) {memset(p,v,n);}
void CPROC MemCpy( void *p, const void *p2, size_t n) {memcpy(p,p2,n);}
uint32_t LockedExchange( uint32_t *p, uint32_t val )
{
uint32_t x;
x = *p;
*p = val;
return x;
/*
long res;
asm .386;
asm les di, p;
asm mov ecx, val;
asm xchg es:[di], ecx ;
asm mov res, ecx;
return res;
*/
}
char *StrDupEx( const char *original DBG_PASS )
{
size_t len = strlen( original ) + 1;
char *result = AllocateEx( len DBG_RELAY );
MemCpy( result, original, len );
return result;
}
#if defined( __GNUC__ ) && !defined( _WIN32 )
int stricmp( char *one, char *two )
{
return strcasecmp( one, two );
}
int strnicmp( char *one, char *two, int len )
{
return strncasecmp( one, two, len );
}
#endif
#if defined( __WINTIME__ )
#endif
#include <time.h>
//#define DEFINE_STDC_VERSION
#define DEBUG_SUBST 0x02
#define DEBUG_DEFINES 0x04
static PDEF pDefineRoot, pCurrentDefine;
// static symbol....
static DEF DefineLine
// static symbol....
, DefineFile
// 199901L
, DefineStdCVersion
// "00:00:00.000"
, DefineTime
// "mmm dd, yyyy"
, DefineDate;
static int nDefines;
//----------------------------------------------------------------------
#ifdef _DEBUG
void ValidateTree( PDEF *root )
{
if( root && *root )
{
if( (*root)->me != root )
{
fprintf( stderr, "Invalid linking this->me is not itself!\n" );
DebugBreak();
}
if( (*root)->pGreater )
{
if( (*root)->pGreater->me != &(*root)->pGreater )
{
fprintf( stderr, "Invalid linking this->greater does not reference me\n" );
DebugBreak();
}
ValidateTree( &(*root)->pGreater );
}
if( (*root)->pLesser )
{
if( (*root)->pLesser->me != &(*root)->pLesser )
{
fprintf( stderr, "Invalid linking this->lesser does not reference me\n" );
DebugBreak();
}
ValidateTree( &(*root)->pLesser );
}
if( (*root)->pSame )
{
if( (*root)->pSame->me != &(*root)->pSame )
{
fprintf( stderr, "Invalid linking this->same does not reference me\n" );
DebugBreak();
}
ValidateTree( &(*root)->pSame );
}
}
}
#else
#define ValidateTree(r)
#endif
#define ValidateTree(r)
//----------------------------------------------------------------------
void FixQuoting( PTEXT test )
{
while( test )
{
if( GetText( test )[0] == '\"' )
{
PTEXT insert = SegCreateFromText( "\\" );
insert->format.spaces = test->format.spaces;
test->format.spaces = 0;
SegInsert( insert, test );
}
else if( GetText( test )[0] == '\'' )
{
PTEXT insert = SegCreateFromText( "\\" );
insert->format.spaces = test->format.spaces;
test->format.spaces = 0;
SegInsert( insert, test );
}
else if( GetText( test )[0] == '\\' )
{
PTEXT insert = SegCreateFromText( "\\" );
insert->format.spaces = test->format.spaces;
test->format.spaces = 0;
SegInsert( insert, test );
}
test = NEXTLINE( test );
}
}
//----------------------------------------------------------------------
void DeleteDefineContent( PDEF p )
{
if( p->pName )
LineRelease( p->pName );
if( p->pData )
LineRelease( p->pData );
{
INDEX idx;
PTEXT param;
FORALL( p->pParams, idx, PTEXT, param )
{
LineRelease( param );
}
DeleteList( p->pParams );
}
}
//----------------------------------------------------------------------
void DeleteStaticDefines( void )
{
DeleteDefineContent( &DefineLine );
DeleteDefineContent( &DefineFile );
#ifdef DEFINE_STDC_VERSION
DeleteDefineContent( &DefineStdCVersion );
#endif
DeleteDefineContent( &DefineDate );
DeleteDefineContent( &DefineTime );
}
//----------------------------------------------------------------------
void InitDefines( void )
{
#if defined( __UNIXTIME__ )
struct tm tm;
time_t now;
now = time( NULL );
localtime_r( &now, &tm );
#elif defined( __WINTIME__ )
SYSTEMTIME st;
GetLocalTime( &st );
#endif
{
DECLTEXT( constname, "__LINE__" );
DefineLine.pName = (PTEXT)&constname;
DefineLine.pParams = NULL;
DefineLine.bUsed = FALSE;
DefineLine.pLesser = NULL;
DefineLine.pGreater = NULL;
}
{
DECLTEXT( constname, "__FILE__" );
DefineFile.pName = (PTEXT)&constname;
DefineFile.pParams = NULL;
DefineFile.bUsed = FALSE;
DefineFile.pLesser = NULL;
DefineFile.pGreater = NULL;
}
//if( TextIs( pName, "__TIME__ " ) ) // hh:mm:ss
{
DECLTEXT( constname, "__TIME__" );
char time[15];
#if defined( __UNIXTIME__ )
strftime( time, 15, "\"%H:%M:%S\"", &tm );
#elif defined( __WINTIME__ )
snprintf( time, 15, "\"%2d:%02d:%02d.%03d\""
, st.wHour, st.wMinute
, st.wSecond, st.wMilliseconds );
#endif
DefineTime.pName = (PTEXT)&constname;
DefineTime.pData = SegCreateFromText( time );
DefineTime.pData->format.spaces = 1;
DefineTime.pParams = NULL;
DefineTime.bUsed = FALSE;
DefineTime.pLesser = NULL;
DefineTime.pGreater = NULL;
}
//if( TextIs( pName, "__DATE__ " ) ) // Mmm dd yyyy dd = ' x' if <10
{
DECLTEXT( constname, "__DATE__" );
char date[20];
#if defined( __UNIXTIME__ )
strftime( date, 20, "\"%b %e %Y\"", &tm );
#elif defined( __WINTIME__ )
snprintf( date, 20, "\"%02d/%02d/%04d\""
, st.wMonth, st.wDay, st.wYear );
#endif
DefineDate.pName = (PTEXT)&constname;
DefineDate.pData = SegCreateFromText( date );
DefineDate.pData->format.spaces = 1;
DefineDate.pParams = NULL;
DefineDate.bUsed = FALSE;
DefineDate.pLesser = NULL;
DefineDate.pGreater = NULL;
}
// on GCC - these end up being defined....
//if( TextIs( pName, "__STDC__ " ) ) // 1
//if( TextIs( pName, "__STDC_HOSTED__ " ) ) // ?? what's a hosted?
// and this - well the compiler itself needs to support this - so
// this should come in from the
#ifdef DEFINE_STDC_VERSION
{
DECLTEXT( constname, "__STDC_VERSION__" );
DefineStdCVersion.pParams = NULL;
DefineStdCVersion.pName = (PTEXT)&constname;
DefineStdCVersion.pData = SegCreateFromInt( 199901L );
DefineStdCVersion.pData->format.spaces = 1;
DefineStdCVersion.bUsed = FALSE;
DefineStdCVersion.pLesser = NULL;
DefineStdCVersion.pGreater = NULL;
}
#endif
}
//----------------------------------------------------------------------
void DeinitDefines( void )
{
DeleteStaticDefines();
}
//----------------------------------------------------------------------
// if params are negative - the count is -(absolute count)
//
PDEF FindDefineName( PTEXT pName, int params )
{
PDEF p;
int levels = 1;
if( TextIs( pName, "__LINE__" ) )
{
if( DefineLine.pData )
LineRelease( DefineLine.pData );
DefineLine.pData = SegCreateFromInt( GetCurrentLine() );
DefineLine.bUsed = FALSE;
return &DefineLine;
}
else if( TextIs( pName, "__FILE__" ) )
{
VARTEXT vt;
VarTextInit( &vt );
if( DefineFile.pData )
LineRelease( DefineFile.pData );
//printf( "Building result: %s\n", GetCurrentFileName() );
VarTextAddCharacter( &vt, '\"' );
VarTextEnd( &vt );
vtprintf( &vt, "%s", GetCurrentShortFileName() );
VarTextEnd( &vt );
VarTextAddCharacter( &vt, '\"' );
DefineFile.pData = VarTextGet( &vt );
VarTextEmpty( &vt );
DefineFile.bUsed = FALSE;
return &DefineFile;
}
//if( TextIs( pName, "__TIME__ " ) ) // hh:mm:ss
else if( TextIs( pName, "__TIME__" ) )
{
DefineTime.bUsed = FALSE;
return &DefineTime;
}
//if( TextIs( pName, "__DATE__ " ) ) // Mmm dd yyyy dd = ' x' if <10
else if( TextIs( pName, "__DATE__" ) )
{
DefineDate.bUsed = FALSE;
return &DefineDate;
}
// This is probably compiler specific.... but let's see what
// happens for now.
#ifdef DEFINE_STDC_VERSION
// 199901L
else if( TextIs( pName, "__STDC_VERSION__" ) )
{
return &DefineStdCVersion;
}
#endif
// all of these are compiler specific....
//if( TextIs( pName, "__STDC__ " ) ) // 1
//if( TextIs( pName, "__STDC_HOSTED__ " ) ) // ?? what's a hosted?
//if( TextIs( pName, "__STDC_IEC_559__ " ) ) // 1 if conform annex f
//if( TextIs( pName, "__STDC_IEC_559_COMPLEX__ " ) ) // 1 if conform annex g
//if( TextIs( pName, "__STDC_ISO_10646__ " ) ) // 199712L yyyymmL wchar_t encodings
// do not allow __cplusplus to redefine...
p = pDefineRoot;
while( p )
{
int d = SameText( pName, p->pName );
if( d == 0 )
{
// just checking to see if defined...
if( params == IGNORE_PARAMS &&
!p->bUsed )
return p;
do
{
if( params < 0 )
{
// looking for macro with var args...
if( p->bVarParams &&
p->pParams->Cnt == -params )
{
// same one...
return p;
}
}
if( p->pParams )
{
if( p->pParams->Cnt == params
|| ( p->bVarParams
&& ( (int)p->pParams->Cnt <= params ) )
)
{
if( !p->bUsed )
return p;
// otherwise - maybe we can use the next one?
}
}
else if( !params )
{
if( !p->bUsed )
return p;
}
p = p->pSame;
}
while( p );
if( p )
break;
}
else if( d > 0 )
p = p->pGreater;
else
p = p->pLesser;
levels++;
}
//if( g.bDebugLog )
// fprintf( stderr, "levels checked for name: %d/%d\n", levels, nDefines );
return NULL;
}
//----------------------------------------------------------------------
// inserts pDef where p is, pushing p to be under pDef as pSame
void InsertDefine( PDEF pDef, PDEF p )
{
*p->me = pDef;
pDef->me = p->me;
if( pDef->pGreater = p->pGreater )
pDef->pGreater->me = &pDef->pGreater;
if( pDef->pLesser = p->pLesser )
pDef->pLesser->me = &pDef->pLesser;
pDef->pSame = p;
p->me = &pDef->pSame;
p->pGreater = NULL;
p->pLesser = NULL;
}
//----------------------------------------------------------------------
void HangNode( PDEF *root, PDEF pDef );
void DeleteDefine( PDEF *ppDef )
{
if( ppDef && *ppDef )
{
PDEF pDef = *ppDef;
PDEF tmp;
// this ends up clearing &pDef usually....
tmp = pDef;
// take me out of the tree...
if( pDef->me )
*pDef->me = NULL;
if( pDef->pSame )
{
pDef->pSame->me = NULL;
HangNode( &pDefineRoot, pDef->pSame );
pDef->pSame = NULL;
}
if( pDef->pLesser )
{
pDef->pLesser->me = NULL;
HangNode( &pDefineRoot, pDef->pLesser );
pDef->pLesser = NULL;
}
if( pDef->pGreater )
{
pDef->pGreater->me = NULL;
HangNode( &pDefineRoot, pDef->pGreater );
pDef->pGreater = NULL;
}
DeleteDefineContent( pDef );
Release( tmp );
ValidateTree( &pDefineRoot );
nDefines--;
}
}
//----------------------------------------------------------------------
void HangNode( PDEF *root, PDEF pDef )
{
PDEF p, prior = NULL;
if( !pDef )
return;
// allow definition of internal __DATE__ and __TIME__
if( TextIs( pDef->pName, "__DATE__" ) )
{
if( pDef->nType == DEFINE_COMMANDLINE )
{
LineRelease( DefineDate.pData );
DefineDate.pData = pDef->pData;
pDef->pData = NULL;
DeleteDefine( &pDef );
}
else
{
fprintf( stderr, "%s(%d): May only define __DATE__ from a command line parameter\n"
, GetCurrentFileName()
, GetCurrentLine()
);
DeleteDefine( &pDef );
}
return;
}
else if( TextIs( pDef->pName, "__TIME__" ) )
{
if( pDef->nType == DEFINE_COMMANDLINE )
{
LineRelease( DefineTime.pData );
DefineTime.pData = pDef->pData;
pDef->pData = NULL;
DeleteDefine( &pDef );
}
else
{
fprintf( stderr, "%s(%d): May only define __TIME__ from a command line parameter\n"
, GetCurrentFileName()
, GetCurrentLine()
);
DeleteDefine( &pDef );
}
return;
}
if( !*root )
{
*root = pDef;
pDef->me = root;
ValidateTree( &pDefineRoot );
return;
}
p = *root;
while( p )
{
int d = SameText( pDef->pName, p->pName );;
if( d > 0 )
{
if( !p->pGreater )
{
pDef->me = &p->pGreater;
p->pGreater = pDef;
ValidateTree( &pDefineRoot );
return;
}
else
{
prior = p;
p = p->pGreater;
}
}
else if( d < 0 )
{
if( !p->pLesser )
{
pDef->me = &p->pLesser;
p->pLesser = pDef;
ValidateTree( &pDefineRoot );
return;
}
else
{
prior = p;
p = p->pLesser;
}
}
else
{
if( pDef->pParams )
// has parameters () - may be 0, but still...
{
// nparams...
do
{
if( p->pParams )
{
if( pDef->pParams->Cnt < p->pParams->Cnt )
{
InsertDefine( pDef, p );
ValidateTree( &pDefineRoot );
return;
}
else if( pDef->pParams->Cnt == p->pParams->Cnt )
{
if( p->bVarParams )
{
if( pDef->bVarParams )
{
fprintf( stderr, "%s(%d): Error attempt to redefine macro %s defined at %s(%d).\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( pDef->pName )
, p->pFile, p->nLine );
g.ErrorCount++;
DeleteDefine( &pDef );
ValidateTree( &pDefineRoot );
return;
}
InsertDefine( pDef, p );
ValidateTree( &pDefineRoot );
return;
}
else
{
if( !pDef->bVarParams )
{
fprintf( stderr, "%s(%d): Error attempt to redefine macro %s defined at %s(%d).\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( pDef->pName )
, p->pFile, p->nLine );
g.ErrorCount++;
DeleteDefine( &pDef );
ValidateTree( &pDefineRoot );
return;
}
// else step to next ( need to add after this)
}
}
}
prior = p;
p = p->pSame;
} while( p );
pDef->me = &prior->pSame;
prior->pSame = pDef;
ValidateTree( &pDefineRoot );
return;
}
else
{
// no paramters - symbol alone...
if( !p->pParams )
{
/*
if( !pDef->pParams )
{
fprintf( stderr, "%s(%d): WARNING Attempt to Redefine macro with no params - failed.!\n"
, GetCurrentFileName()
, GetCurrentLine() );
DeleteDefine( &pDef );
ValidateTree( &pDefineRoot );
return;
}
else
*/
fprintf( stderr, "%s(%d): WARNING Redefining macro \'%s\'(overloading name alone with params)!\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( pDef->pName )
);
}
InsertDefine( pDef, p );
ValidateTree( &pDefineRoot );
return;
}
}
}
}
//----------------------------------------------------------------------
void DeleteDefineTree( PDEF *ppRoot, int type )
{
if( ppRoot && *ppRoot )
{
PDEF root = *ppRoot;
DeleteDefineTree( &(root->pLesser), type );
DeleteDefineTree( &(root->pGreater), type );
DeleteDefineTree( &(root->pSame), type );
if( type == DEFINE_ALL ||
root->nType == type )
DeleteDefine( ppRoot );
ValidateTree( &pDefineRoot );
}
}
//----------------------------------------------------------------------
void DeleteAllDefines( int type )
{
// uhmm this works - but it's hideous...
// should do something like delete bottom up
DeleteDefineTree( &pDefineRoot, type );
}
//----------------------------------------------------------------------
void DefineDefine( char *name, char *value )
{
PDEF pDefine = Allocate( sizeof( DEF ) );
MemSet( pDefine, 0, sizeof( DEF ) );
pDefine->nType = DEFINE_COMMANDLINE;
pDefine->pName = SegCreateFromText( name );
pDefine->pData = SegCreateFromText( value );
if( pDefine->pData )
pDefine->pData->format.spaces = 1;
HangNode( &pDefineRoot, pDefine );
}
//----------------------------------------------------------------------
int ProcessDefine( int type )
{
//PTEXT def;
if( !pCurrentDefine )
{
PTEXT pWord = GetCurrentWord();
if( TextIs( pWord, "__LINE__" )
|| TextIs( pWord, "__FILE__" )
#ifdef DEFINE_STDC_VERSION
|| TextIs( pWord, "__STDC_VERSION__" )
#endif
)
// none of the above constants mentioned may be redefined
// nor 'defined'
{
if( g.bDebugLog )
{
fprintf( stddbg, "%s(%d) Warning: Cannot define predefined symbols."
, GetCurrentFileName(), GetCurrentLine() );
}
fprintf( stderr, "%s(%d) Warning: Cannot define predefined symbols."
, GetCurrentFileName(), GetCurrentLine() );
// just a warning
return TRUE;
}
pCurrentDefine = Allocate( sizeof( DEF ) );
MemSet(pCurrentDefine, 0, sizeof( DEF ) );
strcpy( pCurrentDefine->pFile, GetCurrentFileName() );
pCurrentDefine->nLine = GetCurrentLine();
pCurrentDefine->nType = type;
pWord = GetCurrentWord();
if( g.bDebugLog & DEBUG_DEFINES )
{
fprintf( stddbg, "%s(%d) Defining macro: %s\n"
, GetCurrentFileName(), GetCurrentLine()
, GetText( pWord ) );
}
pCurrentDefine->pName = SegDuplicate( pWord );
if( ( NEXTLINE( pWord )
&& ( NEXTLINE( pWord )->format.spaces == 0 )
&& ( NEXTLINE( pWord )->format.tabs == 0 )
) )
{
pWord = StepCurrentWord();
if( GetText( pWord )[0] == '(' )
{
// these parameters are macros vars for define...
// required count....
pCurrentDefine->pParams = CreateList();
StepCurrentWord();
while( ( pWord = GetCurrentWord() ) &&
GetText( pWord )[0] != ')' )
{
if( GetText( pWord )[0] != ',' )
{
if( TextIs( pWord, "..." ) )
{
if( g.bDebugLog & DEBUG_DEFINES )
fprintf( stddbg, "Adding var args...\n" );
if( pCurrentDefine->bVarParams )
{
fprintf( stderr, "%s(%d): Duplicate \'...\' used in define definition.\n"
, GetCurrentFileName()
, GetCurrentLine() );
}
else
pCurrentDefine->bVarParams = TRUE;
}
else
{
PTEXT param = NULL;
INDEX idx;
if( !pCurrentDefine->bVarParams )
{
if( g.bDebugLog & DEBUG_DEFINES )
fprintf( stddbg, "Adding argument: %s\n", GetText( pWord ) );
FORALL( pCurrentDefine->pParams, idx, PTEXT, param )
{
if( SameText( param, pWord ) == 0 )
{
fprintf( stderr, "%s(%d): Error same parameter name defined twice: %s\n"
, GetCurrentFileName()
, GetCurrentLine()
, GetText( param ) );
g.ErrorCount++;
}
// have to manual reset this...
param = NULL;
}
if( !param )
{
AddLink( pCurrentDefine->pParams
, SegDuplicate( pWord ) );
}
else if( g.bDebugLog & DEBUG_DEFINES )
fprintf( stddbg, "Parameter already existed????\n" );
}
else
{
fprintf( stderr, "%s(%d): regular parameters are not allowed to follow var args (...)\n"
, GetCurrentFileName()
, GetCurrentLine() );
}
}
}
StepCurrentWord();
}
}
}
StepCurrentWord();
}
//----------------
// add data to the current macro here...
//----------------
if( GetCurrentWord() )
{
PTEXT p;
p = GetCurrentWord();
while( p )
{
PTEXT newseg = SegDuplicate( p );
if( p == GetCurrentWord() )
newseg->format.spaces = 0;
pCurrentDefine->pData = SegAppend( pCurrentDefine->pData
, newseg );
p = NEXTLINE(p);
}
pCurrentDefine->pData->format.spaces = 0;
}
if( g.bDebugLog & DEBUG_DEFINES )
{
PTEXT out = BuildLine( pCurrentDefine->pData );
fprintf( stddbg, "Define %s == %s\n", GetText( pCurrentDefine->pName ), GetText( out ) );
LineRelease( out );
}
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "searching for %s(%zd) ...\n"
,GetText( pCurrentDefine->pName)
, pCurrentDefine->pParams
? pCurrentDefine->bVarParams
?-(int)pCurrentDefine->pParams->Cnt
:pCurrentDefine->pParams->Cnt
: 0
);
}
{
PDEF pOld = FindDefineName( pCurrentDefine->pName
, pCurrentDefine->pParams
? pCurrentDefine->bVarParams
?-(int)pCurrentDefine->pParams->Cnt
:(int)pCurrentDefine->pParams->Cnt
: 0 );
if( pOld )
{
if( g.flags.bAllWarnings )
fprintf( stderr, "%s(%d) Warning: redefining symbol: %s Previously defined at %s(%d).\n"
, GetCurrentFileName(), GetCurrentLine()
, GetText( pCurrentDefine->pName )
, pOld->pFile, pOld->nLine );
DeleteDefine( &pOld );
}
//else if( g.bDebugLog )
//{
// fprintf( stderr, "Symbol not found - continue normall.\n" );
//}
}
// completed the macro definition here....
nDefines++;
HangNode( &pDefineRoot, pCurrentDefine );
pCurrentDefine = NULL;
if( g.bDebugLog & DEBUG_DEFINES )
fprintf( stddbg, "done with define...\n" );
return TRUE;
}
//----------------------------------------------------------------------
PTEXT BuildSizeofArgs( PTEXT args )
{
PTEXT arg = NULL
, trinary_then = NULL
, trinary_else = NULL;
PTEXT result = NULL;
char *text;
int quote = 0
, paren = 0
, trinary_collect_then = 0
, trinary_collect_else = 0;
for( ; args; args = NEXTLINE( args ) )
{
text = GetText( args );
if( !quote )
{
if( text[0] == '\"' ||
text[0] == '\'' )
{
quote = text[0];
continue;
}
if( text[0] == '(' )
paren++;
else if( text[0] == ')' )
paren--;
if( paren )
{
if( trinary_collect_else )
trinary_else = SegAppend( trinary_else, SegDuplicate( args ) );
else if( trinary_collect_then )
trinary_then = SegAppend( trinary_then, SegDuplicate( args ) );
else
arg = SegAppend( arg, SegDuplicate( args ) );
continue;
}
if( text[0] == '?' )
{
trinary_collect_then = 1;
continue;
}
if( trinary_collect_then && text[0] == ':' )
{
trinary_collect_else = 1;
continue;
}
}
// in quote...
else
{
if( text[0] == quote )
{
if( trinary_collect_else )
trinary_else = SegAppend( trinary_else, SegCreateFromText( "char*" ) );
else if( trinary_collect_then )
trinary_then = SegAppend( trinary_then, SegCreateFromText( "char*" ) );
else
arg = SegAppend( arg, SegCreateFromText( "char*" ) );
quote = 0;
}
continue;
}
if( text[0] == ',' )
{
PTEXT out = arg;
PTEXT tmp;
trinary_collect_else = 0;
trinary_collect_then = 0;
vtprintf( &g.vt, "(" );
VarTextEnd( &g.vt );
vtprintf( &g.vt , " ( (" );
VarTextEnd( &g.vt );
if( trinary_then && trinary_else )
{
vtprintf( &g.vt , " ( sizeof( " );
VarTextEnd( &g.vt );
out = trinary_then;
while( out )
{
vtprintf( &g.vt, "%s", GetText( out ) );
tmp = VarTextEnd( &g.vt );
tmp->flags |= out->flags & TF_NOEXPAND;
tmp->format.spaces = out->format.spaces;
out = NEXTLINE( out );
}
vtprintf( &g.vt, " ) > " );
VarTextEnd( &g.vt );
vtprintf( &g.vt , "sizeof( " );
VarTextEnd( &g.vt );
out = trinary_else;
while( out )
{
vtprintf( &g.vt, "%s", GetText( out ) );
tmp = VarTextEnd( &g.vt );
tmp->flags |= out->flags & TF_NOEXPAND;
tmp->format.spaces = out->format.spaces;
out = NEXTLINE( out );
}
vtprintf( &g.vt, " ) ? " );
VarTextEnd( &g.vt );
vtprintf( &g.vt , "sizeof( " );
VarTextEnd( &g.vt );
out = trinary_then;
while( out )
{
vtprintf( &g.vt, "%s", GetText( out ) );
tmp = VarTextEnd( &g.vt );
tmp->flags |= out->flags & TF_NOEXPAND;
tmp->format.spaces = out->format.spaces;
out = NEXTLINE( out );
}
vtprintf( &g.vt, " ) : " );
VarTextEnd( &g.vt );
vtprintf( &g.vt , "sizeof( " );
VarTextEnd( &g.vt );
out = trinary_else;
while( out )
{
vtprintf( &g.vt, "%s", GetText( out ) );
tmp = VarTextEnd( &g.vt );
tmp->flags |= out->flags & TF_NOEXPAND;
tmp->format.spaces = out->format.spaces;
out = NEXTLINE( out );
}
vtprintf( &g.vt, " ) ) " );
VarTextEnd( &g.vt );
LineRelease( trinary_then );
LineRelease( trinary_else );
// would be the 'if' part of this expression - unused.
LineRelease( arg );
}
else
{
if( ( trinary_then && !trinary_else )
|| ( !trinary_then && trinary_else ) )
{
fprintf( stderr, "%s(%d): Badly formed trinary operator!\n"
, GetCurrentFileName()
, GetCurrentLine() );
LineRelease( trinary_then );
LineRelease( trinary_else );
}
vtprintf( &g.vt , " sizeof( " );
VarTextEnd( &g.vt );
out = arg;
while( out )
{
vtprintf( &g.vt, "%s", GetText( out ) );
tmp = VarTextEnd( &g.vt );
tmp->flags |= out->flags & TF_NOEXPAND;
tmp->format.spaces = out->format.spaces;
out = NEXTLINE( out );
}
vtprintf( &g.vt, ")" );
VarTextEnd( &g.vt );
LineRelease( arg );
}
vtprintf( &g.vt, " + 3 ) / 4 ) * 4 " );
VarTextEnd( &g.vt );
vtprintf( &g.vt, ")" );
VarTextEnd( &g.vt );
vtprintf( &g.vt, "+" );
VarTextEnd( &g.vt );
result = SegAppend( result, VarTextGet( &g.vt ) );
}
else
{
if( trinary_collect_else )
trinary_else = SegAppend( trinary_else, SegDuplicate( args ) );
else if( trinary_collect_then )
trinary_then = SegAppend( trinary_then, SegDuplicate( args ) );
else
arg = SegAppend( arg, SegDuplicate( args ) );
}
}
if( arg )
{
{
PTEXT out = arg;
PTEXT tmp;
vtprintf( &g.vt, "(" );
VarTextEnd( &g.vt );
vtprintf( &g.vt , " ( (" );
VarTextEnd( &g.vt );
if( trinary_then && trinary_else )
{
vtprintf( &g.vt , " ( sizeof( " );
VarTextEnd( &g.vt );
out = trinary_then;
while( out )
{
vtprintf( &g.vt, "%s", GetText( out ) );
tmp = VarTextEnd( &g.vt );
tmp->flags |= out->flags & TF_NOEXPAND;
tmp->format.spaces = out->format.spaces;
out = NEXTLINE( out );
}
vtprintf( &g.vt, " ) > " );
VarTextEnd( &g.vt );
vtprintf( &g.vt , "sizeof( " );
VarTextEnd( &g.vt );
out = trinary_else;
while( out )
{
vtprintf( &g.vt, "%s", GetText( out ) );
tmp = VarTextEnd( &g.vt );
tmp->flags |= out->flags &TF_NOEXPAND;
tmp->format.spaces = out->format.spaces;
out = NEXTLINE( out );
}
vtprintf( &g.vt, " ) ? " );
VarTextEnd( &g.vt );
vtprintf( &g.vt , "sizeof( " );
VarTextEnd( &g.vt );
out = trinary_then;
while( out )
{
vtprintf( &g.vt, "%s", GetText( out ) );
tmp = VarTextEnd( &g.vt );
tmp->flags |= out->flags & TF_NOEXPAND;
tmp->format.spaces = out->format.spaces;
out = NEXTLINE( out );
}
vtprintf( &g.vt, " ) : " );
VarTextEnd( &g.vt );
vtprintf( &g.vt , "sizeof( " );
VarTextEnd( &g.vt );
out = trinary_else;
while( out )
{
vtprintf( &g.vt, "%s", GetText( out ) );
tmp = VarTextEnd( &g.vt );
tmp->flags |= out->flags & TF_NOEXPAND;
tmp->format.spaces = out->format.spaces;
out = NEXTLINE( out );
}
vtprintf( &g.vt, " ) ) " );
VarTextEnd( &g.vt );
LineRelease( trinary_then );
LineRelease( trinary_else );
// would be the 'if' part of this expression - unused.
LineRelease( arg );
}
else
{
if( ( trinary_then && !trinary_else )
|| ( !trinary_then && trinary_else ) )
{
fprintf( stderr, "%s(%d): Badly formed trinary operator!\n"
, GetCurrentFileName()
, GetCurrentLine() );
LineRelease( trinary_then );
LineRelease( trinary_else );
}
vtprintf( &g.vt , " sizeof( " );
VarTextEnd( &g.vt );
out = arg;
while( out )
{
vtprintf( &g.vt, "%s", GetText( out ) );
tmp = VarTextEnd( &g.vt );
tmp->flags |= out->flags & TF_NOEXPAND;
tmp->format.spaces = out->format.spaces;
out = NEXTLINE( out );
}
vtprintf( &g.vt, " )" );
VarTextEnd( &g.vt );
}
vtprintf( &g.vt, " + 3 ) / 4 ) * 4 " );
VarTextEnd( &g.vt );
vtprintf( &g.vt, ")" );
VarTextEnd( &g.vt );
//vtprintf( &g.vt, "+" );
//VarTextEnd( &g.vt );
LineRelease( arg );
result = SegAppend( result, VarTextGet( &g.vt ) );
arg = NULL;
}
}
else
result = SegAppend( result, SegCreateFromInt( 0 ) );
return result;
}
//----------------------------------------------------------------------
INDEX FindArg( PLIST pArgs, PTEXT pName )
{
INDEX i;
PTEXT pTest;
if( TextIs( pName, "..." )
|| TextIs( pName, "__VA_ARGS__" )
|| TextIs( pName, "__SZ_ARGS__" ) )
{
return pArgs->Cnt;
}
FORALL( pArgs, i, PTEXT, pTest )
{
if( SameText( pName, pTest ) == 0 )
{
return i;
}
}
return INVALID_INDEX;
}
void EmptyArgList( PLIST *pArgVals )
{
INDEX idx;
PTEXT pDelete;
FORALL( *pArgVals, idx, PTEXT, pDelete )
{
LineRelease( pDelete );
}
DeleteListEx( pArgVals DBG_SRC );
}
//----------------------------------------------------------------------
PDEF AddArgumentEx( PLIST *pArgVals, PTEXT *pVal, INDEX *pi, PDEF pDefine, int *pbVarArg DBG_PASS )
#define AddArgument(pav,v,i,d,bva) AddArgumentEx(pav,v,i,d,bva DBG_SRC)
{
if( !*pbVarArg )
{
while( *pi >= pDefine->pParams->Cnt &&
pDefine->pSame )
{
if( g.bDebugLog & DEBUG_SUBST )
fprintf( stddbg, "Attempting to find a define with more arguments...\n" );
pDefine = pDefine->pSame;
}
if( *pi >= pDefine->pParams->Cnt )
{
if( g.bDebugLog & DEBUG_SUBST )
fprintf( stddbg, "Too many paramters for %s (%zd of %zd) - try var arg\n"
, GetText( pDefine->pName )
, *pi, pDefine->pParams->Cnt );
if( !pDefine->bVarParams )
{
fprintf( stderr, "%s(%d): Warning: excessive parameters to macro... resulting no replacement\n"
, GetCurrentFileName(), GetCurrentLine() );
EmptyArgList( pArgVals );
return NULL;
}
if( g.bDebugLog & DEBUG_SUBST )
fprintf( stddbg, "okay and vararg it is!\n" );
if( !(*pbVarArg) )
{
*pbVarArg = 1;
*pi = pDefine->pParams->Cnt;
return pDefine;
}
}
}
if( GetLinkEx( pArgVals, *pi ) )
fprintf( stderr, "Overwriting exisitng parameter with new parameter?!" );
SetLinkEx( pArgVals, *pi, *pVal DBG_RELAY );
*pVal = NULL;
if( !*pbVarArg )
(*pi)++;
return pDefine;
}
//----------------------------------------------------------------------
void EvalSubstitutions( PTEXT *subst, int more )
{
// pWord may be associated with parameters...
// EvanSubst( &"min(a,b)" ) or basically...
PTEXT pStart, pWord, pReset;
PDEF pDefine;
int Quote = 0, Escape = 0;
static int nSubstLevel;
// get word first....
if( !subst || !*subst )
return;
nSubstLevel++;
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stderr, "Looking to substitute:" );
DumpSegs( *subst );
fprintf( stderr, "\n" );
}
// start at the beginning of all symbols...
for( pWord = *subst;
//= GetCurrentWord();
pWord;
pWord = pReset )
{
pReset = NEXTLINE( pWord );
if( pWord->flags & (TF_INDIRECT|TF_NOEXPAND) )
continue;
if( Quote )
{
if( !Escape )
{
if( GetText( pWord )[0] == '\\' )
{
Escape = TRUE;
continue;
}
}
else
{
Escape = FALSE;
continue;
}
if( GetText( pWord )[0] == Quote )
Quote = 0;
continue;
}
//fprintf( stderr, "Word is: %s\n", GetText(pWord) );
if( GetText( pWord )[0] == '\'' ||
GetText( pWord )[0] == '\"' )
{
Quote = GetText( pWord )[0];
continue;
}
if( TextIs( pWord, "defined" ) )
{
PTEXT pNewWord = NULL, pEnd;
pStart = pWord;
pEnd = pWord = NEXTLINE( pWord );
if( pWord &&
GetText( pWord )[0] == '(' )
{
pWord = NEXTLINE( pWord );
if( pWord &&
GetText( pWord )[0] != ')' )
{
if( FindDefineName( pWord, IGNORE_PARAMS ) )
{
pNewWord = SegCreateFromText( "1" );
pNewWord->format.spaces = pStart->format.spaces;
} else
{
pNewWord = SegCreateFromText( "0" );
pNewWord->format.spaces = pStart->format.spaces;
}
pWord = NEXTLINE( pWord );
if( GetText( pWord )[0] != ')' )
{
fprintf( stderr, "%s(%d): Error in parameter to 'defined' - more than one symbol?\n"
, GetCurrentFileName(), GetCurrentLine() );
g.ErrorCount++;
}
pEnd = pWord;
}
else
{
fprintf( stderr, "%s(%d): Empty paranthesis to defined.\n"
, GetCurrentFileName(), GetCurrentLine() );
}
}
else
{
if( pWord )
{
if( FindDefineName( pWord, IGNORE_PARAMS ) )
{
pNewWord = SegCreateFromText( "1" );
pNewWord->format.spaces = pStart->format.spaces;
}
else
{
pNewWord = SegCreateFromText( "0" );
pNewWord->format.spaces = pStart->format.spaces;
}
}
else
fprintf( stderr, "%s(%d): defined used with no parameter (last thing on line)\n"
, GetCurrentFileName(), GetCurrentLine() );
}
// okay having evaluated defined... do subst on that.
if( pNewWord )
{
PTEXT pOrigin = pStart;
pNewWord->flags |=TF_NOEXPAND;
SegSubstRange( &pStart, pEnd, pNewWord );
// already have a good idea that 0/1 will not subst...
pReset = NEXTLINE( pNewWord );
if( pOrigin == *subst )
{
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "Resetitng line begin 1\n" );
}
*subst = pNewWord;
}
}
else
{
PTEXT pOrigin = pStart;
pReset = NEXTLINE( pEnd );
SegSubstRange( &pStart, pEnd, NULL );
if( pOrigin == *subst )
{
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "Resetitng line begin 2\n" );
}
*subst = pReset;
}
}
continue;
}
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "%s(%d): Consider word: %s next: %s\n"
, GetCurrentFileName(), GetCurrentLine()
, GetText( pWord )
, GetText( NEXTLINE( pWord ) ) );
}
// mark this is the first word we're grabbing
pStart = pWord;
// just check to see if this word is anything defined
// then later get the actual define for pDefine...
// look up this symbol
pDefine = FindDefineName( pWord, IGNORE_PARAMS );
// if we found the name as a symbol...
if( pDefine && !pDefine->bUsed )
{
PTEXT pSubst = NULL, p;
PLIST pArgVals = NULL;
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "Found substitution for %s params:%p\n", GetText( pWord ), pDefine->pParams );
}
// don't use it yet....
//pDefine->bUsed = TRUE;
// does the define expect parameters?
if( pDefine->pParams )
{
INDEX i = 0;
int bVarArg = 0;
int bNoArgs = 1;
PTEXT pVal = NULL;
char *file_start;
int line_start;
file_start = GetCurrentFileName();
line_start = GetCurrentLine();
if( !NEXTLINE( pWord ) && more )
pReset = pWord = ReadLine( TRUE );
else
pWord = NEXTLINE( pWord );
if( !pWord ||
GetText( pWord )[0] != '(' )
{
if( g.flags.bAllWarnings )
fprintf( stderr, "%s(%d) Warning: No parameters for macro defined at %s(%d)\n"
, GetCurrentFileName(), GetCurrentLine()
, pDefine->pFile, pDefine->nLine
);
continue;
}
// step to the next word after the leading (
pWord = NEXTLINE( pWord );
// need to gather the parameters specified
// then find the right define result for number of paramters...
while(1)
{
int quote = 0;
int parenlevels = 0;
int escape = 0;
char *text;
while( pWord || ( more && ( pWord = ReadLine( TRUE ) ) ) )
{
// while I have a word, get the text for the word,
// if quote levels or paren levels continue collection
// or if it's not a ','
//fprintf( stddbg, " stuff... %08x %08x %s\n", pWord, GetText( pWord ), GetText( pWord ) );
text = GetText( pWord );
//fprintf( stddbg, "Consider word: %s\n", text );
if( !quote )
{
if( text[0] == '\"' || text[0] == '\'' )
quote = text[0];
if( ( text[0] == '(' )
// otherwise we can assume the paring paren is included...
&& ( GetTextSize( pWord ) == 1 ) )
{
parenlevels++;
}
else if( text[0] == ')' )
{
// last paren?
if( !parenlevels )
break;
parenlevels--;
}
else if( !parenlevels && text[0] == ',' )
{
bNoArgs = FALSE;
if( !bVarArg )
break;
}
}
// is quote
else
{
if( !escape )
{
if( text[0] == '\\' )
escape = TRUE;
else if( text[0] == quote )
quote = 0;
}
// was escape
else
// next character of course clears this
escape = FALSE;
}
{
PTEXT tmp = SegDuplicate(pWord);
pVal = SegAppend( pVal, tmp );
bNoArgs = FALSE;
}
pWord = NEXTLINE( pWord );
}
if( !pWord )
{
fprintf( stderr, "%s(%d): Error: Ran out of file data before end of macro params\n"
, GetCurrentFileName(), GetCurrentLine() );
if( quote )
{
fprintf( stderr, "%s(%d) Error: Unterminated string - out of input.\n"
, GetCurrentFileName(), GetCurrentLine() );
g.ErrorCount++;
quote = 0;
}
if( parenlevels )
{
fprintf( stderr, "%s(%d) Error: Unterminated parenthized expression - out of input.\n"
, GetCurrentFileName(), GetCurrentLine() );
g.ErrorCount++;
parenlevels = 0;
}
EmptyArgList( &pArgVals );
if( pVal )
LineRelease( pVal );
return;
}
//if( !bVarArg && text[0] == ',' )
//{
// pWord = NEXTLINE( pWord );
// if( !pWord )
// pWord = ReadLine( TRUE );
//break; // end the read/gather loop also...
//}
//}
if( GetText( pWord )[0] == ')' )
break;
if( !bVarArg )
{
if( pVal )
{
pVal->format.spaces = 0;
if( g.bDebugLog & DEBUG_SUBST )
{
PTEXT tmp = BuildLine( pVal );
fprintf( stddbg, "Adding parameter: %s\n", GetText( tmp ) );
LineRelease( tmp );
}
}
else
{
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "Adding blank(empty,NIL) parameter\n" );
}
}
//if( pVal )
//{
pDefine = AddArgument( &pArgVals, &pVal, &i, pDefine, &bVarArg );
if( !pDefine )
{
if( pVal )
LineRelease( pVal );
return;
}
if( bVarArg && pVal )
pVal = SegAppend( pVal, SegDuplicate( pWord ) );
//}
}
else
{
// otherwise we'll have already collected the var arg in pVal...
break;
}
pWord = NEXTLINE( pWord );
}
if( !bNoArgs )
{
// var args value is dangling when the above loop ends.
//if( !pDefine->bVarParams )
//{
// fprintf( stderr, "Adding var arg parameter to a macro without var args?\n" );
//}
if( pVal )
pVal->format.spaces = 0;
pDefine = AddArgument( &pArgVals, &pVal, &i, pDefine, &bVarArg );
if( !pDefine )
{
if( pVal )
LineRelease( pVal );
return;
}
if( pVal )
pDefine = AddArgument( &pArgVals, &pVal, &i, pDefine, &bVarArg );
if( pVal )
fprintf( stderr, "BLAH! Still have a parametner...\n" );
}
// hmm at this point the pDefine is auto updated as we find more arguments...
// assuming that there have been a legal ordering of macros declared....
//pDefine = FindDefineName( pDefine->pName
// , pArgVals?pArgVals->Cnt:0 );
if( ( g.bDebugLog & DEBUG_SUBST )
// could be useful to dump arguments....
&& pDefine && pDefine->pParams )
{
//PTEXT arg;
INDEX idx;
if( g.bDebugLog & DEBUG_SUBST )
fprintf( stddbg, "Macro Arguments: \n" );
if( pArgVals )
{
for( idx = 0; idx < pArgVals->Cnt; idx++ )
//FORALL( pArgVals, idx, PTEXT, arg )
{
PTEXT name = GetLink( pDefine->pParams, idx );
PTEXT full = BuildLine( (PTEXT)pArgVals->pNode[idx] );
fprintf( stddbg, "%s = %s (%p)\n"
, name?GetText( name ):"..."
, GetText( full )
, pArgVals->pNode[idx] );
LineRelease( full );
}
}
}
if( pArgVals && pDefine->pParams &&
( pArgVals->Cnt < pDefine->pParams->Cnt ) )
{
fprintf( stderr, "%s(%d): Warning: parameters to macro are short... assuming NIL parameters.\n"
, GetCurrentFileName(), GetCurrentLine() );
}
// ok now we have gathered macro parameters, and the macro
if( pDefine )
{
int MakeString = 0;
int quote = 0;
int escape = 0;
INDEX idx;
if( pArgVals )
{
for( idx = 0; idx < pArgVals->Cnt; idx++ )
{
EvalSubstitutions( (PTEXT*)(pArgVals->pNode + idx), FALSE );
}
}
// is used. now...
pDefine->bUsed = TRUE;
for( p = pDefine->pData; p; p = NEXTLINE( p ) )
{
if( !quote )
{
if( GetText( p )[0] == '\'' )
quote = '\'';
if( GetText( p )[0] == '\"' )
quote = '\"';
}
else
{
if( !escape )
{
if( GetText( p )[0] == '\\' )
escape = TRUE;
else if( GetText( p )[0] == quote )
quote = 0;
}
else
escape = 0;
}
if( quote )
{
pSubst = SegAppend( pSubst, SegDuplicate( p ) );
continue;
}
if( GetText( p )[0] == '#' )
{
MakeString++;
continue;
}
idx = FindArg( pDefine->pParams, p );
if( idx == INVALID_INDEX )
{
PTEXT seg;
if( TextIs( p, "__VA_ARGS__" ) ||
TextIs( p, "..." ) )
{
fprintf( stderr, "%s(%d): Should NEVER be here!\n", __FILE__, __LINE__ );
exit(-1);
}
seg = SegDuplicate( p );
if( MakeString == 2 )
{
if( seg )
{
PTEXT valnow = pSubst;
PTEXT newseg;
SetEnd( valnow );
// just a concatenation - make sure we put these right next to each other...
vtprintf( &g.vt, "%s%s", GetText( valnow ), GetText( seg ) );
newseg = VarTextGet( &g.vt );
newseg->format.spaces = valnow->format.spaces;
SegGrab( valnow );
if( valnow == pSubst )
pSubst = NULL;
LineRelease( valnow );
SegSubst( seg, newseg );
seg = newseg;
}
MakeString = 0;
}
else if( MakeString == 1 )
{
if( seg )
{
PTEXT tmp;
VarTextAddCharacter( &g.vt, '\"' );
tmp = VarTextEnd( &g.vt );
if( !(tmp->format.spaces = p->format.spaces ) )
tmp->format.spaces++;
vtprintf( &g.vt, "%s", GetText( seg ) );
VarTextEnd( &g.vt );
VarTextAddCharacter( &g.vt, '\"' );
LineRelease( seg );
seg = VarTextGet( &g.vt );
}
MakeString = 0;
}
else
{
if( p == pDefine->pData )
seg->format.spaces++;
}
pSubst = SegAppend( pSubst, seg );
}
else
{
PTEXT seg;
if( idx == pDefine->pParams->Cnt )
{
if( TextIs( p, "__SZ_ARGS__" ) )
seg = BuildSizeofArgs( GetLink( pArgVals, idx ) );
else
{
seg = TextDuplicate( GetLink( pArgVals, idx ) );
if( !GetLink( pArgVals, idx ) )
{
PTEXT prior = pSubst;
SetEnd( prior );
if( prior && GetText( prior )[0] == ',' )
{
SegDelete( &prior );
}
continue;
}
}
}
else
{
seg = TextDuplicate( GetLink( pArgVals, idx ) );
}
if( MakeString == 2 )
{
if( seg )
{
PTEXT valnow = pSubst;
PTEXT newseg;
SetEnd( valnow );
// just a concatenation - make sure we put these right next to each other...
vtprintf( &g.vt, "%s%s", GetText( valnow ), GetText( seg ) );
newseg = VarTextGet( &g.vt );
newseg->format.spaces = valnow->format.spaces;
SegGrab( valnow );
if( valnow == pSubst )
pSubst = NULL;
LineRelease( valnow );
SegSubst( seg, newseg );
seg = newseg;
}
/*
// don't check this for substitution
if( seg )
seg->format.spaces = 0;
*/
MakeString = 0;
}
else if( MakeString == 1 )
{
PTEXT text;
if( seg )
{
PTEXT tmp;
FixQuoting( seg );
text = BuildLine( seg );
VarTextAddCharacter( &g.vt, '\"' );
tmp = VarTextEnd( &g.vt );
if( !(tmp->format.spaces = p->format.spaces ) )
tmp->format.spaces++;
vtprintf( &g.vt, "%s", GetText( text ) );
VarTextEnd( &g.vt );
VarTextAddCharacter( &g.vt, '\"' );
LineRelease( text );
LineRelease( seg );
seg = VarTextGet( &g.vt );
}
// don't check this for substitution
MakeString = 0;
}
else
{
// seg will always be a unique thing unto itself here.
/*
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "%s(%d): Doing substitution on substituted parameter: "
, GetCurrentFileName()
, GetCurrentLine()
);
DumpSegs( seg );
fprintf( stddbg, "\n" );
}
EvalSubstitutions( &seg, ppReset );
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "%s(%d): Did substitution: "
, GetCurrentFileName()
, GetCurrentLine()
);
DumpSegs( seg );
fprintf( stddbg, "\n" );
}
*/
if( seg )
{
seg->format.spaces = p->format.spaces;
//if( p == pDefine->pData )
seg->format.spaces++;
}
// check seg itself as a symbol...
}
pSubst = SegAppend( pSubst, seg );
}
}
EmptyArgList( &pArgVals );
}
else
{
fprintf( stderr, "%s(%d): Could not match macro(%s) with specified (%zd) parameters...\n"
, GetCurrentFileName(), GetCurrentLine()
, GetText( pStart )
, pArgVals?pArgVals->Cnt:0 );
EmptyArgList( &pArgVals );
continue;
}
}
// if !define->params...
else
{
pDefine->bUsed = TRUE;
// simple case - no names, no nothing, just literatal substitue
if( pSubst = TextDuplicate( pDefine->pData ) )
{
if( g.bDebugLog & DEBUG_SUBST )
fprintf( stddbg, "First subst word: %s\n", GetText( pSubst ) );
pSubst->format.spaces = 1;
}
else
{
if( g.bDebugLog & DEBUG_SUBST )
fprintf( stddbg, "Symbol has no subst data...\n" );
}
}
if( pSubst )
{
PTEXT pOrigin = pStart;
EvalSubstitutions( &pSubst, FALSE );
pReset = NEXTLINE( pWord );
if( pReset )
pReset->format.spaces = 1;
if( pSubst )
pReset = pSubst;
SegSubstRange( &pStart, pWord, pSubst );
if( pOrigin == *subst )
{
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "Resetting line begin 3\n" );
}
*subst = pStart;
}
// while current is still marked as used, process from HERE
// forward... this will allow recursive defines to work.
/*
if( pStart == *subst )
{
if( g.bDebugLog & DEBUG_SUBST )
fprintf( stddbg, "Doing subst from start of line...\n" );
EvalSubstitutions( subst, FALSE ); // need recursion to keep defined substs from redefining...
pReset = *ppReset;
fprintf( stddbg, "Returning from doing start of line subst...\n" );
}
else
{
if( g.bDebugLog & DEBUG_SUBST )
fprintf( stddbg, "Doing subst from current start\n" );
EvalSubstitutions( &pStart, FALSE ); // need recursion to keep defined substs from redefining...
pReset = *ppReset;
fprintf( stddbg, "Returning from current spot subst...\n" );
}
*/
}
else
{
PTEXT pOrigin = pStart;
// step to the next word... substitution with NO data
// just continue on with current line.
// we will be breaking out of this loop, so this sets
// the initial condition of the next recursion path.
pReset = NEXTLINE( pWord );
if( pReset )
pReset->format.spaces = 1;
//if( ppReset )
// *ppReset = pReset;
SegSubstRange( &pStart, pWord, NULL );
if( pOrigin == *subst )
{
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "Resetitng line begin 4\n" );
}
*subst = pReset;
}
}
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "Line Now:" );
DumpSegs( *subst );
fprintf( stddbg, "\n" );
}
// release symbol just substituted.
if( pDefine )
pDefine->bUsed = FALSE;
// end if define && !used
}
else
{
pWord->flags |= TF_NOEXPAND;
}
//else if( pDefine ) // if used - perhaps we should return now and see if parent substitutions can handle this...
//{
// *ppReset = pWord;
// return;
//}
// while there's a word...
}
if( g.bDebugLog & DEBUG_SUBST )
{
fprintf( stddbg, "Done substituting....\n" );
if( !*subst )
{
fprintf( stddbg, "Resulting No content.\n" );
}
}
nSubstLevel--;
return;
}
//----------------------------------------------------------------------
void CommitDefinesToCommandLineTree( PDEF root )
{
if( root )
{
CommitDefinesToCommandLineTree( root->pLesser );
CommitDefinesToCommandLineTree( root->pSame );
CommitDefinesToCommandLineTree( root->pGreater );
root->nType = DEFINE_COMMANDLINE;
}
}
//----------------------------------------------------------------------
void CommitDefinesToCommandLine( void )
{
CommitDefinesToCommandLineTree( pDefineRoot );
}
//----------------------------------------------------------------------
//#include <windows.h>
//#include <stdio.h>
// offsetof
//#include <string.h> // memset
#ifdef _DEBUG
#define DBG_PASS , char *pFile, int nLine
#define DBG_SRC , __FILE__, __LINE__
#else
#define DBG_PASS
#define DBG_SRC
#endif
//--------------------------------------------------------------------------
PLIST CreateListEx( DBG_VOIDPASS )
{
PLIST pl;
INDEX size;
pl = AllocateEx( ( size = offsetof( LIST, pNode[0] ) ) DBG_RELAY );
MemSet( pl, 0, size );
return pl;
}
//--------------------------------------------------------------------------
PLIST DeleteListEx( PLIST *pList DBG_PASS )
{
if( pList && *pList)
{
while( LockedExchange( &((*pList)->Lock), 1 ) )
{
//Sleep(0);
}
ReleaseExx( (void**)pList DBG_RELAY );
*pList = NULL;
}
return NULL;
}
//--------------------------------------------------------------------------
PLIST ExpandListEx( PLIST *pList, size_t amount DBG_PASS )
{
PLIST pl;
INDEX size;
if( !pList )
return NULL;
if( *pList )
pl = AllocateEx( size = offsetof( LIST, pNode[(*pList)->Cnt+amount] ) DBG_RELAY );
else
pl = AllocateEx( size = offsetof( LIST, pNode[amount] ) DBG_RELAY );
// assume a locked state...
pl->Lock = TRUE;
if( *pList )
{
// copy old list to new list
/*don't include new link*/
MemCpy( pl, *pList, size - (4*amount) );
if( amount == 1 )
pl->pNode[pl->Cnt++] = NULL;
else
{
// clear the new additions to the list
MemSet( pl->pNode + pl->Cnt, 0, amount*4 );
pl->Cnt += amount;
}
// remove the old list...
ReleaseExx( (void**)pList DBG_RELAY );
*pList = NULL;
// DeleteListEx( pList DBG_RELAY ); // bypass this cause it locks the list...
}
else
{
// clear whole structure on creation...
MemSet( pl, 0, size );
// one more ( always a free )
pl->Cnt = amount;
}
*pList = pl;
return pl;
}
//--------------------------------------------------------------------------
PLIST AddLinkEx( PLIST *pList, POINTER p DBG_PASS )
{
INDEX i;
if( !pList )
return NULL;
if( *pList )
while( LockedExchange( &((*pList)->Lock), 1 ) )
{
//Sleep(0);
}
retry1:
ExpandListEx( pList, 1 DBG_RELAY );
for( i = 0; i < (*pList)->Cnt; i++ )
{
if( !(*pList)->pNode[i] )
{
(*pList)->pNode[i] = p;
break;
}
}
if( i == (*pList)->Cnt )
// pList->Cnt changes - don't test in WHILE
goto retry1;
(*pList)->Lock = 0;
// might be a NEW list...
return *pList;
}
//--------------------------------------------------------------------------
PLIST SetLinkEx( PLIST *pList, INDEX idx, POINTER p DBG_PASS )
{
INDEX sz;
if( !pList )
return NULL;
if( *pList )
while( LockedExchange( &((*pList)->Lock), 1 ) )
{
//Sleep(0);
}
if( idx == INVALID_INDEX )
// not set...
return *pList;
sz = 0;
while( !(*pList) || ( sz = (*pList)->Cnt ) <= idx )
ExpandListEx( pList, (idx - sz) + 1 DBG_RELAY );
(*pList)->pNode[idx] = p;
(*pList)->Lock = 0;
// might be a NEW list...
return *pList;
}
//--------------------------------------------------------------------------
POINTER GetLinkEx( PLIST *pList, INDEX idx )
{
// must lock the list so that it's not expanded out from under us...
POINTER p;
if( !pList || !(*pList) )
return NULL;
if( idx == INVALID_INDEX )
// not set...
return pList;
while( LockedExchange( &((*pList)->Lock), 1 ) )
{
//Sleep(0);
}
if( (*pList)->Cnt <= idx )
{
(*pList)->Lock = 0;
return NULL;
}
p = (*pList)->pNode[idx];
(*pList)->Lock = 0;
return p;
}
//--------------------------------------------------------------------------
INDEX FindLink( PLIST *pList, POINTER value )
{
INDEX i, r;
POINTER v;
r = INVALID_INDEX;
/*
while( LockedExchange( &((*pList)->Lock), 1 ) )
{
//Sleep(0);
}
*/
FORALL( (*pList), i, POINTER, v )
if( v == value )
{
r = i;
break;
}
//(*pList)->Lock = 0;
return r;
}
//--------------------------------------------------------------------------
int DeleteLinkEx( PLIST *pList, POINTER value )
{
INDEX idx;
if( !pList )
return 0;
if( !(*pList ) )
return 0;
while( LockedExchange( &((*pList)->Lock), 1 ) )
{
//Sleep(0);
}
if( ( idx = FindLink( pList, value ) ) != INVALID_INDEX )
{
(*pList)->pNode[idx] = NULL;
(*pList)->Lock = 0;
return TRUE;
}
(*pList)->Lock = 0;
return FALSE;
}
//--------------------------------------------------------------------------
PLINKSTACK CreateLinkStack( void )
{
PLINKSTACK pls;
pls = Allocate( sizeof( LINKSTACK ) );
pls->Top = 0;
pls->Cnt = 0;
return pls;
}
//--------------------------------------------------------------------------
void DeleteLinkStack( PLINKSTACK pls )
{
Release( pls );
}
//--------------------------------------------------------------------------
POINTER PeekLink( PLINKSTACK pls )
{
POINTER p = NULL;
if( pls && pls->Top )
p = pls->pNode[pls->Top-1];
return p;
}
//--------------------------------------------------------------------------
POINTER PopLink( PLINKSTACK pls )
{
POINTER p = NULL;
if( !pls )
return NULL;
if( pls->Top )
{
pls->Top--;
p = pls->pNode[pls->Top];
pls->pNode[pls->Top] = (POINTER)0x1BEDCAFE;
}
return p;
}
//--------------------------------------------------------------------------
PLINKSTACK ExpandStack( PLINKSTACK stack, size_t entries )
#define ExpandStack(s,n) ((s)=ExpandStack((s),(n)))
{
PLINKSTACK pNewStack;
if( stack )
entries += stack->Cnt;
pNewStack = Allocate( offsetof( LINKSTACK, pNode[entries] ) );
if( stack )
{
MemCpy( pNewStack->pNode, stack->pNode, stack->Cnt * sizeof(POINTER) );
pNewStack->Top = stack->Top;
Release( stack );
}
else
pNewStack->Top = 0;
pNewStack->Cnt = entries;
return pNewStack;
}
//--------------------------------------------------------------------------
#undef PushLink
PLINKSTACK PushLink( PLINKSTACK pls, POINTER p )
#define PushLink(s,p) ((s)=PushLink((s),(p)))
{
if( !pls ||
pls->Top == pls->Cnt )
{
ExpandStack( pls, 1 );
}
pls->pNode[pls->Top] = p;
pls->Top++;
return pls;
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
POINTER PopData( PDATASTACK *pds )
{
POINTER p = NULL;
if( (*pds)->Top )
{
(*pds)->Top--;
if( (*pds)->Top )
{
p = (*pds)->data + ( (*pds)->Size * ((*pds)->Top-1) );
}
}
return p;
}
//--------------------------------------------------------------------------
PDATASTACK ExpandDataStack( PDATASTACK *pds, size_t entries )
{
PDATASTACK pNewStack;
if( (*pds) )
entries += (*pds)->Cnt;
pNewStack = Allocate( sizeof( DATASTACK ) + ( (*pds)->Size * entries ) - 1 );
MemCpy( pNewStack->data, (*pds)->data, (*pds)->Cnt * (*pds)->Size );
pNewStack->Cnt = entries;
pNewStack->Size = (*pds)->Size;
pNewStack->Top = (*pds)->Top;
Release( (*pds) );
*pds = pNewStack;
return pNewStack;
}
//--------------------------------------------------------------------------
PDATASTACK PushData( PDATASTACK *pds, POINTER pdata )
{
if( pds && *pds )
{
if( (*pds)->Top == (*pds)->Cnt )
{
ExpandDataStack( pds, 1 );
}
MemCpy( (*pds)->data + ((*pds)->Top * (*pds)->Size ), pdata, (*pds)->Size );
(*pds)->Top++;
return (*pds);
}
if( pds )
return *pds;
return NULL;
}
//--------------------------------------------------------------------------
POINTER PeekDataEx( PDATASTACK *pds, int nBack )
{
POINTER p = NULL;
if( ( (int)((*pds)->Top) - nBack ) >= 0 )
p = (*pds)->data + ( (*pds)->Size * ((*pds)->Top - nBack) );
return p;
}
//--------------------------------------------------------------------------
POINTER PeekData( PDATASTACK *pds )
{
POINTER p = NULL;
if( (*pds)->Top )
p = (*pds)->data + ( (*pds)->Size * ((*pds)->Top-1) );
return p;
}
//--------------------------------------------------------------------------
PDATASTACK CreateDataStack( INDEX size )
{
PDATASTACK pds;
pds = Allocate( sizeof( DATASTACK ) );
pds->Cnt = 0;
pds->Top = 0;
pds->Size = size;
return pds;
}
//--------------------------------------------------------------------------
void DeleteDataStack( PDATASTACK *pds )
{
Release( *pds );
*pds = NULL;
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
PLINKQUEUE CreateLinkQueue( void )
{
PLINKQUEUE plq;
plq = Allocate( sizeof( LINKQUEUE ) );
plq->Top = 0;
plq->Bottom = 0;
plq->Lock = 0;
plq->Cnt = 2;
plq->pNode[0] = NULL;
// shrug
plq->pNode[1] = NULL;
return plq;
}
//--------------------------------------------------------------------------
void DeleteLinkQueueEx( PLINKQUEUE *pplq DBG_PASS )
{
if( pplq )
{
if( *pplq )
ReleaseExx( (void**)pplq DBG_RELAY );
*pplq = NULL;
}
}
//--------------------------------------------------------------------------
PLINKQUEUE ExpandLinkQueue( PLINKQUEUE *pplq, int entries )
{
PLINKQUEUE plqNew = NULL;
if( pplq )
{
PLINKQUEUE plq = *pplq;
plqNew = Allocate( offsetof( LINKQUEUE, pNode[plq->Cnt + entries] ) );
plqNew->Cnt = plq->Cnt + entries;
plqNew->Bottom = 0;
if( plq->Bottom > plq->Top )
{
size_t bottom_half;
plqNew->Top = (bottom_half = plq->Cnt - plq->Bottom ) + plq->Top;
MemCpy( plqNew->pNode, plq->pNode + plq->Bottom, sizeof(POINTER)*bottom_half );
MemCpy( plqNew->pNode + bottom_half, plq->pNode, sizeof(POINTER)*plq->Top );
}
else
{
plqNew->Top = plq->Top - plq->Bottom;
MemCpy( plqNew->pNode, plq->pNode + plq->Bottom, sizeof(POINTER)*plqNew->Top );
}
Release( plq );
}
return *pplq = plqNew;
}
//--------------------------------------------------------------------------
PLINKQUEUE EnqueLinkEx( PLINKQUEUE *pplq, POINTER link DBG_PASS )
{
INDEX tmp;
PLINKQUEUE plq;
if( !pplq )
return NULL;
if( !(*pplq) )
*pplq = CreateLinkQueue();
// this is a single threaded task... shouldn't ever end up against a lock...
while( LockedExchange( &(*pplq)->Lock, 1 ) )
{
}
plq = *pplq;
if( link )
{
tmp = plq->Top + 1;
if( tmp >= plq->Cnt )
tmp -= plq->Cnt;
// collided with self...
if( tmp == plq->Bottom )
{
plq = ExpandLinkQueue( &plq, 16 );
// should be room at the end of phsyical array....
tmp = plq->Top + 1;
}
plq->pNode[plq->Top] = link;
plq->Top = tmp;
}
*pplq = plq;
plq->Lock = 0;
return plq;
}
//--------------------------------------------------------------------------
int IsQueueEmpty( PLINKQUEUE *pplq )
{
if( !pplq || !(*pplq) ||
(*pplq)->Bottom == (*pplq)->Top )
return TRUE;
return FALSE;
}
//--------------------------------------------------------------------------
POINTER DequeLink( PLINKQUEUE *pplq )
{
POINTER p;
INDEX tmp;
if( pplq && *pplq )
while( LockedExchange( &((*pplq)->Lock), 1 ) )
{
//Sleep(0);
}
else
return NULL;
p = NULL;
if( (*pplq)->Bottom != (*pplq)->Top )
{
tmp = (*pplq)->Bottom + 1;
if( tmp >= (*pplq)->Cnt )
tmp -= (*pplq)->Cnt;
p = (*pplq)->pNode[(*pplq)->Bottom];
(*pplq)->Bottom = tmp;
}
(*pplq)->Lock = 0;
return p;
}
#include <stdarg.h>
//#include <stdio.h>
//#define RELEASE_LOG
static PTEXT last_vartext_result;
//#define STRICT_LINKING
//---------------------------------------------------------------------------
#ifdef STRICT_LINKING
PTEXT SetPriorLineEx( PTEXT seg, PTEXT newprior DBG_PASS )
{
if( seg == newprior )
{
fprintf( stderr, "ERROR! Segment is same as new prior " DBG_FILELINEFMT "\n" DBG_RELAY );
DebugBreak();
}
if( seg )
{
PTEXT test, start;
seg->Prior = newprior;
start = seg;
test = PRIORLINE( start );
while( test && test != start )
{
test = PRIORLINE( test );
}
if( test )
{
fprintf( stderr, "ERROR! Resulting link causes circularity!" DBG_FILELINEFMT "\n" DBG_RELAY );
DebugBreak();
}
test = NEXTLINE( start );
while( test && test != start )
{
test = NEXTLINE( test );
}
if( test )
{
fprintf( stderr, "ERROR! Resulting link causes circularity!" DBG_FILELINEFMT "\n" DBG_RELAY );
DebugBreak();
}
return newprior;
}
else
{
fprintf( stderr, "ERROR! Attempt to link prior to NULL " DBG_FILELINEFMT "\n" DBG_RELAY );
DebugBreak();
}
return NULL;
}
#else
PTEXT SetPriorLineEx( PTEXT seg, PTEXT newprior DBG_PASS )
{
if( seg )
{
seg->Prior = newprior;
return newprior;
}
return NULL;
}
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#ifdef STRICT_LINKING
PTEXT SetNextLineEx( PTEXT seg, PTEXT newnext DBG_PASS )
{
if( seg == newnext )
{
fprintf( stderr, "ERROR! Segment is same as new next " DBG_FILELINEFMT "\n" DBG_RELAY );
}
if( seg )
{
PTEXT test, start;
seg->Next = newnext;
start = seg;
test = NEXTLINE( start );
while( test && test != start )
{
test = NEXTLINE( test );
}
if( test )
{
fprintf( stderr, "ERROR! Resulting link causes circularity!" DBG_FILELINEFMT "\n" DBG_RELAY );
DebugBreak();
}
test = PRIORLINE( start );
while( test && test != start )
{
test = PRIORLINE( test );
}
if( test )
{
fprintf( stderr, "ERROR! Resulting link causes circularity!" DBG_FILELINEFMT "\n" DBG_RELAY );
DebugBreak();
}
return newnext;
}
else
fprintf( stderr, "ERROR! Attempt to link prior to NULL " DBG_FILELINEFMT "\n" DBG_RELAY );
return NULL;
}
#else
PTEXT SetNextLineEx( PTEXT seg, PTEXT newnext DBG_PASS )
{
if( seg )
{
seg->Next = newnext;
return newnext;
}
return NULL;
}
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
PTEXT SegCreateEx( size_t size DBG_PASS )
{
PTEXT pTemp;
// good thing [1] is already counted.
pTemp = AllocateEx( sizeof(TEXT) + size DBG_RELAY );
MemSet( pTemp, 0, sizeof(TEXT) + size );
// physical space IS one more....
pTemp->data.size = size;
return pTemp;
}
//---------------------------------------------------------------------------
PTEXT GetIndirect(PTEXT segment )
{
if( !segment )
return NULL;
if( !(segment->flags&TF_INDIRECT) )
return 0;
return (PTEXT)segment->data.size;
}
//---------------------------------------------------------------------------
char *GetTextEx( PTEXT segment )
{
if( !segment )
return NULL;
while( segment && segment->flags & TF_INDIRECT )
segment = GetIndirect( segment );
if( segment )
return segment->data.data;
return NULL;
}
//---------------------------------------------------------------------------
INDEX GetTextSize( PTEXT segment )
{
int flags;
if( !segment )
// perhaps return -1, 0xFFFFFFFF
return 0;
if( segment->flags & TF_INDIRECT )
return GetTextSize( GetIndirect( segment ) );
if( !segment->data.size )
{
flags = *(int*)&segment->flags;
if( flags & IS_DATA_FLAGS )
// is data even if is not acurate....
return 2;
}
return segment->data.size;
}
//---------------------------------------------------------------------------
int GetTextFlags( PTEXT segment )
{
if( !segment )
return 0;
if( segment->flags & TF_INDIRECT )
return GetTextFlags( GetIndirect( segment ) );
return segment->flags;
}
//---------------------------------------------------------------------------
PTEXT SegDuplicateEx( PTEXT pText DBG_PASS )
{
PTEXT t;
size_t n;
if( pText )
{
if( pText->flags & TF_INDIRECT )
{
t = SegCreateIndirect( GetIndirect( pText ) );
t->flags = pText->flags;
}
else
{
t = SegCreateEx( n = GetTextSize( pText ) DBG_RELAY );
t->format = pText->format;
t->flags = pText->flags;
MemCpy( GetText(t), GetText(pText), n );
}
t->flags &= ~(TF_STATIC);
pText = t;
}
return pText;
}
//---------------------------------------------------------------------------
PTEXT TextDuplicateEx( PTEXT pText DBG_PASS )
{
PTEXT pt;
PTEXT pDup = NULL, pNew;
pt = pText;
while( pt )
{
if( pt->flags & TF_INDIRECT )
{
pNew = SegCreateIndirectEx(
TextDuplicateEx(
GetIndirect( pt ) DBG_RELAY ) DBG_RELAY );
pNew->format = pt->format;
pNew->flags |= pt->flags&(IS_DATA_FLAGS);
pNew->flags |= TF_DEEP;
}
else
pNew = SegDuplicateEx( pt DBG_RELAY );
pDup = SegAppend( pDup, pNew );
pt = NEXTLINE( pt );
}
SetStart( pDup );
return pDup;
}
//---------------------------------------------------------------------------
PTEXT SegCreateFromTextEx( char *text DBG_PASS )
{
PTEXT pTemp;
size_t nSize;
if( text )
{
pTemp = SegCreateEx( nSize = strlen( text ) DBG_RELAY );
MemCpy( pTemp->data.data, text, nSize );
return pTemp;
}
return NULL;
}
//---------------------------------------------------------------------------
PTEXT SegCreateFromIntEx( int value DBG_PASS )
{
PTEXT pResult;
pResult = SegCreateEx( 12 DBG_RELAY);
pResult->data.size = sprintf( pResult->data.data, "%d", value );
return pResult;
}
//---------------------------------------------------------------------------
PTEXT SegCreateFromFloatEx( float value DBG_PASS )
{
PTEXT pResult;
pResult = SegCreateEx( 32 DBG_RELAY);
pResult->data.size = sprintf( pResult->data.data, "%g", value );
return pResult;
}
//---------------------------------------------------------------------------
PTEXT SegCreateIndirectEx( PTEXT pText DBG_PASS )
{
PTEXT pSeg;
// no data content for indirect...
pSeg = SegCreateEx( -1 DBG_RELAY );
pSeg->flags |= TF_INDIRECT;
/*
if( pText && !(pText->flags & TF_STATIC ) )
HoldEx( pText DBG_RELAY );
*/
pSeg->data.size = (uintptr_t)pText;
return pSeg;
}
//---------------------------------------------------------------------------
// remove leading segments.
PTEXT SegBreak(PTEXT segment)
// return leading segments! might be ORPHANED if not handled.
{
PTEXT temp;
if( !segment )
return NULL;
if( ( temp = PRIORLINE(segment) ) != NULL )
SETNEXTLINE(temp, NULL );
SETPRIORLINE( segment, NULL );
return(temp);
}
//---------------------------------------------------------------------------
PTEXT SegAppend(PTEXT source,PTEXT other)
{
PTEXT temp=source;
if( temp )
{
if( other )
{
SetEnd(temp);
SetStart( other );
SETNEXTLINE( temp, other );
SETPRIORLINE( other, temp );
}
}
else
{
// nothing was before...
source=other;
}
return(source);
}
//---------------------------------------------------------------------------
PTEXT SegAdd(PTEXT source,PTEXT other)
{
PTEXT temp=source;
if( temp )
{
if( other )
{
SetEnd(temp);
SetStart( other );
SETNEXTLINE( temp, other );
SETPRIORLINE( other, temp );
// return new addition...
return other;
}
}
else
{
// nothing was before...
source=other;
}
return(source);
}
//---------------------------------------------------------------------------
PTEXT SegExpandEx(PTEXT source, int nSize DBG_PASS)
{
PTEXT temp;
temp = SegCreateEx( ( GetTextSize( source ) + nSize ) DBG_RELAY );
if( source )
{
MemCpy( temp->data.data, source->data.data, GetTextSize( source ) );
temp->flags = source->flags;
temp->format = source->format;
SegSubst( temp, source );
SegRelease( source );
}
return temp;
}
//---------------------------------------------------------------------------
void SegReleaseEx( PTEXT seg DBG_PASS)
{
if( seg )
ReleaseExx( (void**)&seg DBG_RELAY );
}
//---------------------------------------------------------------------------
void LineReleaseEx(PTEXT *ppLine DBG_PASS )
{
PTEXT line = *ppLine;
PTEXT temp;
#ifdef RELEASE_LOG
static int levels;
#endif
if( !line )
return;
#ifdef RELEASE_LOG
levels++;
printf( "Release...%d\n ", levels);
#endif
SetStart(line);
temp = line;
while(line = temp)
{
temp=NEXTLINE(line);
if( line == last_vartext_result )
last_vartext_result = NULL;
if( !(line->flags&TF_STATIC) )
{
if( (( line->flags & (TF_INDIRECT|TF_DEEP) ) == (TF_INDIRECT|TF_DEEP) ) )
{
LineReleaseEx( (PTEXT*)&line->data.size DBG_RELAY );
}
ReleaseExx( (void**)&line DBG_RELAY );
}
else
{
//Log( "Attempt to free static text...\n" );
}
}
#ifdef RELEASE_LOG
levels--;
#endif
*ppLine = NULL;
}
//---------------------------------------------------------------------------
PTEXT SegConcatEx(PTEXT output,PTEXT input,int32_t offset,int32_t length DBG_PASS )
{
int32_t idx=0,len=0;
output=SegExpandEx(output, length DBG_RELAY);
GetText(output)[0]=0;
while (input&&idx<length)
{
if( ((int32_t)GetTextSize( input ) - offset ) < (length - idx) )
len = ((int32_t)GetTextSize( input ) - offset);
else
len = length-idx;
MemCpy( GetText(output) + idx,
GetText(input) + offset,
len );
idx += len;
offset = 0;
input=NEXTLINE(input);
}
GetText(output)[idx]=0;
return(output);
}
//---------------------------------------------------------------------------
PTEXT SegUnlink(PTEXT segment)
{
PTEXT temp;
if (segment)
{
if( ( temp = PRIORLINE(segment) ) != NULL )
SETNEXTLINE( temp, NEXTLINE(segment) );
if( ( temp = NEXTLINE(segment) ) != NULL )
SETPRIORLINE( temp, PRIORLINE(segment) );
SETPRIORLINE(segment, NULL);
SETNEXTLINE(segment, NULL);
}
return segment;
}
//---------------------------------------------------------------------------
PTEXT SegGrab( PTEXT segment )
{
SegUnlink( segment );
return segment;
}
//---------------------------------------------------------------------------
PTEXT SegDeleteEx( PTEXT *segment DBG_PASS )
{
SegGrab( *segment );
LineReleaseEx( segment DBG_RELAY );
return NULL;
}
//---------------------------------------------------------------------------
PTEXT SegInsert( PTEXT what, PTEXT before )
{
PTEXT that_start = what ,
that_end= what;
SetStart( that_start );
SetEnd( that_end );
if( before )
{
if( ( SETPRIORLINE( that_start, PRIORLINE(before) ) ) != NULL )
SETNEXTLINE( PRIORLINE(that_start), that_start );
if( ( SETNEXTLINE(that_end, before) ) != NULL )
SETPRIORLINE( NEXTLINE( that_end ), that_end );
}
return what;
}
//---------------------------------------------------------------------------
PTEXT SegSubst( PTEXT _this, PTEXT that )
{
PTEXT that_start = that ,
that_end= that;
SetStart( that_start );
SetEnd( that_end );
if( ( SETNEXTLINE(that_end, NEXTLINE(_this) ) ) != NULL )
SETPRIORLINE(NEXTLINE(that_end), that_end );
if( ( SETPRIORLINE(that_start, PRIORLINE(_this))) != NULL )
SETNEXTLINE(PRIORLINE(that_start), that_start );
SETNEXTLINE(_this, NULL );
SETPRIORLINE( _this, NULL );
return _this;
}
//---------------------------------------------------------------------------
PTEXT SegSubstRangeEx( PTEXT *pp_this, PTEXT end, PTEXT that DBG_PASS )
{
PTEXT _this = *pp_this;
PTEXT after_end = NEXTLINE( end );
if( !_this || !end )
{
fprintf( stderr, "%s(%d): returned early from segsubstrange:%p %p %p\n"
, GetCurrentFileName()
, GetCurrentLine()
, _this, end, that );
return NULL;
}
if( !that )
{
if( PRIORLINE( _this ) )
SETNEXTLINE( PRIORLINE(_this), NEXTLINE(end) );
if( NEXTLINE( end ) )
SETPRIORLINE( NEXTLINE( end ), PRIORLINE( _this ) );
}
else
{
PTEXT that_start = that ,
that_end= that;
SetStart( that_start );
SetEnd( that_end );
if( ( SETNEXTLINE( that_end, NEXTLINE(end)) ) != NULL )
SETPRIORLINE(NEXTLINE(that_end), that_end );
if( ( SETPRIORLINE( that_start, PRIORLINE(_this))) != NULL )
SETNEXTLINE(PRIORLINE(that_start), that_start );
}
SETNEXTLINE( end, NULL );
SETPRIORLINE( _this, NULL );
LineReleaseEx( pp_this DBG_RELAY );
if( that )
*pp_this = that;
else
*pp_this = after_end;
return NULL;
}
//---------------------------------------------------------------------------
PTEXT SegSplitEx( PTEXT *pLine, size_t nPos DBG_PASS)
{
// there includes the character at nPos - so all calculations
// on there are +1...
PTEXT here, there;
size_t nLen;
nLen = GetTextSize( *pLine );
if( nPos > nLen )
{
return NULL;
}
if( nPos == nLen )
return *pLine;
here = SegCreateEx( nPos DBG_RELAY );
here->flags = (*pLine)->flags;
here->format = (*pLine)->format;
there = SegCreateEx( (nLen - nPos) DBG_RELAY );
there->flags = (*pLine)->flags;
there->format = (*pLine)->format;
// pretty safe...
there->format.spaces = 0;
// pretty safe...
there->format.tabs = 0;
if( here == there )
{
fprintf( stderr, "Hmm - error in segpslit\n" );
#ifdef __LINUX__
DebugBreak();
#endif
}
MemCpy( GetText( here ), GetText( *pLine ), nPos );
if( nLen - nPos )
MemCpy( GetText( there ), GetText( *pLine ) + nPos, (nLen - nPos) );
if( PRIORLINE( *pLine ) )
SETNEXTLINE( PRIORLINE( *pLine ), here );
SETPRIORLINE( here, PRIORLINE( *pLine ) );
SETNEXTLINE( here, there );
SETPRIORLINE( there, here );
SETNEXTLINE( there, NEXTLINE( *pLine ) );
if( NEXTLINE( *pLine ) )
SETPRIORLINE( NEXTLINE( *pLine ), there );
SETNEXTLINE( *pLine, NULL );
SETPRIORLINE( *pLine, NULL );
LineRelease( *pLine );
*pLine = here;
return here;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
size_t LineLength( PTEXT pt, int bSingle )
{
int TopSingle = bSingle;
PTEXT pStack[32];
int nStack;
int skipspaces = ( PRIORLINE(pt) == NULL );
size_t length = 0;
nStack = 0;
while( pt )
{
if( !(pt->flags & ( IS_DATA_FLAGS | TF_INDIRECT)) &&
!pt->data.size
)
// full binary \r\n insertion assumed
length += 2;
else
{
if( skipspaces ) {
skipspaces = FALSE;
if( g.flags.keep_comments ) {
// not-including NULL.
length += pt->format.tabs;
// not-including NULL.
length += pt->format.spaces;
}
}
else {
// not-including NULL.
length += pt->format.tabs;
// not-including NULL.
length += pt->format.spaces;
}
if( pt->flags&TF_INDIRECT )
{
// will be restored when we get back to top seg.
bSingle = FALSE;
pStack[nStack++] = pt;
pt = GetIndirect( pt );
//if( nStack >= 32 )
// DebugBreak();
continue;
}
else
// not-including NULL.
length += GetTextSize( pt );
stack_resume: ;
}
if( bSingle )
{
bSingle = FALSE;
break;
}
pt = NEXTLINE( pt );
}
if( nStack )
{
pt = pStack[--nStack];
if( !nStack )
bSingle = TopSingle;
goto stack_resume;
}
// if( length > 60000 )
// _asm int 3;
return length;
}
//---------------------------------------------------------------------------
int levels = 0;
// attempts to build a solitary line segment from the text passed
// however, if there are color changes, or absolute position changes
// this cannot work... and it must provide multiple peices...
PTEXT BuildLineEx( PTEXT pt, int bSingle DBG_PASS )
{
char *buf;
int TopSingle = bSingle;
PTEXT pStack[32];
int nStack, spaces = 0, tabs = 0, firstadded;
int skipspaces = ( PRIORLINE(pt) == NULL );
PTEXT pOut;
uintptr_t ofs;
//DebugBreak();
{
size_t len;
len = LineLength( pt, bSingle );
if( !len )
return NULL;
pOut = SegCreateEx( len DBG_RELAY );
firstadded = TRUE;
buf = GetText( pOut );
}
ofs = 0;
nStack = 0;
while( pt )
{
if( !(pt->flags& (TF_INDIRECT|IS_DATA_FLAGS)) &&
!pt->data.size
)
{
buf[ofs++] = '\r';
buf[ofs++] = '\n';
}
else
{
if( skipspaces )
{
skipspaces = FALSE;
if( g.flags.keep_comments ) {
spaces = pt->format.tabs;
// else we cannot collapse into single line (similar to colors.)
while( spaces-- )
{
buf[ofs++] = '\t';
}
spaces = pt->format.spaces;
// else we cannot collapse into single line (similar to colors.)
while( spaces-- )
{
buf[ofs++] = ' ';
}
}
}
else
{
spaces = pt->format.tabs;
// else we cannot collapse into single line (similar to colors.)
while( spaces-- )
{
buf[ofs++] = '\t';
}
spaces = pt->format.spaces;
// else we cannot collapse into single line (similar to colors.)
while( spaces-- )
{
buf[ofs++] = ' ';
}
}
// at this point spaces before tags, and after tags
// which used to be expression level parsed are not
// reconstructed correctly...
if( pt->flags&TF_INDIRECT )
{
// will be restored when we get back to top.
bSingle = FALSE;
pStack[nStack++] = pt;
pt = GetIndirect( pt );
//if( nStack >= 32 )
// DebugBreak();
continue;
}
else
{
size_t len;
MemCpy( buf+ofs, GetText( pt ), len = GetTextSize( pt ) );
ofs += len;
}
stack_resume: ;
}
if( bSingle )
{
bSingle = FALSE;
break;
}
pt = NEXTLINE( pt );
}
if( nStack )
{
pt = pStack[--nStack];
if( !nStack )
bSingle = TopSingle;
goto stack_resume;
}
// have to return length instead of new text seg...
if( !pOut )
return (PTEXT)ofs;
// if formatting was inserted into the stream...
SetStart( pOut );
return pOut;
}
//---------------------------------------------------------------------------
int CompareStrings( PTEXT pt1, int single1
, PTEXT pt2, int single2
, int bExact )
{
while( pt1 && pt2 )
{
if( !pt1 && pt2 )
return FALSE;
if( pt1 && !pt2 )
return FALSE;
if( bExact )
{
if( !SameText( pt1, pt2 ) )
return FALSE;
}
else
{
// Like returns string compare function literal...
if( LikeText( pt1, pt2 ) )
return FALSE;
}
if( !single1 )
{
pt1 = NEXTLINE( pt1 );
if( pt1
&& !GetTextSize( pt1 ) && !(pt1->flags & IS_DATA_FLAGS))
pt1 = NULL;
}
else
pt1 = NULL;
if( !single2 )
{
pt2 = NEXTLINE( pt2 );
if( pt2 &&
!GetTextSize( pt2 ) &&
!(pt2->flags & IS_DATA_FLAGS))
pt2 = NULL;
}
else
pt2 = NULL;
}
if( !pt1 && !pt2 )
return TRUE;
return FALSE;
}
//---------------------------------------------------------------------------
#define COLLECT_LEN 32
void VarTextInitEx( PVARTEXT pvt DBG_PASS )
{
pvt->commit = NULL;
pvt->collect = SegCreateEx( COLLECT_LEN DBG_RELAY );
pvt->collect_text = GetText( pvt->collect );
pvt->collect_used = 0;
}
//---------------------------------------------------------------------------
void VarTextEmptyEx( PVARTEXT pvt DBG_PASS )
{
LineReleaseEx( &pvt->collect DBG_RELAY );
LineReleaseEx( &pvt->commit DBG_RELAY );
MemSet( pvt, 0, sizeof( VARTEXT ) );
}
//---------------------------------------------------------------------------
void VarTextAddCharacterEx( PVARTEXT pvt, char c DBG_PASS )
{
if( !pvt->collect )
VarTextInitEx( pvt DBG_RELAY );
//fprintf( stderr, "Adding character %c\n", c );
pvt->collect_text[pvt->collect_used++] = c;
if( pvt->collect_used == GetTextSize( pvt->collect ) )
{
//fprintf( stderr, "Expanding segment to make sure we have room to extend...\n" );
pvt->collect = SegExpandEx( pvt->collect, COLLECT_LEN DBG_RELAY );
pvt->collect_text = GetText( pvt->collect );
}
}
//---------------------------------------------------------------------------
PTEXT VarTextEndEx( PVARTEXT pvt DBG_PASS )
{
// otherwise ofs will be 0...
if( pvt->collect_used )
{
PTEXT segs;
segs = SegSplitEx( &pvt->collect, pvt->collect_used DBG_RELAY );
//fprintf( stderr, "Breaking collection adding... %s\n", GetText( segs ) );
// so now the remaining buffer( if any )
// is assigned to collect into.
// This results in...
pvt->collect = NEXTLINE( pvt->collect );
// used all of the line...
if( !pvt->collect )
{
//fprintf( stderr, "Starting with new buffers\n" );
pvt->collect = SegCreateEx( COLLECT_LEN DBG_RELAY );
pvt->collect_text = GetText( pvt->collect );
pvt->collect_used = 0;
}
else
{
//Log1( "Remaining buffer is %d", GetTextSize( pvt->collect ) );
SegBreak( pvt->collect );
pvt->collect_text = GetText( pvt->collect );
pvt->collect_used = 0;
}
pvt->commit = SegAppend( pvt->commit, segs );
//fprintf( stderr, "Resulting string: \'%s\' newly added vartextend\n", GetText( segs ) );
return segs;
}
if( pvt->commit )
{
//fprintf( stderr, "Resulting exsiting commit output...\n" );
return pvt->commit;
}
//fprintf( stderr, "Resulting no output... var text end\n" );
return NULL;
}
//---------------------------------------------------------------------------
PTEXT VarTextGetEx( PVARTEXT pvt DBG_PASS )
{
if( VarTextEndEx( pvt DBG_RELAY ) )
{
PTEXT result = pvt->commit;
pvt->commit = NULL;
if( last_vartext_result )
{
#ifdef __LINUX__
//if( last_vartext_result == result )
// asm( "int $3;\n" );
#endif
}
last_vartext_result = result;
return result;
}
return NULL;
}
//---------------------------------------------------------------------------
void VarTextExpandEx( PVARTEXT pvt, int size DBG_PASS)
{
pvt->collect = SegExpandEx( pvt->collect, size DBG_RELAY );
pvt->collect_text = GetText( pvt->collect );
}
//---------------------------------------------------------------------------
size_t VarTextLength( PVARTEXT pvt )
{
//Log1( "Length is : %d", pvt->collect_used );
return pvt->collect_used;
}
//---------------------------------------------------------------------------
int vtprintfEx( PVARTEXT pvt , char *format, ... )
//int vtprintfEx( PVARTEXT pvt DBG_PASS, char *format, ... )
{
//char valid_char;
va_list args;
//Log1( "vtprintf...%s", format );
va_start( args, format );
{
#if defined( __LINUX__ )
// len returns number of characters (not NUL)
int len = vsnprintf( NULL, 0, format, args );
// allocate +1 for length with NUL
// VarTextExpandEx( pvt, len+1 DBG_RELAY );
VarTextExpand( pvt, len+1 );
//Log3( "Print Length: %d into %d after %s", len, pvt->collect_used, pvt->collect_text );
// include NUL in the limit of characters able to print...
vsnprintf( pvt->collect_text + pvt->collect_used, len+1, format, args );
#elif defined( __WATCOMC__ )
int len, destlen;
do {
va_start( args, format );
len = vsnprintf( pvt->collect_text + pvt->collect_used
, destlen = GetTextSize( pvt->collect ) - pvt->collect_used
, format, args );
if( len > destlen )
VarTextExpand( pvt, len - destlen + 1 );
} while( len > destlen );
#else
#if defined( GCC ) || defined( _MSC_VER )
#define vsnprintf _vsnprintf
#endif
int len;
do {
len = vsnprintf( pvt->collect_text + pvt->collect_used
, GetTextSize( pvt->collect ) - pvt->collect_used
, format, args );
if( len < 0 )
VarTextExpand( pvt, 32 );
// VarTextExpandEx( pvt, 32 DBG_SRC );
} while( len < 0 );
//Log1( "Print Length: %d", len );
#endif
pvt->collect_used += len;
return len;
}
}
//#include <windows.h>
// FILE *
// includes text.h...
#define Collapse(towhere) SegConcat(towhere,begin,beginoffset,total)
//----------------------------------------------------------------------
char NextCharEx( PTEXT input, INDEX idx )
{
if( ( ++idx ) >= input->data.size )
{
idx -= input->data.size;
input = NEXTLINE( input );
}
if( input )
return input->data.data[idx];
return 0;
}
#define NextChar() NextCharEx( input, index )
//----------------------------------------------------------------------
static PTEXT BreakAndAddEx( char character, PTEXT outdata, VARTEXT *out, uint32_t *spaces, uint32_t *tabs )
{
PTEXT word;
if( ( word = VarTextGetEx( out DBG_SRC ) ) )
{
outdata = SegAdd( outdata, word );
word->format.spaces = (uint16_t)*spaces;
word->format.tabs = (uint16_t)*tabs;
*spaces = 0;
*tabs = 0;
VarTextAddCharacterEx( out, character DBG_SRC );
word = VarTextGetEx( out DBG_SRC );
outdata = SegAdd( outdata, word );
}
else
{
VarTextAddCharacterEx( out, character DBG_SRC );
word = VarTextGetEx( out DBG_SRC );
word->format.spaces = (uint16_t)*spaces;
word->format.tabs = (uint16_t)*tabs;
*spaces = 0;
*tabs = 0;
outdata = SegAdd( outdata, word );
}
return outdata;
}
#define BreakAndAdd(c) outdata = BreakAndAddEx( c, outdata, &out, &spaces, &tabs )
//----------------------------------------------------------------------------
// translation trigraphs.....
/*
allll occurances of the following three character sets are
replaced without regard.
??= #
??( [
??/ ??) ]
??' ^
??< {
??! |
??> }
??- ~
*/
//void junk(void ) { char test [5]; }
static union {
struct {
uint32_t bLesser : 1;
uint32_t bGreater : 1;
uint32_t bColon : 1;
uint32_t bPercent : 1;
uint32_t bQuestion1 : 1;
uint32_t bQuestion2 : 1;
};
uint32_t dw;
} flags;
#define DBG_OVERRIDE DBG_RELAY
static PTEXT OutputDanglingCharsEx( PTEXT outdata, VARTEXT *out, uint32_t *spaces, uint32_t *tabs )
#define OutputDanglingChars() outdata = OutputDanglingCharsEx( outdata, &out, &spaces, &tabs )
{
int n = 0;
if( flags.bPercent )
{
n++;
outdata = BreakAndAddEx( '%', outdata, out, spaces, tabs );
flags.bPercent = 0;
}
if( flags.bColon )
{
n++;
outdata = BreakAndAddEx( ':', outdata, out, spaces, tabs );
flags.bColon = 0;
}
if( flags.bLesser )
{
n++;
outdata = BreakAndAddEx( '<', outdata, out, spaces, tabs );
flags.bLesser = 0;
}
if( flags.bGreater )
{
n++;
outdata = BreakAndAddEx( '>', outdata, out, spaces, tabs );
flags.bGreater = 0;
}
if( flags.bQuestion2 )
{
n++;
outdata = BreakAndAddEx( '?', outdata, out, spaces, tabs );
outdata = BreakAndAddEx( '?', outdata, out, spaces, tabs );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
}
if( flags.bQuestion1 )
{
n++;
outdata = BreakAndAddEx( '?', outdata, out, spaces, tabs );
flags.bQuestion1 = 0;
}
if( n > 1 )
{
fprintf( stderr, "%s(%d): Fixed %d dangling character - perhaps misordered output\n"
, GetCurrentFileName(), GetCurrentLine()
, n
);
}
return outdata;
}
PTEXT burstEx( PTEXT input DBG_PASS )
// returns a TEXT list of parsed data
{
//#define DBG_OVERRIDE DBG_SRC
/* takes a line of input and creates a line equivalent to it, but
burst into its block peices.*/
VARTEXT out;
PTEXT outdata=(PTEXT)NULL,
word;
char *tempText;
uint32_t index;
INDEX size;
uint8_t character;
uint32_t elipses = FALSE
, spaces = 0
, tabs= 0
, escape = 0
// just used for bi-graph/tri-graph stuff...
, quote = 0;
flags.dw = 0;
// if nothing new to process- return nothing processed.
if (!input)
return((PTEXT)NULL);
VarTextInitEx( &out DBG_OVERRIDE );
// while there is data to process...
while (input)
{
// point to the data to process...
tempText = GetText(input);
size = GetTextSize(input);
if( spaces )
{
//Log( "Need to figure out - new word, new spaces? old word? new spaces?" );
//outdata = Collapse( outdata );
//outdata->format.spaces = spaces;
//spaces = 0;
//set_offset = TRUE;
}
if( input->format.spaces || input->format.tabs )
{
word = VarTextGetEx( &out DBG_OVERRIDE );
if( word )
{
word->format.spaces = (uint16_t)spaces;
word->format.tabs = (uint16_t)tabs;
spaces = 0;
tabs = 0;
outdata = SegAdd( outdata, word );
}
}
spaces += input->format.spaces;
tabs += input->format.tabs;
//Log1( "Assuming %d spaces... ", spaces );
for (index=0;(character = tempText[index]),
// while not at the
(index < size); index++)
// end of the line.
{
if( elipses && character != '.' )
{
if( VarTextEndEx( &out DBG_OVERRIDE ) )
{
PTEXT word = VarTextGetEx( &out DBG_OVERRIDE );
if( word )
{
word->format.spaces = (uint16_t)spaces;
word->format.tabs = (uint16_t)tabs;
spaces = 0;
tabs = 0;
outdata = SegAdd( outdata, word );
}
//else
// Log( "VarTextGet Failed to result." );
}
elipses = FALSE;
}
// elipses and character is . - continue
else if( elipses )
{
VarTextAddCharacterEx( &out, character DBG_OVERRIDE );
continue;
}
if( !quote )
{
if( character == '<' )
{
if( flags.bLesser )
{
BreakAndAdd( '<' );
}
else
{
OutputDanglingChars();
flags.bLesser = 1;
}
continue;
}
else if( character == '>' )
{
if( flags.bGreater )
{
BreakAndAdd( '>' );
}
else if( flags.bColon )
{
BreakAndAdd( ']' );
flags.bColon = 0;
}
else if( flags.bPercent )
{
BreakAndAdd( '}' );
flags.bPercent = 0;
}
else
{
OutputDanglingChars();
flags.bGreater = 1;
}
continue;
}
else if( character == ':' )
{
if( flags.bLesser )
{
BreakAndAdd( '[' );
flags.bLesser = 0;
}
else if( flags.bPercent )
{
BreakAndAdd( '#' );
flags.bPercent = 0;
}
else if( flags.bColon )
{
BreakAndAdd( ':' );
}
else
{
OutputDanglingChars();
flags.bColon = 1;
}
continue;
}
else if( character == '%' )
{
if( flags.bLesser )
{
BreakAndAdd( '{' );
flags.bLesser = 0;
}
else if( flags.bPercent )
{
BreakAndAdd( '%' );
}
else
{
OutputDanglingChars();
flags.bPercent = 1;
}
continue;
}
else
OutputDanglingChars();
}
else if( flags.bQuestion2 )
{
if( character == '<' )
{
BreakAndAdd( '{' );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
}
else if( character == '>' )
{
BreakAndAdd( '}' );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
}
else if( character == '=' )
{
BreakAndAdd( '#' );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
continue;
}
else if( character == '(' )
{
BreakAndAdd( '[' );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
continue;
}
else if( character == '/' )
{
BreakAndAdd( '\\' );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
continue;
}
else if( flags.bQuestion2
&& character == ')' )
{
BreakAndAdd( ']' );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
continue;
}
else if( flags.bQuestion2 &&
character == '\'' )
{
BreakAndAdd( '^' );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
continue;
}
else if( flags.bQuestion2 &&
character == '<' )
{
BreakAndAdd( '{' );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
continue;
}
else if( flags.bQuestion2 &&
character == '!' )
{
BreakAndAdd( '|' );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
continue;
}
else if( flags.bQuestion2 &&
character == '>' )
{
BreakAndAdd( '}' );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
continue;
}
else if( flags.bQuestion2 &&
character == '-' )
{
BreakAndAdd( '~' );
flags.bQuestion2 = 0;
flags.bQuestion1 = 0;
continue;
}
else if( character == '?' )
{
BreakAndAdd( '?' );
}
else
{
fprintf( stderr, "%s(%d): Error unrecognized trigraph sequence!\n"
, GetCurrentFileName()
, GetCurrentLine() );
OutputDanglingChars();
}
}
else if( g.flags.do_trigraph &&
character == '?' )
{
if( flags.bQuestion2 )
{
BreakAndAdd( '?' );
}
else if( flags.bQuestion1 )
{
flags.bQuestion2 = 1;
}
else
flags.bQuestion1 = 1;
continue;
}
else
{
OutputDanglingChars();
}
if( !quote )
{
if( character == '\'' ||
character == '\"' )
quote = character;
}
else
{
if( !escape && quote == character )
quote = 0;
else if( !escape )
if( character == '\\' )
{
escape = 1;
}
else
escape = 0;
else
escape = 0;
}
switch(character)
{
case '\n':
if( ( word = VarTextGetEx( &out DBG_OVERRIDE ) ) )
{
word->format.spaces = (uint16_t)spaces;
word->format.tabs = (uint16_t)tabs;
// fake a space next line...
spaces = 0;
// fake a space next line...
tabs = 0;
outdata = SegAdd( outdata, word );
}
// add a line-break packet
outdata = SegAdd( outdata, SegCreate( 0 ) );
break;
case ' ':
case '\t':
if( ( word = VarTextGetEx( &out DBG_OVERRIDE ) ) )
{
word->format.spaces = (uint16_t)spaces;
word->format.tabs = (uint16_t)tabs;
spaces = 0;
tabs = 0;
outdata = SegAdd( outdata, word );
}
if( character == ' ' )
spaces++;
else
tabs++;
break;
// a space space character...
case '\r':
if( ( word = VarTextGetEx( &out DBG_OVERRIDE ) ) )
{
word->format.spaces = (uint16_t)spaces;
word->format.tabs = (uint16_t)tabs;
spaces = 0;
tabs = 0;
outdata = SegAdd( outdata, word );
}
break;
// handle multiple periods grouped (elipses)
case '.':
//goto NormalPunctuation;
{
char c;
if( ( !elipses &&
( c = NextChar() ) &&
( c == '.' ) ) )
{
if( ( word = VarTextGetEx( &out DBG_OVERRIDE ) ) )
{
outdata = SegAdd( outdata, word );
word->format.spaces = (uint16_t)spaces;
word->format.tabs = (uint16_t)tabs;
spaces = 0;
tabs = 0;
}
VarTextAddCharacterEx( &out, '.' DBG_OVERRIDE );
elipses = TRUE;
break;
}
if( ( c = NextChar() ) &&
( c >= '0' && c <= '9' ) )
{
// gather together as a floating point number...
VarTextAddCharacterEx( &out, '.' DBG_OVERRIDE );
break;
}
}
// single quote bound
case '\'':
// double quote bound
case '\"':
// escape next thingy... unusable in c processor
case '\\':
// expression bounders
case '(':
case '{':
case '[':
// expression closers
case ')':
case '}':
case ']':
// work seperations flaming-long-sword
case '-':
// email addresses
case '@':
case '/':
case ',':
case ';':
case '!':
case '?':
case '=':
case '+':
case '*':
case '&':
case '|':
case '$':
case '^':
case '~':
case '#':
case '`':
BreakAndAdd( character );
break;
default:
if( elipses )
{
if( ( word = VarTextGetEx( &out DBG_OVERRIDE ) ) )
{
outdata = SegAdd( outdata, word );
word->format.spaces = (uint16_t)spaces;
word->format.tabs = (uint16_t)tabs;
spaces = 0;
tabs = 0;
}
elipses = FALSE;
}
VarTextAddCharacterEx( &out, character DBG_OVERRIDE );
break;
}
}
input=NEXTLINE(input);
}
if( flags.bPercent )
{
BreakAndAdd( '%' );
flags.bPercent = 0;
}
if( flags.bColon )
{
BreakAndAdd( ':' );
flags.bColon = 0;
}
if( flags.bLesser )
{
BreakAndAdd( '<' );
flags.bLesser = 0;
}
if( flags.bGreater )
{
BreakAndAdd( '>' );
flags.bGreater = 0;
}
if( flags.bQuestion2 )
{
BreakAndAdd( '?' );
flags.bQuestion2 = 0;
}
if( flags.bQuestion1 )
{
BreakAndAdd( '?' );
flags.bQuestion1 = 0;
}
// any generic outstanding data?
if( ( word = VarTextGetEx( &out DBG_OVERRIDE ) ) )
{
outdata = SegAdd( outdata, word );
word->format.spaces = (uint16_t)spaces;
word->format.tabs = (uint16_t)tabs;
spaces = 0;
tabs = 0;
}
SetStart(outdata);
VarTextEmptyEx( &out DBG_OVERRIDE );
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "Returning segments:" );
DumpSegs( outdata );
fprintf( stddbg, "\n" );
}
return(outdata);
}
PTEXT get_line(FILE *source, int *line)
{
// characters for workspace
#define WORKSPACE 512
PTEXT workline=(PTEXT)NULL,pNew;
uintptr_t length = 0;
if( !source )
return NULL;
do
{
LineContinues:
// create a workspace to read input from the file.
workline=SegAdd(workline,pNew=SegCreate(WORKSPACE));
//workline = pNew;
// SetEnd( workline );
// read a line of input from the file.
// if no input read.
if( !fgets( GetText(workline), WORKSPACE, source) )
{
// if we've read some.
if (PRIORLINE(workline))
{
PTEXT t;
// go back one.
t=PRIORLINE(workline);
SegBreak(workline);
// destroy the current segment.
LineRelease(workline);
workline = t;
}
else
{
// destory only segment.
LineRelease(workline);
workline = NULL;
}
// get out of the loop- there is no more to read.
break;
}
{
// this section of code shall map character trigraphs into a single
// character... this preprocessor should/shall be unicode in nature
// the FUTURE man not the past!
}
// get the length of the line.
length = strlen(GetText(workline));
if( workline )
workline->data.size = length;
}
//while not at the end of the line.
while (GetText(workline)[length-1]!='\n');
if( length > 2 )
{
// auto drop \r from \r\n ...
// since Linux refuses to be kind to dumb animals...
if( GetText(workline)[length-2] == '\r' )
{
GetText(workline)[length-2] = GetText(workline)[length-1];
length--;
}
}
(*line)++;
if( workline && (GetText(workline)[length-1]=='\n' ) )
{
if( length > 1 && GetText(workline)[length-2] == '\\' )
{
workline->data.data[length-2] = 0;
workline->data.size = length-2;
goto LineContinues;
}
else
{
// consider the possibility of ignoring whitespace between a \ \n
// this will ease some effort on editing to kill end of line spaces...
// but as of yet is non standard - and is non comilant to iso9899:1999
workline->data.data[length-1] = 0;
workline->data.size = length-1;
}
}
// if I got a line, and there was some length to it.
if (workline)
// set workline to the beginning.
SetStart(workline);
// return the line read from the file.
return(workline);
}
#include <errno.h>
//----------------------------------------------------------------------
// all files in Root->pAlso are top level dependancies.
static PFILEDEP FileDependancyRoot;
void FixSlashes( char *path )
{
if( g.flags.bForceForeslash )
{
while( path[0] )
{
if( path[0] == '\\' )
path[0] = '/';
path++;
}
}
else if( g.flags.bForceBackslash )
{
while( path[0] )
{
if( path[0] == '/' )
path[0] = '\\';
path++;
}
}
}
//----------------------------------------------------------------------
int CurrentFileDepth( void )
{
int n = 0;
PFILETRACK pft;
for( pft = g.pFileStack; pft; n++, pft = pft->prior );
return n;
}
//----------------------------------------------------------------------
void SetCurrentPath( char *path )
{
strcpy( g.pCurrentPath.data.data, path );
g.pCurrentPath.data.size = strlen( path );
}
//----------------------------------------------------------------------
PFILEDEP FindDependFile( PFILEDEP root, char *filename )
{
PFILEDEP pDep = root, next;
while( pDep )
{
next = pDep->pAlso;
if( (!strcmp( pDep->base_name, filename )) ||
( pDep = FindDependFile( pDep->pDependsOn, filename ) ) )
{
return pDep;
}
pDep = next;
}
return NULL;
}
//----------------------------------------------------------------------
LOGICAL AlreadyLoaded( char *filename )
{
PFILEDEP dep;
if( dep = FindDependFile( FileDependancyRoot, filename ) ) {
if( dep->bAllowMultipleInclude )
return FALSE;
return TRUE;
}
return FALSE;
}
//----------------------------------------------------------------------
PFILEDEP AddDepend( PFILEDEP root, char *basename, char *filename )
{
PFILEDEP pfd = root;
if( !root )
root = FileDependancyRoot;
//fprintf( stderr, "Adding dependancy for: %s %s\n", root?root->full_name:"Base File", filename );
while( pfd && pfd->pDependedBy )
pfd = pfd->pDependedBy;
if( !( pfd = FindDependFile( pfd, basename ) ) )
{
pfd = Allocate( sizeof( FILEDEP ) );
strcpy( pfd->base_name, basename );
strcpy( pfd->full_name, filename );
pfd->bAllowMultipleInclude = FALSE;
pfd->pAlso = NULL;
pfd->pDependsOn = NULL;
pfd->pDependedBy = NULL;
if( root )
{
// this file is included by what?
pfd->pDependedBy = root;
// link this as another file depended file of root...
pfd->pAlso = root->pDependsOn;
root->pDependsOn = pfd;
}
else
{
pfd->pAlso = FileDependancyRoot;
FileDependancyRoot = pfd;
}
{
PFILEDEP pCheck = pfd->pDependedBy;
int count = 1;
while( pCheck )
{
if( strcmp( pCheck->full_name, pfd->full_name ) == 0 )
{
fprintf( stderr, "Check name matched...\n" );
count++;
if( count > 3 )
{
PFILEDEP pDump = pfd->pDependedBy;
fprintf( stderr, "Possible header recursion: \'%s\'", pfd->full_name );
while( pDump && pDump != pCheck )
{
fprintf( stderr, " included by \'%s\'", pDump->full_name );
pDump = pDump->pDependedBy;
}
fprintf( stderr, "\n" );
fprintf( stderr, "Aborting processing.\n" );
exit(0);
}
}
pCheck = pCheck->pDependedBy;
}
}
return pfd;
}
return pfd;
}
//----------------------------------------------------------------------
PFILEDEP AddFileDepend( PFILETRACK pft, char *basename, char *filename ) {
return AddDepend( pft->pFileDep, basename, filename );
}
//----------------------------------------------------------------------
void DumpDependLevel( PFILEDEP pfd, int level )
{
PFILEDEP pDep = pfd->pDependsOn;
if( pDep )
{
if( !level && g.AutoTargetName[0] && !pfd->pDependedBy )
{
fprintf( g.AutoDependFile, "%s:%s ", g.AutoTargetName, pfd->full_name );
}
//else if( level )
// fprintf( g.AutoDependFile, "%s ", pfd->name );
//fprintf( g.AutoDependFile, "%s:", pfd->name );
while( pDep )
{
fprintf( g.AutoDependFile, "%s ", pDep->full_name );
pDep = pDep->pAlso;
}
// for all files which this one depended on,
// dump the files those depend on...
pDep = pfd->pDependsOn;
while( pDep )
{
if( pDep->pDependsOn )
DumpDependLevel( pDep, ++level );
pDep = pDep->pAlso;
}
//fprintf( g.AutoDependFile, "\n" );
}
}
//----------------------------------------------------------------------
void DumpDepends( void )
{
int level = 0;
// trace through root files....
PFILEDEP pfd = FileDependancyRoot;
if( !g.AutoDependFile )
g.AutoDependFile = stdout;
while( pfd )
{
// post increment to make sure we start at 0...
DumpDependLevel( pfd, level++ );
pfd = pfd->pAlso;
}
fprintf( g.AutoDependFile, "\n" );
}
//----------------------------------------------------------------------
void DestroyDependLevel( PFILEDEP pfd )
{
PFILEDEP pDep = pfd->pDependsOn, next;
//if( pfd )
// fprintf( stderr, "destory level...%s \n", pfd->name );
if( pDep )
{
//pDep = pfd->pDependsOn;
while( pDep )
{
next = pDep->pAlso;
DestroyDependLevel( pDep );
pDep = next;
}
}
if( pfd )
Release( pfd );
}
//----------------------------------------------------------------------
void DestoyDepends( void )
{
PFILEDEP pfd = FileDependancyRoot, next;
while( pfd )
{
next = pfd->pAlso;
DestroyDependLevel( pfd );
pfd = next;
}
FileDependancyRoot = NULL;
}
//----------------------------------------------------------------------
int GetCurrentLine( void )
{
if( g.pFileStack )
return g.pFileStack->nLine;
return 0;
}
//----------------------------------------------------------------------
char *GetCurrentFileName( void )
{
if( g.pFileStack )
return g.pFileStack->longname;
return "<Command Line>";
//return NULL;
}
//----------------------------------------------------------------------
char *FixName( char *file )
{
static char realname[__MAX_PATH__];
if( file[0] != '/' && file[1] != ':' )
snprintf( realname, __MAX_PATH__, "%s/%s", g.pWorkPath, file );
else
strcpy( realname, file );
{
char *tmp;
while( tmp = strstr( realname, ".." ) ) {
if( tmp == realname ) {
break;
}
if( tmp[-1] == '/' || tmp[-1] == '\\' ) {
char *start;
tmp[-1] = 0;
start = pathrchr( realname );
{ int n; for( n = 0; start[n] = tmp[2+n]; n++ ); }
}
}
}
//printf( "file %s becomes %s\n", file, realname );
return realname;
}
//----------------------------------------------------------------------
char *GetCurrentShortFileName( void )
{
if( g.pFileStack )
return g.pFileStack->name;
return NULL;
}
//----------------------------------------------------------------------
void GetCurrentFileLine( char *name, int *line )
{
if( name )
strcpy( name, GetCurrentFileName() );
if( line )
*line = GetCurrentLine();
}
//----------------------------------------------------------------------
void WriteLineInfo( char *name, int line )
{
FILE *out = GetCurrentOutput();
static char LastFileWritten[__MAX_PATH__];
static int LastLineWritten;
if( out )
{
LastLineWritten++;
// not match
if( strcmp( name, LastFileWritten ) ||
line != LastLineWritten )
{
strcpy( LastFileWritten, GetCurrentFileName() );
LastLineWritten = line;
if( g.flags.bWriteLineInfo )
{
if( g.flags.bLineUsesLineKeyword )
{
fprintf( out, "#line %d \"%s\"\n"
//"//line %s(%d)\n"
, LastLineWritten
, LastFileWritten
);
}
else
{
// gcc is wonderful, eh?
fprintf( out, "# %d \"%s\"\n"
//"//line %s(%d)\n"
, LastLineWritten
, LastFileWritten
);
}
}
}
}
}
//----------------------------------------------------------------------
void WriteCurrentLineInfo( void )
{
WriteLineInfo( GetCurrentFileName(), GetCurrentLine() );
}
//----------------------------------------------------------------------
void WriteLine( size_t len, char *line )
{
FILE *out = GetCurrentOutput();
if( out )
{
fwrite( line, len, 1, out );
fputc( '\n', out );
//fflush( out );
}
//fprintf( out, "%s\n", line );
}
//----------------------------------------------------------------------
PTEXT GetCurrentWord( void )
{
if( g.pFileStack )
return g.pFileStack->pNextWord;
return NULL;
}
//----------------------------------------------------------------------
PTEXT *GetCurrentTextLine( void )
{
if( g.pFileStack )
return &g.pFileStack->pParsed;
return NULL;
}
//----------------------------------------------------------------------
PTEXT GetNextWord( void )
{
if( g.pFileStack )
return g.pFileStack->pNextWord = NEXTLINE( g.pFileStack->pNextWord );
return NULL;
}
//----------------------------------------------------------------------
void SetCurrentWord( PTEXT word )
{
if( g.pFileStack->pParsed )
if( g.pFileStack->pNextWord == g.pFileStack->pParsed )
g.pFileStack->pParsed = word;
g.pFileStack->pNextWord = word;
}
//----------------------------------------------------------------------
FILE *GetCurrentOutput(void)
{
if( !g.flags.bNoOutput )
{
return g.output;
}
return NULL;
}
//----------------------------------------------------------------------
PTEXT StepCurrentWord( void )
{
if( g.pFileStack )
return g.pFileStack->pNextWord = NEXTLINE( g.pFileStack->pNextWord );
return NULL;
}
//----------------------------------------------------------------------
// root level open.
uintptr_t OpenInputFile( char *basename, char *file )
{
PFILETRACK pft;
FILE *fp;
char *tmp;
if( g.pFileStack )
{
fprintf( stderr, "warning: Already have a root level file open." );
}
if( AlreadyLoaded( basename ) )
{
return 0;
}
fp = fopen( tmp = FixName(file), "rt" );
if( fp )
{
pft = (PFILETRACK)Allocate( sizeof( FILETRACK ) );
pft->bBlockComment = 0;
pft->nLine = 0;
pft->file = fp;
pft->nIfLevel = g.nIfLevels;
strcpy( pft->name, file );
strcpy( pft->longname, tmp );
FixSlashes( pft->longname );
pft->line = NULL;
//pft->output = NULL;
pft->pParsed = NULL;
pft->pNextWord = NULL;
pft->prior = g.pFileStack;
//fprintf( stderr, "Add in OpenInputFile\n" );
pft->pFileDep = AddDepend( NULL, basename, tmp );
g.pFileStack = pft;
}
else
pft = NULL;
return (uintptr_t)pft;
}
//----------------------------------------------------------------------
uintptr_t OpenNewInputFile( char *basename, char *name, char *pFile, int nLine, int bDepend, int bNext )
{
PFILETRACK pft = g.pFileStack;
PFILETRACK pftNew = NULL;
FILE *fp;
char *tmp;
if( bNext )
{
PFILETRACK pftTest = g.pFileStack;
while( pftTest )
{
if( strcmp( name, pftTest->name ) == 0 )
return FALSE;
pftTest = pftTest->prior;
}
}
fp = fopen( tmp = FixName(name), "rt" );
if( fp )
{
pftNew = (PFILETRACK)Allocate( sizeof( FILETRACK ) );
pftNew->bBlockComment = 0;
pftNew->nLine = 0;
pftNew->file = fp;
pftNew->nIfLevel = g.nIfLevels;
strcpy( pftNew->name, name );
strcpy( pftNew->longname, tmp );
FixSlashes( pftNew->longname );
// move the current line to the current file... (so we can log #include?)
pftNew->line = NULL;
pftNew->pNextWord = pft->pNextWord;
pft->pNextWord = NULL;
//pftNew->output = pft->output;
pftNew->pParsed = NULL;
pftNew->pNextWord = NULL;
pftNew->prior = g.pFileStack;
if( bDepend && ( pft->pFileDep ) )
{
//fprintf( stderr, "Add in OpenNewInputFile\n" );
pftNew->pFileDep = AddDepend( pft->pFileDep, basename, tmp );
}
else
pftNew->pFileDep = NULL;
g.pFileStack = pftNew;
}
return (uintptr_t)pftNew;
}
//----------------------------------------------------------------------
uintptr_t OpenOutputFile( char *newfile )
{
//PFILETRACK pft = g.pFileStack;
//if( pft )
{
g.output = fopen( FixName( newfile ), "wb" );
if( g.output )
{
return 1;
}
}
return 0;
}
//----------------------------------------------------------------------
uintptr_t OpenStdOutputFile( void )
{
PFILETRACK pft = g.pFileStack;
if( pft )
{
g.output = stdout;
//if( pft->output )
{
return 1;
}
}
return 0;
}
//----------------------------------------------------------------------
void CloseInputFileEx( DBG_VOIDPASS )
{
PFILETRACK pft = g.pFileStack;
if( pft->nIfLevel != g.nIfLevels )
{
fprintf( stderr, "Warning: Unmatched #if/#endif in %s (%d extra #if)\n"
, pft->longname
, g.nIfLevels - pft->nIfLevel );
}
if( pft->file )
{
fclose( pft->file );
pft->file = NULL;
}
if( !pft->prior )
{
//if( pft->output )
{
//fclose( pft->output );
//pft->output = NULL;
}
}
if( pft->line )
LineRelease( pft->line );
if( pft->pParsed )
LineRelease( pft->pParsed );
pft->line = NULL;
pft->pParsed = NULL;
g.pFileStack = pft->prior;
ReleaseExx( (void**)&pft DBG_RELAY );
}
//----------------------------------------------------------------------
void CloseAllFiles( void )
{
while( g.pFileStack )
CloseInputFile();
}
//----------------------------------------------------------------------
PTEXT ReadLineEx( int Append DBG_PASS )
{
PFILETRACK pft;
PTEXT pNew;
Restart:
pft = g.pFileStack;
if( !pft )
return NULL;
do
{
int bContinue;
PTEXT current;
// loop this far when comments consume entire line...
GetNewLine:
if( pft->line && (pft->pParsed == pft->line) )
DebugBreak();
if( pft->line )
LineReleaseEx( &pft->line DBG_RELAY );
pft->line = NULL;
if( !Append && ( pft->pParsed != pft->line ) )
{
current = pft->pParsed;
do {
if( ( ( (uintptr_t)current)&0xFFFF0000) == (uintptr_t)0xDDDD0000U )
{
DebugBreak();
}
current = NEXTLINE( current );
} while( current );
if( pft->pParsed )
{
current = pft->pParsed;
LineReleaseEx( &pft->pParsed DBG_RELAY );
}
pft->pNextWord = NULL;
}
bContinue = 0;
do
{
pft->line = SegAppend( pft->line, current = get_line( pft->file, &pft->nLine ) );
if( !current )
{
if( bContinue )
{
fprintf( stderr, "%s(%d) Warning: Continuation(\\) at end of file will continue to next file...\n",
GetCurrentFileName(), GetCurrentLine() );
}
CloseInputFile();
goto Restart;
}
else
{
if( !current->format.spaces && pft->line != current )
current->format.spaces = 1;
}
if( current->data.size > 0 && current->data.data[current->data.size-1] == '\\' )
{
current->data.data[current->data.size = (current->data.size-1)] = 0;
bContinue = 1;
}
else
bContinue = 0;
}while( pft && !pft->line && !bContinue );
if( !pft || !pft->line )
{
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "Returning NULL line...\n" );
}
return NULL;
}
pNew = burst( pft->line );
// strip blank lines...
if( pNew && !GetTextSize( pNew ) )
{
if( g.bDebugLog & DEBUG_READING )
{
printf( "No content..." );
}
LineRelease( pNew );
goto GetNewLine;
}
{
PTEXT p, pStart = NULL;
// set to current quote to match ... " or '
int quote = 0;
// if(quote) and prior == '\' skip " or ' chars
int escape = 0;
int nSlash = 0;
int nStar = 0;
int nLessthan = 0;
int nGreaterthan = 0;
int nPercent = 0;
for( p = pNew; p; p = NEXTLINE( p ) )
{
char *pText;
ContinueNoIncrement:
pText = GetText( p );
if( !pft->bBlockComment )
{
if( !quote )
{
if( pText[0] == '\'' )
{
quote = '\'';
continue;
}
else if( pText[0] == '\"' )
{
quote = '\"';
continue;
}
}
}
if( quote )
{
if( !escape )
{
if( pText[0] == '\\' )
escape = 1;
else if( pText[0] == quote )
quote = 0;
}
else
escape = 0;
}
else if( pText[0] == '/' )
{
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "Have a slash...\n" );
}
// leading stars up to close...
if( nStar )
{
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "ending comment...\n" );
}
if( p->format.spaces )
{
nStar = 0;
continue;
}
nStar = 0;
if( !pft->bBlockComment )
{
// this may be the case - may also be a case of invalid paramters....
// */ is an illegal operator combination anyhow....
fprintf( stderr, "%s(%d) Warning: close block comment which was not started.\n"
, pft->name, pft->nLine );
}
pft->bBlockComment = 0;
// began on this line.... ending here also
if( pStart )
{
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "had a start of comment...\n" );
}
if( NEXTLINE( p ) )
{
p = NEXTLINE( p );
SegBreak( p );
if( g.flags.keep_comments )
{
PTEXT pOut;
pOut = BuildLineEx( pStart, FALSE DBG_SRC );
if( pOut )
{
if( g.flags.bWriteLine )
{
WriteCurrentLineInfo();
}
WriteLine( GetTextSize( pOut ), GetText( pOut ) );
LineRelease( pOut );
}
}
if( pStart != pNew )
SegAppend( SegBreak( pStart ), p );
else
{
pNew = p;
}
LineRelease( pStart );
pStart = NULL;
goto ContinueNoIncrement;
}
else
{
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "Trailing part of line was block comment...\n" );
}
// whole line is a block comment...
if( pStart == pNew )
{
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "while line In block comment..." );
}
if( g.flags.keep_comments
/*&&
( !g.flags.bSkipSystemIncludeOut && !g.flags.doing_system_file )*/
)
{
PTEXT pOut;
pOut = BuildLineEx( pNew, FALSE DBG_SRC );
if( pOut )
{
if( g.flags.bWriteLine )
{
WriteCurrentLineInfo();
}
WriteLine( GetTextSize( pOut ), GetText( pOut ) );
LineRelease( pOut );
}
}
LineRelease( pNew );
goto GetNewLine;
}
// else there is something before left...
SegBreak( pStart );
LineRelease( pStart );
// loop ends anyway...
break;
}
}
else
{
// up to this point we have been in a block comment
if( NEXTLINE( p ) )
{
p = NEXTLINE( p );
SegBreak( p );
if( g.flags.keep_comments )
{
PTEXT pOut;
pOut = BuildLineEx( pNew, FALSE DBG_SRC );
if( pOut )
{
if( g.flags.bWriteLine )
{
WriteCurrentLineInfo();
}
WriteLine( GetTextSize( pOut ), GetText( pOut ) );
LineRelease( pOut );
}
}
LineRelease( pNew );
pNew = p;
goto ContinueNoIncrement;
}
else
{
// entire line within block comment...
//printf( "in block comment... " );
if( g.flags.keep_comments )
{
PTEXT pOut;
pOut = BuildLineEx( pNew, FALSE DBG_SRC );
if( pOut )
{
if( g.flags.bWriteLine )
{
WriteCurrentLineInfo();
}
WriteLine( GetTextSize( pOut ), GetText( pOut ) );
LineRelease( pOut );
}
}
LineRelease( pNew );
goto GetNewLine;
}
}
}
if( !nSlash && !nStar &&
( !pft->bBlockComment ) )
{
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "Marking begin...\n" );
}
pStart = p;
}
else
{
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "Pending states: %s%s%s\n"
, nSlash?"nSlash ":""
, nStar?"nStar ":""
, pft->bBlockComment?"In block": "" );
}
}
if( !(pft->bBlockComment ) )
{
if( nSlash )
{
if( p->format.spaces )
{
// reset/set count...
nSlash = 1;
continue;
}
}
nSlash++;
if( nSlash >= 2 )
{
if( pStart == pNew )
{
// releasing the whole line...
//printf( "Whole line commented...\n" );
if( g.flags.keep_comments )
{
PTEXT pOut;
// throw in a newline, comments end up above the actual line
// should force a #line indicator also?
//SegAppend( pNew, SegCreate(0));
pOut = BuildLineEx( pNew, FALSE DBG_SRC );
if( pOut )
{
if( g.flags.bWriteLine )
{
WriteCurrentLineInfo();
}
WriteLine( GetTextSize( pOut ), GetText( pOut ) );
LineRelease( pOut );
}
}
// internally we keep pParsed which is what pNew is also...
// pParsed will delete pNew
//LineRelease( pNew );
goto GetNewLine;
}
SegBreak( pStart );
if( g.flags.keep_comments )
{
PTEXT pOut;
// throw in a newline, comments end up above the actual line
// should force a #line indicator also?
pOut = BuildLineEx( pStart, FALSE DBG_SRC );
if( pOut )
{
if( g.flags.bWriteLine )
{
WriteCurrentLineInfo();
}
WriteLine( GetTextSize( pOut ), GetText( pOut ) );
LineRelease( pOut );
}
}
LineRelease( pStart );
break;
}
}
}
else if( pText[0] == '*' )
{
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "found a star... was there a slash?\n" );
}
// begin block comment
if( nSlash == 1 )
{
if( p->format.spaces )
{
nSlash = 0;
// set/reset count.
nStar = 1;
continue;
}
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "okay defineatly block comment...\n" );
}
if( pft->bBlockComment )
nStar++;
else
pft->bBlockComment = TRUE;
// pStart should point to the beginning '/' already
// /*/ is not a valid comment but /**/ is.
}
else
{
if( p->format.spaces )
{
// set/reset count.
nStar = 1;
continue;
}
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "Adding another star...\n" );
}
// this is beginning of end block comment maybe
nStar++;
}
// begin block comment....
}
// character is neither a '/' or a '*'
else
{
nSlash = 0;
nStar = 0;
}
}
// fell off end of line without a close on this.
if( pft->bBlockComment )
{
if( g.bDebugLog & DEBUG_READING )
{
fprintf( stddbg, "Daning block comment - continue reading...\n" );
}
if( pStart )
{
// began a block comment, but it continues....
if( pStart == pNew )
{
//printf( "In Block comment(3)...\n" );
if( g.flags.keep_comments )
{
PTEXT pOut;
pOut = BuildLineEx( pNew, FALSE DBG_SRC );
if( pOut )
{
if( g.flags.bWriteLine )
{
WriteCurrentLineInfo();
}
WriteLine( GetTextSize( pOut ), GetText( pOut ) );
LineRelease( pOut );
}
}
LineRelease( pNew );
// this block started here and was whole line
goto GetNewLine;
}
else
{
PTEXT pOut;
SegBreak( pStart );
pOut = BuildLineEx( pNew, FALSE DBG_SRC );
if( pOut )
{
if( g.flags.bWriteLine )
{
WriteCurrentLineInfo();
}
WriteLine( GetTextSize( pOut ), GetText( pOut ) );
LineRelease( pOut );
}
LineRelease( pNew );
pNew = pStart;
}
if( !g.flags.keep_comments ) {
SegBreak( pStart );
LineRelease( pStart );
}
/*
if( g.flags.keep_comments )
{
PTEXT pOut;
pOut = BuildLineEx( pStart, FALSE DBG_SRC );
if( pOut )
{
if( g.flags.bWriteLine )
{
WriteCurrentLineInfo();
}
WriteLine( GetTextSize( pOut ), GetText( pOut ) );
LineRelease( pOut );
}
}
*/
}
else
{
//printf( "In Block comment(3)...\n" );
// ignore this line completely!
if( g.flags.keep_comments )
{
PTEXT pOut = BuildLineEx( pNew, FALSE DBG_SRC );
if( pOut )
{
if( g.flags.bWriteLine )
{
WriteCurrentLineInfo();
}
WriteLine( GetTextSize( pOut ), GetText( pOut ) );
LineRelease( pOut );
}
}
LineRelease( pNew );
goto GetNewLine;
}
}
}
}while( !pNew );
//printf( "Adding %lp to %lp\n", pNew, pft->pParsed );
pft->pParsed = SegAppend( pft->pParsed, pNew );
if( !Append )
pft->pNextWord = pNew;
if( g.bDebugLog & DEBUG_READING )
{
fprintf(stddbg, "Readline result: " );
DumpSegs( pNew );
fprintf( stddbg, "\n" );
}
return pNew;
}
char *pathrchr( char *path )
{
char *end1, *end2;
end1 = strrchr( path, '\\' );
end2 = strrchr( path, '/' );
if( end1 > end2 )
return end1;
return end2;
}
//-----------------------------------------------------------------------
char *pathchr( char *path )
{
char *end1, *end2;
end1 = strchr( path, '\\' );
end2 = strchr( path, '/' );
if( end1 && end2 )
{
if( end1 < end2 )
return end1;
return end2;
}
else if( end1 )
return end1;
else if( end2 )
return end2;
return NULL;
}
//----------------------------------------------------------------------
// Expressions parser, processor
// Limitation - handles only constant expressions
// Limitation - expects expression to be on one continuous line
// which is acceptable for the cpp layer.
//----------------------------------------------------------------------
#define C_PRE_PROCESSOR
// debug only...
typedef struct opnode {
int op;
union {
LONGEST_INT i;
LONGEST_FLT f;
PTEXT string;
struct opnode *sub;
} data;
struct opnode *left, *right;
} OPNODE, *POPNODE;
static char pHEX[] = "0123456789ABCDEF";
static char phex[] = "0123456789abcdef";
/*
Section Category Operators
7.5 Primary x.y f(x) a[x] x++ x-- new typeof checked unchecked
7.6 Unary + - ! ~ ++x --x (T)x
7.7 Multiplicative * / %
7.7 Additive + -
7.8 Shift << >>
7.9 Relational and type testing < > <= >= is as
7.9 Equality == !=
7.10 Logical AND &
7.10 Logical XOR ^
7.10 Logical OR |
7.11 Conditional AND &&
7.11 Conditional OR ||
// both of these are right-associative
7.12 Conditional ?:
7.13 Assignment = *= /= %= += -= <<= >>= &= ^= |=
*/
/*
Section Category Operators (relevant to preprocessor)
7.5 Primary a[x] // should apply to const strings
// (results in an operand anyhow)
7.6 Unary + - ! ~ // typecast? (T)x
7.7 Multiplicative * / %
7.7 Additive + -
7.8 Shift << >>
7.9 Relational and type testing < > <= >= is as
7.9 Equality == !=
7.10 Logical AND &
7.10 Logical XOR ^
7.10 Logical OR |
7.11 Conditional AND &&
7.11 Conditional OR ||
// both of these are right-associative
7.12 Conditional ?:
*/
// used to indicate prior op complete, please hang on tree
enum { OP_HANG = -1
// after hanging, please re-check current symbol
, OP_NOOP = 0
// (...)
, OP_SUBEXPRESSION
, OP_INT_OPERAND_8
, OP_INT_OPERAND_16
, OP_INT_OPERAND_32
, OP_INT_OPERAND_64
, OP_SINT_OPERAND_8
, OP_SINT_OPERAND_16
, OP_SINT_OPERAND_32
, OP_SINT_OPERAND_64
, OP_FLT_OPERAND_32
, OP_FLT_OPERAND_64
, OP_CHARACTER_STRING
, OP_CHARACTER_CONST
// = equality
, OP_SETEQUAL
// == comparison
, OP_ISEQUAL
// +
, OP_PLUS
// ++
, OP_INCREMENT
// +=
, OP_PLUSEQUAL
// -
, OP_MINUS
// --
, OP_DECREMENT
// -=
, OP_MINUSEQUAL
// *
, OP_MULTIPLY
// *=
, OP_MULTIPLYEQUAL
// %
, OP_MOD
// %=
, OP_MODEQUAL
// /
, OP_DIVIDE
// /=
, OP_DIVIDEEQUAL
// ^
, OP_XOR
// ^=
, OP_XOREQUAL
// ~
, OP_BINARYNOT
// !
, OP_LOGICALNOT
// !=
, OP_NOTEQUAL
// >
, OP_GREATER
// >>
, OP_SHIFTRIGHT
// >=
, OP_GREATEREQUAL
// >>=
, OP_SHREQUAL
// <
, OP_LESSER
// <<
, OP_SHIFTLEFT
// <=
, OP_LESSEREQUAL
// <<=
, OP_SHLEQUAL
// &
, OP_BINARYAND
// &&
, OP_LOGICALAND
// &=
, OP_ANDEQUAL
// |
, OP_BINARYOR
// ||
, OP_LOGICALOR
// |=
, OP_OREQUAL
// ?
, OP_COMPARISON
// :
, OP_ELSE_COMPARISON
, OP_COMMA
//, OP_DOT
//, OP_
};
char *fullopname[] = { "noop", "sub-expr"
// unsigned int
, "uint8_t", "uint16_t", "uint32_t", "uint64_t"
// signed int
, "int8_t", "int16_t", "int32_t", "int64_t"
// float ops
, "float", "double"
, "string", "character"
, "=", "=="
, "+", "++", "+="
, "-", "--", "-="
, "*", "*="
, "%", "%="
, "/", "/="
, "^", "^="
, "~"
, "!", "!="
, ">", ">>", ">=", ">>="
, "<", "<<", "<=", "<<="
, "&", "&&", "&="
, "|", "||", "|="
, "?", ":", ","
};
typedef struct relation RELATION, *PRELATION;
struct relation {
int thisop;
struct {
char ch;
int becomes;
}trans[16];
};
#define NUM_RELATIONS (sizeof(Relations)/sizeof(RELATION))
RELATION Relations[] = { { OP_NOOP , { { '=', OP_SETEQUAL }
, { '<', OP_LESSER }
, { '>', OP_GREATER }
, { '+', OP_PLUS }
, { '-', OP_MINUS }
, { '*', OP_MULTIPLY }
, { '/', OP_DIVIDE }
, { '%', OP_MOD }
, { '^', OP_XOR }
, { '~', OP_BINARYNOT }
, { '!', OP_LOGICALNOT }
, { '&', OP_BINARYAND }
, { '|', OP_BINARYOR }
, { '?', OP_COMPARISON }
, { ':', OP_ELSE_COMPARISON }
, { ',', OP_COMMA } } }
, { OP_SETEQUAL , { { '=', OP_ISEQUAL } } }
, { OP_PLUS , { { '+', OP_INCREMENT }
, { '=', OP_PLUSEQUAL } } }
, { OP_MINUS , { { '-', OP_DECREMENT }
, { '=', OP_MINUSEQUAL } } }
, { OP_MULTIPLY , { { '=', OP_MULTIPLYEQUAL } } }
, { OP_MOD , { { '=', OP_MODEQUAL } } }
, { OP_DIVIDE , { { '=', OP_DIVIDEEQUAL } } }
, { OP_XOR , { { '=', OP_XOREQUAL } } }
, { OP_LOGICALNOT, { { '=', OP_NOTEQUAL } } }
, { OP_GREATER , { { '>', OP_SHIFTRIGHT }
, { '=', OP_GREATEREQUAL } } }
, { OP_SHIFTRIGHT, { { '=', OP_SHREQUAL } } }
, { OP_LESSER , { { '<', OP_SHIFTLEFT }
, { '=', OP_LESSEREQUAL } } }
, { OP_SHIFTLEFT , { { '=', OP_SHLEQUAL } } }
, { OP_BINARYAND , { { '&', OP_LOGICALAND }
, { '=', OP_ANDEQUAL } } }
, { OP_BINARYOR , { { '|', OP_LOGICALOR }
, { '=', OP_OREQUAL } } }
};
//--------------------------------------------------------------------------
static POPNODE GetOpNodeEx( DBG_VOIDPASS )
#define GetOpNode() GetOpNodeEx( DBG_VOIDSRC )
{
POPNODE pOp = AllocateEx( sizeof( OPNODE ) DBG_RELAY );
memset( pOp, 0, sizeof( OPNODE ) );
pOp->op = OP_NOOP;
return pOp;
}
//--------------------------------------------------------------------------
void DestroyExpressionEx( POPNODE root DBG_PASS );
#define DestroyExpression(r) DestroyExpressionEx(r DBG_SRC )
void DestroyOpNodeEx( POPNODE node DBG_PASS )
#define DestroyOpNode(n) DestroyOpNodeEx(n DBG_SRC)
{
// delete any allocated content...
if( node->op == OP_CHARACTER_STRING )
LineRelease( node->data.string );
else if( node->op == OP_SUBEXPRESSION )
DestroyExpressionEx( node->data.sub DBG_RELAY );
if( node->left )
node->left->right = node->right;
if( node->right )
node->right->left = node->left;
ReleaseExx( (void**)&node DBG_RELAY );
}
//--------------------------------------------------------------------------
void DestroyExpressionEx( POPNODE root DBG_PASS )
{
POPNODE next;
// go to the start of the expression...
if( !root )
return;
while( root->left )
root = root->left;
next = root;
while( root = next )
{
next = root->right;
DestroyOpNodeEx( root DBG_RELAY );
}
}
//--------------------------------------------------------------------------
void ExpressionBreak( POPNODE breakbefore )
{
if( breakbefore->left )
{
breakbefore->left->right = NULL;
breakbefore->left = NULL;
}
}
//--------------------------------------------------------------------------
POPNODE SubstNodes( POPNODE _this_left, POPNODE _this_right, POPNODE that )
{
if( _this_left && _this_right && that )
{
POPNODE that_left = that;
POPNODE that_right = that;
while( that_left->left )
that_left = that_left->left;
while( that_right->right )
that_right = that_right->right;
if( _this_left->left )
_this_left->left->right = that_left;
that_left->left = _this_left->left;
_this_left->left = NULL;
if( _this_right->right )
_this_right->right->left = that_right;
that_right->right = _this_right->right;
_this_right->right = NULL;
return _this_left;
}
return NULL;
}
//--------------------------------------------------------------------------
POPNODE SubstNode( POPNODE _this, POPNODE that )
{
return SubstNodes( _this, _this, that );
}
//--------------------------------------------------------------------------
POPNODE GrabNodes( POPNODE start, POPNODE end )
{
if( start->left )
start->left->right = end->right;
if( end->right )
end->right->left = start->left;
end->right = NULL;
start->left = NULL;
return start;
}
//--------------------------------------------------------------------------
POPNODE GrabNode( POPNODE _this )
{
return GrabNodes( _this, _this );
}
//--------------------------------------------------------------------------
static int RelateOpNode( POPNODE *root, POPNODE node )
{
if( !node )
{
fprintf( stderr, "Fatal Error: cannot relate a NULL node\n" );
return 0;
}
if( !root )
{
fprintf( stderr, "Fatal error: Cannot build expression tree with NULL root.\n" );
return 0;
}
#ifdef C_PRE_PROCESSOR
switch( node->op )
{
case OP_FLT_OPERAND_32:
case OP_FLT_OPERAND_64:
case OP_SETEQUAL:
case OP_INCREMENT:
case OP_PLUSEQUAL:
case OP_DECREMENT:
case OP_MINUSEQUAL:
case OP_MULTIPLYEQUAL:
case OP_MODEQUAL:
case OP_XOREQUAL:
case OP_SHREQUAL:
case OP_SHLEQUAL:
case OP_ANDEQUAL:
case OP_OREQUAL:
fprintf( stderr, "%s(%d) Error: preprocessor expression may not use operand %s\n"
, GetCurrentFileName(), GetCurrentLine(), fullopname[ node->op ] );
DestroyOpNode( node );
return 0;
break;
}
#endif
if( !*root )
*root = node;
else
{
POPNODE last = *root;
while( last && last->right )
{
last = last->right;
}
if( last )
{
node->left = last;
last->right = node;
}
}
return 1;
}
//--------------------------------------------------------------------------
// result : 0 = okay value
// 1 = float number ?
// 2 = invalid number...
static int GetInteger( LONGEST_INT *result, int *length )
{
unsigned char *p = GetText( GetCurrentWord() );
LONGEST_INT accum = 0;
int neg = 0;
int unsigned_value = 0;
int long_value = 0;
if( p[0] >= '0' && p[0] <= '9' )
{
accum = 0;
if( p[0] == '0' && p[1] && ( p[1] == 'x' || p[1] == 'X' ) )
{
char *hexchar;
int okay = 1;
p += 2;
while( p[0] && okay )
{
if( hexchar = strchr( pHEX, p[0] ) )
{
accum *= 16;
accum += hexchar - pHEX;
}
else if( hexchar = strchr( phex, p[0] ) )
{
accum *= 16;
accum += hexchar - phex;
}
else
{
okay = 0;
if( *p == '.' )
{
fprintf( stderr, "%s(%d) Error: Hexadecimal may not be used to define a float.\n", GetCurrentFileName(), GetCurrentLine() );
// invalid number.
return 2;
}
}
p++;
}
}
else if( p[0] == '0' )
{
// octal
while( p[0] >= '0' && p[0] <= '7' )
{
accum *= 8;
accum += p[0] - '0';
p++;
}
if( p[0] == '.' )
{
return 1;
}
else if( p[0] )
{
if( p[0] < 32 )
fprintf( stderr, "%s(%d) Error: Octal constant has invalid character 0x%02x\n", GetCurrentFileName(), GetCurrentLine() , p[0] );
else
fprintf( stderr, "%s(%d) Error: Octal constant has invalid character '%c'\n", GetCurrentFileName(), GetCurrentLine() , p[0] );
return 2;
}
}
else
{
while( p[0] >= '0' && p[0] <= '9' )
{
accum *= 10;
accum += p[0] - '0';
p++;
}
if( *p == '.' )
// invalid number... should consider as float after.
return 1;
}
while( *p )
{
if( *p == 'U' || *p == 'u' )
{
if( unsigned_value )
{
fprintf( stderr, "%s(%d) Error: U or u qualifiers specifed more than once on a constant.\n", GetCurrentFileName(), GetCurrentLine() );
return 2;
}
unsigned_value = 1;
p++;
}
else if( p[0] == 'l' || p[0] == 'L' )
{
if( long_value )
{
fprintf( stderr, "%s(%d) Error: too many L or l qualifiers specifed on a constant.\n", GetCurrentFileName(), GetCurrentLine() );
return 2;
}
if( p[1] && ( p[1] == 'l' || p[1] == 'L' ) )
{
long_value = 2;
p++;
}
else
long_value = 1;
p++;
}
else
{
if( p[0] < 32 )
fprintf( stderr, "%s(%d) Error: Invalid type specification 0x%02x.\n"
, GetCurrentFileName(), GetCurrentLine(), p[1] );
else
fprintf( stderr, "%s(%d) Error: Invalid type specification '%c'.\n"
, GetCurrentFileName(), GetCurrentLine(), p[1] );
return 2;
}
}
}
if( result )
*result = accum;
if( length )
*length = long_value;
// valid result now.
return 0;
}
//--------------------------------------------------------------------------
// result 0: float value okay
// 1: invalid conversion
// this may require multiple tokens to resolve... '.' '-' '+' are all
// seperate symbols.
static int GetFloat( LONGEST_FLT *result, int *length )
{
LONGEST_FLT accum = 0;
//fprintf( stderr, "At this time 'expr.c' does not do float conversion...\n" );
return 0;
}
//--------------------------------------------------------------------------
void LogExpression( POPNODE root )
{
static int level;
level++;
while( root )
{
if( root->op == OP_SUBEXPRESSION )
{
fprintf( stderr, "( " );
LogExpression( root->data.sub );
fprintf( stderr, " )" );
}
else
{
fprintf( stderr, "(%s = %lld)", fullopname[root->op],root->data.i );
}
#ifdef __LINUX__
if( root->right )
if( root->right->left != root )
# if !defined( __ARM__ )
asm( "int $3\n" )
# endif
;
#endif
root = root->right;
}
level--;
if( !level )
fprintf( stderr, "\n" );
}
//--------------------------------------------------------------------------
// one might suppose that
// expressions are read ... left, current, right....
// and things are pushed off to the left and right of myself, and or rotated
// appropriately....
//
// NULL
// (op)+/-/##/(
//--------------------------------------------------------------------------
// expression is queued
POPNODE BuildExpression( void )
{
char *pExp;
int nLastLogical = 0;
int nResult = 0;
int quote = 0;
int overflow = 0;
POPNODE ThisOp = GetOpNode();
POPNODE branch = NULL;
PTEXT thisword;
//return 0; // force false output ... needs work on substitutions...
//if( g.bDebugLog )
//{
// fprintf( stddbg, "Build expression for: " );
// DumpSegs( GetCurrentWord() );
//}
while( ( thisword = GetCurrentWord() ) )
{
int n;
pExp = GetText( thisword );
//printf( "word: %s\n", pExp );
if( pExp[0] == '\'' )
{
if( quote == '\'' )
{
overflow = 0;
RelateOpNode( &branch, ThisOp );
ThisOp = GetOpNode();
quote = 0;
}
else if( !quote )
{
ThisOp->op = OP_CHARACTER_CONST;
quote = pExp[0];
}
StepCurrentWord();
continue;
}
else if( pExp[0] == '\"' )
{
if( quote == '\"' )
{
PTEXT tmp = BuildLine( ThisOp->data.string );
LineRelease( ThisOp->data.string );
ThisOp->data.string = tmp;
RelateOpNode( &branch, ThisOp );
ThisOp = GetOpNode();
quote = 0;
}
else if( !quote )
{
ThisOp->op = OP_CHARACTER_STRING;
quote = pExp[0];
}
StepCurrentWord();
continue;
}
if( quote )
{
if( ThisOp->op == OP_CHARACTER_STRING )
{
ThisOp->data.string =
SegAppend( ThisOp->data.string
, SegDuplicate( thisword ) );
}
else if( ThisOp->op == OP_CHARACTER_CONST )
{
int n, len = (int)GetTextSize( thisword );
for( n = 0; n < thisword->format.spaces; n++ )
{
if( !overflow &&
(ThisOp->data.i & 0xFF00000000000000LL) )
{
overflow = 1;
fprintf( stderr, "%s(%d): warning character constant overflow.\n"
, GetCurrentFileName(), GetCurrentLine() );
}
ThisOp->data.i *= 256;
ThisOp->data.i += ' ';
}
for( n = 0; n < len; n++ )
{
ThisOp->data.i *= 256;
ThisOp->data.i += pExp[n];
}
}
StepCurrentWord();
continue;
}
if( pExp[0] == '(' )
{
POPNODE subexpression;
if( ThisOp->op != OP_NOOP )
{
//if( g.bDebugLog )
//{
// fprintf( stddbg, "Adding operation: " );
// LogExpression( ThisOp );
//}
RelateOpNode( &branch, ThisOp );
ThisOp = GetOpNode();
}
StepCurrentWord();
subexpression = BuildExpression();
pExp = GetText( GetCurrentWord() );
if( pExp && pExp[0] != ')' )
{
fprintf( stderr, "(%s)%d Error: Invalid expression\n", GetCurrentFileName(), GetCurrentLine() );
DestroyExpression( branch );
DestroyOpNode( ThisOp );
return NULL;
// invalid pairing of parens in expression
}
ThisOp->op = OP_SUBEXPRESSION;
ThisOp->data.sub = subexpression;
RelateOpNode( &branch, ThisOp );
ThisOp = GetOpNode();
// pExp = GetText( GetCurrentWord() );
// on return check current token as ')'
}
else if( pExp[0] == ')' )
{
if( ThisOp->op != OP_NOOP )
{
RelateOpNode( &branch, ThisOp );
}
else
DestroyOpNode( ThisOp );
//if( g.bDebugLog )
//{
// fprintf( stddbg, "Built Expression: ") ;
// LogExpression( branch );
//}
return branch;
}
else if( ( pExp[0] >= '0' && pExp[0] <= '9' ) ||
( pExp[0] == '.' ) )
{
LONGEST_INT i;
LONGEST_FLT f;
int len;
switch( GetInteger( &i, &len ) )
{
// good integer.
case 0:
if( ThisOp->op != OP_NOOP )
{
RelateOpNode( &branch, ThisOp );
ThisOp = GetOpNode();
}
ThisOp->op = OP_INT_OPERAND_64;
ThisOp->data.i = i;
RelateOpNode( &branch, ThisOp );
ThisOp = GetOpNode();
break;
// might be a float...
case 1:
switch( GetFloat( &f, &len ) )
{
case 0:
// invalid conversion (invalid number)
case 1:
// also if preprocessor - this always must fail
DestroyExpression( branch );
DestroyOpNode( ThisOp );
//if( g.bDebugLog )
//{
// fprintf( stddbg, "Built Expression 2: ") ;
// LogExpression( branch );
//}
return branch;
}
break;
// invalid number
case 2:
break;
}
}
else if( pExp[0] == '_'
|| ( pExp[0] >= 'A' && pExp[0] <= 'Z' )
|| ( pExp[0] >= 'a' && pExp[0] <= 'z' ) )
{
// this is unsubstituted, is not a predefined thing, etc,
// therefore this is a 0.
if( quote )
{
}
else
{
if( ThisOp->op != OP_NOOP )
{
RelateOpNode( &branch, ThisOp );
ThisOp = GetOpNode();
}
ThisOp->op = OP_INT_OPERAND_64;
ThisOp->data.i = 0;
RelateOpNode( &branch, ThisOp );
ThisOp = GetOpNode();
}
}
else {
if( !thisword->format.spaces || ThisOp->op == OP_NOOP )
{
retry_this_operator:
for( n = 0; n < NUM_RELATIONS; n++ )
{
if( Relations[n].thisop == ThisOp->op )
{
int o;
for( o = 0; Relations[n].trans[o].ch; o++ )
{
if( Relations[n].trans[o].ch == pExp[0] )
{
//if( g.bDebugLog )
//{
// fprintf( stddbg, "%s becomes %s\n",
// ThisOp->op<0?"????":fullopname[ThisOp->op], fullopname[Relations[n].trans[o].becomes] );
//}
ThisOp->op = Relations[n].trans[o].becomes;
break;
}
}
if( !Relations[n].trans[o].ch )
{
//fprintf( stddbg, "Invalid expression addition\n" );
fprintf( stderr, "%s(%d): Error invalid operator: %s\n"
, GetCurrentFileName()
, GetCurrentLine()
, pExp );
// invalid expression addition....
n = NUM_RELATIONS;
}
break;
}
}
}
// spaces seperate operators.
else
n = NUM_RELATIONS;
// then this operator does not add to the prior operator...
// therefore hang the old, create the new...
// unfound
if( n == NUM_RELATIONS )
{
if( ThisOp->op != OP_NOOP )
{
RelateOpNode( &branch, ThisOp );
ThisOp = GetOpNode();
goto retry_this_operator;
}
DestroyExpression( branch );
return NULL;
}
}
StepCurrentWord();
}
//if( g.bDebugLog )
//{
// fprintf( stddbg, "Deleting: " );
// LogExpression( ThisOp );
//}
DestroyOpNode( ThisOp );
//if( g.bDebugLog )
//{
// fprintf( stddbg, "Built Expression: ") ;
// LogExpression( branch );
//}
return branch;
}
//--------------------------------------------------------------------------
POPNODE ResolveExpression( POPNODE *expr );
//--------------------------------------------------------------------------
int IsValue( POPNODE *node, int collapse_sub )
{
POPNODE temp;
if( !node )
return FALSE;
switch( (*node)->op )
{
case OP_INT_OPERAND_8:
case OP_INT_OPERAND_16:
case OP_INT_OPERAND_32:
case OP_INT_OPERAND_64:
case OP_SINT_OPERAND_8:
case OP_SINT_OPERAND_16:
case OP_SINT_OPERAND_32:
case OP_SINT_OPERAND_64:
return TRUE;
case OP_FLT_OPERAND_32:
case OP_FLT_OPERAND_64:
fprintf( stderr, "%s(%d): Floating point operand is not supported\n"
, GetCurrentFileName(), GetCurrentLine() );
return FALSE;
case OP_SUBEXPRESSION:
if( collapse_sub )
{
temp = ResolveExpression( &(*node)->data.sub );
(*node)->data.sub = NULL;
DestroyOpNode( SubstNode( *node, temp ) );
*node = temp;
}
return TRUE;
}
return FALSE;
}
//--------------------------------------------------------------------------
void ApplyBinaryNot( POPNODE node )
{
switch( node->op )
{
case OP_INT_OPERAND_8:
case OP_INT_OPERAND_16:
case OP_INT_OPERAND_32:
case OP_INT_OPERAND_64:
case OP_SINT_OPERAND_8:
case OP_SINT_OPERAND_16:
case OP_SINT_OPERAND_32:
case OP_SINT_OPERAND_64:
node->data.i = ~node->data.i;
break;
default:
fprintf( stderr, "Dunno how we got here...\n" );
}
}
//--------------------------------------------------------------------------
void ApplyLogicalNot( POPNODE node )
{
switch( node->op )
{
case OP_INT_OPERAND_8:
case OP_INT_OPERAND_16:
case OP_INT_OPERAND_32:
case OP_INT_OPERAND_64:
case OP_SINT_OPERAND_8:
case OP_SINT_OPERAND_16:
case OP_SINT_OPERAND_32:
case OP_SINT_OPERAND_64:
node->data.i = !node->data.i;
break;
default:
fprintf( stderr, "Dunno how we got here...\n" );
}
}
//--------------------------------------------------------------------------
void ApplyNegative( POPNODE node )
{
switch( node->op )
{
case OP_INT_OPERAND_8:
case OP_INT_OPERAND_16:
case OP_INT_OPERAND_32:
case OP_INT_OPERAND_64:
case OP_SINT_OPERAND_8:
case OP_SINT_OPERAND_16:
case OP_SINT_OPERAND_32:
case OP_SINT_OPERAND_64:
node->data.i = -node->data.i;
break;
default:
fprintf( stderr, "Dunno how we got here...\n" );
}
}
//--------------------------------------------------------------------------
POPNODE ApplyMultiply( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
result->data.i = node1->data.i * node2->data.i;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyDivide( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
if( node2->data.i != 0 )
result->data.i = node1->data.i * node2->data.i;
else
{
fprintf( stderr, "Right hand operator of divide is 0! - returning MAXINT\n" );
#if defined( _MSC_VER ) || defined( __WATCOMC__ )
result->data.i = 0xFFFFFFFFFFFFFFFFU;
#else
result->data.i = 0xFFFFFFFFFFFFFFFFULL;
#endif
}
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyModulus( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
result->data.i = node1->data.i % node2->data.i;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyShiftRight( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
result->data.i = node1->data.i >> node2->data.i;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyShiftLeft( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
result->data.i = node1->data.i << node2->data.i;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyGreater( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
if( node1->data.i > node2->data.i )
result->data.i = 1;
else
result->data.i = 0;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyLesser( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
if( node1->data.i < node2->data.i )
result->data.i = 1;
else
result->data.i = 0;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyGreaterEqual( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
if( node1->data.i >= node2->data.i )
result->data.i = 1;
else
result->data.i = 0;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyLesserEqual( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
if( node1->data.i <= node2->data.i )
result->data.i = 1;
else
result->data.i = 0;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyIsEqual( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
if( node1->data.i == node2->data.i )
result->data.i = 1;
else
result->data.i = 0;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyIsNotEqual( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
if( node1->data.i != node2->data.i )
result->data.i = 1;
else
result->data.i = 0;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyBinaryAnd( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
result->data.i = node1->data.i & node2->data.i;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyBinaryOr( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
result->data.i = node1->data.i | node2->data.i;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyXor( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
result->data.i = node1->data.i ^ node2->data.i;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyLogicalAnd( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
result->data.i = node1->data.i && node2->data.i;
//if( g.bDebugLog )
//{
// fprintf( stddbg, "%Ld && %Ld == %Ld\n", node1->data.i, node2->data.i, result->data.i );
//}
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyLogicalOr( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
result->data.i = node1->data.i || node2->data.i;
return result;
}
//--------------------------------------------------------------------------
POPNODE ApplyAddition( POPNODE node1, POPNODE node2 )
{
POPNODE result = GetOpNode();
result->op = OP_SINT_OPERAND_64;
result->data.i = node1->data.i + node2->data.i;
return result;
}
//--------------------------------------------------------------------------
POPNODE ResolveExpression( POPNODE *expr )
{
// find highest operand... next next next next....
POPNODE node;
node = (*expr);
//if( g.bDebugLog )
// LogExpression( node );
while( node )
{
// first loop - handle ! and ~
if( node->op == OP_SUBEXPRESSION )
{
POPNODE sub;
ResolveExpression( &node->data.sub );
SubstNode( node, sub = node->data.sub );
node->data.sub = NULL;
DestroyExpression( node );
if( node == (*expr) )
(*expr) = sub;
node = (*expr);
continue;
}
else if( node->op == OP_BINARYNOT )
{
if( !node->right )
{
fprintf( stderr, "%s(%d): Error binary not operator(~) with no right hand operand\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
return NULL;
}
{
POPNODE right = node->right;
if( IsValue( &right, TRUE ) )
{
ApplyBinaryNot( right );
DestroyOpNode( GrabNode( node ) );
if( node == (*expr) )
(*expr) = right;
node = (*expr);
}
else
{
fprintf( stderr, "%s(%d): Error binary not(~) is not followed by an integer...\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
continue;
}
else if( node->op == OP_LOGICALNOT )
{
if( !node->right )
{
fprintf( stderr, "%s(%d): Error logical not operator with no right hand operand\n"
, GetCurrentFileName(), GetCurrentLine() );
g.ErrorCount++;
return NULL;
}
{
POPNODE right = node->right;
if( IsValue( &right, TRUE ) )
{
ApplyLogicalNot( right );
DestroyOpNode( GrabNode( node ) );
if( node == (*expr) )
(*expr) = right;
node = (*expr);
}
else
{
fprintf( stderr, "%s(%d): Logical not is not followed by an integer...\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
continue;
}
else if( node->op == OP_PLUS )
{
POPNODE right = node->right;
DestroyOpNode( node );
if( node == (*expr) )
(*expr) = right;
node = (*expr);
continue;
}
else if( node->op == OP_MINUS )
{
POPNODE right = node->right;
if( IsValue( &right, TRUE ) )
{
ApplyNegative( right );
DestroyOpNode( node );
if( node == (*expr) )
(*expr) = right;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Negative operator is not followed by a value\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
return NULL;
}
}
node = node->right;
}
//if( g.bDebugLog )
// fprintf( stddbg, "Done with unary +,-,!,~,()" );
node = (*expr);
//if( g.bDebugLog )
// LogExpression(node);
while( node )
{
// Second loop handle * / %
if( node->op == OP_MULTIPLY )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyMultiply( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to multiply?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
if( node->op == OP_DIVIDE )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyDivide( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to divide?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
if( node->op == OP_MOD )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyModulus( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to mod?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
node = node->right;
}
// +/- additive operators would be next - but already done as unary.
node = (*expr);
//if( g.bDebugLog )
// LogExpression(node);
while( node )
{
// third loop handle >> <<
if( node->op == OP_SHIFTRIGHT )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyShiftRight( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to shift right?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
if( node->op == OP_SHIFTLEFT )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyShiftLeft( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to shift left?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
node = node->right;
}
node = (*expr);
while( node )
{
// 4th loop handle > < >= <= comparisons (result in 0/1)
if( node->op == OP_GREATER )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyGreater( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to greater?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
if( node->op == OP_LESSER )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyLesser( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to lesser?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
if( node->op == OP_GREATEREQUAL )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyGreaterEqual( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to greater equal?\n"
, GetCurrentFileName()
, GetCurrentLine() );
LogExpression( *expr );
g.ErrorCount++;
}
}
if( node->op == OP_LESSEREQUAL )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyLesserEqual( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Invalid operands to lesser equal?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
node = node->right;
}
node = (*expr);
//if( g.bDebugLog )
// LogExpression(node);
while( node )
{
// 5th loop handle == !=
if( node->op == OP_ISEQUAL )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyIsEqual( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to equal?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
if( node->op == OP_NOTEQUAL )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyIsNotEqual( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to not equal?\n"
, GetCurrentFileName()
, GetCurrentLine() );
LogExpression( *expr );
g.ErrorCount++;
}
}
node = node->right;
}
node = (*expr);
//if( g.bDebugLog )
// LogExpression(node);
while( node )
{
// 6th loop
if( node->op == OP_BINARYAND )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyBinaryAnd( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to not equal?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
node = node->right;
}
node = (*expr);
//if( g.bDebugLog )
// LogExpression(node);
while( node )
{
// 7th loop
if( node->op == OP_XOR )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyXor( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to not equal?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
node = node->right;
}
node = (*expr);
//if( g.bDebugLog )
// LogExpression(node);
while( node )
{
// 8th loop
if( node->op == OP_BINARYOR )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyBinaryOr( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to not equal?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
node = node->right;
}
node = (*expr);
//if( g.bDebugLog )
// LogExpression(node);
while( node )
{
// 8th loop
if( node->op == OP_LOGICALAND )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyLogicalAnd( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to not equal?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
node = node->right;
}
node = (*expr);
//if( g.bDebugLog )
// LogExpression(node);
while( node )
{
// 9th loop
if( node->op == OP_LOGICALOR )
{
POPNODE left, right;
left = node->left;
right = node->right;
if( IsValue( &left, TRUE )
&& IsValue( &right, TRUE ) )
{
POPNODE result;
result = ApplyLogicalOr( left, right );
DestroyExpression( SubstNodes( left, right, result ) );
if( (*expr) == left )
(*expr) = result;
node = (*expr);
continue;
}
else
{
fprintf( stderr, "%s(%d): Error invalid operands to not equal?\n"
, GetCurrentFileName()
, GetCurrentLine() );
g.ErrorCount++;
}
}
node = node->right;
}
node = (*expr);
while( node )
{
// and finally - add all subsequent operators...
POPNODE right;
right = node->right;
if( node && right )
{
POPNODE result;
result = ApplyAddition( node, right );
DestroyExpression( SubstNodes( node, right, result ) );
(*expr) = result;
node = (*expr);
continue;
}
node = node->right;
}
//if( g.bDebugLog )
// LogExpression(*expr);
return *expr;
}
//--------------------------------------------------------------------------
int IsValidExpression( POPNODE *ppexpr )
{
// check to see if any operands are next to any other operands...
// like 3 4 2 is not valid 3 + 4 + 2 is though
// though the processing will cause the +'s to dissappear and
// subsequently when done - any operands next to each other are
// implied +'s
POPNODE node = *ppexpr;
int prior_operand = 0;
while( node )
{
if( node->op == OP_COMMA )
{
*ppexpr = node->right;
ExpressionBreak( node->right );
DestroyExpression( node );
node = *ppexpr;
prior_operand = 0;
continue;
}
if( node->op == OP_SUBEXPRESSION )
{
if( !IsValidExpression( &node->data.sub ) )
return FALSE;
prior_operand = 1;
}
else if( IsValue( &node, FALSE ) )
{
if( prior_operand )
{
LogExpression( *ppexpr );
fprintf( stderr, "%s(%d): Multiple operands with no operator!\n"
, GetCurrentFileName(), GetCurrentLine() );
return FALSE;
}
prior_operand = 1;
}
else
prior_operand = 0;
node = node->right;
}
return TRUE;
}
//--------------------------------------------------------------------------
LONGEST_INT ProcessExpression( void )
{
POPNODE tree = BuildExpression();
if( IsValidExpression( &tree ) )
{
ResolveExpression( &tree );
if( tree->left || tree->right )
{
fprintf( stderr, "%s(%d): Expression failed to resolve completely...\n"
, GetCurrentFileName(), GetCurrentLine() );
}
{
LONGEST_INT resultval = 0;
if( tree )
{
resultval = tree->data.i;
}
DestroyExpression( tree );
return resultval;
}
}
DestroyExpression( tree );
return 0;
}
@d3x0r
Copy link
Author

d3x0r commented Apr 29, 2019

usage:  (options) <files...>
        options to include
        ------------------------------------------
         -[Ii]<path(s)>      add include path to default
         -[Ss][Ii]<path(s)>  add include path to system default
         -[Dd]<symbol>       define additional symbols
         -MF<file>           dump out auto-depend info
         -MT<file>           use (file) as name of target in depend file
         -L                  write file/line info prefixing output lines
         -l                  write file/line info prefixing output lines
                                   (without line directive)
         -K                  emit unknown pragmas into output
         -k                  do not emit unknown pragma (default)
         -c                  keep comments in output
         -p                  keep includes in output (don't output content of include)
         -f                  force / into \ in include statements with paths
         -sd                 skip define processing (if,else,etc also skippped)
         -sl                 skip logic processing (if,else,endif skippped; process defines for include subst)
         -ssio               Skip System Include Out;try to keep #includes that are missing as #include
         -F                  force \ into /
         -[Oo]<file>         specify the output filename; output filename must be set before input(s) are read
                                 -o output "process this file into output.c"
         -once               only load any include once
         -[Zz]#              debug info mode. where number is in ( 1, 2, 4 )
         @<file>              any option read from a file...
  Any option prefixed with a - will force the option off...  --c to force not keeping comments
  Option L is by default on. (line info with #line keyword)
  output default is input name substituing the last character for an i...
                  test.cpp -> test.cpi  test.c -> test.i
         examples :
                ppc source_file.c
                # the following is how to do an amalgamtion
                ppc -sd -ssio -K -c -once -Iinclude -o file_all.c file1.c file2.c file3.c
                ppc -sdssioKconce -Iinclude -o file_all.c file1.c file2.c file3.c
         -? for more help
 (startup directory)/config.ppc is read first.  It is only read once.   Usage is intended to generate
 one file at a time.   It IS possible to do -o file1.i file1.c -o file2.i file2.c but the config.ppc won't
 be read the second time.  However, symbols meant to be kept in an amalgamtion output can be define here, and
 those defines will be kept.

@d3x0r
Copy link
Author

d3x0r commented Apr 29, 2019

When I added the usage comment, it duplicated the build comment, so there was 2, then I deleted one now there's none... so here goes

Build from

is built using this batch file... SACK


@set SRCS=
@set SRCS= %SRCS%   ../../makefiles/prog/ppc/cppmain.c 
@set SRCS= %SRCS%   ../../makefiles/prog/ppc/args.c    
@set SRCS= %SRCS%   ../../makefiles/prog/ppc/mem.c     
@set SRCS= %SRCS%   ../../makefiles/prog/ppc/define.c  
@set SRCS= %SRCS%   ../../makefiles/prog/ppc/links.c   
@set SRCS= %SRCS%   ../../makefiles/prog/ppc/text.c    
@set SRCS= %SRCS%   ../../makefiles/prog/ppc/input.c   
@set SRCS= %SRCS%   ../../makefiles/prog/ppc/fileio.c  
@set SRCS= %SRCS%   ../../makefiles/prog/ppc/expr.c    

del panther_preprocessor.c

c:\tools\ppc.exe -c -K -once -ssio -sd -I../../include -p -opanther_preprocessor.c -DINCLUDE_LOGGING %SRCS%

gcc -O3 -o ppc.exe panther_preprocessor.c

echo Please Update https://gist.github.com/d3x0r/8c8ab33cd7130c3c9983e12d354ad067

Which amalgamates sources in SACK/makefiles/prog/pcc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment