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