f3aeef258c4fa8db1241f704dcf3451646f5bf64
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003-2009 Victor Kirhenshtein
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "libnetxms.h"
29 // Constructor for config entry
32 ConfigEntry::ConfigEntry(const TCHAR
*name
, ConfigEntry
*parent
, const TCHAR
*file
, int line
)
34 m_name
= _tcsdup(CHECK_NULL(name
));
38 parent
->addEntry(this);
41 m_file
= _tcsdup(CHECK_NULL(file
));
47 // Destructor for config entry
50 ConfigEntry::~ConfigEntry()
52 ConfigEntry
*entry
, *next
;
54 for(entry
= m_childs
; entry
!= NULL
; entry
= next
)
56 next
= entry
->getNext();
61 for(int i
= 0; i
< m_valueCount
; i
++)
62 safe_free(m_values
[i
]);
71 ConfigEntry
*ConfigEntry::findEntry(const TCHAR
*name
)
75 for(e
= m_childs
; e
!= NULL
; e
= e
->getNext())
76 if (!_tcsicmp(e
->getName(), name
))
86 const TCHAR
*ConfigEntry::getValue(int index
)
88 if ((index
< 0) || (index
>= m_valueCount
))
90 return m_values
[index
];
98 void ConfigEntry::setValue(const TCHAR
*value
)
100 for(int i
= 0; i
< m_valueCount
; i
++)
101 safe_free(m_values
[i
]);
103 m_values
= (TCHAR
**)realloc(m_values
, sizeof(TCHAR
*));
104 m_values
[0] = _tcsdup(value
);
112 void ConfigEntry::addValue(const TCHAR
*value
)
114 m_values
= (TCHAR
**)realloc(m_values
, sizeof(TCHAR
*) * (m_valueCount
+ 1));
115 m_values
[m_valueCount
] = _tcsdup(value
);
121 // Get summary length of all values as if they was concatenated with separator character
124 int ConfigEntry::getConcatenatedValuesLength()
128 if (m_valueCount
< 1)
131 for(i
= 0, len
= 0; i
< m_valueCount
; i
++)
132 len
+= _tcslen(m_values
[i
]);
133 return len
+ (m_valueCount
- 1);
138 // Constructor for config
143 m_root
= new ConfigEntry(_T("[root]"), NULL
, NULL
, 0);
159 // Default error handler
162 void Config::onError(const TCHAR
*errorMessage
)
164 _ftprintf(stderr
, _T("%s\n"), errorMessage
);
172 void Config::error(const TCHAR
*format
, ...)
178 va_start(args
, format
);
179 _vsntprintf(buffer
, 4096, format
, args
);
186 // Bind parameters to variables: simulation of old NxLoadConfig() API
189 bool Config::bindParameters(const TCHAR
*section
, NX_CFG_TEMPLATE
*cfgTemplate
)
191 TCHAR name
[MAX_PATH
], *curr
, *eptr
;
196 nx_strncpy(&name
[1], section
, MAX_PATH
- 2);
197 _tcscat(name
, _T("/"));
200 for(i
= 0; cfgTemplate
[i
].iType
!= CT_END_OF_LIST
; i
++)
202 nx_strncpy(&name
[pos
], cfgTemplate
[i
].szToken
, MAX_PATH
- pos
);
203 entry
= getEntry(name
);
206 const TCHAR
*value
= CHECK_NULL(entry
->getValue());
207 switch(cfgTemplate
[i
].iType
)
210 *((LONG
*)cfgTemplate
[i
].pBuffer
) = _tcstol(value
, &eptr
, 0);
213 error(_T("Invalid number '%s' in configuration file %s at line %d\n"), value
, entry
->getFile(), entry
->getLine());
217 *((WORD
*)cfgTemplate
[i
].pBuffer
) = (WORD
)_tcstoul(value
, &eptr
, 0);
220 error(_T("Invalid number '%s' in configuration file %s at line %d\n"), value
, entry
->getFile(), entry
->getLine());
224 if (!_tcsicmp(value
, _T("yes")) || !_tcsicmp(value
, _T("true")) ||
225 !_tcsicmp(value
, _T("on")) || !_tcsicmp(value
, _T("1")))
227 *((DWORD
*)cfgTemplate
[i
].pBuffer
) |= cfgTemplate
[i
].dwBufferSize
;
231 *((DWORD
*)cfgTemplate
[i
].pBuffer
) &= ~(cfgTemplate
[i
].dwBufferSize
);
235 nx_strncpy((TCHAR
*)cfgTemplate
[i
].pBuffer
, value
, cfgTemplate
[i
].dwBufferSize
);
238 *((TCHAR
**)cfgTemplate
[i
].pBuffer
) = (TCHAR
*)malloc(sizeof(TCHAR
) * (entry
->getConcatenatedValuesLength() + 1));
239 for(j
= 0, curr
= *((TCHAR
**)cfgTemplate
[i
].pBuffer
); j
< entry
->getValueCount(); j
++)
241 _tcscpy(curr
, entry
->getValue(j
));
242 curr
+= _tcslen(curr
);
243 *curr
= cfgTemplate
[i
].cSeparator
;
258 return m_errorCount
== 0;
263 // Load INI-style config
266 bool Config::loadIniConfig(const TCHAR
*file
, const TCHAR
*defaultSectionName
)
269 TCHAR buffer
[4096], *ptr
;
270 ConfigEntry
*currentSection
;
273 cfg
= _tfopen(file
, _T("r"));
276 error(_T("Cannot open file %s"), file
);
280 currentSection
= m_root
->findEntry(defaultSectionName
);
281 if (currentSection
== NULL
)
283 currentSection
= new ConfigEntry(defaultSectionName
, m_root
, file
, 0);
288 // Read line from file
290 _fgetts(buffer
, 4095, cfg
);
292 ptr
= _tcschr(buffer
, _T('\n'));
295 ptr
= _tcschr(buffer
, _T('#'));
303 // Check if it's a section name
304 if ((buffer
[0] == _T('*')) || (buffer
[0] == _T('[')))
306 if (buffer
[0] == _T('['))
308 TCHAR
*end
= _tcschr(buffer
, _T(']'));
312 currentSection
= m_root
->findEntry(&buffer
[1]);
313 if (currentSection
== NULL
)
315 currentSection
= new ConfigEntry(&buffer
[1], m_root
, file
, sourceLine
);
320 // Divide on two parts at = sign
321 ptr
= _tcschr(buffer
, _T('='));
324 error(_T("Syntax error in configuration file %s at line %d"), file
, sourceLine
);
332 ConfigEntry
*entry
= currentSection
->findEntry(buffer
);
334 entry
= new ConfigEntry(buffer
, currentSection
, file
, sourceLine
);
335 entry
->addValue(ptr
);
347 const TCHAR
*Config::getValue(const TCHAR
*path
)
349 ConfigEntry
*entry
= getEntry(path
);
350 return (entry
!= NULL
) ? entry
->getValue() : NULL
;
358 ConfigEntry
*Config::getEntry(const TCHAR
*path
)
360 const TCHAR
*curr
, *end
;
362 ConfigEntry
*entry
= m_root
;
364 if ((path
== NULL
) || (*path
!= _T('/')))
370 end
= _tcschr(curr
, _T('/'));
373 int len
= min((int)(end
- curr
), 255);
374 _tcsncpy(name
, curr
, len
);
376 entry
= entry
->findEntry(name
);
381 return entry
->findEntry(curr
);