Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.
Layout:
engine/ MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
models) + image codec; the minimal rp/ headers the audio HAL needs
game/ reconstructed BT logic + surviving-original BT source + fwd shims
+ WinMain launcher
content/ full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
docs/ format specs + reconstruction ledgers
reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
tools/ MP console emulator + map/resource scanners
One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
826 lines
16 KiB
C++
826 lines
16 KiB
C++
#include "munga.h"
|
|
#include "windows.h"
|
|
#pragma hdrstop
|
|
|
|
#include <direct.h>
|
|
#include "fileutil.h"
|
|
#include "notation.h"
|
|
|
|
char *WorkingDirectory = NULL;
|
|
|
|
//#############################################################################
|
|
|
|
const char *White_Space = " \t\n";
|
|
|
|
//#############################################################################
|
|
|
|
char
|
|
*SourceDirectory = NULL,
|
|
*ConfigDirectory = NULL,
|
|
*MaterialDirectory = NULL,
|
|
*TextureDirectory = NULL,
|
|
*AnimationDirectory = NULL,
|
|
*ProductionDirectory = NULL;
|
|
const char
|
|
*OutputDirectory = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SetSourceDirectory(const char *input_file)
|
|
{
|
|
Check_Pointer(input_file);
|
|
|
|
static const char
|
|
* const ARTTOOLS_FILENAME = ".arttoolsrc",
|
|
* const DIRECTORIES_PAGE = "directories",
|
|
* const CFG_DIR_ENTRY = "cfg_dir",
|
|
* const MTL_DIR_ENTRY = "mtl_dir",
|
|
* const TEX_DIR_ENTRY = "tex_dir",
|
|
* const KIN_DIR_ENTRY = "kin_dir",
|
|
* const PRD_DIR_ENTRY = "prd_dir";
|
|
|
|
NotationFile
|
|
*tools_info;
|
|
char
|
|
*cwd;
|
|
const char
|
|
*cp,
|
|
*contents;
|
|
|
|
//------------------------------------------------
|
|
// parse the source directory from the input file
|
|
//------------------------------------------------
|
|
if ((cp = strrchr(input_file, '/')) == NULL)
|
|
{
|
|
//---------------------------------------------------
|
|
// set source directory to current working directory
|
|
//---------------------------------------------------
|
|
cwd = _getcwd(NULL, 256);
|
|
Verify( cwd );
|
|
SourceDirectory = new char[strlen(cwd) + 2];
|
|
Register_Pointer(SourceDirectory);
|
|
strcpy(SourceDirectory, cwd);
|
|
strcat(SourceDirectory, "/");
|
|
free(cwd);
|
|
}
|
|
else
|
|
{
|
|
//------------------------------------------------------
|
|
// set source directory to path specified in input file
|
|
//------------------------------------------------------
|
|
++cp;
|
|
SourceDirectory = new char[cp - input_file + 1];
|
|
Register_Pointer(SourceDirectory);
|
|
*SourceDirectory = '\0';
|
|
strncat(SourceDirectory, input_file, cp - input_file);
|
|
}
|
|
|
|
//-----------------------------------------------------------
|
|
// set other directories from tools config file (if present)
|
|
//-----------------------------------------------------------
|
|
tools_info = new NotationFile(SourceFile(ARTTOOLS_FILENAME));
|
|
Register_Object(tools_info);
|
|
|
|
if (tools_info->GetEntry(DIRECTORIES_PAGE, CFG_DIR_ENTRY, &contents))
|
|
{
|
|
ConfigDirectory = new char[strlen(contents) + 2];
|
|
Register_Pointer(ConfigDirectory);
|
|
strcpy(ConfigDirectory, contents);
|
|
cp = strchr(contents, '\0');
|
|
if (cp > contents && *--cp != '/')
|
|
{
|
|
strcat(ConfigDirectory, "/");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ConfigDirectory = SourceDirectory;
|
|
}
|
|
|
|
if (tools_info->GetEntry(DIRECTORIES_PAGE, MTL_DIR_ENTRY, &contents))
|
|
{
|
|
MaterialDirectory = new char[strlen(contents) + 2];
|
|
Register_Pointer(MaterialDirectory);
|
|
strcpy(MaterialDirectory, contents);
|
|
cp = strchr(contents, '\0');
|
|
if (cp > contents && *--cp != '/')
|
|
{
|
|
strcat(MaterialDirectory, "/");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MaterialDirectory = SourceDirectory;
|
|
}
|
|
|
|
if (tools_info->GetEntry(DIRECTORIES_PAGE, TEX_DIR_ENTRY, &contents))
|
|
{
|
|
TextureDirectory = new char[strlen(contents) + 2];
|
|
Register_Pointer(TextureDirectory);
|
|
strcpy(TextureDirectory, contents);
|
|
cp = strchr(contents, '\0');
|
|
if (cp > contents && *--cp != '/')
|
|
{
|
|
strcat(TextureDirectory, "/");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TextureDirectory = MaterialDirectory; // this one is different!
|
|
}
|
|
|
|
if (tools_info->GetEntry(DIRECTORIES_PAGE, KIN_DIR_ENTRY, &contents))
|
|
{
|
|
AnimationDirectory = new char[strlen(contents) + 2];
|
|
Register_Pointer(AnimationDirectory);
|
|
strcpy(AnimationDirectory, contents);
|
|
cp = strchr(contents, '\0');
|
|
if (cp > contents && *--cp != '/')
|
|
{
|
|
strcat(AnimationDirectory, "/");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AnimationDirectory = SourceDirectory;
|
|
}
|
|
|
|
if (tools_info->GetEntry(DIRECTORIES_PAGE, PRD_DIR_ENTRY, &contents))
|
|
{
|
|
ProductionDirectory = new char[strlen(contents) + 2];
|
|
Register_Pointer(ProductionDirectory);
|
|
strcpy(ProductionDirectory, contents);
|
|
cp = strchr(contents, '\0');
|
|
if (cp > contents && *--cp != '/')
|
|
{
|
|
strcat(ProductionDirectory, "/");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ProductionDirectory = SourceDirectory;
|
|
}
|
|
|
|
OutputDirectory = SourceDirectory;
|
|
|
|
Unregister_Object(tools_info);
|
|
delete tools_info;
|
|
|
|
return;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SetOutputDirectory(const char *directory)
|
|
{
|
|
Check_Pointer(directory);
|
|
|
|
OutputDirectory = directory;
|
|
return;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
GetSourceDirectory()
|
|
{
|
|
return SourceDirectory;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
GetConfigDirectory()
|
|
{
|
|
return ConfigDirectory;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
GetMaterialDirectory()
|
|
{
|
|
return MaterialDirectory;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
GetTextureDirectory()
|
|
{
|
|
return TextureDirectory;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
GetAnimationDirectory()
|
|
{
|
|
return AnimationDirectory;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
GetProductionDirectory()
|
|
{
|
|
return ProductionDirectory;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
GetOutputDirectory()
|
|
{
|
|
return OutputDirectory;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
ClearDirectories()
|
|
{
|
|
//do not clear output directory
|
|
|
|
if (ProductionDirectory && ProductionDirectory != SourceDirectory)
|
|
{
|
|
Unregister_Pointer(ProductionDirectory);
|
|
delete ProductionDirectory;
|
|
}
|
|
if (AnimationDirectory && AnimationDirectory != SourceDirectory)
|
|
{
|
|
Unregister_Pointer(AnimationDirectory);
|
|
delete AnimationDirectory;
|
|
}
|
|
if (TextureDirectory && TextureDirectory != MaterialDirectory) //different!
|
|
{
|
|
Unregister_Pointer(TextureDirectory);
|
|
delete TextureDirectory;
|
|
}
|
|
if (MaterialDirectory && MaterialDirectory != SourceDirectory)
|
|
{
|
|
Unregister_Pointer(MaterialDirectory);
|
|
delete MaterialDirectory;
|
|
}
|
|
if (ConfigDirectory && ConfigDirectory != SourceDirectory)
|
|
{
|
|
Unregister_Pointer(ConfigDirectory);
|
|
delete ConfigDirectory;
|
|
}
|
|
if (SourceDirectory)
|
|
{
|
|
Unregister_Pointer(SourceDirectory);
|
|
delete SourceDirectory;
|
|
}
|
|
return;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
DirectoryPlusFilename(
|
|
const char *directory,
|
|
const char *filename,
|
|
const char *extension
|
|
)
|
|
{
|
|
//do not check directory here
|
|
Check_Pointer(filename);
|
|
//do not check extension here
|
|
|
|
static char
|
|
buffer[512];
|
|
int
|
|
length;
|
|
|
|
if (!directory) { directory = "\0"; }
|
|
Check_Pointer(directory);
|
|
|
|
length = strlen(directory);
|
|
if (extension)
|
|
{
|
|
Check_Pointer(extension);
|
|
length += strlen(StripExtension(StripDirectory(filename)));
|
|
length += *extension == '.'?0:1;
|
|
length += strlen(extension);
|
|
}
|
|
else
|
|
{
|
|
length += strlen(StripDirectory(filename));
|
|
}
|
|
|
|
if (length >= ELEMENTS(buffer))
|
|
{
|
|
DEBUG_STREAM <<
|
|
": Program Error - buffer[] too small in DirectoryPlusFilename().\n" << std::flush;
|
|
PostQuitMessage(AbortExitCodeID);
|
|
}
|
|
strcpy(buffer, directory);
|
|
if (extension)
|
|
{
|
|
strcat(buffer, StripExtension(StripDirectory(filename)));
|
|
if (*extension != '.')
|
|
{
|
|
strcat(buffer, ".");
|
|
}
|
|
strcat(buffer, extension);
|
|
}
|
|
else
|
|
{
|
|
strcat(buffer, StripDirectory(filename));
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
SourceFile(
|
|
const char *filename,
|
|
const char *extension
|
|
)
|
|
{
|
|
return DirectoryPlusFilename(SourceDirectory, filename, extension);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
ConfigFile(
|
|
const char *filename,
|
|
const char *extension
|
|
)
|
|
{
|
|
return DirectoryPlusFilename(ConfigDirectory, filename, extension);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
MaterialFile(
|
|
const char *filename,
|
|
const char *extension
|
|
)
|
|
{
|
|
return DirectoryPlusFilename(MaterialDirectory, filename, extension);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
TextureFile(
|
|
const char *filename,
|
|
const char *extension
|
|
)
|
|
{
|
|
return DirectoryPlusFilename(TextureDirectory, filename, extension);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
AnimationFile(
|
|
const char *filename,
|
|
const char *extension
|
|
)
|
|
{
|
|
return DirectoryPlusFilename(AnimationDirectory, filename, extension);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
OutputFile(
|
|
const char *filename,
|
|
const char *extension
|
|
)
|
|
{
|
|
return DirectoryPlusFilename(OutputDirectory, filename, extension);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
const char*
|
|
StripDirectory(const char *filename)
|
|
{
|
|
Check_Pointer(filename);
|
|
|
|
if (DirectoryIsSpecified(filename))
|
|
{
|
|
const char
|
|
*p;
|
|
|
|
//--------------------------------------
|
|
// parse the filename from the filepath
|
|
//--------------------------------------
|
|
p = strchr(filename, '\0');
|
|
Verify( p );
|
|
while (*p != '\\' && p != filename)
|
|
{
|
|
--p;
|
|
}
|
|
if (*p == '\\')
|
|
{
|
|
++p;
|
|
}
|
|
filename = p;
|
|
}
|
|
return filename;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char*
|
|
StripExtension(const char *filename)
|
|
{
|
|
Check_Pointer(filename);
|
|
|
|
static char
|
|
buffer[512];
|
|
char
|
|
*p;
|
|
|
|
if (strlen(filename) >= sizeof(buffer))
|
|
{
|
|
//DEBUG_STREAM << ProgName <<
|
|
// ": Program Error - buffer[] too small in StripExtension()." << std::endl;
|
|
DEBUG_STREAM <<
|
|
": Program Error - buffer[] too small in StripExtension()." << std::endl << std::flush;
|
|
|
|
PostQuitMessage(AbortExitCodeID);
|
|
}
|
|
strcpy(buffer, filename);
|
|
|
|
//------------------------------------
|
|
// remove the extension from filename
|
|
//------------------------------------
|
|
p = strchr(buffer, '\0');
|
|
Verify( p );
|
|
while (*p != '.' && p != buffer)
|
|
{
|
|
--p;
|
|
}
|
|
if (*p == '.')
|
|
{
|
|
*p = '\0';
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
//#############################################################################
|
|
|
|
char*
|
|
Ind(int level)
|
|
{
|
|
const int buf_len = 128;
|
|
static char buf[buf_len];
|
|
|
|
//---------------------------------------------------------
|
|
// Return string of spaces used to indent an output stream
|
|
//---------------------------------------------------------
|
|
buf[0] = '\0';
|
|
if (level > 63) level = 63; // floor((buf_len - 1)/number of spaces per indent)
|
|
for (; level > 0; --level)
|
|
{
|
|
strcat(buf, " ");
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical GetLine(std::istream &stream, char *buffer, int size_of_buffer)
|
|
{
|
|
static char temp_buffer[512];
|
|
|
|
//-------------------------------------------------------------
|
|
// read next line(s) from input stream automatically resolving
|
|
// lines with a continuation character '\' at the end
|
|
//-------------------------------------------------------------
|
|
if (stream.getline(buffer, size_of_buffer))
|
|
{
|
|
char *p;
|
|
int i;
|
|
|
|
while (True)
|
|
{
|
|
if ((i = strlen(buffer)) > (size_of_buffer - 2))
|
|
{
|
|
//DEBUG_STREAM << ProgName << ": ERROR - Input line too long." << std::endl << std::flush;
|
|
|
|
DEBUG_STREAM << ": ERROR - Input line too long." << std::endl << std::flush;
|
|
break;
|
|
}
|
|
|
|
p = buffer + i;
|
|
while (p-- > buffer && isspace(*p)); // find last non-blank character
|
|
|
|
if (p >= buffer && *p == '\\')
|
|
{
|
|
if (stream.getline(temp_buffer, sizeof(temp_buffer)))
|
|
{
|
|
*p = ' ';
|
|
++p;
|
|
strncat(p, temp_buffer, size_of_buffer - (p - buffer));
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return True;
|
|
}
|
|
else
|
|
{
|
|
*buffer = '\0';
|
|
return False;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
#if 0
|
|
char*
|
|
stripname(char filename[])
|
|
{
|
|
|
|
// Doesn't work
|
|
|
|
char
|
|
file2[200];
|
|
char
|
|
*filetosendback;
|
|
|
|
int
|
|
wordlength,
|
|
count,
|
|
countbackward,
|
|
length;
|
|
|
|
|
|
length = strlen(filename);
|
|
|
|
|
|
count = 0;
|
|
countbackward = length-1;
|
|
|
|
while (filename[countbackward-1] != '\\')
|
|
{
|
|
--countbackward;
|
|
}
|
|
|
|
wordlength = length - countbackward;
|
|
|
|
for (count = 0; count < wordlength; ++count)
|
|
{
|
|
file2[count] = filename[countbackward];
|
|
++countbackward;
|
|
}
|
|
|
|
file2[count] = '\0';
|
|
|
|
filetosendback = strdup(file2);
|
|
|
|
return filetosendback;
|
|
}
|
|
#endif
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Scalar
|
|
D2R(float degrees)
|
|
{
|
|
return degrees*(3.14159259f/180.0f);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
char*
|
|
MakeWorkingDirectory(
|
|
const char *file
|
|
)
|
|
{
|
|
char *directory;
|
|
const char *p;
|
|
int size;
|
|
p = file;
|
|
|
|
for (int i = (strlen(file) - 1 ); i >= 0; --i)
|
|
{
|
|
if ( (*p == '/') || (*p == '\\') )
|
|
{
|
|
size = strlen(file) - i + 1;
|
|
|
|
directory = new char[size];
|
|
strncpy(directory, file, size);
|
|
|
|
return directory;
|
|
}
|
|
++p;
|
|
}
|
|
|
|
//
|
|
// Else return local directory
|
|
//
|
|
#define BUFFER_SIZE (256)
|
|
char buffer[BUFFER_SIZE];
|
|
getcwd(buffer, BUFFER_SIZE);
|
|
|
|
#if 0
|
|
directory = strdup(buffer);
|
|
strcat(directory, "\\"); // ECH 1/29/96 - This is an overwrite
|
|
#else
|
|
Str_Cat(buffer, "\\", BUFFER_SIZE);
|
|
size = strlen(buffer) + 1;
|
|
directory = new char[size];
|
|
Str_Copy(directory, buffer, size);
|
|
#endif
|
|
|
|
//
|
|
// This is "\\" for DOS
|
|
//
|
|
|
|
return directory;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Logical
|
|
DirectoryIsSpecified(
|
|
const char *file
|
|
)
|
|
{
|
|
return strchr(file,'/') || strchr(file,':') || strchr(file,'\\');
|
|
|
|
#if 0
|
|
const char *p;
|
|
|
|
p = file;
|
|
|
|
for (int i = 0; i < strlen(file); ++i)
|
|
{
|
|
if ( (*p == '/') || (*p == '\\') )
|
|
{
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
++p;
|
|
}
|
|
return False;
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
char*
|
|
MakePathedFilename(
|
|
const char *directory,
|
|
const char *name
|
|
)
|
|
{
|
|
char *filename;
|
|
|
|
if (DirectoryIsSpecified(name))
|
|
{
|
|
filename = new char[ strlen(name) + 1];
|
|
strcpy(filename, name);
|
|
return filename;
|
|
}
|
|
|
|
if (directory == NULL)
|
|
{
|
|
filename = new char[strlen(name) + 1];
|
|
strcpy(filename, name);
|
|
}
|
|
else
|
|
{
|
|
filename = new char[strlen(directory) + strlen(name) + 1];
|
|
|
|
strcpy(filename, directory);
|
|
strcat(filename, name);
|
|
}
|
|
|
|
return filename;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void OpenOutput(std::ofstream &stream, const char *directory, const char *filename)
|
|
{
|
|
//do not check directory here
|
|
Check_Pointer(filename);
|
|
|
|
char
|
|
*file_to_open;
|
|
|
|
if (DirectoryIsSpecified(filename) || directory == NULL)
|
|
{
|
|
file_to_open = new char[strlen(filename) + 1];
|
|
Register_Pointer(file_to_open);
|
|
strcpy(file_to_open, filename);
|
|
}
|
|
else
|
|
{
|
|
Check_Pointer(directory);
|
|
file_to_open = new char[strlen(directory) + strlen(filename) + 1];
|
|
Register_Pointer(file_to_open);
|
|
strcpy(file_to_open, directory);
|
|
strcat(file_to_open, filename);
|
|
}
|
|
|
|
stream.open(file_to_open);
|
|
Unregister_Pointer(file_to_open);
|
|
delete file_to_open;
|
|
return;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void OpenInput(std::ifstream &stream, char *directory, const char *filename)
|
|
{
|
|
char tempfile[100];
|
|
|
|
if (DirectoryIsSpecified(filename))
|
|
{
|
|
strcpy(tempfile, filename);
|
|
}
|
|
else
|
|
{
|
|
if (directory != NULL)
|
|
{
|
|
strcpy(tempfile, directory);
|
|
strcat(tempfile, filename);
|
|
}
|
|
else
|
|
{
|
|
strcpy(tempfile, filename);
|
|
}
|
|
}
|
|
|
|
stream.open(tempfile);
|
|
return;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Logical
|
|
LabOnly(
|
|
NotationFile
|
|
*notation_file
|
|
)
|
|
{
|
|
|
|
if (notation_file->PageExists("LAB_ONLY"))
|
|
{
|
|
std::cout << "WARNING: LAB_ONLY" << std::endl;
|
|
return True;
|
|
}
|
|
else
|
|
{
|
|
return False;
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
void
|
|
AddLabOnly(
|
|
NotationFile
|
|
*notation_file
|
|
)
|
|
{
|
|
if (!notation_file->PageExists("LAB_ONLY"))
|
|
{
|
|
notation_file->AppendEntry("LAB_ONLY", NULL, NULL);
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Logical
|
|
DoesNotationFileExist(
|
|
NotationFile
|
|
*notation_file
|
|
)
|
|
{
|
|
Check(notation_file);
|
|
Check_Pointer(notation_file->GetFileName());
|
|
std::ifstream notation_file_stream(notation_file->GetFileName());
|
|
return (notation_file_stream) ? True : False;
|
|
}
|
|
|
|
//=============================================================================
|