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"
50 qboolean lookedForServer = qfalse;
51 UINT wm_BroadcastCommand = -1;
54 socket_t *brdcst_socket;
57 qboolean verbose = qfalse;
60 // is streamed through the network to Radiant
61 // possibly written to disk at the end of the run
62 //++timo FIXME: need to be global, required when creating nodes?
67 xmlNodePtr xml_NodeForVec( vec3_t v ){
71 sprintf( buf, "%f %f %f", v[0], v[1], v[2] );
72 ret = xmlNewNode( NULL, (xmlChar*)"point" );
73 xmlNodeSetContent( ret, (xmlChar*)buf );
77 // send a node down the stream, add it to the document
78 void xml_SendNode( xmlNodePtr node ){
80 char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks ..
81 // this index loops through the node buffer
85 xmlAddChild( doc->children, node );
87 if ( brdcst_socket ) {
88 xml_buf = xmlBufferCreate();
89 xmlNodeDump( xml_buf, doc, node, 0, 0 );
91 // the XML node might be too big to fit in a single network message
92 // l_net library defines an upper limit of MAX_NETMESSAGE
93 // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe
94 // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages
95 while ( pos < (int)xml_buf->use )
97 // what size are we gonna send now?
98 ( xml_buf->use - pos < MAX_NETMESSAGE - 10 ) ? ( size = xml_buf->use - pos ) : ( size = MAX_NETMESSAGE - 10 );
99 //++timo just a debug thing
100 if ( size == MAX_NETMESSAGE - 10 ) {
101 Sys_FPrintf( SYS_NOXML, "Got to split the buffer\n" );
103 memcpy( xmlbuf, xml_buf->content + pos, size );
106 NMSG_WriteString( &msg, xmlbuf );
107 Net_Send( brdcst_socket, &msg );
108 // now that the thing is sent prepare to loop again
113 // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE
114 // we will need to split into chunks
115 // (we could also go lower level, in the end it's using send and receiv which are not size limited)
116 //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message
117 // there's some tweaking to do in l_net for that .. so let's give us a margin for now
119 //++timo we need to handle the case of a buffer too big to fit in a single message
120 // try without checks for now
121 if ( xml_buf->use > MAX_NETMESSAGE - 10 ) {
122 // if we send that we are probably gonna break the stream at the other end..
123 // and Error will call right there
124 //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
125 Sys_FPrintf( SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use );
126 xml_buf->content[xml_buf->use] = '\0'; //++timo this corrupts the buffer but we don't care it's for printing
127 Sys_FPrintf( SYS_NOXML, xml_buf->content );
132 memcpy( xmlbuf, xml_buf->content, size );
135 NMSG_WriteString( &msg, xmlbuf );
136 Net_Send( brdcst_socket, &msg );
139 xmlBufferFree( xml_buf );
143 void xml_Select( char *msg, int entitynum, int brushnum, qboolean bError ){
144 xmlNodePtr node, select;
148 // now build a proper "select" XML node
149 sprintf( buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg );
150 node = xmlNewNode( NULL, (xmlChar*)"select" );
151 xmlNodeSetContent( node, (xmlChar*)buf );
152 level[0] = (int)'0' + ( bError ? SYS_ERR : SYS_WRN ) ;
154 xmlSetProp( node, (xmlChar*)"level", (xmlChar *)&level );
155 // a 'select' information
156 sprintf( buf, "%i %i", entitynum, brushnum );
157 select = xmlNewNode( NULL, (xmlChar*)"brush" );
158 xmlNodeSetContent( select, (xmlChar*)buf );
159 xmlAddChild( node, select );
160 xml_SendNode( node );
162 sprintf( buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg );
167 Sys_FPrintf( SYS_NOXML, "%s\n", buf );
172 void xml_Point( char *msg, vec3_t pt ){
173 xmlNodePtr node, point;
177 node = xmlNewNode( NULL, (xmlChar*)"pointmsg" );
178 xmlNodeSetContent( node, (xmlChar*)msg );
179 level[0] = (int)'0' + SYS_ERR;
181 xmlSetProp( node, (xmlChar*)"level", (xmlChar *)&level );
183 sprintf( buf, "%g %g %g", pt[0], pt[1], pt[2] );
184 point = xmlNewNode( NULL, (xmlChar*)"point" );
185 xmlNodeSetContent( point, (xmlChar*)buf );
186 xmlAddChild( node, point );
187 xml_SendNode( node );
189 sprintf( buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2] );
193 #define WINDING_BUFSIZE 2048
194 void xml_Winding( char *msg, vec3_t p[], int numpoints, qboolean die ){
195 xmlNodePtr node, winding;
196 char buf[WINDING_BUFSIZE];
201 node = xmlNewNode( NULL, (xmlChar*)"windingmsg" );
202 xmlNodeSetContent( node, (xmlChar*)msg );
203 level[0] = (int)'0' + SYS_ERR;
205 xmlSetProp( node, (xmlChar*)"level", (xmlChar *)&level );
207 sprintf( buf, "%i ", numpoints );
208 for ( i = 0; i < numpoints; i++ )
210 sprintf( smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2] );
212 if ( strlen( buf ) + strlen( smlbuf ) > WINDING_BUFSIZE ) {
215 strcat( buf, smlbuf );
218 winding = xmlNewNode( NULL, (xmlChar*)"winding" );
219 xmlNodeSetContent( winding, (xmlChar*)buf );
220 xmlAddChild( node, winding );
221 xml_SendNode( node );
234 #include "stream_version.h"
236 void Broadcast_Setup( const char *dest ){
241 Net_StringToAddress( dest, &address );
242 brdcst_socket = Net_Connect( &address, 0 );
243 if ( brdcst_socket ) {
245 sprintf( sMsg, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">" );
247 NMSG_WriteString( &msg, sMsg );
248 Net_Send( brdcst_socket, &msg );
252 void Broadcast_Shutdown(){
253 if ( brdcst_socket ) {
254 Sys_Printf( "Disconnecting\n" );
255 Net_Disconnect( brdcst_socket );
256 brdcst_socket = NULL;
260 // all output ends up through here
261 void FPrintf( int flag, char *buf ){
263 static qboolean bGotXML = qfalse;
268 // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe?
269 if ( flag == SYS_NOXML ) {
273 // ouput an XML file of the run
274 // use the DOM interface to build a tree
276 <message level='flag'>
278 .. various nodes to describe corresponding geometry ..
283 doc = xmlNewDoc( (xmlChar*)"1.0" );
284 doc->children = xmlNewDocRawNode( doc, NULL, (xmlChar*)"q3map_feedback", NULL );
287 node = xmlNewNode( NULL, (xmlChar*)"message" );
289 gchar* utf8 = g_locale_to_utf8( buf, -1, NULL, NULL, NULL );
290 xmlNodeSetContent( node, (xmlChar*)utf8 );
293 level[0] = (int)'0' + flag;
295 xmlSetProp( node, (xmlChar*)"level", (xmlChar *)&level );
297 xml_SendNode( node );
302 xmlSaveFile( "XMLDump.xml", doc );
306 void Sys_FPrintf( int flag, const char *format, ... ){
307 char out_buffer[4096];
310 if ( ( flag == SYS_VRB ) && ( verbose == qfalse ) ) {
314 va_start( argptr, format );
315 vsprintf( out_buffer, format, argptr );
318 FPrintf( flag, out_buffer );
321 void Sys_Printf( const char *format, ... ){
322 char out_buffer[4096];
325 va_start( argptr, format );
326 vsprintf( out_buffer, format, argptr );
329 FPrintf( SYS_STD, out_buffer );
336 For abnormal program terminations
339 void Error( const char *error, ... ){
340 char out_buffer[4096];
344 va_start( argptr,error );
345 vsprintf( tmp, error, argptr );
348 sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
350 FPrintf( SYS_ERR, out_buffer );
356 //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener.
357 // a clean solution is to send a sync request node in the stream and wait for an answer before exiting
360 Broadcast_Shutdown();