Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
1186 lines
28 KiB
C++
1186 lines
28 KiB
C++
#include "StuffHeaders.hpp"
|
|
#include <GameOS\ToolOS.hpp>
|
|
#include <mbstring.h>
|
|
#define __mbschr(s,c) (char*)_mbschr((const unsigned char*)(s),(c))
|
|
#define __mbsrchr(s,c) (char*)_mbsrchr((const unsigned char*)(s),(c))
|
|
|
|
#pragma warning(push)
|
|
#include <stlport\map>
|
|
#pragma warning(pop)
|
|
|
|
#define MAX_LINE_SIZE 512
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Macro::Macro(MString *replace)
|
|
{
|
|
m_replacement = *replace;
|
|
m_inUse = false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Macro::AddValue(
|
|
void *macro_tree,
|
|
const char* name,
|
|
const char* value
|
|
)
|
|
{
|
|
Check_Pointer(macro_tree);
|
|
Check_Pointer(name);
|
|
Check_Pointer(value);
|
|
|
|
//
|
|
//----------------------------------------------------
|
|
// Create MStrings for all this, and create a new plug
|
|
//----------------------------------------------------
|
|
//
|
|
MString ms_define(name);
|
|
ms_define.ToLower();
|
|
MString ms_replace(value);
|
|
Macro *mr_new = new(g_Heap) Macro(&ms_replace);
|
|
Check_Object(mr_new);
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// See if a previous definition is there. If so, remove it
|
|
//---------------------------------------------------------
|
|
//
|
|
stlport::map<MString, Macro*> *map = (stlport::map<MString, Macro*>*)macro_tree;
|
|
stlport::map<MString, Macro*>::iterator seeker = map->find(ms_define);
|
|
if (seeker != map->end())
|
|
{
|
|
Macro *old = (*seeker).second;
|
|
Check_Object(old);
|
|
delete old;
|
|
(*seeker).second = NULL;
|
|
map->erase(seeker);
|
|
}
|
|
(*map)[ms_define] = mr_new;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Macro::ReplaceMacros(
|
|
void *macro_tree,
|
|
const char *buffer,
|
|
char *new_buf,
|
|
int new_buf_size
|
|
)
|
|
{
|
|
Check_Pointer(macro_tree);
|
|
Check_Pointer(buffer);
|
|
Check_Pointer(new_buf);
|
|
|
|
//
|
|
//----------------------------------------------------
|
|
// Copy the characters one by one until we find the $(
|
|
//----------------------------------------------------
|
|
//
|
|
stlport::map<MString, Macro*> *map = (stlport::map<MString, Macro*>*)macro_tree;
|
|
while (1)
|
|
{
|
|
while (*buffer && (*buffer != '$' || buffer[1] != '('))
|
|
{
|
|
*new_buf++ = *buffer++;
|
|
--new_buf_size;
|
|
Verify(new_buf_size > 0);
|
|
}
|
|
|
|
//
|
|
//--------------------------------------
|
|
// If we are out of buffer, search again
|
|
//--------------------------------------
|
|
//
|
|
if (!*buffer)
|
|
{
|
|
Verify(new_buf_size > 0);
|
|
*new_buf = 0;
|
|
return;
|
|
}
|
|
|
|
//
|
|
//-------------------------------
|
|
// Find the end of the macro name
|
|
//-------------------------------
|
|
//
|
|
const char *p = strchr(buffer, ')');
|
|
if (!p)
|
|
{
|
|
Verify(new_buf_size > 0);
|
|
*new_buf = '\0';
|
|
return;
|
|
}
|
|
|
|
//
|
|
//-------------------
|
|
// Isolate macro name
|
|
//-------------------
|
|
//
|
|
int len = p-buffer - 2;
|
|
MString macro_name;
|
|
macro_name.AllocateLength(len+1);
|
|
int i=0;
|
|
for (p = buffer+2; *p != ')'; ++p,++i)
|
|
{
|
|
Verify(i<len);
|
|
macro_name[i] = *p;
|
|
}
|
|
macro_name[len] = '\0';
|
|
macro_name.ToLower();
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Find it in the tree, and if it exists, copy it into the buffer. If
|
|
// not, leave the buffer alone
|
|
//--------------------------------------------------------------------
|
|
//
|
|
buffer = p+1;
|
|
stlport::map<MString, Macro*>::iterator seeker = map->find(macro_name);
|
|
if (seeker != map->end())
|
|
{
|
|
Macro *macro = (*seeker).second;
|
|
Check_Object(macro);
|
|
if (!macro->m_inUse)
|
|
{
|
|
macro->m_inUse = true;
|
|
ReplaceMacros(
|
|
macro_tree,
|
|
macro->m_replacement,
|
|
new_buf,
|
|
new_buf_size
|
|
);
|
|
len = strlen(new_buf);
|
|
new_buf_size -= len;
|
|
new_buf += len;
|
|
macro->m_inUse = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//#############################################################################
|
|
//############## NotationFile ###########################################
|
|
//#############################################################################
|
|
|
|
void *NotationFile::s_cachedIncludes = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
NotationFile::NotationFile(
|
|
const char *file_name,
|
|
Type type,
|
|
bool preserve_case
|
|
):
|
|
m_pages(NULL),
|
|
m_preserveCase(preserve_case)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Pointer(file_name);
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// See if we need to read stuff from a file
|
|
//-----------------------------------------
|
|
//
|
|
FileStream file_stream;
|
|
if (gos_DoesFileExist(file_name))
|
|
{
|
|
file_stream.Open(file_name);
|
|
m_fileName = file_stream.GetFileName();
|
|
m_fileDependencies.AddDependency(&file_stream);
|
|
}
|
|
else
|
|
m_fileName = file_name;
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Set up the file dependencies, and finish constructing the file
|
|
//---------------------------------------------------------------
|
|
//
|
|
m_type = type;
|
|
CommonConstruction(&file_stream, NULL);
|
|
|
|
//
|
|
//-----------------------------------------------------------
|
|
// Make sure that we don't allow a non-empty file to be empty
|
|
//-----------------------------------------------------------
|
|
//
|
|
if (m_type==NonEmpty && IsEmpty())
|
|
STOP(("%s is missing or empty!", file_name));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
NotationFile::NotationFile(MemoryStream *memory_stream):
|
|
m_pages(NULL),
|
|
m_preserveCase(false)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// If we were given a stream and it was a file, get the dependency and
|
|
// filename info from it
|
|
//--------------------------------------------------------------------
|
|
//
|
|
if (memory_stream)
|
|
{
|
|
Check_Object(memory_stream);
|
|
if (memory_stream->IsDerivedFrom(FileStream::DefaultData))
|
|
{
|
|
FileStream* file_stream = Cast_Object(FileStream*, memory_stream);
|
|
m_fileDependencies.AddDependency(file_stream);
|
|
m_fileName = file_stream->GetFileName();
|
|
}
|
|
}
|
|
|
|
//
|
|
//-------------------
|
|
// Finish building it
|
|
//-------------------
|
|
//
|
|
m_type = Standard;
|
|
CommonConstruction(memory_stream, NULL);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
NotationFile::NotationFile(
|
|
MemoryStream *memory_stream,
|
|
void *macro_tree
|
|
):
|
|
m_pages(NULL),
|
|
m_preserveCase(false)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// If we were given a stream and it was a file, get the dependency and
|
|
// filename info from it
|
|
//--------------------------------------------------------------------
|
|
//
|
|
if (memory_stream)
|
|
{
|
|
Check_Object(memory_stream);
|
|
if (memory_stream->IsDerivedFrom(FileStream::DefaultData))
|
|
{
|
|
FileStream* file_stream = Cast_Object(FileStream*, memory_stream);
|
|
m_fileDependencies.AddDependency(file_stream);
|
|
m_fileName = file_stream->GetFileName();
|
|
}
|
|
}
|
|
|
|
//
|
|
//-------------------
|
|
// Finish building it
|
|
//-------------------
|
|
//
|
|
m_type = Standard;
|
|
CommonConstruction(memory_stream, macro_tree);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
NotationFile::~NotationFile()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//------------------------
|
|
// Clear out the notepages
|
|
//------------------------
|
|
//
|
|
stlport::map<MString, Page*> *map = (stlport::map<MString, Page*> *)m_pageMap;
|
|
delete map;
|
|
Verify(!IsChanged());
|
|
m_pages.DeletePlugs();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NotationFile::TestInstance() const
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NotationFile::CommonConstruction(
|
|
MemoryStream *memory_stream,
|
|
void *macro_tree
|
|
)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
//
|
|
//--------------------------
|
|
// Set up our nasty stl hack
|
|
//--------------------------
|
|
//
|
|
m_pageMap = new stlport::map<Stuff::MString, Page*>;
|
|
Check_Pointer(m_pageMap);
|
|
|
|
//
|
|
//-------------------
|
|
// Read the stream in
|
|
//-------------------
|
|
//
|
|
m_concatenate = true;
|
|
if (memory_stream)
|
|
{
|
|
Check_Object(memory_stream);
|
|
Read(memory_stream, macro_tree, NULL, false);
|
|
}
|
|
m_dirtyFlag = false;
|
|
Check_Object(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NotationFile::Read(
|
|
MemoryStream *stream,
|
|
void *macro_tree,
|
|
Page **page,
|
|
bool nested
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(stream);
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// If aren't already reading a page, make a pointer to hold the info
|
|
//------------------------------------------------------------------
|
|
//
|
|
Page *temp_page = NULL;
|
|
if (!page)
|
|
page = &temp_page;
|
|
|
|
//
|
|
//------------------------------------------------
|
|
// If we don't have a macro tree yet, make one now
|
|
//------------------------------------------------
|
|
//
|
|
void *orig_tree = macro_tree;
|
|
if (!macro_tree)
|
|
macro_tree = new(g_Heap) stlport::map<MString, Macro*>;
|
|
Check_Pointer(macro_tree);
|
|
|
|
//
|
|
//--------------------------------
|
|
// Read each line till we are done
|
|
//--------------------------------
|
|
//
|
|
bool comment_mode = false;
|
|
char buffer[MAX_LINE_SIZE];
|
|
while (stream->ReadLine(buffer, sizeof(buffer)))
|
|
{
|
|
char *p;
|
|
if (*buffer == '@')
|
|
{
|
|
p = buffer;
|
|
while (*p)
|
|
{
|
|
*p = p[1];
|
|
++p;
|
|
}
|
|
p = buffer;
|
|
}
|
|
else if (!m_preserveCase)
|
|
p = strlwr(buffer);
|
|
else
|
|
p = buffer;
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// Deal with any comments - C++ style are the easiest to deal with
|
|
//----------------------------------------------------------------
|
|
//
|
|
char *comment_start = NULL;
|
|
while ((p = strchr(p, '/')) != NULL)
|
|
{
|
|
if (p[1] == '/')
|
|
break;
|
|
|
|
//
|
|
//--------------------------------------------------------------
|
|
// If we are ending a C style comment, move the memory to where
|
|
// the comment started on this line. If it didn't start on this
|
|
// line, move it to the beginning of the buffer
|
|
//--------------------------------------------------------------
|
|
//
|
|
else if (p[-1] == '*')
|
|
{
|
|
if (!comment_mode)
|
|
{
|
|
strcpy(p-1, p+1);
|
|
--p;
|
|
}
|
|
else if (!comment_start)
|
|
{
|
|
strcpy(buffer, p+1);
|
|
p = buffer;
|
|
}
|
|
else
|
|
{
|
|
strcpy(comment_start, p+1);
|
|
p = comment_start;
|
|
}
|
|
comment_start = NULL;
|
|
comment_mode = false;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------
|
|
// If we are starting a C style comment, remember where we are
|
|
//------------------------------------------------------------
|
|
//
|
|
else if (p[1] == '*')
|
|
{
|
|
comment_mode = true;
|
|
comment_start = p;
|
|
}
|
|
++p;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// If we started a comment on this line, clip the line there. If not,
|
|
// and we are within a C comment block, skip the whole line
|
|
//--------------------------------------------------------------------
|
|
//
|
|
if (comment_start)
|
|
p = comment_start;
|
|
else if (comment_mode)
|
|
continue;
|
|
|
|
//
|
|
//---------------------
|
|
// Clip off the comment
|
|
//---------------------
|
|
//
|
|
if (p)
|
|
*p = '\0';
|
|
|
|
//
|
|
//-----------------------
|
|
// Trim ending whitespace
|
|
//-----------------------
|
|
//
|
|
p = buffer + strlen(buffer) - 1;
|
|
while (p >= buffer && (*p==' ' || *p=='\t'))
|
|
*p-- = '\0';
|
|
p = buffer;
|
|
#if defined(_ARMOR)
|
|
bool macroed=false;
|
|
#endif
|
|
|
|
//
|
|
//--------------------------
|
|
// Ignore leading whitespace
|
|
//--------------------------
|
|
//
|
|
Parse:
|
|
while (*p==' ' || *p=='\t')
|
|
++p;
|
|
if(!*p)
|
|
continue;
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// If the line consists of a nested block end, handle it appropriately
|
|
//--------------------------------------------------------------------
|
|
//
|
|
if (!strcmp(p, "}"))
|
|
{
|
|
if (nested)
|
|
{
|
|
m_dirtyFlag = false;
|
|
if (!orig_tree)
|
|
{
|
|
Check_Pointer(macro_tree);
|
|
stlport::map<MString, Macro*> *map = (stlport::map<MString, Macro*>*)macro_tree;
|
|
stlport::map<MString, Macro*>::iterator seeker = map->begin();
|
|
while (seeker != map->end())
|
|
{
|
|
Macro *macro = (*seeker).second;
|
|
Check_Object(macro);
|
|
delete macro;
|
|
++seeker;
|
|
}
|
|
delete map;
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
continue;
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// If we aren't in raw mode, look for our preprocessor directives
|
|
//---------------------------------------------------------------
|
|
//
|
|
if (m_type != Raw)
|
|
{
|
|
char *q;
|
|
if (*p == '!')
|
|
HandleBangStuff(p+1, macro_tree, page);
|
|
else if(*p == '#')
|
|
HandlePoundStuff(p+1, macro_tree, page);
|
|
|
|
//
|
|
//-------------------------------------------
|
|
// Look to see if we need to deal with macros
|
|
//-------------------------------------------
|
|
//
|
|
else if((q = strchr(p, '$')) != NULL && q[1]=='(')
|
|
{
|
|
#if defined(_ARMOR)
|
|
Verify(!macroed);
|
|
macroed = true;
|
|
#endif
|
|
char new_buf[MAX_LINE_SIZE];
|
|
Macro::ReplaceMacros(macro_tree, buffer, new_buf, sizeof(new_buf));
|
|
p = new_buf;
|
|
goto Parse;
|
|
}
|
|
else
|
|
ProcessLine(stream, macro_tree, page, p);
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------
|
|
// We are in raw mode, so just process each line as it happens
|
|
//------------------------------------------------------------
|
|
//
|
|
else
|
|
ProcessLine(stream, macro_tree, page, p);
|
|
}
|
|
if (comment_mode)
|
|
PAUSE(("There is a missing */ in %s", (const char*)m_fileName));
|
|
if (nested)
|
|
PAUSE(("There is a missing } in %s", (const char*)m_fileName));
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// If we allocated the macro tree, delete it now. The extra braces are to
|
|
// remove the iterator needed for deletion
|
|
//------------------------------------------------------------------------
|
|
//
|
|
if (!orig_tree)
|
|
{
|
|
Check_Pointer(macro_tree);
|
|
stlport::map<MString, Macro*> *map = (stlport::map<MString, Macro*>*)macro_tree;
|
|
stlport::map<MString, Macro*>::iterator seeker = map->begin();
|
|
while (seeker != map->end())
|
|
{
|
|
Macro *macro = (*seeker).second;
|
|
Check_Object(macro);
|
|
delete macro;
|
|
++seeker;
|
|
}
|
|
delete map;
|
|
}
|
|
|
|
//
|
|
//---------------------
|
|
// Nothing to save, yet
|
|
//---------------------
|
|
//
|
|
m_dirtyFlag = false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NotationFile::Write(MemoryStream *stream)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(stream);
|
|
|
|
//
|
|
//----------------------------------
|
|
// Write each page out to the stream
|
|
//----------------------------------
|
|
//
|
|
Page *null_page=FindPage("");
|
|
if(null_page)
|
|
{
|
|
Check_Object(null_page);
|
|
null_page->WriteNotes(stream);
|
|
}
|
|
|
|
PageIterator pages(&m_pages);
|
|
Page *page;
|
|
while ((page = pages.ReadAndNext()) != NULL)
|
|
{
|
|
if(page!=null_page)
|
|
{
|
|
Check_Object(page);
|
|
page->WriteNotes(stream);
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NotationFile::Save()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//------------------------------------------------------
|
|
// If the file is dirty and has a filename, write it out
|
|
//------------------------------------------------------
|
|
//
|
|
if (m_dirtyFlag && m_fileName.GetLength()>0)
|
|
{
|
|
FileStream output(m_fileName, FileStream::WriteOnly);
|
|
Write(&output);
|
|
}
|
|
IgnoreChanges();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NotationFile::SaveAs(const char* file_name)
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//------------------------------------------------------
|
|
// If the file is dirty and has a filename, write it out
|
|
//------------------------------------------------------
|
|
//
|
|
FileStream output(file_name, FileStream::WriteOnly);
|
|
m_fileName = output.GetFileName();
|
|
Write(&output);
|
|
IgnoreChanges();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NotationFile::ProcessLine(
|
|
MemoryStream *stream,
|
|
void *macro_tree,
|
|
Page **notepage,
|
|
char *buffer
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(stream);
|
|
Check_Pointer(macro_tree);
|
|
Check_Pointer(buffer);
|
|
Check_Pointer(notepage);
|
|
|
|
//
|
|
//--------------------------------
|
|
// find first non-blank character
|
|
//--------------------------------
|
|
//
|
|
char *p = buffer;
|
|
while (*p == ' ' || *p == '\t')
|
|
++p;
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// If this is a page name, isolate the name, then only add it if it is a
|
|
// new page
|
|
//----------------------------------------------------------------------
|
|
//
|
|
char *token;
|
|
if (*p == '[')
|
|
{
|
|
token = p+1;
|
|
while (*token == ' ' || *token == '\t')
|
|
++token;
|
|
if ((p = strchr(token, ']')) != NULL)
|
|
{
|
|
p--;
|
|
while (p>token && *p==' ' || *p=='\t')
|
|
p--;
|
|
p[1] = '\0';
|
|
}
|
|
if (m_concatenate)
|
|
*notepage = SetPage(token);
|
|
else
|
|
*notepage = AddPage(token);
|
|
return;
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------
|
|
// If this is a comment or empty line, stop now
|
|
//---------------------------------------------
|
|
//
|
|
if (!*p)
|
|
return;
|
|
|
|
//
|
|
//--------------------------------------------------------------
|
|
// Look for an entry, and if we find one, clear out the trailing
|
|
// whitespace on the name
|
|
//--------------------------------------------------------------
|
|
//
|
|
token = p;
|
|
char *entry = NULL;
|
|
if ((p = strchr(token, '=')) != NULL)
|
|
{
|
|
*p = '\0';
|
|
entry = p + 1;
|
|
--p;
|
|
while (*p == ' ' || *p == '\t')
|
|
{
|
|
*p = '\0';
|
|
if (--p < token)
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------
|
|
// If a notepage structure does not exist yet, make the empty page
|
|
//----------------------------------------------------------------
|
|
//
|
|
if (!*notepage)
|
|
*notepage = AddPage("");
|
|
Check_Object(*notepage);
|
|
|
|
//
|
|
//--------------------------------------------------
|
|
// Create the new entry if it is not a complex entry
|
|
//--------------------------------------------------
|
|
//
|
|
Note *notation = (*notepage)->AddNote(token);
|
|
Check_Object(notation);
|
|
if (entry)
|
|
{
|
|
if (strcmp(entry, "{"))
|
|
notation->SetEntry(entry);
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Now we create a new notation file to read the next part of the stream
|
|
// into
|
|
//----------------------------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
NotationFile nested_file;
|
|
nested_file.m_preserveCase = m_preserveCase;
|
|
nested_file.Read(stream, macro_tree, NULL, true);
|
|
DynamicMemoryStream file_buffer(5);
|
|
file_buffer << "{\r\n";
|
|
if (m_preserveCase)
|
|
file_buffer << "!preservecase=true\r\n";
|
|
nested_file.Write(&file_buffer);
|
|
file_buffer << "}" << '\0';
|
|
file_buffer.Rewind();
|
|
notation->m_text = static_cast<const char*>(file_buffer.GetPointer());
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NotationFile::HandleBangStuff(
|
|
char *buffer,
|
|
void *macro_tree,
|
|
Page **page
|
|
)
|
|
{
|
|
Check_Pointer(buffer);
|
|
Check_Pointer(page);
|
|
Check_Pointer(macro_tree);
|
|
|
|
//
|
|
//-------------------------
|
|
// Move past any whitespace
|
|
//-------------------------
|
|
//
|
|
while (*buffer == ' ' || *buffer == '\t')
|
|
++buffer;
|
|
if (!*buffer)
|
|
return;
|
|
|
|
//
|
|
//----------------------------
|
|
// Handle an include directive
|
|
//----------------------------
|
|
//
|
|
char *p;
|
|
if (!strnicmp(buffer, "include", 7))
|
|
{
|
|
p = buffer+7;
|
|
|
|
//
|
|
//---------------------------------------
|
|
// Look for the beginning of the filename
|
|
//---------------------------------------
|
|
//
|
|
while (*p == ' ' || *p == '\t')
|
|
++p;
|
|
if (*p == '=')
|
|
{
|
|
++p;
|
|
while (*p == ' ' || *p == '\t')
|
|
++p;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------
|
|
// If the filename starts with a quote, strip it off
|
|
//--------------------------------------------------
|
|
//
|
|
char *file_name;
|
|
if (*p == '"')
|
|
{
|
|
file_name = ++p;
|
|
p = strrchr(p, '"');
|
|
if (p)
|
|
*p = '\0';
|
|
}
|
|
else
|
|
file_name = p;
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// If there is a pathname in the file, it is searched for by gos,
|
|
// otherwise we assume it is relative to us
|
|
//---------------------------------------------------------------
|
|
//
|
|
char path[MAX_LINE_SIZE];
|
|
if (!__mbschr(file_name, '\\'))
|
|
{
|
|
Str_Copy(path, GetFileName(), sizeof(path));
|
|
p = __mbsrchr(path, '\\');
|
|
if (p)
|
|
{
|
|
Str_Copy(p+1, file_name, sizeof(path) - (p - path) - 1);
|
|
file_name = path;
|
|
}
|
|
}
|
|
|
|
//
|
|
//---------------
|
|
// Now open it up
|
|
//---------------
|
|
//
|
|
if (s_cachedIncludes)
|
|
{
|
|
stlport::map<MString, FileStream*> *map = (stlport::map<MString, FileStream*>*)s_cachedIncludes;
|
|
MString name(file_name);
|
|
stlport::map<MString, FileStream*>::iterator seeker = map->find(file_name);
|
|
FileStream *header;
|
|
if (seeker != map->end())
|
|
{
|
|
header = (*seeker).second;
|
|
header->Rewind();
|
|
}
|
|
else
|
|
{
|
|
header = new FileStream(name);
|
|
(*map)[name] = header;
|
|
}
|
|
Check_Object(header);
|
|
m_fileDependencies.AddDependency(header);
|
|
Read(header, macro_tree, page, false);
|
|
}
|
|
else
|
|
{
|
|
FileStream input(file_name);
|
|
m_fileDependencies.AddDependency(&input);
|
|
Read(&input, macro_tree, page, false);
|
|
}
|
|
}
|
|
|
|
//
|
|
//-------------------------------
|
|
// Handle a concatenate directive
|
|
//-------------------------------
|
|
//
|
|
else if (!strnicmp(buffer, "concatenate", 11))
|
|
{
|
|
p = buffer+11;
|
|
|
|
//
|
|
//------------------------------------
|
|
// Look for the beginning of the state
|
|
//------------------------------------
|
|
//
|
|
while (*p == ' ' || *p == '\t')
|
|
++p;
|
|
if (*p == '=')
|
|
{
|
|
++p;
|
|
while (*p == ' ' || *p == '\t')
|
|
++p;
|
|
}
|
|
|
|
//
|
|
//--------------
|
|
// set the value
|
|
//--------------
|
|
//
|
|
m_concatenate = (!stricmp(p, "true") || !stricmp(p, "yes") || atoi(p) != 0);
|
|
}
|
|
|
|
//
|
|
//-------------------------------
|
|
// Handle a concatenate directive
|
|
//-------------------------------
|
|
//
|
|
else if (!strnicmp(buffer, "preservecase", 12))
|
|
{
|
|
p = buffer+12;
|
|
|
|
//
|
|
//------------------------------------
|
|
// Look for the beginning of the state
|
|
//------------------------------------
|
|
//
|
|
while (*p == ' ' || *p == '\t')
|
|
++p;
|
|
if (*p == '=')
|
|
{
|
|
++p;
|
|
while (*p == ' ' || *p == '\t')
|
|
++p;
|
|
}
|
|
|
|
//
|
|
//--------------
|
|
// set the value
|
|
//--------------
|
|
//
|
|
m_preserveCase = (!stricmp(p, "true") || !stricmp(p, "yes") || atoi(p) != 0);
|
|
}
|
|
|
|
//
|
|
//------------------------------------------
|
|
// Otherwise, we must have ourselves a macro
|
|
//------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
char *entry = NULL;
|
|
|
|
//
|
|
//--------------------------------
|
|
// trim the spaces off of the name
|
|
//--------------------------------
|
|
//
|
|
if ((p = strchr(buffer, '=')) != NULL)
|
|
{
|
|
*p = '\0';
|
|
entry = p + 1;
|
|
--p;
|
|
while (*p == ' ' || *p == '\t')
|
|
{
|
|
*p = '\0';
|
|
if (--p < buffer)
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// Make sure the name is decent and that the entry is valid
|
|
//---------------------------------------------------------
|
|
//
|
|
if (!*buffer || !entry || !*entry)
|
|
return;
|
|
|
|
Macro::AddValue(macro_tree, buffer, entry);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NotationFile::HandlePoundStuff(
|
|
char *buffer,
|
|
void *macro_tree,
|
|
Page **page
|
|
)
|
|
{
|
|
Check_Pointer(buffer);
|
|
Check_Pointer(page);
|
|
Check_Pointer(macro_tree);
|
|
|
|
//
|
|
//-------------------------
|
|
// Move past any whitespace
|
|
//-------------------------
|
|
//
|
|
while (*buffer == ' ' || *buffer == '\t')
|
|
++buffer;
|
|
if (!*buffer)
|
|
return;
|
|
|
|
//
|
|
//----------------------------
|
|
// Handle an include directive
|
|
//----------------------------
|
|
//
|
|
char *p;
|
|
if (!strnicmp(buffer, "define", 6))
|
|
{
|
|
p = buffer+6;
|
|
char *entry = NULL;
|
|
|
|
//
|
|
//--------------------------------
|
|
// trim the spaces before the name
|
|
//--------------------------------
|
|
//
|
|
while (*p == ' ' || *p == '\t')
|
|
{
|
|
p++;
|
|
}
|
|
|
|
buffer = p;
|
|
|
|
//
|
|
//-------------------------------------------
|
|
// Skip the name before the first white space
|
|
//-------------------------------------------
|
|
//
|
|
while (*p != ' ' && *p != '\t' && *p != '\0')
|
|
{
|
|
p++;
|
|
}
|
|
|
|
*p=0;
|
|
p++;
|
|
//
|
|
//-----------------------------------------------
|
|
// trim the spaces between the name and the macro
|
|
//-----------------------------------------------
|
|
//
|
|
while (*p == ' ' || *p == '\t')
|
|
{
|
|
p++;
|
|
}
|
|
entry = p;
|
|
//
|
|
//---------------------------------------------------------
|
|
// Make sure the name is decent and that the entry is valid
|
|
//---------------------------------------------------------
|
|
//
|
|
if (!*buffer || !entry || !*entry)
|
|
return;
|
|
|
|
Macro::AddValue(macro_tree, buffer, entry);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Page* NotationFile::FindPage(const char *pagename)
|
|
{
|
|
Check_Object(this);
|
|
|
|
PageIterator pages(&m_pages);
|
|
MString page_lwr = pagename;
|
|
if (pagename)
|
|
page_lwr.ToLower();
|
|
else
|
|
page_lwr = "";
|
|
stlport::map<MString, Page*> *map = (stlport::map<MString, Page*>*)m_pageMap;
|
|
stlport::map<MString, Page*>::iterator seeker = map->find(page_lwr);
|
|
if (seeker != map->end())
|
|
return (*seeker).second;
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Page* NotationFile::GetPage(const char *pagename)
|
|
{
|
|
Page *page = FindPage(pagename);
|
|
if (!page)
|
|
STOP((
|
|
"%s: [%s] is a required page!",
|
|
GetFileName(),
|
|
pagename
|
|
));
|
|
return page;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Page* NotationFile::SetPage(const char *pagename)
|
|
{
|
|
Check_Object(this);
|
|
|
|
Page *page = FindPage(pagename);
|
|
if (!page)
|
|
page = AddPage(pagename);
|
|
Check_Object(page);
|
|
return page;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Page* NotationFile::AddPage(const char *pagename)
|
|
{
|
|
Check_Object(this);
|
|
|
|
SetDirty();
|
|
Page *page = new(g_Heap) Page(this);
|
|
Check_Object(page);
|
|
if (!pagename)
|
|
page->SetName("");
|
|
else
|
|
page->SetName(pagename);
|
|
m_pages.Add(page);
|
|
stlport::map<MString, Page*> *map = (stlport::map<MString, Page*>*)m_pageMap;
|
|
(*map)[page->m_name] = page;
|
|
return page;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NotationFile::DeletePage(const char *pagename)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(pagename);
|
|
|
|
MString page_lwr = pagename;
|
|
if (pagename)
|
|
page_lwr.ToLower();
|
|
else
|
|
page_lwr = "";
|
|
stlport::map<MString, Page*> *map = (stlport::map<MString, Page*>*)m_pageMap;
|
|
stlport::map<MString, Page*>::iterator seeker = map->find(page_lwr);
|
|
if (seeker != map->end())
|
|
{
|
|
Page *page = (*seeker).second;
|
|
map->erase(seeker);
|
|
Check_Object(page);
|
|
delete page;
|
|
SetDirty();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void NotationFile::DeleteAllPages()
|
|
{
|
|
Check_Object(this);
|
|
|
|
PageIterator pages(&m_pages);
|
|
Page *page;
|
|
while ((page = pages.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(page);
|
|
delete page;
|
|
}
|
|
stlport::map<MString, Page*> *map = (stlport::map<MString, Page*>*)m_pageMap;
|
|
delete map;
|
|
m_pageMap = new stlport::map<Stuff::MString, Page*>;
|
|
Check_Pointer(m_pageMap);
|
|
}
|