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