]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake3/common/inout.c
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / tools / quake3 / common / inout.c
diff --git a/tools/quake3/common/inout.c b/tools/quake3/common/inout.c
new file mode 100644 (file)
index 0000000..ede8889
--- /dev/null
@@ -0,0 +1,367 @@
+/*\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 = qfalse;\r
+UINT wm_BroadcastCommand = -1;\r
+#endif\r
+\r
+socket_t *brdcst_socket;\r
+netmessage_t msg;\r
+\r
+qboolean verbose = qfalse;\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 = qfalse;\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 = qtrue;\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 == qfalse))\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