2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
24 #include "NodeFactory.h"
25 #include "Exception.h"
32 Node::Node(NodeFactory
* pnf
, CStringW name
)
43 void Node::AddTail(Node
* pNode
)
45 if(POSITION pos
= m_nodes
.Find(pNode
)) // TODO: slow
47 m_nodes
.MoveToTail(pos
);
51 m_nodes
.AddTail(pNode
);
52 m_name2node
[pNode
->m_name
] = pNode
;
55 bool Node::IsNameUnknown()
57 return m_name
.IsEmpty() || !!iswdigit(m_name
[0]);
60 bool Node::IsTypeUnknown()
62 return m_type
.IsEmpty() || m_type
== '?';
65 bool Node::IsType(CStringW type
)
67 return m_type
== type
;
70 void Node::GetChildDefs(CAtlList
<Definition
*>& l
, LPCWSTR type
, bool fFirst
)
72 CAtlList
<Definition
*> rdl
[3];
76 if(Definition
* pDef
= m_pnf
->GetDefByName(m_type
))
78 pDef
->GetChildDefs(rdl
[pDef
->m_priority
], type
, false);
82 POSITION pos
= m_nodes
.GetHeadPosition();
85 if(Node
* pNode
= m_nodes
.GetNext(pos
))
87 pNode
->GetChildDefs(rdl
[pNode
->m_priority
], type
, false);
91 for(int i
= 0; i
< sizeof(rdl
)/sizeof(rdl
[0]); i
++)
93 l
.AddTailList(&rdl
[i
]);
99 Reference::Reference(NodeFactory
* pnf
, CStringW name
)
104 Reference::~Reference()
108 void Reference::GetChildDefs(CAtlList
<Definition
*>& l
, LPCWSTR type
, bool fFirst
)
110 CAtlList
<Definition
*> rdl
[3];
112 POSITION pos
= m_nodes
.GetHeadPosition();
115 if(Definition
* pDef
= dynamic_cast<Definition
*>(m_nodes
.GetNext(pos
)))
117 if(!type
|| pDef
->m_type
== type
) // TODO: faster lookup
119 rdl
[pDef
->m_priority
].AddTail(pDef
);
124 for(int i
= 0; i
< sizeof(rdl
)/sizeof(rdl
[0]); i
++)
126 l
.AddTailList(&rdl
[i
]);
130 void Reference::Dump(OutputStream
& s
, int level
, bool fLast
)
132 if(m_predefined
) return;
134 CStringW
tabs(' ', level
*4);
136 // s.PutString(tabs + '\n' + tabs + L" {\n");
137 s
.PutString(L
" {\n");
139 POSITION pos
= m_nodes
.GetHeadPosition();
142 Node
* pNode
= m_nodes
.GetNext(pos
);
144 if(Definition
* pDef
= dynamic_cast<Definition
*>(pNode
))
146 pDef
->Dump(s
, level
+ 1, pos
== NULL
);
150 s
.PutString(tabs
+ '}');
155 Definition::Definition(NodeFactory
* pnf
, CStringW name
)
162 Definition::~Definition()
167 bool Definition::IsVisible(Definition
* pDef
)
169 Node
* pNode
= m_parent
;
173 if(pNode
->m_name2node
.Lookup(pDef
->m_name
))
178 pNode
= pNode
->m_parent
;
184 void Definition::AddTail(Node
* pNode
)
186 // if(Reference* pRef = dynamic_cast<Reference*>(pNode))
188 ASSERT(m_status
== node
);
192 if(IsTypeUnknown() && !pNode
->IsTypeUnknown())
194 m_type
= pNode
->m_type
;
198 RemoveFromCache(pNode
->m_type
);
201 __super::AddTail(pNode
);
204 Definition
& Definition::operator[] (LPCWSTR type
)
206 Definition
* pRetDef
= NULL
;
207 if(m_type2def
.Lookup(type
, pRetDef
))
210 pRetDef
= new Definition(m_pnf
, L
"");
211 pRetDef
->m_priority
= PLow
;
212 pRetDef
->m_type
= type
;
213 m_type2def
[type
] = pRetDef
;
215 CAtlList
<Definition
*> l
;
216 GetChildDefs(l
, type
);
220 Definition
* pDef
= l
.RemoveHead();
222 pRetDef
->m_priority
= pDef
->m_priority
;
223 pRetDef
->m_parent
= pDef
->m_parent
;
227 pRetDef
->SetAsValue(pDef
->m_status
, pDef
->m_value
, pDef
->m_unit
);
231 pRetDef
->m_status
= node
;
232 pRetDef
->m_nodes
.AddTailList(&pDef
->m_nodes
);
239 void Definition::RemoveFromCache(LPCWSTR type
)
243 POSITION pos
= m_type2def
.GetStartPosition();
244 while(pos
) delete m_type2def
.GetNextValue(pos
);
246 else if(StringMapW
<Definition
*>::CPair
* p
= m_type2def
.Lookup(type
))
249 m_type2def
.RemoveKey(type
);
253 bool Definition::IsValue(status_t s
)
255 return s
? m_status
== s
: m_status
!= node
;
258 void Definition::SetAsValue(status_t s
, CStringW v
, CStringW u
)
263 m_name2node
.RemoveAll();
271 void Definition::SetAsNumber(CStringW v
, CStringW u
)
273 SetAsValue(number
, v
, u
);
276 GetAsNumber(n
); // will throw an exception if not a number
280 void Definition::GetAsNumber(Number
<T
>& n
, StringMapW
<T
>* n2n
)
282 CStringW str
= m_value
;
283 str
.Replace(L
" ", L
"");
291 if(m_status
== node
) throw Exception(_T("expected value type"));
293 if(StringMapW
<T
>::CPair
* p
= n2n
->Lookup(str
))
295 n
.value
= p
->m_value
;
300 if(m_status
!= number
) throw Exception(_T("expected number"));
302 n
.sign
= str
.Find('+') == 0 ? 1 : str
.Find('-') == 0 ? -1 : 0;
305 if(str
.Find(L
"0x") == 0)
307 if(n
.sign
) throw Exception(_T("hex values must be unsigned"));
309 n
.value
= (T
)wcstoul(str
.Mid(2), NULL
, 16);
313 CStringW num_string
= m_value
+ m_unit
;
315 if(m_num_string
!= num_string
)
318 Split
sa2('.', sa
? sa
[sa
-1] : L
"");
320 if(sa
== 0 || sa2
== 0 || sa2
> 2) throw Exception(_T("invalid number"));
323 for(size_t i
= 0; i
< sa
; i
++) {f
*= 60; f
+= wcstoul(sa
[i
], NULL
, 10);}
324 if(sa2
> 1) f
+= (float)wcstoul(sa2
[1], NULL
, 10) / pow((float)10, sa2
[1].GetLength());
326 if(n
.unit
== L
"ms") {f
/= 1000; n
.unit
= L
"s";}
327 else if(n
.unit
== L
"m") {f
*= 60; n
.unit
= L
"s";}
328 else if(n
.unit
== L
"h") {f
*= 3600; n
.unit
= L
"s";}
332 m_num_string
= num_string
;
338 n
.value
= (T
)m_num
.value
;
342 if(n
.sign
) n
.value
*= n
.sign
;
346 void Definition::GetAsString(CStringW
& str
)
348 if(m_status
== node
) throw Exception(_T("expected value type"));
353 void Definition::GetAsNumber(Number
<int>& n
, StringMapW
<int>* n2n
) {return GetAsNumber
<int>(n
, n2n
);}
354 void Definition::GetAsNumber(Number
<DWORD
>& n
, StringMapW
<DWORD
>* n2n
) {return GetAsNumber
<DWORD
>(n
, n2n
);}
355 void Definition::GetAsNumber(Number
<float>& n
, StringMapW
<float>* n2n
) {return GetAsNumber
<float>(n
, n2n
);}
357 void Definition::GetAsBoolean(bool& b
)
359 static StringMapW
<bool> s2b
;
367 s2b
[L
"false"] = false;
373 if(!s2b
.Lookup(m_value
, b
)) // m_status != boolean && m_status != number ||
375 throw Exception(_T("expected boolean"));
379 bool Definition::GetAsTime(Time
& t
, StringMapW
<float>& offset
, StringMapW
<float>* n2n
, int default_id
)
381 Definition
& time
= (*this)[L
"time"];
384 if(time
[L
"id"].IsValue()) id
= time
[L
"id"];
385 else id
.Format(L
"%d", default_id
);
387 float scale
= time
[L
"scale"].IsValue() ? time
[L
"scale"] : 1.0f
;
389 if(time
[L
"start"].IsValue() && time
[L
"stop"].IsValue())
391 time
[L
"start"].GetAsNumber(t
.start
, n2n
);
392 time
[L
"stop"].GetAsNumber(t
.stop
, n2n
);
394 if(t
.start
.unit
.IsEmpty()) t
.start
.value
*= scale
;
395 if(t
.stop
.unit
.IsEmpty()) t
.stop
.value
*= scale
;
398 offset
.Lookup(id
, o
);
400 if(t
.start
.sign
!= 0) t
.start
.value
= o
+ t
.start
.value
;
401 if(t
.stop
.sign
!= 0) t
.stop
.value
= t
.start
.value
+ t
.stop
.value
;
403 offset
[id
] = t
.stop
.value
;
411 Definition::operator LPCWSTR()
418 Definition::operator float()
425 Definition::operator bool()
432 Definition
* Definition::SetChildAsValue(CStringW path
, status_t s
, CStringW v
, CStringW u
)
434 Definition
* pDef
= this;
436 Split
split('.', path
);
438 for(size_t i
= 0, j
= split
-1; i
<= j
; i
++)
440 CStringW type
= split
[i
];
442 if(pDef
->m_nodes
.IsEmpty() || !dynamic_cast<Reference
*>(pDef
->m_nodes
.GetTail()))
444 EXECUTE_ASSERT(m_pnf
->CreateRef(pDef
) != NULL
);
447 if(Reference
* pRef
= dynamic_cast<Reference
*>(pDef
->m_nodes
.GetTail()))
451 POSITION pos
= pRef
->m_nodes
.GetTailPosition();
454 Definition
* pChildDef
= dynamic_cast<Definition
*>(pRef
->m_nodes
.GetPrev(pos
));
456 if(pChildDef
->IsType(type
))
458 if(pChildDef
->IsNameUnknown()) pDef
= pChildDef
;
465 pDef
= m_pnf
->CreateDef(pRef
, type
);
470 pDef
->SetAsValue(s
, v
, u
);
479 Definition
* Definition::SetChildAsNumber(CStringW path
, CStringW v
, CStringW u
)
481 Definition
* pDef
= SetChildAsValue(path
, number
, v
, u
);
484 pDef
->GetAsNumber(n
); // will throw an exception if not a number
489 void Definition::Dump(OutputStream
& s
, int level
, bool fLast
)
491 if(m_predefined
) return;
493 CStringW
tabs(' ', level
*4);
496 if(m_predefined
) str
+= '?';
497 if(m_priority
== PLow
) str
+= '*';
498 else if(m_priority
== PHigh
) str
+= '!';
499 if(!IsTypeUnknown() && !m_autotype
) str
+= m_type
;
500 if(!IsNameUnknown()) str
+= '#' + m_name
;
502 s
.PutString(L
"%s", str
);
504 if(!m_nodes
.IsEmpty())
506 POSITION pos
= m_nodes
.GetHeadPosition();
509 Node
* pNode
= m_nodes
.GetNext(pos
);
511 if(Reference
* pRef
= dynamic_cast<Reference
*>(pNode
))
513 pRef
->Dump(s
, level
, fLast
);
517 ASSERT(!pNode
->IsNameUnknown());
518 s
.PutString(L
" %s", pNode
->m_name
);
524 if(!fLast
&& (!m_nodes
.IsEmpty() || level
== 0)) s
.PutString(L
"\n");
526 else if(m_status
== string
)
528 CStringW str
= m_value
;
529 str
.Replace(L
"\"", L
"\\\"");
530 s
.PutString(L
" \"%s\";\n", str
);
532 else if(m_status
== number
)
534 CStringW str
= m_value
;
535 if(!m_unit
.IsEmpty()) str
+= m_unit
;
536 s
.PutString(L
" %s;\n", str
);
538 else if(m_status
== boolean
)
540 s
.PutString(L
" %s;\n", m_value
);
542 else if(m_status
== block
)
544 s
.PutString(L
" {%s};\n", m_value
);
548 s
.PutString(L
" null;\n");