Architecture Of The CVSTrac Program

1.0 Introduction

This note gives a high-level overview of how the CVSTrac program works and how it is put together. It is assumed that the reader is already familiar with what CVSTrac does. The purpose of this document is to provide some additional background information on the internal operation of CVSTrac in order to guide potential contributors in making improvements to the code.

2.0 Design Rules

CVSTrac is designed so that each incoming HTTP request is handled by a separate process. No attempt is made to avoid memory leaks, since the process will terminate as soon as the HTTP request is finished. Global variables are used where it is convenient since only a single thread will be running in the address space.

Some people worry that using a separate process for each HTTP request is inefficient. It may be true that one process per request is not the most efficient design, but it appears to be efficient enough. A 166MHz Pentium with 32MB of RAM has proven to be more than adequate to service a large development group. So for now, CVSTrac will stick with a simple but adequate design that avoids subtle bugs rather than push the envelope with a high-performance design that is harder to work with and more prone to errors.

The program is designed for Unix. No thought has been given to making it run on the "other platform", though there have been reports of limited success getting it to work using Cygwin. (See for example CvstracOnWindows.)

3.0 Code Generators And Preprocessors

The programming language used to implement CVSTrac is C. But most of the code that actually reaches the C compiler is either automatically generated or preprocessed. The source code that you, the programmer, look at in an editor is not the same source code that the C compiler works with.

CVSTrac currently uses five different code generators and preprocessors:

A few of these code generators and preprocessors are explained in added detail by the following subheadings.

3.1 Extracting embedded HTML using "translate"

The CVSTrac program deals with a lot of text - mostly HTML but also a fair amount of SQL. But large blocks of text (where large means hundreds or thousands of characters or dozens of lines) are difficult to deal with in C. All the text must be enclosed in double-quotes and special characters, such as newlines and the double-quote character itself, must be escaped by using a backslash. The net result is that the text becomes difficult to read and edit.

The translate program tries to make the code more readable by converting all lines that begin with a "@" character into code that appends the text on that line to the HTML document being generated. This makes the output text more readable by avoiding the need to write "\n" and "\"". Furthermore, the line of @ characters at the left margin allows the eye to quickly see what code is C executable and what is HTML text. Consider this example (taken from ticket.c):

  @ Description:
  @ (<small>See <a href="#format_hints">formatting hints</a></small>)<br>
  if( isPreview ){
    @ <table border=1 cellpadding=15 width="100%%"><tr><td>
    output_formatted(aParm[10].zNew, zPage);
    @  </td></tr></table><br>
    @ <input type="hidden" name="c" value="%h(aParm[10].zNew)">
    @ <textarea name="c" rows="8" cols="70" wrap="virtual">
    @ %h(aParm[10].zNew)
    @ </textarea><br>

This is a block of code that generates the "Description:" section of a ticket display in CVSTrac. The text of the description will appear formatted as HTML if the "isPreview" boolean is true or as an editable textarea if "isPreview" is false.

The embedded HTML text can contain references to C variables. For example, "%s(z)" will insert the content of the string variable "z". "%d(n)" will insert the content of integer n. The "%" character is generated by putting two percent signs in a row, like this: "%%". Of special note is the sequence "%h(z)" which inserts the content of string variable z, but also translates that content by escaping characters that have special meaning to HTML. So if you write code like this:

  z = "<yes> & <no>";
  @ The string is %h(z)

The generated HTML will look like this:

  The string is &lt;yes&gt; & &lt;no&gt;

The %h substitution is used extensively in CVSTrac to make user-entered text safe for inclusing in an HTML document.

From this short example, it may not be immediately clear that the translate program helps the readability of the code. But if you examine a larger section of the source and compare it to the real C code that translate outputs, you will find that the code with embedded HTML is much easier to work with.

Additional information about translate can be found in the header comments of the program's source file: translate.c.

To Be Continued...