]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/common/inout.c
30ae39df7ee9026ae3cae5d94afff7083691c9de
[xonotic/netradiant.git] / tools / quake2 / common / inout.c
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
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.
11
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.
16
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
20  */
21
22 //-----------------------------------------------------------------------------
23 //
24 //
25 // DESCRIPTION:
26 // deal with in/out tasks, for either stdin/stdout or network/XML stream
27 //
28
29 #include "cmdlib.h"
30 #include "mathlib.h"
31 #include "polylib.h"
32 #include "inout.h"
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #ifdef WIN32
37 #include <direct.h>
38 #include <windows.h>
39 #endif
40
41 // network broadcasting
42 #include "l_net/l_net.h"
43 #include "libxml/tree.h"
44
45 #ifdef WIN32
46 HWND hwndOut = NULL;
47 qboolean lookedForServer = false;
48 UINT wm_BroadcastCommand = -1;
49 #endif
50
51 socket_t *brdcst_socket;
52 netmessage_t msg;
53
54 qboolean verbose = false;
55
56 // our main document
57 // is streamed through the network to Radiant
58 // possibly written to disk at the end of the run
59 //++timo FIXME: need to be global, required when creating nodes?
60 xmlDocPtr doc;
61 xmlNodePtr tree;
62
63 // some useful stuff
64 xmlNodePtr xml_NodeForVec( vec3_t v ){
65         xmlNodePtr ret;
66         char buf[1024];
67
68         sprintf( buf, "%f %f %f", v[0], v[1], v[2] );
69         ret = xmlNewNode( NULL, "point" );
70         xmlNodeSetContent( ret, buf );
71         return ret;
72 }
73
74 // send a node down the stream, add it to the document
75 void xml_SendNode( xmlNodePtr node ){
76         xmlBufferPtr xml_buf;
77         char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks ..
78         // this index loops through the node buffer
79         int pos = 0;
80         int size;
81
82         xmlAddChild( doc->children, node );
83
84         if ( brdcst_socket ) {
85                 xml_buf = xmlBufferCreate();
86                 xmlNodeDump( xml_buf, doc, node, 0, 0 );
87
88                 // the XML node might be too big to fit in a single network message
89                 // l_net library defines an upper limit of MAX_NETMESSAGE
90                 // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe
91                 // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages
92                 while ( pos < xml_buf->use )
93                 {
94                         // what size are we gonna send now?
95                         ( xml_buf->use - pos < MAX_NETMESSAGE - 10 ) ? ( size = xml_buf->use - pos ) : ( size = MAX_NETMESSAGE - 10 );
96                         //++timo just a debug thing
97                         if ( size == MAX_NETMESSAGE - 10 ) {
98                                 Sys_FPrintf( SYS_NOXML, "Got to split the buffer\n" );
99                         }
100                         memcpy( xmlbuf, xml_buf->content + pos, size );
101                         xmlbuf[size] = '\0';
102                         NMSG_Clear( &msg );
103                         NMSG_WriteString( &msg, xmlbuf );
104                         Net_Send( brdcst_socket, &msg );
105                         // now that the thing is sent prepare to loop again
106                         pos += size;
107                 }
108
109 #if 0
110                 // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE
111                 // we will need to split into chunks
112                 // (we could also go lower level, in the end it's using send and receiv which are not size limited)
113                 //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message
114                 //  there's some tweaking to do in l_net for that .. so let's give us a margin for now
115
116                 //++timo we need to handle the case of a buffer too big to fit in a single message
117                 // try without checks for now
118                 if ( xml_buf->use > MAX_NETMESSAGE - 10 ) {
119                         // if we send that we are probably gonna break the stream at the other end..
120                         // and Error will call right there
121                         //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
122                         Sys_FPrintf( SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use );
123                         xml_buf->content[xml_buf->use] = '\0'; //++timo this corrupts the buffer but we don't care it's for printing
124                         Sys_FPrintf( SYS_NOXML, xml_buf->content );
125
126                 }
127
128                 size = xml_buf->use;
129                 memcpy( xmlbuf, xml_buf->content, size );
130                 xmlbuf[size] = '\0';
131                 NMSG_Clear( &msg );
132                 NMSG_WriteString( &msg, xmlbuf );
133                 Net_Send( brdcst_socket, &msg );
134 #endif
135
136                 xmlBufferFree( xml_buf );
137         }
138 }
139
140 void xml_Select( char *msg, int entitynum, int brushnum, qboolean bError ){
141         xmlNodePtr node, select;
142         char buf[1024];
143         char level[2];
144
145         // now build a proper "select" XML node
146         sprintf( buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg );
147         node = xmlNewNode( NULL, "select" );
148         xmlNodeSetContent( node, buf );
149         level[0] = (int)'0' + ( bError ? SYS_ERR : SYS_WRN )  ;
150         level[1] = 0;
151         xmlSetProp( node, "level", (char *)&level );
152         // a 'select' information
153         sprintf( buf, "%i %i", entitynum, brushnum );
154         select = xmlNewNode( NULL, "brush" );
155         xmlNodeSetContent( select, buf );
156         xmlAddChild( node, select );
157         xml_SendNode( node );
158
159         sprintf( buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg );
160         if ( bError ) {
161                 Error( buf );
162         }
163         else{
164                 Sys_FPrintf( SYS_NOXML, "%s\n", buf );
165         }
166
167 }
168
169 void xml_Point( char *msg, vec3_t pt ){
170         xmlNodePtr node, point;
171         char buf[1024];
172         char level[2];
173
174         node = xmlNewNode( NULL, "pointmsg" );
175         xmlNodeSetContent( node, msg );
176         level[0] = (int)'0' + SYS_ERR;
177         level[1] = 0;
178         xmlSetProp( node, "level", (char *)&level );
179         // a 'point' node
180         sprintf( buf, "%g %g %g", pt[0], pt[1], pt[2] );
181         point = xmlNewNode( NULL, "point" );
182         xmlNodeSetContent( point, buf );
183         xmlAddChild( node, point );
184         xml_SendNode( node );
185
186         sprintf( buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2] );
187         Error( buf );
188 }
189
190 #define WINDING_BUFSIZE 2048
191 void xml_Winding( char *msg, vec3_t p[], int numpoints, qboolean die ){
192         xmlNodePtr node, winding;
193         char buf[WINDING_BUFSIZE];
194         char smlbuf[128];
195         char level[2];
196         int i;
197
198         node = xmlNewNode( NULL, "windingmsg" );
199         xmlNodeSetContent( node, msg );
200         level[0] = (int)'0' + SYS_ERR;
201         level[1] = 0;
202         xmlSetProp( node, "level", (char *)&level );
203         // a 'winding' node
204         sprintf( buf, "%i ", numpoints );
205         for ( i = 0; i < numpoints; i++ )
206         {
207                 sprintf( smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2] );
208                 // don't overflow
209                 if ( strlen( buf ) + strlen( smlbuf ) > WINDING_BUFSIZE ) {
210                         break;
211                 }
212                 strcat( buf, smlbuf );
213         }
214
215         winding = xmlNewNode( NULL, "winding" );
216         xmlNodeSetContent( winding, buf );
217         xmlAddChild( node, winding );
218         xml_SendNode( node );
219
220         if ( die ) {
221                 Error( msg );
222         }
223         else
224         {
225                 Sys_Printf( msg );
226                 Sys_Printf( "\n" );
227         }
228 }
229
230 // in include
231 #include "stream_version.h"
232
233 void Broadcast_Setup( const char *dest ){
234         address_t address;
235         char sMsg[1024];
236
237         Net_Setup();
238         Net_StringToAddress( (char *)dest, &address );
239         brdcst_socket = Net_Connect( &address, 0 );
240         if ( brdcst_socket ) {
241                 // send in a header
242                 sprintf( sMsg, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">" );
243                 NMSG_Clear( &msg );
244                 NMSG_WriteString( &msg, sMsg );
245                 Net_Send( brdcst_socket, &msg );
246         }
247 }
248
249 void Broadcast_Shutdown(){
250         if ( brdcst_socket ) {
251                 Sys_Printf( "Disconnecting\n" );
252                 Net_Disconnect( brdcst_socket );
253                 brdcst_socket = NULL;
254         }
255 }
256
257 // all output ends up through here
258 void FPrintf( int flag, char *buf ){
259         xmlNodePtr node;
260         static qboolean bGotXML = false;
261         char level[2];
262
263         printf( buf );
264
265         // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe?
266         if ( flag == SYS_NOXML ) {
267                 return;
268         }
269
270         // ouput an XML file of the run
271         // use the DOM interface to build a tree
272         /*
273            <message level='flag'>
274            message string
275            .. various nodes to describe corresponding geometry ..
276            </message>
277          */
278         if ( !bGotXML ) {
279                 // initialize
280                 doc = xmlNewDoc( "1.0" );
281                 doc->children = xmlNewDocRawNode( doc, NULL, "q3map_feedback", NULL );
282                 bGotXML = true;
283         }
284         node = xmlNewNode( NULL, "message" );
285         xmlNodeSetContent( node, buf );
286         level[0] = (int)'0' + flag;
287         level[1] = 0;
288         xmlSetProp( node, "level", (char *)&level );
289
290         xml_SendNode( node );
291 }
292
293 #ifdef DBG_XML
294 void DumpXML(){
295         xmlSaveFile( "XMLDump.xml", doc );
296 }
297 #endif
298
299 void Sys_FPrintf( int flag, const char *format, ... ){
300         char out_buffer[4096];
301         va_list argptr;
302
303         if ( ( flag == SYS_VRB ) && ( verbose == false ) ) {
304                 return;
305         }
306
307         va_start( argptr, format );
308         vsprintf( out_buffer, format, argptr );
309         va_end( argptr );
310
311         FPrintf( flag, out_buffer );
312 }
313
314 void Sys_Printf( const char *format, ... ){
315         char out_buffer[4096];
316         va_list argptr;
317
318         va_start( argptr, format );
319         vsprintf( out_buffer, format, argptr );
320         va_end( argptr );
321
322         FPrintf( SYS_STD, out_buffer );
323 }
324
325 /*
326    =================
327    Error
328
329    For abnormal program terminations
330    =================
331  */
332 void Error( const char *error, ... ){
333         char out_buffer[4096];
334         char tmp[4096];
335         va_list argptr;
336
337         va_start( argptr,error );
338         vsprintf( tmp, error, argptr );
339         va_end( argptr );
340
341         sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
342
343         FPrintf( SYS_ERR, out_buffer );
344
345 #ifdef DBG_XML
346         DumpXML();
347 #endif
348
349         //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener.
350         // a clean solution is to send a sync request node in the stream and wait for an answer before exiting
351         Sys_Sleep( 1000 );
352
353         Broadcast_Shutdown();
354
355         exit( 1 );
356 }