About TRIMpl

Using a single programming language lets different types of applications, such as report writers and screen painters, share the logic of common functions.

Trifox development tools, collectively called TRIMtools, use TRIMpl as their shared language. Using these design tools, developers build and maintain a framework of events and triggers that can be shared. Thus, for example, all applications that have an exit key designated as [F3] can use the same piece of TRIMpl code to execute that operation.

TRIMpl scripts can also run as standalone programs to perform a variety of database or system management functions.

TRIMpl, based on the C language, is easy for any C programmer to learn. The main difference is in its its handling of specific datatypes.

You can download the information in PDF format from our FTP site.

List data manipulation

The list object is central to TRIMpl's data manipulation capabilities. A list is non-typed array of data which can be loaded from a data source, modified, extended, copied, etc.., and then saved back to any data source including XML files. Data retrieval and storage functions use bulk database interfaces to maximize performance.

In addition to disk based storage, list objects can also be loaded into shared memory. This is often advantageous for static data lookup tables such as part numbers, zipcodes, and so on.

The data in a list column does not have to all be of the same type and lists themselves can be stored in list data items. For example, a part record can have a data column that expands into sub-assemblies. Even TRIMpl code itself can be stored in a list data item and executed dynamically.

A simple TRIMpl script to update staff salaries could look like this:

{
list   ll;
number nn;
ll = list_open("select salary,id from staff",10000);
while (true) {
  nn = to_number(prompt("Enter new salary for id "^^
                        list_curr(ll,1)^^" ==> "));
  list_modcol(ll,0,n);
  if (list_pos(ll) == list_next(ll)) break;
  }
exec_sql("update staff set salary = :1 where id = :2",ll);
commit();
}
A slightly more complicated script is used to build the Makefile and spec files for the Trifox rpms:
/******************************************************************************/
/* Script builds the Makefile and Spec file for the Trifox rpms               */
/* parm0 - Product                                                            */
/* parm1 - Version                                                            */
/******************************************************************************/
{
list ll,ml,sl;
int  i,prelen;
char prefix[200];
char os[10];

prefix = "/tmp/TrifoxRPM/"^^parm.0^^"-"^^ parm.1 ^^"/"; /* get the version    */
prelen = length(prefix) + 1;
system("rm -f /tmp/makefile.os; uname > /tmp/makefile.os;");
os = list_curr(list_open("/tmp/makefile.os",1),0);
delete("/tmp/makefile.os");

/******************************************************************************/
/* Spec file header                                                           */
/******************************************************************************/
list_mod(sl,1,"BuildRoot: /tmp/"^^parm.0^^"-root");
list_mod(sl,1,"Summary:   "^^parm.0);
list_mod(sl,1,"License:   Trifox");
list_mod(sl,1,"Name:      "^^parm.0);
list_mod(sl,1,"Version:   "^^parm.1);
list_mod(sl,1,"Release:   1");
list_mod(sl,1,"Source:    Trifox-"^^parm.0^^"-"^^parm.1^^".tar.gz");
list_mod(sl,1,"Group:     Application Development");
if (parm.0 == "DesignVision")
  list_mod(sl,1,"Requires:  Trimtools >= "
               ^^substr(parm.1,1,instr(parm.1,".",-1)-1)^^", Vortex");
list_mod(sl,1,"");
list_mod(sl,1,"%description");
switch (parm.0) {
  case "DesignVision":
    list_mod(sl,1,"DesignVision includes a 4GL application designer and ");
    list_mod(sl,1,"TRIMqmr, an adhoc query and report tool. It requires the ");
    list_mod(sl,1,"installation of Trimtools and optionally Vortex for DBMS ");
    list_mod(sl,1,"access.");
    break;
  case "Vortex" :
    list_mod(sl,1,"Vortex provides the DBMS drivers for DesignVision and ");
    list_mod(sl,1,"Trimtools. It also includes the C and COBOL SQL ");
    list_mod(sl,1,"precompilers and C++ class library.");
    break;
  case "Trimtools" :
    list_mod(sl,1,"Trimtools provides the TRIMpl script language system.");
    break;
  }
list_mod(sl,1,"");
list_mod(sl,1,"%prep");
list_mod(sl,1,"%setup -q");
list_mod(sl,1,"");
list_mod(sl,1,"%build");
list_mod(sl,1,"");
list_mod(sl,1,"%install");
list_mod(sl,1,"make install prefix=$RPM_BUILD_ROOT");
list_mod(sl,1,"");
list_mod(sl,1,"%clean");
list_mod(sl,1,"");
list_mod(sl,1,"%post");
list_mod(sl,1,"cat $RPM_BUILD_ROOT/usr/local/Trifox/INSTALL."^^parm.0);
list_mod(sl,1,"");
if (os == "AIX") list_mod(sl,1,"%define __find_requires /rad/usr3/rad/port/rpm/fake-find-requires");
else             list_mod(sl,1,"%define __find_requires %{nil}");
list_mod(sl,1,"%files");
list_mod(sl,1,"%defattr(-,bin,bin)");

/******************************************************************************/
/* Makefile header                                                            */
/******************************************************************************/
list_mod(ml,1,"#");
list_mod(ml,1,"# Makefile for installing "^^parm.0);
list_mod(ml,1,"#");
list_mod(ml,1,"PGMS = ");

/******************************************************************************/
/* Load the filenames that were moved by the bldrpm script.                   */
/******************************************************************************/
ll = list_open("dir! "^^prefix^^"bin/*",10000);
for (i=list_rows(ll);i;i--,ll++) {
  list_modcol(ml,0,list_curr(ml,0)^^substr(list_curr(ll,0),prelen) ^^" ");
  list_mod(sl,1,"/usr/local/Trifox/bin/"^^substr(list_curr(ll,0),prelen+4));
  }
list_mod(ml,1,"LIBS = ");
ll = list_open("dir! "^^prefix^^"lib/*",10000);
for (i=list_rows(ll);i;i--,ll++) {
  list_modcol(ml,0,list_curr(ml,0)^^substr(list_curr(ll,0),prelen) ^^" ");
  list_mod(sl,1,"/usr/local/Trifox/lib/"^^substr(list_curr(ll,0),prelen+4));
  }
if (parm.0 == "Trimtools") {
  list_mod(ml,1,"TERM = ");
  ll = list_open("dir! "^^prefix^^"term/*",10000);
  for (i=list_rows(ll);i;i--,ll++) {
    list_modcol(ml,0,list_curr(ml,0)^^substr(list_curr(ll,0),prelen) ^^" ");
    list_mod(sl,1,"/usr/local/Trifox/term/"^^substr(list_curr(ll,0),prelen+5));
    }
  list_mod(ml,1,"SAMPLES = ");
  ll = list_open("dir! "^^prefix^^"samples/*",10000);
  for (i=list_rows(ll);i;i--,ll++) {
    list_modcol(ml,0,list_curr(ml,0)^^substr(list_curr(ll,0),prelen) ^^" ");
    list_mod(sl,1,"/usr/local/Trifox/samples/"
                  ^^substr(list_curr(ll,0),prelen+8));
    }
  }
else if (parm.0 == "DesignVision") {
  list_mod(ml,1,"QMR = ");
  ll = list_open("dir! "^^prefix^^"qmr/*",10000);
  for (i=list_rows(ll);i;i--,ll++) {
    list_modcol(ml,0,list_curr(ml,0)^^substr(list_curr(ll,0),prelen) ^^" ");
    list_mod(sl,1,"/usr/local/Trifox/qmr/"^^substr(list_curr(ll,0),prelen+4));
    }
  }
else if (parm.0 == "Vortex") {
  list_mod(ml,1,"OBJ = ");
  ll = list_open("dir! "^^prefix^^"obj/*",10000);
  for (i=list_rows(ll);i;i--,ll++) {
    list_modcol(ml,0,list_curr(ml,0)^^substr(list_curr(ll,0),prelen) ^^" ");
    list_mod(sl,1,"/usr/local/Trifox/obj/"^^substr(list_curr(ll,0),prelen+4));
    }
  list_mod(ml,1,"PERL = ");
  ll = list_open("dir! "^^prefix^^"perl/*",10000);
  for (i=list_rows(ll);i;i--,ll++) {
    list_modcol(ml,0,list_curr(ml,0)^^substr(list_curr(ll,0),prelen) ^^" ");
    list_mod(sl,1,"/usr/local/Trifox/perl/"^^substr(list_curr(ll,0),prelen+5));
    }
  list_mod(ml,1,"JAVA = ");
  ll = list_open("dir! "^^prefix^^"java/*",10000);
  for (i=list_rows(ll);i;i--,ll++) {
    list_modcol(ml,0,list_curr(ml,0)^^substr(list_curr(ll,0),prelen) ^^" ");
    list_mod(sl,1,"/usr/local/Trifox/java/"^^substr(list_curr(ll,0),prelen+5));
    }
  }
list_mod(sl,1,"/usr/local/Trifox/INSTALL."^^parm.0);
list_file(sl,"/usr/src/packages/SPECS/Trifox-"^^parm.0^^".spec","a");

/******************************************************************************/
/* Makefile footer                                                            */
/******************************************************************************/
list_mod(ml,1,"prefix=/tmp/dogface");       /* for safety                     */
list_mod(ml,1,"");
list_mod(ml,1,"install: $(PGMS) $(LIBS)");
if (parm.0 == "Trimtools") {
  list_modcol(ml,0,list_curr(ml,0)^^" $(TERM)");
  list_modcol(ml,0,list_curr(ml,0)^^" $(SAMPLES)");
  }
else if (parm.0 == "DesignVision") 
  list_modcol(ml,0,list_curr(ml,0)^^" $(QMR)");
else if (parm.0 == "Vortex") {
  list_modcol(ml,0,list_curr(ml,0)^^" $(OBJ)");
  list_modcol(ml,0,list_curr(ml,0)^^" $(JAVA)");
  list_modcol(ml,0,list_curr(ml,0)^^" $(PERL)");
  } 
list_mod(ml,1,chr(9)^^"mkdir -p ${prefix}/usr/local/Trifox/bin");
list_mod(ml,1,chr(9)^^"mkdir -p ${prefix}/usr/local/Trifox/lib");
if (parm.0 == "Trimtools") {
  list_mod(ml,1,chr(9)^^"mkdir -p ${prefix}/usr/local/Trifox/term");
  list_mod(ml,1,chr(9)^^"mkdir -p ${prefix}/usr/local/Trifox/samples");
  }
else if (parm.0 == "DesignVision") 
  list_mod(ml,1,chr(9)^^"mkdir -p ${prefix}/usr/local/Trifox/qmr");
else if (parm.0 == "Vortex") {
  list_mod(ml,1,chr(9)^^"mkdir -p ${prefix}/usr/local/Trifox/obj");
  list_mod(ml,1,chr(9)^^"mkdir -p ${prefix}/usr/local/Trifox/perl");
  list_mod(ml,1,chr(9)^^"mkdir -p ${prefix}/usr/local/Trifox/java");
  }
list_mod(ml,1,chr(9)^^"cp $(PGMS) ${prefix}/usr/local/Trifox/bin");
list_mod(ml,1,chr(9)^^"cp $(LIBS) ${prefix}/usr/local/Trifox/lib");
if (parm.0 == "Trimtools") {
  list_mod(ml,1,chr(9)^^"cp $(TERM)    ${prefix}/usr/local/Trifox/term");
  list_mod(ml,1,chr(9)^^"cp $(SAMPLES) ${prefix}/usr/local/Trifox/samples");
  }
else if (parm.0 == "DesignVision") 
  list_mod(ml,1,chr(9)^^"cp $(QMR)  ${prefix}/usr/local/Trifox/qmr");
else if (parm.0 == "Vortex") {
  list_mod(ml,1,chr(9)^^"cp $(OBJ)   ${prefix}/usr/local/Trifox/obj");
  list_mod(ml,1,chr(9)^^"cp $(PERL)  ${prefix}/usr/local/Trifox/perl");
  list_mod(ml,1,chr(9)^^"cp $(JAVA)  ${prefix}/usr/local/Trifox/java");
  }
list_mod(ml,1,chr(9)^^"cp INSTALL."^^parm.0^^" ${prefix}/usr/local/Trifox/");

list_file(ml,"Makefile","a");
}

Function library

Commonly used user functions written in TRIMPL can be stored in a function library and accessed by other TRIMPL scripts. This minimizes duplicate code and simplifies maintenance.

Portability

TRIMpl scripts are converted into a binary tree format for high-speed execution. They can also be saved in a machine independent format for distribution to other hardware types and then converted back into the efficient binary tree format. In this way, the actual TRIMpl source does not have to be distributed and can be controlled.

TRIMpl runtime scripts can also be embedded into the trimrun executable so that only one file need be distributed.

Remote Procedure Call (RPC)

TRIMpl scripts can run via the TRIMrpc mechanism. The TRIMrpc server looks like a standard TRIMpl database connection and contains a complete TRIMtools runtime except for user I/O. Data is returned to the calling programs in lists in the same way as other database connections.

Interface to other programming languages

TRIMpl scripts can also interface with other programming languages, such as C, C++, and so on. The exec_usr() function calls the cexuser shared library using the C argc/argv calling convention except that argv[0] is not the program name but rather the first parameter. The standard cexuser that ships with the TRIMtools bundle looks like this:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <math.h>

#ifdef _MSWIN
__declspec(dllexport)
#endif

#ifdef __370__
#pragma export(cexuser)
#endif

char *cexuser(argc,argv)
int           argc;                         /* number of arguments            */
char         *argv[];                       /* array of arguments             */
{

static  int  argck[] = {2,2,2,3};           /* required argc                  */
static  char buf[128];                      /* return information buffer      */
int     action;                             /* what to do                     */
double  d1,d2;
char   *p;

if (!isdigit(argv[0][0]) &&
    argv[0][0] != '-') return("");          /* first parameter is int action  */
action = atoi(argv[0]);                     /* what to do?                    */

if (action == (-1))                         /* describe?                      */
  return("EXP,LOG,LOG10,POW");

if (action > (sizeof(argck)/sizeof(int) - 1)) {
  sprintf(buf,"Invalid exit number %d, maximum supported %d",
          action,sizeof(argck)/sizeof(int));
  return(buf);
  }
if (argc < argck[action]) {
  sprintf(buf,"Expected %d arguments, received %d",argck[action],argc);
  return(buf);
  }
errno = 0;                                  /* reset in case of leftovers     */

switch(action) {
  /****************************************************************************/
  /* Math functions                                                           */
  /****************************************************************************/
  case 0:                                   /* exp()                          */
    d1 = strtod(argv[1],&p);
    if (errno || (argv[1] == p)) return("");
    d1 = exp(d1);
    sprintf(buf,"%.16f",d1);
    return(buf);
  case 1:                                   /* log()                          */
    d1 = strtod(argv[1],&p);
    if (errno || (argv[1] == p)) return("");
    d1 = log(d1);
    sprintf(buf,"%.16f",d1);
    return(buf);
  case 2:                                   /* log10()                        */
    d1 = strtod(argv[1],&p);
    if (errno || (argv[1] == p)) return("");
    d1 = log10(d1);
    sprintf(buf,"%.16f",d1);
    return(buf);
  case 3:                                   /* pow()                          */
    d1 = strtod(argv[1],&p);
    if (errno || (argv[1] == p)) return("");
    d2 = strtod(argv[2],&p);
    if (errno || (argv[2] == p)) return("");
    d1 = pow(d1,d2);
    sprintf(buf,"%.16f",d1);
    return(buf);
  default: return("ERROR: Unknown user exit");
  }
return("");
}

By combining TRIMrpc TRIMpl scripts with the exec_usr() external programming language capability, you can create remote data servers for almost any system.