Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
xml.cpp
Go to the documentation of this file.
1 #include <portability.h>
2 
3 /*************************************************************************
4  * PLEASE SEE THE FILE "license.txt" (INCLUDED WITH THIS SOFTWARE PACKAGE)
5  * FOR LICENSE AND COPYRIGHT INFORMATION.
6  *************************************************************************/
7 
8 /*************************************************************************
9  *
10  * file: xml.cpp
11  *
12  * =======================================================================
13  *
14  * Contains methods for generating XML objects in response to kernel commands.
15  *
16  * The commands are modelled after the existing kernel functions which are tied to generating
17  * string output. In the past we added code to some of those functions so they'd
18  * generate string output and also XML output (as a string: <aaa>...</aaa>). To capture
19  * the XML output a caller would register for the XML callback, generate the XML as a string,
20  * parse the XML back to an object and return it.
21  *
22  * These methods generate XML as an object, so there are no strings being created
23  * and subsequently parsed and no need to "intercept" the XML callback channel (which is
24  * really for XML trace output to the debugger, not for results from commands).
25  * This new approach is more efficient to both create and to subsequently use.
26  *
27  * =======================================================================
28  */
29 
30 #include "xml.h"
31 
32 #include "agent.h"
33 #include "soar_TraceNames.h"
34 #include "XMLTrace.h"
35 #include "ElementXML.h"
36 #include "print.h"
37 #include "wmem.h"
38 
39 #include "assert.h"
40 
41 using namespace soar_TraceNames;
42 namespace stn = soar_TraceNames;
43 
44 void xml_create( agent* pAgent )
45 {
46  if ( !pAgent )
47  {
48  assert( pAgent );
49  return;
50  }
51 
52  soarxml::XMLTrace* pTrace = new soarxml::XMLTrace();
53  soarxml::XMLTrace* pCommands = new soarxml::XMLTrace();
54 
55  pAgent->xml_trace = static_cast< xml_handle >( pTrace );
56  pAgent->xml_commands = static_cast< xml_handle >( pCommands );
57 
58  pAgent->xml_destination = pAgent->xml_trace;
59 }
60 
61 void xml_reset( agent* pAgent )
62 {
63  if ( !pAgent || !pAgent->xml_trace || !pAgent->xml_commands )
64  {
65  assert( pAgent );
66  assert( pAgent->xml_trace );
67  assert( pAgent->xml_commands );
68  return;
69  }
70 
71  soarxml::XMLTrace* pTrace = static_cast< soarxml::XMLTrace* >( pAgent->xml_trace );
72  soarxml::XMLTrace* pCommands = static_cast< soarxml::XMLTrace* >( pAgent->xml_commands );
73 
74  pTrace->Reset();
75  pCommands->Reset();
76 }
77 
78 void xml_destroy( agent* pAgent )
79 {
80  if ( !pAgent || !pAgent->xml_trace || !pAgent->xml_commands )
81  {
82  assert( pAgent );
83  assert( pAgent->xml_trace );
84  assert( pAgent->xml_commands );
85  return;
86  }
87 
88  soarxml::XMLTrace* pTrace = static_cast< soarxml::XMLTrace* >( pAgent->xml_trace );
89  soarxml::XMLTrace* pCommands = static_cast< soarxml::XMLTrace* >( pAgent->xml_commands );
90 
91  delete pTrace;
92  delete pCommands;
93 
94  pAgent->xml_trace = 0;
95  pAgent->xml_commands = 0;
96 
97  pAgent->xml_destination = 0;
98 }
99 
100 void xml_begin_tag( agent* pAgent, char const* pTag )
101 {
102  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
103  pXML->BeginTag( pTag ) ;
104 }
105 
106 void xml_end_tag( agent* pAgent, char const* pTag )
107 {
108  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
109  pXML->EndTag( pTag ) ;
110 }
111 
112 // These "moveCurrent" methods allow us to move the entry point for new XML
113 // around in the existing structure. That's not often required but occassionally is helpful.
115 {
116  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
117  pXML->MoveCurrentToParent();
118 }
119 
120 void xml_move_current_to_child( agent* pAgent, int index )
121 {
122  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
123  pXML->MoveCurrentToChild( index );
124 }
125 
127 {
128  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
129  pXML->MoveCurrentToLastChild();
130 }
131 
132 void xml_att_val( agent* pAgent, char const* pAttribute, uint64_t value )
133 {
134  char buf[51];
135  SNPRINTF(buf, 50, "%llu", static_cast<long long unsigned>(value));
136 
137  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
138  pXML->AddAttribute( pAttribute, buf ) ;
139 }
140 
141 void xml_att_val( agent* pAgent, char const* pAttribute, int value )
142 {
143  char buf[51];
144  SNPRINTF(buf, 50, "%d", value);
145 
146  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
147  pXML->AddAttribute( pAttribute, buf ) ;
148 }
149 
150 void xml_att_val( agent* pAgent, char const* pAttribute, int64_t value )
151 {
152  char buf[51];
153  SNPRINTF(buf, 50, "%lld", static_cast<long long>(value));
154 
155  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
156  pXML->AddAttribute( pAttribute, buf ) ;
157 }
158 
159 void xml_att_val( agent* pAgent, char const* pAttribute, double value )
160 {
161  char buf[51];
162  SNPRINTF(buf, 50, "%f", value);
163 
164  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
165  pXML->AddAttribute( pAttribute, buf ) ;
166 }
167 
168 void xml_att_val( agent* pAgent, char const* pAttribute, char const* pValue )
169 {
170  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
171  pXML->AddAttribute( pAttribute, pValue ) ;
172 }
173 
174 void xml_att_val( agent* pAgent, char const* pAttribute, Symbol* pSymbol )
175 {
176  // Passing 0, 0 as buffer to symbol to string causes it to use internal, temporary buffers
177  // which is fine because we immediately copy that string in XMLAddAttribute.
178  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
179  pXML->AddAttribute( pAttribute, symbol_to_string( pAgent, pSymbol, true, 0, 0 ) ) ;
180 }
181 
182 void xml_object( agent* pAgent, char const* pTag )
183 {
184  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
185 
186  pXML->BeginTag( pTag ) ;
187  pXML->EndTag( pTag ) ;
188 }
189 
190 void xml_object( agent* pAgent, char const* pTag, char const* pAttribute, char const* pValue )
191 {
192  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
193 
194  pXML->BeginTag( pTag ) ;
195  pXML->AddAttribute( pAttribute, pValue ) ;
196  pXML->EndTag( pTag ) ;
197 }
198 
199 void xml_object( agent* pAgent, char const* pTag, char const* pAttribute, uint64_t value )
200 {
201  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
202 
203  pXML->BeginTag( pTag ) ;
204  xml_att_val( pAgent, pAttribute, value );
205  pXML->EndTag( pTag ) ;
206 }
207 
208 void xml_object( agent* pAgent, char const* pTag, char const* pAttribute, int64_t value )
209 {
210  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
211 
212  pXML->BeginTag( pTag ) ;
213  xml_att_val( pAgent, pAttribute, value );
214  pXML->EndTag( pTag ) ;
215 }
216 
217 void xml_object( agent* pAgent, char const* pTag, char const* pAttribute, double value )
218 {
219  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
220 
221  pXML->BeginTag( pTag ) ;
222  xml_att_val( pAgent, pAttribute, value );
223  pXML->EndTag( pTag ) ;
224 }
225 
226 void xml_object( agent* pAgent, wme* pWME, bool printTimetag ) {
227  // <wme tag="123" id="s1" attr="foo" attrtype="string" val="123" valtype="string"></wme>
228 
229  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
230 
231  pXML->BeginTag( stn::kTagWME ) ;
232 
233  // BADBAD: These calls are redundantly converting pXML again. Possibly optimize.
234  if ( printTimetag )
235  {
236  xml_att_val( pAgent, kWME_TimeTag, pWME->timetag );
237  }
238  xml_att_val( pAgent, kWME_Id, pWME->id );
239  xml_att_val( pAgent, kWME_Attribute, pWME->attr );
240  xml_att_val( pAgent, kWME_Value, pWME->value );
241  xml_att_val( pAgent, kWME_ValueType, symbol_to_typeString( pAgent, pWME->value ) );
242 
243  if ( pWME->acceptable )
244  {
245  xml_att_val( pAgent, kWMEPreference, "+" );
246  }
247 
248  pXML->EndTag( stn::kTagWME ) ;
249 }
250 
251 void xml_generate_warning( agent* pAgent, const char* pMessage )
252 {
253  xml_object( pAgent, stn::kTagWarning, stn::kTypeString, pMessage );
254 }
255 
256 void xml_generate_error( agent* pAgent, const char* pMessage )
257 {
258  xml_object( pAgent, stn::kTagError, stn::kTypeString, pMessage );
259 }
260 
261 void xml_generate_message( agent* pAgent, const char* pMessage )
262 {
263  xml_object( pAgent, stn::kTagMessage, stn::kTypeString, pMessage );
264 }
265 
266 void xml_generate_verbose( agent* pAgent, const char* pMessage )
267 {
268  xml_object( pAgent, stn::kTagVerbose, stn::kTypeString, pMessage );
269 }
270 
271 void xml_invoke_callback( agent* pAgent )
272 {
273  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
274  if ( pXML->IsEmpty() )
275  {
276  return;
277  }
278 
279  soarxml::ElementXML* pResult = pXML->DetatchObject();
280  pXML->Reset();
281 
282 #ifdef _DEBUG
283  char* pStr = pResult->GenerateXMLString( true ) ;
284  pResult->DeleteString( pStr ) ;
285 #endif // _DEBUG
286 
287  // We need to call the handler explicitly here instead of using soar_invoke_callbacks
288  // because we need to create a new ElementXML object for each handler that gets called.
289  for ( cons* c = pAgent->soar_callbacks[XML_GENERATION_CALLBACK]; c != NIL; c = c->rest )
290  {
291  soarxml::ElementXML* pCallbackData = new soarxml::ElementXML( pResult->GetXMLHandle() );
292  pCallbackData->AddRefOnHandle();
293 
294  soar_callback* cb = static_cast< soar_callback* >( c->first );
295 
296  // handler responsible for deleting pCallbackData
297  cb->function( pAgent, cb->eventid, cb->data, static_cast< soar_call_data >( pCallbackData ) );
298  }
299 
300  delete pResult;
301 }
302 
303 soarxml::ElementXML* xml_get_xml( agent* pAgent )
304 {
305  if ( !pAgent || !pAgent->xml_destination )
306  {
307  assert( pAgent );
308  assert( pAgent->xml_destination );
309  return 0;
310  }
311 
312  soarxml::XMLTrace* pXML = static_cast< soarxml::XMLTrace* >( pAgent->xml_destination );
313 
314  soarxml::ElementXML* pReturn = pXML->DetatchObject();
315  pXML->Reset();
316 
317  return pReturn;
318 }
319 
321 {
322  if ( !pAgent || !pAgent->xml_trace || !pAgent->xml_commands )
323  {
324  assert( pAgent );
325  assert( pAgent->xml_trace );
326  assert( pAgent->xml_commands );
327  return;
328  }
329 
330  pAgent->xml_destination = pAgent->xml_commands;
331 }
332 
333 soarxml::ElementXML* xml_end_command_mode( agent* pAgent )
334 {
335  if ( !pAgent )
336  {
337  assert( pAgent );
338  return 0;
339  }
340 
341  soarxml::ElementXML* pReturn = xml_get_xml( pAgent );
342 
343  pAgent->xml_destination = pAgent->xml_trace;
344 
345  return pReturn;
346 }
347