Files
TeslaRel410/restoration/source410/MUNGA/FILEUTIL.CPP
T
CydandClaude Fable 5 5b35eb973c 4.10 reconstruction: BTL4OPT.EXE links clean and BOOTS to the first staged brick
The reconstructed tree now produces a runnable binary with the authentic
1995 toolchain (BC4.52 / tlink32 / DPMI32):

- BTL4.CPP main TU reconstructed from the 4.11 Ghidra decomp (FUN_0040109c)
  + the 4.10 binary's own string pool + surviving RPL4TOOL.CPP house style;
  probe_main.cpp scaffold retired (BTL4.NOTES.md documents every decoded call)
- L4NET.CPP staged: L4NetworkManager ctor/dtor + 10 vtable-pulled virtuals
  (standalone-benign ones no-op, network ones Fail loudly) + NetNub client
  globals (Net_Common_Ptr=NULL routes L4File to its plain-DOS path)
- build410.sh: libs now built in the AUTHENTIC makefile member order
  (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK). Order is load-bearing:
  tlink emits static-init records in module pull order, and alphabetical
  order booted into a null-vptr crash (IcomManager::ClassDerivations
  constructing before parent NetworkClient::ClassDerivations). Also fixed
  stage_link to the proven 32-bit lib set (SOSDBXC+SOSMBXC, no WATTCPLG)
- BOXTREE.HPP MemoryBlock unify, BTL4GRND notify stubs, remaining engine
  backfills (audio/gauge/resource/stream TUs) that closed the deep ledger

Smoke test (DOSBox-X + 32RTM, copy of the pod BT tree, our exe swapped in):
  BattleTech v4.10
  BTL4Application::BTL4Application
  l4net.cpp(22): L4NetworkManager -- l4net.cpp not yet reconstructed
Static init, main, -egg parse, BTL4.RES load (version 1.0.6 check passes),
ApplicationManager and the BTL4Application ctor chain all execute real
reconstructed code; boot halts at the first staged Fail() as designed.
Next brick: the real l4net.cpp body.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 19:05:53 -05:00

833 lines
17 KiB
C++

# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
#include <dir.h>
#include <direct.h>
# if !defined(FILEUTIL_HPP)
# include <fileutil.hpp>
# endif
# if !defined(NOTATION_HPP)
# include <notation.hpp>
# endif
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" << flush;
Fail("Exiting");
}
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()." << endl;
DEBUG_STREAM <<
": Program Error - buffer[] too small in StripExtension()." << endl << flush;
Fail("Exiting");
}
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(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." << endl << flush;
DEBUG_STREAM << ": ERROR - Input line too long." << endl << 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(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(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"))
{
cout << "WARNING: LAB_ONLY" << 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());
ifstream notation_file_stream(notation_file->GetFileName());
return (notation_file_stream) ? True : False;
}
//=============================================================================