924 lines
20 KiB
C++
924 lines
20 KiB
C++
// vim: set ts=4 sw=4 tw=99 noet:
|
|
//
|
|
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
// Copyright (C) The AMX Mod X Development Team.
|
|
//
|
|
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
// https://alliedmods.net/amxmodx-license
|
|
|
|
#include "amxmodx.h"
|
|
#include "datastructs.h"
|
|
#include <am-utility.h>
|
|
|
|
// Note: All handles start at 1. 0 and below are invalid handles.
|
|
// This way, a plugin that doesn't initialize a vector or
|
|
// string will not be able to modify another plugin's data
|
|
// on accident.
|
|
ke::Vector<CellArray*> VectorHolder;
|
|
|
|
|
|
// Array:ArrayCreate(cellsize=1, reserved=32);
|
|
static cell AMX_NATIVE_CALL ArrayCreate(AMX* amx, cell* params)
|
|
{
|
|
// params[1] (cellsize) is how big in cells each element is.
|
|
// this MUST be greater than 0!
|
|
int cellsize = params[1];
|
|
|
|
// params[2] (reserved) is how many elements to allocate
|
|
// immediately when the list is created.
|
|
int reserved = params[2];
|
|
|
|
if (cellsize <= 0)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid array size (%d)", cellsize);
|
|
return -1;
|
|
}
|
|
|
|
// Scan through the vector list to see if any are NULL.
|
|
// NULL means the vector was previously destroyed.
|
|
for (unsigned int i=0; i < VectorHolder.length(); ++i)
|
|
{
|
|
if (VectorHolder[i]==NULL)
|
|
{
|
|
VectorHolder[i] = new CellArray(cellsize);
|
|
|
|
if (reserved > 0)
|
|
{
|
|
VectorHolder[i]->resize(reserved);
|
|
}
|
|
|
|
return i + 1;
|
|
}
|
|
}
|
|
|
|
// None are NULL, create a new vector
|
|
CellArray* NewVector = new CellArray(cellsize);
|
|
|
|
if (reserved > 0)
|
|
{
|
|
NewVector->resize(reserved);
|
|
}
|
|
|
|
VectorHolder.append(NewVector);
|
|
|
|
return VectorHolder.length();
|
|
}
|
|
|
|
// native ArrayClear(Array:which);
|
|
static cell AMX_NATIVE_CALL ArrayClear(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
vec->clear();
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native ArraySize(Array:which);
|
|
static cell AMX_NATIVE_CALL ArraySize(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return vec->size();
|
|
}
|
|
|
|
// native bool:ArrayResize(Array:which, newsize);
|
|
static cell AMX_NATIVE_CALL ArrayResize(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (!vec->resize(params[2]))
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Unable to resize array to \"%u\"", params[2]);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native Array:ArrayClone(Array:which);
|
|
static cell AMX_NATIVE_CALL ArrayClone(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
CellArray *clonevec = vec->clone();
|
|
|
|
// Scan through the vector list to see if any are NULL.
|
|
// NULL means the vector was previously destroyed.
|
|
for (unsigned int i = 0; i < VectorHolder.length(); ++i)
|
|
{
|
|
if (VectorHolder[i] == NULL)
|
|
{
|
|
VectorHolder[i] = clonevec;
|
|
return i + 1;
|
|
}
|
|
}
|
|
|
|
VectorHolder.append(clonevec);
|
|
|
|
return VectorHolder.length();
|
|
}
|
|
|
|
// native ArrayGetArray(Array:which, item, any:output[], size = -1);
|
|
static cell AMX_NATIVE_CALL ArrayGetArray(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = (size_t)params[2];
|
|
|
|
if (idx >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
cell *blk = vec->at(idx);
|
|
size_t indexes = vec->blocksize();
|
|
|
|
if (params[4] != -1 && (size_t)params[4] <= vec->blocksize())
|
|
{
|
|
indexes = params[4];
|
|
}
|
|
|
|
cell *addr = get_amxaddr(amx, params[3]);
|
|
|
|
memcpy(addr, blk, sizeof(cell) * indexes);
|
|
|
|
return indexes;
|
|
}
|
|
|
|
// native any:ArrayGetCell(Array:which, item, block = 0, bool:asChar = false);
|
|
static cell AMX_NATIVE_CALL ArrayGetCell(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = (size_t)params[2];
|
|
|
|
if (idx >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
cell *blk = vec->at(idx);
|
|
idx = (size_t)params[3];
|
|
|
|
if (!params[4])
|
|
{
|
|
if (idx >= vec->blocksize())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid block %d (blocksize: %d)", idx, vec->blocksize());
|
|
return 0;
|
|
}
|
|
|
|
return blk[idx];
|
|
}
|
|
else
|
|
{
|
|
if (idx >= vec->blocksize() * 4)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid byte %d (blocksize: %d bytes)", idx, vec->blocksize() * 4);
|
|
return 0;
|
|
}
|
|
|
|
return (cell)*((char *)blk + idx);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// native ArrayGetString(Array:which, item, output[], size);
|
|
static cell AMX_NATIVE_CALL ArrayGetString(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = (size_t)params[2];
|
|
|
|
if (idx >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
cell *blk = vec->at(idx);
|
|
return set_amxstring_utf8(amx, params[3], blk, amxstring_len(blk), params[4] + 1); // + EOS.
|
|
}
|
|
|
|
// native ArraySetArray(Array:which, item, const any:input[], size =-1);
|
|
static cell AMX_NATIVE_CALL ArraySetArray(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = (size_t)params[2];
|
|
|
|
if (idx >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
cell *blk = vec->at(idx);
|
|
size_t indexes = vec->blocksize();
|
|
|
|
if (params[4] != -1 && (size_t)params[4] <= vec->blocksize())
|
|
{
|
|
indexes = params[4];
|
|
}
|
|
|
|
cell *addr = get_amxaddr(amx, params[3]);
|
|
|
|
memcpy(blk, addr, sizeof(cell) * indexes);
|
|
|
|
return indexes;
|
|
}
|
|
|
|
// native ArraySetCell(Array:which, item, any:input, block = 0, bool:asChar = false);
|
|
static cell AMX_NATIVE_CALL ArraySetCell(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = (size_t)params[2];
|
|
|
|
if (idx >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
cell *blk = vec->at(idx);
|
|
idx = (size_t)params[4];
|
|
|
|
if (params[5] == 0)
|
|
{
|
|
if (idx >= vec->blocksize())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid block %d (blocksize: %d)", idx, vec->blocksize());
|
|
return 0;
|
|
}
|
|
blk[idx] = params[3];
|
|
}
|
|
else
|
|
{
|
|
if (idx >= vec->blocksize() * 4)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid byte %d (blocksize: %d bytes)", idx, vec->blocksize() * 4);
|
|
return 0;
|
|
}
|
|
*((char *)blk + idx) = (char)params[3];
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native ArraySetString(Array:which, item, const input[]);
|
|
static cell AMX_NATIVE_CALL ArraySetString(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = (size_t)params[2];
|
|
|
|
if (idx >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
cell *blk = vec->at(idx);
|
|
|
|
int len;
|
|
char *str = get_amxstring(amx, params[3], 0, len);
|
|
|
|
return strncopy(blk, str, ke::Min((size_t)len + 1, vec->blocksize()));
|
|
}
|
|
|
|
// native ArrayPushArray(Array:which, const any:input[], size = -1);
|
|
static cell AMX_NATIVE_CALL ArrayPushArray(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
cell *blk = vec->push();
|
|
|
|
if (!blk)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Failed to grow array");
|
|
return 0;
|
|
}
|
|
|
|
cell *addr = get_amxaddr(amx, params[2]);
|
|
size_t indexes = vec->blocksize();
|
|
|
|
if (params[3] != -1 && (size_t)params[3] <= vec->blocksize())
|
|
{
|
|
indexes = params[3];
|
|
}
|
|
|
|
memcpy(blk, addr, sizeof(cell) * indexes);
|
|
|
|
return static_cast<cell>((vec->size() - 1));
|
|
}
|
|
|
|
// native ArrayPushCell(Array:which, any:input);
|
|
static cell AMX_NATIVE_CALL ArrayPushCell(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
cell *blk = vec->push();
|
|
|
|
if (!blk)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Failed to grow array");
|
|
return 0;
|
|
}
|
|
|
|
*blk = params[2];
|
|
|
|
return static_cast<cell>((vec->size() - 1));
|
|
}
|
|
|
|
// native ArrayPushString(Array:which, const input[]);
|
|
static cell AMX_NATIVE_CALL ArrayPushString(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
cell *blk = vec->push();
|
|
if (!blk)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Failed to grow array");
|
|
return 0;
|
|
}
|
|
|
|
strncopy(blk, get_amxaddr(amx, params[2]), vec->blocksize());
|
|
|
|
return static_cast<cell>((vec->size() - 1));
|
|
}
|
|
|
|
// native DoNotUse : ArrayGetStringHandle(Array : which, item);
|
|
static cell AMX_NATIVE_CALL ArrayGetStringHandle(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = (size_t)params[2];
|
|
|
|
if (idx >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
cell* ptr = vec->at(idx);
|
|
|
|
if (ptr == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return reinterpret_cast<cell>(ptr);
|
|
}
|
|
|
|
// native ArrayInsertArrayAfter(Array:which, item, const any:input[]);
|
|
static cell AMX_NATIVE_CALL ArrayInsertArrayAfter(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = params[2] + 1;
|
|
|
|
if (idx > vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertArrayAfter (%d:%d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
cell *addr = get_amxaddr(amx, params[3]);
|
|
|
|
memcpy(vec->insert_at(idx), addr, sizeof(cell) * vec->blocksize());
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native ArrayInsertCellAfter(Array:which, item, any:input);
|
|
static cell AMX_NATIVE_CALL ArrayInsertCellAfter(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = params[2] + 1;
|
|
|
|
if (idx > vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertCellAfter (%d:%d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
*vec->insert_at(idx) = params[3];
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native ArrayInsertStringAfter(Array:which, item, const input[]);
|
|
static cell AMX_NATIVE_CALL ArrayInsertStringAfter(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = params[2] + 1;
|
|
|
|
if (idx > vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertStringAfter (%d:%d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
int len;
|
|
const char *str = get_amxstring(amx, params[3], 0, len);
|
|
|
|
return strncopy(vec->insert_at(idx), str, ke::Min((size_t)len + 1, vec->blocksize()));
|
|
}
|
|
|
|
// native ArrayInsertArrayBefore(Array:which, item, const any:input[]);
|
|
static cell AMX_NATIVE_CALL ArrayInsertArrayBefore(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = params[2];
|
|
|
|
if (idx >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertArrayBefore (%d:%d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
cell *addr = get_amxaddr(amx, params[3]);
|
|
|
|
memcpy(vec->insert_at(idx), addr, vec->blocksize() * sizeof(cell));
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native ArrayInsertCellBefore(Array:which, item, const any:input);
|
|
static cell AMX_NATIVE_CALL ArrayInsertCellBefore(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = params[2];
|
|
|
|
if (idx >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertCellBefore (%d:%d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
*vec->insert_at(idx) = params[3];
|
|
|
|
return 1;
|
|
}
|
|
// native ArrayInsertStringBefore(Array:which, item, const input[]);
|
|
static cell AMX_NATIVE_CALL ArrayInsertStringBefore(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = params[2];
|
|
|
|
if (idx >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertStringBefore (%d:%d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
int len;
|
|
const char *str = get_amxstring(amx, params[3], 0, len);
|
|
|
|
return strncopy(vec->insert_at(idx), str, ke::Min((size_t)len + 1, vec->blocksize()));
|
|
}
|
|
|
|
// native ArraySwap(Array:which, item1, item2);
|
|
static cell AMX_NATIVE_CALL ArraySwap(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx1 = (size_t)params[2];
|
|
size_t idx2 = (size_t)params[3];
|
|
|
|
if (idx1 >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx1, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
if (idx2 >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx2, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
vec->swap(idx1, idx2);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native ArrayDeleteItem(Array:which, item);
|
|
static cell AMX_NATIVE_CALL ArrayDeleteItem(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = (size_t)params[2];
|
|
|
|
if (idx >= vec->size())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
return 0;
|
|
}
|
|
|
|
vec->remove(idx);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native ArrayDestroy(&Array:which);
|
|
static cell AMX_NATIVE_CALL ArrayDestroy(AMX* amx, cell* params)
|
|
{
|
|
cell* handle = get_amxaddr(amx, params[1]);
|
|
CellArray* vec = HandleToVector(amx, *handle);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
delete vec;
|
|
|
|
VectorHolder[*handle-1] = NULL;
|
|
|
|
*handle = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
struct ArraySort_s
|
|
{
|
|
int func;
|
|
cell array_hndl;
|
|
cell* array_base;
|
|
cell array_bsize;
|
|
cell data;
|
|
cell size;
|
|
cell addr1;
|
|
cell addr2;
|
|
AMX *amx;
|
|
};
|
|
|
|
ArraySort_s SortInfo;
|
|
|
|
int SortArrayList(const void *elem1, const void *elem2)
|
|
{
|
|
return executeForwards(
|
|
SortInfo.func,
|
|
SortInfo.array_hndl,
|
|
((cell)((cell *)elem1 - SortInfo.array_base)) / SortInfo.array_bsize,
|
|
((cell)((cell *)elem2 - SortInfo.array_base)) / SortInfo.array_bsize,
|
|
SortInfo.data,
|
|
SortInfo.size
|
|
);
|
|
}
|
|
|
|
// native ArraySort(Array:array, const comparefunc[], data[]="", data_size=0);
|
|
static cell AMX_NATIVE_CALL ArraySort(AMX* amx, cell* params)
|
|
{
|
|
int handle = params[1];
|
|
CellArray* vec = HandleToVector(amx, handle);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int len;
|
|
char* funcName = get_amxstring(amx, params[2], 0, len);
|
|
|
|
// MySortFunc(Array:array, item1, item2, const data[], data_size)
|
|
int func = registerSPForwardByName(amx, funcName, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
|
|
if (func < 0)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "The public function \"%s\" was not found.", funcName);
|
|
return 0;
|
|
}
|
|
|
|
size_t arraysize = vec->size();
|
|
size_t blocksize = vec->blocksize();
|
|
cell *array = vec->base();
|
|
|
|
ArraySort_s oldinfo = SortInfo;
|
|
|
|
SortInfo.func = func;
|
|
SortInfo.array_base = array;
|
|
SortInfo.array_bsize = static_cast<cell>(blocksize);
|
|
SortInfo.array_hndl = handle;
|
|
SortInfo.data = params[3];
|
|
SortInfo.size = params[4];
|
|
|
|
qsort(array, arraysize, blocksize * sizeof(cell), SortArrayList);
|
|
|
|
SortInfo = oldinfo;
|
|
|
|
unregisterSPForward(func);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int SortArrayListExCell(const void *elem1, const void *elem2)
|
|
{
|
|
size_t index1 = ((cell)((cell *)elem1 - SortInfo.array_base)) / SortInfo.array_bsize;
|
|
size_t index2 = ((cell)((cell *)elem2 - SortInfo.array_base)) / SortInfo.array_bsize;
|
|
|
|
return executeForwards(
|
|
SortInfo.func,
|
|
SortInfo.array_hndl,
|
|
*&SortInfo.array_base[index1 * SortInfo.array_bsize],
|
|
*&SortInfo.array_base[index2 * SortInfo.array_bsize],
|
|
SortInfo.data,
|
|
SortInfo.size
|
|
);
|
|
}
|
|
|
|
int SortArrayListExArray(const void *elem1, const void *elem2)
|
|
{
|
|
size_t index1 = ((cell)((cell *)elem1 - SortInfo.array_base)) / SortInfo.array_bsize;
|
|
size_t index2 = ((cell)((cell *)elem2 - SortInfo.array_base)) / SortInfo.array_bsize;
|
|
|
|
cell *addr1 = get_amxaddr(SortInfo.amx, SortInfo.addr1);
|
|
cell *addr2 = get_amxaddr(SortInfo.amx, SortInfo.addr2);
|
|
|
|
memcpy(addr1, &SortInfo.array_base[index1 * SortInfo.array_bsize], SortInfo.array_bsize * sizeof(cell));
|
|
memcpy(addr2, &SortInfo.array_base[index2 * SortInfo.array_bsize], SortInfo.array_bsize * sizeof(cell));
|
|
|
|
return executeForwards(
|
|
SortInfo.func,
|
|
SortInfo.array_hndl,
|
|
SortInfo.addr1,
|
|
SortInfo.addr2,
|
|
SortInfo.data,
|
|
SortInfo.size
|
|
);
|
|
}
|
|
|
|
// native ArraySortEx(Array:array, const comparefunc[], data[]="", data_size=0);
|
|
static cell AMX_NATIVE_CALL ArraySortEx(AMX* amx, cell* params)
|
|
{
|
|
int handle = params[1];
|
|
CellArray* vec = HandleToVector(amx, handle);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int len;
|
|
char* funcName = get_amxstring(amx, params[2], 0, len);
|
|
|
|
int func = registerSPForwardByName(amx, funcName, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
|
|
|
|
if (!func)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "The public function \"%s\" was not found.", funcName);
|
|
return 0;
|
|
}
|
|
|
|
size_t arraysize = vec->size();
|
|
size_t blocksize = vec->blocksize();
|
|
cell *array = vec->base();
|
|
cell amx_addr1 = 0, amx_addr2 = 0, *phys_addr = NULL;
|
|
|
|
if (blocksize > 1)
|
|
{
|
|
int err;
|
|
if ((err = amx_Allot(amx, blocksize, &amx_addr1, &phys_addr)) != AMX_ERR_NONE
|
|
|| ( err = amx_Allot(amx, blocksize, &amx_addr2, &phys_addr)) != AMX_ERR_NONE)
|
|
{
|
|
LogError(amx, err, "Ran out of memory");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ArraySort_s oldinfo = SortInfo;
|
|
|
|
SortInfo.func = func;
|
|
SortInfo.array_base = array;
|
|
SortInfo.array_bsize = static_cast<cell>(blocksize);
|
|
SortInfo.array_hndl = params[1];
|
|
SortInfo.data = params[3];
|
|
SortInfo.size = params[4];
|
|
SortInfo.amx = amx;
|
|
SortInfo.addr1 = amx_addr1;
|
|
SortInfo.addr2 = amx_addr2;
|
|
|
|
qsort(array, arraysize, blocksize * sizeof(cell), blocksize > 1 ? SortArrayListExArray : SortArrayListExCell);
|
|
|
|
SortInfo = oldinfo;
|
|
|
|
if (blocksize > 1)
|
|
{
|
|
amx_Release(amx, amx_addr1);
|
|
amx_Release(amx, amx_addr2);
|
|
}
|
|
|
|
unregisterSPForward(func);
|
|
|
|
return 1;
|
|
}
|
|
|
|
extern bool fastcellcmp(cell *a, cell *b, cell len);
|
|
extern int amxstring_len(cell* a);
|
|
|
|
// native ArrayFindString(Array:which, const item[]);
|
|
static cell AMX_NATIVE_CALL ArrayFindString(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
cell *b, *a = get_amxaddr(amx, params[2]);
|
|
size_t cellcount = vec->blocksize();
|
|
size_t a_len = ke::Max(1, amxstring_len(a));
|
|
size_t len = a_len > cellcount ? cellcount : a_len;
|
|
|
|
for (size_t i = 0; i < vec->size(); i++)
|
|
{
|
|
b = vec->at(i);
|
|
|
|
if (fastcellcmp(a, b, len))
|
|
{
|
|
return static_cast<cell>(i);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// native ArrayFindValue(Array:which, any:item);
|
|
static cell AMX_NATIVE_CALL ArrayFindValue(AMX* amx, cell* params)
|
|
{
|
|
CellArray* vec = HandleToVector(amx, params[1]);
|
|
|
|
if (vec == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
for (size_t i = 0; i < vec->size(); i++)
|
|
{
|
|
if (params[2] == *vec->at(i))
|
|
{
|
|
return static_cast<cell>(i);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
AMX_NATIVE_INFO g_DataStructNatives[] =
|
|
{
|
|
{ "ArrayCreate", ArrayCreate },
|
|
{ "ArrayClear", ArrayClear },
|
|
{ "ArrayClone", ArrayClone },
|
|
{ "ArraySize", ArraySize },
|
|
{ "ArrayResize", ArrayResize },
|
|
{ "ArrayGetArray", ArrayGetArray },
|
|
{ "ArrayGetCell", ArrayGetCell },
|
|
{ "ArrayGetString", ArrayGetString },
|
|
{ "ArraySetArray", ArraySetArray },
|
|
{ "ArraySetCell", ArraySetCell },
|
|
{ "ArraySetString", ArraySetString },
|
|
{ "ArrayPushArray", ArrayPushArray },
|
|
{ "ArrayPushCell", ArrayPushCell },
|
|
{ "ArrayPushString", ArrayPushString },
|
|
{ "ArrayInsertArrayAfter", ArrayInsertArrayAfter },
|
|
{ "ArrayInsertCellAfter", ArrayInsertCellAfter },
|
|
{ "ArrayInsertStringAfter", ArrayInsertStringAfter },
|
|
{ "ArrayInsertArrayBefore", ArrayInsertArrayBefore },
|
|
{ "ArrayInsertCellBefore", ArrayInsertCellBefore },
|
|
{ "ArrayInsertStringBefore", ArrayInsertStringBefore },
|
|
{ "ArraySwap", ArraySwap },
|
|
{ "ArrayDeleteItem", ArrayDeleteItem },
|
|
{ "ArrayGetStringHandle", ArrayGetStringHandle },
|
|
{ "ArrayDestroy", ArrayDestroy },
|
|
{ "ArraySort", ArraySort },
|
|
{ "ArraySortEx", ArraySortEx },
|
|
{ "ArrayFindString", ArrayFindString },
|
|
{ "ArrayFindValue", ArrayFindValue },
|
|
|
|
{ NULL, NULL }
|
|
};
|