// Filename: generic_stuff.cpp // #include "stdafx.h" #include "includes.h" #include "MainFrm.h" // #include "generic_stuff.h" #define BASEDIRNAME "base" #define BASEDIRNAME_XMEN "development" // kept as non-hungarian labels purely because these 2 are so common in our projects... // char qdir[1024]={0}; // "S:\" char gamedir[1024]={0}; // "S:\\baseq3\\" // unlike "normal" SetQdirFromPath() functions, I need to see if qdir has changed // (ie by loading an EF model over an SOF model) which could mean that we're in a different dir, and so // should lose all cached textures etc... // bool bXMenPathHack = false; bool bQ3RulesApply = true; static bool SetQdirFromPath2( const char *path, const char *psBaseDir ); void SetQdirFromPath( const char *path ) { char prevQdir[1024]; strcpy(prevQdir,qdir); bXMenPathHack = false; // MUST be here if (SetQdirFromPath2(path,BASEDIRNAME)) { bQ3RulesApply = true; } else { if (SetQdirFromPath2(path,BASEDIRNAME_XMEN)) { bQ3RulesApply = false; bXMenPathHack = true; } } if (stricmp(prevQdir,qdir)) { extern void Media_Delete(void); Media_Delete(); } } static bool SetQdirFromPath2( const char *path, const char *psBaseDir ) { // static bool bDone = false; // if (!bDone) { // bDone = true; char temp[1024]; strcpy(temp,path); path = temp; const char *c; const char *sep; int len, count; // if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':')) // { // path is partial // Q_getwd (temp); // strcat (temp, path); // path = temp; // } _strlwr((char*)path); // search for "base" in path from the RIGHT hand side (and must have a [back]slash just before it) len = strlen(psBaseDir); for (c=path+strlen(path)-1 ; c != path ; c--) { int i; if (!strnicmp (c, psBaseDir, len) && (*(c-1) == '/' || *(c-1) == '\\') // would be more efficient to do this first, but only checking after a strncasecmp ok ensures no invalid pointer-1 access ) { sep = c + len; count = 1; while (*sep && *sep != '/' && *sep != '\\') { sep++; count++; } strncpy (gamedir, path, c+len+count-path); gamedir[c+len+count-path]='\0'; for ( i = 0; i < (int)strlen( gamedir ); i++ ) { if ( gamedir[i] == '\\' ) gamedir[i] = '/'; } // qprintf ("gamedir: %s\n", gamedir); strncpy (qdir, path, c-path); qdir[c-path] = 0; for ( i = 0; i < (int)strlen( qdir ); i++ ) { if ( qdir[i] == '\\' ) qdir[i] = '/'; } // qprintf ("qdir: %s\n", qdir); return true; } } // Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path); } return false; } // takes (eg) "q:\quake\baseq3\textures\borg\name.tga" // // and produces "textures/borg/name.tga" // void Filename_RemoveQUAKEBASE(CString &string) { string.Replace("\\","/"); string.MakeLower(); /* int loc = string.Find("/quake"); if (loc >=0 ) { loc = string.Find("/",loc+1); if (loc >=0) { // now pointing at "baseq3", "demoq3", whatever... loc = string.Find("/", loc+1); if (loc >= 0) { // now pointing at local filename... // string = string.Mid(loc+1); } } } */ // SetQdirFromPath( string ); string.Replace( gamedir, "" ); } bool FileExists (LPCSTR psFilename) { FILE *handle = fopen(psFilename, "r"); if (!handle) { return false; } fclose (handle); return true; } long FileLen( LPCSTR psFilename) { FILE *handle = fopen(psFilename, "r"); if (!handle) { return -1; } long l = filesize(handle); fclose (handle); return l; } // returns actual filename only, no path // char *Filename_WithoutPath(LPCSTR psFilename) { static char sString[MAX_PATH]; /* LPCSTR p = strrchr(psFilename,'\\'); if (!p++) { p = strrchr(psFilename,'/'); if (!p++) p=psFilename; } strcpy(sString,p); */ LPCSTR psCopyPos = psFilename; while (*psFilename) { if (*psFilename == '/' || *psFilename == '\\') psCopyPos = psFilename+1; psFilename++; } strcpy(sString,psCopyPos); return sString; } // returns (eg) "\dir\name" for "\dir\name.bmp" // char *Filename_WithoutExt(LPCSTR psFilename) { static char sString[MAX_PATH]; strcpy(sString,psFilename); char *p = strrchr(sString,'.'); char *p2= strrchr(sString,'\\'); char *p3= strrchr(sString,'/'); // special check, make sure the first suffix we found from the end wasn't just a directory suffix (eg on a path'd filename with no extension anyway) // if (p && (p2==0 || (p2 && p>p2)) && (p3==0 || (p3 && p>p3)) ) *p=0; return sString; } // loses anything after the path (if any), (eg) "\dir\name.bmp" becomes "\dir" // char *Filename_PathOnly(LPCSTR psFilename) { static char sString[MAX_PATH]; strcpy(sString,psFilename); // for (int i=0; ip2)?p1:p2; if (p) *p=0; return sString; } // returns filename's extension only (including '.'), else returns original string if no '.' in it... // char *Filename_ExtOnly(LPCSTR psFilename) { static char sString[MAX_PATH]; LPCSTR p = strrchr(psFilename,'.'); if (!p) p=psFilename; strcpy(sString,p); return sString; } // used when sending output to a text file etc, keeps columns nice and neat... // char *String_EnsureMinLength(LPCSTR psString, int iMinLength) { static char sString[8][1024]; static int i=0; i=(i+1)&7; strcpy(sString[i],psString); // a bit slow and lazy, but who cares?... // while (strlen(sString[i])<(UINT)iMinLength) strcat(sString[i]," "); return sString[i]; } // similar to strlwr, but (crucially) doesn't touch original... // char *String_ToLower(LPCSTR psString) { static char sString[MAX_PATH]; strcpy(sString,psString); return strlwr(sString); } // similar to strupr, but (crucially) doesn't touch original... // char *String_ToUpper(LPCSTR psString) { static char sString[MAX_PATH]; strcpy(sString,psString); return strupr(sString); } char *String_ForwardSlash(LPCSTR psString) { static char sString[MAX_PATH]; strcpy(sString,psString); char *p; while ( (p=strchr(sString,'\\')) != NULL) { *p = '/'; } return strlwr(sString); } char *String_RemoveOccurences(LPCSTR psString, LPCSTR psSubStr) { static CString str; str = psString; str.Replace(psSubStr,""); return const_cast < char * > ((LPCSTR) str); // :-) } char *va(char *format, ...) { va_list argptr; static char string[16][16384]; // important to have a good depth to this. 16 is nice static index = 0; index = (++index)&15; va_start (argptr, format); // vsprintf (string[index], format,argptr); _vsnprintf(string[index], sizeof(string[0]), format, argptr); va_end (argptr); string[index][sizeof(string[0])-1] = '\0'; return string[index]; } // returns a path to somewhere writeable, without trailing backslash... // // (for extra speed now, only evaluates it on the first call, change this if you like) // char *scGetTempPath(void) { static char sBuffer[MAX_PATH]; DWORD dwReturnedSize; static int i=0; if (!i++) { dwReturnedSize = GetTempPath(sizeof(sBuffer),sBuffer); if (dwReturnedSize>sizeof(sBuffer)) { // temp path too long to return, so forget it... // strcpy(sBuffer,"c:"); // "c:\\"); // should be writeable } // strip any trailing backslash... // if (sBuffer[strlen(sBuffer)-1]=='\\') sBuffer[strlen(sBuffer)-1]='\0'; }// if (!i++) return sBuffer; } // psInitialSaveName can be "" if not bothered LPCSTR InputSaveFileName(LPCSTR psInitialSaveName, LPCSTR psCaption, LPCSTR psInitialPath, LPCSTR psFilter, LPCSTR psExtension) { CFileStatus Filestatus; CFile File; static char name[MAX_PATH]; CString strInitialSaveName(psInitialSaveName); strInitialSaveName.Replace("/","\\"); // or windows immediately cancels the dialog CFileDialog FileDlg(FALSE, psExtension, strInitialSaveName, OFN_OVERWRITEPROMPT|OFN_CREATEPROMPT, psFilter, //TEXT("Map Project Files (*.mpj)|*.lit|Other Map Files (*.smd/*.sc2)|*.sc2;*.smd|FastMap Files (*.fmf)|*.fmf|All Files(*.*)|*.*||"), //Map Object Files|*.sms||"), AfxGetMainWnd() ); // FileDlg.m_ofn.lpstrInitialDir=psInitialPath; // FileDlg.m_ofn.lpstrTitle=psCaption; // strcpy(name,psInitialSaveName); // FileDlg.m_ofn.lpstrFile=name; if (FileDlg.DoModal() == IDOK) { static CString strName; strName = FileDlg.GetPathName(); return strName; } return NULL; } // "psInitialLoadName" param can be "" if not bothered, "psInitialDir" can be NULL to open to last browse-dir // // psFilter example: TEXT("Model files (*.glm)|*.glm|All Files(*.*)|*.*||") // LPCSTR psFilter // // there is too much crap in here, and some needless code, fix it sometime... (yeah, right) // LPCSTR InputLoadFileName(LPCSTR psInitialLoadName, LPCSTR psCaption, LPCSTR psInitialDir, LPCSTR psFilter) { CFileStatus Filestatus; CFile File; static char name[MAX_PATH]; CFileDialog FileDlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST, //TEXT("Map Project Files (*.mpj)|*.lit|Other Map Files (*.smd/*.sc2)|*.sc2;*.smd|FastMap Files (*.fmf)|*.fmf|All Files(*.*)|*.*||"), //Map Object Files|*.sms||"), psFilter, //Map Object Files|*.sms||"), AfxGetMainWnd()); static CString strInitialDir; if (psInitialDir) strInitialDir = psInitialDir; strInitialDir.Replace("/","\\"); FileDlg.m_ofn.lpstrInitialDir = (LPCSTR) strInitialDir; FileDlg.m_ofn.lpstrTitle=psCaption; // Load Editor Model"; CString strInitialLoadName(psInitialLoadName); strInitialLoadName.Replace("/","\\"); strcpy(name,(LPCSTR)strInitialLoadName); FileDlg.m_ofn.lpstrFile=name; if (FileDlg.DoModal() == IDOK) { return name; } return NULL; } // these MUST all be MB_TASKMODAL boxes now!! // bool gbErrorBox_Inhibit = false; // Keith wanted to be able to remote-deactivate these... string strLastError; LPCSTR ModView_GetLastError() // function for him to be able to interrogate if he's disabled the error boxes { return strLastError.c_str(); } extern bool Gallery_Active(); extern void Gallery_AddError (LPCSTR psText); extern void Gallery_AddInfo (LPCSTR psText); extern void Gallery_AddWarning (LPCSTR psText); void ErrorBox(const char *sString) { if (Gallery_Active()) { Gallery_AddError(sString); Gallery_AddError("\n"); return; } if (!gbErrorBox_Inhibit) { MessageBox( NULL, sString, "Error", MB_OK|MB_ICONERROR|MB_TASKMODAL ); } strLastError = sString; } void InfoBox(const char *sString) { if (Gallery_Active()) { Gallery_AddInfo(sString); Gallery_AddInfo("\n"); return; } MessageBox( NULL, sString, "Info", MB_OK|MB_ICONINFORMATION|MB_TASKMODAL ); } void WarningBox(const char *sString) { if (Gallery_Active()) { Gallery_AddWarning(sString); Gallery_AddWarning("\n"); return; } MessageBox( NULL, sString, "Warning", MB_OK|MB_ICONWARNING|MB_TASKMODAL ); } bool GetYesNo(const char *psQuery) { if (Gallery_Active()) { Gallery_AddWarning("GetYesNo call (... to which I guessed 'NO' ) using this query...\n\n"); Gallery_AddWarning(psQuery); Gallery_AddWarning("\n"); return false; } //#define GetYesNo(psQuery) (!!(MessageBox(AppVars.hWnd,psQuery,"Query",MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES)) #define _GetYesNo(psQuery) (!!(AfxMessageBox(psQuery, MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES)) return _GetYesNo(psQuery); } void StatusMessage(LPCSTR psString) // param can be NULL to indicate fallback to "ready" or whatever you want { CMainFrame* pMainFrame = (CMainFrame*) AfxGetMainWnd(); if (pMainFrame) { pMainFrame->StatusMessage(psString); } } /* this piece copied out of on-line examples, it basically works as a similar function to Ffilelength(int handle), but it works with streams */ long filesize(FILE *handle) { long curpos, length; curpos = ftell(handle); fseek(handle, 0L, SEEK_END); length = ftell(handle); fseek(handle, curpos, SEEK_SET); return length; } // returns -1 for error int LoadFile (LPCSTR psPathedFilename, void **bufferptr, int bReportErrors) { FILE *f; int length; void *buffer; f = fopen(psPathedFilename,"rb"); if (f) { length = filesize(f); buffer = malloc (length+1); ((char *)buffer)[length] = 0; int lread = fread (buffer,1,length, f); fclose (f); if (lread==length) { *bufferptr = buffer; return length; } free(buffer); } extern bool gbInImageLoader; // tacky, but keeps quieter errors if (bReportErrors && !gbInImageLoader) { ErrorBox(va("Error reading file %s!",psPathedFilename)); } return -1; } // returns -1 for error int SaveFile (LPCSTR psPathedFilename, const void *pBuffer, int iSize) { extern void CreatePath (const char *path); CreatePath(psPathedFilename); FILE *f = fopen(psPathedFilename,"wb"); if (f) { int iLength = fwrite(pBuffer, 1, iSize, f); fclose (f); if (iLength == iSize) { return iLength; } ErrorBox(va("Error writing file \"%s\" (length %d), only %d bytes written!",psPathedFilename,iSize,iLength)); return -1; } ErrorBox(va("Error opening file \"%s\" for writing!",psPathedFilename)); return -1; } // this'll return a string of up to the first 4095 chars of a system error message... // LPCSTR SystemErrorString(DWORD dwError) { static char sString[4096]; LPVOID lpMsgBuf=0; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); ZEROMEM(sString); strncpy(sString,(LPCSTR) lpMsgBuf,sizeof(sString)-1); LocalFree( lpMsgBuf ); return sString; } void SystemErrorBox(DWORD dwError) { ErrorBox( SystemErrorString(dwError) ); } LPCSTR scGetComputerName(void) { static char cTempBuffer[128]; // well ott for laziness DWORD dwTempBufferSize; static int i=0; if (!i++) { dwTempBufferSize = (sizeof (cTempBuffer))-1; strcpy(cTempBuffer,""); if (!GetComputerName(cTempBuffer, &dwTempBufferSize)) strcpy(cTempBuffer,"Unknown"); // error retrieving host computer name } return &cTempBuffer[0]; } LPCSTR scGetUserName(void) { static char cTempBuffer[128]; DWORD dwTempBufferSize; static int i=0; if (!i++) { dwTempBufferSize = (sizeof (cTempBuffer))-1; strcpy(cTempBuffer,""); if (!GetUserName(cTempBuffer, &dwTempBufferSize)) strcpy(cTempBuffer,"Unknown"); // error retrieving host computer name } return &cTempBuffer[0]; } bool TextFile_Read(CString &strFile, LPCSTR psFullPathedFilename, bool bLoseSlashSlashREMs /* = true */, bool bLoseBlankLines /* = true */) { FILE *fhTextFile = fopen(psFullPathedFilename,"rt"); if (fhTextFile) { char sLine[32768]; // sod it, should be enough for one line. char *psLine; strFile.Empty(); while ((psLine = fgets( sLine, sizeof(sLine), fhTextFile ))!=NULL) { if (bLoseSlashSlashREMs && !strncmp(psLine,"//",2)) { // do nothing } else { // lose any whitespace to either side CString strTemp(psLine); strTemp.TrimLeft(); strTemp.TrimRight(); strTemp+="\n"; // restore the CR that got trimmed off by TrimRight() if (bLoseBlankLines && (strTemp.IsEmpty() || strTemp.GetAt(0)=='\n')) { // do nothing } else { strFile += strTemp; } } } fclose(fhTextFile); } return !!fhTextFile; } bool SendFileToNotepad(LPCSTR psFilename) { bool bReturn = false; char sExecString[MAX_PATH]; sprintf(sExecString,"notepad %s",psFilename); if (WinExec(sExecString, // LPCSTR lpCmdLine, // address of command line SW_SHOWNORMAL // UINT uCmdShow // window style for new application ) >31 // don't ask me, Windoze just uses >31 as OK in this call. ) { // ok... // bReturn = true; } else { ErrorBox("Unable to locate/run NOTEPAD on this machine!\n\n(let me know about this -Ste)"); } return bReturn; } // creates as temp file, then spawns notepad with it... // bool SendStringToNotepad(LPCSTR psWhatever, LPCSTR psLocalFileName) { bool bReturn = false; LPCSTR psOutputFileName = va("%s\\%s",scGetTempPath(),psLocalFileName); FILE *handle = fopen(psOutputFileName,"wt"); if (handle) { fprintf(handle,psWhatever); fclose(handle); bReturn = SendFileToNotepad(psOutputFileName); } else { ErrorBox(va("Unable to create file \"%s\" for notepad to use!",psOutputFileName)); } return bReturn; } ////////////////////////// eof ///////////////////////////