Howto: Integrate V1 Script with C/C++ API into own projects
You can integrate the V1 interpreter language with a simple C/C++ API into own applications.
Therefore download the newest development package from v1-script.net with precompiled v1.dll for Windows or libv1.so for Linux (libc >= 2.2 required) and VC++, GCC examples.
Here are 16 examples how to work with the C API. Take a look at v1.h to see all API functions.
Example 1: Hello World
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Evaluate V1 code
const char* code = "print ('Hello World');";
v1Eval (ctx, code, strlen (code));
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 2: Calculate a value
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
V1Data ret = v1CreateData ();
// Evaluate V1 code and return a calculated value
const char* code = "10+22*8;";
v1Eval (ctx, code, strlen (code), ret);
printf ("Return: %g\r\n", v1Number(ret));
v1DeleteData (ret);
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 3: Execute a V1 script file
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
// Execute a V1 filename
v1Execute (ctx, "example.v1", argc, argv);
v1Shutdown ();
return 0;
}
Example 4: Fetch a parser error
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Evaluate V1 code with parser error
const char* code = "print X ('Hello World');";
int retCode = v1Eval (ctx, code, strlen (code));
if (v1Aborted (ctx))
printf ("Aborted with: %s\r\n", (const char*) v1LastError (ctx));
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 5: Exit with exit code
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Exit with exit code
const char* code = "exit(99);";
exitCode = v1Eval (ctx, code, strlen (code));
if (v1Exited (ctx))
printf ("Exit Code: %i\r\n", (int) exitCode);
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 6: Set own error function
#include <stdio.h>
#include "v1.h"
int myErrorFunc (const char* filename, int line, const char* text)
{
printf ("%s\r\n", text);
return 0;
}
int main (int argc, char **argv)
{
v1Startup ();
// Set own error function, otherwise errors will be printed to stdout/stderr
v1SetErrorFunction (myErrorFunc);
v1Shutdown ();
return 0;
}
Example 7: Working with own functions
#include <stdio.h>
#include "v1.h"
int myFunction (V1ArgList args, V1Data ret, V1Context ctx)
{
// Check if first parameter is set and at least a string value (also number, bool, null possible)
if (v1Argument1NoString (args))
return V1_RET_PARAM1|V1_RET_NUM_REQUIRED;
// Parameter 2 is required and must be an array
if (v1ArgumentCount(args)<2 || v1Argument2Type (args)<V1_DATATYPE_ARRAY)
return V1_RET_PARAM2|V1_RET_ARRAY_REQUIRED;
// Parameter 3 is optional and must be a number value (also number, bool, null possible)
if (v1ArgumentCount(args)>2 && v1Argument3Type (args)>V1_DATATYPE_STR)
return V1_RET_PARAM3|V1_RET_NUM_REQUIRED;
// Get the arguments
printf ("myFunction() is called with %i arguments.\r\n", v1ArgumentCount(args));
V1Data arg1 = v1Argument(args,0);
printf ("First argument: %s\r\n", v1String (arg1));
printf ("Second argument:\r\n");
V1Data arg2 = v1Argument(args,1);
V1Data value; const char* key;
v1ArrayIterate (arg2);
while (value=v1ArrayNext (arg2, &key)) {
printf ("%s => %s\r\n", (const char*) key, (const char*) v1String (value));
}
if (v1ArgumentCount(args)>2) {
V1Data arg3 = v1Argument(args,2);
printf ("Third argument: %g\r\n", v1Number (arg3));
}
/*
// Raise a warning
v1WarnInterprete (ctx, "Raise a warning");
*/
/*
// Abort, you can check if interpreter is aborted by v1IsAborted (ctx)
v1AbortInterprete (ctx, "Now abort");
return V1_RET_ABORT;
*/
// Set return value as string
v1SetString (ret, "My return value");
return 0;
}
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Register own function and call it
v1RegisterFunction (ctx, "myFunction", myFunction);
const char* code = "print (myFunction ('Param 1', ['Param 2'=>'Value']));";
v1Eval (ctx, code, strlen (code));
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 8: Set constants
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Set simple constants
v1SetConstant (ctx, "MY_CONSTANT", 0, "MY STRING"); // String "MY STRING"
v1SetConstant (ctx, "MY_CONSTANT2", 99, NULL); // Number 99
const char* code =
"print (MY_CONSTANT);"\
"print (MY_CONSTANT2);";
v1Eval (ctx, code, strlen (code));
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 9: Read and change a global variable written by V1
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Read a global variable written by V1
const char* code = "a = time ();";
v1Eval (ctx, code, strlen (code));
V1Data a = v1Symbol (ctx, "a", V1_SYMBOLS_GLOBAL); // 0 = constants, 1 = global vars
if (a) {
printf ("a = %.13g\r\n", (double) v1Number (a));
// Change the variable
v1SetNumber (a, 99);
code = "print('a is now ', a);";
v1Eval (ctx, code, strlen (code));
}
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 10: Manipulate a global array written by V1
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Manipulate a global array written by V1
const char* code = "b = array ('key1'=>'Value 1', 'key2'=>99, 'key3'=>true); print_r (b);";
v1Eval (ctx, code, strlen (code));
V1Data b = v1Symbol (ctx, "b", V1_SYMBOLS_GLOBAL); // 0 = constants, 1 = global vars
if (b) {
// Unset key2
v1UnsetArrayKey (b, "key2");
printf ("b has now %u elements\r\n", v1ArraySize (b));
// Iterate the array
V1Data value; const char* key;
v1ArrayIterate (b);
while (value=v1ArrayNext (b, &key)) {
printf ("%s => %s\r\n", (const char*) key, (const char*) v1String (value));
}
// Set a value in array safe:
// Note! v1ArrayPut...() will insert/replace the complete array key/value pair
// To change only the value of a key, first get the value with v1ArrayValue().
// So the references to this value will be not destroyed!
V1Data v = v1ArrayValue (b, "key1");
if (v) {
v1SetNumber (v, 100);
}
code = "print ('key1 was changed by application.'); print_r (b);";
v1Eval (ctx, code, strlen (code));
}
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 11: Call a V1 user function
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Define a V1 user function
code = "function myUserFunc (arg1,arg2) { print ('myUserFunc() called from application with arg1=', arg1, ' and arg2=', arg2); return 'OK'; }";
v1Eval (ctx, code, strlen (code));
// Call the V1 function with arguments
V1ArgList argList = v1CreateArgList ();
V1Data ret = v1CreateData ();
V1Data arg1 = v1CreateData ();
v1SetString (arg1, "Value for Argument 1");
V1Data arg2 = v1CreateData ();
v1SetNumber (arg2, 99);
v1SetArgument (argList, 0, arg1);
v1SetArgument (argList, 1, arg2);
if (!v1CallUserFunction (ctx, "myUserFunc", argList, ret)) {
printf ("Return value: %s\r\n", (const char*) v1String (ret));
}
else {
printf ("%s\r\n", (const char*) v1LastError (ctx));
}
v1DeleteData (arg1); // v1DeleteData() must be called for a corresponding v1CreateData()
v1DeleteData (arg2);
v1DeleteData (ret);
v1DeleteArgList (argList); // v1DeleteArgList() must be called for a corresponding v1CreateArgList()
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 12: Read a V1 file handle
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Create a file handle with V1 and work with it
code = "fh = fopen ('testfile.txt', 'w+');";
v1Eval (ctx, code, strlen (code));
V1Data fh = v1Symbol (ctx, "fh", V1_SYMBOLS_GLOBAL); // 0 = constants, 1 = global vars
if (fh && v1HandleType (fh)==V1_HANDLETYPE_FILE) {
// Cast to FILE* HANDLE
FILE* pFile = (FILE*) v1Handle (fh);
if (pFile) {
// Write
const char* buf = "Written by application";
unsigned int size = strlen (buf);
if (fwrite (buf, sizeof(char), size, pFile) < size) {
printf ("Problems to write file.\r\n");
}
}
}
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 13: Create a file and assign the file handle to a V1 variable
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Create a WIN32 file and assign file handle to V1 variable (on Linux you can assign a FILE* pointer)
wchar_t wFilename[MAX_PATH+1];
DWORD size = MultiByteToWideChar(CP_UTF8, 0, "testfile2.txt", -1, wFilename, MAX_PATH);
wFilename[size]=0;
HANDLE hFile;
if (INVALID_HANDLE_VALUE == (hFile = CreateFileW (wFilename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL))) {
printf ("Cannot create file.");
}
else {
V1Data symbol = v1CreateSymbol (ctx, "fh2", V1_SYMBOLS_CONSTANT); // 0=constants, 1=global vars, 2=first running function ...
v1SetHandle (ctx, symbol, V1_HANDLETYPE_FILE, (V1Handle) hFile); // only V1_HANDLETYPE_FILE, V1_HANDLETYPE_SOCKET allowed
code = "fwrite (fh2, 'Written by V1'); fclose (fh2);";
v1Eval (ctx, code, strlen (code));
// Note! File handles will be closed also automatically in v1DeleteContext()
}
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 14: Iterate all variables of current symbol table
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Set some variables
code = "a=1;b=2;c=['key'=>'value'];";
v1Eval (ctx, code, strlen (code));
// Iterate all variables of current symbol table
V1Data value; const char* name;
v1SymbolIterate (ctx, v1CurrentSymbolTable (ctx));
printf ("Max. %u symbol tables available, current symbol table is %u.\r\n", (unsigned int) v1SymbolTableCount (ctx), (unsigned int) v1CurrentSymbolTable (ctx));
while (value=v1SymbolNext (ctx, v1CurrentSymbolTable (ctx), &name)) {
printf ("%s => Type %i (string=\"%s\")\r\n", (const char*) name, (int) v1Type (value), (const char*) v1String (value));
}
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 15: Remove a function
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Remove a function
code = "function userFunc (x) { return sqrt(x); }; print (userFunc(16));";
v1Eval (ctx, code, strlen (code));
if (v1FunctionRegistered (ctx, "userFunc")) {
v1RemoveFunction (ctx, "userFunc");
// Redefinition will cause no error, because function was removed
v1Eval (ctx, code, strlen (code));
}
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}
Example 16: Create a constant array
#include <stdio.h>
#include "v1.h"
int main (int argc, char **argv)
{
v1Startup ();
V1Context ctx = v1CreateContext ();
// Create a constant array
V1Data symbol = v1CreateSymbol (ctx, "mySymbol", V1_SYMBOLS_CONSTANT); // 0=constants, 1=global vars, 2=first running function ...
v1PutArrayString (symbol, "key1", "Value 1");
v1PutArrayString (symbol, "key2", "Value 2");
v1PutArrayBool (symbol, "key3", true);
V1Data subArray = v1PutArrayArray (symbol, "subArray");
v1PutArrayString (subArray, "key1", "Value 1");
v1PutArrayString (subArray, "key2", "Value 2");
v1PutArrayBool (subArray, "key3", true);
V1Data subArray2 = v1PutArrayArray (symbol, "subArray2");
// Push will create a vector (keys are set automatically 0,1,2 ...)
v1PushArrayString (subArray2, "Value 1");
v1PushArrayNumber (subArray2, 42.12);
v1PushArrayBool (subArray2, true);
code = "print_r (mySymbol);";
v1Eval (ctx, code, strlen (code));
// Try to overwrite constant array will cause error
code = "mySymbol['key1']['key3']=42;";
v1Eval (ctx, code, strlen (code));
printf ("%s\r\n", (const char*) v1LastError (ctx));
v1DeleteContext (ctx);
v1Shutdown ();
return 0;
}