// This file is a part of Framsticks SDK. http://www.framsticks.com/ // Copyright (C) 1999-2015 Maciej Komosinski and Szymon Ulatowski. // See LICENSE.txt for details. #include "stl-util.h" #include #include #include "nonstd_stdio.h" #include "Convert.h" #include "nonstd.h" #include "log.h" #include #ifdef USE_VIRTFILE #include #endif #ifdef __BORLANDC__ #define va_copy(to,from) to=from //borland does not have va_copy() at all; va_list is just a pointer in borland #endif string ssprintf_va(const char* format, va_list ap) { string s; //clang crashed when this declaration was in s=buf int size = 256; char* buf; va_list ap_copy; // "va_list ap" can only by used once by printf-type functions as they advance the current argument pointer (crashed on linux x86_64) // (does not apply to SString::sprintf, it does not have the va_list variant) //almost like SString::sprintf, but there is no common code to share because SString can use its directWrite to avoid double allocating/copying #ifdef USE_VSCPRINTF va_copy(ap_copy, ap); size = _vscprintf(format, ap_copy) + 1; //+1 for terminating null character va_end(ap_copy); #endif while (1) { buf = (char*)malloc(size); assert(buf != NULL); va_copy(ap_copy, ap); int n = vsnprintf(buf, size, format, ap_copy); va_end(ap_copy); if (n > -1 && n < size) { s = buf; free(buf); return s; } #ifdef VSNPRINTF_RETURNS_REQUIRED_SIZE if (n > -1) /* glibc 2.1 */ size = n+1; /* precisely what is needed */ else /* glibc 2.0 */ #endif size *= 2; /* twice the old size */ free(buf); } } char* strmove(char *a, char *b) //strcpy that works well for overlapping strings ("Source and destination overlap") { if (a == NULL || b == NULL) return NULL; memmove(a, b, strlen(b) + 1); return a; } string ssprintf(const char* format, ...) { va_list ap; va_start(ap, format); string ret = ssprintf_va(format, ap); //is it too wasteful? copying the string again... unless the compiler can handle it better va_end(ap); return ret; } bool readCompleteFile(const char* filename, vector& data, bool warn_on_missing_file) { bool ok = false; #ifdef USE_VIRTFILE // if (!isAbsolutePath(filename)) { VirtFILE *f=Vfopen(filename,FOPEN_READ_BINARY); if (f) { int size=f->getSize(); data.resize(size); int przeczytane = f->Vread(&data[0], size, 1); ok = przeczytane == 1; delete f; } } // else #endif { MFILE *f = mfopen(filename, FOPEN_READ_BINARY); if (f) { int size = getFileSize(f); data.resize(size); int przeczytane = mfread(&data[0], size, 1, f); mfclose(f); ok = przeczytane == 1; } } if (warn_on_missing_file && !ok) logPrintf("stl-util", "readCompleteFile", LOG_WARN, "Couldn't open file '%s'", filename); return ok; } bool readCompleteFile(const char* filename, string& out, bool warn_on_missing_file) { vector data; if (readCompleteFile(filename, data, warn_on_missing_file)) { out = string(&data[0], data.size()); return true; } return false; } bool writeCompleteFile(const char* filename, const string& text, bool warn_on_fail) { #ifdef USE_VIRTFILE VirtFILE *f = Vfopen(filename, FOPEN_WRITE_BINARY); bool ok = f != NULL; if (f) { int zapisane = f->Vwrite(text.c_str(), text.length(), 1); delete f; ok &= zapisane == 1; } #else MFILE *f = mfopen(filename, FOPEN_WRITE_BINARY); bool ok = f != NULL; if (f) { int zapisane = mfwrite(text.c_str(), text.length(), 1, f); mfclose(f); ok &= zapisane == 1; } #endif if (warn_on_fail && !ok) logPrintf("stl-util", "writeCompleteFile", LOG_WARN, "Couldn't write file '%s'", filename); return ok; } bool writeCompleteFile(const char* filename, vector& data, bool warn_on_fail) { string s(&data[0], data.size()); return writeCompleteFile(filename, s, warn_on_fail); } string stripExt(const string& filename) { size_t dot = filename.rfind('.'); if (dot == string::npos) return filename; size_t sep = filename.rfind(PATH_SEPARATOR_CHAR); if ((sep == string::npos) || (sep < dot)) return filename.substr(0, dot); return filename; } string stripFileDir(const string& filename) { size_t sep = filename.rfind(PATH_SEPARATOR_CHAR); if (sep == string::npos) return filename; return filename.substr(sep+1); } string getFileExt(const string& filename) { size_t dot = filename.rfind('.'); if (dot == string::npos) return string(""); size_t sep = filename.rfind(PATH_SEPARATOR_CHAR); if ((sep == string::npos) || (sep < dot)) return filename.substr(dot); return string(""); } string getFileDir(const string& filename) { size_t slash = filename.rfind(PATH_SEPARATOR_CHAR); if (slash == string::npos) return string(""); return filename.substr(0, slash); }