...

View Full Version : Resolved Filling a string with memcpy...



Apothem
08-24-2008, 01:58 AM
So I'm trying to replicate PHP's "implode" syntax to work with a game's scripting engine. As I'm extremely new to C coding (haven't really used it a lot), I have no idea what I'm doing half the times.

Here's the code:

BUILDIN_FUNC(implode)
{
TBL_PC* sd = NULL;
struct script_data* data;
const char* name;
int32 start = 0;
int32 end;
int32 id;
int i, delim_len;
unsigned long len = 0, len_sub = 0;
char *str;
const char *delim_fake;
char *delim;

delim_fake = script_getstr(st, 2);
delim = aMalloc(strlen(delim_fake));
sprintf(delim, "%s", delim_fake);

data = script_getdata(st, 3);
if( !data_isreference(data) )
{
ShowError("script:implode: not a variable\n");
script_reportdata(data);
st->state = END;
return 1;// not a variable
}

id = reference_getid(data);
start = reference_getindex(data);
name = reference_getname(data);
if( not_array_variable(*name) )
{
ShowError("script:implode: illegal scope\n");
script_reportdata(data);
st->state = END;
return 1;// not supported
}

if( not_server_variable(*name) )
{
sd = script_rid2sd(st);
if( sd == NULL )
return 0;// no player attached
}

end = getarraysize(st, id, start, is_string_variable(name), reference_getref(data));
i = start;

if( !end )
script_pushstrcopy(st, "");


for( start; start < end; start++ ) { // Count the length of the string.
void* v;
v = get_val2(st, reference_uid(id, start), reference_getref(data));
len = len + strlen(v);
}

delim_len = strlen(delim);

if( end == 1 ) {
push_val2(st->stack, C_NAME, reference_uid(id, i), reference_getref(data));
return 0;
}

len = len + (end - 1 * delim_len);
str = aMalloc(len);

for( ; i < end; i++ ) {
void* value;
value = get_val2(st, reference_uid(id, i), reference_getref(data));

memcpy(str + len_sub, value, strlen(value) + 1);

len_sub = strlen(value) + len_sub + 1;
if( i != end - 1 ) {
memcpy(str + delim_len, delim, delim_len + 1);
len_sub = len_sub + delim_len + 1;
}
}

script_pushstrcopy(st, str);
return 0;
}

To explain what (I think) some things mean:
TBL_PC* sd = The attached player's data
struct script_data* data = I'm guessing this is for getting ready to use variables.
script_getstr = Gets a constant char variable that was inputted via the game's script.
script_getdata = Get's the data of an inputted value via the game's script.
data_isreference = Checks if the data is a real variable or not.
script_reportdata = I'm guessing this is for error logs.
reference_* = Gets a certain thing of a variable; not really sure what.
getarraysize = Get the size of an inputted array.
get_val2 = Gets a array data depending on the index from reference_uid... the second value in reference_uid is the index for an array.

If you have any other questions about a certain syntax, please ask.
I tried to execute this syntax by:

setarray $@var$[0], "tik", "tak", "toe";
debugmes implode("-", $@var$);

Now here's the problem:
The debugmes always outputs "tik"...

Is anybody able to explain to me what's the problem?

ralph l mayo
08-24-2008, 07:00 AM
I don't feel like deciphering all that but the result you get makes me think you might be copying null terminators from every token, which would make the string look like it was the same as the first argument even if its memory really did contain every string.

When you're using strings, use string functions! You're already using <string.h> for strlen so why are you banging your head against memset at all? strcat was made to do exactly, and I mean EXACTLY, this:



#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
int ii = 1, size = 0;
// Sum lengths
for (; ii < argc; ++ii)
{
size += strlen(argv[ii]);
}

// Allocate
char* combined = calloc(size + 1, 1); // +1 for null terminator, calloc to zero

// Implode
for (ii = 1; ii < argc; ++ii)
{
strcat(combined, argv[ii]);
}
puts(combined);
// Deallocate
free(combined);
return 0;
}

Apothem
08-24-2008, 08:05 AM
Well, that actually worked when you use puts.

For some reason, the returned value of implode() is always the first value...


/// Pushes a string into the stack (script engine frees it automatically)
#define script_pushstr(st,val) push_str((st)->stack, C_STR, (val))
/// Pushes a copy of a string into the stack
#define script_pushstrcopy(st,val) push_str((st)->stack, C_STR, aStrdup(val))
/// Pushes a constant string into the stack (must never change or be freed)
#define script_pushconststr(st,val) push_str((st)->stack, C_CONSTSTR, (val))


void push_str(struct script_stack* stack, enum c_op type, char* str)
{
if( stack->sp >= stack->sp_max )
stack_expand(stack);
stack->stack_data[stack->sp].type = type;
stack->stack_data[stack->sp].u.str = str;
stack->stack_data[stack->sp].ref = NULL;
stack->sp++;
}

Here's the current code:

BUILDIN_FUNC(implode)
{
TBL_PC* sd = NULL;
struct script_data* data;
const char* name;
int32 start = 0;
int32 end;
int32 id;
int i;
unsigned long len = 0;
char *str;
const char *delim;

delim = script_getstr(st, 2);

data = script_getdata(st, 3);
if( !data_isreference(data) )
{
ShowError("script:implode: not a variable\n");
script_reportdata(data);
st->state = END;
return 1;// not a variable
}

id = reference_getid(data);
start = reference_getindex(data);
name = reference_getname(data);
if( not_array_variable(*name) )
{
ShowError("script:implode: illegal scope\n");
script_reportdata(data);
st->state = END;
return 1;// not supported
}

if( not_server_variable(*name) )
{
sd = script_rid2sd(st);
if( sd == NULL )
return 0;// no player attached
}

end = getarraysize(st, id, start, is_string_variable(name), reference_getref(data));
i = start;

if( !end )
script_pushstrcopy(st, "");


for( start; start < end; start++ ) { // Count the length of the string.
void* v;
v = get_val2(st, reference_uid(id, start), reference_getref(data));
len = len + strlen(v);
}

if( end == 1 ) {
push_val2(st->stack, C_NAME, reference_uid(id, i), reference_getref(data));
return 0;
}

len = len + (end - 1 * strlen(delim));

str = calloc(len + 1, 1);

for( ; i < end; i++ ) {
void* v;
v = get_val2(st, reference_uid(id, i), reference_getref(data));
strcat(str, ((char*)v));

if( i != end - 1 ) {
strcat(str, delim);
}
}

script_pushstrcopy(st, str);
return 0;
}

If you wanna see the whole source code, look: http://svn.eathena.ws/svn/ea/trunk/src/map/script.c



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum