URL: http://www.firstbasesoftware.com/man/man1/dbmacro.htm
Last modified: 20 January 2000
Copyright © by FirstBase Software.
[ Index of Contents] [ FirstBase RDBMS Overview]


NAME

dbmacro - general purpose text, CGI, HTML, and record processing language

SYNOPSIS

dbmacro [-b] [-c] [-r] [-d database] [-i index] [macro_file | -m script]

DESCRIPTION

Dbmacro, a general purpose processing tool for text files, CGI requests, HTML forms, database records and FirstBase databases. Dbmacro executes macro(5) code from a file, standard input, or an inline script. Default output is written to standard output.

The macro language provides a powerful general purpose processing tool that can be used with or without a FirstBase database. The dbmacro tool is free-ware. However, the free version of dbmacro does not read/write FirstBase databases.

The macro(5) language is similar to C in syntax and includes most of the familiar programming constructs, including conditionals, loop constructs, user defined functions, and printf mechanisms. This high level language also supports associative arrays, run time loadable code, strings, and all of the FirstBase data types. In addition, there are many built in functions covering math, string, date, screen input/output, stream input/output, and CGI/HTML processing.

Variables are dynamically created without being declared and are global in all situations unless specified as local using the local directive. These variables can take on any of these data types: float, date, string, associative array, or database array.

Functions can accept and return any number of arguments and parameters of any type, including arrays. All function parameters are local.

At runtime, variables can be introduced and initialized on the argument line using a var=value syntax. Variables can also be introduced using CGI methods. See below.

Database records and fields can be created, modified, or deleted using simple assignments and/or calls to the putrec function. The -r flag invokes dbmacro in read-only mode so that records cannot be modified.

Using the -c flag, or invoking dbmacro as dbmacro.cgi, enables dbmacro to process Common Gateway Interface (CGI) requests, either GET or POST methods, as used by http servers and World Wide Web browsers. See the section on CGI below.

A macro_file is a simple text file containing macro(5) code. Generally, a macro_file can contain three main sections: begin, body, and end, and any number of function sections. Each of these sections is declared using these keywords. The default section type is body.

When provided with a database argument, dbmacro will processes the database in the normal FirstBase generator manner -- the macro_file is executed once for each referenced record. The set of processed records can be limited using the -i index specifier. The begin section is done once before any processing occurs (for initialization needs), the body section is done once for each referenced database record and the end section is done once after the last record has been processed (for clean up or totals printing).

When not provided with a database, dbmacro processes the macro_file one time. In this scenario, if database processing is desired, macro(5) functions like opendb and getxrec are used in the macro code.

When using the -m method of providing macro code, use single quote marks to surround the code. Note: this method assumes that all code in the script is part of the body section.

Dbmacro can be used for database processing, simple reports, complex inquiries involving many criteria, and selective, sophisticated database updates. Fields in records can be modified by using code that does simple field assignment.

The following example shows a simple macro file. Note that this BEGIN section is not really needed (since all variables default to 0 or the NULL string) but, it serves the purpose here.

begin total = records = 0 body records++ total += $AmountDue end print("The grand total is ", formfield(total, "$", 18)) print("The average is ", formfield(total/records, "$", 18)) print("The number of records processed is ", records)
This example will calculate the grand total of a dollar field named AmountDue. After processing, the total will be formatted and printed with a message, along with an average and number of records. To use this macro code, the database must be specified using the -d flag.

As another example, the following is a functionally equivalent piece of macro(5) code. In this case dbmacro is invoked without a database, but uses builtin macro functions to directly open and process a FirstBase database.

# # sample code to read and total records # db = opendb("dbase", "r") if (db >= 0){ process(db) closedb(db) } else print("could not open the database") # end of main section # # process - process all records of database db # function process(db) { total = records = 0 initrec(db, dbase) records = reccnt(db) for (rec = 1; rec <= records; rec++){ getrec(rec, db) total += dbase[AmountDue] } print("The grand total is ", formfield(total, "$", 18)) print("The average is ", formfield(total/records, "$", 18)) print("The number of records processed is ", records) }

COMMON GATEWAY INTERFACE (CGI)

Dbmacro will process both GET and POST requests via the Common Gateway Interface (CGI). Install dbmacro into the http server's cgi-bin directory, rename dbmacro to dbmacro.cgi, and allow access to dbmacro.cgi via the http server. In addition, create a symbolic link from /usr/local/firstbase to the actual $FIRSTBASEHOME directory (if they are different).

If invoked as dbmacro.cgi, CGI data is automatically converted to variables available in the macro code at runtime. In this case, dbmacro(1) also emits the standard CGI script lines "Content-type: text/html\n\n". Multipart CGI data is also handled automatically (see html_form_open() in macro(5)).

However, if dbmacro(1) is called from a shell script, or is used as the command interpreter itself via something like

#!/usr/local/firstbase/bin/dbmacro
as the first line of the CGI file, then the cgi_read mechanism can be used to parse standard CGI parameters and values. Note that the script will have to print the HTML Content-type directive itself if needed.

When processing a GET request, the query string will be searched for var=value pairs. During a POST request, all HTML form fields are used as var=value pairs. In all cases, the variable var will be preassigned the string value before macro processing begins.

To pass the name of a file with the macro code to execute, connect the macro file name to the URL just beyond the dbmacro.cgi string.

In the following CGI GET request example, dbmacro executes the macro code in script.m passing a variable named Command that has a string value of Modify, and another variable, Status, set to OK.

/cgi-bin/dbmacro.cgi/script.m?Command=Modify&Status=OK

In the following CGI POST request example, dbmacro uses the macro code in the file webmaker.m. Variables are passed from standard HTML input fields, in this case, a field named Command, and another named Status. The values of these fields will be whatever is contained in the HTML form field at the time of the POST request.

<FORM METHOD="POST" ACTION="www.horseweb.com/cgi-bin/dbmacro.cgi/webmaker.m"> <INPUT TYPE=TEXT NAME=Command SIZE=10 MAXLENGTH=10> <INPUT TYPE=HIDDEN NAME=Status VALUE=OK>

The special checkbox HTML forms input type is provided to dbmacro code as an array named the same name as the field name. (The same applies to the use the keyword MULTIPLE in an HTML SELECT statement). The subscripts or keys of this checkbox array are from one to countkey(array). In other words, dbmacro handles multiple occurrences of the same variable passed in from an HTML form.

However, there is one caveat with these methods where the same variable has multiple values as passed in from an HTML form: If only one of many in the HTML checkbox or selection list is selected, then dbmacro will only see one occurrence of this HTML field name, and the variable available at run time will not be an array, but will be a simple variable like any other HTML input fields. In this case, the countkey function will return a zero (0).

If provided with a variable named database, the value of this variable will be used as the name of the default database, and dbmacro will behave as if it received a -d flag. Another variable, index, can be used to process the default database via index.

Two other variables are automatically set as well: PATH_TRANSLATED (or path_translated) is set to the full path name of the excess values beyond the dbmacro.cgi reference, for example, /usr/htdocs/firstbase/webmaker.m. In addition, the base directory name is stored into PATH_DIR (or path_dir).

File type variables from encoded multipart forms will contain the name of a temporary file with the contents of the CGI transmission. See html_form_open() in macro(5) for more details.

MORE EXAMPLES

Here are some more example uses of dbmacro. In the following example, a database is opened, ten records are added, and the database is closed.
db = opendb("dbase", "w") for (i = 1; i < 10; i++){ initrec(dbase, db) dbase[1] = i dbase[2] = date(now()) st = addrec(db) printf("status from addrec is %d\n", st) } closedb(db)

In this next example, a database is opened, an index is requested, and an array named dbase is associated with the database via initrec. Then, a record with a search key of value 6 is located, printed, locked, deleted, and then unlocked. Finally, the database is closed.

db = opendb("dbase", "w") st = useidx(i, channel) printf("status of useidx is %d\n", st) initrec(dbase, db) key = makess("6", "N", 6) st = getxrec(key, db) if (st < 0){ printf("could not find record ...exiting\n") exit(1) } printf("%s %s %s %s\n", dbase[1], dbase[2], dbase[3], dbase[4]) rec = recno(db) st = lock(rec, db) printf("st for lock is %d ... pausing - hit return to continue", st) gets() st = delrec(db); printf("st for delrec is %d\n", st) unlock(rec, db) closedb(db)

In the next example, no databases are used at all. Here, an array is subscripted with a couple of strings, and initialized. Then, the array is processed twice, printing each element.

word["apple"] = "A good fruit" word["orange"] = "An orange fruit" for (;;){ if (key(subscript, word)) printf("got a subscript of %s, val of %s\n", subscript, word[subscript]) else break; } print("Start again") for (;;){ if (!key(subscript, word)) break; printf("got a subscript of %s, val of %s\n", subscript, word[subscript]) }

SEE ALSO

dbedit(1), macro(5), fbtstmac(8)

FirstBase User's Guide and Reference Manual


URL: http://www.firstbasesoftware.com/man/man1/dbmacro.htm
Last modified: 20 January 2000
Copyright © by FirstBase Software.
[ Index of Contents] [ FirstBase RDBMS Overview]