13.1 C-scripts
13.1.1 Introduction
If REBOL and batch file script engines
aren't enough fast for you, you can use the C-scripts. They aren't based on a
script engines because they are real C programs that are compiled on-the-fly and
converted in machine code. Thanks to the powerful Tiny C compiler, this step is
so fast that the user thinks to use scripts executed by an interpreter
instead of source codes built by a compiler. The C-scripts are executed
inside the VEGA ZZ environment allowing to access to the same resources used by
the master software. This approach allows to obtain extreme performances, but it
have some risks related to the master program (VEGA ZZ) stability. For this
reason, the C-scripts are executed inside an exception-trapping box that
protects the VEGA ZZ main core from illegal memory accesses.
The C compiler supports the ANSI C, the ISO C99 standard and many GNU C
extensions including inline assembly. For more information, see the Tiny
C reference documentation.
13.1.2 Machine code generation
VEGA ZZ calls Tiny C compiler to build the C source code in a dynamic link library and if an error occurs, the compiling procedure is stopped showing a message in the console. The resulting link library, called VEGA Link Library (VLL), is loaded, linked to the main VEGA process and at this step only, is executed calling the entry point using a separate thread. The main process waits the end of the execution but if the C-script performs an illegal operation, it's halted and an error message is shown. When the script is halted or it's normally terminated, the main process releases all resources. VEGA ZZ can run more then one C-script in the same time in the same environment.
13.1.3 Script management
PowerNet
plug-in has the job to manage the C-scripts, allowing to create, to delete,
to edit, to rename and to run them as the batch and REBOL files. Selecting
File
Run script in main menu,
you can perform all above
operations. When you want create a new C-script, right-clicking the Select script window and selecting New
C-script, two multiple templates are available. New templates can be added
coping them to ...\VEGA ZZ\Scripts\_Templates directory.
13.1.4 How to create a C-script
The C-script creation is very easy: you can use the tools built-in in VEGA ZZ or an external text editor. Remember to place the script in the Scripts directory (or in its subdirectories). If you want to use template scripts, you can follow these steps:
Open the script selection window (File
Run script).
Explore the directory tree in order to find the preferred place in which to put the script.
Click a directory by the right mouse
button and select New
C script
Template name
(e.g. Standard). New.c file is created.
Rename it, clicking on it by the right mouse button and selecting Rename (e.g. my_script.c).
Edit it by the built-in mini editor, using the context menu and selecting Edit.
The standard C-script code is the following:
/******************************************* **** VEGA ZZ C Script **** **** Standard template **** **** (c) 2005-2023, Alessandro Pedretti **** *******************************************/
#define VGVLL #include <vega.h>
int VllMain(VGP_VEGAINFO *VegaInfo) {
/**** Put here your code ***/
return 0; }
A C script or a VLL must always include the vega.h header defining the VGVLL symbol. The header contains the prototypes of the functions callable inside the script. The C-script entry point is defined by the VllMain() function and without it the script can't be linked. The VllMain() function should return a non-zero value if an error occurs, otherwise zero if no error is found. This function receives the address of the VGP_VEGAINFO structure defined in vgplugin.h header:
typedef struct { HD_UWORD Version; /* VEGA version */ HD_UWORD Release; /* VEGA release */ HD_ULONG * GlobErr; /* Pointer to global error variable */ HD_CHAR * ErrStr; /* Pointer to error string */ HD_ATOM ** BegAtm; /* Pointer to the pointer of the atom list */ HD_ATOM ** LastAtm; /* Pointer to the pointer to the last atom */ HD_ULONG * TotalAtm; /* Pointer to the number of atoms variable */ HD_LIST ** SrfList; /* Pointer to the pointer of the surface */ /* list defined by HD_LIST in hyperdrive.h */ HD_CHAR * Result; /* Pointer to the result string */ HD_VOID * AppHandle; /* Application handle */ HWND ComPort; /* Communication port */ HD_VOID * Res1; /* Reserved pointer */ HDC hDC; /* Device context */ HGLRC hRC; /* Rendering context */ HMENU hMenu; /* Handle of the main menu */ HMENU hPopUpMenu; /* Handle of the popup menu */ HWND hWnd; /* Handle of the main window */ HD_CHAR IniFile[MAX_PATH]; /* Plugin .ini file with full path */ HD_CHAR PrgPath[MAX_PATH]; /* Program path \ terminated */ /**** Super API ****/ HD_VOID (*VegaCmd)(const HD_CHAR *); /* Send a command */ HD_VOID (*Free)(HD_VOID *); /* Free the memory */ HD_VOID * (*Malloc)(HD_ULONG); /* Alloc the memory */ HD_ULONG (*ChoosePixelFormat)(HD_VOID *Dc, HD_LONG *PixelFormat, HD_LONG Multisample, HD_LONG Stereo, HD_LONG RbgBits); /* Choose the pixel format */ HD_VOID * (*AW_InitAlphaWin)(HWND); /* Initialize the alpha blend */ HD_VOID (*AW_FadeOut)(HWND); /* Fade out the window */ HD_VOID (*WaitCalc)(HD_VOID); /* Wait the calculation end */ HD_VOID (*UndoDisable)(HD_BOOL); /* Enable/disable the undo */ HD_BOOL (*UndoPop)(HD_BOOL); /* Pop the redo/undo object */ HD_BOOL (*UndoPush)(HD_LONG, const HD_CHAR *); /* Push the undo object */ HD_BOOL (*GetProcAddresses)(HD_VOID **, HD_CHAR *, int, ... ); /* Load a DLL dynamically */ HD_VOID (*RegisterForm)(const HD_CHAR *Name, HD_VOID **Form, HD_VOID (*ShowFunc)(int)); /* Register the VCL form */ HD_VOID (*UnRegisterForm)(HD_VOID **Form); /* Unregister the VCL form */ #ifdef __HDRIVE_H HD_LONG (*VegaCmdThs)(HD_STRING Result, const HD_CHAR *Cmd); /* VageCmd() thread safe */ #endif } VGP_VEGAINFO;
The Super API section could be expanded in the next releases and it allows to access directly to the VEGA ZZ functions. The C-script must read only this structure (write operations aren't allowed).
The C scripts are linked to the startup code (see Tcc\src\Vgcrt2 and Tcc\Lib directories) including the functions to control the extended commands. They can used as in the REBOL scripts and in the batch files, but they must be called using the C wrapper:
13.1.5 Functions for C-scripts
Here are the functions that are provided to implement the communication between the C-Script and VEGA ZZ. Their code is automatically linked on-the-fly by TCC compiler.
HD_LONG VegaCmd(const HD_CHAR
*Com)
Send an extended command to VEGA ZZ main process and wait the execution end. The
function returns the error code (0 if no error occurs)
and the command output, if available, is copied in the Result character
pointer of the VGP_VEGAINFO structure.
Example:
char CurPath[256];
VegaCmd("Get CurDir"); // Send the Get command to VEGA ZZ strcpy(CurPath, VegaInfo -> Result); // Copy the result in the user defined variable
The function returns 0 if no error occurs, or an error code greater than zero if it fails (click here for a complete list of error codes). This function is dirty and deprecated, because is not thread-safe. It's maintained only for compatibility with the old scripts.
HD_LONG VegaCmdEx(const HD_CHAR
*Com, ...)
This is the extended version of the VegaCmd()
function. It accepts the format specifiers as printf() standard
function combining a series of arguments.
Example:
VegaCmdEx("GraphAdd %d %f", Item, Value);
Also this function is dirty and deprecated, because is not thread-safe. It's maintained only for compatibility with the old scripts.
HD_LONG VegaCmdSafe(HD_STRING Result, const HD_CHAR *Com, ...)
Send a command to VEGA ZZ and copy the results to HyperDrive Result
string. This function is thread safe and if you don't need to retrieve the
output of the command, Result can be a NULL pointer.
Example:
HD_STRING Result = HD_StrNew(); HD_ULONG Atoms;
VegaCmdSafe(Result, "Get TotAtm"); // Send the Get command to VEGA ZZ Atoms = HD_Str2Uint(Result); // Convert it from character to an unsigned integer
HD_BOOL VegaIsCalc(HD_VOID)
This command is useful to check if VEGA ZZ is busy because is already running a calculation (e.g. AMMP, NAMD, MOPAC calculations). It returns 1 or 0 if a calculation is running or not.
Example:
if (VegaIsCalc()) { VegaPrint("ERROR: VEGA ZZ is already busy\n"); return 0; }
HD_BOOL VegaLoadMem(HD_VOID *MemPtr, HD_ULONG Size, HD_LONG Flags)
By this function, you can load a molecule directly from memory. You must specify the pointer to the memory section including the molecule (MemPtr), its size (Size) and the optional flags (Flags). At this time, only two type of flags are supported:
VG_LOADMEM_NONE
None flag.
VG_LOADMEM_SILENT
doesn't show any message in the console window.
If the function succeeds, a non-zero value is returned.
HD_VOID VegaPrint(const HD_CHAR *Fmt, ...)
This function print a message to the VEGA ZZ console by using the same formatting rules implemented in printf() C statement. It adds also the %a qualifier to print directly the value of a HD_STRING.
Example:
HD_STRING Result = HD_StrNew();
VegaCmdSafe(Result, "Get WksCurBame"); VegaPrint("Name of the current workspace: %a\n", Result); HD_StrFree(Result);
13.1.6 Macros
vega.h includes several macros to help you in programming the scripts:
Macro | Description |
VegaFirstAtom | gives you the pointer of the first atom in the list used by VEGA to manage the molecule in the current workspace. |
VegaIsEmpty() | checks if there is a molecule in the current workspace. It returns a non-zero value if the current workspace is empty. |
VegaLastAtom | gives you the pointer of the last atom in the list used by VEGA to manage the molecule in the current workspace. |
VegaTotAtom | returns the number of atoms of the molecule in the current workspace. |
VegaWaitCalc() | waits the current calculation until it ends. |
A C-script can read and write directly the atoms: please take care because no check are done if wrong data are inserted in the atom list. This is an example:
#include <stdio.h>
#define VGVLL #include <vega.h>
/**** Write the X, Y, Z coordinates of each atom ****/
int VllMain(VGP_VEGAINFO *VegaInfo) { HD_ATOMO * Atm; FILE * FH;
/**** Check if a molecule is loaded ****/
if (VegaIsEmpty()) return 0;
/**** Show a message in the console ****/
VegaPrint("* Saving the XYZ coordinates\n");
/**** Open the output file ****/
if ((FH = fopen("C:\\xyz.txt", "w")) == NULL) return 0;
/**** Atom loop ****/
for(Atm = VegaFirstAtom; Atm; Atm = Atm -> Ptr) { if (fprintf(FH, "%f %f %f\n", Atm -> x, Atm -> y, Atm -> z) <= 0) { VegaPrint("ERROR: Can't write the file\n"); break; } } /* End of for (Atm) */
/**** Close the file handle ****/
fclose(FH);
return 0; }
13.2 How to build a VEGA Link Library
The VEGA Link Library (VLL) is a C-script compiled by Tiny C. It's in the middle between a script and a plug-in: it's already in binary format and the compiling and linking phases aren't required to run it. By this way, the VLL is started much faster than a C-script but you can't edited it. The use of a VLL is recommended if you have a complex and very large C-scripts that requires 2 or more seconds to start it. To build a VLL you must follow these steps:
Open the VEGA ZZ console (Start
VEGA ZZ
VEGA Console).
Change the current directory to the folder containing the C-script file.
In the console type:
tcc -shared [VEGA_PATH]\tcc\lib\vgcrt2.voj my_script.c -o my_script.vll
where [VEGA_PATH] is the VEGA ZZ installation path, my_script.c
is the file name of the C-script and my_script.vll is the file
name of the output VLL.
To run the VLL, you must copy it to VEGA ZZ\Scripts directory tree. When you run VEGA ZZ,
it's automatically recognized by PowerNet plug-in
and using the script selection tool (File
Run script) is
possible to run it.
13.3 The super APIs
The super APIs are real VEGA ZZ functions remapped into the plug-in layer. They are declared in vgplugin.h that is palced in VEGA ZZ\Tcc\include directory and in plugins.h file of the plug-in SDK. They can be called using the address of the VGP_VEGAINFO structure (e.g. VegaInfo -> WaitCalc()).
HD_VOID AW_InitAlphaWin(HWND hWnd)
Initialize the alpha channel use for the specified window handle (hWnd). This is
an interface to the AwLib library linked to VEGA ZZ that allows the creation of
transparent windows with fade-in and fade-out effects. This function doesn't
have any effect if the glass windows are disabled (see
Preferences dialog window).
HD_VOID AW_FadeOut(HWND hWnd)
Force the fade-out effect of the specified window (hWnd). This effect
doesn't work if the glass windows aren't enabled in the
Preferences control panel. This
function should be called before closing the window. Please remember to
initialize the window calling AW_InitAlphaWin() with the appropriate window
handle.
HD_ULONG ChoosePixelFormat(HD_VOID *Dc,
HD_LONG *PixelFormat, HD_LONG Multisample, HD_LONG Stereo, HD_LONG RgbBits)
This function replace the standard ChoosePixelFormat() provided by Windows APIs
to choose the pixel format for the OpenGL rendering context. The required
arguments are the device context (Dc); the pointer of the pixel format
variable (PixelFormat); the ARB multisample anti-aliasing value (Multisample)
that could be 0 (no anti-aliasing), 2 (2x), 4 (4x), 6 (6x), etc; the hardware
stereo mode (Stereo), that could be 0 (disabled) or 1 (enabled). Not all
graphic cards implement the stereo hardware and so it's possible that it can
work. The the anti-alias mode currently enabled in VEGA ZZ is available getting
the value of the MSAA system variable (see
GET command).
The function returns zero if it fails, and the requested
pixel format (PixeFormat ) that will be used to create the OpenGL rendering context.
HD_VOID Free(HD_VOID *Mem)
Free a memory segment (Mem), previously allocated by Malloc().
HD_BOOL GetProcAddresses(HD_VOID **Handle, HD_CHAR *DllName, HD_LONG NumberOfFunctions, ... )
This function loads dynamically a DLL, returning its handle.
HD_VOID *Malloc(HD_ULONG Size)
Allocate an uninitialized memory segment of specified size (Size). If you
want to allocate memory blocks (e.g. atoms, surfaces, etc) that will be managed
directly by VEGA ZZ, you must use this function only and not the equivalent
malloc() function provided by the standard C library, because it's incompatible
with the memory manager embedded in VEGA ZZ.
HD_VOID UndoDisable(HD_BOOL Disable)
Disable/enable the undo function.
HD_BOOL UndoPop(HD_BOOL Redo)
If Redo is TRUE, this function performs re-do, otherwise it does undo.
HD_BOOL UndoPush(HD_LONG Object, const HD_CHAR *Message)
Pushes the specified Object into the undo buffer with the Message string that is shown in the graphic interface.
HD_VOID VegaCmd(const HD_CHAR
*Com)
It's the same function used in C-scripts. For more details, see above.
HD_VOID VegaCmdThs(HD_STRING Result, const HD_CHAR
*Com)
It's the same function used in C-scripts (VegaCmdSafe). For more details, see above.
HD_VOID WaitCalc(HD_VOID)
Wait the end of a calculation (e.g. AMMP, MOPAC, etc). It's strongly recommended
the use of this function instead of the polling of ISRUNNING system
variables, because it uses the kernel events and doesn't loose the CPU
performances.