core/smn_string.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Aug 24 04:35:48 2008 +0000 (2008-08-24)
changeset 2237 4403a982ec91
parent 2193 db7c6362f3f2
child 2271 b15123c83b57
permissions -rw-r--r--
Improved bot detection slightly. This was meant to go along with the fix for amb1801.
ds@1952
     1
/**
ds@1952
     2
 * vim: set ts=4 :
ds@1952
     3
 * =============================================================================
ds@1952
     4
 * SourceMod
ds@1952
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1952
     6
 * =============================================================================
ds@1952
     7
 *
ds@1952
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1952
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952
    10
 * Free Software Foundation.
ds@1952
    11
 * 
ds@1952
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1952
    15
 * details.
ds@1952
    16
 *
ds@1952
    17
 * You should have received a copy of the GNU General Public License along with
ds@1952
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
ds@1952
    19
 *
ds@1952
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1952
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1952
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1952
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952
    27
 * or <http://www.sourcemod.net/license.php>.
ds@1952
    28
 *
ds@1952
    29
 * Version: $Id$
ds@1952
    30
 */
ds@1952
    31
ds@1952
    32
#include <string.h>
ds@1952
    33
#include <stdlib.h>
ds@1952
    34
#include "sm_globals.h"
ds@1952
    35
#include "sm_stringutil.h"
ds@1952
    36
#include <ITextParsers.h>
ds@1952
    37
#include <ctype.h>
ds@1952
    38
ds@1952
    39
inline const char *_strstr(const char *str, const char *substr)
ds@1952
    40
{
ds@1952
    41
#ifdef PLATFORM_WINDOWS
ds@1952
    42
	return strstr(str, substr);
ds@1952
    43
#elif defined PLATFORM_LINUX
ds@1952
    44
	return (const char *)strstr(str, substr);
ds@1952
    45
#endif
ds@1952
    46
}
ds@1952
    47
ds@1952
    48
/*********************************************
ds@1952
    49
*                                            *
ds@1952
    50
* STRING MANIPULATION NATIVE IMPLEMENTATIONS *
ds@1952
    51
*                                            *
ds@1952
    52
*********************************************/
ds@1952
    53
ds@1952
    54
static cell_t sm_strlen(IPluginContext *pCtx, const cell_t *params)
ds@1952
    55
{
ds@1952
    56
	char *str;
ds@1952
    57
	pCtx->LocalToString(params[1], &str);
ds@1952
    58
ds@1952
    59
	return strlen(str);
ds@1952
    60
}
ds@1952
    61
ds@1952
    62
static cell_t sm_contain(IPluginContext *pCtx, const cell_t *params)
ds@1952
    63
{
ds@1952
    64
	typedef const char *(*STRSEARCH)(const char *, const char *);
ds@1952
    65
	STRSEARCH func;
ds@1952
    66
	char *str, *substr;
ds@1952
    67
ds@1952
    68
	pCtx->LocalToString(params[1], &str);
ds@1952
    69
	pCtx->LocalToString(params[2], &substr);
ds@1952
    70
ds@1952
    71
	func = (params[3]) ? _strstr : stristr;
ds@1952
    72
	const char *pos = func(str, substr);
ds@1952
    73
	if (pos)
ds@1952
    74
	{
ds@1952
    75
		return (pos - str);
ds@1952
    76
	}
ds@1952
    77
ds@1952
    78
	return -1;
ds@1952
    79
}
ds@1952
    80
ds@1952
    81
static cell_t sm_strcmp(IPluginContext *pCtx, const cell_t *params)
ds@1952
    82
{
ds@1952
    83
	typedef int (*STRCOMPARE)(const char *, const char *);
ds@1952
    84
	STRCOMPARE func;
ds@1952
    85
	char *str1, *str2;
ds@1952
    86
ds@1952
    87
	pCtx->LocalToString(params[1], &str1);
ds@1952
    88
	pCtx->LocalToString(params[2], &str2);
ds@1952
    89
ds@1952
    90
	func = (params[3]) ? strcmp : stricmp;
ds@1952
    91
ds@1952
    92
	return (func(str1, str2));
ds@1952
    93
}
ds@1952
    94
ds@1952
    95
static cell_t sm_strncmp(IPluginContext *pCtx, const cell_t *params)
ds@1952
    96
{
ds@1952
    97
	char *str1, *str2;
ds@1952
    98
ds@1952
    99
	pCtx->LocalToString(params[1], &str1);
ds@1952
   100
	pCtx->LocalToString(params[2], &str2);
ds@1952
   101
	
ds@1952
   102
	if  (params[4])
ds@1952
   103
	{
ds@1952
   104
		return strncmp(str1, str2, (size_t)params[3]);
ds@1952
   105
	} else {
ds@1952
   106
		return strncasecmp(str1, str2, (size_t)params[3]);
ds@1952
   107
	}
ds@1952
   108
}
ds@1952
   109
ds@1952
   110
static cell_t sm_strcopy(IPluginContext *pCtx, const cell_t *params)
ds@1952
   111
{
ds@1952
   112
	char *dest, *src;
ds@1952
   113
ds@1952
   114
	pCtx->LocalToString(params[1], &dest);
ds@1952
   115
	pCtx->LocalToString(params[3], &src);
ds@1952
   116
ds@1952
   117
	return strncopy(dest, src, params[2]);
ds@1952
   118
}
ds@1952
   119
ds@1952
   120
static cell_t sm_strconvint(IPluginContext *pCtx, const cell_t *params)
ds@1952
   121
{
ds@1952
   122
	char *str, *dummy;
ds@1952
   123
	pCtx->LocalToString(params[1], &str);
ds@1952
   124
ds@1952
   125
	return static_cast<cell_t>(strtol(str, &dummy, params[2]));
ds@1952
   126
}
ds@1952
   127
ds@1952
   128
static cell_t StringToIntEx(IPluginContext *pCtx, const cell_t *params)
ds@1952
   129
{
ds@1952
   130
	char *str, *dummy = NULL;
ds@1952
   131
	cell_t *addr;
ds@1952
   132
	pCtx->LocalToString(params[1], &str);
ds@1952
   133
	pCtx->LocalToPhysAddr(params[2], &addr);
ds@1952
   134
ds@1952
   135
	*addr = static_cast<cell_t>(strtol(str, &dummy, params[3]));
ds@1952
   136
ds@1952
   137
	return dummy - str;
ds@1952
   138
}
ds@1952
   139
ds@1952
   140
static cell_t sm_numtostr(IPluginContext *pCtx, const cell_t *params)
ds@1952
   141
{
ds@1952
   142
	char *str;
ds@1952
   143
	pCtx->LocalToString(params[2], &str);
ds@1952
   144
	size_t res = UTIL_Format(str, params[3], "%d", params[1]);
ds@1952
   145
ds@1952
   146
	return static_cast<cell_t>(res);
ds@1952
   147
}
ds@1952
   148
ds@1952
   149
static cell_t sm_strtofloat(IPluginContext *pCtx, const cell_t *params)
ds@1952
   150
{
ds@1952
   151
	char *str, *dummy;
ds@1952
   152
	pCtx->LocalToString(params[1], &str);
ds@1952
   153
ds@1952
   154
	float val = (float)strtod(str, &dummy);
ds@1952
   155
ds@1952
   156
	return sp_ftoc(val);
ds@1952
   157
}
ds@1952
   158
ds@1952
   159
static cell_t StringToFloatEx(IPluginContext *pCtx, const cell_t *params)
ds@1952
   160
{
ds@1952
   161
	char *str, *dummy = NULL;
ds@1952
   162
	cell_t *addr;
ds@1952
   163
	pCtx->LocalToString(params[1], &str);
ds@1952
   164
	pCtx->LocalToPhysAddr(params[2], &addr);
ds@1952
   165
ds@1952
   166
	float val = (float)strtod(str, &dummy);
ds@1952
   167
ds@1952
   168
	*addr = sp_ftoc(val);
ds@1952
   169
ds@1952
   170
	return dummy - str;
ds@1952
   171
}
ds@1952
   172
ds@1952
   173
static cell_t sm_floattostr(IPluginContext *pCtx, const cell_t *params)
ds@1952
   174
{
ds@1952
   175
	char *str;
ds@1952
   176
	pCtx->LocalToString(params[2], &str);
ds@1952
   177
	size_t res = UTIL_Format(str, params[3], "%f", sp_ctof(params[1]));
ds@1952
   178
ds@1952
   179
	return static_cast<cell_t>(res);
ds@1952
   180
}
ds@1952
   181
ds@1952
   182
static cell_t sm_formatex(IPluginContext *pCtx, const cell_t *params)
ds@1952
   183
{
ds@1952
   184
	char *buf, *fmt;
ds@1952
   185
	size_t res;
ds@1952
   186
	int arg = 4;
ds@1952
   187
ds@1952
   188
	pCtx->LocalToString(params[1], &buf);
ds@1952
   189
	pCtx->LocalToString(params[3], &fmt);
ds@1952
   190
	res = atcprintf(buf, static_cast<size_t>(params[2]), fmt, pCtx, params, &arg);
ds@1952
   191
ds@1952
   192
	return static_cast<cell_t>(res);
ds@1952
   193
}
ds@1952
   194
ds@1952
   195
static char g_formatbuf[2048];
ds@1952
   196
static cell_t sm_format(IPluginContext *pCtx, const cell_t *params)
ds@1952
   197
{
ds@1952
   198
	char *buf, *fmt, *destbuf;
ds@1952
   199
	cell_t start_addr, end_addr, maxparam;
ds@1952
   200
	size_t res, maxlen;
ds@1952
   201
	int arg = 4;
ds@1952
   202
	bool copy = false;
ds@1952
   203
ds@1952
   204
	pCtx->LocalToString(params[1], &destbuf);
ds@1952
   205
	pCtx->LocalToString(params[3], &fmt);
ds@1952
   206
ds@1952
   207
	maxlen = static_cast<size_t>(params[2]);
ds@1952
   208
	start_addr = params[1];
ds@1952
   209
	end_addr = params[1] + maxlen;
ds@1952
   210
	maxparam = params[0];
ds@1952
   211
ds@1952
   212
	for (cell_t i=3; i<=maxparam; i++)
ds@1952
   213
	{
ds@1952
   214
		if ((params[i] >= start_addr) && (params[i] <= end_addr))
ds@1952
   215
		{
ds@1952
   216
			copy = true;
ds@1952
   217
			break;
ds@1952
   218
		}
ds@1952
   219
	}
ds@1952
   220
	buf = (copy) ? g_formatbuf : destbuf;
ds@1952
   221
	res = atcprintf(buf, maxlen, fmt, pCtx, params, &arg);
ds@1952
   222
ds@1952
   223
	if (copy)
ds@1952
   224
	{
ds@1952
   225
		memcpy(destbuf, g_formatbuf, res+1);
ds@1952
   226
	}
ds@1952
   227
ds@1952
   228
	return static_cast<cell_t>(res);
ds@1952
   229
}
ds@1952
   230
ds@1952
   231
static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params)
ds@1952
   232
{
ds@1952
   233
	int vargPos = static_cast<int>(params[4]);
ds@1952
   234
ds@1952
   235
	/* Get the parent parameter array */
dvander@2193
   236
	cell_t *local_params = pContext->GetLocalParams();
ds@1952
   237
ds@1952
   238
	cell_t max = local_params[0];
ds@1952
   239
	if (vargPos > (int)max + 1)
ds@1952
   240
	{
ds@1952
   241
		return pContext->ThrowNativeError("Argument index is invalid: %d", vargPos);
ds@1952
   242
	}
ds@1952
   243
ds@1952
   244
	cell_t addr_start = params[1];
ds@1952
   245
	cell_t addr_end = addr_start + params[2];
ds@1952
   246
	bool copy = false;
ds@1952
   247
	for (int i=vargPos; i<=max; i++)
ds@1952
   248
	{
ds@1952
   249
		/* Does this clip bounds? */
ds@1952
   250
		if ((local_params[i] >= addr_start)
ds@1952
   251
			&& (local_params[i] <= addr_end))
ds@1952
   252
		{
ds@1952
   253
			copy = true;
ds@1952
   254
			break;
ds@1952
   255
		}
ds@1952
   256
	}
ds@1952
   257
ds@1952
   258
	/* Get destination info */
ds@1952
   259
	char *format, *destination;
ds@1952
   260
	size_t maxlen = static_cast<size_t>(params[2]);
ds@1952
   261
ds@1952
   262
	if (copy)
ds@1952
   263
	{
ds@1952
   264
		destination = g_formatbuf;
ds@1952
   265
	} else {
ds@1952
   266
		pContext->LocalToString(params[1], &destination);
ds@1952
   267
	}
ds@1952
   268
ds@1952
   269
	pContext->LocalToString(params[3], &format);
ds@1952
   270
ds@1952
   271
	size_t total = atcprintf(destination, maxlen, format, pContext, local_params, &vargPos);
ds@1952
   272
ds@1952
   273
	/* Perform copy-on-write if we need to */
ds@1952
   274
	if (copy)
ds@1952
   275
	{
ds@1952
   276
		pContext->StringToLocal(params[1], maxlen, g_formatbuf);
ds@1952
   277
	}
ds@1952
   278
ds@1952
   279
	return total;
ds@1952
   280
}
ds@1952
   281
ds@1952
   282
/* :TODO: make this UTF8 safe */
ds@1952
   283
static cell_t BreakString(IPluginContext *pContext, const cell_t *params)
ds@1952
   284
{
ds@1952
   285
	const char *input;
ds@1952
   286
	char *out;
ds@1952
   287
	size_t outMax;
ds@1952
   288
ds@1952
   289
	/* Get parameters */
ds@1952
   290
	pContext->LocalToString(params[1], (char **)&input);
ds@1952
   291
	pContext->LocalToString(params[2], &out);
ds@1952
   292
	outMax = params[3];
ds@1952
   293
ds@1952
   294
	const char *inptr = input;
ds@1952
   295
	/* Eat up whitespace */
ds@1952
   296
	while (*inptr != '\0' && textparsers->IsWhitespace(inptr))
ds@1952
   297
	{
ds@1952
   298
		inptr++;
ds@1952
   299
	}
ds@1952
   300
ds@1952
   301
	if (*inptr == '\0')
ds@1952
   302
	{
ds@1952
   303
		if (outMax)
ds@1952
   304
		{
ds@1952
   305
			*out = '\0';
ds@1952
   306
		}
ds@1952
   307
		return -1;
ds@1952
   308
	}
ds@1952
   309
ds@1952
   310
	const char *start, *end = NULL;
ds@1952
   311
ds@1952
   312
	bool quoted = (*inptr == '"');
ds@1952
   313
	if (quoted)
ds@1952
   314
	{
ds@1952
   315
		inptr++;
ds@1952
   316
		start = inptr;
ds@1952
   317
		/* Read input until we reach a quote. */
ds@1952
   318
		while (*inptr != '\0' && *inptr != '"')
ds@1952
   319
		{
ds@1952
   320
			/* Update the end point, increment the stream. */
ds@1952
   321
			end = inptr++;
ds@1952
   322
		}
ds@1952
   323
		/* Read one more token if we reached an end quote */
ds@1952
   324
		if (*inptr == '"')
ds@1952
   325
		{
ds@1952
   326
			inptr++;
ds@1952
   327
		}
ds@1952
   328
	} else {
ds@1952
   329
		start = inptr;
ds@1952
   330
		/* Read input until we reach a space */
ds@1952
   331
		while (*inptr != '\0' && !textparsers->IsWhitespace(inptr))
ds@1952
   332
		{
ds@1952
   333
			/* Update the end point, increment the stream. */
ds@1952
   334
			end = inptr++;
ds@1952
   335
		}
ds@1952
   336
	}
ds@1952
   337
ds@1952
   338
	/* Copy the string we found, if necessary */
ds@1952
   339
	if (end == NULL)
ds@1952
   340
	{
ds@1952
   341
		if (outMax)
ds@1952
   342
		{
ds@1952
   343
			*out = '\0';
ds@1952
   344
		}
ds@1952
   345
	} else if (outMax) {
ds@1952
   346
		char *outptr = out;
ds@1952
   347
		outMax--;
ds@1952
   348
		for (const char *ptr=start;
ds@1952
   349
			(ptr <= end) && ((unsigned)(outptr - out) < (outMax));
ds@1952
   350
			ptr++, outptr++)
ds@1952
   351
			{
ds@1952
   352
			*outptr = *ptr;
ds@1952
   353
		}
ds@1952
   354
		*outptr = '\0';
ds@1952
   355
	}
ds@1952
   356
ds@1952
   357
	/* Consume more of the string until we reach non-whitespace */
ds@1952
   358
	while (*inptr != '\0' && textparsers->IsWhitespace(inptr))
ds@1952
   359
	{
ds@1952
   360
		inptr++;
ds@1952
   361
	}
ds@1952
   362
ds@1952
   363
	if (*inptr == '\0')
ds@1952
   364
	{
ds@1952
   365
		return -1;
ds@1952
   366
	}
ds@1952
   367
ds@1952
   368
	return inptr - input;
ds@1952
   369
}
ds@1952
   370
ds@1952
   371
static cell_t GetCharBytes(IPluginContext *pContext, const cell_t *params)
ds@1952
   372
{
ds@1952
   373
	char *str;
ds@1952
   374
	pContext->LocalToString(params[1], &str);
ds@1952
   375
ds@1952
   376
	return _GetUTF8CharBytes(str);
ds@1952
   377
};
ds@1952
   378
ds@1952
   379
static cell_t IsCharAlpha(IPluginContext *pContext, const cell_t *params)
ds@1952
   380
{
ds@1952
   381
	char chr = params[1];
ds@1952
   382
ds@1952
   383
	if (_GetUTF8CharBytes(&chr) != 1)
ds@1952
   384
	{
ds@1952
   385
		return 0;
ds@1952
   386
	}
ds@1952
   387
ds@1952
   388
	return isalpha(chr);
ds@1952
   389
}
ds@1952
   390
ds@1952
   391
static cell_t IsCharNumeric(IPluginContext *pContext, const cell_t *params)
ds@1952
   392
{
ds@1952
   393
	char chr = params[1];
ds@1952
   394
ds@1952
   395
	if (_GetUTF8CharBytes(&chr) != 1)
ds@1952
   396
	{
ds@1952
   397
		return 0;
ds@1952
   398
	}
ds@1952
   399
ds@1952
   400
	return isdigit(chr);
ds@1952
   401
}
ds@1952
   402
ds@1952
   403
static cell_t IsCharSpace(IPluginContext *pContext, const cell_t *params)
ds@1952
   404
{
ds@1952
   405
	char chr = params[1];
ds@1952
   406
ds@1952
   407
	if (_GetUTF8CharBytes(&chr) != 1)
ds@1952
   408
	{
ds@1952
   409
		return 0;
ds@1952
   410
	}
ds@1952
   411
ds@1952
   412
	return isspace(chr);
ds@1952
   413
}
ds@1952
   414
ds@1952
   415
static cell_t IsCharMB(IPluginContext *pContext, const cell_t *params)
ds@1952
   416
{
ds@1952
   417
	char chr = params[1];
ds@1952
   418
ds@1952
   419
	unsigned int bytes = _GetUTF8CharBytes(&chr);
ds@1952
   420
	if (bytes == 1)
ds@1952
   421
	{
ds@1952
   422
		return 0;
ds@1952
   423
	}
ds@1952
   424
ds@1952
   425
	return bytes;
ds@1952
   426
}
ds@1952
   427
ds@1952
   428
static cell_t IsCharUpper(IPluginContext *pContext, const cell_t *params)
ds@1952
   429
{
ds@1952
   430
	char chr = params[1];
ds@1952
   431
ds@1952
   432
	if (_GetUTF8CharBytes(&chr) != 1)
ds@1952
   433
	{
ds@1952
   434
		return 0;
ds@1952
   435
	}
ds@1952
   436
ds@1952
   437
	return isupper(chr);
ds@1952
   438
}
ds@1952
   439
ds@1952
   440
static cell_t IsCharLower(IPluginContext *pContext, const cell_t *params)
ds@1952
   441
{
ds@1952
   442
	char chr = params[1];
ds@1952
   443
ds@1952
   444
	if (_GetUTF8CharBytes(&chr) != 1)
ds@1952
   445
	{
ds@1952
   446
		return 0;
ds@1952
   447
	}
ds@1952
   448
ds@1952
   449
	return islower(chr);
ds@1952
   450
}
ds@1952
   451
ds@1952
   452
static cell_t ReplaceString(IPluginContext *pContext, const cell_t *params)
ds@1952
   453
{
ds@1952
   454
	char *text, *search, *replace;
ds@1952
   455
	size_t maxlength;
ds@1952
   456
	
ds@1952
   457
	pContext->LocalToString(params[1], &text);
ds@1952
   458
	pContext->LocalToString(params[3], &search);
ds@1952
   459
	pContext->LocalToString(params[4], &replace);
ds@1952
   460
	maxlength = (size_t)params[2];
ds@1952
   461
dvander@2095
   462
	if (search[0] == '\0')
dvander@2095
   463
	{
dvander@2095
   464
		return pContext->ThrowNativeError("Cannot replace searches of empty strings");
dvander@2095
   465
	}
ds@1952
   466
dvander@2095
   467
	return UTIL_ReplaceAll(text, maxlength, search, replace);
ds@1952
   468
}
ds@1952
   469
ds@1952
   470
static cell_t ReplaceStringEx(IPluginContext *pContext, const cell_t *params)
ds@1952
   471
{
ds@1952
   472
	char *text, *search, *replace;
ds@1952
   473
	size_t maxlength;
ds@1952
   474
ds@1952
   475
	pContext->LocalToString(params[1], &text);
ds@1952
   476
	pContext->LocalToString(params[3], &search);
ds@1952
   477
	pContext->LocalToString(params[4], &replace);
ds@1952
   478
	maxlength = (size_t)params[2];
ds@1952
   479
ds@1952
   480
	size_t searchLen = (params[5] == -1) ? strlen(search) : (size_t)params[5];
ds@1952
   481
	size_t replaceLen = (params[6] == -1) ? strlen(replace) : (size_t)params[6];
ds@1952
   482
dvander@2095
   483
	if (searchLen == 0)
dvander@2095
   484
	{
dvander@2095
   485
		return pContext->ThrowNativeError("Cannot replace searches of empty strings");
dvander@2095
   486
	}
dvander@2095
   487
ds@1952
   488
	char *ptr = UTIL_ReplaceEx(text, maxlength, search, searchLen, replace, replaceLen);
ds@1952
   489
ds@1952
   490
	if (ptr == NULL)
ds@1952
   491
	{
ds@1952
   492
		return -1;
ds@1952
   493
	}
ds@1952
   494
ds@1952
   495
	return ptr - text;
ds@1952
   496
}
ds@1952
   497
ds@1952
   498
static cell_t TrimString(IPluginContext *pContext, const cell_t *params)
ds@1952
   499
{
ds@1952
   500
	char *str;
ds@1952
   501
	pContext->LocalToString(params[1], &str);
ds@1952
   502
ds@1952
   503
	size_t chars = strlen(str);
ds@1952
   504
ds@1952
   505
	if (chars == 0)
ds@1952
   506
	{
ds@1952
   507
		return 0;
ds@1952
   508
	}
ds@1952
   509
ds@1952
   510
	char *end = str + chars - 1;
ds@1952
   511
ds@1952
   512
	/* Iterate backwards through string until we reach first non-whitespace char */
ds@1952
   513
	while (end >= str && textparsers->IsWhitespace(end))
ds@1952
   514
	{
ds@1952
   515
		end--;
ds@1952
   516
	}
ds@1952
   517
ds@1952
   518
	/* Replace first whitespace char (at the end) with null terminator */
ds@1952
   519
	*(end + 1) = '\0';
ds@1952
   520
ds@1952
   521
	/* Iterate forwards through string until first non-whitespace char is reached */
ds@1952
   522
	while (textparsers->IsWhitespace(str))
ds@1952
   523
	{
ds@1952
   524
		str++;
ds@1952
   525
	}
ds@1952
   526
ds@1952
   527
	size_t bytes;
ds@1952
   528
	pContext->StringToLocalUTF8(params[1], chars + 1, str, &bytes);
ds@1952
   529
ds@1952
   530
	return bytes;
ds@1952
   531
}
ds@1952
   532
ds@1952
   533
static cell_t SplitString(IPluginContext *pContext, const cell_t *params)
ds@1952
   534
{
ds@1952
   535
	char *text, *split;
ds@1952
   536
	
ds@1952
   537
	pContext->LocalToString(params[1], &text);
ds@1952
   538
	pContext->LocalToString(params[2], &split);
ds@1952
   539
ds@1952
   540
	size_t maxLen = (size_t)params[4];
ds@1952
   541
	size_t textLen = strlen(text);
ds@1952
   542
	size_t splitLen = strlen(split);
ds@1952
   543
ds@1952
   544
	if (splitLen > textLen)
ds@1952
   545
	{
ds@1952
   546
		return -1;
ds@1952
   547
	}
ds@1952
   548
ds@1952
   549
	/**
ds@1952
   550
	 * Note that it's <= ... you could also just add 1,
ds@1952
   551
	 * but this is a bit nicer
ds@1952
   552
	 */
ds@1952
   553
	for (size_t i=0; i<=textLen - splitLen; i++)
ds@1952
   554
	{
ds@1952
   555
		if (strncmp(&text[i], split, splitLen) == 0)
ds@1952
   556
		{
ds@1952
   557
			/* Split hereeeee */
ds@1952
   558
			if (i >= maxLen)
ds@1952
   559
			{
ds@1952
   560
				pContext->StringToLocalUTF8(params[3], maxLen, text, NULL);
ds@1952
   561
			} else {
ds@1952
   562
				pContext->StringToLocalUTF8(params[3], i+1, text, NULL);
ds@1952
   563
			}
ds@1952
   564
			return (cell_t)(i + splitLen);
ds@1952
   565
		}
ds@1952
   566
	}
ds@1952
   567
ds@1952
   568
	return -1;
ds@1952
   569
}
ds@1952
   570
dvander@2004
   571
static cell_t StripQuotes(IPluginContext *pContext, const cell_t *params)
dvander@2004
   572
{
dvander@2004
   573
	char *text;
dvander@2004
   574
	size_t length;
dvander@2004
   575
dvander@2004
   576
	pContext->LocalToString(params[1], &text);
dvander@2004
   577
	length = strlen(text);
dvander@2004
   578
dvander@2004
   579
	if (text[0] == '"' && text[length-1] == '"')
dvander@2004
   580
	{
dvander@2004
   581
		/* Null-terminate */
dvander@2004
   582
		text[--length] = '\0';
dvander@2004
   583
		/* Move the remaining bytes (including null terminator) down by one */
dvander@2004
   584
		memmove(&text[0], &text[1], length);
dvander@2004
   585
dvander@2004
   586
		return 1;
dvander@2004
   587
	}
dvander@2004
   588
dvander@2004
   589
	return 0;	
dvander@2004
   590
}
dvander@2004
   591
ds@1952
   592
REGISTER_NATIVES(basicStrings)
ds@1952
   593
{
ds@1952
   594
	{"BreakString",			BreakString},
ds@1952
   595
	{"FloatToString",		sm_floattostr},
ds@1952
   596
	{"Format",				sm_format},
ds@1952
   597
	{"FormatEx",			sm_formatex},
ds@1952
   598
	{"GetCharBytes",		GetCharBytes},
ds@1952
   599
	{"IntToString",			sm_numtostr},
ds@1952
   600
	{"IsCharAlpha",			IsCharAlpha},
ds@1952
   601
	{"IsCharLower",			IsCharLower},
ds@1952
   602
	{"IsCharMB",			IsCharMB},
ds@1952
   603
	{"IsCharNumeric",		IsCharNumeric},
ds@1952
   604
	{"IsCharSpace",			IsCharSpace},
ds@1952
   605
	{"IsCharUpper",			IsCharUpper},
ds@1952
   606
	{"ReplaceString",		ReplaceString},
ds@1952
   607
	{"ReplaceStringEx",		ReplaceStringEx},
ds@1952
   608
	{"SplitString",			SplitString},
ds@1952
   609
	{"strlen",				sm_strlen},
ds@1952
   610
	{"StrContains",			sm_contain},
ds@1952
   611
	{"strcmp",				sm_strcmp},
ds@1952
   612
	{"strncmp",				sm_strncmp},
ds@1952
   613
	{"strcopy",				sm_strcopy},
ds@1952
   614
	{"StringToInt",			sm_strconvint},
ds@1952
   615
	{"StringToIntEx",		StringToIntEx},
ds@1952
   616
	{"StringToFloat",		sm_strtofloat},
ds@1952
   617
	{"StringToFloatEx",		StringToFloatEx},
dvander@2004
   618
	{"StripQuotes",			StripQuotes},
ds@1952
   619
	{"TrimString",			TrimString},
ds@1952
   620
	{"VFormat",				sm_vformat},
ds@1952
   621
	{NULL,					NULL},
ds@1952
   622
};