#include #include #include #include #include #include #include "mswint.h" #include #include #if _MSC_VER >=1400 #define stricmp _stricmp #endif char * mswStrdup( const char * ); static char appLibDirName[MAX_PATH]; static char appWorkDirName[MAX_PATH]; /** * Get the location of the shared files (parameters, help file, etc. ): This location is * derived from the modulename, ie. the directory where the exe is installed. * For an instalaltion directory of somedir/bin/xtrkcad.exe the library directory is * somedir/share/xtrkcad/ */ const char * wGetAppLibDir( void ) { char *cp; char module_name[MAX_PATH]; if (appLibDirName[0] != '\0') { return appLibDirName; } GetModuleFileName( mswHInst, module_name, sizeof module_name ); cp = strrchr( module_name, '\\' ); if (cp) { *cp = '\0'; } #ifdef XTRKCAD_CMAKE_BUILD strncpy(appLibDirName, module_name, sizeof(appLibDirName)); size_t len = sizeof(appLibDirName)-strlen(appLibDirName)-1; strncat(appLibDirName, "\\..\\share\\xtrkcad", len); _fullpath( appLibDirName, appLibDirName, MAX_PATH ); return appLibDirName; #endif strncpy(appLibDirName, module_name, sizeof(appLibDirName)); appLibDirName[sizeof(appLibDirName)-1] = '\0'; return appLibDirName; } /** * Gets the working directory for the application. At least the INI file is stored here. * The working directory can be specified manually by creating a file called xtrkcad0.ini * in the application lib dir (the directory where the .EXE is located). * * [workdir] * path=somepath * * when somepath is set to the keyword "installdir", the install directory for the EXE is * used. * * If no xtrkcad0.ini could be found, the user settings directory (appdata) is used. * */ const char * wGetAppWorkDir( void ) { char *cp; int rc; if ( appWorkDirName[0] != 0 ) { return appWorkDirName; } wGetAppLibDir(); snprintf( mswTmpBuff, sizeof(mswTmpBuff), "%s\\xtrkcad0.ini", appLibDirName ); rc = GetPrivateProfileString( "workdir", "path", "", appWorkDirName, sizeof appWorkDirName, mswTmpBuff ); if ( rc!=0 ) { if ( stricmp( appWorkDirName, "installdir" ) == 0 ) { strncpy( appWorkDirName, appLibDirName, sizeof(appWorkDirName) ); appWorkDirName[sizeof(appWorkDirName)-1] = '\0'; } else { cp = &appWorkDirName[strlen(appWorkDirName)-1]; while (cp>appWorkDirName && *cp == '\\') { *cp-- = 0; } } return appWorkDirName; } if (SHGetSpecialFolderPath( NULL, mswTmpBuff, CSIDL_APPDATA, 0 ) == 0 ) { wNoticeEx( NT_ERROR, "Cannot get user's profile directory", "Exit", NULL ); wExit(0); } else { snprintf( appWorkDirName, sizeof(appWorkDirName), "%s\\%s", mswTmpBuff, "XTrackCad" ); if( !PathIsDirectory( appWorkDirName )) { if( !CreateDirectory( appWorkDirName, NULL )) { wNoticeEx( NT_ERROR, "Cannot create user's profile directory", "Exit", NULL ); wExit(0); } } } return appWorkDirName; } /** Get the user's Documents directory. * * \return pointer to the user's Documents directory */ const char *wGetUserHomeDir( void ) { if (SHGetSpecialFolderPath( NULL, mswTmpBuff, CSIDL_PERSONAL, 0 ) == 0 ) { wNoticeEx( NT_ERROR, "Cannot get user's documents directory", "Exit", NULL ); wExit(0); return( NULL ); } else { return( mswTmpBuff ); } } typedef struct { char * section; char * name; BOOL_T present; BOOL_T dirty; char * val; } prefs_t; static dynArr_t prefs_da; #define prefs(N) DYNARR_N(prefs_t,prefs_da,N) void wPrefSetString( const char * section, const char * name, const char * sval ) { prefs_t * p; for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { if ( strcmp( p->section, section ) == 0 && strcmp( p->name, name ) == 0 ) { if (p->val) { free(p->val); } p->dirty = TRUE; p->val = mswStrdup( sval ); return; } } DYNARR_APPEND( prefs_t, prefs_da, 10 ); p = &prefs(prefs_da.cnt-1); p->name = mswStrdup(name); p->section = mswStrdup(section); p->dirty = TRUE; p->val = mswStrdup(sval); } void wPrefsLoad(char * name) { prefs_t *p; for (int i= 0; isection, p->name, "", mswTmpBuff, sizeof mswTmpBuff, name ); if (rc==0) { continue; } p->val = mswStrdup(mswTmpBuff); } } char * wPrefGetStringBasic( const char * section, const char * name ) { prefs_t * p; int rc; for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { if ( strcmp( p->section, section ) == 0 && strcmp( p->name, name ) == 0 ) { return p->val; } } rc = GetPrivateProfileString( section, name, "", mswTmpBuff, sizeof mswTmpBuff, mswProfileFile ); if (rc==0) { return NULL; } DYNARR_APPEND( prefs_t, prefs_da, 10 ); p = &prefs(prefs_da.cnt-1); p->name = mswStrdup(name); p->section = mswStrdup(section); p->dirty = FALSE; p->val = mswStrdup(mswTmpBuff); return p->val; } void wPrefSetInteger( const char * section, const char * name, long lval ) { char tmp[20]; snprintf( tmp, sizeof(tmp), "%ld", lval ); wPrefSetString( section, name, tmp ); } wBool_t wPrefGetIntegerBasic( const char * section, const char * name, long *res, long def ) { const char * cp; char * cp1; cp = wPrefGetStringBasic( section, name ); if (cp == NULL) { *res = def; return FALSE; } *res = strtol(cp,&cp1,0); if (cp==cp1) { *res = def; return FALSE; } return TRUE; } void wPrefSetFloat( const char * section, /* Section */ const char * name, /* Name */ double lval ) /* Value */ /* */ { char tmp[20]; snprintf(tmp, sizeof(tmp), "%0.6f", lval ); wPrefSetString( section, name, tmp ); } wBool_t wPrefGetFloatBasic( const char * section, /* Section */ const char * name, /* Name */ double * res, /* Address of result */ double def ) /* Default value */ /* */ { const char * cp; char * cp1; cp = wPrefGetStringBasic( section, name ); if (cp == NULL) { *res = def; return FALSE; } *res = strtod(cp, &cp1); if (cp == cp1) { *res = def; return FALSE; } return TRUE; } void wPrefFlush( char * name ) { prefs_t * p; for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { if (name && name[0]) { WritePrivateProfileString( p->section, p->name, p->val, name ); } else if (p->dirty) { WritePrivateProfileString( p->section, p->name, p->val, mswProfileFile ); } } if (name && name[0]) { WritePrivateProfileString( NULL, NULL, NULL, name ); } else { WritePrivateProfileString( NULL, NULL, NULL, mswProfileFile ); } } void wPrefReset( void ) /* */ { prefs_t * p; for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { if (p->section) { free( p->section ); } if (p->name) { free( p->name ); } if (p->val) { free( p->val ); } } prefs_da.cnt = 0; } /** * Split a line from the config file ie. an ini-file into separate tokens. The * line is split into sections, name of value and value following. Pointers * to the respective token are returned. These are zero-terminated. * If a token is not present, NULL is returned instead. * The input line is modified. * * \param line input line, modified during excution of function * \param section section if present * \param name name of config value if present * \param value name of value if present */ void wPrefTokenize(char* line, char** section, char** name, char** value) { *section = NULL; *name = NULL; *value = NULL; if (*line == '[') { *section = strtok(line, "[]"); } else { *name = strtok(line, "="); *value = strtok(NULL, "\n"); } } /** * A valid line for a config file is created from the individual elements. * Values not need for specific statement are ignored. Eg. when section is * present, name and value are not used. * The caller has to make sure, that the return buffer is large enough. * * \param section section, returned inside squared brackets * \param name name, left side of '=' * \param value value, right side of '=' * \param result pointer to buffer for formated line. */ void wPrefFormatLine(const char* section, const char* name, const char* value, char* result) { if (!value || *value == '\0') { value = ""; } if (section) { sprintf(result, "[%s]", section); } else { sprintf(result, "%s=%s", name, value); } }