]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - prvm_edict.c
replaced prvm_tempstringmemory cvar with automatic buffer growth (with a limit of...
[xonotic/darkplaces.git] / prvm_edict.c
index 5f75aa7b9b37c36f3e42277f64db5968f3bf9241..c7c6e61fb9a8f44dff385bcde0d062c30624aae0 100644 (file)
@@ -1870,21 +1870,63 @@ prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
 */
 
 
+sizebuf_t vm_tempstringsbuf;
+
 const char *PRVM_GetString(int num)
 {
-       if (num >= 0 && num < prog->stringssize)
-               return prog->strings + num;
-       else if (num < 0 && num >= -prog->numknownstrings)
+       if (num >= 0)
        {
-               num = -1 - num;
-               if (!prog->knownstrings[num])
-                       PRVM_ERROR("PRVM_GetString: attempt to get string that is already freed");
-               return prog->knownstrings[num];
+               if (num < prog->stringssize)
+                       return prog->strings + num;
+               else
+#if 1
+               if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
+               {
+                       num -= prog->stringssize;
+                       if (num < vm_tempstringsbuf.cursize)
+                               return (char *)vm_tempstringsbuf.data + num;
+                       else
+                       {
+                               VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
+                               return "";
+                       }
+               }
+               else
+#endif
+               {
+                       VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)", num, prog->stringssize);
+                       return "";
+               }
        }
        else
        {
-               PRVM_ERROR("PRVM_GetString: invalid string offset %i", num);
-               return "";
+               num = -1 - num;
+#if 0
+               if (num >= (1<<30))
+               {
+                       // special range reserved for tempstrings
+                       num -= (1<<30);
+                       if (num < vm_tempstringsbuf.cursize)
+                               return (char *)vm_tempstringsbuf.data + num;
+                       else
+                       {
+                               VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
+                               return "";
+                       }
+               }
+               else
+#endif
+               if (num < prog->numknownstrings)
+               {
+                       if (!prog->knownstrings[num])
+                               VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)", num);
+                       return prog->knownstrings[num];
+               }
+               else
+               {
+                       VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)", num, prog->numknownstrings);
+                       return "";
+               }
        }
 }
 
@@ -1895,6 +1937,15 @@ int PRVM_SetEngineString(const char *s)
                return 0;
        if (s >= prog->strings && s <= prog->strings + prog->stringssize)
                PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
+       // if it's in the tempstrings area, use a reserved range
+       // (otherwise we'd get millions of useless string offsets cluttering the database)
+       if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
+#if 1
+               return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
+#else
+               return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
+#endif
+       // see if it's a known string address
        for (i = 0;i < prog->numknownstrings;i++)
                if (prog->knownstrings[i] == s)
                        return -1 - i;
@@ -1926,6 +1977,49 @@ int PRVM_SetEngineString(const char *s)
        return -1 - i;
 }
 
+// temp string handling
+
+// all tempstrings go into this buffer consecutively, and it is reset
+// whenever PRVM_ExecuteProgram returns to the engine
+// (technically each PRVM_ExecuteProgram call saves the cursize value and
+//  restores it on return, so multiple recursive calls can share the same
+//  buffer)
+// the buffer size is automatically grown as needed
+
+int PRVM_SetTempString(const char *s)
+{
+       int size;
+       char *t;
+       if (!s)
+               return 0;
+       size = (int)strlen(s) + 1;
+       if (developer.integer >= 300)
+               Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
+       if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
+       {
+               sizebuf_t old = vm_tempstringsbuf;
+               if (vm_tempstringsbuf.cursize + size >= 1<<28)
+                       PRVM_ERROR("PRVM_SetTempString: ran out of tempstring memory!  (refusing to grow tempstring buffer over 256MB, cursize %i, size %i)\n", vm_tempstringsbuf.cursize, size);
+               vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
+               while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
+                       vm_tempstringsbuf.maxsize *= 2;
+               if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
+               {
+                       if (developer.integer >= 100)
+                               Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
+                       vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
+                       if (old.cursize)
+                               memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
+                       if (old.data)
+                               Mem_Free(old.data);
+               }
+       }
+       t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
+       memcpy(t, s, size);
+       vm_tempstringsbuf.cursize += size;
+       return PRVM_SetEngineString(t);
+}
+
 int PRVM_AllocString(size_t bufferlength, char **pointer)
 {
        int i;