2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 //-----------------------------------------------------------------------------
26 // deal with in/out tasks, for either stdin/stdout or network/XML stream
33 #include <sys/types.h>
41 // network broadcasting
42 #include "l_net/l_net.h"
43 #include "libxml/tree.h"
46 #include <glib/gconvert.h>
47 #include <glib/gmem.h>
51 qboolean lookedForServer = qfalse;
52 UINT wm_BroadcastCommand = -1;
55 socket_t *brdcst_socket;
58 qboolean verbose = qfalse;
61 // is streamed through the network to Radiant
62 // possibly written to disk at the end of the run
63 //++timo FIXME: need to be global, required when creating nodes?
68 xmlNodePtr xml_NodeForVec( vec3_t v )
73 sprintf (buf, "%f %f %f", v[0], v[1], v[2]);
74 ret = xmlNewNode (NULL, "point");
75 xmlNodeSetContent (ret, buf);
79 // send a node down the stream, add it to the document
80 void xml_SendNode (xmlNodePtr node)
83 char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks ..
84 // this index loops through the node buffer
88 xmlAddChild( doc->children, node );
92 xml_buf = xmlBufferCreate();
93 xmlNodeDump( xml_buf, doc, node, 0, 0 );
95 // the XML node might be too big to fit in a single network message
96 // l_net library defines an upper limit of MAX_NETMESSAGE
97 // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe
98 // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages
99 while (pos < xml_buf->use)
101 // what size are we gonna send now?
102 (xml_buf->use - pos < MAX_NETMESSAGE - 10) ? (size = xml_buf->use - pos) : (size = MAX_NETMESSAGE - 10);
103 //++timo just a debug thing
104 if (size == MAX_NETMESSAGE - 10)
105 Sys_FPrintf (SYS_NOXML, "Got to split the buffer\n");
106 memcpy( xmlbuf, xml_buf->content+pos, size);
109 NMSG_WriteString (&msg, xmlbuf );
110 Net_Send(brdcst_socket, &msg );
111 // now that the thing is sent prepare to loop again
116 // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE
117 // we will need to split into chunks
118 // (we could also go lower level, in the end it's using send and receiv which are not size limited)
119 //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message
120 // there's some tweaking to do in l_net for that .. so let's give us a margin for now
122 //++timo we need to handle the case of a buffer too big to fit in a single message
123 // try without checks for now
124 if (xml_buf->use > MAX_NETMESSAGE-10 )
126 // if we send that we are probably gonna break the stream at the other end..
127 // and Error will call right there
128 //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
129 Sys_FPrintf (SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
130 xml_buf->content[xml_buf->use]='\0'; //++timo this corrupts the buffer but we don't care it's for printing
131 Sys_FPrintf (SYS_NOXML, xml_buf->content);
136 memcpy( xmlbuf, xml_buf->content, size );
139 NMSG_WriteString (&msg, xmlbuf );
140 Net_Send(brdcst_socket, &msg );
143 xmlBufferFree( xml_buf );
147 void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError)
149 xmlNodePtr node, select;
153 // now build a proper "select" XML node
154 sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);
155 node = xmlNewNode (NULL, "select");
156 xmlNodeSetContent (node, buf);
157 level[0] = (int)'0' + (bError ? SYS_ERR : SYS_WRN) ;
159 xmlSetProp (node, "level", (char *)&level);
160 // a 'select' information
161 sprintf (buf, "%i %i", entitynum, brushnum);
162 select = xmlNewNode (NULL, "brush");
163 xmlNodeSetContent (select, buf);
164 xmlAddChild (node, select);
167 sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);
171 Sys_FPrintf (SYS_NOXML, "%s\n", buf);
175 void xml_Point (char *msg, vec3_t pt)
177 xmlNodePtr node, point;
181 node = xmlNewNode (NULL, "pointmsg");
182 xmlNodeSetContent (node, msg);
183 level[0] = (int)'0' + SYS_ERR;
185 xmlSetProp (node, "level", (char *)&level);
187 sprintf (buf, "%g %g %g", pt[0], pt[1], pt[2]);
188 point = xmlNewNode (NULL, "point");
189 xmlNodeSetContent (point, buf);
190 xmlAddChild (node, point);
193 sprintf (buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2]);
197 #define WINDING_BUFSIZE 2048
198 void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die)
200 xmlNodePtr node, winding;
201 char buf[WINDING_BUFSIZE];
206 node = xmlNewNode (NULL, "windingmsg");
207 xmlNodeSetContent (node, msg);
208 level[0] = (int)'0' + SYS_ERR;
210 xmlSetProp (node, "level", (char *)&level);
212 sprintf( buf, "%i ", numpoints);
213 for(i = 0; i < numpoints; i++)
215 sprintf (smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2]);
217 if (strlen(buf)+strlen(smlbuf)>WINDING_BUFSIZE)
219 strcat( buf, smlbuf);
222 winding = xmlNewNode (NULL, "winding");
223 xmlNodeSetContent (winding, buf);
224 xmlAddChild (node, winding);
237 #include "stream_version.h"
239 void Broadcast_Setup( const char *dest )
245 Net_StringToAddress((char *)dest, &address);
246 brdcst_socket = Net_Connect(&address, 0);
250 sprintf (sMsg, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">");
252 NMSG_WriteString(&msg, sMsg );
253 Net_Send(brdcst_socket, &msg );
257 void Broadcast_Shutdown()
261 Sys_Printf("Disconnecting\n");
262 Net_Disconnect(brdcst_socket);
263 brdcst_socket = NULL;
267 // all output ends up through here
268 void FPrintf (int flag, char *buf)
271 static qboolean bGotXML = qfalse;
276 // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe?
277 if (flag == SYS_NOXML)
280 // ouput an XML file of the run
281 // use the DOM interface to build a tree
283 <message level='flag'>
285 .. various nodes to describe corresponding geometry ..
291 doc = xmlNewDoc("1.0");
292 doc->children = xmlNewDocRawNode(doc, NULL, "q3map_feedback", NULL);
295 node = xmlNewNode (NULL, "message");
297 gchar* utf8 = g_locale_to_utf8(buf, -1, NULL, NULL, NULL);
298 xmlNodeSetContent(node, utf8);
301 level[0] = (int)'0' + flag;
303 xmlSetProp (node, "level", (char *)&level );
311 xmlSaveFile( "XMLDump.xml", doc );
315 void Sys_FPrintf (int flag, const char *format, ...)
317 char out_buffer[4096];
320 if ((flag == SYS_VRB) && (verbose == qfalse))
323 va_start (argptr, format);
324 vsprintf (out_buffer, format, argptr);
327 FPrintf (flag, out_buffer);
330 void Sys_Printf (const char *format, ...)
332 char out_buffer[4096];
335 va_start (argptr, format);
336 vsprintf (out_buffer, format, argptr);
339 FPrintf (SYS_STD, out_buffer);
346 For abnormal program terminations
349 void Error( const char *error, ...)
351 char out_buffer[4096];
355 va_start (argptr,error);
356 vsprintf (tmp, error, argptr);
359 sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
361 FPrintf( SYS_ERR, out_buffer );
367 //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener.
368 // a clean solution is to send a sync request node in the stream and wait for an answer before exiting
371 Broadcast_Shutdown();