Serving the DataPerfect* Community

Home > Firestorm > Principles of Operation > Programmatic Interface > Demonstration
Last updated: October 31, 2001

Firestorm Demonstration

In this demonstration, we will show how to take a simple DataPerfect database and create a web application based on it. When complete, the demonstration will consist of:

  1. a simple program to print all the records
  2. a program to generate an HTML page showing all the records
  3. a CGI script to generate an HTML page showing all the records
  4. a CGI script to add one to a field of a particular record, creating it if necessary
  5. a CGI script to generate an HTML page showing a subset of the records

In this demonstration, we will use a simple DataPerfect database with one panel, two fields, and one index. The fields are P1F1 (named "Name"), formatted A8;;T, and P1F2 (named "Count"), formatted GZZZZZZZZZZZZZ9;;B. The panel is indexed by Name.

This database would require the PBA description shown in the file pba.c. Don't be alarmed by the apparent complexity of this file. It is created automatically for you by the METAD database, as explained in the usage guide.

Demonstration (Part One)

A program to open this database, position to the first record in the panel and print out all of the records is shown here. The line numbers are not a part of the program, but for reference in the discussion that follows.

 1  #include <stdio.h>
 2  #include "../fs.h"
 4  void main()
 5  {
 6    FS_panel p1;
 7    int err;
 9    FSopen();
10    p1 = FSsetPanel(1);
11    err = FSfirstRec(p1,1);
12    while (err == FS_OK) {
13      printf("Name: %s Count: %s\n",
14        FSfield(p1,1)->field_data,
15        FSfield(p1,2)->field_data);
16      err = FSnextRec(p1);
17    }
18    FSclose();
19  }

Here is an explanation of the example program:

C preprocessor directive to include standard input/output definitions
C preprocessor directive to include Firestorm definitions
the main program begins here
declaration of a variable named p1 that represents the first panel
declaration of a variable to hold an error code
call the FSopen function to open the database
setup the first panel for use
call the FSfirstRec function to position to the first record using index one
while there is a record left to process
print two field values (each %s is replaced by a value)
get the field data value for panel one field one
get the field data value for panel one field two
call the FSnextRec function to position to the next record if any
end of the while loop
call the FSclose function to close the database
end of the main program

Once you have created the 19 line program and saved it in a file named demo.c, you will need to compile it, as described in the usage guide. When it is run, the program will produce output like this:

Name: CDIB01 Count: 1174230
Name: CDIB02 Count: 210049
Name: CDIL01 Count: 6095288
Name: CDIL02 Count: 91093

To get the same output from DataPerfect, you would have used a very simple report. Note: to see this report, you can save the .STE file that defines the simple DataPerfect database and run DPIMP, then DP DEMO, 1 (to recreate TXX file), 1 (to recreate IND file), Enter (to go to the panel), Shift-F7 (to go to the report list), Down-arrow (to go the sample report), Enter (to go to the report definition page), and, finally, 8 (to see the report form). Then, press down-arrow three times, and control-right-arrow three times.

Programming with Firestorm is going to be different than programming in DataPerfect. But, it's not really all that much harder. For example, refer to the sample program above, and compare it with the simple report. For a report, you specify the panel (program, line 10). You specify which index to use, and whether in ascending or descending order (program, line 11). For descending order, line 11 would have called the FSlastRec function, and line 16 the FSprevRec function. Page headers and footers tend to be used differently on the web. Anything your program prints before the loop (before line 12) would appear in the output before the first record. Conversely, anything your program prints after the loop (after line 17) would appear after the last record printed. In Firestorm, we have to specify the REPORT BODY loop ourselves (program, lines 12, 16, and 17).

To actually print something, we include it in the quoted string argument to the ANSI C printf function (program, line 13). Lines end with backslash n (for a newline character). Whenever we want to place a field value, we put a percent s into the quoted string. For each percent s, we must include an extra argument for the printf function. Each such argument identifies the panel and field and calls for the field data. Compare "P1F2" with "FSfield(p1,2)->field_data" to see the comparison (program, line 15).

Demonstration (Part Two)

To produce a page suitable for display in a browser, we would need a program that produces valid HTML. Such a program is demo2.c. Notice that it differs from demo.c only in that it prints many more lines, all of them HTML tags. The ouput of the demo2.c program looks like this.

It would be a good exercise to look at the Page Source for the program output, and compare it with the program. Be sure you can explain to yourself where each line in the output comes from the program.

Demonstration (Part Three)

A very small change to demo2.c will produce demo3.c. This is the addition of a line that says "Content-type: text/html" and a completely blank line as the two very first lines produced by the program.

Whereas demo2.c could be used to produce a file named demo2.html, which could then be placed on a web server, demo3.c can actually run on a web server and produce its output on demand. It has become what is known as a "CGI script."

Exactly how to write a URL that invokes a CGI script depends on the way the web server is set up. On this web site (hosted by sanbachs.NET), the URL to invoke demo3 looks like this:

The output of demo2.c and the output of demo3.c look very similar in a web browser. But, there is an important difference between the two. You must run demo2 from time to time to produce its output, demo2.html. Then, you must upload the file demo2.html to your web server. The data displayed in this page doesn't change until the next time you do this. This is sometimes called a "static page." On the other hand, the person viewing the URL that invokes the demo3.cgi program causes the demo3 program to run at that very moment, so the data they see is completely up to date. Furthermore, you are not required to take any action.

Demonstration (Part Four)

If you examine the demo4.c program, you will notice that it is very similar to demo3.c, with the following additions:

  Field_Value *Demo = NewField(1,'9',4,"DEMO");
  Field_Value *One = NewField(2,'3',1,"1");

These lines create two new field values. For field one ('9' for type A or U), the string "DEMO" of length 4. For field two ('3' for type G, H or N), the string "1" of length 1.

  err = FSequalRec(p1,FSifList(p1,1,Demo));
  if (err == FS_OK) {
    err = FSupdateField(p1,FSifList(p1,1,Demo),2,'+',One);
  } else {
    err = FScreateRec(p1,FSfList(p1,Demo,One));

First we look for a record in panel one, using index one, that has the value "DEMO" in the first field of the index. If we find such a record, we update field two of that record by adding ('+') the value "1" to the value already in that field. If, on the other hand, we didn't find such a record, we create a new record in panel one, consisting of the field values in Demo and One in that order.

  printf("<a href=>");
  printf("<font face=Arial>Powered by Sanbachs Firestorm</font></a>\n");

These lines produce a link to the Firestorm home page, as we ask you to do when using Firestorm with your DataPerfect databases on the Internet.

The program demo4.c is also a CGI script. To run it, you would use this URL: If you click the reload button on your browser, you will see the count value for DEMO increasing. At this point it is worth going back to Part Three of the demonstration and comparing the output of demo2.c with the output of demo3.c to notice that they are now different. The demo2.c program was run to produce the static HTML file, demo2.html, some number of days ago. It captured a static "snapshot" of the data in the database. On the other hand, the demo3.c program is run when you click on the "output of demo3.c" link and provides an up to the minute view of the data in the database.

As a courtesy to other readers of this demonstration, please remove the DEMO counter after you are finished playing with it, by running the demo-reset CGI script. For the curious, feel free to look at the source code of demo-reset.c.

Demonstration (Part Five)

In this part of the demonstration, we introduce several new things. Probably the most important of these is the ability to accept input from the user to modify the page that is generated in response. The URL for the demo5.c program is href= which is different from the others in that it contains a question mark. This makes it a "query" URL. Try modifying the URL with different things after the "?Prefix=", such as C, D, CDI, CDIB, etc.

In practice, you would not expect your users to modify the URL when making queries against your database. Instead you would provide them with a query form, such as demo5.html. The HTML code to display this form has been kept as simple as possible. Look at it using your browser's menu to View Page Source.

The part of the program that allows user input is

char *WhatFilename = "what-demo.txt";

Field_Value *Prefix;

FS_CGI_arg FSexpect[] = {
  { "Prefix", &Prefix, ""},

int FSquery()
You'll notice that instead of being named "main" this program is named "FSquery" which means that the main program must be defined elsewhere. This program must be linked with what is called the "CGI Interface" of the second diagram of the Principles of Operation page. On that same diagram, the program called "Custom CGI program" is our demo5.c program, which implements the FSquery function.

It interacts with the main program by setting up two variables: "WhatFilename" and "FSexpect". The first of these gives the name of a file which will contain an access log recording every call to the CGI script. This file can get rather long, but you are welcome to look at it. Towards the end of it, you should be able to see the queries you made to it while working with it earlier. The second variable, FSexpect, is an array, or list, of structures (of type FS_CGI_arg) which tell the main program what inputs you are expecting. In this program we are only expecting one, named "Prefix", to be stored in the Field_Value variable named "Prefix", with the value of "" (an empty string) if the user does not provide it.

Instead of positioning to the first record of the panel, this program identifies a subset of the records, consisting of those records in index one which match the Prefix:

  err = FSsubFirstRec(p1,FSifList(p1,1,Prefix));

Having set up the subset, we call the FSrecCount function to learn how many records are in the subset:

  recordCount = FSrecCount(p1);

This number is used later on in the program to produce different text; either "No records matching" the Prefix, or "# record(s) matching" the Prefix.

  if (recordCount == 0) {
    printf("No records matching \"%s\"
\n", Prefix->field_data); } else { printf("%d record%s matching \"%s\"\n", recordCount, (recordCount==1) ? "" : "s", Prefix->field_data); ... }

The ellipsis (...) is almost exactly the same code that produced the HTML table of record values in the demo3.c and demo4.c programs. The difference is that, at the bottom of the while loop, instead of calling the function FSnextRec (to get the next record in the panel), it calls the function FSsubNextRec (to get the next record in the subset).

Contacting sanbachs.NET

Sign or browse our guest book.
A. Lewis Bastian, Jr.
Bruce Conrad
Thom Boyer


*DataPerfect® is a copyright of Novell, Inc. sanbachs.NET is not affiliated with Novell, Inc.

visitors since November 23, 2000.
Copyright © 2001 sanbachs.NET