core/smn_string.cpp
author Scott Ehlert <ds@alliedmods.net>
Sat Apr 21 17:03:28 2007 +0000 (2007-04-21)
changeset 702 ff520b71249c
parent 681 02f6c1c5fd06
child 748 0433498ab05c
permissions -rw-r--r--
Wow, how did I forget this - exported IMemoryUtils interface
dvander@370
     1
/**
ds@653
     2
 * vim: set ts=4 :
dvander@370
     3
 * ===============================================================
dvander@370
     4
 * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
dvander@370
     5
 * ===============================================================
dvander@370
     6
 *
dvander@370
     7
 * This file is not open source and may not be copied without explicit
dvander@370
     8
 * written permission of AlliedModders LLC.  This file may not be redistributed 
dvander@370
     9
 * in whole or significant part.
dvander@370
    10
 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
dvander@370
    11
 *
dvander@370
    12
 * Version: $Id$
dvander@370
    13
 */
dvander@370
    14
faluco@225
    15
#include <string.h>
dvander@233
    16
#include <stdlib.h>
dvander@233
    17
#include "sm_globals.h"
faluco@230
    18
#include "sm_stringutil.h"
dvander@631
    19
#include "TextParsers.h"
faluco@225
    20
faluco@225
    21
inline const char *_strstr(const char *str, const char *substr)
faluco@225
    22
{
faluco@225
    23
#ifdef PLATFORM_WINDOWS
faluco@225
    24
	return strstr(str, substr);
dvander@351
    25
#elif defined PLATFORM_LINUX
faluco@225
    26
	return (const char *)strstr(str, substr);
faluco@225
    27
#endif
faluco@225
    28
}
faluco@225
    29
faluco@225
    30
/*********************************************
faluco@225
    31
*                                            *
faluco@225
    32
* STRING MANIPULATION NATIVE IMPLEMENTATIONS *
faluco@225
    33
*                                            *
faluco@225
    34
*********************************************/
faluco@225
    35
faluco@225
    36
static cell_t sm_strlen(IPluginContext *pCtx, const cell_t *params)
faluco@225
    37
{
faluco@225
    38
	char *str;
faluco@225
    39
	pCtx->LocalToString(params[1], &str);
faluco@225
    40
faluco@225
    41
	return strlen(str);
faluco@225
    42
}
faluco@225
    43
faluco@225
    44
static cell_t sm_contain(IPluginContext *pCtx, const cell_t *params)
faluco@225
    45
{
faluco@225
    46
	typedef const char *(*STRSEARCH)(const char *, const char *);
faluco@225
    47
	STRSEARCH func;
faluco@225
    48
	char *str, *substr;
faluco@225
    49
faluco@225
    50
	pCtx->LocalToString(params[1], &str);
faluco@225
    51
	pCtx->LocalToString(params[2], &substr);
faluco@225
    52
faluco@225
    53
	func = (params[3]) ? _strstr : stristr;
faluco@225
    54
	const char *pos = func(str, substr);
faluco@225
    55
	if (pos)
faluco@225
    56
	{
faluco@225
    57
		return (pos - str);
faluco@225
    58
	}
faluco@225
    59
faluco@225
    60
	return -1;
faluco@225
    61
}
faluco@225
    62
dvander@233
    63
static cell_t sm_strcmp(IPluginContext *pCtx, const cell_t *params)
faluco@225
    64
{
faluco@225
    65
	typedef int (*STRCOMPARE)(const char *, const char *);
faluco@225
    66
	STRCOMPARE func;
faluco@225
    67
	char *str1, *str2;
faluco@225
    68
faluco@225
    69
	pCtx->LocalToString(params[1], &str1);
faluco@225
    70
	pCtx->LocalToString(params[2], &str2);
faluco@225
    71
faluco@225
    72
	func = (params[3]) ? strcmp : stricmp;
faluco@225
    73
dvander@233
    74
	return (func(str1, str2));
faluco@225
    75
}
faluco@225
    76
dvander@680
    77
static cell_t sm_strncmp(IPluginContext *pCtx, const cell_t *params)
dvander@680
    78
{
dvander@680
    79
	char *str1, *str2;
dvander@680
    80
dvander@680
    81
	pCtx->LocalToString(params[1], &str1);
dvander@680
    82
	pCtx->LocalToString(params[2], &str2);
dvander@680
    83
	
dvander@680
    84
	if  (params[4])
dvander@680
    85
	{
dvander@680
    86
		return strncmp(str1, str2, (size_t)params[3]);
dvander@680
    87
	} else {
dvander@680
    88
		return strncasecmp(str1, str2, (size_t)params[3]);
dvander@680
    89
	}
dvander@680
    90
}
dvander@680
    91
faluco@225
    92
static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params)
faluco@225
    93
{
faluco@230
    94
	char *dest, *src;
faluco@225
    95
faluco@225
    96
	pCtx->LocalToString(params[1], &dest);
faluco@225
    97
	pCtx->LocalToString(params[3], &src);
faluco@225
    98
faluco@230
    99
	return strncopy(dest, src, params[2]);
faluco@225
   100
}
faluco@226
   101
dvander@233
   102
static cell_t sm_strconvint(IPluginContext *pCtx, const cell_t *params)
faluco@226
   103
{
dvander@233
   104
	char *str, *dummy;
faluco@226
   105
	pCtx->LocalToString(params[1], &str);
faluco@226
   106
dvander@233
   107
	return static_cast<cell_t>(strtol(str, &dummy, params[2]));
faluco@226
   108
}
faluco@226
   109
faluco@226
   110
static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params)
faluco@226
   111
{
faluco@226
   112
	char *str;
faluco@226
   113
	pCtx->LocalToString(params[2], &str);
faluco@274
   114
	size_t res = UTIL_Format(str, params[3], "%d", params[1]);
faluco@226
   115
faluco@274
   116
	return static_cast<cell_t>(res);
faluco@226
   117
}
faluco@226
   118
faluco@226
   119
static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params)
faluco@226
   120
{
dvander@233
   121
	char *str, *dummy;
faluco@226
   122
	pCtx->LocalToString(params[1], &str);
faluco@226
   123
dvander@233
   124
	float val = (float)strtod(str, &dummy);
dvander@233
   125
dvander@233
   126
	return sp_ftoc(val);
faluco@226
   127
}
faluco@226
   128
faluco@226
   129
static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params)
faluco@226
   130
{
faluco@226
   131
	char *str;
faluco@226
   132
	pCtx->LocalToString(params[2], &str);
faluco@274
   133
	size_t res = UTIL_Format(str, params[3], "%f", sp_ctof(params[1]));
faluco@226
   134
faluco@274
   135
	return static_cast<cell_t>(res);
faluco@226
   136
}
dvander@233
   137
faluco@236
   138
static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params)
faluco@236
   139
{
faluco@236
   140
	char *buf, *fmt;
faluco@236
   141
	size_t res;
faluco@236
   142
	int arg = 4;
faluco@236
   143
faluco@236
   144
	pCtx->LocalToString(params[1], &buf);
faluco@236
   145
	pCtx->LocalToString(params[3], &fmt);
faluco@236
   146
	res = atcprintf(buf, static_cast<size_t>(params[2]), fmt, pCtx, params, &arg);
faluco@236
   147
faluco@236
   148
	return static_cast<cell_t>(res);
faluco@236
   149
}
faluco@236
   150
faluco@236
   151
static char g_formatbuf[2048];
faluco@236
   152
static cell_t sm_format(IPluginContext *pCtx, const cell_t *params)
faluco@236
   153
{
faluco@236
   154
	char *buf, *fmt, *destbuf;
faluco@236
   155
	cell_t start_addr, end_addr, maxparam;
faluco@236
   156
	size_t res, maxlen;
faluco@236
   157
	int arg = 4;
faluco@236
   158
	bool copy = false;
faluco@236
   159
faluco@236
   160
	pCtx->LocalToString(params[1], &destbuf);
faluco@236
   161
	pCtx->LocalToString(params[3], &fmt);
faluco@236
   162
faluco@236
   163
	maxlen = static_cast<size_t>(params[2]);
faluco@236
   164
	start_addr = params[1];
faluco@236
   165
	end_addr = params[1] + maxlen;
faluco@236
   166
	maxparam = params[0];
faluco@236
   167
faluco@236
   168
	for (cell_t i=3; i<=maxparam; i++)
faluco@236
   169
	{
faluco@236
   170
		if ((params[i] >= start_addr) && (params[i] <= end_addr))
faluco@236
   171
		{
faluco@236
   172
			copy = true;
faluco@236
   173
			break;
faluco@236
   174
		}
faluco@236
   175
	}
faluco@236
   176
	buf = (copy) ? g_formatbuf : destbuf;
faluco@236
   177
	res = atcprintf(buf, maxlen, fmt, pCtx, params, &arg);
faluco@236
   178
faluco@236
   179
	if (copy)
faluco@236
   180
	{
faluco@236
   181
		memcpy(destbuf, g_formatbuf, res+1);
faluco@236
   182
	}
faluco@236
   183
faluco@236
   184
	return static_cast<cell_t>(res);
faluco@236
   185
}
faluco@236
   186
dvander@411
   187
static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params)
dvander@411
   188
{
dvander@411
   189
	int vargPos = static_cast<int>(params[4]);
dvander@411
   190
dvander@411
   191
	/* Get the parent parameter array */
dvander@411
   192
	sp_context_t *ctx = pContext->GetContext();
dvander@411
   193
	cell_t *local_params = (cell_t *)(ctx->memory + ctx->frm + (2 * sizeof(cell_t)));
dvander@411
   194
dvander@411
   195
	cell_t max = local_params[0];
dvander@411
   196
	if (vargPos > (int)max + 1)
dvander@411
   197
	{
dvander@411
   198
		return pContext->ThrowNativeError("Argument index is invalid: %d", vargPos);
dvander@411
   199
	}
dvander@411
   200
dvander@411
   201
	cell_t addr_start = params[1];
dvander@411
   202
	cell_t addr_end = addr_start + params[2];
dvander@411
   203
	bool copy = false;
dvander@411
   204
	for (int i=vargPos; i<=max; i++)
dvander@411
   205
	{
dvander@411
   206
		/* Does this clip bounds? */
dvander@411
   207
		if ((local_params[i] >= addr_start)
dvander@411
   208
			&& (local_params[i] <= addr_end))
dvander@411
   209
		{
dvander@411
   210
			copy = true;
dvander@411
   211
			break;
dvander@411
   212
		}
dvander@411
   213
	}
dvander@411
   214
dvander@411
   215
	/* Get destination info */
dvander@411
   216
	char *format, *destination;
dvander@411
   217
	size_t maxlen = static_cast<size_t>(params[2]);
dvander@411
   218
dvander@411
   219
	if (copy)
dvander@411
   220
	{
dvander@411
   221
		destination = g_formatbuf;
dvander@411
   222
	} else {
dvander@411
   223
		pContext->LocalToString(params[1], &destination);
dvander@411
   224
	}
dvander@411
   225
dvander@411
   226
	pContext->LocalToString(params[3], &format);
dvander@411
   227
dvander@411
   228
	size_t total = atcprintf(destination, maxlen, format, pContext, local_params, &vargPos);
dvander@411
   229
dvander@411
   230
	/* Perform copy-on-write if we need to */
dvander@411
   231
	if (copy)
dvander@411
   232
	{
dvander@411
   233
		pContext->StringToLocal(params[1], maxlen, g_formatbuf);
dvander@411
   234
	}
dvander@411
   235
dvander@411
   236
	return total;
dvander@411
   237
}
dvander@411
   238
dvander@631
   239
/* :TODO: make this UTF8 safe */
dvander@631
   240
static cell_t StrBreak(IPluginContext *pContext, const cell_t *params)
dvander@631
   241
{
dvander@631
   242
	const char *input;
dvander@631
   243
	char *out;
dvander@631
   244
	size_t outMax;
dvander@631
   245
dvander@631
   246
	/* Get parameters */
dvander@631
   247
	pContext->LocalToString(params[1], (char **)&input);
dvander@631
   248
	pContext->LocalToString(params[2], &out);
dvander@631
   249
	outMax = params[3];
dvander@631
   250
dvander@631
   251
	const char *inptr = input;
dvander@631
   252
	/* Eat up whitespace */
dvander@631
   253
	while (*inptr != '\0' && IsWhitespace(inptr))
dvander@631
   254
	{
dvander@631
   255
		inptr++;
dvander@631
   256
	}
dvander@631
   257
dvander@631
   258
	if (*inptr == '\0')
dvander@631
   259
	{
dvander@631
   260
		if (outMax)
dvander@631
   261
		{
dvander@631
   262
			*out = '\0';
dvander@631
   263
		}
dvander@631
   264
		return -1;
dvander@631
   265
	}
dvander@631
   266
dvander@631
   267
	const char *start, *end = NULL;
dvander@631
   268
dvander@631
   269
	bool quoted = (*inptr == '"');
dvander@631
   270
	if (quoted)
dvander@631
   271
	{
dvander@631
   272
		inptr++;
dvander@631
   273
		start = inptr;
dvander@631
   274
		/* Read input until we reach a quote. */
dvander@631
   275
		while (*inptr != '\0' && *inptr != '"')
dvander@631
   276
		{
dvander@631
   277
			/* Update the end point, increment the stream. */
dvander@631
   278
			end = inptr++;
dvander@631
   279
		}
dvander@631
   280
		/* Read one more token if we reached an end quote */
dvander@631
   281
		if (*inptr == '"')
dvander@631
   282
		{
dvander@631
   283
			inptr++;
dvander@631
   284
		}
dvander@631
   285
	} else {
dvander@631
   286
		start = inptr;
dvander@631
   287
		/* Read input until we reach a space */
dvander@631
   288
		while (*inptr != '\0' && !IsWhitespace(inptr))
dvander@631
   289
		{
dvander@631
   290
			/* Update the end point, increment the stream. */
dvander@631
   291
			end = inptr++;
dvander@631
   292
		}
dvander@631
   293
	}
dvander@631
   294
dvander@631
   295
	/* Copy the string we found, if necessary */
dvander@631
   296
	if (end == NULL)
dvander@631
   297
	{
dvander@631
   298
		if (outMax)
dvander@631
   299
		{
dvander@631
   300
			*out = '\0';
dvander@631
   301
		}
dvander@631
   302
	} else if (outMax) {
dvander@631
   303
		char *outptr = out;
dvander@631
   304
		outMax--;
dvander@631
   305
		for (const char *ptr=start;
dvander@631
   306
			(ptr <= end) && ((unsigned)(outptr - out) < (outMax));
dvander@631
   307
			ptr++, outptr++)
dvander@631
   308
			{
dvander@631
   309
			*outptr = *ptr;
dvander@631
   310
		}
dvander@631
   311
		*outptr = '\0';
dvander@631
   312
	}
dvander@631
   313
dvander@631
   314
	/* Consume more of the string until we reach non-whitespace */
dvander@631
   315
	while (*inptr != '\0' && IsWhitespace(inptr))
dvander@631
   316
	{
dvander@631
   317
		inptr++;
dvander@631
   318
	}
dvander@631
   319
dvander@631
   320
	if (*inptr == '\0')
dvander@631
   321
	{
dvander@631
   322
		return -1;
dvander@631
   323
	}
dvander@631
   324
dvander@631
   325
	return inptr - input;
dvander@631
   326
}
dvander@631
   327
dvander@631
   328
REGISTER_NATIVES(basicStrings)
dvander@233
   329
{
dvander@233
   330
	{"strlen",				sm_strlen},
dvander@631
   331
	{"StrBreak",			StrBreak},
dvander@233
   332
	{"StrContains",			sm_contain},
dvander@681
   333
	{"strcmp",				sm_strcmp},
dvander@681
   334
	{"StrCompare",			sm_strcmp},			/* Backwards compat shim */
dvander@681
   335
	{"strncmp",				sm_strncmp},
dvander@681
   336
	{"strcopy",				sm_strcopy},
dvander@681
   337
	{"StrCopy",				sm_strcopy},		/* Backwards compat shim */
dvander@233
   338
	{"StringToInt",			sm_strconvint},
dvander@233
   339
	{"IntToString",			sm_numtostr},
dvander@233
   340
	{"StringToFloat",		sm_strtofloat},
dvander@233
   341
	{"FloatToString",		sm_floattostr},
dvander@255
   342
	{"Format",				sm_format},
dvander@255
   343
	{"FormatEx",			sm_formatex},
dvander@411
   344
	{"VFormat",				sm_vformat},
dvander@233
   345
	{NULL,					NULL},
dvander@233
   346
};