2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
22 //-----------------------------------------------------------------------------
\r
26 // deal with in/out tasks, for either stdin/stdout or network/XML stream
\r
30 #include "mathlib.h"
\r
31 #include "polylib.h"
\r
33 #include <sys/types.h>
\r
34 #include <sys/stat.h>
\r
38 #include <windows.h>
\r
41 // network broadcasting
\r
42 #include "l_net/l_net.h"
\r
43 #include "libxml/tree.h"
\r
46 HWND hwndOut = NULL;
\r
47 qboolean lookedForServer = false;
\r
48 UINT wm_BroadcastCommand = -1;
\r
51 socket_t *brdcst_socket;
\r
54 qboolean verbose = false;
\r
56 // our main document
\r
57 // is streamed through the network to Radiant
\r
58 // possibly written to disk at the end of the run
\r
59 //++timo FIXME: need to be global, required when creating nodes?
\r
63 // some useful stuff
\r
64 xmlNodePtr xml_NodeForVec( vec3_t v )
\r
69 sprintf (buf, "%f %f %f", v[0], v[1], v[2]);
\r
70 ret = xmlNewNode (NULL, "point");
\r
71 xmlNodeSetContent (ret, buf);
\r
75 // send a node down the stream, add it to the document
\r
76 void xml_SendNode (xmlNodePtr node)
\r
78 xmlBufferPtr xml_buf;
\r
79 char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks ..
\r
80 // this index loops through the node buffer
\r
84 xmlAddChild( doc->children, node );
\r
88 xml_buf = xmlBufferCreate();
\r
89 xmlNodeDump( xml_buf, doc, node, 0, 0 );
\r
91 // the XML node might be too big to fit in a single network message
\r
92 // l_net library defines an upper limit of MAX_NETMESSAGE
\r
93 // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe
\r
94 // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages
\r
95 while (pos < xml_buf->use)
\r
97 // what size are we gonna send now?
\r
98 (xml_buf->use - pos < MAX_NETMESSAGE - 10) ? (size = xml_buf->use - pos) : (size = MAX_NETMESSAGE - 10);
\r
99 //++timo just a debug thing
\r
100 if (size == MAX_NETMESSAGE - 10)
\r
101 Sys_FPrintf (SYS_NOXML, "Got to split the buffer\n");
\r
102 memcpy( xmlbuf, xml_buf->content+pos, size);
\r
103 xmlbuf[size] = '\0';
\r
104 NMSG_Clear( &msg );
\r
105 NMSG_WriteString (&msg, xmlbuf );
\r
106 Net_Send(brdcst_socket, &msg );
\r
107 // now that the thing is sent prepare to loop again
\r
112 // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE
\r
113 // we will need to split into chunks
\r
114 // (we could also go lower level, in the end it's using send and receiv which are not size limited)
\r
115 //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message
\r
116 // there's some tweaking to do in l_net for that .. so let's give us a margin for now
\r
118 //++timo we need to handle the case of a buffer too big to fit in a single message
\r
119 // try without checks for now
\r
120 if (xml_buf->use > MAX_NETMESSAGE-10 )
\r
122 // if we send that we are probably gonna break the stream at the other end..
\r
123 // and Error will call right there
\r
124 //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
\r
125 Sys_FPrintf (SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
\r
126 xml_buf->content[xml_buf->use]='\0'; //++timo this corrupts the buffer but we don't care it's for printing
\r
127 Sys_FPrintf (SYS_NOXML, xml_buf->content);
\r
131 size = xml_buf->use;
\r
132 memcpy( xmlbuf, xml_buf->content, size );
\r
133 xmlbuf[size] = '\0';
\r
134 NMSG_Clear( &msg );
\r
135 NMSG_WriteString (&msg, xmlbuf );
\r
136 Net_Send(brdcst_socket, &msg );
\r
139 xmlBufferFree( xml_buf );
\r
143 void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError)
\r
145 xmlNodePtr node, select;
\r
149 // now build a proper "select" XML node
\r
150 sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);
\r
151 node = xmlNewNode (NULL, "select");
\r
152 xmlNodeSetContent (node, buf);
\r
153 level[0] = (int)'0' + (bError ? SYS_ERR : SYS_WRN) ;
\r
155 xmlSetProp (node, "level", (char *)&level);
\r
156 // a 'select' information
\r
157 sprintf (buf, "%i %i", entitynum, brushnum);
\r
158 select = xmlNewNode (NULL, "brush");
\r
159 xmlNodeSetContent (select, buf);
\r
160 xmlAddChild (node, select);
\r
161 xml_SendNode (node);
\r
163 sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);
\r
167 Sys_FPrintf (SYS_NOXML, "%s\n", buf);
\r
171 void xml_Point (char *msg, vec3_t pt)
\r
173 xmlNodePtr node, point;
\r
177 node = xmlNewNode (NULL, "pointmsg");
\r
178 xmlNodeSetContent (node, msg);
\r
179 level[0] = (int)'0' + SYS_ERR;
\r
181 xmlSetProp (node, "level", (char *)&level);
\r
183 sprintf (buf, "%g %g %g", pt[0], pt[1], pt[2]);
\r
184 point = xmlNewNode (NULL, "point");
\r
185 xmlNodeSetContent (point, buf);
\r
186 xmlAddChild (node, point);
\r
187 xml_SendNode (node);
\r
189 sprintf (buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2]);
\r
193 #define WINDING_BUFSIZE 2048
\r
194 void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die)
\r
196 xmlNodePtr node, winding;
\r
197 char buf[WINDING_BUFSIZE];
\r
202 node = xmlNewNode (NULL, "windingmsg");
\r
203 xmlNodeSetContent (node, msg);
\r
204 level[0] = (int)'0' + SYS_ERR;
\r
206 xmlSetProp (node, "level", (char *)&level);
\r
207 // a 'winding' node
\r
208 sprintf( buf, "%i ", numpoints);
\r
209 for(i = 0; i < numpoints; i++)
\r
211 sprintf (smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2]);
\r
213 if (strlen(buf)+strlen(smlbuf)>WINDING_BUFSIZE)
\r
215 strcat( buf, smlbuf);
\r
218 winding = xmlNewNode (NULL, "winding");
\r
219 xmlNodeSetContent (winding, buf);
\r
220 xmlAddChild (node, winding);
\r
221 xml_SendNode (node);
\r
233 #include "stream_version.h"
\r
235 void Broadcast_Setup( const char *dest )
\r
241 Net_StringToAddress((char *)dest, &address);
\r
242 brdcst_socket = Net_Connect(&address, 0);
\r
245 // send in a header
\r
246 sprintf (sMsg, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">");
\r
247 NMSG_Clear( &msg );
\r
248 NMSG_WriteString(&msg, sMsg );
\r
249 Net_Send(brdcst_socket, &msg );
\r
253 void Broadcast_Shutdown()
\r
257 Sys_Printf("Disconnecting\n");
\r
258 Net_Disconnect(brdcst_socket);
\r
259 brdcst_socket = NULL;
\r
263 // all output ends up through here
\r
264 void FPrintf (int flag, char *buf)
\r
267 static qboolean bGotXML = false;
\r
272 // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe?
\r
273 if (flag == SYS_NOXML)
\r
276 // ouput an XML file of the run
\r
277 // use the DOM interface to build a tree
\r
279 <message level='flag'>
\r
281 .. various nodes to describe corresponding geometry ..
\r
287 doc = xmlNewDoc("1.0");
\r
288 doc->children = xmlNewDocRawNode(doc, NULL, "q3map_feedback", NULL);
\r
291 node = xmlNewNode (NULL, "message");
\r
292 xmlNodeSetContent (node, buf);
\r
293 level[0] = (int)'0' + flag;
\r
295 xmlSetProp (node, "level", (char *)&level );
\r
297 xml_SendNode (node);
\r
303 xmlSaveFile( "XMLDump.xml", doc );
\r
307 void Sys_FPrintf (int flag, const char *format, ...)
\r
309 char out_buffer[4096];
\r
312 if ((flag == SYS_VRB) && (verbose == false))
\r
315 va_start (argptr, format);
\r
316 vsprintf (out_buffer, format, argptr);
\r
319 FPrintf (flag, out_buffer);
\r
322 void Sys_Printf (const char *format, ...)
\r
324 char out_buffer[4096];
\r
327 va_start (argptr, format);
\r
328 vsprintf (out_buffer, format, argptr);
\r
331 FPrintf (SYS_STD, out_buffer);
\r
338 For abnormal program terminations
\r
341 void Error( const char *error, ...)
\r
343 char out_buffer[4096];
\r
347 va_start (argptr,error);
\r
348 vsprintf (tmp, error, argptr);
\r
351 sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
\r
353 FPrintf( SYS_ERR, out_buffer );
\r
359 //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener.
\r
360 // a clean solution is to send a sync request node in the stream and wait for an answer before exiting
\r
363 Broadcast_Shutdown();
\r