]> icculus.org git repositories - divverent/netradiant.git/blob - tools/quake2/common/inout.c
initial
[divverent/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 {
66   xmlNodePtr ret;
67   char buf[1024];
68   
69   sprintf (buf, "%f %f %f", v[0], v[1], v[2]);
70   ret = xmlNewNode (NULL, "point");
71   xmlNodeSetContent (ret, buf);
72   return ret;
73 }
74
75 // send a node down the stream, add it to the document
76 void xml_SendNode (xmlNodePtr node)
77 {
78   xmlBufferPtr xml_buf;
79   char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks ..
80   // this index loops through the node buffer
81   int pos = 0;
82   int size;
83
84   xmlAddChild( doc->children, node );
85
86   if (brdcst_socket)
87   {
88     xml_buf = xmlBufferCreate();
89     xmlNodeDump( xml_buf, doc, node, 0, 0 );
90
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 < xml_buf->use)
96     {
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");
102       memcpy( xmlbuf, xml_buf->content+pos, size);
103       xmlbuf[size] = '\0';
104       NMSG_Clear( &msg );
105       NMSG_WriteString (&msg, xmlbuf );
106       Net_Send(brdcst_socket, &msg );
107       // now that the thing is sent prepare to loop again
108       pos += size;
109     }
110
111 #if 0
112     // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE
113     // we will need to split into chunks
114     // (we could also go lower level, in the end it's using send and receiv which are not size limited)
115     //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message
116     //  there's some tweaking to do in l_net for that .. so let's give us a margin for now
117
118     //++timo we need to handle the case of a buffer too big to fit in a single message
119     // try without checks for now
120     if (xml_buf->use > MAX_NETMESSAGE-10 )
121     {
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);
128
129     }
130
131     size = xml_buf->use;
132     memcpy( xmlbuf, xml_buf->content, size );
133     xmlbuf[size] = '\0';
134     NMSG_Clear( &msg );
135     NMSG_WriteString (&msg, xmlbuf );
136     Net_Send(brdcst_socket, &msg );
137 #endif
138
139     xmlBufferFree( xml_buf );
140   }  
141 }
142
143 void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError)
144 {
145   xmlNodePtr node, select;
146   char buf[1024];
147   char level[2];
148
149   // now build a proper "select" XML node
150   sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);
151   node = xmlNewNode (NULL, "select");
152   xmlNodeSetContent (node, buf);
153   level[0] = (int)'0' + (bError ? SYS_ERR : SYS_WRN)  ;
154   level[1] = 0;
155   xmlSetProp (node, "level", (char *)&level);
156   // a 'select' information
157   sprintf (buf, "%i %i", entitynum, brushnum);
158   select = xmlNewNode (NULL, "brush");
159   xmlNodeSetContent (select, buf);
160   xmlAddChild (node, select);
161   xml_SendNode (node);
162
163   sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);
164   if (bError)
165     Error(buf);
166   else
167     Sys_FPrintf (SYS_NOXML, "%s\n", buf);
168
169 }
170
171 void xml_Point (char *msg, vec3_t pt)
172 {
173   xmlNodePtr node, point;
174   char buf[1024];
175   char level[2];
176
177   node = xmlNewNode (NULL, "pointmsg");
178   xmlNodeSetContent (node, msg);
179   level[0] = (int)'0' + SYS_ERR;
180   level[1] = 0;
181   xmlSetProp (node, "level", (char *)&level);
182   // a 'point' node
183   sprintf (buf, "%g %g %g", pt[0], pt[1], pt[2]);
184   point = xmlNewNode (NULL, "point");
185   xmlNodeSetContent (point, buf);
186   xmlAddChild (node, point);
187   xml_SendNode (node);
188
189   sprintf (buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2]);
190   Error (buf);
191 }
192
193 #define WINDING_BUFSIZE 2048
194 void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die)
195 {
196   xmlNodePtr node, winding;
197   char buf[WINDING_BUFSIZE];
198   char smlbuf[128];
199   char level[2];
200   int i;
201
202   node = xmlNewNode (NULL, "windingmsg");
203   xmlNodeSetContent (node, msg);
204   level[0] = (int)'0' + SYS_ERR;
205   level[1] = 0;
206   xmlSetProp (node, "level", (char *)&level);
207   // a 'winding' node
208   sprintf( buf, "%i ", numpoints);
209   for(i = 0; i < numpoints; i++)
210   {
211           sprintf (smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2]);
212     // don't overflow
213     if (strlen(buf)+strlen(smlbuf)>WINDING_BUFSIZE)
214       break;
215           strcat( buf, smlbuf);
216   }
217
218   winding = xmlNewNode (NULL, "winding");
219   xmlNodeSetContent (winding, buf);
220   xmlAddChild (node, winding);
221   xml_SendNode (node);
222
223   if(die)
224     Error (msg);
225   else
226   {
227     Sys_Printf(msg);
228     Sys_Printf("\n");
229   }
230 }
231
232 // in include
233 #include "stream_version.h"
234
235 void Broadcast_Setup( const char *dest )
236 {
237         address_t address;
238   char sMsg[1024];
239
240         Net_Setup();
241         Net_StringToAddress((char *)dest, &address);
242   brdcst_socket = Net_Connect(&address, 0);
243   if (brdcst_socket)
244   {
245     // send in a header
246     sprintf (sMsg, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">");
247     NMSG_Clear( &msg );
248     NMSG_WriteString(&msg, sMsg );
249     Net_Send(brdcst_socket, &msg );
250   }
251 }
252
253 void Broadcast_Shutdown()
254 {
255   if (brdcst_socket)
256   {    
257     Sys_Printf("Disconnecting\n");
258     Net_Disconnect(brdcst_socket);
259     brdcst_socket = NULL;
260   }
261 }
262
263 // all output ends up through here
264 void FPrintf (int flag, char *buf)
265 {
266   xmlNodePtr node;
267   static qboolean bGotXML = false;
268   char level[2];
269
270   printf(buf);
271
272   // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe?
273   if (flag == SYS_NOXML)
274     return;
275
276   // ouput an XML file of the run
277   // use the DOM interface to build a tree
278   /*
279   <message level='flag'>
280     message string
281     .. various nodes to describe corresponding geometry ..
282   </message>
283   */
284   if (!bGotXML)
285   {
286     // initialize
287     doc = xmlNewDoc("1.0");
288     doc->children = xmlNewDocRawNode(doc, NULL, "q3map_feedback", NULL);
289     bGotXML = true;
290   }
291   node = xmlNewNode (NULL, "message");
292   xmlNodeSetContent (node, buf);
293   level[0] = (int)'0' + flag;
294   level[1] = 0;
295   xmlSetProp (node, "level", (char *)&level );
296   
297   xml_SendNode (node);
298 }
299
300 #ifdef DBG_XML
301 void DumpXML()
302 {
303   xmlSaveFile( "XMLDump.xml", doc );
304 }
305 #endif
306
307 void Sys_FPrintf (int flag, const char *format, ...)
308 {
309   char out_buffer[4096];
310         va_list argptr;
311   
312   if ((flag == SYS_VRB) && (verbose == false))
313     return;
314
315   va_start (argptr, format);
316         vsprintf (out_buffer, format, argptr);
317         va_end (argptr);
318
319   FPrintf (flag, out_buffer);
320 }
321
322 void Sys_Printf (const char *format, ...)
323 {
324   char out_buffer[4096];
325         va_list argptr;
326
327   va_start (argptr, format);
328         vsprintf (out_buffer, format, argptr);
329         va_end (argptr);
330   
331   FPrintf (SYS_STD, out_buffer);
332 }
333
334 /*
335 =================
336 Error
337
338 For abnormal program terminations
339 =================
340 */
341 void Error( const char *error, ...)
342 {
343   char out_buffer[4096];
344   char tmp[4096];
345         va_list argptr;
346
347         va_start (argptr,error);
348         vsprintf (tmp, error, argptr);
349         va_end (argptr);
350
351   sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
352
353   FPrintf( SYS_ERR, out_buffer );
354
355 #ifdef DBG_XML  
356   DumpXML();
357 #endif
358
359   //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener.
360   // a clean solution is to send a sync request node in the stream and wait for an answer before exiting
361   Sys_Sleep( 1000 );
362   
363   Broadcast_Shutdown();
364
365         exit (1);
366 }
367