1 /**
2 * NamedList.cpp
3 * This file is part of the YATE Project http://YATE.null.ro
4 *
5 * Yet Another Telephony Engine - a fully featured software PBX and IVR
6 * Copyright (C) 2004-2014 Null Team
7 *
8 * This software is distributed under multiple licenses;
9 * see the COPYING file in the main directory for licensing
10 * information for this specific distribution.
11 *
12 * This use of this software may be subject to additional restrictions.
13 * See the LEGAL file in the main directory for details.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20 #include "yateclass.h"
21
22 using namespace TelEngine;
23
24 static const NamedList s_empty("");
25
empty()26 const NamedList& NamedList::empty()
27 {
28 return s_empty;
29 }
30
NamedList(const char * name)31 NamedList::NamedList(const char* name)
32 : String(name)
33 {
34 }
35
NamedList(const NamedList & original)36 NamedList::NamedList(const NamedList& original)
37 : String(original)
38 {
39 ObjList* dest = &m_params;
40 for (const ObjList* l = original.m_params.skipNull(); l; l = l->skipNext()) {
41 const NamedString* p = static_cast<const NamedString*>(l->get());
42 dest = dest->append(new NamedString(p->name(),*p));
43 }
44 }
45
NamedList(const char * name,const NamedList & original,const String & prefix)46 NamedList::NamedList(const char* name, const NamedList& original, const String& prefix)
47 : String(name)
48 {
49 copySubParams(original,prefix);
50 }
51
operator =(const NamedList & value)52 NamedList& NamedList::operator=(const NamedList& value)
53 {
54 String::operator=(value);
55 clearParams();
56 return copyParams(value);
57 }
58
getObject(const String & name) const59 void* NamedList::getObject(const String& name) const
60 {
61 if (name == YATOM("NamedList"))
62 return const_cast<NamedList*>(this);
63 return String::getObject(name);
64 }
65
addParam(NamedString * param)66 NamedList& NamedList::addParam(NamedString* param)
67 {
68 XDebug(DebugInfo,"NamedList::addParam(%p) [\"%s\",\"%s\"]",
69 param,(param ? param->name().c_str() : ""),TelEngine::c_safe(param));
70 if (param)
71 m_params.append(param);
72 return *this;
73 }
74
addParam(const char * name,const char * value,bool emptyOK)75 NamedList& NamedList::addParam(const char* name, const char* value, bool emptyOK)
76 {
77 XDebug(DebugInfo,"NamedList::addParam(\"%s\",\"%s\",%s)",name,value,String::boolText(emptyOK));
78 if (emptyOK || !TelEngine::null(value))
79 m_params.append(new NamedString(name, value));
80 return *this;
81 }
82
setParam(const String & name,const char * value)83 NamedList& NamedList::setParam(const String& name, const char* value)
84 {
85 XDebug(DebugInfo,"NamedList::setParam(\"%s\",\"%s\")",name.c_str(),value);
86 ObjList *p = m_params.skipNull();
87 while (p) {
88 NamedString *s = static_cast<NamedString*>(p->get());
89 if (s->name() == name) {
90 *s = value;
91 return *this;
92 }
93 ObjList* next = p->skipNext();
94 if (next)
95 p = next;
96 else
97 break;
98 }
99 if (p)
100 p->append(new NamedString(name,value));
101 else
102 m_params.append(new NamedString(name,value));
103 return *this;
104 }
105
clearParam(const String & name,char childSep)106 NamedList& NamedList::clearParam(const String& name, char childSep)
107 {
108 XDebug(DebugInfo,"NamedList::clearParam(\"%s\",'%.1s')",
109 name.c_str(),&childSep);
110 String tmp;
111 if (childSep)
112 tmp << name << childSep;
113 ObjList *p = &m_params;
114 while (p) {
115 NamedString *s = static_cast<NamedString *>(p->get());
116 if (s && ((s->name() == name) || s->name().startsWith(tmp)))
117 p->remove();
118 else
119 p = p->next();
120 }
121 return *this;
122 }
123
124 // Remove a specific parameter
clearParam(NamedString * param,bool delParam)125 NamedList& NamedList::clearParam(NamedString* param, bool delParam)
126 {
127 if (!param)
128 return *this;
129 ObjList* o = m_params.find(param);
130 if (o)
131 o->remove(delParam);
132 XDebug(DebugInfo,"NamedList::clearParam(%p) found=%p",param,o);
133 return *this;
134 }
135
copyParam(const NamedList & original,const String & name,char childSep)136 NamedList& NamedList::copyParam(const NamedList& original, const String& name, char childSep)
137 {
138 XDebug(DebugInfo,"NamedList::copyParam(%p,\"%s\",'%.1s')",
139 &original,name.c_str(),&childSep);
140 if (!childSep) {
141 // faster and simpler - used in most cases
142 const NamedString* s = original.getParam(name);
143 return s ? setParam(name,*s) : clearParam(name);
144 }
145 clearParam(name,childSep);
146 String tmp;
147 tmp << name << childSep;
148 ObjList* dest = &m_params;
149 for (const ObjList* l = original.m_params.skipNull(); l; l = l->skipNext()) {
150 const NamedString* s = static_cast<const NamedString*>(l->get());
151 if ((s->name() == name) || s->name().startsWith(tmp))
152 dest = dest->append(new NamedString(s->name(),*s));
153 }
154 return *this;
155 }
156
copyParams(const NamedList & original)157 NamedList& NamedList::copyParams(const NamedList& original)
158 {
159 XDebug(DebugInfo,"NamedList::copyParams(%p) [%p]",&original,this);
160 for (const ObjList* l = original.m_params.skipNull(); l; l = l->skipNext()) {
161 const NamedString* p = static_cast<const NamedString*>(l->get());
162 setParam(p->name(),*p);
163 }
164 return *this;
165 }
166
copyParams(const NamedList & original,ObjList * list,char childSep)167 NamedList& NamedList::copyParams(const NamedList& original, ObjList* list, char childSep)
168 {
169 XDebug(DebugInfo,"NamedList::copyParams(%p,%p,'%.1s') [%p]",
170 &original,list,&childSep,this);
171 for (; list; list = list->next()) {
172 GenObject* obj = list->get();
173 if (!obj)
174 continue;
175 String name = obj->toString();
176 name.trimBlanks();
177 if (name)
178 copyParam(original,name,childSep);
179 }
180 return *this;
181 }
182
copyParams(const NamedList & original,const String & list,char childSep)183 NamedList& NamedList::copyParams(const NamedList& original, const String& list, char childSep)
184 {
185 XDebug(DebugInfo,"NamedList::copyParams(%p,\"%s\",'%.1s') [%p]",
186 &original,list.c_str(),&childSep,this);
187 ObjList* l = list.split(',',false);
188 if (l) {
189 copyParams(original,l,childSep);
190 l->destruct();
191 }
192 return *this;
193 }
194
copySubParams(const NamedList & original,const String & prefix,bool skipPrefix,bool replace)195 NamedList& NamedList::copySubParams(const NamedList& original, const String& prefix,
196 bool skipPrefix, bool replace)
197 {
198 XDebug(DebugInfo,"NamedList::copySubParams(%p,\"%s\",%s,%s) [%p]",
199 &original,prefix.c_str(),String::boolText(skipPrefix),
200 String::boolText(replace),this);
201 if (prefix) {
202 unsigned int offs = skipPrefix ? prefix.length() : 0;
203 ObjList* dest = &m_params;
204 for (const ObjList* l = original.m_params.skipNull(); l; l = l->skipNext()) {
205 const NamedString* s = static_cast<const NamedString*>(l->get());
206 if (s->name().startsWith(prefix)) {
207 const char* name = s->name().c_str() + offs;
208 if (!*name)
209 continue;
210 if (!replace)
211 dest = dest->append(new NamedString(name,*s));
212 else if (offs)
213 setParam(name,*s);
214 else
215 setParam(s->name(),*s);
216 }
217 }
218 }
219 return *this;
220 }
221
hasSubParams(const char * prefix) const222 bool NamedList::hasSubParams(const char* prefix) const
223 {
224 XDebug(DebugInfo,"NamedList::hasSubParams(\"%s\") [%p]",prefix,this);
225 if (!TelEngine::null(prefix)) {
226 for (const ObjList* l = m_params.skipNull(); l; l = l->skipNext()) {
227 const NamedString* s = static_cast<const NamedString*>(l->get());
228 if (s->name().startsWith(prefix))
229 return true;
230 }
231 }
232 return false;
233 }
234
dump(String & str,const char * separator,char quote,bool force) const235 void NamedList::dump(String& str, const char* separator, char quote, bool force) const
236 {
237 if (force && str.null())
238 str << separator;
239 str << quote << *this << quote;
240 const ObjList *p = m_params.skipNull();
241 for (; p; p = p->skipNext()) {
242 const NamedString* s = static_cast<const NamedString *>(p->get());
243 String tmp;
244 tmp << quote << s->name() << quote << "=" << quote << *s << quote;
245 str.append(tmp,separator);
246 }
247 }
248
getIndex(const NamedString * param) const249 int NamedList::getIndex(const NamedString* param) const
250 {
251 if (!param)
252 return -1;
253 const ObjList *p = &m_params;
254 for (int i=0; p; p=p->next(),i++) {
255 if (static_cast<const NamedString *>(p->get()) == param)
256 return i;
257 }
258 return -1;
259 }
260
getIndex(const String & name) const261 int NamedList::getIndex(const String& name) const
262 {
263 const ObjList *p = &m_params;
264 for (int i=0; p; p=p->next(),i++) {
265 NamedString *s = static_cast<NamedString *>(p->get());
266 if (s && (s->name() == name))
267 return i;
268 }
269 return -1;
270 }
271
getParam(const String & name) const272 NamedString* NamedList::getParam(const String& name) const
273 {
274 XDebug(DebugInfo,"NamedList::getParam(\"%s\")",name.c_str());
275 const ObjList *p = m_params.skipNull();
276 for (; p; p=p->skipNext()) {
277 NamedString *s = static_cast<NamedString *>(p->get());
278 if (s->name() == name)
279 return s;
280 }
281 return 0;
282 }
283
getParam(unsigned int index) const284 NamedString* NamedList::getParam(unsigned int index) const
285 {
286 XDebug(DebugInfo,"NamedList::getParam(%u)",index);
287 return static_cast<NamedString *>(m_params[index]);
288 }
289
operator [](const String & name) const290 const String& NamedList::operator[](const String& name) const
291 {
292 const String* s = getParam(name);
293 return s ? *s : String::empty();
294 }
295
getValue(const String & name,const char * defvalue) const296 const char* NamedList::getValue(const String& name, const char* defvalue) const
297 {
298 XDebug(DebugInfo,"NamedList::getValue(\"%s\",\"%s\")",name.c_str(),defvalue);
299 const NamedString *s = getParam(name);
300 return s ? s->c_str() : defvalue;
301 }
302
getIntValue(const String & name,int defvalue,int minvalue,int maxvalue,bool clamp) const303 int NamedList::getIntValue(const String& name, int defvalue, int minvalue, int maxvalue,
304 bool clamp) const
305 {
306 const NamedString *s = getParam(name);
307 return s ? s->toInteger(defvalue,0,minvalue,maxvalue,clamp) : defvalue;
308 }
309
getIntValue(const String & name,const TokenDict * tokens,int defvalue) const310 int NamedList::getIntValue(const String& name, const TokenDict* tokens, int defvalue) const
311 {
312 const NamedString *s = getParam(name);
313 return s ? s->toInteger(tokens,defvalue) : defvalue;
314 }
315
getInt64Value(const String & name,int64_t defvalue,int64_t minvalue,int64_t maxvalue,bool clamp) const316 int64_t NamedList::getInt64Value(const String& name, int64_t defvalue, int64_t minvalue,
317 int64_t maxvalue, bool clamp) const
318 {
319 const NamedString *s = getParam(name);
320 return s ? s->toInt64(defvalue,0,minvalue,maxvalue,clamp) : defvalue;
321 }
322
getUInt64Value(const String & name,uint64_t defvalue,uint64_t minvalue,uint64_t maxvalue,bool clamp) const323 uint64_t NamedList::getUInt64Value(const String& name, uint64_t defvalue, uint64_t minvalue,
324 uint64_t maxvalue, bool clamp) const
325 {
326 const NamedString *s = getParam(name);
327 return s ? s->toUInt64(defvalue,0,minvalue,maxvalue,clamp) : defvalue;
328 }
329
getDoubleValue(const String & name,double defvalue) const330 double NamedList::getDoubleValue(const String& name, double defvalue) const
331 {
332 const NamedString *s = getParam(name);
333 return s ? s->toDouble(defvalue) : defvalue;
334 }
335
getBoolValue(const String & name,bool defvalue) const336 bool NamedList::getBoolValue(const String& name, bool defvalue) const
337 {
338 const NamedString *s = getParam(name);
339 return s ? s->toBoolean(defvalue) : defvalue;
340 }
341
replaceParams(String & str,bool sqlEsc,char extraEsc) const342 int NamedList::replaceParams(String& str, bool sqlEsc, char extraEsc) const
343 {
344 int p1 = 0;
345 int cnt = 0;
346 while ((p1 = str.find("${",p1)) >= 0) {
347 int p2 = str.find('}',p1+2);
348 if (p2 > 0) {
349 String def;
350 String tmp = str.substr(p1+2,p2-p1-2);
351 tmp.trimBlanks();
352 int pq = tmp.find('$');
353 if (pq >= 0) {
354 // param is in ${<name>$<default>} format
355 def = tmp.substr(pq+1).trimBlanks();
356 tmp = tmp.substr(0,pq).trimBlanks();
357 }
358 DDebug(DebugAll,"NamedList replacing parameter '%s' [%p]",tmp.c_str(),this);
359 const String* ns = getParam(tmp);
360 if (ns) {
361 if (sqlEsc) {
362 const DataBlock* data = 0;
363 if (ns->null()) {
364 NamedPointer* np = YOBJECT(NamedPointer,ns);
365 if (np)
366 data = YOBJECT(DataBlock,np->userData());
367 }
368 if (data)
369 tmp = data->sqlEscape(extraEsc);
370 else
371 tmp = ns->sqlEscape(extraEsc);
372 }
373 else
374 tmp = *ns;
375 }
376 else
377 tmp = def;
378 str = str.substr(0,p1) + tmp + str.substr(p2+1);
379 // advance search offset past the string we just replaced
380 p1 += tmp.length();
381 cnt++;
382 }
383 else
384 return -1;
385 }
386 return cnt;
387 }
388
389 /* vi: set ts=8 sw=4 sts=4 noet: */
390