-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-\r
-//-----------------------------------------------------------------------------\r
-//\r
-//\r
-// DESCRIPTION:\r
-// deal with in/out tasks, for either stdin/stdout or network/XML stream\r
-// \r
-\r
-#include "cmdlib.h"\r
-#include "mathlib.h"\r
-#include "polylib.h"\r
-#include "inout.h"\r
-#include <sys/types.h>\r
-#include <sys/stat.h>\r
-\r
-#ifdef _WIN32\r
-#include <direct.h>\r
-#include <windows.h>\r
-#endif\r
-\r
-// network broadcasting\r
-#include "l_net/l_net.h"\r
-#include "libxml/tree.h"\r
-\r
-#ifdef _WIN32\r
-HWND hwndOut = NULL;\r
-qboolean lookedForServer = false;\r
-UINT wm_BroadcastCommand = -1;\r
-#endif\r
-\r
-socket_t *brdcst_socket;\r
-netmessage_t msg;\r
-\r
-qboolean verbose = false;\r
-\r
-// our main document\r
-// is streamed through the network to Radiant\r
-// possibly written to disk at the end of the run\r
-//++timo FIXME: need to be global, required when creating nodes?\r
-xmlDocPtr doc;\r
-xmlNodePtr tree;\r
-\r
-// some useful stuff\r
-xmlNodePtr xml_NodeForVec( vec3_t v )\r
-{\r
- xmlNodePtr ret;\r
- char buf[1024];\r
- \r
- sprintf (buf, "%f %f %f", v[0], v[1], v[2]);\r
- ret = xmlNewNode (NULL, "point");\r
- xmlNodeSetContent (ret, buf);\r
- return ret;\r
-}\r
-\r
-// send a node down the stream, add it to the document\r
-void xml_SendNode (xmlNodePtr node)\r
-{\r
- xmlBufferPtr xml_buf;\r
- char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks ..\r
- // this index loops through the node buffer\r
- int pos = 0;\r
- int size;\r
-\r
- xmlAddChild( doc->children, node );\r
-\r
- if (brdcst_socket)\r
- {\r
- xml_buf = xmlBufferCreate();\r
- xmlNodeDump( xml_buf, doc, node, 0, 0 );\r
-\r
- // the XML node might be too big to fit in a single network message\r
- // l_net library defines an upper limit of MAX_NETMESSAGE\r
- // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe\r
- // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages\r
- while (pos < xml_buf->use)\r
- {\r
- // what size are we gonna send now?\r
- (xml_buf->use - pos < MAX_NETMESSAGE - 10) ? (size = xml_buf->use - pos) : (size = MAX_NETMESSAGE - 10);\r
- //++timo just a debug thing\r
- if (size == MAX_NETMESSAGE - 10)\r
- Sys_FPrintf (SYS_NOXML, "Got to split the buffer\n");\r
- memcpy( xmlbuf, xml_buf->content+pos, size);\r
- xmlbuf[size] = '\0';\r
- NMSG_Clear( &msg );\r
- NMSG_WriteString (&msg, xmlbuf );\r
- Net_Send(brdcst_socket, &msg );\r
- // now that the thing is sent prepare to loop again\r
- pos += size;\r
- }\r
-\r
-#if 0\r
- // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE\r
- // we will need to split into chunks\r
- // (we could also go lower level, in the end it's using send and receiv which are not size limited)\r
- //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message\r
- // there's some tweaking to do in l_net for that .. so let's give us a margin for now\r
-\r
- //++timo we need to handle the case of a buffer too big to fit in a single message\r
- // try without checks for now\r
- if (xml_buf->use > MAX_NETMESSAGE-10 )\r
- {\r
- // if we send that we are probably gonna break the stream at the other end..\r
- // and Error will call right there\r
- //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);\r
- Sys_FPrintf (SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);\r
- xml_buf->content[xml_buf->use]='\0'; //++timo this corrupts the buffer but we don't care it's for printing\r
- Sys_FPrintf (SYS_NOXML, xml_buf->content);\r
-\r
- }\r
-\r
- size = xml_buf->use;\r
- memcpy( xmlbuf, xml_buf->content, size );\r
- xmlbuf[size] = '\0';\r
- NMSG_Clear( &msg );\r
- NMSG_WriteString (&msg, xmlbuf );\r
- Net_Send(brdcst_socket, &msg );\r
-#endif\r
-\r
- xmlBufferFree( xml_buf );\r
- } \r
-}\r
-\r
-void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError)\r
-{\r
- xmlNodePtr node, select;\r
- char buf[1024];\r
- char level[2];\r
-\r
- // now build a proper "select" XML node\r
- sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);\r
- node = xmlNewNode (NULL, "select");\r
- xmlNodeSetContent (node, buf);\r
- level[0] = (int)'0' + (bError ? SYS_ERR : SYS_WRN) ;\r
- level[1] = 0;\r
- xmlSetProp (node, "level", (char *)&level);\r
- // a 'select' information\r
- sprintf (buf, "%i %i", entitynum, brushnum);\r
- select = xmlNewNode (NULL, "brush");\r
- xmlNodeSetContent (select, buf);\r
- xmlAddChild (node, select);\r
- xml_SendNode (node);\r
-\r
- sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);\r
- if (bError)\r
- Error(buf);\r
- else\r
- Sys_FPrintf (SYS_NOXML, "%s\n", buf);\r
-\r
-}\r
-\r
-void xml_Point (char *msg, vec3_t pt)\r
-{\r
- xmlNodePtr node, point;\r
- char buf[1024];\r
- char level[2];\r
-\r
- node = xmlNewNode (NULL, "pointmsg");\r
- xmlNodeSetContent (node, msg);\r
- level[0] = (int)'0' + SYS_ERR;\r
- level[1] = 0;\r
- xmlSetProp (node, "level", (char *)&level);\r
- // a 'point' node\r
- sprintf (buf, "%g %g %g", pt[0], pt[1], pt[2]);\r
- point = xmlNewNode (NULL, "point");\r
- xmlNodeSetContent (point, buf);\r
- xmlAddChild (node, point);\r
- xml_SendNode (node);\r
-\r
- sprintf (buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2]);\r
- Error (buf);\r
-}\r
-\r
-#define WINDING_BUFSIZE 2048\r
-void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die)\r
-{\r
- xmlNodePtr node, winding;\r
- char buf[WINDING_BUFSIZE];\r
- char smlbuf[128];\r
- char level[2];\r
- int i;\r
-\r
- node = xmlNewNode (NULL, "windingmsg");\r
- xmlNodeSetContent (node, msg);\r
- level[0] = (int)'0' + SYS_ERR;\r
- level[1] = 0;\r
- xmlSetProp (node, "level", (char *)&level);\r
- // a 'winding' node\r
- sprintf( buf, "%i ", numpoints);\r
- for(i = 0; i < numpoints; i++)\r
- {\r
- sprintf (smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2]);\r
- // don't overflow\r
- if (strlen(buf)+strlen(smlbuf)>WINDING_BUFSIZE)\r
- break;\r
- strcat( buf, smlbuf);\r
- }\r
-\r
- winding = xmlNewNode (NULL, "winding");\r
- xmlNodeSetContent (winding, buf);\r
- xmlAddChild (node, winding);\r
- xml_SendNode (node);\r
-\r
- if(die)\r
- Error (msg);\r
- else\r
- {\r
- Sys_Printf(msg);\r
- Sys_Printf("\n");\r
- }\r
-}\r
-\r
-// in include\r
-#include "stream_version.h"\r
-\r
-void Broadcast_Setup( const char *dest )\r
-{\r
- address_t address;\r
- char sMsg[1024];\r
-\r
- Net_Setup();\r
- Net_StringToAddress((char *)dest, &address);\r
- brdcst_socket = Net_Connect(&address, 0);\r
- if (brdcst_socket)\r
- {\r
- // send in a header\r
- sprintf (sMsg, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">");\r
- NMSG_Clear( &msg );\r
- NMSG_WriteString(&msg, sMsg );\r
- Net_Send(brdcst_socket, &msg );\r
- }\r
-}\r
-\r
-void Broadcast_Shutdown()\r
-{\r
- if (brdcst_socket)\r
- { \r
- Sys_Printf("Disconnecting\n");\r
- Net_Disconnect(brdcst_socket);\r
- brdcst_socket = NULL;\r
- }\r
-}\r
-\r
-// all output ends up through here\r
-void FPrintf (int flag, char *buf)\r
-{\r
- xmlNodePtr node;\r
- static qboolean bGotXML = false;\r
- char level[2];\r
-\r
- printf(buf);\r
-\r
- // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe?\r
- if (flag == SYS_NOXML)\r
- return;\r
-\r
- // ouput an XML file of the run\r
- // use the DOM interface to build a tree\r
- /*\r
- <message level='flag'>\r
- message string\r
- .. various nodes to describe corresponding geometry ..\r
- </message>\r
- */\r
- if (!bGotXML)\r
- {\r
- // initialize\r
- doc = xmlNewDoc("1.0");\r
- doc->children = xmlNewDocRawNode(doc, NULL, "q3map_feedback", NULL);\r
- bGotXML = true;\r
- }\r
- node = xmlNewNode (NULL, "message");\r
- xmlNodeSetContent (node, buf);\r
- level[0] = (int)'0' + flag;\r
- level[1] = 0;\r
- xmlSetProp (node, "level", (char *)&level );\r
- \r
- xml_SendNode (node);\r
-}\r
-\r
-#ifdef DBG_XML\r
-void DumpXML()\r
-{\r
- xmlSaveFile( "XMLDump.xml", doc );\r
-}\r
-#endif\r
-\r
-void Sys_FPrintf (int flag, const char *format, ...)\r
-{\r
- char out_buffer[4096];\r
- va_list argptr;\r
- \r
- if ((flag == SYS_VRB) && (verbose == false))\r
- return;\r
-\r
- va_start (argptr, format);\r
- vsprintf (out_buffer, format, argptr);\r
- va_end (argptr);\r
-\r
- FPrintf (flag, out_buffer);\r
-}\r
-\r
-void Sys_Printf (const char *format, ...)\r
-{\r
- char out_buffer[4096];\r
- va_list argptr;\r
-\r
- va_start (argptr, format);\r
- vsprintf (out_buffer, format, argptr);\r
- va_end (argptr);\r
- \r
- FPrintf (SYS_STD, out_buffer);\r
-}\r
-\r
-/*\r
-=================\r
-Error\r
-\r
-For abnormal program terminations\r
-=================\r
-*/\r
-void Error( const char *error, ...)\r
-{\r
- char out_buffer[4096];\r
- char tmp[4096];\r
- va_list argptr;\r
-\r
- va_start (argptr,error);\r
- vsprintf (tmp, error, argptr);\r
- va_end (argptr);\r
-\r
- sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );\r
-\r
- FPrintf( SYS_ERR, out_buffer );\r
-\r
-#ifdef DBG_XML \r
- DumpXML();\r
-#endif\r
-\r
- //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener.\r
- // a clean solution is to send a sync request node in the stream and wait for an answer before exiting\r
- Sys_Sleep( 1000 );\r
- \r
- Broadcast_Shutdown();\r
-\r
- exit (1);\r
-}\r
-\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+//-----------------------------------------------------------------------------
+//
+//
+// DESCRIPTION:
+// deal with in/out tasks, for either stdin/stdout or network/XML stream
+//
+
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "polylib.h"
+#include "inout.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#include <windows.h>
+#endif
+
+// network broadcasting
+#include "l_net/l_net.h"
+#include "libxml/tree.h"
+
+#ifdef _WIN32
+HWND hwndOut = NULL;
+qboolean lookedForServer = false;
+UINT wm_BroadcastCommand = -1;
+#endif
+
+socket_t *brdcst_socket;
+netmessage_t msg;
+
+qboolean verbose = false;
+
+// our main document
+// is streamed through the network to Radiant
+// possibly written to disk at the end of the run
+//++timo FIXME: need to be global, required when creating nodes?
+xmlDocPtr doc;
+xmlNodePtr tree;
+
+// some useful stuff
+xmlNodePtr xml_NodeForVec( vec3_t v )
+{
+ xmlNodePtr ret;
+ char buf[1024];
+
+ sprintf (buf, "%f %f %f", v[0], v[1], v[2]);
+ ret = xmlNewNode (NULL, "point");
+ xmlNodeSetContent (ret, buf);
+ return ret;
+}
+
+// send a node down the stream, add it to the document
+void xml_SendNode (xmlNodePtr node)
+{
+ xmlBufferPtr xml_buf;
+ char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks ..
+ // this index loops through the node buffer
+ int pos = 0;
+ int size;
+
+ xmlAddChild( doc->children, node );
+
+ if (brdcst_socket)
+ {
+ xml_buf = xmlBufferCreate();
+ xmlNodeDump( xml_buf, doc, node, 0, 0 );
+
+ // the XML node might be too big to fit in a single network message
+ // l_net library defines an upper limit of MAX_NETMESSAGE
+ // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe
+ // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages
+ while (pos < xml_buf->use)
+ {
+ // what size are we gonna send now?
+ (xml_buf->use - pos < MAX_NETMESSAGE - 10) ? (size = xml_buf->use - pos) : (size = MAX_NETMESSAGE - 10);
+ //++timo just a debug thing
+ if (size == MAX_NETMESSAGE - 10)
+ Sys_FPrintf (SYS_NOXML, "Got to split the buffer\n");
+ memcpy( xmlbuf, xml_buf->content+pos, size);
+ xmlbuf[size] = '\0';
+ NMSG_Clear( &msg );
+ NMSG_WriteString (&msg, xmlbuf );
+ Net_Send(brdcst_socket, &msg );
+ // now that the thing is sent prepare to loop again
+ pos += size;
+ }
+
+#if 0
+ // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE
+ // we will need to split into chunks
+ // (we could also go lower level, in the end it's using send and receiv which are not size limited)
+ //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message
+ // there's some tweaking to do in l_net for that .. so let's give us a margin for now
+
+ //++timo we need to handle the case of a buffer too big to fit in a single message
+ // try without checks for now
+ if (xml_buf->use > MAX_NETMESSAGE-10 )
+ {
+ // if we send that we are probably gonna break the stream at the other end..
+ // and Error will call right there
+ //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
+ Sys_FPrintf (SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use);
+ xml_buf->content[xml_buf->use]='\0'; //++timo this corrupts the buffer but we don't care it's for printing
+ Sys_FPrintf (SYS_NOXML, xml_buf->content);
+
+ }
+
+ size = xml_buf->use;
+ memcpy( xmlbuf, xml_buf->content, size );
+ xmlbuf[size] = '\0';
+ NMSG_Clear( &msg );
+ NMSG_WriteString (&msg, xmlbuf );
+ Net_Send(brdcst_socket, &msg );
+#endif
+
+ xmlBufferFree( xml_buf );
+ }
+}
+
+void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError)
+{
+ xmlNodePtr node, select;
+ char buf[1024];
+ char level[2];
+
+ // now build a proper "select" XML node
+ sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);
+ node = xmlNewNode (NULL, "select");
+ xmlNodeSetContent (node, buf);
+ level[0] = (int)'0' + (bError ? SYS_ERR : SYS_WRN) ;
+ level[1] = 0;
+ xmlSetProp (node, "level", (char *)&level);
+ // a 'select' information
+ sprintf (buf, "%i %i", entitynum, brushnum);
+ select = xmlNewNode (NULL, "brush");
+ xmlNodeSetContent (select, buf);
+ xmlAddChild (node, select);
+ xml_SendNode (node);
+
+ sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg);
+ if (bError)
+ Error(buf);
+ else
+ Sys_FPrintf (SYS_NOXML, "%s\n", buf);
+
+}
+
+void xml_Point (char *msg, vec3_t pt)
+{
+ xmlNodePtr node, point;
+ char buf[1024];
+ char level[2];
+
+ node = xmlNewNode (NULL, "pointmsg");
+ xmlNodeSetContent (node, msg);
+ level[0] = (int)'0' + SYS_ERR;
+ level[1] = 0;
+ xmlSetProp (node, "level", (char *)&level);
+ // a 'point' node
+ sprintf (buf, "%g %g %g", pt[0], pt[1], pt[2]);
+ point = xmlNewNode (NULL, "point");
+ xmlNodeSetContent (point, buf);
+ xmlAddChild (node, point);
+ xml_SendNode (node);
+
+ sprintf (buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2]);
+ Error (buf);
+}
+
+#define WINDING_BUFSIZE 2048
+void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die)
+{
+ xmlNodePtr node, winding;
+ char buf[WINDING_BUFSIZE];
+ char smlbuf[128];
+ char level[2];
+ int i;
+
+ node = xmlNewNode (NULL, "windingmsg");
+ xmlNodeSetContent (node, msg);
+ level[0] = (int)'0' + SYS_ERR;
+ level[1] = 0;
+ xmlSetProp (node, "level", (char *)&level);
+ // a 'winding' node
+ sprintf( buf, "%i ", numpoints);
+ for(i = 0; i < numpoints; i++)
+ {
+ sprintf (smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2]);
+ // don't overflow
+ if (strlen(buf)+strlen(smlbuf)>WINDING_BUFSIZE)
+ break;
+ strcat( buf, smlbuf);
+ }
+
+ winding = xmlNewNode (NULL, "winding");
+ xmlNodeSetContent (winding, buf);
+ xmlAddChild (node, winding);
+ xml_SendNode (node);
+
+ if(die)
+ Error (msg);
+ else
+ {
+ Sys_Printf(msg);
+ Sys_Printf("\n");
+ }
+}
+
+// in include
+#include "stream_version.h"
+
+void Broadcast_Setup( const char *dest )
+{
+ address_t address;
+ char sMsg[1024];
+
+ Net_Setup();
+ Net_StringToAddress((char *)dest, &address);
+ brdcst_socket = Net_Connect(&address, 0);
+ if (brdcst_socket)
+ {
+ // send in a header
+ sprintf (sMsg, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">");
+ NMSG_Clear( &msg );
+ NMSG_WriteString(&msg, sMsg );
+ Net_Send(brdcst_socket, &msg );
+ }
+}
+
+void Broadcast_Shutdown()
+{
+ if (brdcst_socket)
+ {
+ Sys_Printf("Disconnecting\n");
+ Net_Disconnect(brdcst_socket);
+ brdcst_socket = NULL;
+ }
+}
+
+// all output ends up through here
+void FPrintf (int flag, char *buf)
+{
+ xmlNodePtr node;
+ static qboolean bGotXML = false;
+ char level[2];
+
+ printf(buf);
+
+ // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe?
+ if (flag == SYS_NOXML)
+ return;
+
+ // ouput an XML file of the run
+ // use the DOM interface to build a tree
+ /*
+ <message level='flag'>
+ message string
+ .. various nodes to describe corresponding geometry ..
+ </message>
+ */
+ if (!bGotXML)
+ {
+ // initialize
+ doc = xmlNewDoc("1.0");
+ doc->children = xmlNewDocRawNode(doc, NULL, "q3map_feedback", NULL);
+ bGotXML = true;
+ }
+ node = xmlNewNode (NULL, "message");
+ xmlNodeSetContent (node, buf);
+ level[0] = (int)'0' + flag;
+ level[1] = 0;
+ xmlSetProp (node, "level", (char *)&level );
+
+ xml_SendNode (node);
+}
+
+#ifdef DBG_XML
+void DumpXML()
+{
+ xmlSaveFile( "XMLDump.xml", doc );
+}
+#endif
+
+void Sys_FPrintf (int flag, const char *format, ...)
+{
+ char out_buffer[4096];
+ va_list argptr;
+
+ if ((flag == SYS_VRB) && (verbose == false))
+ return;
+
+ va_start (argptr, format);
+ vsprintf (out_buffer, format, argptr);
+ va_end (argptr);
+
+ FPrintf (flag, out_buffer);
+}
+
+void Sys_Printf (const char *format, ...)
+{
+ char out_buffer[4096];
+ va_list argptr;
+
+ va_start (argptr, format);
+ vsprintf (out_buffer, format, argptr);
+ va_end (argptr);
+
+ FPrintf (SYS_STD, out_buffer);
+}
+
+/*
+=================
+Error
+
+For abnormal program terminations
+=================
+*/
+void Error( const char *error, ...)
+{
+ char out_buffer[4096];
+ char tmp[4096];
+ va_list argptr;
+
+ va_start (argptr,error);
+ vsprintf (tmp, error, argptr);
+ va_end (argptr);
+
+ sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp );
+
+ FPrintf( SYS_ERR, out_buffer );
+
+#ifdef DBG_XML
+ DumpXML();
+#endif
+
+ //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener.
+ // a clean solution is to send a sync request node in the stream and wait for an answer before exiting
+ Sys_Sleep( 1000 );
+
+ Broadcast_Shutdown();
+
+ exit (1);
+}
+