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:

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:

 

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.