Added modelviewer.

Added neural network code(turned off by default).
Lots of editor and rendering fixes.
This commit is contained in:
Justin Marshall
2026-05-17 22:09:25 -07:00
parent 079442e7ba
commit 76f642286e
74 changed files with 101444 additions and 2227 deletions
+572 -68
View File
@@ -139,6 +139,9 @@ protected:
// Set textSource possible with compression.
void SetTextLocal(const char* text, const int length);
// Replaces this decl's range in the backing source file with arbitrary text.
bool WriteSourceFileText(const char* text, const int length);
private:
idDecl* self;
@@ -218,7 +221,11 @@ public:
virtual void ListType(const idCmdArgs& args, declType_t type);
virtual void PrintType(const idCmdArgs& args, declType_t type);
virtual idDecl* CreateNewDecl(declType_t type, const char* name, const char* fileName);
virtual bool CreateDeclFile(const char* fileName, declType_t defaultType);
virtual idDecl* CreateNewDecl(declType_t type, const char* name, const char* fileName, bool save = true);
virtual bool SetDeclText(declType_t type, const char* name, const char* text, bool parse = true, bool save = false);
virtual bool SaveDecl(declType_t type, const char* name);
virtual bool DeleteDecl(declType_t type, const char* name, bool deleteSourceText = true);
//BSM Added for the material editors rename capabilities
virtual bool RenameDecl(declType_t type, const char* oldName, const char* newName);
@@ -275,9 +282,19 @@ private:
static idCVar decl_show;
private:
idDeclFile* FindDeclFile(const char* fileName) const;
idDeclFile* GetOrCreateDeclFile(const char* fileName, declType_t defaultType, bool createOnDisk);
declType_t GetDefaultTypeForFileName(const char* fileName, declType_t fallback) const;
void RemoveDeclFromSourceFile(idDeclLocal* decl);
void FreeDeclLocal(idDeclLocal* decl);
static void ListDecls_f(const idCmdArgs& args);
static void ReloadDecls_f(const idCmdArgs& args);
static void TouchDecl_f(const idCmdArgs& args);
static void CreateDeclFile_f(const idCmdArgs& args);
static void CreateDecl_f(const idCmdArgs& args);
static void SaveDecl_f(const idCmdArgs& args);
static void DeleteDecl_f(const idCmdArgs& args);
};
idCVar idDeclManagerLocal::decl_show("decl_show", "0", CVAR_SYSTEM, "set to 1 to print parses, 2 to also print references", 0, 2, idCmdSystem::ArgCompletion_Integer<0, 2>);
@@ -867,6 +884,73 @@ int idDeclFile::LoadAndParse() {
const char* listDeclStrings[] = { "current", "all", "ever", NULL };
/*
===================
DeclCountLineBreaks
===================
*/
static int DeclCountLineBreaks(const char* text, const int length) {
int count = 0;
if (text == NULL || length <= 0) {
return 0;
}
for (int i = 0; i < length; i++) {
if (text[i] == '\n') {
count++;
}
}
return count;
}
/*
===================
DeclCountFileLines
===================
*/
static int DeclCountFileLines(const char* text, const int length) {
if (text == NULL || length <= 0) {
return 0;
}
return DeclCountLineBreaks(text, length) + 1;
}
/*
===================
DeclLineForOffset
===================
*/
static int DeclLineForOffset(const char* text, const int offset) {
if (text == NULL || offset <= 0) {
return 1;
}
return DeclCountLineBreaks(text, offset) + 1;
}
/*
===================
DeclGetTypeFromCommandArg
===================
*/
static bool DeclGetTypeFromCommandArg(const idCmdArgs& args, const int arg, declType_t& type) {
type = declManagerLocal.GetDeclTypeFromName(args.Argv(arg));
if (type != DECL_MAX_TYPES) {
return true;
}
common->Printf("unknown decl type '%s'\n", args.Argv(arg));
common->Printf("valid types: ");
for (int i = 0; i < declManagerLocal.GetNumDeclTypes(); i++) {
idDeclType* declType = declManagerLocal.GetDeclType(i);
if (declType != NULL) {
common->Printf("%s ", declType->typeName.c_str());
}
}
common->Printf("\n");
return false;
}
/*
===================
idDeclManagerLocal::Init
@@ -915,6 +999,10 @@ void idDeclManagerLocal::Init(void) {
cmdSystem->AddCommand("reloadDecls", ReloadDecls_f, CMD_FL_SYSTEM, "reloads decls");
cmdSystem->AddCommand("touch", TouchDecl_f, CMD_FL_SYSTEM, "touches a decl");
cmdSystem->AddCommand("createDeclFile", CreateDeclFile_f, CMD_FL_SYSTEM, "creates an empty decl file: createDeclFile <type> <file>");
cmdSystem->AddCommand("createDecl", CreateDecl_f, CMD_FL_SYSTEM, "creates and saves a default decl: createDecl <type> <name> <file>");
cmdSystem->AddCommand("saveDecl", SaveDecl_f, CMD_FL_SYSTEM, "saves a decl: saveDecl <type> <name>");
cmdSystem->AddCommand("deleteDecl", DeleteDecl_f, CMD_FL_SYSTEM, "deletes a decl and removes its source text: deleteDecl <type> <name>");
cmdSystem->AddCommand("listTables", idListDecls_f<DECL_TABLE>, CMD_FL_SYSTEM, "lists tables", idCmdSystem::ArgCompletion_String<listDeclStrings>);
cmdSystem->AddCommand("listMaterials", idListDecls_f<DECL_MATERIAL>, CMD_FL_SYSTEM, "lists materials", idCmdSystem::ArgCompletion_String<listDeclStrings>);
@@ -1684,12 +1772,143 @@ void idDeclManagerLocal::PrintType(const idCmdArgs& args, declType_t type) {
}
}
/*
===================
idDeclManagerLocal::GetDefaultTypeForFileName
===================
*/
declType_t idDeclManagerLocal::GetDefaultTypeForFileName(const char* fileName, declType_t fallback) const {
if (fallback != DECL_MAX_TYPES || fileName == NULL || fileName[0] == '\0') {
return fallback;
}
const char* extension = strrchr(fileName, '.');
if (extension == NULL) {
return fallback;
}
for (int i = 0; i < declFolders.Num(); i++) {
if (declFolders[i] != NULL && declFolders[i]->extension.Icmp(extension) == 0) {
return declFolders[i]->defaultType;
}
}
return fallback;
}
/*
===================
idDeclManagerLocal::FindDeclFile
===================
*/
idDeclFile* idDeclManagerLocal::FindDeclFile(const char* _fileName) const {
if (_fileName == NULL || _fileName[0] == '\0') {
return NULL;
}
idStr fileName = _fileName;
fileName.BackSlashesToSlashes();
for (int i = 0; i < loadedFiles.Num(); i++) {
if (loadedFiles[i]->fileName.Icmp(fileName) == 0) {
return loadedFiles[i];
}
}
return NULL;
}
/*
===================
idDeclManagerLocal::GetOrCreateDeclFile
If the file already exists on disk but has not been registered yet, it is
registered and parsed. If it does not exist and createOnDisk is true, an
empty file is written to fs_devpath and registered.
===================
*/
idDeclFile* idDeclManagerLocal::GetOrCreateDeclFile(const char* _fileName, declType_t defaultType, bool createOnDisk) {
if (_fileName == NULL || _fileName[0] == '\0') {
common->Warning("idDeclManager::GetOrCreateDeclFile: empty file name");
return NULL;
}
idStr fileName = _fileName;
fileName.BackSlashesToSlashes();
idDeclFile* sourceFile = FindDeclFile(fileName.c_str());
if (sourceFile != NULL) {
return sourceFile;
}
defaultType = GetDefaultTypeForFileName(fileName.c_str(), defaultType);
ID_TIME_T timestamp = 0;
int length = fileSystem->ReadFile(fileName.c_str(), NULL, &timestamp);
sourceFile = new idDeclFile(fileName.c_str(), defaultType);
loadedFiles.Append(sourceFile);
if (length > 0) {
sourceFile->LoadAndParse();
return sourceFile;
}
if (length == 0) {
sourceFile->timestamp = timestamp;
sourceFile->checksum = MD5_BlockChecksum("", 0);
sourceFile->fileSize = 0;
sourceFile->numLines = 0;
sourceFile->decls = NULL;
return sourceFile;
}
if (!createOnDisk) {
return sourceFile;
}
idFile* file = fileSystem->OpenFileWrite(fileName.c_str(), "fs_devpath");
if (file == NULL) {
loadedFiles.RemoveIndex(loadedFiles.Num() - 1);
delete sourceFile;
common->Warning("Couldn't create decl file %s", fileName.c_str());
return NULL;
}
fileSystem->CloseFile(file);
sourceFile->timestamp = 0;
sourceFile->checksum = MD5_BlockChecksum("", 0);
sourceFile->fileSize = 0;
sourceFile->numLines = 0;
sourceFile->decls = NULL;
fileSystem->ReadFile(fileName.c_str(), NULL, &sourceFile->timestamp);
return sourceFile;
}
/*
===================
idDeclManagerLocal::CreateDeclFile
===================
*/
bool idDeclManagerLocal::CreateDeclFile(const char* fileName, declType_t defaultType) {
int typeIndex = (int)defaultType;
if (defaultType != DECL_MAX_TYPES && (typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL)) {
common->Warning("idDeclManager::CreateDeclFile: bad default type: %i", typeIndex);
return false;
}
return GetOrCreateDeclFile(fileName, defaultType, true) != NULL;
}
/*
===================
idDeclManagerLocal::CreateNewDecl
===================
*/
idDecl* idDeclManagerLocal::CreateNewDecl(declType_t type, const char* name, const char* _fileName) {
idDecl* idDeclManagerLocal::CreateNewDecl(declType_t type, const char* name, const char* _fileName, bool save) {
int typeIndex = (int)type;
int i, hash;
@@ -1697,75 +1916,235 @@ idDecl* idDeclManagerLocal::CreateNewDecl(declType_t type, const char* name, con
common->FatalError("idDeclManager::CreateNewDecl: bad type: %i", typeIndex);
}
char canonicalName[MAX_STRING_CHARS];
if (name == NULL || name[0] == '\0') {
common->Warning("idDeclManager::CreateNewDecl: empty %s name", declTypes[typeIndex]->typeName.c_str());
return NULL;
}
idDeclFile* sourceFile = GetOrCreateDeclFile(_fileName, type, save);
if (sourceFile == NULL) {
return NULL;
}
char canonicalName[MAX_STRING_CHARS];
MakeNameCanonical(name, canonicalName, sizeof(canonicalName));
idStr fileName = _fileName;
fileName.BackSlashesToSlashes();
// see if it already exists
idDeclLocal* decl = NULL;
hash = hashTables[typeIndex].GenerateKey(canonicalName, false);
for (i = hashTables[typeIndex].First(hash); i >= 0; i = hashTables[typeIndex].Next(i)) {
if (linearLists[typeIndex][i]->name.Icmp(canonicalName) == 0) {
linearLists[typeIndex][i]->AllocateSelf();
return linearLists[typeIndex][i]->self;
}
}
idDeclFile* sourceFile;
// find existing source file or create a new one
for (i = 0; i < loadedFiles.Num(); i++) {
if (loadedFiles[i]->fileName.Icmp(fileName) == 0) {
decl = linearLists[typeIndex][i];
break;
}
}
if (i < loadedFiles.Num()) {
sourceFile = loadedFiles[i];
}
else {
sourceFile = new idDeclFile(fileName, type);
loadedFiles.Append(sourceFile);
// If an explicit decl already exists, keep the invariant that type/name is unique.
if (decl != NULL && decl->sourceFile != &implicitDecls) {
decl->AllocateSelf();
common->Warning("%s '%s' already exists at %s:%i", declTypes[typeIndex]->typeName.c_str(),
canonicalName, decl->sourceFile->fileName.c_str(), decl->sourceLine);
return decl->self;
}
bool createdNewDecl = false;
if (decl == NULL) {
decl = new idDeclLocal;
decl->self = NULL;
decl->name = canonicalName;
decl->type = type;
decl->declState = DS_UNPARSED;
decl->referencedThisLevel = false;
decl->everReferenced = false;
decl->parsedOutsideLevelLoad = !insideLevelLoad;
createdNewDecl = true;
}
idDeclLocal* decl = new idDeclLocal;
decl->name = canonicalName;
decl->type = type;
decl->declState = DS_UNPARSED;
decl->AllocateSelf();
idStr header = declTypes[typeIndex]->typeName;
idStr defaultText = decl->self->DefaultDefinition();
idStr declText;
if (sourceFile->fileSize > 0) {
declText = "\n\n";
}
declText += declTypes[typeIndex]->typeName;
declText += " ";
declText += canonicalName;
declText += " ";
declText += decl->self->DefaultDefinition();
if (declText.Length() <= 0 || declText[declText.Length() - 1] != '\n') {
declText += "\n";
}
int size = header.Length() + 1 + idStr::Length(canonicalName) + 1 + defaultText.Length();
char* declText = (char*)_alloca(size + 1);
memcpy(declText, header, header.Length());
declText[header.Length()] = ' ';
memcpy(declText + header.Length() + 1, canonicalName, idStr::Length(canonicalName));
declText[header.Length() + 1 + idStr::Length(canonicalName)] = ' ';
memcpy(declText + header.Length() + 1 + idStr::Length(canonicalName) + 1, defaultText, defaultText.Length() + 1);
decl->SetTextLocal(declText, size);
decl->SetTextLocal(declText.c_str(), declText.Length());
decl->sourceFile = sourceFile;
decl->sourceTextOffset = sourceFile->fileSize;
decl->sourceTextLength = 0;
decl->sourceLine = sourceFile->numLines;
decl->ParseLocal();
decl->sourceLine = (sourceFile->numLines > 0) ? sourceFile->numLines : 1;
decl->declState = DS_UNPARSED;
// add this decl to the source file list
decl->nextInFile = sourceFile->decls;
sourceFile->decls = decl;
// add it to the hash table and linear list
decl->index = linearLists[typeIndex].Num();
hashTables[typeIndex].Add(hash, linearLists[typeIndex].Append(decl));
// add new explicit decls to the hash table and linear list
if (createdNewDecl) {
decl->index = linearLists[typeIndex].Num();
hashTables[typeIndex].Add(hash, linearLists[typeIndex].Append(decl));
}
decl->ParseLocal();
if (save && !decl->ReplaceSourceFileText()) {
common->Warning("%s '%s' was created in memory but could not be saved to %s",
declTypes[typeIndex]->typeName.c_str(), canonicalName, sourceFile->fileName.c_str());
}
return decl->self;
}
/*
===================
idDeclManagerLocal::SetDeclText
===================
*/
bool idDeclManagerLocal::SetDeclText(declType_t type, const char* name, const char* text, bool parse, bool save) {
int typeIndex = (int)type;
if (typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL) {
common->FatalError("idDeclManager::SetDeclText: bad type: %i", typeIndex);
}
if (text == NULL) {
common->Warning("idDeclManager::SetDeclText: NULL text for %s '%s'", declTypes[typeIndex]->typeName.c_str(), name ? name : "<NULL>");
return false;
}
idDeclLocal* decl = FindTypeWithoutParsing(type, name, false);
if (decl == NULL) {
common->Warning("idDeclManager::SetDeclText: %s '%s' not found", declTypes[typeIndex]->typeName.c_str(), name ? name : "<NULL>");
return false;
}
decl->SetTextLocal(text, idStr::Length(text));
decl->declState = DS_UNPARSED;
if (parse) {
decl->ParseLocal();
}
if (save) {
return decl->ReplaceSourceFileText();
}
return true;
}
/*
===================
idDeclManagerLocal::SaveDecl
===================
*/
bool idDeclManagerLocal::SaveDecl(declType_t type, const char* name) {
int typeIndex = (int)type;
if (typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL) {
common->FatalError("idDeclManager::SaveDecl: bad type: %i", typeIndex);
}
idDeclLocal* decl = FindTypeWithoutParsing(type, name, false);
if (decl == NULL) {
common->Warning("idDeclManager::SaveDecl: %s '%s' not found", declTypes[typeIndex]->typeName.c_str(), name ? name : "<NULL>");
return false;
}
if (decl->textSource == NULL) {
common->Warning("idDeclManager::SaveDecl: %s '%s' has no source text", declTypes[typeIndex]->typeName.c_str(), decl->GetName());
return false;
}
return decl->ReplaceSourceFileText();
}
/*
===================
idDeclManagerLocal::RemoveDeclFromSourceFile
===================
*/
void idDeclManagerLocal::RemoveDeclFromSourceFile(idDeclLocal* decl) {
if (decl == NULL || decl->sourceFile == NULL) {
return;
}
idDeclLocal** prev = &decl->sourceFile->decls;
while (*prev != NULL) {
if (*prev == decl) {
*prev = decl->nextInFile;
decl->nextInFile = NULL;
return;
}
prev = &(*prev)->nextInFile;
}
}
/*
===================
idDeclManagerLocal::FreeDeclLocal
===================
*/
void idDeclManagerLocal::FreeDeclLocal(idDeclLocal* decl) {
if (decl == NULL) {
return;
}
if (decl->self != NULL) {
decl->self->FreeData();
delete decl->self;
decl->self = NULL;
}
if (decl->textSource != NULL) {
Mem_Free(decl->textSource);
decl->textSource = NULL;
}
delete decl;
}
/*
===================
idDeclManagerLocal::DeleteDecl
===================
*/
bool idDeclManagerLocal::DeleteDecl(declType_t type, const char* name, bool deleteSourceText) {
int typeIndex = (int)type;
if (typeIndex < 0 || typeIndex >= declTypes.Num() || declTypes[typeIndex] == NULL) {
common->FatalError("idDeclManager::DeleteDecl: bad type: %i", typeIndex);
}
idDeclLocal* decl = FindTypeWithoutParsing(type, name, false);
if (decl == NULL) {
common->Warning("idDeclManager::DeleteDecl: %s '%s' not found", declTypes[typeIndex]->typeName.c_str(), name ? name : "<NULL>");
return false;
}
if (deleteSourceText && decl->sourceFile != &implicitDecls) {
if (!decl->WriteSourceFileText("", 0)) {
return false;
}
}
RemoveDeclFromSourceFile(decl);
int oldIndex = decl->index;
int hashKey = hashTables[typeIndex].GenerateKey(decl->name.c_str(), false);
hashTables[typeIndex].RemoveIndex(hashKey, oldIndex);
linearLists[typeIndex].RemoveIndex(oldIndex);
for (int i = oldIndex; i < linearLists[typeIndex].Num(); i++) {
linearLists[typeIndex][i]->index = i;
}
FreeDeclLocal(decl);
return true;
}
/*
===============
idDeclManagerLocal::RenameDecl
@@ -2035,6 +2414,92 @@ void idDeclManagerLocal::TouchDecl_f(const idCmdArgs& args) {
}
}
/*
===================
idDeclManagerLocal::CreateDeclFile_f
===================
*/
void idDeclManagerLocal::CreateDeclFile_f(const idCmdArgs& args) {
if (args.Argc() != 3) {
common->Printf("usage: createDeclFile <type> <file>\n");
return;
}
declType_t type;
if (!DeclGetTypeFromCommandArg(args, 1, type)) {
return;
}
if (declManagerLocal.CreateDeclFile(args.Argv(2), type)) {
common->Printf("created decl file '%s'\n", args.Argv(2));
}
}
/*
===================
idDeclManagerLocal::CreateDecl_f
===================
*/
void idDeclManagerLocal::CreateDecl_f(const idCmdArgs& args) {
if (args.Argc() != 4) {
common->Printf("usage: createDecl <type> <name> <file>\n");
return;
}
declType_t type;
if (!DeclGetTypeFromCommandArg(args, 1, type)) {
return;
}
idDecl* decl = declManagerLocal.CreateNewDecl(type, args.Argv(2), args.Argv(3), true);
if (decl != NULL) {
common->Printf("created %s '%s' in '%s'\n", declManagerLocal.GetDeclNameFromType(type), decl->GetName(), decl->GetFileName());
}
}
/*
===================
idDeclManagerLocal::SaveDecl_f
===================
*/
void idDeclManagerLocal::SaveDecl_f(const idCmdArgs& args) {
if (args.Argc() != 3) {
common->Printf("usage: saveDecl <type> <name>\n");
return;
}
declType_t type;
if (!DeclGetTypeFromCommandArg(args, 1, type)) {
return;
}
if (declManagerLocal.SaveDecl(type, args.Argv(2))) {
common->Printf("saved %s '%s'\n", declManagerLocal.GetDeclNameFromType(type), args.Argv(2));
}
}
/*
===================
idDeclManagerLocal::DeleteDecl_f
===================
*/
void idDeclManagerLocal::DeleteDecl_f(const idCmdArgs& args) {
if (args.Argc() != 3) {
common->Printf("usage: deleteDecl <type> <name>\n");
return;
}
declType_t type;
if (!DeclGetTypeFromCommandArg(args, 1, type)) {
return;
}
if (declManagerLocal.DeleteDecl(type, args.Argv(2), true)) {
common->Printf("deleted %s '%s'\n", declManagerLocal.GetDeclNameFromType(type), args.Argv(2));
}
}
/*
===================
idDeclManagerLocal::FindTypeWithoutParsing
@@ -2104,6 +2569,7 @@ idDeclLocal::idDeclLocal
=================
*/
idDeclLocal::idDeclLocal(void) {
self = NULL;
name = "unnamed";
textSource = NULL;
textLength = 0;
@@ -2287,31 +2753,38 @@ void idDeclLocal::SetTextLocal(const char* text, const int length) {
textLength = length;
}
/*
=================
idDeclLocal::ReplaceSourceFileText
idDeclLocal::WriteSourceFileText
=================
*/
bool idDeclLocal::ReplaceSourceFileText(void) {
bool idDeclLocal::WriteSourceFileText(const char* replacementText, const int replacementLength) {
int oldFileLength, newFileLength;
char* buffer;
idFile* file;
common->Printf("Writing \'%s\' to \'%s\'...\n", GetName(), GetFileName());
if (replacementText == NULL || replacementLength < 0) {
common->Warning("idDeclLocal::WriteSourceFileText: bad replacement text for %s", GetName());
return false;
}
if (sourceFile == &declManagerLocal.implicitDecls) {
if (sourceFile == NULL || sourceFile == &declManagerLocal.implicitDecls) {
common->Warning("Can't save implicit declaration %s.", GetName());
return false;
}
// get length and allocate buffer to hold the file
oldFileLength = sourceFile->fileSize;
newFileLength = oldFileLength - sourceTextLength + textLength;
buffer = (char*)Mem_Alloc(Max(newFileLength, oldFileLength));
if (sourceTextOffset < 0 || sourceTextOffset > oldFileLength || sourceTextLength < 0 || sourceTextOffset + sourceTextLength > oldFileLength) {
common->Warning("Decl %s has an invalid source range in %s.", GetName(), GetFileName());
return false;
}
// read original file
if (sourceFile->fileSize) {
newFileLength = oldFileLength - sourceTextLength + replacementLength;
buffer = (char*)Mem_Alloc(Max(Max(newFileLength, oldFileLength), 1));
// read original file if it is known to exist
if (sourceFile->timestamp != 0 || sourceFile->fileSize > 0) {
file = fileSystem->OpenFileRead(GetFileName());
if (!file) {
Mem_Free(buffer);
@@ -2320,12 +2793,15 @@ bool idDeclLocal::ReplaceSourceFileText(void) {
}
if (file->Length() != sourceFile->fileSize || file->Timestamp() != sourceFile->timestamp) {
fileSystem->CloseFile(file);
Mem_Free(buffer);
common->Warning("The file %s has been modified outside of the engine.", GetFileName());
return false;
}
file->Read(buffer, oldFileLength);
if (oldFileLength > 0) {
file->Read(buffer, oldFileLength);
}
fileSystem->CloseFile(file);
if (MD5_BlockChecksum(buffer, oldFileLength) != sourceFile->checksum) {
@@ -2335,11 +2811,18 @@ bool idDeclLocal::ReplaceSourceFileText(void) {
}
}
// insert new text
char* declText = (char*)_alloca(textLength + 1);
GetText(declText);
memmove(buffer + sourceTextOffset + textLength, buffer + sourceTextOffset + sourceTextLength, oldFileLength - sourceTextOffset - sourceTextLength);
memcpy(buffer + sourceTextOffset, declText, textLength);
int oldLineBreaks = DeclCountLineBreaks(buffer + sourceTextOffset, sourceTextLength);
int newLineBreaks = DeclCountLineBreaks(replacementText, replacementLength);
int textDelta = replacementLength - sourceTextLength;
int lineDelta = newLineBreaks - oldLineBreaks;
// insert replacement text
memmove(buffer + sourceTextOffset + replacementLength,
buffer + sourceTextOffset + sourceTextLength,
oldFileLength - sourceTextOffset - sourceTextLength);
if (replacementLength > 0) {
memcpy(buffer + sourceTextOffset, replacementText, replacementLength);
}
// write out new file
file = fileSystem->OpenFileWrite(GetFileName(), "fs_devpath");
@@ -2348,30 +2831,51 @@ bool idDeclLocal::ReplaceSourceFileText(void) {
common->Warning("Couldn't open %s for writing.", GetFileName());
return false;
}
file->Write(buffer, newFileLength);
if (newFileLength > 0) {
file->Write(buffer, newFileLength);
}
fileSystem->CloseFile(file);
// set new file size, checksum and timestamp
// set new file size, checksum, timestamp, and line count
sourceFile->fileSize = newFileLength;
sourceFile->checksum = MD5_BlockChecksum(buffer, newFileLength);
sourceFile->numLines = DeclCountFileLines(buffer, newFileLength);
fileSystem->ReadFile(GetFileName(), NULL, &sourceFile->timestamp);
// free buffer
Mem_Free(buffer);
// move all decls in the same file
for (idDeclLocal* decl = sourceFile->decls; decl; decl = decl->nextInFile) {
if (decl->sourceTextOffset > sourceTextOffset) {
decl->sourceTextOffset += textLength - sourceTextLength;
if (decl != this && decl->sourceTextOffset > sourceTextOffset) {
decl->sourceTextOffset += textDelta;
decl->sourceLine += lineDelta;
}
}
// set new size of text in source file
sourceTextLength = textLength;
sourceTextLength = replacementLength;
sourceLine = DeclLineForOffset(buffer, sourceTextOffset);
Mem_Free(buffer);
return true;
}
/*
=================
idDeclLocal::ReplaceSourceFileText
=================
*/
bool idDeclLocal::ReplaceSourceFileText(void) {
if (textSource == NULL) {
common->Warning("Decl %s has no text to save.", GetName());
return false;
}
common->Printf("Writing \'%s\' to \'%s\'...\n", GetName(), GetFileName());
char* declText = (char*)_alloca(textLength + 1);
GetText(declText);
return WriteSourceFileText(declText, textLength);
}
/*
=================
idDeclLocal::SourceFileChanged