sourcepawn/vm/sp_vm.c
author Borja Ferrer <faluco@alliedmods.net>
Sun Aug 06 23:08:02 2006 +0000 (2006-08-06)
changeset 57 2ee48bce97bb
parent 55 ccaca168c18f
child 60 1828af9008a5
permissions -rw-r--r--
debug API implementation
added SetString
dvander@37
     1
#include <limits.h>
faluco@42
     2
#include <string.h>
dvander@37
     3
#include <assert.h>
dvander@55
     4
#include <malloc.h>
dvander@37
     5
#include "sp_vm.h"
dvander@37
     6
dvander@37
     7
#define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
dvander@37
     8
#define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
dvander@37
     9
dvander@37
    10
int main()
dvander@37
    11
{
dvander@37
    12
	/** temporary testing area */
dvander@37
    13
	sp_context_t ctx;
dvander@37
    14
	cell_t l, *p;
faluco@54
    15
	cell_t arr1[] = {1,3,3,7};
faluco@54
    16
	cell_t arr2[] = {123,1234,12345,123456};
faluco@54
    17
	const char *str = "hat hat";
faluco@54
    18
	char buf[20];
dvander@37
    19
dvander@37
    20
	ctx.data = (uint8_t *)malloc(50000);
dvander@37
    21
	ctx.memory = 50000;
dvander@37
    22
	ctx.heapbase = 200;
dvander@37
    23
	ctx.hp = ctx.heapbase;
dvander@37
    24
	ctx.sp = 45000;
dvander@37
    25
dvander@37
    26
	assert(SP_HeapAlloc(&ctx, 500, &l, &p) == SP_ERR_NONE);
dvander@37
    27
	assert(SP_HeapPop(&ctx, l) == SP_ERR_NONE);
dvander@37
    28
	assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE);
dvander@37
    29
	assert(SP_HeapRelease(&ctx, 4) == SP_ERR_INVALID_ADDRESS);
dvander@37
    30
	assert(SP_HeapAlloc(&ctx, 500, &l, &p) == SP_ERR_NONE);
dvander@37
    31
	assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE);
faluco@53
    32
	assert(SP_PushCell(&ctx, 1337) == SP_ERR_NONE);
faluco@54
    33
	assert(SP_PushCellArray(&ctx, &l, &p, arr1, 4) == SP_ERR_NONE);
faluco@54
    34
	assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE);
faluco@54
    35
	assert(SP_PushCellsFromArray(&ctx, arr2, 4) == SP_ERR_NONE);
faluco@54
    36
	assert(SP_PushString(&ctx, &l, &p, str) == SP_ERR_NONE);
faluco@54
    37
	assert(SP_LocalToString(&ctx, l, NULL, buf, 20) == SP_ERR_NONE);
faluco@54
    38
	assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE);
dvander@37
    39
dvander@37
    40
	return 0;
dvander@37
    41
}
dvander@37
    42
dvander@37
    43
int SP_HeapAlloc(sp_context_t *ctx, unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
dvander@37
    44
{
dvander@37
    45
	cell_t *addr;
dvander@37
    46
	ucell_t realmem;
dvander@37
    47
dvander@37
    48
#if 0
dvander@37
    49
	if (cells > CELLBOUNDMAX)
dvander@37
    50
	{
dvander@37
    51
		return SP_ERR_PARAM;
dvander@37
    52
	}
dvander@37
    53
#else
dvander@37
    54
	assert(cells < CELLBOUNDMAX);
dvander@37
    55
#endif
dvander@37
    56
dvander@37
    57
	realmem = cells * sizeof(cell_t);
dvander@37
    58
dvander@37
    59
	/**
dvander@37
    60
	 * Check if the space between the heap and stack is sufficient.
dvander@37
    61
	 */
dvander@37
    62
	if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
dvander@37
    63
	{
dvander@37
    64
		return SP_ERR_HEAPLOW;
dvander@37
    65
	}
dvander@37
    66
dvander@37
    67
	addr = (cell_t *)(ctx->data + ctx->hp);
dvander@37
    68
	/* store size of allocation in cells */
dvander@37
    69
	*addr = (cell_t)cells;
dvander@37
    70
	addr++;
dvander@37
    71
	ctx->hp += sizeof(cell_t);
dvander@37
    72
dvander@37
    73
	*local_addr = ctx->hp;
dvander@37
    74
dvander@37
    75
	if (phys_addr)
dvander@37
    76
	{
dvander@37
    77
		*phys_addr = addr;
dvander@37
    78
	}
dvander@37
    79
dvander@37
    80
	ctx->hp += realmem;
dvander@37
    81
dvander@37
    82
	return SP_ERR_NONE;
dvander@37
    83
}
dvander@37
    84
dvander@37
    85
int SP_HeapPop(sp_context_t *ctx, cell_t local_addr)
dvander@37
    86
{
dvander@37
    87
	cell_t cellcount;
dvander@37
    88
	cell_t *addr;
dvander@37
    89
dvander@37
    90
	/* check the bounds of this address */
dvander@37
    91
	local_addr -= sizeof(cell_t);
dvander@37
    92
	if (local_addr < ctx->heapbase || local_addr >= ctx->sp)
dvander@37
    93
	{
dvander@37
    94
		return SP_ERR_INVALID_ADDRESS;
dvander@37
    95
	}
dvander@37
    96
dvander@37
    97
	addr = (cell_t *)(ctx->data + local_addr);
dvander@37
    98
	cellcount = (*addr) * sizeof(cell_t);
dvander@37
    99
	/* check if this memory count looks valid */
dvander@37
   100
	if (ctx->hp - cellcount - sizeof(cell_t) != local_addr)
dvander@37
   101
	{
dvander@37
   102
		return SP_ERR_INVALID_ADDRESS;
dvander@37
   103
	}
dvander@37
   104
dvander@37
   105
	ctx->hp = local_addr;
dvander@37
   106
dvander@37
   107
	return SP_ERR_NONE;
dvander@37
   108
}
dvander@37
   109
dvander@37
   110
int SP_HeapRelease(sp_context_t *ctx, cell_t local_addr)
dvander@37
   111
{
dvander@37
   112
	if (local_addr < ctx->heapbase)
dvander@37
   113
	{
dvander@37
   114
		return SP_ERR_INVALID_ADDRESS;
dvander@37
   115
	}
dvander@37
   116
dvander@37
   117
	ctx->hp = local_addr - sizeof(cell_t);
dvander@37
   118
dvander@37
   119
	return SP_ERR_NONE;
dvander@37
   120
}
faluco@42
   121
faluco@42
   122
int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index)
faluco@42
   123
{
faluco@53
   124
	uint32_t mid, low, high;
faluco@53
   125
	int diff;
faluco@49
   126
faluco@49
   127
	high = ctx->plugin->info.natives_num - 1;
faluco@49
   128
	low = 0;
faluco@49
   129
faluco@49
   130
	while (low <= high)
faluco@49
   131
	{
faluco@49
   132
		mid = (low + high) / 2;
faluco@49
   133
		diff = strcmp(ctx->natives[mid].name, name);
faluco@49
   134
		if (diff == 0)
faluco@49
   135
		{
faluco@49
   136
			if (index)
faluco@53
   137
			{
faluco@49
   138
				*index = mid;
faluco@53
   139
			}
faluco@49
   140
			return SP_ERR_NONE;
faluco@49
   141
		} else if (diff < 0) {
faluco@49
   142
			low = mid + 1;
faluco@49
   143
		} else {
faluco@49
   144
			high = mid - 1;
faluco@49
   145
		}
faluco@49
   146
	}
faluco@49
   147
faluco@49
   148
	return SP_ERR_NOT_FOUND;
faluco@49
   149
}
faluco@42
   150
faluco@49
   151
int SP_GetNativeByIndex(sp_context_t *ctx, uint32_t index, sp_native_t **native)
faluco@49
   152
{
faluco@49
   153
	if (index >= ctx->plugin->info.natives_num)
faluco@53
   154
	{
faluco@49
   155
		return SP_ERR_INDEX;
faluco@53
   156
	}
faluco@49
   157
faluco@49
   158
	if (native)
faluco@53
   159
	{
faluco@49
   160
		*native = &(ctx->natives[index]);
faluco@53
   161
	}
faluco@49
   162
faluco@49
   163
	return SP_ERR_NONE;
faluco@49
   164
}
faluco@49
   165
faluco@49
   166
int SP_GetNativesNum(sp_context_t *ctx, uint32_t *num)
faluco@49
   167
{
faluco@49
   168
	*num = ctx->plugin->info.natives_num;
faluco@49
   169
faluco@49
   170
	return SP_ERR_NONE;
faluco@49
   171
}
faluco@49
   172
faluco@49
   173
int SP_FindPublicByName(sp_context_t *ctx, const char *name, uint32_t *index)
faluco@49
   174
{
faluco@53
   175
	uint32_t mid, low, high;
faluco@53
   176
	int diff;
faluco@49
   177
faluco@49
   178
	high = ctx->plugin->info.publics_num - 1;
faluco@49
   179
	low = 0;
faluco@49
   180
faluco@49
   181
	while (low <= high)
faluco@42
   182
	{
faluco@49
   183
		mid = (low + high) / 2;
faluco@49
   184
		diff = strcmp(ctx->publics[mid].name, name);
faluco@49
   185
		if (diff == 0)
faluco@42
   186
		{
faluco@42
   187
			if (index)
faluco@53
   188
			{
faluco@49
   189
				*index = mid;
faluco@53
   190
			}
faluco@42
   191
			return SP_ERR_NONE;
faluco@49
   192
		} else if (diff < 0) {
faluco@49
   193
			low = mid + 1;
faluco@49
   194
		} else {
faluco@49
   195
			high = mid - 1;
faluco@42
   196
		}
faluco@42
   197
	}
faluco@49
   198
faluco@42
   199
	return SP_ERR_NOT_FOUND;
faluco@49
   200
}
faluco@49
   201
faluco@49
   202
int SP_GetPublicByIndex(sp_context_t *ctx, uint32_t index, sp_public_t **pblic)
faluco@49
   203
{
faluco@49
   204
	if (index >= ctx->plugin->info.publics_num)
faluco@53
   205
	{
faluco@49
   206
		return SP_ERR_INDEX;
faluco@53
   207
	}
faluco@49
   208
faluco@49
   209
	if (pblic)
faluco@53
   210
	{
faluco@49
   211
		*pblic = &(ctx->publics[index]);
faluco@53
   212
	}
faluco@49
   213
faluco@49
   214
	return SP_ERR_NONE;
faluco@49
   215
}
faluco@49
   216
faluco@49
   217
int SP_GetPublicsNum(sp_context_t *ctx, uint32_t *num)
faluco@49
   218
{
faluco@49
   219
	*num = ctx->plugin->info.publics_num;
faluco@49
   220
faluco@49
   221
	return SP_ERR_NONE;
faluco@49
   222
}
faluco@49
   223
faluco@49
   224
int SP_GetPubvarByIndex(sp_context_t *ctx, uint32_t index, sp_pubvar_t **pubvar)
faluco@49
   225
{
faluco@49
   226
	if (index >= ctx->plugin->info.pubvars_num)
faluco@53
   227
	{
faluco@49
   228
		return SP_ERR_INDEX;
faluco@53
   229
	}
faluco@49
   230
faluco@49
   231
	if (pubvar)
faluco@53
   232
	{
faluco@49
   233
		*pubvar = &(ctx->pubvars[index]);
faluco@53
   234
	}
faluco@49
   235
faluco@49
   236
	return SP_ERR_NONE;
faluco@49
   237
}
faluco@49
   238
faluco@49
   239
int SP_FindPubvarByName(sp_context_t *ctx, const char *name, uint32_t *index)
faluco@49
   240
{
faluco@53
   241
	uint32_t mid, low, high;
faluco@53
   242
	int diff;
faluco@49
   243
faluco@49
   244
	high = ctx->plugin->info.pubvars_num - 1;
faluco@49
   245
	low = 0;
faluco@49
   246
faluco@49
   247
	while (low <= high)
faluco@49
   248
	{
faluco@49
   249
		mid = (low + high) / 2;
faluco@49
   250
		diff = strcmp(ctx->pubvars[mid].name, name);
faluco@49
   251
		if (diff == 0)
faluco@49
   252
		{
faluco@49
   253
			if (index)
faluco@53
   254
			{
faluco@49
   255
				*index = mid;
faluco@53
   256
			}
faluco@49
   257
			return SP_ERR_NONE;
faluco@49
   258
		} else if (diff < 0) {
faluco@49
   259
			low = mid + 1;
faluco@49
   260
		} else {
faluco@49
   261
			high = mid - 1;
faluco@49
   262
		}
faluco@49
   263
	}
faluco@49
   264
faluco@49
   265
	return SP_ERR_NOT_FOUND;
faluco@49
   266
}
faluco@49
   267
faluco@49
   268
int SP_GetPubvarAddrs(sp_context_t *ctx, uint32_t index, cell_t *local_addr, cell_t **phys_addr)
faluco@49
   269
{
faluco@49
   270
	if (index >= ctx->plugin->info.pubvars_num)
faluco@53
   271
	{
faluco@49
   272
		return SP_ERR_INDEX;
faluco@53
   273
	}
faluco@49
   274
faluco@49
   275
	*local_addr = ctx->plugin->info.pubvars[index].address;
faluco@49
   276
	*phys_addr = ctx->pubvars[index].offs;
faluco@49
   277
faluco@49
   278
	return SP_ERR_NONE;
faluco@49
   279
}
faluco@49
   280
faluco@49
   281
int SP_GetPubVarsNum(sp_context_t *ctx, uint32_t *num)
faluco@49
   282
{
faluco@49
   283
	*num = ctx->plugin->info.pubvars_num;
faluco@49
   284
faluco@49
   285
	return SP_ERR_NONE;
faluco@50
   286
}
faluco@50
   287
faluco@50
   288
int SP_BindNatives(sp_context_t *ctx, sp_nativeinfo_t *natives, unsigned int num, int overwrite)
faluco@50
   289
{
faluco@50
   290
	uint32_t i, j, max;
faluco@50
   291
faluco@50
   292
	max = ctx->plugin->info.natives_num;
faluco@50
   293
faluco@50
   294
	for (i=0; i<max; i++)
faluco@50
   295
	{
faluco@51
   296
		if ((ctx->natives[i].status == SP_NATIVE_OKAY) && !overwrite)
faluco@53
   297
		{
faluco@50
   298
			continue;
faluco@53
   299
		}
faluco@50
   300
faluco@50
   301
		for (j=0; (natives[j].name) && (!num || j<num); j++)
faluco@50
   302
		{
faluco@50
   303
			if (!strcmp(ctx->natives[i].name, natives[j].name))
faluco@50
   304
			{
faluco@50
   305
				ctx->natives[i].pfn = natives[j].func;
faluco@50
   306
				ctx->natives[i].status = SP_NATIVE_OKAY;
faluco@50
   307
			}
faluco@50
   308
		}
faluco@50
   309
	}
faluco@50
   310
faluco@50
   311
	return SP_ERR_NONE;
faluco@50
   312
}
faluco@50
   313
faluco@50
   314
int SP_BindNative(sp_context_t *ctx, sp_nativeinfo_t *native, uint32_t status)
faluco@50
   315
{
faluco@53
   316
	uint32_t index;
faluco@53
   317
	int err;
faluco@50
   318
faluco@50
   319
	if ((err = SP_FindNativeByName(ctx, native->name, &index)) != SP_ERR_NONE)
faluco@53
   320
	{
faluco@50
   321
		return err;
faluco@53
   322
	}
faluco@50
   323
faluco@50
   324
	ctx->natives[index].pfn = native->func;
faluco@50
   325
	ctx->natives[index].status = status;
faluco@50
   326
faluco@50
   327
	return SP_ERR_NONE;
faluco@50
   328
}
faluco@50
   329
faluco@50
   330
int SP_BindNativeToAny(sp_context_t *ctx, SPVM_NATIVE_FUNC native)
faluco@50
   331
{
faluco@50
   332
	uint32_t nativesnum, i;
faluco@50
   333
faluco@50
   334
	nativesnum = ctx->plugin->info.natives_num;
faluco@50
   335
faluco@50
   336
	for (i=0; i<nativesnum; i++)
faluco@50
   337
	{
faluco@50
   338
		if (ctx->natives[i].status != SP_NATIVE_OKAY)
faluco@50
   339
		{
faluco@50
   340
			ctx->natives[i].pfn = native;
faluco@50
   341
			ctx->natives[i].status = SP_NATIVE_PENDING;
faluco@50
   342
		}
faluco@50
   343
	}
faluco@50
   344
faluco@50
   345
	return SP_ERR_NONE;
faluco@51
   346
}
faluco@51
   347
faluco@51
   348
int SP_LocalToPhysAddr(sp_context_t *ctx, cell_t local_addr, cell_t **phys_addr)
faluco@51
   349
{
faluco@51
   350
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory))
faluco@53
   351
	{
faluco@51
   352
		return SP_ERR_INVALID_ADDRESS;
faluco@53
   353
	}
faluco@53
   354
faluco@51
   355
	if (phys_addr)
faluco@53
   356
	{
faluco@51
   357
		*phys_addr = (cell_t *)(ctx->data + local_addr);
faluco@53
   358
	}
faluco@53
   359
faluco@53
   360
	return SP_ERR_NONE;
faluco@53
   361
}
faluco@53
   362
faluco@53
   363
int SP_PushCell(sp_context_t *ctx, cell_t value)
faluco@53
   364
{
faluco@53
   365
	if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
faluco@53
   366
	{
faluco@53
   367
		return SP_ERR_HEAPLOW;
faluco@53
   368
	}
faluco@53
   369
faluco@53
   370
	ctx->sp -= sizeof(cell_t);
faluco@53
   371
	*(cell_t *)(ctx->data + ctx->sp) = value;
faluco@53
   372
	ctx->pushcount++;
faluco@51
   373
faluco@51
   374
	return SP_ERR_NONE;
faluco@53
   375
}
faluco@53
   376
faluco@53
   377
int SP_PushCellsFromArray(sp_context_t *ctx, cell_t array[], unsigned int numcells)
faluco@53
   378
{
faluco@53
   379
	unsigned int i;
faluco@53
   380
	int err;
faluco@53
   381
faluco@53
   382
	for (i=0; i<numcells; i++)
faluco@53
   383
	{
faluco@53
   384
		if ((err = SP_PushCell(ctx, array[i])) != SP_ERR_NONE)
faluco@53
   385
		{
faluco@53
   386
			ctx->sp += i * sizeof(cell_t);
faluco@53
   387
			ctx->pushcount -= i;
faluco@53
   388
			return err;
faluco@53
   389
		}
faluco@53
   390
	}
faluco@53
   391
faluco@53
   392
	return SP_ERR_NONE;
faluco@53
   393
}
faluco@53
   394
faluco@53
   395
int SP_PushCellArray(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
faluco@53
   396
{
faluco@53
   397
	cell_t *ph_addr;
faluco@53
   398
	int err;
faluco@53
   399
faluco@53
   400
	if ((err = SP_HeapAlloc(ctx, numcells, local_addr, &ph_addr)) != SP_ERR_NONE)
faluco@53
   401
	{
faluco@53
   402
		return err;
faluco@53
   403
	}
faluco@53
   404
faluco@53
   405
	memcpy(ph_addr, array, numcells * sizeof(cell_t));
faluco@53
   406
faluco@53
   407
	if ((err = SP_PushCell(ctx, *local_addr)) != SP_ERR_NONE)
faluco@53
   408
	{
faluco@53
   409
		SP_HeapRelease(ctx, *local_addr);
faluco@53
   410
		return err;
faluco@53
   411
	}
faluco@53
   412
faluco@57
   413
	if (phys_addr)
faluco@57
   414
	{
faluco@57
   415
		*phys_addr = ph_addr;
faluco@57
   416
	}
faluco@57
   417
faluco@53
   418
	return SP_ERR_NONE;
faluco@53
   419
}
faluco@54
   420
faluco@54
   421
int SP_LocalToString(sp_context_t *ctx, cell_t local_addr, int *chars, char *buffer, size_t maxlength)
faluco@54
   422
{
faluco@54
   423
	size_t len = 0;
faluco@54
   424
	cell_t *src;
faluco@54
   425
faluco@54
   426
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory))
faluco@54
   427
	{
faluco@54
   428
		return SP_ERR_INVALID_ADDRESS;
faluco@54
   429
	}
faluco@54
   430
faluco@54
   431
	src = (cell_t *)(ctx->data + local_addr);
faluco@54
   432
	while ((*src != '\0') && (len < maxlength))
faluco@54
   433
	{
faluco@54
   434
		buffer[len++] = (char)*src++;
faluco@54
   435
	}
faluco@54
   436
faluco@54
   437
	if (len >= maxlength)
faluco@54
   438
	{
faluco@54
   439
		len = maxlength - 1;
faluco@54
   440
	}
faluco@54
   441
	if (len >= 0)
faluco@54
   442
	{
faluco@54
   443
		buffer[len] = '\0';
faluco@54
   444
	}
faluco@54
   445
faluco@54
   446
	if (chars)
faluco@54
   447
	{
faluco@54
   448
		*chars = len;
faluco@54
   449
	}
faluco@54
   450
faluco@54
   451
	return SP_ERR_NONE;
faluco@54
   452
}
faluco@54
   453
faluco@54
   454
int SP_PushString(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, const char *string)
faluco@54
   455
{
faluco@54
   456
	cell_t *ph_addr;
faluco@54
   457
	int err;
faluco@54
   458
	unsigned int i, numcells = strlen(string);
faluco@54
   459
faluco@54
   460
	if ((err = SP_HeapAlloc(ctx, numcells+1, local_addr, &ph_addr)) != SP_ERR_NONE)
faluco@54
   461
	{
faluco@54
   462
		return err;
faluco@54
   463
	}
faluco@54
   464
faluco@54
   465
	for (i=0; i<numcells; i++)
faluco@54
   466
	{
faluco@54
   467
		ph_addr[i] = (cell_t)string[i];
faluco@54
   468
	}
faluco@54
   469
	ph_addr[numcells] = '\0';
faluco@54
   470
faluco@54
   471
	if ((err = SP_PushCell(ctx, *local_addr)) != SP_ERR_NONE)
faluco@54
   472
	{
faluco@54
   473
		SP_HeapRelease(ctx, *local_addr);
faluco@54
   474
		return err;
faluco@54
   475
	}
faluco@54
   476
faluco@57
   477
	if (phys_addr)
faluco@57
   478
	{
faluco@57
   479
		*phys_addr = ph_addr;
faluco@57
   480
	}
faluco@57
   481
faluco@54
   482
	return SP_ERR_NONE;
faluco@54
   483
}
faluco@57
   484
faluco@57
   485
int SP_StringToLocal(sp_context_t *ctx, cell_t local_addr, size_t chars, const char *source)
faluco@57
   486
{
faluco@57
   487
	cell_t *dest;
faluco@57
   488
	size_t i, len;
faluco@57
   489
faluco@57
   490
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory))
faluco@57
   491
	{
faluco@57
   492
		return SP_ERR_INVALID_ADDRESS;
faluco@57
   493
	}
faluco@57
   494
faluco@57
   495
	len = strlen(source);
faluco@57
   496
	dest = (cell_t *)(ctx->data + local_addr);
faluco@57
   497
faluco@57
   498
	if (len >= chars)
faluco@57
   499
	{
faluco@57
   500
		len = chars - 1;
faluco@57
   501
	}
faluco@57
   502
faluco@57
   503
	for (i=0; i<len; i++)
faluco@57
   504
	{
faluco@57
   505
		dest[i] = (cell_t)source[i];
faluco@57
   506
	}
faluco@57
   507
	dest[len] = '\0';
faluco@57
   508
faluco@57
   509
	return SP_ERR_NONE;
faluco@57
   510
}