Work-in-progress extension: DP_QC_STRINGBUFFERS_EXT_WIP.
authorvortex <vortex@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 20 Mar 2012 21:55:04 +0000 (21:55 +0000)
committervortex <vortex@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 20 Mar 2012 21:55:04 +0000 (21:55 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11767 d7cf8633-e32d-0410-b094-e92efae38249

clvm_cmds.c
dpdefs/dpextensions.qc
mvm_cmds.c
progsvm.h
prvm_cmds.c
prvm_cmds.h
svvm_cmds.c

index cdb8f42..b1ed103 100644 (file)
@@ -4742,10 +4742,10 @@ VM_CL_setpause,                                 // #531 float(float ispaused) setpause = #531 (DP_CSQC_SETPA
 VM_log,                                                        // #532
 VM_getsoundtime,                               // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
 VM_soundlength,                                        // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
-NULL,                                                  // #535
-NULL,                                                  // #536
-NULL,                                                  // #537
-NULL,                                                  // #538
+VM_buf_loadfile,                // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_buf_writefile,               // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_bufstr_find,                 // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_matchpattern,                // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
 NULL,                                                  // #539
 VM_physics_enable,                             // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
 VM_physics_addforce,                   // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
index 0acf262..96f9835 100644 (file)
@@ -2485,6 +2485,28 @@ void(float bufhandle, float string_index) bufstr_free = #469;
 //cvars that start with pattern but not with antipattern will be stored into the buffer
 void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517;
 
+//DP_QC_STRINGBUFFERS_EXT_WIP
+//idea: VorteX
+//darkplaces implementation: VorteX
+//constant definitions:
+const float MATCH_AUTO = 0;
+const float MATCH_WHOLE = 1;
+const float MATCH_LEFT = 2;
+const float MATCH_RIGHT = 3;
+const float MATCH_MIDDLE = 4;
+const float MATCH_PATTERN = 5;
+//builtin definitions:
+float(string filename, float bufhandle) buf_loadfile = #535; // append each line of file as new buffer string, return 1 if succesful
+float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile = #536; // writes buffer strings as lines, returns 1 if succesful
+float(float bufhandle, string match, float matchrule, float startpos, float step) bufstr_find = #537; // returns string index
+float(string s, string pattern, float matchrule) matchpattern = #538; // returns 0/1
+float(string s, string pattern, float matchrule, float pos) matchpatternofs = #538;
+//description:
+//provides a set of functions to manipulate with string buffers
+//pattern wildcards: * - any character (or no characters), ? - any 1 character
+//Warning: This extension is work-in-progress, it may be changed/revamped/removed at any time, dont use it if you dont want any trouble
+//wip note: UTF8 is not supported yet
+
 //DP_QC_STRREPLACE
 //idea: Sajt
 //darkplaces implementation: Sajt
index 79edacf..63a798b 100644 (file)
@@ -36,6 +36,7 @@ const char *vm_m_extensions =
 "DP_QC_STRFTIME "
 "DP_QC_STRINGBUFFERS "
 "DP_QC_STRINGBUFFERS_CVARLIST "
+"DP_QC_STRINGBUFFERS_EXT_WIP "
 "DP_QC_STRINGCOLORFUNCTIONS "
 "DP_QC_STRING_CASE_FUNCTIONS "
 "DP_QC_STRREPLACE "
@@ -1434,10 +1435,10 @@ NULL,                                                                   // #531
 VM_log,                                                                        // #532
 VM_getsoundtime,                                               // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
 VM_soundlength,                                                        // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
-NULL,                                                                  // #535
-NULL,                                                                  // #536
-NULL,                                                                  // #537
-NULL,                                                                  // #538
+VM_buf_loadfile,                        // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_buf_writefile,                       // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_bufstr_find,                         // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_matchpattern,                        // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
 NULL,                                                                  // #539
 NULL,                                                                  // #540
 NULL,                                                                  // #541
index b87822a..343b99b 100644 (file)
--- a/progsvm.h
+++ b/progsvm.h
@@ -512,7 +512,6 @@ prvm_prog_funcoffsets_t;
 
 // stringbuffer flags
 #define STRINGBUFFER_SAVED     1 // saved in savegames
-
 typedef struct prvm_stringbuffer_s
 {
        int max_strings;
index c4a4866..e45c409 100644 (file)
@@ -4627,7 +4627,7 @@ void VM_buf_create (prvm_prog_t *prog)
        int i;
        
        VM_SAFEPARMCOUNTRANGE(0, 2, VM_buf_create);
-
+       
        // VorteX: optional parm1 (buffer format) is unfinished, to keep intact with future databuffers extension must be set to "string"
        if(prog->argc >= 1 && strcmp(PRVM_G_STRING(OFS_PARM0), "string"))
        {
@@ -4991,11 +4991,358 @@ void VM_bufstr_free (prvm_prog_t *prog)
        BufStr_Shrink(prog, stringbuffer);
 }
 
+/*
+========================
+VM_buf_loadfile
+load a file into string buffer, return 0 or 1
+float buf_loadfile(string filename, float bufhandle) = #535;
+========================
+*/
+void VM_buf_loadfile(prvm_prog_t *prog)
+{
+       size_t alloclen;
+       prvm_stringbuffer_t *stringbuffer;
+       char string[VM_STRINGTEMP_LENGTH];
+       int filenum, strindex, c, end;
+       const char *filename;
+       char vabuf[1024];
 
+       VM_SAFEPARMCOUNT(2, VM_buf_loadfile);
 
+       // get file
+       filename = PRVM_G_STRING(OFS_PARM0);
+       for (filenum = 0;filenum < PRVM_MAX_OPENFILES;filenum++)
+               if (prog->openfiles[filenum] == NULL)
+                       break;
+       prog->openfiles[filenum] = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "data/%s", filename), false);
+       if (prog->openfiles[filenum] == NULL)
+               prog->openfiles[filenum] = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "%s", filename), false);
+       if (prog->openfiles[filenum] == NULL)
+       {
+               if (developer_extra.integer)
+                       VM_Warning(prog, "VM_buf_loadfile: failed to open file %s in %s\n", filename, prog->name, filename);
+               PRVM_G_FLOAT(OFS_RETURN) = 0;
+               return;
+       }
 
+       // get string buffer
+       stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM1));
+       if(!stringbuffer)
+       {
+               VM_Warning(prog, "VM_buf_loadfile: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM1), prog->name);
+               PRVM_G_FLOAT(OFS_RETURN) = 0;
+               return;
+       }
 
+       // read file (append to the end of buffer)
+       strindex = stringbuffer->num_strings;
+       while(1)
+       {
+               // read line
+               end = 0;
+               for (;;)
+               {
+                       c = FS_Getc(prog->openfiles[filenum]);
+                       if (c == '\r' || c == '\n' || c < 0)
+                               break;
+                       if (end < VM_STRINGTEMP_LENGTH - 1)
+                               string[end++] = c;
+               }
+               string[end] = 0;
+               // remove \n following \r
+               if (c == '\r')
+               {
+                       c = FS_Getc(prog->openfiles[filenum]);
+                       if (c != '\n')
+                               FS_UnGetc(prog->openfiles[filenum], (unsigned char)c);
+               }
+               // add and continue
+               if (c >= 0 || end)
+               {
+                       BufStr_Expand(prog, stringbuffer, strindex);
+                       stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1);
+                       alloclen = strlen(string) + 1;
+                       stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen);
+                       memcpy(stringbuffer->strings[strindex], string, alloclen);
+                       strindex = stringbuffer->num_strings;
+               }
+               else
+                       break;
+       }
 
+       // close file
+       FS_Close(prog->openfiles[filenum]);
+       prog->openfiles[filenum] = NULL;
+       if (prog->openfiles_origin[filenum])
+               PRVM_Free((char *)prog->openfiles_origin[filenum]);
+       PRVM_G_FLOAT(OFS_RETURN) = 1;
+}
+
+/*
+========================
+VM_buf_writefile
+writes stringbuffer to a file, returns 0 or 1
+float buf_writefile(float filehandle, float bufhandle, [, float startpos, float numstrings]) = #468;
+========================
+*/
+
+void VM_buf_writefile(prvm_prog_t *prog)
+{
+       int filenum, strindex, strnum, strlength;
+       prvm_stringbuffer_t *stringbuffer;
+
+       VM_SAFEPARMCOUNTRANGE(2, 4, VM_buf_writefile);
+
+       // get file
+       filenum = (int)PRVM_G_FLOAT(OFS_PARM0);
+       if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES)
+       {
+               VM_Warning(prog, "VM_buf_writefile: invalid file handle %i used in %s\n", filenum, prog->name);
+               return;
+       }
+       if (prog->openfiles[filenum] == NULL)
+       {
+               VM_Warning(prog, "VM_buf_writefile: no such file handle %i (or file has been closed) in %s\n", filenum, prog->name);
+               return;
+       }
+       
+       // get string buffer
+       stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM1));
+       if(!stringbuffer)
+       {
+               VM_Warning(prog, "VM_buf_writefile: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM1), prog->name);
+               PRVM_G_FLOAT(OFS_RETURN) = 0;
+               return;
+       }
+
+       // get start and end parms
+       if (prog->argc > 3)
+       {
+               strindex = (int)PRVM_G_FLOAT(OFS_PARM2);
+               strnum = (int)PRVM_G_FLOAT(OFS_PARM3);
+       }
+       else if (prog->argc > 2)
+       {
+               strindex = (int)PRVM_G_FLOAT(OFS_PARM2);
+               strnum = stringbuffer->num_strings - strindex;
+       }
+       else
+       {
+               strindex = 0;
+               strnum = stringbuffer->num_strings;
+       }
+       if (strindex < 0 || strindex >= stringbuffer->num_strings)
+       {
+               VM_Warning(prog, "VM_buf_writefile: wrong start string index %i used in %s\n", strindex, prog->name);
+               PRVM_G_FLOAT(OFS_RETURN) = 0;
+               return;
+       }
+       if (strnum < 0)
+       {
+               VM_Warning(prog, "VM_buf_writefile: wrong strings count %i used in %s\n", strnum, prog->name);
+               PRVM_G_FLOAT(OFS_RETURN) = 0;
+               return;
+       }
+
+       // write
+       while(strindex < stringbuffer->num_strings && strnum)
+       {
+               if (stringbuffer->strings[strindex])
+               {
+                       if ((strlength = strlen(stringbuffer->strings[strindex])))
+                               FS_Write(prog->openfiles[filenum], stringbuffer->strings[strindex], strlength);
+                       FS_Write(prog->openfiles[filenum], "\n", 1);
+               }
+               strindex++;
+               strnum--;
+       }
+
+       PRVM_G_FLOAT(OFS_RETURN) = 1;
+}
+
+#define MATCH_AUTO     0
+#define MATCH_WHOLE    1
+#define MATCH_LEFT     2
+#define MATCH_RIGHT    3
+#define MATCH_MIDDLE   4
+#define MATCH_PATTERN  5
+
+const char *detect_match_rule(char *pattern, int *matchrule)
+{
+       char *ppos, *qpos;
+       int patternlength;
+
+       patternlength = strlen(pattern);
+       ppos = strchr(pattern, '*');
+       qpos = strchr(pattern, '?');
+       // has ? - pattern
+       if (qpos) 
+       {
+               *matchrule = MATCH_PATTERN;
+               return pattern;
+       }
+       // has * - left, mid, right or pattern
+       if (ppos)
+       {
+               // starts with * - may be right/mid or pattern
+               if ((ppos - pattern) == 0)
+               {
+                       ppos = strchr(pattern+1, '*');
+                       // *something 
+                       if (!ppos) 
+                       {
+                               *matchrule = MATCH_RIGHT;
+                               return pattern+1;
+                       }
+                       // *something*
+                       if ((ppos - pattern) == patternlength)
+                       {
+                               *matchrule = MATCH_MIDDLE;
+                               *ppos = 0;
+                               return pattern+1;
+                       }
+                       // *som*thing
+                       *matchrule = MATCH_PATTERN;
+                       return pattern;
+               }
+               // end with * - left
+               if ((ppos - pattern) == patternlength)
+               {
+                       *matchrule = MATCH_LEFT;
+                       *ppos = 0;
+                       return pattern;
+               }
+               // som*thing
+               *matchrule = MATCH_PATTERN;
+               return pattern;
+       }
+       // have no wildcards - whole string
+       *matchrule = MATCH_WHOLE;
+       return pattern;
+}
+
+// todo: support UTF8
+qboolean match_rule(const char *string, int max_string, const char *pattern, int patternlength, int rule)
+{
+       const char *mid;
+
+       if (rule == 1)
+               return !strncmp(string, pattern, max_string) ? true : false;
+       if (rule == 2)
+               return !strncmp(string, pattern, patternlength) ? true : false;
+       if (rule == 3)
+       {
+               mid = strstr(string, pattern);
+               return mid && !*(mid+patternlength);
+       }
+       if (rule == 4)
+               return strstr(string, pattern) ? true : false;
+       // pattern
+       return matchpattern_with_separator(string, pattern, false, "", false) ? true : false;
+}
+
+/*
+========================
+VM_bufstr_find
+find an index of bufstring matching rule
+float bufstr_find(float bufhandle, string match, float matchrule, float startpos, float step) = #468;
+========================
+*/
+
+void VM_bufstr_find(prvm_prog_t *prog)
+{
+       prvm_stringbuffer_t *stringbuffer;
+       char string[VM_STRINGTEMP_LENGTH];
+       int matchrule, matchlen, i, step;
+       const char *match;
+       
+       VM_SAFEPARMCOUNTRANGE(3, 5, VM_bufstr_find);
+
+       PRVM_G_FLOAT(OFS_RETURN) = -1;
+
+       // get string buffer
+       stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0));
+       if(!stringbuffer)
+       {
+               VM_Warning(prog, "VM_bufstr_find: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name);
+               return;
+       }
+
+       // get pattern/rule
+       matchrule = (int)PRVM_G_FLOAT(OFS_PARM2);
+       if (matchrule < 0 && matchrule > 5)
+       {
+               VM_Warning(prog, "VM_bufstr_find: invalid match rule %i in %s\n", matchrule, prog->name);
+               return;
+       }
+       if (matchrule)
+               match = PRVM_G_STRING(OFS_PARM1);
+       else
+       {
+               strlcpy(string, PRVM_G_STRING(OFS_PARM1), sizeof(string));
+               match = detect_match_rule(string, &matchrule);
+       }
+       matchlen = strlen(match);
+
+       // find
+       i = (prog->argc > 3) ? (int)PRVM_G_FLOAT(OFS_PARM3) : 0;
+       step = (prog->argc > 4) ? (int)PRVM_G_FLOAT(OFS_PARM4) : 1;
+       while(i < stringbuffer->num_strings)
+       {
+               if (stringbuffer->strings[i] && match_rule(stringbuffer->strings[i], VM_STRINGTEMP_LENGTH, match, matchlen, matchrule))
+               {
+                       PRVM_G_FLOAT(OFS_RETURN) = i;
+                       break;
+               }
+               i += step;
+       }
+}
+
+/*
+========================
+VM_matchpattern
+float matchpattern(string s, string pattern, float matchrule, float startpos) = #468;
+========================
+*/
+void VM_matchpattern(prvm_prog_t *prog)
+{
+       const char *s, *match;
+       char string[VM_STRINGTEMP_LENGTH];
+       int matchrule, l;
+
+       VM_SAFEPARMCOUNTRANGE(2, 4, VM_matchpattern);
+
+       s = PRVM_G_STRING(OFS_PARM0);
+
+       // get pattern/rule
+       matchrule = (int)PRVM_G_FLOAT(OFS_PARM2);
+       if (matchrule < 0 && matchrule > 5)
+       {
+               VM_Warning(prog, "VM_bufstr_find: invalid match rule %i in %s\n", matchrule, prog->name);
+               return;
+       }
+       if (matchrule)
+               match = PRVM_G_STRING(OFS_PARM1);
+       else
+       {
+               strlcpy(string, PRVM_G_STRING(OFS_PARM1), sizeof(string));
+               match = detect_match_rule(string, &matchrule);
+       }
+
+       // offset
+       l = strlen(match);
+       if (prog->argc > 3)
+               s += max(0, min((unsigned int)PRVM_G_FLOAT(OFS_PARM3), strlen(s)-1));
+
+       // match
+       PRVM_G_FLOAT(OFS_RETURN) = match_rule(s, VM_STRINGTEMP_LENGTH, match, l, matchrule);
+}
+
+/*
+========================
+VM_buf_cvarlist
+========================
+*/
 
 void VM_buf_cvarlist(prvm_prog_t *prog)
 {
index 7679336..39ec496 100644 (file)
@@ -410,6 +410,11 @@ void VM_bufstr_set (prvm_prog_t *prog);
 void VM_bufstr_add (prvm_prog_t *prog);
 void VM_bufstr_free (prvm_prog_t *prog);
 
+void VM_buf_loadfile(prvm_prog_t *prog);
+void VM_buf_writefile(prvm_prog_t *prog);
+void VM_bufstr_find(prvm_prog_t *prog);
+void VM_matchpattern(prvm_prog_t *prog);
+
 void VM_changeyaw (prvm_prog_t *prog);
 void VM_changepitch (prvm_prog_t *prog);
 
index 6612f27..2fd3464 100644 (file)
@@ -125,6 +125,7 @@ const char *vm_sv_extensions =
 "DP_QC_STRFTIME "
 "DP_QC_STRINGBUFFERS "
 "DP_QC_STRINGBUFFERS_CVARLIST "
+"DP_QC_STRINGBUFFERS_EXT_WIP "
 "DP_QC_STRINGCOLORFUNCTIONS "
 "DP_QC_STRING_CASE_FUNCTIONS "
 "DP_QC_STRREPLACE "
@@ -3701,10 +3702,10 @@ VM_SV_setpause,                                 // #531 void(float pause) setpause = #531;
 VM_log,                                                        // #532
 VM_getsoundtime,                               // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
 VM_soundlength,                                        // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
-NULL,                                                  // #535
-NULL,                                                  // #536
-NULL,                                                  // #537
-NULL,                                                  // #538
+VM_buf_loadfile,                // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_buf_writefile,               // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_bufstr_find,                 // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_matchpattern,                // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
 NULL,                                                  // #539
 VM_physics_enable,                             // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
 VM_physics_addforce,                   // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)