1 // Config.cpp: implementation of the CConfigFile class.
2 //
3 /////////////////////////////////////////////////////////////////////////////
4 // Name: config.cpp
5 // Purpose: Application configuration class, deal with configuration automatically
6 // Author: PCMan (HZY) http://pcman.ptt.cc/
7 // E-mail: pcman.tw@gmail.com
8 // Created: 2004.7.22
9 // Copyright: (C) 2004 PCMan
10 // Licence: GPL : http://www.gnu.org/licenses/gpl.html
11 // Modified by:
12 /////////////////////////////////////////////////////////////////////////////
13
14 #ifdef __GNUG__
15 #pragma implementation "configfile.h"
16 #endif
17
18
19 // Copyright (C) 2004 PCMan
20 // Author: PCMan (HZY) 2004/07/22 07:51 AM
21 // I finally came up with a really smart way to maintain ini file.
22 // Every time I add a variable to CAppConfig, all I need to do is
23 // adding the variable in my "Config Table," and all the data will
24 // be load and save automatically. This is not the most efficient way.
25 // In my first version I use some more efficient method, but at last I change
26 // my code to what it is now. Because I think in a program not time-critical,
27 // easy-maintaining is much more important.
28
29 #include "configfile.h"
30 #include <cstdio>
31 #include <cstdlib>
32 #include <cstring>
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36
37 #include <gdk/gdk.h>
38 #include <glib.h>
39
40 #include "stringutil.h"
41
42 //////////////////////////////////////////////////////////////////////
43 // Construction/Destruction
44 //////////////////////////////////////////////////////////////////////
45
46
CConfigFile(string AppName,int LineBufSize)47 CConfigFile::CConfigFile( string AppName, int LineBufSize )
48 : m_pCurSect(NULL),
49 m_pRootMap(NULL)
50 {
51 m_AppName = AppName;
52 m_LineBufSize = LineBufSize;
53
54 m_ConfigDirPath = getenv("HOME");
55 if( m_ConfigDirPath[m_ConfigDirPath.length()-1] != '/' )
56 m_ConfigDirPath += '/';
57
58 m_ConfigDirPath += '.';
59 m_ConfigDirPath += m_AppName;
60
61 if(!g_file_test(m_ConfigDirPath.c_str(),
62 GFileTest(G_FILE_TEST_IS_DIR|G_FILE_TEST_EXISTS)) )
63 mkdir(m_ConfigDirPath.c_str(), 0777);
64
65 m_ConfigDirPath += "/";
66
67 m_DataDirPath = DATADIR "/" + AppName;
68
69 if( g_file_test(m_DataDirPath.c_str(),
70 GFileTest(G_FILE_TEST_IS_DIR|G_FILE_TEST_EXISTS)) )
71 m_DataDirPath += "/";
72 else
73 m_DataDirPath = m_ConfigDirPath;
74 }
75
~CConfigFile()76 CConfigFile::~CConfigFile()
77 {
78 }
79
80
81
Load()82 bool CConfigFile::Load()
83 {
84 return DoDataExchange(true); // call virtual function defined in derived class.
85 }
86
DoLoad()87 bool CConfigFile::DoLoad()
88 {
89 FILE* fp = fopen( GetConfigPath().c_str() ,"r");
90 if(fp)
91 {
92 char* line = new char[m_LineBufSize];
93 while( fgets( line, m_LineBufSize, fp) )
94 {
95 char* keyname = strtok( line, " =\n");
96 if( !keyname ) continue;
97 if( keyname[0] == '[' ) // This line doesn't contain any value.
98 {
99 keyname = strtok( line, "[]\n" );
100 if( keyname ) // Find a section.
101 {
102 CConfigEntry* pent = m_pRootMap;
103 for( ; pent->m_Name; pent++ )
104 {
105 if( 0 == strcmp(keyname, pent->m_Name ) )
106 {
107 m_pCurSect = (CConfigEntry*)pent->m_pData;
108 break;
109 }
110 }
111 continue;
112 }
113 }
114 char* pstrval = strtok( NULL, "=\n");
115 if( !pstrval ) continue;
116
117 CConfigEntry* pent = m_pCurSect;
118 for( ; pent->m_Name; pent++ )
119 {
120 if( 0 == strcmp(keyname, pent->m_Name ) )
121 break;
122 }
123
124 if( pent->m_Name )
125 {
126 switch( pent->m_DataType )
127 {
128 case CConfigEntry::VT_BOOL:
129 *((bool*)pent->m_pData) = atoi(pstrval);
130 break;
131 case CConfigEntry::VT_INT:
132 *((int*)pent->m_pData) = atoi(pstrval);
133 break;
134 case CConfigEntry::VT_STR:
135 *((string*)pent->m_pData) = pstrval;
136 break;
137 case CConfigEntry::VT_ESTR:
138 *((string*)pent->m_pData) = UnEscapeStr( pstrval );
139 break;
140 case CConfigEntry::VT_COLOR:
141 {
142 int r,g,b;
143 if( 3 == sscanf( pstrval, "%d,%d,%d", &r, &g, &b ) )
144 {
145 // ((wxColour*)pent->m_pData)->Set( r, g, b );
146 GdkColor* clr = (GdkColor*)pent->m_pData;
147 clr->red = r*(65536/256);
148 clr->green = g*(65536/256);
149 clr->blue = b*(65536/256);
150 }
151 }
152 break;
153 case CConfigEntry::VT_SHORT:
154 *((short*)pent->m_pData) = atoi(pstrval);
155 break;
156 default:
157 break; // This shouldn't happen.
158 }
159 }
160 }
161 fclose(fp);
162 delete []line;
163 }
164 return fp;
165 }
166
Save()167 bool CConfigFile::Save()
168 {
169 return DoDataExchange(false); // call virtual function defined in derived class.
170 }
171
DoSave()172 bool CConfigFile::DoSave()
173 {
174 FILE* fp = fopen( GetConfigPath().c_str() ,"w");
175 if(fp)
176 {
177 string esc_str;
178 for( ; m_pRootMap->m_Name; m_pRootMap++ )
179 {
180 m_pCurSect = (CConfigEntry*)m_pRootMap->m_pData;
181 fprintf(fp, "[%s]\n", m_pRootMap->m_Name );
182
183 char strval[32]; const char* pstrval;
184 for( ; m_pCurSect->m_Name; m_pCurSect++ )
185 {
186 pstrval = strval;
187 switch( m_pCurSect->m_DataType )
188 {
189 case CConfigEntry::VT_BOOL:
190 sprintf(strval,"%d", (int)*((bool*)m_pCurSect->m_pData));
191 break;
192 case CConfigEntry::VT_INT:
193 sprintf(strval,"%d", *((int*)m_pCurSect->m_pData) );
194 break;
195 case CConfigEntry::VT_STR:
196 pstrval = ((string*)m_pCurSect->m_pData)->c_str();
197 break;
198 case CConfigEntry::VT_ESTR:
199 esc_str = EscapeStr( ((string*)m_pCurSect->m_pData)->c_str() );
200 pstrval = esc_str.c_str();
201 break;
202 case CConfigEntry::VT_COLOR:
203 {
204 // wxColour& clr = *((wxColour*)m_pCurSect->m_pData);
205 GdkColor& clr = *((GdkColor*)m_pCurSect->m_pData);
206 sprintf( strval, "%d,%d,%d", clr.red*256/65536, clr.green*256/65536, clr.blue*256/65536 );
207 }
208 break;
209 case CConfigEntry::VT_SHORT:
210 sprintf(strval,"%d", *((short*)m_pCurSect->m_pData) );
211 break;
212 default: // This shouldn't happen.
213 break;
214 }
215 fprintf(fp, "%s=%s\n", m_pCurSect->m_Name, pstrval );
216 }
217 fputs( "\n", fp );
218 }
219 fclose(fp);
220 }
221 return fp;
222 }
223
DoDataExchange(bool bLoad)224 bool CConfigFile::DoDataExchange( bool bLoad )
225 {
226 return bLoad ? DoLoad():DoSave();
227 }
228
GetConfigPath(string FileName)229 string CConfigFile::GetConfigPath( string FileName )
230 {
231 string path = m_ConfigDirPath;
232 path += FileName;
233
234 return path;
235 }
236
GetDataPath(string FileName)237 string CConfigFile::GetDataPath( string FileName )
238 {
239 // Windows NT or UNIX-like systems
240 string path = GetConfigPath(FileName);
241 // if( ::wxFileExists( path ) ) // Find the same file in users' home dir first.
242 FILE *fp;
243 if( (fp = fopen(path.c_str(), "r")) )
244 {
245 fclose(fp);
246 return path;
247 }
248 path = m_DataDirPath;
249 path += FileName;
250 return path;
251 }
252
253 /*
254 string CConfigFile::GetExecPath(const char* exec_name)
255 {
256 const char* ppaths = getenv("PATH");
257 if( !ppaths || !*ppaths )
258 ppaths = "/usr/local/bin:/usr/bin:/bin";
259 char *dirs = strdup(ppaths);
260 for( char* dir = strtok(dirs, ":"); dir && *dir; dir=strtok(NULL, ":") )
261 {
262 string path(dir);
263 if( '/' != path[path.length()-1] )
264 path += '/';
265 path += exec_name;
266 if( g_file_test( path.c_str(), G_FILE_TEST_EXISTS )
267 && g_file_test( path.c_str(), G_FILE_TEST_IS_EXECUTABLE ) )
268 {
269 free(dirs);
270 return path;
271 }
272 }
273 free(dirs);
274 }
275 */
276