Skip to content

Commit

Permalink
Add more functions to ArrayStack (#2019)
Browse files Browse the repository at this point in the history
* Add more functions to ArrayStack

* Make formatting consistent with other functions

* Don't remove the element for TopArray

* Replace 4 with sizeof(cell_t)
  • Loading branch information
Mikusch authored Sep 27, 2023
1 parent 0656696 commit 1e8db95
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 4 deletions.
97 changes: 93 additions & 4 deletions core/logic/smn_adt_stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,9 @@ static cell_t PopStackCell(IPluginContext *pContext, const cell_t *params)
}
else
{
if (idx >= array->blocksize() * 4)
if (idx >= array->blocksize() * sizeof(cell_t))
{
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
}
*buffer = (cell_t)*((char *)blk + idx);
}
Expand Down Expand Up @@ -356,15 +356,41 @@ static cell_t ArrayStack_Pop(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
rval = blk[idx];
} else {
if (idx >= array->blocksize() * 4)
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
if (idx >= array->blocksize() * sizeof(cell_t))
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
rval = (cell_t)*((char *)blk + idx);
}

array->remove(array->size() - 1);
return rval;
}

static cell_t ArrayStack_Top(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
if (!array.Ok())
return 0;

if (array->size() == 0)
return pContext->ThrowNativeError("stack is empty");

cell_t *blk = array->at(array->size() - 1);
size_t idx = (size_t)params[2];

cell_t rval;
if (params[3] == 0) {
if (idx >= array->blocksize())
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
rval = blk[idx];
} else {
if (idx >= array->blocksize() * sizeof(cell_t))
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
rval = (cell_t)*((char *)blk + idx);
}

return rval;
}

static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
Expand All @@ -387,6 +413,27 @@ static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *param
return 1;
}

static cell_t ArrayStack_TopString(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
if (!array.Ok())
return 0;

if (array->size() == 0)
return pContext->ThrowNativeError("stack is empty");

size_t idx = array->size() - 1;
cell_t *blk = array->at(idx);

cell_t *pWritten;
pContext->LocalToPhysAddr(params[4], &pWritten);

size_t numWritten;
pContext->StringToLocalUTF8(params[2], params[3], (char *)blk, &numWritten);
*pWritten = (cell_t)numWritten;
return 1;
}

static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
Expand All @@ -411,6 +458,29 @@ static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params
return 0;
}

static cell_t ArrayStack_TopArray(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
if (!array.Ok())
return 0;

if (array->size() == 0)
return pContext->ThrowNativeError("stack is empty");

cell_t *addr;
pContext->LocalToPhysAddr(params[2], &addr);

size_t idx = array->size() - 1;
cell_t *blk = array->at(idx);
size_t indexes = array->blocksize();

if (params[3] != -1 && (size_t)params[3] <= array->blocksize())
indexes = params[3];

memcpy(addr, blk, sizeof(cell_t) * indexes);
return 0;
}

static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
{
HandleError err;
Expand All @@ -426,6 +496,21 @@ static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
return array->blocksize();
}

static cell_t GetStackSize(IPluginContext *pContext, const cell_t *params)
{
HandleError err;
CellArray *array;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);

if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&array))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
}

return array->size();
}

REGISTER_NATIVES(cellStackNatives)
{
{"CreateStack", CreateStack},
Expand All @@ -444,13 +529,17 @@ REGISTER_NATIVES(cellStackNatives)
{"ArrayStack.Clear", ClearStack},
{"ArrayStack.Clone", CloneStack},
{"ArrayStack.Pop", ArrayStack_Pop},
{"ArrayStack.Top", ArrayStack_Top},
{"ArrayStack.PopString", ArrayStack_PopString},
{"ArrayStack.TopString", ArrayStack_TopString},
{"ArrayStack.PopArray", ArrayStack_PopArray},
{"ArrayStack.TopArray", ArrayStack_TopArray},
{"ArrayStack.Push", PushStackCell},
{"ArrayStack.PushString", PushStackString},
{"ArrayStack.PushArray", PushStackArray},
{"ArrayStack.Empty.get", IsStackEmpty},
{"ArrayStack.BlockSize.get", GetStackBlockSize},
{"ArrayStack.Length.get", GetStackSize},

{NULL, NULL},
};
30 changes: 30 additions & 0 deletions plugins/include/adt_stack.inc
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ methodmap ArrayStack < Handle
// @error The stack is empty.
public native any Pop(int block=0, bool asChar=false);

// Reads a cell value from a stack without removing it.
//
// @param block Optionally specify which block to read from
// (useful if the blocksize > 0).
// @param asChar Optionally read as a byte instead of a cell.
// @return Value read from the stack.
// @error The stack is empty.
public native any Top(int block=0, bool asChar=false);

// Pops a string value from a stack.
//
// @param buffer Buffer to store string.
Expand All @@ -108,6 +117,15 @@ methodmap ArrayStack < Handle
// @error The stack is empty.
public native void PopString(char[] buffer, int maxlength, int &written = 0);

// Reads a string value from a stack without removing it.
//
// @param buffer Buffer to store string.
// @param maxlength Maximum size of the buffer.
// @param written Number of characters written to buffer, not including
// the null terminator.
// @error The stack is empty.
public native void TopString(char[] buffer, int maxlength, int &written = 0);

// Pops an array of cells from a stack.
//
// @param buffer Buffer to store the array in.
Expand All @@ -116,6 +134,14 @@ methodmap ArrayStack < Handle
// @error The stack is empty.
public native void PopArray(any[] buffer, int size=-1);

// Reads an array of cells from a stack without removing it.
//
// @param buffer Buffer to store the array in.
// @param size If not set, assumes the buffer size is equal to the
// blocksize. Otherwise, the size passed is used.
// @error The stack is empty.
public native void TopArray(any[] buffer, int size=-1);

// Returns true if the stack is empty, false otherwise.
property bool Empty {
public native get();
Expand All @@ -125,6 +151,10 @@ methodmap ArrayStack < Handle
property int BlockSize {
public native get();
}

property int Length {
public native get();
}
};

/**
Expand Down

0 comments on commit 1e8db95

Please sign in to comment.