Table of Contents

last update 10/2022

▶︎
all
running...

Gonuts Reference

let's go nuts!

12th Oct 2022 - draft version , work in progress

Introduction

Gonuts is a runtime library, compiler and interpreter utilizing and extending the Squirrel Language, especially for creating client/server applications, IoT or industry data harvesting and processing while offering source code protection, encryption, events, multithreading and lots more.
It is statically linked and not depending on any external library and runs on (almost) any Linux or Windows platform with a very small footprint.
It comes with an optimized internal memory management and has a very small RAM (and disk) footprint. It was successfully used on standard Distributions like Windows 7,10 and 11, Debian Linux, Ubuntu and even on ARM Hardware like Raspberry Pi, BeagleBone or even on commercial ARM based LTE-Router/Gateway hardware.

Platforms

We tested and used Gonuts on

As it's statically linked, the currently provided AMD64 (compiled on Debian), Win32 (compiled on Win7) and ARM64 (Raspbian) versions probably run on any similar sytems.
Sorry, we didn't come round to fix compilation for Win64 yet, seems to be quite an issue.

History

Historically all started with a protocol we made, among others, for Teamspeak; and which probably now can be found working behind the scenes of MyTeamspeak on both clients and server side to securely synchronize user settings, bookmarks and identities.
A more updated and generalized protocol was then named PXP (Phobyx eXtended Protocol) and was used internally on quite some projects. From some projects of our former game developer era we knew Squirrel and merged them, adding some more features to get standard tasks done more rapidly. PXLib was born, also known as libPXP (the library to implement PXP using Squirrel).
PXLib grew over the years, and more and more features were added on demand to serve for example in a huge public traffic telemetry project, image/video kiosk systems, an embedded http server simulator and integrated templating engine or a complex chemistry recipe and regulatory affairs software, to name a few. Dependency on C/C+ coding was reduced with each step and more and more control went to Squirrel while we rolled out for more and more hardware platforms and projects, until PXLib finally made it into a standalone application that now would enable us to re-develop all our servers and clients we made so far on a 5 to 50% schedule compared to the original projects. PXLib was finally renamed to “go nuts", regarding the Squirrel source code file extension being "nut".
Today we are happily throwing nuts and pnuts at "gonuts" to feed our squirrels and provide them a den (module) every now and then and one of our largest projects with over 150.000 lines of gonuts code (and exactly 0 lines of c++) is a ERP system, including bookkeeping export interfaces, sales platform (like Amazon, Ebay...) interfaces and lots more. As you read these lines, apparently we published gonuts as a general development and production tool.
At the time of this writing, the main approach is M2M/IoT and we’re currently introducing CAN support among others, but we also occasionally work on OpenGL(ES) and multi-platform GUI bindings and plan for an IDE named “Drey” (a drey is a tree squirrel/flying squirrel nest). Our focus, however, currently is on small embedded systems and the Linux server side. However, gonuts is flexible enough to be considered a somewhat general purpose development platform now.

Caveats and drawbacks

Keyboard input

First and most of all, access to keyboard input unfortunately is quite limited. There is no getch() or something, In Squirrel you only can open use stdin, stdout and stderr as files (see squirrel standard I/O library), which usually are line driven!
On linux, though, you can use the event system to access keyboard (using sockfd class on tty files for example), but on Windows you simply can't do that. There is a den, however, to SIMULATE keyboard strokes programmatically, which in turn works für Windows only. Funny, isn't it?
Well, we'll work on that some day, but as keyboard input is handled so differently on different platforms, it'll take a while.

enums across script files

Another caveat is about Squirrel ENUMs, but this is nothing unusual for Squirrel - enums are handled by the compiler an hence work within the same source file only.
See Script management functions about for a proposed workaround using the preprocessor feature provided by pxlib.pnut

Gonuts is stable, but can crash (documented)

gonuts is really stable and we're using it in production for years now, but it has some features that are explicitly documented as "use at your own risk", like destructor support for example. Sometimes normal program termination will stall when using RealThreads, but it happened on very, very complex and huge applications only - we're still digging into that. Also in combination with realthreads we also observed memory leaks in rare cases, though very few and short blocks or memory. However, it IS possible to produce memory leaks.
Also gonuts CAN crash when some den (or even gonuts native) c-functions require a dynamic stack resize.

Cross platform issues

Gonuts is designed for Linux. Few functionality is unavailable on Windows, this is explicitly documented. Additionally, Database access is currently limited to sqlite3 on Windows (unless someone creates a proper Den Module for that, we didn't come round yet).
Also, your code is not magically forced to be platform independent. Beginning with line endings (windows: \r\n Linux:\n). Use the ISWINDOWS constant to check what platform you're running on.
Integer and floats may be 32 or 64 bits wide.

Wide characters and character sets

Well, UTF-8 is supported, but wide characters and Unicode are not. You have to work around when dealing with those. A simple comparison like if (inputstring=="Unmöglich♠") - note the Ggerman special character ö and the pike symbol - may or may not work depending on underlying OS, settings and source file character set, but it will fail 100% when the string has a different character set compared to your source file editor or dealing with wide characters. The source files are expected to be UTF-8, iso-8859, ASCII-128, ASCII-256 or WINDOWS-1252 or anything like that bound to standard characters being single bytes.

Debugging issues

Debugging is not thread-aware when it comes to RealThreads. Breakpoints do work very well, but you never know which thread you're actually in unless looking at the base of the call history. When stepping into or over, you may suddenly find yourself in a totally different thread and source. Hence we now have the habit of using breakpoints a lot.

Breaking sometimes can take a lot of time when a lot of local and stack data is to be transferred to your debugging client, especially remotely. Breking into a loop processing an SQL-request that returned 50.000 lines with 500 columns each tends to make you go fetch some coffee.
Large tables and arrays get truncated to a few thousands entries (which is indicated), but when their elements again hold large arrays/tables, or some ring references occur, it can be really tedious - or even impossible (network timeout).

Also you can not alter memory/data/variables manually, or use conditional breakpoints.

The call stack is not complete when a function was invoked by the event management.
Also, when an event throws an exception while debugging you get into it, but in production mode (non-debugging) you need to know it won't stop execution of the thread, it will return to the loop.dispatch despite any error. (However, you can see this while debugging, too, it's just a special behaviour to be aware of)

Debugging requires squirrels special debugging interface and protocol, so you need to have an IDE or client supporting that. To our knowledge, there's currently only a VisualStudio 2008 edition and VisualStudio2015 plugin plus a dedicated, but way less featured small opensource project named nutcracker.

Performance

There's no JIT compiler available yet for Squirrel, hence also no JIT for Gonuts. Everything is executing bytecode in the end, so you may face performance issues when doing really "heavy things". So it's no good advice to build a render loop for 3d games in Gonuts. However, you can work around using c++ by creating your own Den module. Just note: Gonuts usually is "in control", you can reverse that of course and just load your module, start a function that only returns for application exit, and use sq_compile and sq_call to execute gonuts stuff in reverse.

Linux Dependencies

On linux, very few dependencies exist (glib6):

libpthread.so.0 (libpthread)
librt.so.1 (librt)
libdl.so.2 (libdl)
libstdc++.so.6 (libstdc++6)
libm.so.6 (libm6)
libgcc_s.so.1 (libgcc6)
libc.so.6 (libc6)

These should be present on roughly every linux, as they're simply the very, very basics.

Windows Dependencies

There are none we're aware of

Invocation and command line parameters

gonuts (or gonuts.exe) is a command line (win: console) application.
All versions except amalgamations support control via command line parameters described below. All command line parameters usually are also passed to the Squirrel app (unless specified otherwise using the -a option, see below).

gonuts [inputfilename] [options and/or excess parameters]

where inputfilename is a name of the .nut or .cnut file to load and execute. Note that you can omit the file extension, gonuts will try both .nut and .cnut automatically in all cases (passing the extension only changes the order it will try to load). inputfilename can optionally have a path (relative or absolute). Unless a namespace name is provided using the -n option, the namespace the file will be loaded to is the raw filename body, without any extension or prepending path.
When no input filename is provided "main" will be used in the current working directory (--> ./main.nut or ./main.cnut)

Command Line Options:

Option Description
-SQDBG Optional. Run in remote debugging mode. Wait for a debugger to connect before starting the app.
-n yourname Optional. Set yourname as the namespace table to load the code file to
-p pnutfile Optional. Add a pnut archive to the gonuts include paths. you may repeat this option to add more than one pnut archive. The order of multiple archives is obeyed when searching them for nuts lateron. pnutfile must be the full filename including extension (.pnut) and include any relative or absolute path required to access it.
-a Optional. Argument separator. When not present, all arguments will be passed to the Squirrel app. When present, only arguments from this point on will be passed (including the -a, which accordingly will replace the executable filename usually being the very first argument).
--namespace yourname synonym for -n
--pnut pnutfile synonym for -p

note that when running an amalgamation (the executable contains script resources) is run, these still apply except the startup script and -namespace.

Exit Status

The exit status will be the value function main() returns, provided it is integer. Otherwise (main does not return an integer or is not present at all), gonuts will exit with status 0.
If an error occurs preventing execution though, gonuts exit status will be -1
gonuts supports calling exit(intval); to prematurely exit with the given integer exit status. However, note that when using RealThreads that usually is not a good approach because all threads will be immediately stopped and killed

Filename extensions

Default filename extensions:

extension file type
.nut Text script files, plain text
.cnut Pre-compiled (byte code) script files, raw, optionally compressed and/or encrypted
.pnut PNUT script archives (collections of scripts), where each file inside the archive can be either plain or byte code and in both cases optionally compressed and/or encrypted

Wether a script is byte code, compressed or encrypted is detected using Headers within the file.
Note: Though Squirrel supports UTF-8 (just another header), extended gonuts functionality usually does NOT.
When explicitly using a filename extension, you're able to use that, so it's possible to load a script with filename "foo.bar" actually. This comes in handy for example when using the preprocessor that comes with pxplib.pnut, so you can use files extensions like .hnut, .inut or .inc

Squirrel language and Squirrel standard library

See http://www.squirrel-lang.org for documentation. Currently gonuts is housing Squirrel 3.1 - but we're moving to 3.2 very soon, which comes with some nice syntactic sugar
The Squirrel standard library is fully supported and already registered in the root table.

Additional compiler features

gonuts introduces additional compiler keywords for comfort reasons:

Keyword Effect
var synonym for local
auto synonym for local
nil synonym for null
`___FREEZE___ will stop compiler to do line counting. See script.compilehook
`___MELT___ compiler will continue linecounting
protected synonym for function but makes the function locked against serialization (writeclosure)

Namespaces and script loading

In gonuts, scripts usually are loaded using script.require (see script.require, script.release and script.shrink); users are discouraged to use the Squirrel standard lib functions dofile or loadfile or the “include” pre-compile instruction unless they need to achieve certain special outcomes.
Gonuts uses namespaces. Namespaces are tables (always created in the root table) where the script gets executed upon loading. All script elements (functions, classes, objects) are placed into that table. The table name (its index in the root table) by default is defined by the file name without path or extension. Note: Loading a file “somepath/test.nut” while a file “test.cnut” was loaded before will result in the same namespace, overwriting the script loaded first. Hence all filenames should be unique, disregarding their extensions or subfolders they’re in.
Elements of scripts can always be accessed using double colons like “::namespace.element”.

Note that loading mechanisms implemented by the Squirrel language or standard library (loadfile and dofile) do not follow any rules, they directly load a script. Also note that the “include” directive literally includes plain text sourcefiles, which in turn become part of the compiled script while the include instruction gets REPLACED by the included source text. Hence include is to be considered a “pre-compile instruction” not following any additional rules. It is recommended to name included source texts “.inut”.

Technically spoken, gonuts loads scripts by creating (or replacing!) a namespace table in the root table and immediately executing the script with the namespace table as the “this” object.
After initial script execution(!) ends, depending on the way the script was loaded (normal via e.g. script.require or via RealThread) a function named either “Main” or "threadmain" gets executed if it exists in the namespace table.
Hence, users are advised to NOT create infinite loops or event loops directly on script level – a script MUST return when executed (usually by end of the script file), while its “Main” or "threadmain" is not required to return. (Having a “Main” or “threadmain” function at all in a script also is not mandatory except for real threads).

Special namespace objects

After loading a script to its namespace and before executing any “Main” or “threadmain” function, additional objects are placed into the namespace table when loaded using commandline or script.require:

Index Object
filename string containing the script filename (note: not necessary to actually EXIST!)
namespace a string representing the namespace name (for backward access or comparisons)
scriptregister The string the loaded script got registered with and to pass to script.release

Real Multithreading context

A note on multithreading: Real Threads (“real”, because the single term “thread” is used for a different concept in Squirrel) are separated VMS. They do not share a root table or any Squirrel object directly and have their own separated state also regarding loaded scripts. RThreads, however, share the loading rules, like paths and archives to apply while loading.

Paths and Archives, script loading rules

When loading a file either way supporting paths, these rules are used to load a script.
PX will iterate all registered loading paths, and then try to find either provided,“.nut” or “.cnut” file matching any provided subfolder path by concatenation. When no such file could be loaded, gonuts will try all registered archives before continuing with the next loading path.
Loading paths are iterated in their registered order (while the current working directory is used as a default when no paths were configured using script.Paths), the same applies to archives (registered by script.AddArchive). The outer loop is for loading paths, the inner for archives.
You can change the default priority of "files before archives" globally for all threads using the script.Rule command. Amalgamations swap the order automatically to "archives over files" and any attempt of reconfiguration will be simply ignored.
In case the provided filename already has a file extension, that very filename will be tried first, then ".nut" and finally ".cnut".
Note pnut archives ignore file extensions and accessing them always strips any file extension.

**Example: **

script.Paths(“”,”subfolder/”,”/home/user/”) ;
script.AddArchive(“./my.pnut”,”/var/pxlib.pnut”) ;
script.require(“somepath/somescript.myext”) ;

will try to find and load the first script found in the follwing orders, depending on global script.Rule configuration:
After script.Rule("priopnut",0) (or unconfigured) and not running an amalgamation:
file ./somepath/somescript.myext
file ./somepath/somescript.nut
file ./somepath/somescript.cnut
somepath/somescript in ./my.pnut
somepath/somescript in /var/pxlib.pnut
file ./subfolder/somepath/somescript.myext
file ./subfolder/somepath/somescript.nut
file ./subfolder/somepath/somescript.cnut
subfolder/somepath/somescript in ./my.pnut
subfolder/somepath/somescript in /var/pxlib.pnut
file /home/user/somepath/somescript.myext
file /home/user/somepath/somescript.nut
file /home/user/somepath/somescript.cnut
/home/user/somepath/somescript in ./my.pnut
/home/user/somepath/somescript in /var/pxlib.pnut

After script.Rule("priopnut",1) or when running an amalgamation:
somepath/somescript in ./my.pnut
somepath/somescript in /var/pxlib.pnut
file ./somepath/somescript.myext
file ./somepath/somescript.nut
file ./somepath/somescript.cnut
subfolder/somepath/somescript in ./my.pnut
subfolder/somepath/somescript in /var/pxlib.pnut
file ./subfolder/somepath/somescript.myext
file ./subfolder/somepath/somescript.nut
file ./subfolder/somepath/somescript.cnut
/home/user/somepath/somescript in ./my.pnut
/home/user/somepath/somescript in /var/pxlib.pnut
file /home/user/somepath/somescript.myext
file /home/user/somepath/somescript.nut
file /home/user/somepath/somescript.cnut

Note: it does not matter whether a .nut or .cnut actually contains plain source or precompiled code, or if it is compressed and/or encrypted.

Loading Paths can be set using script.Paths(array) and retrieved by local array=script.Paths() ;
To add a path, for example: { local p=script.Paths. p.append(“somepath/”) ; script.Paths(p) ; }
Archives can be added by using script.AddArchive(string) ; where string is a full or relative path, filename and extension(mandatory!). Despite the methods name, an array of archives can be retrieved by calling script.AddArchive() ;
Note: Unlike for paths, you can not alter the archive list, but only append single archives!

General note about paths:

Where paths are used, they usually can be relative or absolute. When a path without a filename is used, it should (and sometimes must) end with a trailing slash. When it comes to script and pnut archives, path format (slash or backslash) will be converted according to the platform. Users should always use slashes for such paths.
However, using absolute paths always binds your app to the platform, because device names are handled differently by the OS (e.g. "/tmp/" vs "C:/tmp/" cannot be converted automatically).

Loading mechanism file type support

This table shows the ways of loading scripts and the supported loading features:

Mechanism paths from file from pnut source bytecode compressed crypted refs ("require") function main
Commandline yes yes yes yes yes yes yes yes yes
script.require yes yes yes yes yes yes yes yes no
script.run yes yes yes yes yes yes yes yes yes
script.getsource yes yes yes yes no yes yes no no
RealThread yes yes yes yes yes yes yes in new thread threadmain
::pxp.execfile yes yes yes yes yes yes yes no yes
::pxp.loadfile yes yes yes yes yes license dep. license dep. ** no** no
loadfile no yes no yes yes no no no no
dofile no yes no yes yes no no no no
#include (*1) yes yes yes yes no yes yes no no

(*1): not natively supported, but possible using preprocessor features of pxplib.pnut, see script.compilehook

Compile errors

Compiling happens when loading plain text source files (also compressed and/or encrypted ones for example from pnut archives) or when explicitly compiling strings to functions.
Compile errors won’t stop overall execution and will result in the script simply be neither loaded nor executed in all cases. However, logs / stderr output will output the first compile error encountered and the instruction used to try to load will return a proper value indicating loading failed. In debugging mode, the debugger will jump to the compile error, however any "run", "step", "stepinto" command or the like will refer to the instruction trying to load and/or compile, not to the line the debugger thinks the break occured at.
Note: When using libpxp.pnut preprocessor feature, an #include will inject the included source into the current source and the compiler will always throw any error on the #include instruction when the included file is erroneous!

Arguments and Important Global variables

Arguments

Arguments from the command line invocation are present to all threads in the _argv and _argc elements of the root table, the first being an array, the latter an integer (though redundant due to len() method of arrays). However, note that _argv[0] is not necessarily the gonuts invocation binary, it can also be “-a” indicating preceding commandline parameters were suppressed.

Constants/globals

Besides the standard squirrel constants and globals, gonuts provides these additions:
::_argv see Arguments
::_argc see Arguments
::ISWINDOWS this constant is 1 when running on Windows, otherwise 0 (for Linux). Use to avoid accessing objects not available on the current platform
::_GONUTSREV_ integer gonuts revision (internal version number)

Native global gonuts functions

These are objects available in gonuts providing additional features to Squirrel. Unless otherwise specified, they're registered in any VMs root table, also across RThreads.
Object and function names grew historically, and were kept for backwards compatibility though naming unfortunately is not consistent across all features.

Please note
As in a programming language things can get really complex, not all combinations and cases were thoroughly tested. In case you experience a crash of gonuts related to the use of gonuts' classes and functions (except when you used the WITH_DTORS class), please post a bug report to the proper board forum at http://forum.goinguts.net
Please make sure you were using the latest version of gonuts before doing so, and attach a code snipped and short explanation on how to reproduce the crash. In case too much code is required please ask for advice or try to user other means of providing source code (pastebin or hastebin for example)

Script Management

The followimg functions are registered in a table "script" residing in the root table. As it is a standard table, it is possible to override or delete them (highly NOT recommended)

ATTENTION: There is a general gonuts-specific caveat: Any ENUMs are available within the same source only. Scripts loading other scripts containing enums will not have access to the enums, because they're processed by compiler and not available at runtime. Recommendation: enums that need to be shared between scripts should be in separate files and included using the preprocessor feature of pxlib.pnut. Similar applies to const declarations, however, consts are in fact available at runtime (at some slight performance costs).
Example:
at startup:

script.addarchive("pxlib.pnut"); 
if (script.require("pxp")) ::__px.prep.enable();

in scripts required or run afterwards, include your enums with

#include "myenums.nut"

(note the # must be the very first character of the line and the included file must be source code, no cnuts will work regarding enums)

script.require function

function require(spec[,filename])

Requires a script to be present, and if it is not present it will be loaded.
Also provides increase of reference count for the specified namespace (see how namespace is derived below).
Will not run any function 'main' or 'threadmain' in the script (use script.Run for that)

INPUTS:
spec string specifying a namespace or a filename to derive a namespace from, depending on filename. In both cases spec is what the script reference count will be accounted for
filename string, optional. A filename to load the script from, when omitted spec is treated as filename and the namespace is derived from it. When present, spec specifies the namespace directly 'as is'.
RETURNS: bool. true if the script was sucessfully loaded, false if an error occured.
THROWS when a license violation occurs or the script was precompiled for a different architecture (e.g. 64bit vs 32bit)

When two parameters are used, the first specifies the exact namespace to load the script to and the second the filename, otherwise the only parameter specifies both at once, deriving the namespace from the filename by removing any filename extension or prepending path. The namespace will be the part of the string between its beginning or the last occurence of either backslash or slash, and the end of the string or the last occurence of a dot.

Filename handling:
In both cases (either one or two parameters passed) the filename can additionally hold a path in any notation(win or linux), and either relative or absolute - which is not recommended; if possible you should prefer using script.AddPath
Any filename extension is used to identify the very first attempt to load the exact file and then removed for further tries of different extensions.

Also see script Namespaces and script loading and script loading rules in the introductory part of this document.

Namespace handling
In both cases (either one or two parameters), the resulting or specified namespace is taken literally for reference counting. The exact same string must be used for other script-related methods to work (see script.release, script.Run, script.shrink). If the string contains a prepending path of any kind this will be INCLUDED, but any filename extension will be EXCLUDED from identifying the reference counter.
In case the reference count is zero, the script will be loaded and placed into a slot in the roottable named after the namespace. This namespace table in the root table is set hard on loading, deleting any table already existing with this name! If the reference count is other than 0, however, no action is taken, be the table still present or not! (You can, but are not recommended to "fiddle around" with namespace tables. You should know what you're doing if so...)

Long story short, for most users it will simply work as expected, as long as they re-use the exact same string for all script-Functions in this section.

Namespaces should not (but in fact can) contain any special characters and are taken literally. Namespaces won't iterate and always reside in the root table, the common indexing syntax like table.subtable1.subtable2 won't do, instead it will create something along "getroottable()["table.subtable1.subtable2"]<-{}".

Examples, providing myfile.nut exists and contains a function named somefunc:

if (script.require("somepath/myfile.nut"))
{
	myfile.somefunc() ; 
}

automatically derives namespace from filename, while the following will provide a custom namespace and execute somefunc from it:

if (script.require("myCustomNamespace","somepath/myfile.nut"))
{
	myCustomNamespace.somefunc() ;
}

However, no path iteration is provided, so this variant have a probably unexpected result:

if (script.require("some.weird.namespace","myfile.nut)) 
{
	//some.weird.namespace.somefunc() ; //this would fail
	getroottable()["some.weird.namespace"].somefunc() ; //but this way it does the job
}

script.release function

function script.release(asindicated_on_require)

Reduces the reference count for a script (see script.require) and when the reference count drops to zero, remove the script from memory and drop the whole namespace table. Note this means deletion of any slot within the namespace of the script created in the meantime also.

INPUTS: asindicated_on_require string to identify the script, as described above (see script.require, namespace handling).
RETURNS: bool indicating wether the script got released or is still present
THROWS: no

script.run function

function script.run(spec[,filename])

will load and reference count a script, then call its "function main"
In case the script already is loaded and script.shrink was not yet called for it, it will delete and re-create its namespace table. In case the script was shrinked in the meantime tohugh, only function 'main' will be called but no re-creation of classes, globals or functions is performed.
See script.require for parameters. Hence can be used to either re-run a script already loaded, or to load and execute a script.

script.shrink function

function script.shrink(spec)

INPUTS: spec the identifier specifying the script, as descripted for script.require
RETURNS: bool. true when re-run was executed successfully, otherwise false
THROWS: when spec is missing or no string

As some data needed to re-run (re-creating the namespace, classes and so on) an already loaded script is obsolete in many cases, script.shrink will free such allocated memory script.Run would need. Note, however, it's not about the source code, which is discarded at loading time already. So shrinking may be applied to scripts loadad from bytecode, too.

script.paths function

function script.paths([newpaths])

Call without parameters to get an array of include paths used by script.require or other script loading mechanisms as described in section script loading rules.

INPUTS: newpaths array, optional. Set all paths according to array content. Omit for inquiry
RETURNS: an array of current paths
THROWS: when array contains other objects than strings

When newpaths is provided it sets all paths at once accordingly. The array contains strings, each elemenet defining a path. The order of the elements is the order for loading attempts.
Paths may be relative to the working directory or absolute, and MUST be provided with a trailing slash. (Note in gonuts, all script paths should be provided using slashes, not backslashes. However, gonuts will convert slashes and backslashes to the required platform format)
Important note: script paths are not local to threads – all threads share the same set of paths, and altering the path array in one thread applies to all other threads, too. Beware of race conditions.
newpaths may be omitted to perform an inquiry only.

script.addarchive function

script.addarchive([pnutfile]

Adds a pnut archive to search in when loading scripts. Note you can add an archive only, never remove.

INPUTS: pnutfile string, optional. path and filename of pnut archive
RETURNS: in case pnutfile is provided: true when successfully added, false when archive file does not exist. When no pnutfile provided returns an array of active pnut file locations
THROWS: on input parameter error
file locations may contain absolute or relative paths
Important note: Archives are not local to threads – all threads share the same set of archives, and adding an archive in one thread applies to all other threads, too. As archives can only be added there are no possible race conditions.

script.rule function

script.rule(command,parameter)

control overall behaviour, configure or lock global rules

INPUTS:
command: string, see table below
parameter: see table below
RETURNS: none
THROWS: exception on any error! (including unknown command or when rules are already locked)

command parameter effect
lock ignored further attempts to call script.rule will throw an exception
priopnuts bool true = change loading order to "pnuts first, then files"

script.compilehook

By default, this "slot" is not present. If present, gonuts expect it to be a function taking a string argument with source code that is about to compile and returns either null (use unchanged) or a string, buffer, blob or precompiled closure that is taken over.
Prototype is

function myhook(input) { 
	local retval=input ; //string. retval can be string, null, blob or buffer or a precompiled closure created by compilestring()(). Note it is important to EXECUTE the returned function of compilestring() ro return a closure and not a function!
	return retval; //returning null equals "return input", but saves memory.
}

and the "this" object will be the root table (so the function is recommended to bindenv()), example:

function myhook(input) { 
	return null ;  //do stuff here when needed
}

script.compilehook<-myhook.bindenv(this)>

gonuts' PXP library uses this to implement a preprocessor with macros, macro conditions and include functionality. To use the pxp library preprocessor:

if (script.require("pxp")) ::__px.prep.enable() ;

Note this hook is called by script.require and script.run only, but not for dofile(...) or compilestring(...) for example.

Within the function, make sure to keep the line counter (for debugging) matching the original input sourcecode. You may stop line counting by emitting ___FREEZE___; in the output and continue line counting by emitting ___MELT___; (three underscores each side) in the return string to compile. BTW: Those keywords work in "normal, nonaltered" sourcecode, too, but aren't recommended in normal use.

script.getsource function

function script.getsource(filename)

get the source code of a source file

INPUTS
filename: string, same rules apply like with script.run or script.require
RETURNS: string sourcecode or false. When unable to fetch source code (e.g.file not found or file is precompiled bytecode), false will be returned
THROWS: no

script environment and stack control

script.cwd function

function script.cwd()

get the current working directory

INPUTS: none
RETURNS: string
THROWS: no

script.ensurestack function

function ensurestack(freesize)

reallocates the stack and makes sure at leastfreesize stack entries are unused and available. If the stack is smaller it will grow, otherwise it will not change.

INPUTS: freesize integer defining the minimum amount of unused stack after the call
RETURNS: none
THROWS: when called from within a metamethod

Stacksize does not count bytes but squirrel objects.
Important note: gonuts starts with a default stack size of 512. However, increasing the stack size may significantly impact memory usage by magnitudes of the stack size, among others because internally gonuts creates temporary virtual machines quite often.
Especially complex multithreading and event usage may significantly increase memory footprint this way.

Gonuts will automatically double the current stack size every time it detects a potential shortage, so usually you won't need to call ensurestack yourself, unless you want to avoid the automatic (and potentially costly) mechanism kicking in.

script.getenv function

function getenv(key)

retrieve a named environment variable

INPUTS: key a string identifying the environment variable to get
RETURNS: the environment variable as a string, or null in case it does not exist
THROWS: no

script.breakpoint function

internal purpose, do not use.

blackbox class (separated and restricted VM)

In some cases you may have the need for a VM that does not allow for I/O operations or is otherwise restricted. An example gonuts makes use of would be the ability to load for example JSON config files simply as scripts while suppressing functionality that would enable someone to create configuration files actually executing malicious code when loaded.

Blackboxes provide most functionality, except all about events and networking, file access, system access (squirrel standard system lib, or systemfork and related functions), all XML classes or anything that may be directily abused to create output (in the sense of I/O) - with the exception of print, which is supported.
Also, a blackbox is unable to import dens (to hinder someone writing and using a den to avoid the restrictions)
Additionally a blackboxed VM cannot use the experimental WITH_DTORS class to provide destructors to classes.

User will not have direct access to objects in the blackbox, but the blackbox class provides some functions to transfer objects from a VM to another (the same restrictions like described for multithreading object transfers, see rtsync class).
Unlike rtsync, reading objects from the blackbox will convert non-transferrable objects to null instead of aborting the copy operation.

IMPORTANT NOTES:

blackbox Constructors

blackbox([stacksize[,...]])

Create an empty "black box" VM where

stacksize is an optional integer defining the stacksize of the VM in bytes. When stacksize is provided, the following parameters will be passed as arguments to the VM ( _argc and _argv variables). When no parameters provided the stacksize will be 1024 Bytes.

blackbox Methods

blackbox.require Method

function require(spec[,filepath])

externallly causes the script to execute "script.require(spec)" or "script.require(spec,filepath)" within the blackbox and returns the exact same result to the caller.
See script.require above for reference.
Note you can neither externally release nor shrink a script within the blackbox
Note: this call may not return, depending on the script loaded (may already enter an infinite loop)

blackbox.run Method

function run(namespace[,filepath])

Similar to require, this causes the blackbox to execute a respective script.run command , and returns the same result to the caller.
See above for reference.
Note this call may not return when the code executed in the blackbox does not return (e.g. enters an infinite loop)

blackbox.allow Method

function allow(...)

activates certain functionality, that is registering classes, functions and constants within the blackbox.

INPUTS: any number of strings, which must exactly match one of the keywords desribed below
RETURNS: none
THROWS: on parameter type mismatch or unrecognized keyword

keyword activates and registers within blackbox
events all event and networking abilities
system sqstd_systemlib and shell/fork abilities
io sqstd_iolib
threads realthread (note rtsync is always available)
xml all xml handling objects
destructors the WITH_DTORS base class
addarchive script.addarchive function

ATTENTION: Activating the event system also registers sockfd, which may be used to read or write files already. Not allowing "io" will not prevent this!

blackbox.call Method

function call(objpath[,...])

calls a function in the blackbox

INPUTS:
objpath a string indicating the function to call, in squirrel notation
... optional, any number of parameters to pass to the blackbox function
RETURNS: the return value of the called function, or null when it is not transferrable
THROWS: when objpath does not point to a valid function or an exception occured within the blackbox during execution

Note this call may not return when the code executed in the blackbox does not return (e.g. enters an infinite loop)

blackbox.compile Method

function compile(objpath,source)

compiles a string to a closure and placing the result to the indicated location within the blackbox

INPUTS:
objpath a string defining the location where to put the closure to, in squirrel notation
source a string to compile
RETURNS: true unless objpath indicated to replace the roottable (-> false)
THROWS: on any other error, including compile errors

imagine this executes [objpath]<-compilestring(source) ; and objpath could iterate, effectively re-using existing or creating non-existing tables on its "path".

blackbox.take Method

function take(objpath)

copies the indicated object (and all of its sub-objects in case of an array or table) from the blackbox to the return variable.

INPUTS: objpath string, path to the object to retrieve
RETURNS: a copy of the object, where non-transferrable objects will be null. Returns null when objpath did not "hit" an object (or the object is non-transferrable or in fact by itself null)
THROWS: on input parameter mismatch only

blackbox example:

local box=blackbox();
box.allow("threads","destructors","xml") ;
if (box.require("myscript"))
{
	local result=box.call("::myscript.somefunc","parameter",1234) ;
	print("Result: "+result+"\n") ;
}
if (box.compile("::foo.bar","::foo <- function (y) { print (\"foo got \"+y+\"\n\") ; } print \"replacing ::foo\"") {
	box.call("::foo.bar","foobar") ; // will replace foo and print "replacing ::foo"
	box.call("::foo","stuff") ; //calls the replacement and hence prints "foo got stuff\n"
	box.call("::foo","too","much") ; //will throw an exception, beacuse ::foo takes a single parameter!
}
local boxroottable=box.take("::") ; //copies over the complete root table. Extreme costly! 

Output and Logging

gonuts provides a configurable multi-channel logging system, and internally uses some default channels always present. Users may use the default channels or add their own.
Channels can only be configured, but channel configuation can not be queried. Logging can be buffered or instant, configurable separately for each channel. Buffered logging provides more stable timing and is more effective, but in turn in case of a hard crash some logs may be lost.

Note that any string logged will have a linefeed added when an optional timestamp is activated (see below)

Also note, that the maximum byte (character) length for every string to log is 4095.

script.logconf function

function script.logconf(channel,type[,synchroneous][,aux])

configures a log channel

INPUTS:
channel integer, channel number to configure
type string, any of the list below
synchroneous bool, optional. true for direct action, false for background buffering (recommended)
aux string, auxiliary info depending on type, for example an output filename or a syslog name. When omitted defaults to "gonuts" or "gonuts.log", depending on type
RETURNS: none
THROWS: on parameter errors

available types:

type linux win32 aux
"off" no logging no logging ignored if provided
"file" log to file log to file filename (incl. optional path) to log to, will always have a timestamp
"syslog" log to syslog info log to "syslog.txt" source name string
"syslog_crit" log to syslog crit log to "syslog.txt" source name string
"syslog_err" log to syslog error log to "syslog.txt" source name string
"syslog_warn" log to syslog warning log to "syslog.txt" source name string
"syslog_info" log to syslog info log to "syslog.txt" source name string
"syslog_debug" log to syslog debug log to "syslog.txt" source name string
"print" print to stdout print to stdout when empty string suppress timestamp, otherwise print timestamp
"stdout" print to stdout print to stdout when empty string suppress timestamp, otherwise print timestamp
"stderr" print to stderr print to stderr when empty string suppress timestamp, otherwise print timestamp
"debug" syslog debug and print to stdout in parallel win debug feature (OutputDebugString) ignored if provided

Default log channels

When starting up, these default log channels are preconfigured:

Channel type gonuts usage
0 - debug "print" no. buffered
1 - info "print" print instruction. buffered
2 - warn "print" no. buffered
3 - error "stderr" error instruction, compiler, runtime and internal errors. unbuffered
4 - fatal "stderr" internal fatal errors (usually indicating termination). unbuffered

Note: the print instruction will always print to stdout in parallel, and the error instruction always prints to stderr in parallel. Only the respective log channel will have an optional timestamp and linefeed added when configured.

script.log function

function log([channel[,output])

logs a string to a log channel

INPUTS:
channel integer channel number.
output string to log
RETURNS: none
THROWS: on parameter error

When channel and output provided the output string is logged to the channel, which is normal usage of the feature.

script.log(2,"something is slightly wrong") ; logs "something is slightly wrong" using channel 2

Special combinations exist to provide ability to flush files and/or background buffers:
when no output is provided for a channel this flushes the given channel file, if any. In case the channel is not configured to type "file" the call will have no effect. This will NOT flush the background buffer queue for this channel:

script.log(1) ; //flush the file channel 1 writes to 

When no channel and output is provided at all, all buffered log queues will be flushed, forcing all output. This may take quite some time depending on the size of buffered log strings to output:

script.log() ; //flush all background buffering

Extended Class Constructors and Destructors

To make classes behave more like C++ classes, a base class providing (optional) class hierarchy constructors and destructors is available. However, there are a lot of side effects and constraints making usage a risky undertaking. However, we feel there are people out there that might find this feature useful for some special cases.

class WITH_DTORS

Use with care, no guarantees. This is experimental, nasty and has a lot of odd side effects!
Define your classes extending this base class to get the constructor- and destructor effects. The WITH_DTORS class itself has no members at all.

    class myclass extends WITH_DTORS {
      constructor() {} ;
      _destructor() {} ;
    }

constructor effects:

ALL class constructors will be iterated from bottom base class to top on instanciation, not just the constructor at the top in hierarchy(which is standard squirrel behaviour). This constructor behaviour is pretty much more like C++ does it. When a class or base class has no constructor, it's skipped on instanciation.
Note that any C++ constructors of any base class provided through dens (modules) will be skipped - hence such classes will probably be nonfunctional and prone to hard crashes or undefined behaviour. Use such base classes at your own risk!
This is also true for many gonuts native classes.

Destructors:

Destructors are highly experimental, use at your own risk!
Define a destructor being called when the class instance got destroyed.
They work like constructors, just other way around, executing going down any base class hierarchy. When a class or base class has no destructor it's simply skipped in the process.
However, note that the VM calling the destructor(s) IS INDETERMINED,in most cases it will be the VM or friend VM of the vm that ran the constructors, sometimes it will be the VM causing the object release.
Also destructors have a big disadvantage - there is no exact control when they're executed, usually they're executed one or two instructions after the point where one would expect the destruction. Object deconstruction is completely asynchroneous.
Be aware that accessing objects outside of the class instance being destructed generally is a very, very bad idea.
Do not fall into the pit to store references just to be able to access them from your destructor, or you'll find yourself in the "spurious host crash" or "unresolveable ring reference memory leak" situation soon.
Destructors make sense to operate on weak references ONLY.
Destructors can cause the garbage collector to fail lateron, and they may **cause gonuts to hard crash **on any thread deinitialization (that is, a real thread ends or application exits)

To put this explicitly: DESTRUCTORS ARE EVIL. They're really experimental... No guarantees, check them out yourself, but never, ever rely on them just for the sake of their existence!

Dens (Modules)

gonuts supports importing modules called dens. Modules generally are dynamically linked libraries (Windows: .DLL, Linux: .so) loaded at runtime using the import directive and extending functionality.

Users may create and distribute own modules. The import system ensures that loaded modules match the gonuts settings (like 32 or 64bits, float or double, garbage collector presence and some other squirrel specific settings) and provide general compatibility.
Gonuts comes with a C++ source code API for creating modules and some module sources are available as examples.
However, users must not modify the API source files in a way potentially or in fact breaking compatibility. Note that extending function pointer lists for example will probably do so LATER in time. However, the API provides a way for extensions (see hostspecific struct) which also can be used to have dens interoperate.
In this document only the Squirrel aspect is described, refer to specialized documentation about how to create dens.

import function

function import(name[,table])

loads and initializse a den module

INPUTS:
name string. Filename (optionally including path) of a den, **excluding any filename extension **(e.g. no .dll or .so)
table table object to pass to module initialization (destination table). Defaults to root table when omitted
RETURNS: null on failure, otherwise a table
THROWS: on lots of possible errors

Notes:

explicit 64bit operations

Sometimes, on 32 bit systems explicit 64 bit operations are required. Of course, they will also work on 64bit systems to keep code compatilbe with the drawback of less performance.

int64 class

The int64 class "emulates" (as much as possible) an 64bit (signed) integer type.
The class though has some syntactic drawbacks when it comes to expressions. It always must be on the right (in terms of 'proper') side of the operand of any (sub-)expression, or an exception will be thrown (unless both operands are an int64 instance).

This will fail:

local foo=1 ;
local bar=int64(2) ;
local result=foo+bar ; //will throw an exception
if (1 < bar) print("less\n") ; //will throw an exception

but this will work:

local foo=1 ;
local bar=int64(2) ;
local result=bar+foo ; //result will be an int64 class of the value 3.

Another drawback is taht not all operators will work, like shift operators or binary operators like or, and, xor... and even not.
The unary ! operator will also not work properly:

local foo=int64(0);
local isnull = !foo ; //isnull will be false, in absolutely ALL CASES!

Another drawback besides inevitable longer execution speed of operations (even on 64bit systems) is memory usage. Each "number" represented by an int64 instance will use up DOUBLE the memory needed, plus some global overhead - per RThread.
Comparisons will work properly between two instances, to be able to compare to other types (like standard integers, strings or floats) you need to utilize the member functions:

local foo=1 ;
local bar=int64(1) ;
local tmp=int64(2) ;
if (bar==foo) print("equal!\n") ; //will throw an exception.
if (bar==tmp) print("equal!\n") ; //will work, but not print (they aren't equal!)
if (foo==bar) print("equal!\n") ; //will throw an exception
if (bar.equals(foo)) print("equal!\n); //will print.

Additionally, to be compatible with legacy functions, an int64 also accepts strings as constructor input. Unrecognized strings will result in a value of 0 (zero),

supported operators

these operators are supported (int64 being an int64 instance, op2 being any of int64 instance, string, integer or float):

Operator position remarks
- -int64 (unary minus, like in local negative=-positive ; )
- int64 - op2
+ int64 + op2
* int64 * op2
/ int64 / op2
% int64 % op2
++ ++int64 or int64++ post- or preincrement
-- --int64 or int64-- post- or predecrement

when int64 instances being on both sides of the operator, these are additionally supported:
(this is Squirrel-inherent, and gonuts already "tricks" squirrel to make even these possible)

!=
==
<
>
<=
>=

However, there are member functions to be able to do comparisons of all kind between an int64 instance and either a string, another int64 instance, an integer or a float type. Also, all math operators are mirrored using a member function, plus some binary operation member functions exist.
Attention: The unary not (!) will never work properly

int64 class prototype

class int64{
	constructor(int[,inth]);
	function tostring();
	function tointeger();
	funtion gethi();
	function getlo();
	function isnative();
	
	function add(other[,otherh]);
	function sub(other[,otherh]);
	function mul(other[,otherh]);
	function div(other[,otherh]);
	function mod(other[,otherh]);

	function or(other[,otherh]);	
	function xor(other[,otherh]);
	function add(other[,otherh]);
	function sl(bits);
	function sr(bits);

	function cmp(other[,otherh]);
	function equals(other[,otherh]);

}

int64 constructor

int64(int[,inth]) ;

constructs a 64 bit instance from the parameters, where
int is either another int64 instance or an integer value, and
inthis an optional second "hi order" integer value. Must be omitted when int is an int64
The 64bit value is combined from int and inth with the following formula:
value=int | (inth<<32);

int64 Methods

Method int64.getlo

getlo()

returns the least significant 32 bit of the represented 64bit value

INPUTS: none
RETURNS:integer, the low order 32 bit integer value of the stored 64bit value
THROWS: no

Method int64.gethi

gethi()

returns the most significant 32 bit of the represented 64 bit valuie

INPUTS: none
RETURNS:integer, the high order 32 bit integer value of the stored 64bit value
THROWS: no

Method int64.tointeger

tointeger()

on 64 bit systems returns the 64 bit integer value, on 32 bit returns the least significant 31 bit of the represented 64 bit value, keeping its sign bit in the MSB.

INPUTS: none
RETURNS:integer, the "cast" of the 64bit to the native integer representation
THROWS: no

Method int64.isnative

isnative()

check if the stored 64 bit value fits into a native integer. On 64bit systems always returns true, otherwise the return value depends on the stored 64bit value.

INPUTS: none
RETURNS:bool, true=value fits into an integer, false=value does not fit into an integer
THROWS: no

Method int64.add

add(other[,otherh])

adds "other" to the current value and returns another int64 instance of the result

INPUTS:
other any int64 instance, string representing a decimal number, float or integer value
otherh optional and only when other is an integer, an integer similar to constructor inth (MSB part).
RETURNS:an int64 instance holding the result of the operation
THROWS: on any input parameter mismatch

Method int64.sub

sub(other[,otherh])

subtracts "other" from the current value and returns another int64 instance of the result

INPUTS:
other any int64 instance, string representing a decimal number, float or integer value
otherh optional and only when other is an integer, an integer similar to constructor inth (MSB part).
RETURNS:an int64 instance holding the result of the operation
THROWS: on any input parameter mismatch

Method int64.mul

mul(other[,otherh])

multiplies "other" with the current value and returns another int64 instance of the result

INPUTS:
other any int64 instance, string representing a decimal number, float or integer value
otherh optional and only when other is an integer, an integer similar to constructor inth (MSB part).
RETURNS:an int64 instance holding the result of the operation
THROWS: on any input parameter mismatch

Method int64.div

div(other[,otherh])

divides the current value by "other" and returns another int64 instance of the result

INPUTS:
other any int64 instance, string representing a decimal number, float or integer value
otherh optional and only when other is an integer, an integer similar to constructor inth (MSB part).
RETURNS:an int64 instance holding the result of the operation
THROWS: on any input parameter mismatch or on division by zero

Method int64.mod

mod(other[,otherh])

modulo operation. Returns another int64 instance of the result of the operation "current modulo other".

INPUTS:
other any int64 instance, string representing a decimal number, float or integer value
otherh optional and only when other is an integer, an integer similar to constructor inth (MSB part).
RETURNS:an int64 instance holding the result of the operation
THROWS: on any input parameter mismatch

Method int64.cmp

cmp(other[,otherh])

compares the current value with the provided other value

INPUTS:
other any int64 instance, string representing a decimal number, float or integer value
otherh optional and only when other is an integer, an integer similar to constructor inth (MSB part).
RETURNS: integer 0 when both values are equal, a negative integer when the current value is less than the provided, or a positive integer when the current value is greater than the provided
THROWS: on any input parameter mismatch

Method int64.equals

equals(other[,otherh])

compares current value with other and returns true or false

INPUTS:
other any int64 instance, string representing a decimal number, float or integer value
otherh optional and only when other is an integer, an integer similar to constructor inth (MSB part).
RETURNS:bool, true when both values are equal, otherwise false
THROWS: on any input parameter mismatch
Note: when other is an int64 you may as well directly compare them using the comparison == operator

Method int64.or

or(other[,otherh])

returns the result of the binary "or" operation of current and given value

INPUTS:
other any int64 instance, string representing a decimal number, float or integer value
otherh optional and only when other is an integer, an integer similar to constructor inth (MSB part).
RETURNS:an int64 instance holding the result of the operation
THROWS: on any input parameter mismatch

Method int64.xor

xor(other[,otherh])

returns the result of the binary "xor" (exclusive or) operation of current and given value

INPUTS:
other any int64 instance, string representing a decimal number, float or integer value
otherh optional and only when other is an integer, an integer similar to constructor inth (MSB part).
RETURNS:an int64 instance holding the result of the operation
THROWS: on any input parameter mismatch

Method int64.and

and(other[,otherh])

returns the result of the binary "and" operation of current and given value

INPUTS:
other any int64 instance, string representing a decimal number, float or integer value
otherh optional and only when other is an integer, an integer similar to constructor inth (MSB part).
RETURNS:an int64 instance holding the result of the operation
THROWS: on any input parameter mismatch

Method int64.sl

sl(bits)

performs a binare "shift left" operation of current value by given number of bits

INPUTS:
bits any int64 instance, string representing a decimal number, float or integer value denoting the number of bits to shift (only values making any sense are 0 to 64)
RETURNS:an int64 instance holding the result of the operation
THROWS: on any input parameter mismatch

Method int64.sr

sr(bits)

performs a binare "shift right" operation of current value by given number of bits

INPUTS:
other any int64 instance, string representing a decimal number, float or integer value denoting the number of bits to shift (only values making any sense are 0 to 64)
RETURNS:an int64 instance holding the result of the operation
THROWS: on any input parameter mismatch

Metamethod int64.tostring

tostring()

returns the 64bit value as a human readable string (in decimal format)

INPUTS: none
RETURNS:string
THROWS: no

Legacy functions

Basic 64bit operations can be performed using the following global functions.
All these functions can perform on 32 bit integers, but for values exceeding 32 bits they will use human readable string representations of numbers. All numbers can be entered as string or integer, return values depend on the necessary bit size.
(On 64 bit Squirrel they operate normally, not using strings as return values, but still accept them as an alternative input)
However, note that due to number conversions on 32bit Squirrel systems, these operations can get pretty slow especially when processing string inputs or outputs.
Note: String representations are always "plain decimal". There is no support for hexadecimal or octal representation.

Add64 function

function add64(op1,op2)

Adds two operands

INPUTS:
op1 Operand1 (integer or string containing an integer representation)
op2 Operand2 (integer or string containing an integer representation)
RETURNS:The sum of op1 and op2 (op1+op2) as an integer, or when an integer is limited to 32 bit and the result does not fit into 32 bits returns a human readable string representation
THROWS: no

Sub64 function

function sub64(op1,op2)

Subtracts op1 from op2

INPUTS:
op1 Operand1 (integer or string containing an integer representation)
op2 Operand2 (integer or string containing an integer representation)
RETURNS:The difference between op2 and op1 (op1 - op2) as an integer, or when an integer is limited to 32 bit and the result does not fit into 32 bits returns a human readable string representation
THROWS: no

Mul64 function

function mul64(op1,op2)

multiplies two operands

INPUTS:
op1 Operand1 (integer or string containing an integer representation)
op2 Operand2 (integer or string containing an integer representation)
RETURNS:The product of op1 and op2 (op1*op2) as an integer, or when an integer is limited to 32 bit and the result does not fit into 32 bits returns a human readable string representation
THROWS: no

Div64 function

function div64(op1,op2)

divides two operands

INPUTS:
op1 Operand1 (integer or string containing an integer representation)
op2 Operand2 (integer or string containing an integer representation)
RETURNS:The quotient of op1 divided by op2 (op1/op2) as an integer, or when an integer is limited to 32 bit and the result does not fit into 32 bits returns a human readable string representation
THROWS: no

Mod64 function

function mod64(op1,op2)

calculates the division remainder pf two operands

INPUTS:
op1 Operand1 (integer or string containing an integer representation)
op2 Operand2 (integer or string containing an integer representation)
RETURNS:The remainder of op1 divided by op2 (op1%op2) as an integer, or when an integer is limited to 32 bit and the result does not fit into 32 bits returns a human readable string representation
THROWS: no

GT64 comparison function

function gt64(op1,op2)

compares the operands

INPUTS:
op1 Operand1 (integer or string containing an integer representation)
op2 Operand2 (integer or string containing an integer representation)
RETURNS:True if op1 is greater than op2, otherwise false.
THROWS: no

LT64 comparison function

function lt64(op1,op2)

compares the operands

INPUTS:
op1 Operand1 (integer or string containing an integer representation)
op2 Operand2 (integer or string containing an integer representation)
RETURNS:True if op1 is lesser than op2, otherwise false.
THROWS: no

EQ64 comparison function

function eq64(op1,op2)

compares the operands

INPUTS:
op1 Operand1 (integer or string containing an integer representation)
op2 Operand2 (integer or string containing an integer representation)
RETURNS:True if op1 is equal op2, otherwise false.
THROWS: no

other tool functions

Millitime function

function millitime() 

INPUTS: none
RETURNS: an integer representing milliseconds since 1.1.1970
THROWS: no

Note: integers in squirrel generally are signed, but the value returned is meant to be unsigned. Expect a "negative" overflow accordingly.

Microtime function

function microtime()

INPUTS: none
RETURNS: an integer representing microseconds since 1.1.1970
THROWS: no

Same as millitime (negative overflow), plus 32 bit integers are prone to multiple overruns. Use for relative timings only

adler32 CRC function

function adler32(buffer[,concat])

calculates an adler32 checksum

INPUTS:
buffer any string, buffer, sockbuf or blob instance
concat integer, optional. start value (result of previous adler32 call to "concatenate" several buffers)
RETURNS: integer adler32 checksum of the given buffer.
THROWS: on input errors
Note: adler32 is a very fast algorithm with the drawback of high collision probability especially on short input buffers.

crc32 CRC function

function crc32(buffer[,concat])

calculates an 32 bit crc

INPUTS:
buffer any string, buffer, sockbuf or blob instance
concat integer, optional. start value (result of previous crc32 call to "concatenate" several buffers)
RETURNS: integer crc of the given buffer.
THROWS: on input errors
A standard cyclic redundancy checksum using 8 shifts per input byte and polynomial 0x04C11DB7 XOR on MSB(bit 31) set.

zinflate function

function zinflate(buffer[,expectheader])

INPUTS:
buffer any buffer, sockbuf or blob instance
expectheader bool, optional. Whether or not to expect a zlib header in the compressed data.
RETURNS: a buffer instance holding decompressed data, or null on invalid input data
THROWS: on input errors

zdeflate function

function zdeflate(buffer[,rate])

INPUTS:
buffer any string, buffer, sockbuf or blob instance
rate integer, optional compression rate. Value must be from 0 to 4095. Generally spoken, the higher the number the better (and slower) compression. Defaults to 128 when omitted.
RETURNS: a buffer instance holding compressed data, or null on compression failure
THROWS: on input errors

URLencode function

function  urlencode(string)

Encodes a string to an url compatible formatted string

INPUTS: string string to encode
RETURNS: encoded string
THROWS: on input parameter failures

URLdecode function

Decodes an url encoded string back to its standard format

function urldecode(string)

INPUTS: string url encoded string to decode
RETURNS: decoded string
THROWS: on input parameter failures

base64encode function

Convert a buffer object to a base64 encoded string

function base64encode(buffer)

INPUTS: buffer any string, buffer, sockbuf or blob instance
RETURNS: encoded string
THROWS: on input parameter failures

base64decode function

function base64decode(string)

Convert a base64 encoded string to a binary SQBuffer instance

INPUTS: string a base64 encoded string
RETURNS: an SQBuffer containing the decoded binary data or null when input cannot be decoded
THROWS: on input parameter failures

Note: for base32 encoding and decoding, use ::pxp.base32encode and ::pxp.base32decode from pxlib.pnut (remember: script.addarchive("pxlib.pnut"), but script.require("pxp") )

tohex function

function tohex(buffer)

Convert binary data to a 2character hexadecimal representation string
Convert a buffer object to a base64 encoded string
function base64encode(buffer)

INPUTS: buffer any string, buffer, sockbuf or blob instance
RETURNS: encoded string
THROWS: on input parameter failures

fromhex function

converts a hex string back to an SQBufferobject

function fromhex(string)

INPUTS: string a hex encoded string.
RETURNS: an SQBuffer containing the decoded binary data
THROWS: on input parameter failures or when input is no valid hex encoded sring

Note: accepts both upper- or lowercase alpha characters

GUUID function

function GUUID()

Creates and returns a new GUUID (Global unique universal ID) string

INPUTS: none
RETURNS: a string containing a new GUUID
THROWS: no

Global Universal Unique IDs are usually created from current time, hardware and random entropy data. It is utmost unlikely, if not impossible, that two identical GUUIDs are created anytime and anywhere on this planet. However, this behaviour is not guaranteed. Also note that GUUIDs are not inherently cryptographically safe.

NOTE: On Windows, this function uses the built in CoCreatGuid windows function. On linux, a random algorithm based on Yarrow is used. In case you want to use libuuid of your linux distribution there is a den supporting that (the den is available for windows, too, again using that CoCreateGuid function). That den will overwrite the built-in function when imported to the root table.

stat function

function stat(pathtofile)

returns general information about a file (calls stat() C function).
Especially useful in combination with fsdir class, which handles names only

INPUTS:
pathtofile: a string with a relative or absolute path to a file or directory
RETURNS: null when file not found or accessible, otherwise a table with below structure
THROWS: no
returned table when file or directory exists and is accessible:
{
path=pathtofile, //exactly the same as passed argument
len=int64(filesize), //size of file in bytes, see int64 class
ctime=creation_timestamp, //unix timestamp integer of file creation time
mtime=modify_timestamp, //unix timestamp integer of last file modification
atime=access_timestamp, //unix timestamp integer of last access
mode=filemode, //file type and mode (see linux/windows stat() c-function)
}

buffer class

buffers are binary buffer representations, offering a variety of data conversion and access.
They can also be a reference to parts of another buffer (copyless operations). They’re widely used within gonuts and a general binary data representation, unlike blobs (see Squirrel standard library) which represent binary data as streams.

Virtual representation:

	class buffer {
		constructor(in) ;
		_get(offset) ; //operator []
		_set(offset) ; //operator []
		function get(offset) ;
		function set(offset,integer) ; //no return value
		function set(offset,array) ;  //no return value
		function len() ;
		function size() ; //synonym for len()
		function array([offset[,len]]) ;
		function getstring() ;
		function setstring(string,offset[,len]) ; //no return value
		function setstringraw(string,offset[,len]) ; //no return value
		function setname(string) ;
		function getname() ;  
		function slice(offset[,len[,forcecopy]] ;
		function readblob(offset,len) ;
		function readsockbuf(offsetl,len) ;
		function getparent() ;
		function fillfrom(other) ;//inline operation, no return value
		function append(other) ; //inline operation, no return value
		function prepend(other) ;//inline operation, no return value
		function search(needle[,offset[,limit]]) ;
	}

buffer Constructors:

buffer(integer) 	

creates a new buffer with the size in bytes given by the integer parameter. The buffer content is random and not initialized!

buffer(string)

creates a buffer from a string, copying the string. Note the buffer is of size string.len()+1, adding a null termination!

buffer(array)

creates a buffer from an array. The array elements are expected to be integer values from 0 to 255 only!

buffer(blob)

Takes the given blob (see Squirrel standard library)) and REFERENCES IT. Changing the blob will change the buffer content and vice versa. However, changing the blob size will not be reflected on the buffer or vice versa. (For example when appending another buffer to this reference, the blob data will be copied before concatenation happens. Writing to the blob will not be reflected in the buffer).

buffer(sockbuf)

Creates a buffer by copying the contents of the given sockbuf instance. The sockbuf will not be drained and keeps its contents.

Note: You cannot create an buffer from another buffer using constructors. Use appropriate methods instead (fillfrom, append, prepend or slice, where slice puts you in control whether you want a referencing or copied buffer)

Methods

Bracket indexing (metamethods _get and _set )

You can access any byte within the buffer like an array by using brackets, both reading and writing. Will throw an exception when accessing indexes outside boundaries or the index is no integer
Example:

local buf=buffer(5) ;
buf[0]=0 ;
print(“buf 1: “+buf[1]) ;
local test=buf[5] ; //will throw an exception, as buffer size is 5 maximum index is 4.

Method buffer.get

function get(index)

An alternate way of reading a byte from the buffer at a given position.

INPUTS: index integer index position within the buffer
RETURNS: integer, byte at given buffer position
THROWS: when index is outside buffer bounds or no integer

Methods buffer.set

function set(index,value)

An alternate way of writing a byte to a buffer.

INPUTS:
indexinteger buffer position to write to
value integer byte to write to given position. Note the value will be ANDed with 255.
RETURNS: none
THROWS: on invalid input parameters or when index is outside buffer bounds

function set(index,array)

Copy several bytes to the given position in the buffer.
Array must be an array containing integer values. Index is integer.

INPUTS:
'index' integer start position for writing to the buffer
'array' array, each array element must be an integer value representing a byte to write (will be ANDed with 255)
RETURNS: none
THROWS: on invalid input parameters or when index is out of bounds

Method buffer.len

Synonym for size(), see below

Method buffer.size

function size()

returns the size of the buffer in bytes

INPUTS: none
RETURNS: integer, size of the buffer in bytes
THROWS: no

Method buffer.array

function array([offset[,len]]) 

returns buffer content as an array of integers representing bytes

INPUTS:
offset integer, optional. Offset within the buffer to start conversion. Defaults to 0 (start of buffer) when omitted
len integer, optional. Amount of bytes to process. When omitted, all bytes until end of buffer will be processed.
RETURNS: an array containing the bytes according to the input parameters
THROWS: on invalid input parameters or when the requested area of the buffer is out of bounds

Method buffer.getstring

getstring([offset[,len]])

converts the buffer or part of the buffer to a string

INPUTS:
offset integer, optional. Start position within the buffer
len integer, optional when offset is given. Amount of bytes to read from the buffer
RETURNS: a string consisting of the bytes in the buffer according to input parameters
THROWS: when input parameters are invalid

When len is omitted, zero or negative, all bytes until end of the buffer are returned.
When offset is omitted it is assumed to be 0, denoting the begin of the buffer.

Method buffer.setstring

function setstring(string,index,[len])

Copies the first len bytes of given string to given index position of the buffer (will cut the string regarding len and buffer size). Will append a null termination to the string. If you don't want an addition termination byte, use SetStringRaw instead (see below).

INPUTS:
string string, the input string
index integer (mandatory!), index of the target position within the buffer
len integer, optional. The amount of bytes to read from string. When omitted, all of the string will be processed.
RETURNS: integer, number of processed bytes
THROWS: on invalid input parameters

Notes: you must not omit index.
The buffer size will not change, when there is not enough room not all of the string will be copied to the buffer. The return value indicates how many bytes were actually processed, not including the terminating null character.

If len is omitted it is regarded zero (=copy to end of buffer or end of string, whichever occurs first).

Method buffer.setstringraw

function setstringraw(string,index,[len])

identical to setstring (see above), but will not append a null termination within the buffer.

Method buffer.setname

function setname(string)

Sets an additional string “name”, which basically is metadata attached to the string. When not set, defaults to an empty string. Note that this string will be included in the string returned by the tostring() metamethod of the buffer.

INPUTS: string, any string
RETURNS: none
THROWS: no

Method buffer.getname

function getname() 

Returns the additional name string. (empty string if not set)

INPUTS: none
RETURNS: the string set by setname (or an empty string when none is set)
THROWS: no

Method buffer.fillfrom

function fillfrom(bufferobject)

Re-creates the buffer by copying from a given buffer object, which can either be another buffer, a blob, an sockbuf or a string. Discards any current buffer content before copying. (Basically this is the same as constructor, but additionally supports SQBuffers, plus it never references a nother buffer but always copies data!)

INPUTS: any string, buffer, sockbuf or blob instance
RETURNS: none
THROWS: no

Method buffer.slice

function slice(offset[,len[,forcecopy]]) *

Returns part of the buffer as another new buffer.

INPUTS:
offset integer, start index within the buffer
len integer, optional. Byte count, when omitted, zero or negative processes until end of buffer
forcecopy bool, optional. When true or omitted the returned buffer will be independent and data is copied, otherwise (false) the returned buffer is a subbuffer referencing the data requested
RETURNS: An buffer instance referencing or containing the bytes requested
THROWS: on illegal input or out when requested area is out of bounds

Note that when referencing for a copyless operation, forcecopy must be provided as boolean false, and later changes to the subbuffer or the original buffer will reflect in the paired buffer, too.

Method buffer.readblob

function readblob(offset,len) 

Similar to slice, get the buffer or part of the buffer as a blob instance

INPUTS:
offset integer, mandatory. Offset where to start copying to blob in the buffer
len integer, mandatory. Number of bytes to copy from the buffer. When zero or negative will process all bytes until end of buffer
RETURNS: A blob fresh instance containing a copy of the indicated slice
THROWS: when indicated slice is outside buffer bounds or input parameters are invalid
Note: both input parameters are mandatory (yet)

Method buffer.getparent

function getparent()

returns the parent buffer referenced

INPUTS:: none
RETURNS: a parent SQBuffer instance or null when there is no referenced parent
THROWS: no

If the SQBuffer is a subbuffer (referencing another buffer), it returns the parent buffer, otherwise returns null.
Note that in case of a referenced blob this method will also return null!

Method buffer.search

function search(needle,offset[,limit]) 

Performs a binary search for first occurrence of needle within the buffer, starting at offset in the buffer, optionally limiting the search to limit bytes of needle.

INPUTS
needle: any string, buffer, sockbuf or blob instance to search fo within the buffer
offset: integer. An offset where to start the search in the buffer
limit: intereger, optional. Limit to "cripple" the amount of bytes taken into consideration from needle (always starting at its beginning)
RETURNS: a negative integer value of -1 when needle was not found in the indicated area of the buffer, otherwise an integer value indicating the first byte of the matching byte sequence within the buffer

If needle is a string, no terminating null character is included.
When offset is negative, it is calculated from the end of the buffer, but still a forward search is performed.
When limit is 0 or omitted, all of needle is searched for.
Returns the an integer value of the found starting position within buffer or -1 when there’s no match

Method buffer.readsockbuf

function readsockbuf()

Copies all content of this buffer to a sockbuf and returns it. Unlike readblob, this function always copies the complete buffer content.

INPUTS: none
RETURNS: an EvBuffer containing a copy of the SQBuffer content
THROWS: no

Method buffer.append

function append(object)

Appends the content of the passed buffer object to the current buffer content by copying.

INPUTS: a string, blob, buffer or sockbuf instance to append
RETURNS: none - the operation is inline
THROWS: exception if the input is invalid or missing

Note: When object is a sockbuf, this operation will not drain it and the sockbuf will keep its content.

Method buffer.prepend

function prepend(object)

Same a append, just the concatenation is other way around, the buffer will contain a copy of the content of object followed by its former content.

INPUTS: a string, blob, buffer or sockbuf instance to prepend
RETURNS: none - the operation is perfoming inline on current buffer content
THROWS: exception when parameter is invalid or missing

Note that this involves significantly more copying (the current buffer content will be also copied, not only that of the given object) compared to append().

Method buffer.array

function array([offset[,len]) 

Returns buffer content as an array of integers. Optional offset and len to indicate where to start and how many bytes to read from the buffer.

INPUTS:
offset: integer, optional. Index where to start reading from buffer content. Defaults to start of buffer content when omitted
len: integer, optional. Number of bytes (and hence array elements) to read. Defaults to read all bytes until end of buffer.
RETURNS: an array containing an integer element for each byte
THROWS: no

Note: Zero or negative len has the same effect like omitting and will indicate to get all bytes until end of buffer.

fsdir class

Tool class for reading filesystem directories.
Available on both windows and linux, but unfortunately working slightly different depending on platform. It is recommended to use the ISWINDOWS global to compensate yourself.
Currently fsdir can not differentiate between links, hardlinks and will not return hidden or system files on Windows.
See also stat function if you need more detailed infos besides names

Virtual class definition:

	class fsdir {
		constructor(filespec) ;
		function get() ;
		function getfiles() ;
		function getdirectories() ;
		function getentry(indexno) ;
		function size() ;
	}

fsdir Constructor:

fsdir(filespec) ;

Where filespec is a string.
It may contain an absolute or relative path and * wildcards (comparable to “dir” or “ls” shell commands).
Note: Will read the given directory immediately on construction ONCE, any changes in the filesystem won't be reflected afterwards and all methods will access this buffered "snapshot" information only.
Note that windows and linux operate differently about wildcards, and that path notation differs too. On linux, it is possible to get a subset of files matching a wildcard, while on windows you can only read a full directory and any "file specification" is treaded as a folder name.
Example Windows:

local a=fsdir("C:\mypath\somepath") ; //windows. note somepath is a PATH. A trailing backslash is optional

Examples Linux:

local a=fsdir("/var/log/*.log") ; //will return all files (and folders, if any) ending with ".log" 
local b=fsdir("/var/log/") ; similar behaviour as Windows, gets the full directory
local c=fsdir("./mypath/somepath") ; undefined, depending on somepath being a directory, file or is missing

Hint: There are tool functions in pxlib.nut providing automatic slash/backslash conversion depending on platform

Methods:

Method fsdir.get

function get()

Get all all entries as an array containing of tables with name and type(file or dir)

INPUTS: none
RETURNS: an array of tables representing all matching entries
THROWS: no
The tables include strings for name and type of entry each. Later versions may add more slots to the tables. Can return an empty table when something about the filespec was wrong (like the path did not exist).
Note that on linux, the parent and current directories will be returned (".." and ".") as usual.

Method fsdir.getfiles

function getfiles() 

Get all files (Linux: matching the filespec), omitting directories

INPUTS: none
RETURNS: an array of strings representing the filenames
THROWS: no

Method fsdir.getdirectories

function getdirectories()

like Getfiles, but returns directories only

INPUTS: none
RETURNS: an array of strings representing directory names
THROWS: no

Method fsdir.getentry

function getentry(index)

Returns a single table for the directory entry requested

INPUTS: an integer index specifying the entry number to retrieve, starting with 0.
RETURNS: A table containing type and name of entry
THROWS: on illegal index, negative index or when index is equal or larger than the return value of Size() (see below)

Method fsdir.size

function size()

Returns the number of present directory entries in the snapshot

INPUTS: none
RETURNS: integer value, number of available entries
THROWS: no

Tables returned by getentry() and get()

Tables returned by GetEntry and Get contain the following keys:

table key value
name a string with the directory entry name (e.g. filename, or subdirectory name)
type a string denoting the entry type, either being “file”, “directory” or “unknown”.

Later versions may extend functionality and present more sophisticated information in the tables

System/Shell (Daemons, Childs, Pipes) – Linux only

These classes and function do not exist on windows platform

systemfork Function

function systemfork(command[,path][,daemon[,pipes]][,parameters…])

Forks a program or shell command either as a child or daemon process, optionally installing I/O pipes for communication.
This function is much more flexible than the Squirrel stdlib system call and allows for parallel processing and process communication through standard pipes.

INPUTS:
command: string. shell command to execute (or path to executable)
path: string, optional. Working directory for the new process
daemon: bool, optional. true=daemonize, false= start a child process
pipes: integer, optional. Bitflags controlling pipe installment (see below)
parameters: any number of strings being the command line parameters to pass to the new process. Note that a single string with space separated parameters will not be the same like passeng them separately, but rather look like a single parameter put in parantheses for the new process
RETURNS : a ProcPipe instance when pipes were installed or the PID as an integer value if not, or null in case an error occured
THROWS: on any error but "unknown command/file not found"

Note some optional parameters can be omitted while providing followup parameter(s) due to type safety.

Bitflag table for pipes:

bit value meaning
0 1 install a pipe to childs stdin stream
1 2 install a pipe from childs stdout stream
2 4 install a pipe from childs stderr stream

bits not set will cause the related stream to be closed.
A value of 7 installs all three pipes, where a value of 2 will only install a pipe to read the standard output of the process
When pipes is omitted its value is assumed 0, which will cause the function to return a PID value rather than a ProcPipe instance on success

childstat Function

function childstat (PID)

Must be called regularly on forked childs to check child status and avoid zombie processes. Not necessary for daemons, but when a child process terminates it is wiped from the kernels process table ONLY when you called this function on its PID.
Use when SystemFork returned a PID integer value

INPUT: PID integer, mandatory. The process ID as returned by SystemFork
RETURNS: null, integer or bool (see below)
THROWS: no

Returns either:
-an integer representing the exit status of the child
-boolean false when the child was signalled (for example killed or crashed)
-boolean true when the child is still running
-null when the child does not exists or any other error occurred
When systemfork returns a procpipe instance users should prefer its status method over this global childstat function.
However, in Theory the PID can be of ANY process in theory to get their status, even foreign ones not started by gonuts

killPID Function

function killPID(PID[,signal])

Signal a process, usually to terminate it
Signals a process with the given PID. Not necessarily restricted to processes created using SystemFork.
It is similar to the well-known linux shell command "kill"

INPUTS:
PID integer, process ID of the process to signal
signal integer, optional. Signal number. Defaults to 15 (SIGTERM) when omitted. See table below
RETURNS: null when the PID did not exist, integer zero when signalled or integer -1 on any error (happens for example in cases of an invalid signal number, your gonuts does not have the permission to send the specified signal or when the targeted PID does not exist or is a zombie already.

Important: If you run gonuts underh admin privileges (root) and provide a PID of -1 here you signal to ALL PROCESSES of the host system (except gonuts and the 'init' process).

gonuts provides constants for the most common signals:
SIGHUP, SIGINT, SIGABRT, SIGKILL, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM and SIGQUIT for convenience.

Table of sample signals:

Integer value Signal
1 SIGHUP - indicate the death of terminal or controlling process
2 SIGINT - interrupt from keyboard, attention signal
3 SIGQUIT - caused by CTRL-C on keyboard
9 SIGKILL - immediate "forced" termination via kernel, unblockable
10 user defined signal
12 user defined signal
14 SIGALRM (alarm clock timer signal)
15 SIGTERM - normal termination request
19 SIGCONT - continue after SIGSTOP
20 SIGSTOP - stop process, unblockable

consult your host system documentation about its signals.
You can catch some external signals using gonuts' event system (see Event), too.

Note: Users should prefer the methods of ProcPipe instances over this general global function when handling non-daemonized childs.

procpipe class

The procpipe class instance represents a forked child or daemon process, enabling communication through pipes (and also providing the PID and functions to signal or check the status).

Virtual prototype:

	class procpipe  {		//note this class has no constructor
		function Read(count);
		function ReadErr(count);
		function Write(buffer);
		function WriteString(string);
		function CloseWrite();
		function CloseErr();
		function GetPID();
		function Signal(sig);
		function Status();
	}

Constructors:

Not available. Users cannot create instances directly, they’re ONLY returned by the function SystemFork.

Methods:

Method procpipe.read

function read(count) //blocking call

reads (up to) count bytes from the standard I/O pipe (process stdout).

INPUTS: count integer, amount of bytes to rad
RETURNS: null when pipe is disconnected or a read error occurs, otherwise a SQBuffer object
THROWS: on input parameter error

This is a blocking call and will only return on error or after the requested number of bytes was read!
When count is negative, it defaults to 128. When it is 0, all available data is read.
Again, note this is a blocking call!

Method procpipe.readerr

function readerr(count) //blocking call

Same as Read, but uses the stderr pipe of the process

Method procpipe.write

function write(buffer)

Writes an SQBuffer to the stdin of the process

INPUTS: buffer a bufferobject. Mandatory, no buffer conversions!
RETURNS: integer. -1 = write error, 0 = success
THROWS: on input parameter error

Note this method accepts buffer objects only.

Method procpipe.writestring

function writestring(string)

Writes a string to the stdin of the process without a terminating null character (note converting a string to a SQBuffer object usually inplies a terminating null character)

INPUTS: string string to write
RETURNS: integer. -1 = write error, 0 = success
THROWS: on input parameter error

Method procpipe.getPID

Returns the integer Process ID of the process
function getPID()

INPUTS: none
RETURNS: integer PID of the process, or -1 after process terminated
THROWS: when input parameter provided

Do not rely on the process NOT being terminated when return value is not -1. Use Method Status() instead.

Method procpipe.closewrite

function closewrite()

Close the pipe to stdin of the process

INPUTS: none
RETURNS: none
THROWS: when input parameter provided

Method procpipe.closeerr

function closeerr()

Close the pipe to stderr of the process

INPUTS: none
RETURNS: none
THROWS: when input parameter provided

Method procpipe.closeread

function closeread()

Close the pipe to stdout of the process

INPUTS: none
RETURNS: none
THROWS: when input parameter provided

Method procpipe.signal

Signal the child process

function signal(sig)

INPUTS: sig integer or integer constant, see table of function KillPID
RETURNS: null when the PID did not exist, integer zero when signalled or integer -1 on any error (happens for example in cases of an invalid signal number, your gonuts does not have the permission to send the specified signal or when the targeted PID does not exist or is a zombie already.
THROWS: onm input parameter number or type mismatch

Method procpipe.status

function status()

Returns process status similar to function ChildStat, however is will invalidate the stored PID (by setting PID to -1) when child status indicates any termination.
Users should prefer this method over using global function ChildStat with method GetPID.
However, status will return false or an integer only ONCE when the child terminated meanwhile, any subsequent calls will then return null. In case of a null return, if you're unsure if there was another call returning a termination/exit value, you may check for GetPID() returning -1 which is indicating a termination.

Database support

Native database support has been removed from the gonuts core to reduce footprint for users not requiring database access.
There are several options for database support using den modules: dendbi(linux only), densqlite or dencql. A denmariadb to access mysql is work in progress (use dendbi to access mysql or mssql for now. Not available for MS Windows)

.

Events, Timers, Network and sockets

classes for event handling and networking.

Preliminary notes

VMs do have a mutex for their shared state, which is locked while the VM is running, and temporarily unlocked for any eventbase dispatching, osyield or rtsync operation. Basically spoken, this happens every time gonuts expects code execution within the same VM state before the respective call returns (called code injections), for example caused by event handlers. Before the call returns, it will lock the VM again.
This functionality may cause lockups in some special situations, which is intended and necessary to resolve improper nesting of event and multithreading capabilites. In a worst case scenario a programmer in fact could run his application into an infinite stall situation. Be careful when nesting these gonuts capabilities, and make sure you understand what is happening under the hoods and which situations may possibly arise in your application. A simple truth when it comes to multitasking is "sh!t happens just because (you did not think twice)".

Network addresses

gonuts uses strings for network addresses, in "the usual human-readable form". That is, you may use (and expect) strings like "127.0.0.1", "0.0.0.0:8000" or "192.168.1.17:80".
Most methods try to resolve hostnames, so you also may use "localhost", "mydomain.com:80" or such representations you are used to. However, you **must not ** add protocol prefixes like "http://"
Important: gonuts does not yet fully support IPV6. As gonuts grew historically, this is pretty much what people call a PITA...

Event handlers

Event handlers are described in the respective sections of the classes using them. Depending on the type of event they have slightly different prototypes, but they have some common traits.
When called, the Squirrel this object is always the event handler function itself, hence you cannot access any objects except parameters passed to the function or functions and class definitions in the root table, which is a Squirrel default fallback. Hence you will need to use the bindenv method on the function to provide a this object in case you need a different behaviour - or you need to access globals using an absolute "path" (using the double colons to reference the root table and "index your way" through the tables/objects).
Within the handler, the callee function would return the handler function itself, while a stack trace would reveal the eventbase.dispatch line followed by an "unknown" native function and the handler function (gonuts is performing some tricks here and cannot provide proper function names).
Dispatching the calling eventbase loop from within a handler will throw an exception.
Any runtime error or exception occuring will not survive or propagate beyond the event call, however, at the end of the call any exception not catched (try/catch) will definitely and inevitably print the callstack (That is, if you set up a timer to call every 2 milliseconds and the handler code is erroneous, excessive error output or logging would occur).

hostresolve function

function hostresolve(host)

resolves a hostname string to an IP address string

INPUTS: host string. a hostname/ domain name
RETURNS: a string in human readable IP address format, e.g. "127.0.0.1" when resolving "localhost"
THROWS:

The human readable address representation can be passed to network classes and functions. There is no need for a binary representation.

hostname function

function hostname() ;

returns the hostname of the local platform

INPUTS: none
RETURNS: string
THROWS:

getmacs function

function getmacs()

returns a list of all (networking) interfaces including their hardware address

INPUTS: none
RETURNS: a table, where each key is a network interface identifyer (string) and its value is a buffer holding the binary hardware address
THROWS: no

you will need to iterate through the table entries using a foreach loop

pairedbuffers function

function pairedbuffers(base[,options])

creates paired (interconnected) bufferedevent instances. Each output is connected to the input of the partner, making your app able to "talk to itself" via the pair.

INPUTS:
base: an eventbase instance the buffers will be linked to.
options: integer, option flags - see bufferdevent options
RETURNS: an array with two elements, each holding a bufferedevent instance
THROWS: on input parameter mismatch
Note there is only a single eventbase for both bufferedevent instances created, and they both do not have a socket. Hence when used in multithreading, only one single thread can dispatch. For a multithreading usage, you either must not provide options or provide at least BEV_THREADSAFE, or really, really bad things will happen!
options will default to BEV_THREADSAFE | BEV_DEFER when omitted. Also BEV_DEFER will always be set, no matter which options you provide.

pairedsockets function

function pairedsockets() 

creates a pair of interconnected sockets (on localhost/127.0.0.1).

INPUTS: none
RETURNS: an array with two elements, each holding a sockfd instance
THROWS: when no socket pair could be created
Similar to pairedbuffers, these sockfd instances are connected via localhost and are intended to be used to create bufferedevents in different threads, which then are able to use different eventbase loops and provide means for the threads to talk to each other using a tcp stream over localhost. (Note, there is also the rtsync class providing a FIFO for complex objects which do not require a protocol or manual serialization and deserialization, or use any socket). Important: a firewall may block these paired sockets or prevent their creation, same as kernel issues/limitations may do, both resulting in an exception.

eventbase class

The base for handling events (event loop object). Events may be handled by several base objects in parallel, whereas only one eveentbase per RThread may actually process or loop at a given time.
IMPORTANT NOTE: events are prone to lockups or exceptions when trying to re-enter the same eventbase loop from within an event handler called by that loop.

virtual prototype:

	class eventbase {
		constructor() ;
		function dispatch();
		function dispatchonce();
		function dispatchnoblock();
		function exit(inms);
		function break();
		function priority_init(prioritiescount)
	}

eventbase Constructor

eventbase()

dead simple create an event base, no parameters

eventbase Methods

eventbase.dispatch Method

function dispatch(ms)

run an event loop and dispatch events for a certain time

INPUTS: ms time in milliseconds to run the loop. Pass any negative value for infinity
RETUNRS: none
THROWS: on any direct or indirect recursive call

Notes:

eventbase.dispatchonce Method

function dispatchonce()

runs the event loop exactly one time until a first active and pending event is served. Hence calling exactly one event handler of a pending event or does nothing if none is both active and pending.

INPUTS: none
RETUNRS: none
THROWS: on any direct or indirect recursive call

eventbase.dispatchnoblock Method

function dispatchnoblock()

runs the event loop exactly one time, dispatching all active and pending events, if any.

INPUTS: none
RETUNRS: none
THROWS: on any direct or indirect recursive call

eventbase.exit Method

function exit([ms])

Will end any dispatch command above after the given time. When time is 0 or negative, it will end dispatching after the current loop cycle is finished.

INPUTS: ms integer, optional time in milliseconds until the looping of any dispatch command will end.
RETUNRS: none
THROWS: no

eventbase.break Method

function break() 

Aborts the loop so that a running dispatch command will return without serving any event that may still be pending.
When the eventbase is not in its loop and dispatching, this function will have no effect.
Any active and pending event stays pending and will be served by the next dispatch loop

INPUTS: none
RETUNRS: none
THROWS: no

eventbase.priority_init

function priority_init(prioritiescount)

sets a range of event priorities supported by the eventbase. When set, event priorities may be set within the range provided.

INPUTS: prioritiescount integer, number of priorities supported by the event base
RETUNRS: none
THROWS: no

basically this configures the eventbase to several loop passes, where any event assigned is located in a loop queue corresponding to its priority. Every dispatch loop of the eventbase will run these queues in order.

Event class

general event object. An event always is assigned to an eventbase, where it can be active or inactive, and when it is active it may be pending or not. Whether it is active or not is under user control; whether it is pending is controlled by the event source (socket, file descriptor, timer, and/or user control also, see fire method).
An active pending events callback handler (event handler) is subject to be called by the eventloop when dispatching.

virtual prototype:

	class event {
		constructor(ebase,cbfunc,arg,flags[,evfd]) ;
		function fire(argflags) ; //trigger
		function getflags();
		function getbase();
		function activate(timeout);
		function deactivate();
		function setpriority(prio);
		function setcallback(func[,arg]);
		function setcbarg(arg);
	}

Event handler prototype function

Any event handler function for an event must accept exactly 4 parameters:

function myhandler(fd,eventtype,eventinstance,argument)

where

Any return value of the handler function will be ignored

Event Constructor

event(ebase,cbfunc,arg,flags[,evfd])  //when EV_SIGNAL is not set in flags
event(ebase,cbfunc,arg,flags,sig[,evfd]) //when EV_SIGNAL is set in flags

where

ebase instance of eventbase to assign this event to
cbfunc function, callback/event handler function to call when the event is triggered, prototype described above
arg any type/object. Argument to be passed to the event handler function
flags integer, bitwise flags determining event type and behaviour, see table below
evfd optional instance of sockfd to assign a socket or file descriptor to the event
sig integer, mandatory when EV_SIGNAL is set in flags. See table of signals and predefined constants. Use on linux platform only, on win32 there are no such signals and the event can only be triggered manually.

Creates an event instance and assigns it to an eventbase instance. The event instance is inactive and needs to get activated using event.activate method before any event.fire or external event (as defined by flags) can be processed. Events will be handled during any dispatch call on the assigned eventbase

event flags

Event flags, except EV_SIGNAL, may be ORed using the pipe operator to combine them

Flag Effect
EV_SIGNAL Listen to a linux process signal, see table of signals
EV_READ pending/trigger when there is data to read on the connected sockfd stream
EV_WRITE pending/trigger when the connected sockfd is ready to write to
EV_TIMEOUT pending/trigger when the timer/timeout elapsed (as passed to event.activate)
EV_PERSIST enable repetitive triggering; when triggered and handler was called, the event shall remain active in the eventbase
EV_ET enable edge triggering (may be necessary for some hardware related events, will trigger every time the status of the event source changes, be it from 1 to 0 or other way around)

Note: these are not the values passed to eventhandlers in the eventtype parameter. See [constants table for bufferedevent(#eventtypetable) for flags passed to handlers by bufferedevent or event instances connected to a socket

Event Methods

event.fire Method

function fire(pass)

make an event pending (aka trigger it). If it is active for a certain eventbase its eventhandler will be called by running (or by future) dispatching of that eventbase.

INPUTS: pass an integer value passed to the handler function of the event.
RETURNS: none
THROWS: no

The parameter will be passed as the "eventtype" parameter to the handler function.

event.activate Method

function activate(ms)

activate the event in its eventbase. Non-active events will not trigger. Optionally sets a timer for the event to trigger when elapsed (to use as timeout, or to use the event as a timer)

INPUTS: ms integer, optional Milliseconds for timeout/timer
RETURNS: bool, wether the event was activated (true) or an internal error occured (false)
THROWS: no

event.deactivate Method

function deactivate()

deactivate the event in its eventbase. The event source cannot trigger the event anymore

INPUTS: none
RETURNS: bool, wether the event was deactivated (true) or is still active (false on error)
THROWS: no

event.setpriority Method

function setpriority(prio)

INPUTS: prio integer, positive priority of the event compared to other events in the same eventbase. Note this value must be within the range already defined using eventbase.priority_init
RETURNS: bool, wether the event was activated (true) or an internal error occured (false)
THROWS: no

event.getflags Method

function getflags()

returns the flags set on construction of the instance (see event flags above)

INPUTS: none
RETURNS: integer, event flags set on construction of the instance
THROWS: no

event.getbase Method

function getbase()

INPUTS: none
RETURNS: the eventbase instance this event is assigned to
THROWS: no

event.setcallback Method

function setcallback(cbfunc[,arg]);

(Re-)Sets the callback function and optionally user argument (see also: constructor)

INPUTS:
cbfunc the callback function (prototype see above)
arg optional user argument to pass
RETURNS: none
THROWS:: on invalid input arguments

event.setcbarg Method

function setcbarg(arg);

(Re-)Sets the callback user argument. Does not care wether a callback is actually set or not

INPUTS: arg the user argument to pass to the callabck function
RETURNS: none
THROWS: no

sockbuf class

…A class representing a single stream buffer, optimized for copyless operation on streams, especially utilized by the Event system for I/O operations on files and sockets. sockbufs basically work as a byte FIFO, supporting copy-less operations in the background as well as automatic concatenation of allocated memory blocks through a linked list. They're the most effective type of binary buffer when you need a FIFO only without any seeking or indexing abilities - aka streams.

virtual prototype:

	class sockbuf {
		constructor() ;
		function enablelocking(); //multithreading precaution
		function lock(); //multithreading precaution
		function unlock(); //multithreading precaution
		function size();
		function readln(bytes,EOLtype);
		function getcontiguous();
		function reserve(bytes);
		function linearize(bytes);	
		function drain(bytes);
		function remove(len) ;
		function peek(len) ;
		function add(data[,len]);
		function prepend(data[,len]);
		function write(fd);
		function read(fd,bytes);
		
	}

sockbuf global constants

predefined constants for EOLtype:

constant type of linefeed
EOL_LF newline ('\n') character only
EOL_CRLF carriage return ('\r') and newline ('\n') in any order
EOL_CRLF_STRICT carriage return followed by newline only
EOL_ANY any newline, carriage return or both in any order

sockbuf Construtctor

sockbuf() 

Dead simple, create an empty stream buffer. Unlike buffer or blob, as sockbufs are FIFO only, there are no parameters to reserve space or assign data upon construction.

sockbuf Methods

sockbuf.enablelocking Method

function enablelocking()

enable mutex locking for this buffer. Used internally, but provided to Squirrel in case someone finds a special use case. Note sockbufs cannot be passed to another thread (yet)

sockbuf.lock Method

function lock() 

locks a sockbuf for access. Any subsequent lock will wait infinitely for the buffer to be unlocked. used internally, but provided to Squirrel in case someone finds a special use for this.
When the sockbuf is not enabled for locking, this function won't do anything.

sockbuf.unlock Method

function unlock()

counterpart of lock(), unlocks a sockbuf

sockbuf.size Method

function size() 

returns the size of the data in the sockbuf in bytes. Note there intentionally is no len() alias, because a sockbuf cannot be indexed

INPUTS: none
RETURNS: integer, total size of data within the sockbuf
THROWS. no

sockbuf.readln Method

function readln(len,EOLtype)

reads a line from the buffer, where EOLtype defines how line endings will be detected

INPUTS:
len integer, maximum number of characters to read (must be positive, there is no "unlimited" indication!)
EOLtype mandatory integer, either EOL_LF, EOL_CRLF, EOL_CRLF_STRICT or EOL_ANY as described above.
RETURNS: a string holding the line read
THROWS: on input parameter failures

sockbuf.getcontiguous

function getcontiguous()

returns the maximum amount of bytes a peek or remove operation will be most effective (Exceeding this value will involve more copying internally), or when the sockbuf is not split into several memory areas, the amount of bytes readable.

INPUTS: none
RETURNS: integer, size of first memory block in the FIFO
THROWS: none

sockbuf.reserve

function reserve(bytecount)

internally allocates memory for a certain amount of bytes to be added without involving further allocations. subsequently added data using add up to this amount of bytes will be located in this contiguous memory area.

INPUTS: bytecount integer, number of bytes to ensure add operations will hit the same linear chunk of memory internally
RETURNS: none
THROWS: no

sockbuf.linearize Method

function linearize(bytecount)

internally ensures, by allocations and copying data if needed, that a certain amount of data subsequent drain, readln, remove or peek methods will operate on, is within a linear chunk of memory.

INPUTS: bytecount integer, number of bytes to linearize within the buffer. Negative values will linearize the whole buffer into a single memory chunk
RETURNS: none
THROWS: no

Note: On large buffers created by many subsequent adds this may be a quite costly operation

sockbuf.drain Method

function drain(len)

removes bytes from the buffer as if they were consumed by remove

INPUTS: len integer number of bytes to remove without actually copying or returning them
RETURNS: none
THROWS: no

sockbuf.remove Method

function remove([len])

reads bytes from the buffer and returns them in a buffer instance. This is the standard method for reading data from a sockbuf, do not confuse with read method (see below)

INPUTS: len integer, optional. Number of bytes to read and return. When omitted, all data in the sockbuf is processed.
RETURNS: a buffer instance holding up to len bytes of data read from the FIFO (depending on bytes present in the FIFO), or null when there are no bytes in the FIFO.
THROWS: no

sockbuf.peek Method

function peek([len])

copies bytes from the FIFO without draining/removing them. The sockbuf FIFO stays unchanged and data returned by subsequent drain, remove or peek calls is not affected.

INPUTS: len integer, optional. Number of bytes to copy and return. When omitted, all data in the sockbuf is processed.
RETURNS: a buffer instance holding up to len bytes of data as if read from the FIFO using remove, or null when there are no bytes in the FIFO.
THROWS: no

depending on the memory chunks present in the FIFO this may involve costly copying operations internally. Also see linearize and reserve to manipulate internal memory organization.

sockbuf.add Method

function add(data[,len])

adds data to the FIFO. This is tha usual operation for adding data not to be confused with write (see below)

INPUTS:
data: any string, blob, buffer or other sockbuf instance. When a sockbuf instance is passed, you must omit len. When asockbufis passed it will be drained and hence empty afterwards
len: integer, optional. (Maximum) number of bytes to copy from data to the FIFO
RETURNS: integer number of bytes added to the FIFO
THROWS: when len is provided, but data is another sockbuf instance

Note sockbuf data amount can not be limited and always all data in it will be used, however such an operation is most effective and not actually copying any data - it simply concatenates internal memory chunks and leaves tha passed sockbuf instance fully drained (=empty).

sockbuf.prepend Method

function prepend(data[,len])

similar to add, but data is added to the 'wrong' end of the FIFO (= LILO operation). Subsequent peek, drain or remove operations will see the passed data first.

INPUTS:
data: any string, blob, buffer or other sockbuf instance. When a sockbuf instance is passed, you must omit len, and it will be drained and hence empty afterwards
len: integer, optional. (Maximum) number of bytes to copy from data to the FIFO
RETURNS: integer number of bytes actually prepended
THROWS: when len is provided, but data is another sockbuf instance

Again, prepending a sockbuf is an almost copyless operation, but leaves the passed other sockbuf drained (empty).

sockbuf.write Method

function write(fd)

writes the whole content of the sockbuf to a socket or file, draining the sockbuf

INPUTS: fd a sockfd instance to write data to
RETURNS: integer amount of bytes written, or -1 on any error
THROWS: no

Note that the amount of bytes actually written not only depends on the sockbuf FIFO content, but also on the sockfd. This method tries to write as much data as possible, but does not guarantee to write all FIFO content.
If fd is configured as nonblocking a return value of -1 possibly means the call would block and should be tried again later. There is no way yet to determine the exact cause of an error return value.

sockbuf.read Method

function read(fd,count)

reads data from a socket or file and add it to the FIFO

INPUTS:
fd a sockfd instance to read data from
count integer, maximum number of bytes to read from given sockfd. When negative, tries to read as much as possible
RETURNS: integer amount of bytes read, 0 on EOF or -1 on any error
THROWS: no

Same as write, may read less than countbytes, and also may return -1 when fd is in nonblocking mode and the call would block (which may happen when count is not negative, a positive count WILL try to block until the amount of bytes is read, and hence return an error on nonblocking sockfd)

sockfd class (Sockets/File Descriptor)

On Windows, this represents a network socket only. On Linux, where “everything is a file”, it additionally supports files and provides special functionality to operate on tty (serial) interfaces.
It allows for manual binding of network sockets and provides basic means for DATAGRAM or CAN sockets. However, using sockfd and its recvfrom and sendto methods (for UDP or CAN) is somewhat slower compared to TCP sockets utilizing the bufferedevent class.
When using sockfd in conjunction with events, you shall use the event system access methods for reading and writing rather than the sockfd methods, otherwise the event system may behave in an odd manner.
Important note: Many methods are unavailable on win32 platform

Be aware, sockfd is a rather sloppy implementation grown historically. Originally it was intended to be able to pass around file/socket descriptors for the event system only, then to be able to access and configure serial interfaces and latest to make UDP sockets available to the event system. It is not tested for other uses or socket types yet.

virtual protoype:

	class sockfd {
		constructor();
		constructor(fd);
		construcotr(af,prot[,pf]);
		//file stream methods, linux only
		function read(count);
		function write(data[,count])
		function openfile(filespec,mode);
		function ioctl(request,...);

		//tty/serial methods, linux only
		function setbaudrate(bps,mode);
		function TIOGet();
		function TIOSet(flags);
		function TIOClearBit(which);
		function TIOSetBit(which);
		
		//socket methods, all platforms
		function setnonblocking();
		function setreusable();
		function setcloseonexec();
		function setbroadcast();
		function bind(address); 
		function connect(address);  //recommended to prefer bufferedevent class
		function sendto(data,address); 
		function recvfrom([mtu]);
		function accept();   //recommended to prefer socketlistener class
		function listen([backlog]);  //recommended to prefer socketlistener class
		
	}

sockfd global constants

modes (flags for openfile, to combine using OR operator | ):
O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, O_CREAT, O_EXCL, O_NOCTTY, O_DSYNC, O_NONBLOCK, O_RSYNC, O_SYNC, O_TRUNC

TIO bits /flags (modem control)
TIO_RTS, TIO_CTS, TIO_DSR, TIO_DTR, TIO_RI, TIO_DCD

socket modes
AF_INET, AF_UNIX, AF_INET6, AF_APPLETALK and
SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET as well as
AF_CAN, PF_CAN, CAN_RAW, CAN_BCM, CAN_MCNET, CAN_ISOTP (not supported by sockfd directly)

sockfd Constructor

sockfd() ;

creates an "empty" instance not connected to any socket or file yet (for use with openfile)

sockfd(fd) ;

copy constructor, take over the socket or file from another sockfd instance. Both then can operate in parallel
where fd is another sockfd instance.

sockfd(af,type[,pf])

create a socket, where

af integer, address family. Pass AF_INET, AF_UNIX, AF_INET6, AF_APPLETALK or AF_CAN
type integer, socket type. Pass SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_RDM or SOCK_SEQPACKET
pf integer, optional. Protocol family, pass AF_INET, AF_UNIX, AF_INET6, AF_APPLETALK or PF_CAN

Note: CAN is not really supported by sockfd methods, but present as preparation for a respective den module, where sockfd instances may still be used for passing around only.

sockfd Methods

sockfd.read Method

function read(count)

attempts to read bytes from a stream. Note this is a blocking call!

INPUTS: count maximum number of bytes to read
RETURNS: false on any error (including EOF), integer 0 when no bytes were read, otherwise a buffer instance holding the bytes actually read
THROWS: on parameter errors

Note: In case of any error there is no way to retrieve more detailed information about the cause

sockfd.write Method

function write(data[,count])

attempts to write as much bytes as possible to a stream, up to an optionally passed limit
Note this basically also can block.

INPUTS:
data a buffer, sockbuf or blob instance, or a string
count maximum number of bytes to write
RETURNS: integer count of bytes actually written, or false in case of any error
THROWS: on parameter errors

Note: In case of any error there is no way to retrieve more detailed information about the cause

sockfd.openfile Method

function openfile(filespec,mode)

opens a linux file stream.

INPUTS:
filespec string. file specification as an absolute or relative path
mode integer, bitflags combined of O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, O_CREAT, O_EXCL, O_NOCTTY, O_DSYNC, O_NONBLOCK, O_RSYNC, O_SYNC and/or O_TRUNC
RETURNS: bool, true on success, false on any error
THROWS: no

Trying to call openfile on a sockfd already being a socket or already opened file will fail and return -1
Refer to linux man pages for "open".

Note there is no dedicated close. To close an opened stream you need to simply destroy the sockfd instance.
(Also note there is no flush method! When using actual files the use of Squirrel Standard Lib's file class is much more convenient). Using sockfd for files is meant to allow for event or bufferedevent driven data transfers, especially when it comes to devices like serial ports.

sockfd.ioctl Method
function ioctl(request,...)

performs an ioctl operation on the sockfd file descriptor

INPUTS:
request integer, the "command" for ioctl. For now, gonuts does not provide enums for that, so refer to the appropriate c/c++ headers of the target OS!
... additional paremeters may be intereger, float, string or buffer. Buffers will be double buffered with a maximum size of 4KB.
RETURNS:
either integer in case of an error (ERRNO), or an array of the input parameters, possibly modified by ioctl.
THROWS: no. ATTENTION: In case the system call writes to the parameters, strings should be passed as buffers. POSSIBLE HARD CRASH WHEN SHORT STRINGS BECOME LONGER STRINGS! (or ioctl writes to buffers more than 4KB).

sockfd.setbaudrate Method

function setbaudrate(baud,mode)

sets the baud (Bits per second) rate and operation mode for a device supporting the feature (aka serial ports)

INPUTS:
baud integer baud rate. Supports 50,75,110,134,160,200,300,600,1200,2400,4800,9600,19200,38400,57600,115200 and 230400 baud. All other values will cause an error
mode string denoting data format, for example "8N1" or "7O2". Supports 5,6,7,8 for the first character (data bits), N (no parity), O (odd parity) or E(even parity) for the second and 1 or 2 for the third (stopbits)
RETURNS: true when set, or false on any error

Note: On success this call also disables canonical mode (=line oriented processing), disables blocking and enables raw output.
You will have to handle raw binary data by all means. If you do not want this behaviour you may try to configure the interface using system shell commands instead and leave the sockbuf unconfigured...

sockfd.TIOGet Method

function TIOGet()

return the current TIO flags (for serial interfaces this is modem control usually)

INPUTS: none
RETURNS: integer, curent flags as returned by ioctl with TIOCMGET. Returns 0 when no file descriptor connected
THROWS: no

sockfd.TIOSet Method

function TIOSet(flags)

sets tthe TIOFlags, any bitwise ORed combination of TIO_RTS, TIO_CTS, TIO_DSR, TIO_DTR, TIO_RI, TIO_DCD
returns true on success, false on error

sockfd.TIOSetBit Method

function TIOSetBit(flag)

sets a single bit, any one of TIO_RTS, TIO_CTS, TIO_DSR, TIO_DTR, TIO_RI, TIO_DCD
returns true on success, false on error

sockfd.TIOGetBit Method

function TIOClearBit(flag)

clears a single bit, any one of TIO_RTS, TIO_CTS, TIO_DSR, TIO_DTR, TIO_RI, TIO_DCD
returns true on success, false on error

sockfd.setnonblocking Method

function setnonblocking()

sets the stream to nonblocking operations. Note this introduces additional causes of errors for usually blocking methods of sockfd.
No parameters, no return value.

sockfd.setreusable Method

function setreusable()

Sets a socket to reuseable mode. That is, the kernel will allow to re-bind to the port/socket in question, preventing an error when trying to do so. Find more information on the Internet about SO_REUSEADDR. (Note this method does not set SO_REUSEPORT!)
Works on win and linux platforms. You need to call this BEFORE any binding to an address.
No parameters, no return value.

sockfd.setcloseonexec Method

function setcloseonexec()

Sets the close-on-exec flag. When forking a child (see systemfork) that child will usually have access to sockets created by its parent. Setting this flag will close the socket in that case. For gonuts, this basically can be considered a simple security issue for now.
No parameters, no return value.

sockfd.setbroadcast Method

function setbroadcast()

Allows sending broadcast packets through this socket. Usually used for SOCK_DGRAM (UDP) sockets. Recommended to do BEFORE binding to an address.
UDP sockets are not allowed to send to broadcast addresses for security reasons. To enable a socket to broadcast, you need to call this method on it.
No parameters, no return value.

sockfd.bind Method

funtion bind(address)

Binds a socket to an address. The address must be available on the host system.

INPUTS: address string address representation as described above
RETURNS: true on success, false on any error
THROWS: no

Note: You should prefer event instances (like socketlistener or bufferedevent) when it comes to TCP sockets.

sockfd.connect Method

funtion connect(address)

connects to a target address

INPUTS: address string address representation as described above
RETURNS: true on success, false on any error
THROWS: no

Note that this returns immediately, and a TCP stream may not already set up properly by the kernel. Will return true even when the host at the target address is not up, or if it is rejecting the connection.
For TCP sockets you really should prefer bufferedevent

sockfd.listen Method

function listen([backlog])

makes the socket listening for connections.

INPUTS: backlog integer, optional backlog size. When omitted, backlog is set to 0. See BSD socket documentation about backlogs.
RETURNS: true on success, false on any error
THROWS: no

you should have reasons to use this directly on a sockfd, you are recommended to use the socketlistener class if possible.

sockfd.accept Method

function accept()

Accepts an incoming connection, and waits for connections when none is available

INPUTS: none
RETURNS: null on any error, or a fresh sockfd instance holding the new connected socket
THROWS: may

Again, you should prefer using the socketlistener class and event system if possible, tt's much more effective and less programming involved.

sockfd.sendto Method

function sendto(data,addr)

send data to an address. This method is meant for use with UDP sockets, but will also work on SOCK_STREAM (TCP) sockets by ignoring addr.
When possible use event system instead (bufferedevent)

INPUTS:
data any buffer, sockbuf or blob instance, or a string
addr string target network address,
RETURNS: number of bytes sent, or -1 on any error
THROWS:: no

Note you can not limit the amount of bytes to send, the method always tries to send all of it. Also note, this method does not drain any sockbuf.

sockfd.recvfrom Method

function recvfrom([mtu])

gets data received on the socket. This is a costly call, for TCP you really should prefer using the event system. We cannot repeat this enough.

INPUTS: mtu integer, optional. Maximum size of data. Note for UDP this is PER PACKET, and this call may return back more than one packet from a single call

RETURNS:

THROWS: no

bufferedevent class

a bufferedevent instance is an event object combined with both input- and output-buffer of a stream (socket or file), streamlining event driven stream/socket communications
virtual prototype:

	class bufferedevent {
		constructor(evbase[,flags]);
		constructor(evbase,sfd[,flags]);
		function getinput();
		function getoutput();
		function enable(flags);
		function disable(flags);
		function connect(destination);
		function getfd() ;
		function write(data[,count]);
		function read([count]);
		function readsockbuf([addto]);
		function setreadcb(fn,arg);
		function setwritecb(fn,arg) ;
		function seterrorcb(fn,arg) ;
		function setcallbacks(readfn,writefn,errfn,arg[,argw,arge]);
		function settimeouts(read,write) ;
		
	}

bufferedevent global constants

constants for bitflags passed to event handlers:

(eventtype parameter of handlers)

constant bitflag meaning
EVENT_READING data available to read from socket/stream
EVENT_WRITING socket/stream ready to write data to
EVENT_ERROR socket/stream error
EVENT_TIMEOUT timer/timeout elapsed
EVENT_EOF streak end of file / socket closing
EVENT_CONNECTED socket connected, ready for data transfers

constants for bufferedevent options:

constant bitflag option meaning
BEV_CLOSE_ON_FREE flush and close stream/socket on bufferedevent instance destruction
BEV_THREADSAFE bufffer access will be thread safe. You may need this flag for future den modules, gonuts itself cannot pass bufferedevents or its buffers to foreign threads anyways.
BEV_DEFER when set, event handlers will be called deferred after all events were evaluated in a eventbase loop run. When not set, handlers will be called immediately while the loop is running
BEV_UNLOCK_CALLBACKS usually a mutex for an event is locked when calling an event handler, preventing access to its event instance or the loop. When set, the event system will unlock before calling the event handler

Use BEV_DEFER to solve synchronization issues regarding events and to control the order of handler calls in case of "parallel" events. Recommended to beginners: Easiest handling when always setting (BEV_CLOSE_ON_FREE | BEV_THREADSAFE | BEV_DEFER)

bufferedevent Constructors

bufferedevent(evbase)

create a bufferedevent instance, put it into the eventbase passed and activate it.
the bufferedevent instance is not connected to a socket or file stream

bufferedevent(evbase,flags)

create a bufferedevent instance, join the eventbase and pass option flags (see table above)
the bufferedevent instance is not connected to a socket or file stream

bufferedevent(evbase,sfd)

create a bufferedevent instance, connect it to the passed sockfd instance and join the given eventbase

bufferedevent(evbase,sfd,flags)

The most common constructor. Create a bufferedevent instance connected to sfd and join evbase

Constructors throwing exception on parameter mismatch

bufferedevent Methods

bufferedevent.getinput Method

getinput() ;

get the input buffer data from the source socket/stream will be readable from

INPUTS; none
RETURNS: a sockbuf instance being the input buffer of the stream/socket, or null when no data source connected
THROWS: no

Note bufferedevent also provides direct methods to read from this buffer without indirection

bufferedevent.getoutput Method

getoutput() ;

get the output buffer for writing to the sink socket/stream

INPUTS: none
RETURNS: a sockbuf instance being the output buffer of the stream/socket, or null when no data sink connected
THROWS: no

Note bufferedevent also provides direct methods to write to this buffer without indirection

bufferedevent.enable Method

function enable(flags)

activates event triggers for the callback handlers

INPUTS: flags integer bitflag, an ORed combination of EV_READ and/or EV_WRITE constants
RETURNS: integer 0 on success, -1 on error
THROWS: no

bufferedevent.disable Method

function disable(flags)

deactivates event triggers for the callback handlers

INPUTS: flags integer bitflag, an ORed combination of EV_READ and/or EV_WRITE constants
RETURNS: integer 0 on success, -1 on error
THROWS: no

bufferedevent.connect Method

function connect(address)

initiates a socket connection to a peer

INPUTS: address string address representation as described above (e.g. "127.0.0.1:1234" or the like)
RETURNS: true on success, false on error
THROWS: no

Note a return value of true indicates the initiation of a connection, not the success of the connection. When connection succeeds or fails, the event handler will be called with the respective EVENT_CONNECTED, EVENT_ERROR or EVENT_TIMEOUT flags

bufferedevent.getfd Method

function getfd() ;

returns the sockfd instance the bufferedevent is connected to.

INPUTS: none
RETURNS: a sockfd instance (in all cases!)
THROWS: no

note when the bufferedevent instance does not have a socket or stream, this method still will return a sockfd instance being an "empty" sockfd

bufferedevent.write Method

function write(data[,count])

writes data to the socket/stream (via the output buffer)

INPUTS:
data: any blob,buffer or sockbuf instance or a string
count: integer, optional. Number of bytes to write
RETURNS: the byte count actually written
THROWS: when data is a sockbuf and count is provided, or any other parameter error occurs

This is the preferred method of writing data to a socket
Note: Best performance when passing a sockbuf instance. Note a sockbuf passed will be drained accordingly

bufferedevent.read Method

function read([count])

reads data from the socket/stream input buffer

INPUTS: count integer, optional. Maximum number of bytes to read
RETURNS: a buffer instance, or null when no data is available
THROWS: no

will try to read all available data when omitting count.
Actual byte count read may be less than provided by count

bufferedevent.readsockbuf Method

function readsockbuf([add])

reads data from the socket/stream and return or add it to a sockbuf

INPUTS: add optional, a sockbuf instance to add the data read to
RETURNS: a sockbuf instance (when add is provided will be the same instance)
THROWS: no

the most performant way of reading data from a socket/stream

bufferedevent.setreadcb Method

function setreadcb(fn,arg)

sets the event handler to call on read events

INPUTS:
fn a function object of the event handler (see below) or null do disable the callback
arg any variable to pass to the handler as user argument
RETURNS: none
THROWS: no

bufferedevent.setwritecb Method

function setwritecb(fn,arg)

sets the event handler to call on write events (that is, when the socket or stream is ready to process output data)

INPUTS:
fn a function object of the event handler (see below) or null do disable the callback
arg any variable to pass to the handler as user argument
RETURNS: none
THROWS: no

bufferedevent.seterrorcb Method

function seterrorcb(fn,arg)

sets the event handler to call on other/error events (including outgoing TCP connection established)

INPUTS:
fn a function object of the event handler (see below) or null do disable the callback
arg any variable to pass to the handler as user argument
RETURNS: none
THROWS: no

bufferedevent.setcallbacks Method

function setcallbacks(readfn,writefn,errfn,arg[,argw,arge]);

sets all callback handlers at once

INPUTS:
readfn function object for read events or null do disable the callback
writefn function object for write events or null do disable the callback
errorfn function object for state/error events or null do disable the callback
arg any variable to pass as user argument to the read handler, or all handlers when argw and arge omitted
argw optional, any variable to pass to the write handler as user argument. When omitted, arg is used
arge optional, mandatory when argw is provided. Any user variable for the error handler. When omitted, arg is used
RETURNS: none
THROWS: on input parameter errors

note you may provide a single user argument for all three types of callbacks or three user arguments for each type of handler, but not two user arguments.

bufferedevent.settimeouts Method

function settimeouts(readto,writeto)

sets and activates or deactivates timeouts for reading and/or writing

INPUTS:
readto: integer, milliseconds read timeout, when 0 or negative deactivates read timeout events
writeto: integer, milliseconds write timeout, when 0 or negative deactivates write timeout events
RETURNS: none
THROWS: no

Read and Write event handler prototype

event handler functions for a read and/or write events of a bufferedevent must match this prototype:

function onReadOrWrite(bev,argument)  

where

note there are no flags, as bufferedevent will use different handler callbacks for reading and writing
Any return value of the handler function will be ignored
a simple tcp echo server would use such a handler:

function onRead(bev,arg) {
	local data=bev.read() ; //read all data available
	bev.write(data) ; //and write back to output
}

or, most performant:

function onRead(bev,arg) { bev.write(bev.readsockbuf()) ; }

A note on write event handlers: write events will be triggered when a socket or stream gets ready to send data, not when data is actually sent.

Error event handler prototype

an error event handler must follow this prototype:
function myerrorhandler(bev,state,argument)
where

Any return value of the handler function will be ignored
state has bits sets depending on the cause, matching the constants EVENT_READING, EVENT_WRITING, EVENT_CONNECTED, EVENT_EOF, EVENT_ERROR or EVENT_TIMEOUT, where the lower bits indcate further information (reading or writing) and the upper 4 bits usually match exactly ONE of connected, eof, error or timeout.
EVENT_ERROR is indicating any other error not listed, usually some socket error.
Usually, one one of the upper 4 bits is set and additionally none, one or both bits for reading and writing in teh lower bits is set to indicate the operation on wich the error indicated by one of the upper 4 bits.
Hence, you may check the error for example as following:

	function onError(bev,state,arg) {
		switch (state&0xf0)
		{
			case EVENT_CONNECTED:   //TCP socket connection established, do something
									break ;
			case EVENT_EOF:		 //peer terminated the connection (or end of file), do something else
									break ;
			case EVENT_TIMEOUT:	 if (!(state&0x0f)) { /*probably unable to connecto to peer*/ }
									if (state&EVENT_WRITING) { /*write timeout*/ }
									if (state&EVENT_READING) { /*read timeout*/ }	
									break ;
			default:				//any other error,  
									if (state&EVENT_WRITING) { /*occured when trying to write*/ }
									if (state&EVENT_READING) { /*occured on reading data*/ }	
									if (!(state&0x0f)) { /*spurious socket error*/ }
									break ; 
		}
	}

As you may note an "error" event is also triggered when a tcp connection is established after you called connect

socketlistener class

Setting up a socket to listening mode and operating “accept” on it, causing an event for each connection
virtual prototype:

	class socketlistener {
		constructor(evbase,addr_or_fd[,flags])
		function enable() ;
		function disable();
		function getfd();
		function isbound();
		function onaccept(fn[,arg]);
	}

socketlistener Global Constants

constant bitflag effect
SLI_BLOCKING_SOCKETS when set, all sockets accepted will be in blocking mode, otherwise nonblocking (default). Note a blocking socket will have massive adverse effects when further used in the event system
SLI_CLOSE_ON_FREE when set the listening socket will be freed when the instance is destroyed
SLI_CLOSE_ON_EXEC when set the listening socket will have the close-on-exec flag set(see sockfd.setcloseonexec)
SLI_REUSEABLE the listening socket will have SO_REUSEABLE set see sockfd.setreuseable), allowing faster re-binding to the same socket. Very useful when you're debugging and need to start over
SLI_THREADSAFE the socketlistener will be threadsafe. At the time of this writing it is unclear whether socketlistener instances can be passed to foreign threads,but if that's actually or will be possible in the future , you should set this flag to avoid hard crashes.

Beginners should always set (SLI_CLOSE_ON_FREE | SLI_CLOSE_ON_EXEC | SLI_REUSEABLE | SLI_THREADSAFE)

socketlistener Constructor

socketlistener(evbase,addr_or_fd[,flags])

create an activated socketlistener, assign it to en eventbase and activate it
where

evbase is the eventbase instance to assign. The socketlistener requires the event system for asynchroneously accepting incoming connections
addr_or_fd is either a network address string or a sockfd instance (see notes below) and
flags is an optional integer bitflag, ORed from the constants described above. When omitted defaults to SLI_CLOSE_ON_FREE|SLI_CLOSE_ON_EXEC|SLI_REUSEABLE|SLI_THREADSAFE

The socketlistener is automatically enabled.

Note the constructor will bind a socket when you pass a network address string (for example "0.0.0.0:80"), but in case you pass a sockfd instance you need to manually call bind on it (if possible BEFORE creating the socketlistener). Additionally the flags will not affect the sockfd instance and its socket in this case, so you will have to configure thease manually, too.

socketlistener Methods

socketlistener.enable Method

function enable() 

enables the socketlistener to accept new incoming connections. Note on construction, a socketlistener instance already is enabled.

socketlistener.disable Method

function disable()

disables the socketlistener, and it will not accept further incoming connections.

socketlistener.getfd Method

function getfd()

return a sockfd for the socket the listener acts on

INPUTS: none
RETURNS: a sockfd instance or null
THROWS: no

socketlistener.onaccept Method

function onaccept(fn[,arg])

sets the callback function for accepting incoming connections, including an optional user argument to pass

INPUTS:
fn the handler function, mandatory to be of prototype described below
arg optional, any object or variable to pass to the handler as user argument. defaults to null when omitted

soccetlistener accept handler prototype

function onAccept(listener,fd,peeraddr,arg)

where

listener is the socketlistener instance accepting an incoming connection,
fd is a sockfd instance of the newly created socket connected to the peer
peeraddr is a string holding the peer network address (and port) and
arg is the user defined argument

httpevent class

this class handles http connections.

HERE BE DRAGONS ::[TODO]::
virtual prototype:

	class httpevent {
		constructor( ...
		function setgencallback( ...
		function setcallback( ...
		function encode( ...
	}

httprequest class


Note: This class is not considered safe. Peers may abuse implementation flaws.
HERE BE DRAGONS ::[TODO]::
virtual prototype:

	class httprequest {
		constructor( ...
		function getURI();
		function getcommand();
		function gethost();
		function getpath( ...
		function getheaders( ...
		function addreplyheader( ...
		function addreply( ...
		function discardreply();
		function reply( ...
		function error( ...
		function cancel();
		function encode(string);
		function getinputstring( ...
		function getinputblob( ...
		function getinputarray( ...

	}

Cryptology (AES, ECC & Hashes)

Random class

The random class provides much more secure random number generation than the rand function included from Squirrels stdlib, which is required by many crypto actions.
However, it provides two different generators to gives the user a a speed-vs-security tradeoff choice when used manually (Cryptologic classes and functions will always use the more secure Yarrow generator though)

virtual prototype:

	class random {
		constructor() ;
		function seed(data) ;
		function number(upto);
		function yarrownumber(upto);
		function buffer(size);
		function yarrowbuffer(size);
	}

random Constructor

random() ;

no parameters. The constructor will seed both random generators automatically with some entropy (about 128 bytes, partly derived from system time)

random Methods

random.seed Method

function seed(data)

seeds both random generators with the provided data. Use to increase entropy. may be used any time, even recursively (that is, provide seed from the same or other random generators)

INPUTS: data any blob, buffer, sockbuf or string to seed from.
RETURNS: none
THROWS: no

random.number Method

function number(modulo)  

get a single random integer from the fast random generator

INPUTS: modulo integer, the modulo value.
RETURNS: a random integer in the range of 0 to modulo-1
TROWS: no

random.yarrownumber Method

function yarrownumber(modulo)  

get a single random integer from the Yarrow random generator

INPUTS: modulo integer, the modulo value.
RETURNS: a random integer in the range of 0 to modulo-1
TROWS: no

random.buffer Method

function buffer(size)  

gets a buffer of given size filled from the fast random generator

INPUTS: size integer, buffer size in bytes
RETURNS: a buffer instance of size size holding the random data
TROWS: no

random.yarrowbuffer Method

function yarrowbuffer(size)  

gets a buffer of given size filled from the Yarrow random generator

INPUTS: size integer, buffer size in bytes
RETURNS: a buffer instance of size size holding the random data
TROWS: no

Crypt class

Class providing ECC and AES operations
virtual prototype:

	class crypt {
		constructor();
		//ECC functionality
		function createECC(type,rnd);
		function getECCprivkey();
		function getECCpubkey();
		function setECCkey(key);
		function ECCdecrypt(enckeydata);
		function ECCencrypt(keydata);
		function ECCsignhash(hash,rnd);
		function ECCveryfysig(sig,hash);

		//AES functionality
		function setAESkey(key,iv);
		function getAESIV();
		function encrypt(data); //note: inline encryption, altering data!
		function decrypt(data); //note: inline decryption, altering data!
	}	

Global Constants

ECC112, ECC127, ECC160, ECC192, ECC224, ECC256, ECC384, ECC512 used for ECC key creation (see createECC)

crypt Constructor

crypt()

Dead simple. Just create, no parameters. No keys assigned

crypt Methods

crypt.createECC Method

function createECC(keysize,rnd)

create a new random ECC key pair you may read using getECCprivkey and getECCpubkey

INPUTS:
keysize integer defining the key size, pass any of above ECC112 to ECC512 constants
rnd a random instance the function will use for entropy
RETURNS: true when the key pair was created, false on error
THROWS: on input parameter errors

crypt.getECCprivkey Method

function getECCprivkey()

gets the current private ECC key (if any)

INPUTS: none
RETURNS: a buffer instance holding the key or null when no private ECC key is present
THROWS: on input parameter errors

crypt.getECCprivkey Method

function getECCprivkey()

gets the current public ECC key (if any)

INPUTS: none
RETURNS: a buffer instance holding the key or null when no public ECC key is present
THROWS: on input parameter errors

crypt.setECCkey Method

function setECCkey(key)

sets the ecc private and public or just public key

INPUTS: key a buffer instance holding either private or public key. Note a private key always also contains the corresponding public key!
RETURNS: true when the key(s) was/were set, false when any error occured (e.g. key did not contain valid key data)
THROWS: on input parameter errors

crypt.ECCdecrypt Method

function ECCdecrypt(data)

decrypts a key or hash (for example an aes key) encrypted using ECCencrypt, using the current private key
ECCEncryption is NOT meant to encrypt any data, but rather other keys, hashes or initialization vectors.

INPUTS: data a buffer instance holding encrypted data to decrypt
RETURNS: a buffer instance holdeing decrypted data or null on error
THROWS: on input parameter error

crypt.ECCencrypt Method

function ECCencrypt(data)

encrypts a key or hash (for example an aes key) encrypted using ECCencrypt, using the current public ECC key. Only holders of the corresponding private key may decrypt the data.
ECC encryption is not suitable for encryption of any data, but rather to encrypt other keys, hashes or initialization vectors.

INPUTS: data a buffer instance holding the binary data to encrypt, usually an AES key, a hash or the like.
RETURNS: a buffer instance holding the ECC encrypted data or null on error
THROWS: on input parameter error

crypt.ECCsignhash Method

function ECCsignhash(hash,rnd)

signs a hash (or key) using the current private ECC key

INPUTS:
hash a buffer instance holding the hash to sign
rnd a random instance the function derives necessary entropy from
RETURNS: a buffer instance holding the ECC signature for the provided hash
THROWS: on input parameter error

crypt.ECCveryfysig Method

function ECCveryfysig(sig,hash);

checks a signature created by ECCsignhash for validity against a given hash using the current public ECC key, veryfying the hash and signature match and the signature was created using the proper private key.

INPUTS:
sig a buffer instance holding the signature as created by ECCsignhash
hash a buffer instance holding the hash that was signed
RETURNS: integer 0 when hash, signature and key match, integer 1 when they do not match or -1 in case of any error
THROWS: on input parameter error

crypt.setAESkey Method

function setAESkey(key,iv)

sets an AES key and initialization vector.

INPUTS:
key a buffer instance holding the AES key to set or null to not set a new key. Minimum size 16 bytes
iv a buffer instance holding the initialization vector to set, or null to not set a vector. when provided, vector size must match key size
RETURNS: true on success, false on any error (usually key size mismatch)
THROWS: on input parameter mismatch
Important note: only 16,24 or 32 bytes data sizes supported for key and iv, any excess bytes will not be taken into account. The iv must be at least of the same size as key.

crypt.getAESIV Method

function getAESIV()

returns the current IV state. encrypt and decrypt will change the iv, so this function does not literally return the "initialization" vector, but the current crypt vector state

INPUTS: none
RETURNS: a buffer instance holding the current vector state between any encryption or decryption step
THROWS no

crypt.encrypt Method

function encrypt(data)

performs an AES encryption on data using the current AES key and IV. Progresses IV state internally to provide chaining capabilitie

INPUTS: data any buffer, blob or sockbuf instance or string to encrypt
RETURNS: null on error, otherwise the input object
THROWS: when no AES key is set, parameter errors

Note this function encrypts in place, the input buffer data is altered!
(including any passed string. It is important to know that a null character at any position may occur and cause inadvertent string termination to some functions the string is applied to later)

crypt.encrypt Method

function decrypt(data)

performs an AES decryption on data using the current AES key and IV. Progresses IV state internally to provide chaining capabilitie

INPUTS: data any buffer, blob or sockbuf instance or string to encrypt
RETURNS: null on error, otherwise the input object
THROWS: when no AES key is set or on parameter errors

Note this function decrypts in place, the input buffer data is altered!
(including any passed string. It is important to know that a null character at any position may occur and cause inadvertent string termination to some functions the string is applied to later).

Hashstate class

while the hash function (see below) is easy and convenient to use for single blocks of data, you may encounter situations where you want to hash data chunks one by one for a single hash.
This class allows you to process any sequential data in arbitrary steps.
virtual prototype:

class hashstate {
	constructor(algo);
	function process(data);
	function done();
}

Hashstate Constructor

hashstate(algo)

create a hashstate instance for the given hash type, where

algo is a string identifying the hash function to use. Note it does NOT support the "integer" hash type and will throw an exception when the string parameter does not match any of the other standard hash types as set out in the table below (supported hash types).

hashstate.process Method

function process(data)

continue processing input data

INPUTS: data any blob, buffer, sockbuf or string input
RETURNS: none
THROWS: on input parameter error

hashstate.done Method

function done()

end processing and return the hash object resulting from all preceding process operations. Resets the state, subsequent process operation will be input to a new hash

INPUTS: none
RETURNS: a buffer instance holding the hash
THROWS: no

hash function

function hash(data,algo)

calculates a hash of data using the provided algorithm

INPUTS:
data any blob, buffer, sockbuf instance or string to build the hash for
algo a string indicating the hash algorithm (see below)
RETURNS: type depends on hash algorithm, most hashes return a buffer instance.
THROWS: no

Note: in current gonuts, when the indicated hash algorithm is not available or mistyped, the hash algorithm defaults to "integer" as a fallback and the function returns an integer hash.

Supported hash types

These hash types are currently supported by gonuts:

"sha512" (recommended for encryption usage)
"sha384"
"sha256"
"sha224"
"sha1" (do not use for encryption)
"md5" (do not use for encryption)
"whirlpool"
"rmd128" (RIPEMD)
"rmd320" (RIPEMD)
and
"integer", an ultra fast hashing algorithm returning an integer hash (64 or 32 bit, depending on platform), optimized to hash strings. It significantly (but linearly) loses precision for every 32 bytes of input data. Not available to the hashstate class

sha256 function

sha256(buf) is simply a convenience shortcut for Hash(buf,”sha256”)

PKCS5 function

function PKCS5(passw,salt[,hash[,iterations]])

performs a PBKDF2 operation to derive a cryptographic key or IV from a password, a salt and a hash.

INPUTS:
passw a string, buffer, sockbuf or blob defining the password
salt a string, buffer, sockbuf or blob defining the salt
hash string, optional hash type (see table above), defaults to sha256 when omitted
iterations integer, optional number of iterations, defaults to 5000
RETURNS: a buffer holding the generated key
THROWS: on any error

As it's performing PKCS#5 as PBKDF2, the output may longer than the hash type output, and the salt is of any size (where salts below 8 bytes are not considered safe against rainbow table attacks)
The number of iterations, put simpliflied, defines the overall security and is meant to adjust to increasing computational power over time. See https://en.wikipedia.org/wiki/PBKDF2 for more details.

HMAC class

Creates an HMAC from a key and data using specified hash algorithm
Attention: You can set the key ONCE in constructor, and when calling done() the key will change to the calculated HMAC while the hash is reset. This means, for he current HMAC instance calling done() is similar to creating a new instance with the result of the last as its key, similar to hmacinstance=HMAC(algo,hmacinstance.done()). This is very useful for concatenations like for example Amazons AWS APIs / SP-API requires. However, you cannot change the key on an instance manually after creation. To do so, create a new instance (and throw away the old one if no longer needed)

virtual prototype:

class HMAC {
	constructor(hashalgo,key);
	function process(data);
	function done();
}

HMAC Constructor

HMAC(hashalgo,key)

create a HMAC instance for the given hash type and key, where

hashalgo: a string identifying the hash function to use. See hashstate class or hash function. Note it does NOT support the "integer" hash type and will throw an exception when the string parameter does not match any of the other standard hash types as set out in the table below (supported hash types).
key: string, buffer, blob or evbuffer holding the key for HMAC creation

HMAC.process Method

function process(data)

feed input data (chunks)

INPUTS: data: any blob, buffer, sockbuf or string input
RETURNS: none
THROWS: on input parameter error

HMAC.done Method

function done()

end processing and return the HMAC resulting from the key and all preceding process operations. Resets the state, subsequent process operation will be input to a new HMAC, where it's is the HMAC just returned (for concatenation). See remarks above

INPUTS: none
RETURNS: a buffer instance holding the hash
THROWS: no

Multithreading

Squirrel has implemented threads in a fully cooperative way, allowing you to create a thread, where the thread can suspend itself and you need to resume it manually. Those built-in threads basically represent a separate stack, operating on the same root table.
However, they’re no real threads in terms of CPU/Operating system threads, but rather provide functionality for generators (see Squirrel language documentation about generators)
Gonuts introduces an additional “Real thread” mechanism, allowing you to leverage the full power of multitasking.
Usually based on pthreads, real threads represent a totally independent Squirrel context (completely separated memory, root table, stack and state).
To exchange data between real threads you will need the rtsync class providing the one and only mean to exchange data and interact (unless you want to use sockets for that, see below).
This mechanism can not interoperate between different gonuts processes, to have different gonuts processes communicate you will need to use localhost sockets (or when spawning a gonuts child you may use pipes as well)

osyield function

function osyield()

Yields the current “real” thread (preemptive multitasking), giving control back to the OS, which then usually immediately schedules any thread it deems viable. Do not confuse with Squirrels' yield keyword

realthread class

Creates an OS thread and absolutely separate context (including memory) to load a nut/cnut and run its threadmain function.
Creaton and starting the thread is a single action performed upon instanciation.

Virtual prototype:

	class realthread {
		constructor(script[,prio][,...]) ;
		
	}

realthread Constructor

Create and start a new thread
realthread(script[,prio][,...]) ;

Parameters:
script - string. A script name/filename as described for script.require.
prio - integer, optional. Thread priority, clamped from -2 to 2. Default is 0. Lower values are lower priority.
... - any number of arguments to pass to the thread. Arguments must be intrinsic primitive or strings, the only allowed class instance as an argument is an RTSync instance. See below for the threads main function prototype and how parameters will be passed.

Notes:

Experimental alternative construction

script may also be a function object instead of a string. The thread then won't load a script and execute its threadmain, but simply will execute the passed function. When the function returns, the thread is terminated.
When the calling thread terminates immediately after creating the new thread, there is a probability for a hard crash terminating the gonuts process.

realthread Methods

realthread.ThreadID method

function threadID();

returns the (yet pretty much useless) thread ID

INPUTS: none
RETURNS: integer thread ID
THROWS: when parameters passed only

realthread.Running method

returns whether the thread is running or terminated
function running();

INPUTS: none
RETURNS: bool (false=thread is terminated)
THROWS: when parameters passed only

realthread.Join method

infinitely waits for a thread to terminate
function join();

INPUTS: none
RETURNS: none
THROWS: when parameters passed only

to be exact, it waits for the thread to not run. Hence immediately returns when the thread already terminated.
Note that this method will not cause the thread to terminate, user has to provide thread termination mechanisms separately. This function simply will block as long as the thread is running.

The thread entry function

The script loaded and executed in the newly created has to define an entry point:
function threadmain(params)

INPUTS: param array, where each element is an argument taken from the arguments passed to the RealThread command that started the current thread.
RETURNS: any return value will be discarded. Thread terminates upon return

rtsync class

A class to create synch objects for communication between RThreads.
This is the one and only object type in gonuts referencing an internal memory object accessible for different threads and handles signalling, locking and inter-thread data transfers.
Data transfer is somewhat limited but still versatile, and can be performed both using indexes or FIFO pipelines.
Note all data transfers involve internal data copies and mutex accesses (spin locking allowed).
Also note not all class instance types can be transferred, only cloneable instances can be transferred.
Most important though, you may safely transfer a buffer or sockfd instance.
At the time of this writing it is not clear wether a sockbuf or bufferedevent can be transferred - however, in case that is actually possible or become possible in the future, you MUST take manual multithreading precautions (utilize BEV_THREADSAFE flag for bufferedevents, for example, and the enablelocking', lock and unlock Methods of sockbuf instances, or utilise rtsync.lock, trylock and unlock manually to protect them against concurrent access from several threads)

All data copying will happen when data is read.
When a thread shuts down, all squirrel objects in any RTSync object will be set to null unless they're intrinsic primitives (e.g.integer, float, bool, but not including strings in this case!).
Users should regard any subsequent read of such data in another thread hence will be null.

Also note, on Win32 the signalling mechanism may produce weird results when several threads are listening to the same signal. We therefore recommend to use RTSync objects in a thread-to-thread manner and not for broadcasting, though gonuts widely mitigates any such issues arising from Windows' WaitForSingleObject implementation.

Important note:
When you registered a signal event using setsignalevent the registered event will not survive the case that no thread references the channel (= no VM has an rtsync object for the channel). Though it is convenient to be able to "summon" and discard an rtsync at will, all of its data will be lost when noone currently "holds" an rtsync object for that channel. Hence, when at least one thread holds a permanent reference, then for other threads it seems like magically its event, slots, pipe and and signal state persist beyond the lifetime of an rtsync Squirrel instance.

virtual prototype:

	class rtsync {
		constructor(name) ;
		function getname() ;
		function cleanup() ;

			//indexed transfers
		function setvar(idx,obj) ;
		function getvar(idx,obj) ;
		
			//FIFO transfers
		function push(obj,int) ;
		function pop() ;
		
			//signalling
		function setsignalevent(eventobj, arg);
		function signal() ;
		function wait(ms) ;

			//mutex functionality
		function lock() ;
		function trylock() ;
		function unlock() ;

rtsync Constructor

rtsync(name)

Create an rtsync instance in squirrel for a channel identified by name (which must be a string). When creating, the instance will either create or refer an already existing rtsync of the same name, depending whether an instance already exists for that very name. Note name is case sensitive, exact match is required. You may define as many channels as you like, and there are no predefined channels.

rtsync Methods

rtsync.getname Method

function getname()

returns the channel name of the instance

INPUTS: none
RETURNS: string, sync channel identifier (name)
THROWS: no

rtsync.cleanup Method

function cleanup

performs a garbage collection, freeing all memory still allocated by objects that are not accessible anymore.
Note that setvar, getvar, push and pop also internally perform a cleanup, as a VM shutdown (Thread termination) will.

INPUTS: none
RETURNS: none
THROWS: no
You won't need this function unless you want to avoid too much excess data is piling up in certain situations, slowing down any data transfer causing method.

rtsync.setvar Method

function setvar(idx,obj)

stores a value or object in a specified channel slot. Slots may be accessed by all threads (provided they have instanciated an rtsync for that channel name)

INPUTS:
idx: either an integer index or a string (for a named slot) indicating the slot to use
obj: Any primitive value (integer, float, bool, null), string, table, array or gonuts instance, esp. buffer or sockfd.
ATTENTION obj must not include circular references, or a hard crash definitely WILL happen

rtsync.getvar Method

function getvar(idx)

retrieves a value or object from the specified channel slot. This might be a costly operation not only involving mutexing, but also cloning especially for large buffer objects, tables and arrays.
The content of the slot is read, but not changed.

INPUTS:
idx: either an integer index or a string (for a named slot) indicating the slot to use
RETURNS: the stored object or value, or null when the slot does not exist. Note you cannot tell the difference from a slot actually storing null or not present.
THROWS: no

Note: To be exact about nonexisting slots, getvar will indeed CREATE a null object in an unused slots, which effectively uses up some small amount of memory.

rtsync.push Method

function push(int,obj)

Enqueues a pair of an integer value and a Squirrel object (or primitive) on the channel FIFO

INPUTS:
int integer, meant as the type of entry. If possible do not use 0 or negative numbers, which are dedicated to pxlib.pnut functionalities
obj Any primitive value (
integer, float, bool, null), string, table, array or gonuts instance, esp. buffer and sockfd.
RETURNS: none
THROWS: on wrong input parameters

ATTENTION obj must not include circular references, or a hard crash definitely WILL happen

the integer value is for the receiving thread to distinguish different types of obj interpretation.Anyways, rtsync does not care about any interpretation, it simply provides a FIFO queue to pass pairs to other threads (or even the same)

rtsync.pop Method

function pop()

Tries to pop a integer-object pair from the channels' FIFO queue.

INPUTS: none
RETURNS: false when there is nothing to pop, or a table containing two entries, keyed in slots "t" holding the integer value of the pair and "o" holding a deep clone of the obj of the pair.
THROWS: no

rtsync.setsignalevent Method

function setsignalevent(eventobj)

disables or sets an event instance to trigger when the channel is signalled (see below)

INPUTS: eventobj either null to disable or an event instance to fire on receiving a channel signal
RETURNS: none
THROWS: no

rtsync.signal Method

function signal()

signals the rtsync, waking up threads waiting for a signal on the same channel, and fire/trigger all events in all channels linked to the channel via setsignalevent in their respective thread
Note on win32 the wait mechanism is somewhat limited and may show odd behaviour.

INPUTS: none
RETURNS: none
THROWS: no

rtsync.wait Method

function wait(ms)

waits for a signal on the sync channel. Premature return may occur, check return value

INPUTS: ms maximum time in millisecond to wait. infinite when negative
RETURNS: false on a spurious wakeup, true for ONE thread waiting when this channel was signalled
THROWS: no

Note that wait will also return true when the channel was signalled before calling this method, however such a stored signal will not abort waiting time. So be careful (you may want to call passing 0ms first to check for any "premature" signals first)
Remember on win32 the signal/wait mechanism is somewhat limited and may show odd behaviour, like waking up only SOME threads.
For that very reason we recommend using this mechanism on a "thread-to-thread" basis to avoid any such platform differences. When only two threads involved (one waiting, one signalling) all platforms will deliver the expected results.
However, wait entsures in case several threads are waiting on the same channel only one single thread gets the return value of true.
Note that this is not true for signal events, which are triggered for all threads having registered an event for the channel. So when you use rtsync to receive for example a global signal (like a shutdown signal) you should catch the signal using an event, while in case you need to distribute workload on worker threads you should use something along while (!syncobj.wait(-1)){}; to ensure only one worker thread wakes.
Passing zero will simply clear the signal flags and check wether the calling thread is the one and only meant to wake up, without any delays involved (for use in event handlers, to check wether to take action or not, for example).

below ##### HERE BE DRAGONS - :: TODO :: - #####

The documentation below this point is to be considered work in progress and surely is inaccurate and incomplete. However, all functionality indicated is implemented and proven to work.

PX Protocol

Protocol conventions

The PXProtocol is highly versatile. Each Packet has a single “token”(Identifier) and zero to literally unlimited data blocks of several types and again literally unlimited size, while having nearly no overhead. It can be used over any line, be it I2C, packet driven layers like CAN or UDP or within any stream, e.g. TCP. Ultimately, it allows for CPU-less dedicated network or endpoint hardware devices (using latches, shifters and comparators).
However, as it is highly (mis-)configurable and proprietary the PXProtocol class is not documented here directly. pxlib.pnut offers an API to use the protocol.

Tokens

The following table shows mandatory token usages and restrictions when using one of the default configurations schemes.
Token(s) Usage/Restriction
0 to 15 Reserved for internal protocol use (private/peer use)
16-8191 registered protocols (#1) (public + private)
8192-16383 Publicly free for applications (#2) (private, public with special care)
16384-32767 Reserved for internal protocol extensions (public use)

(#1) Registered protocols have predefined public functionality, for example ping, file transfer or RPC.
Note: not mandatory to support them.
(#2) When using them in public networks or when interoperating with foreign party peers you need to provide additional measures to mitigate unmet expectations, for example by using the logon/application id.
Application identifiers should be registered with us to avoid coincidental matches. This is mandatory for these types of identifiers:
• Positive 64 bit integer values (MSB not set)
• Positive 32 bit integer values (MSB not set)
• 16 bit integer values < 32768 (0x7FFFF and below)
• strings that do not begin with “VOID” or “A”
• 8 bit values below 240 (note: functional grouping applies)
You may use the following identifiers without registration, but risking coincidental matches and hence you need to provide additional measures to mitigate unmet expectations about received and sent protocols. Note: You will be unable to interoperate with registered applications.
• Negative 64bit integer values
• Negative 32bit integer values
• Strings starting with “A”
For development purposes you may use any 8 bit value from 240 to 249 or any string starting with “VOID” as long as you ensure there is no connection/interoperation with production systems, especially 3rd party ones and when using 8bit identifiers (which, by the way, are dedicated to busses like I2C).

marker class

…Besides buffer this is the only class that can be serialized natively or sent through pxprotocol in Squirrel Object Mode. As the name indicates, it is a marker only with the simple functionality to just exist.

pxprotocol class

use pxlib.nut to access the protocol

Protocol configuration

use pxlib.nut to configure the protocol

Using the Protocol class in “Squirrel Object Mode”

XML

Classes to read, create and process XML files
Note: Due to the complex nature and long method names, naming conventions deliberately differ on capitalization.
However, pxlib.pnut provides far less complex accessibility to XML files by mapping them to Squirrel tables.
You may want to use the library and have a look at its doc first, unless you need to handle specialized functionality not supported by the pnut library.

Most classes are inherited from CMLNode and hence share its methods

XMLNode class

The general node class most XML classes inherit from

XMLDocument class

Extends SQXMLNode
Represents an XML Document

XMLAttribute class

This is an independent class NOT extending a node.
It holds a single attribute of an element

XMLElement class

extends SQXMLNode

XMLText class

extends SQXMLNode

XMLDeclaration class

extends SQXMLNode

XMLComment class

extends SQXMLNode

XMLUnknown class

extends SQXMLNode

Global Constants

XML_ELEMENT, XML_UNKNOWN, XML_COMMENT, XML_TEXT, XML_DECLARATION, XML_DOCUMENT
Data Compression (inflate&deflate)

Systemtools.pnut

Utilities for gonuts installations. gonuts has no need for installation, but when it is these utilities can be used for automation of include paths and overall installation environment handling.
Doc: TODO

The pxlib.pnut Library

Additional convenience classes and functions optionally can be loaded at runtime from the pxlib.pnut archive by manually adding the archive and loading the “pxp” script from it.

General toolset

WIP - still lots of documentation work to do...
...

function base32encode(input)
function base32decode(input)
function FindSquirrelFunction(path,start=null)
function IterateSquirrelPath(path,create=true,start=null)
function CopyFile(sourcefilepath,targetfilepath,chunksize=1048576)
function strreplace(source,what,by)
function FixPath(input,asfolder=false)
function GetFilePath(inputpath)
function GetFileName(inputpath)
function GetFileExtension(inputpath)
function StripExtension(inputpath)
function Serialize(obj)
function DeSerialize(inpstring)
function wiperoottable()
function findadirectory(searchpath,dirspec,recursive=false)
function findafile(searchpath,filespec,recursive=false)
function GetAllFiles(searchpath,filespec,recursive=false)
function FileHash(filepath,chunksize=65536)
function MergeTables(destination,source,except=null)
function deepclone(obj)
function Sleep(ms,loop=null,loopms=100)
function ReadCSV(filepath,linesep="\n",columnsep=";",stringdelimiter="\"",headerline=false)

XML toolset

function generic(data,parent) ; 
function XML2SQ(node,generic=1) ;
function Document(rootelement) ;
function WriteXML(xmlin,filepathout) ;

JSON tools

function readjson(string_input)
function tojson(elem,indent="",cr="\n") 

Archive management, auxiliary script handling

	class pnutarchive {
		constructor(filename);
		function rebuildindex();
		function addnutfile(filepath,encrypt=false,compress=2047,nameinarchive=null)
		function pxloadfile(name,debug=false)
		function pxexecfile(name,debug=false)
	}	

Inter-Thread and Inter-Host communication toolset

Default application event loops

...

	class ThreadLoop {
		constructor();
		function run();
		eventloop=null ; //the eventbase object
	}

	class AppMainLoop extends ThreadLoop {}

Networking toolset

Remote Code Procedure toolset

...

file transfer toolset

...

Standard dens (import modules)

gonuts comes with some standard modules to import. Note that when gonuts is installed, these modules can be automatically loaded using the systemtools (see above)

Documentation for dens is separated and not covered in detail here.
Available standard dens:
denguuid - create GUUIDs using a common algorithm (replaces built-in GUUID function)
densqlite - sqlite3 support
denserial - direct serial device support (without using files)
densqratthread - cooperative pseudo-threading support
denlfiles - large files support (for 32bit systems,but also 64bit compatible for common API)

and for linux systems only:
dendbi - libdbi support, currently tested for mysql, postgresql (and sqlite).