Programmers' guide to the acedb - graph interface

Overview

This document describes the changes made to the graph package (i.e. code in the 'w2' source directory) as part of a restructuring of acedb code to introduce independent packages or libraries of code. In the case of graph this meant removing acedb-specific code (e.g. lexNNN functions etc) from the package so that an independent graph library could be compiled. This has been achieved by allowing the registering of callback functions with the graph package that allow the acedb specific routines to be called from the graph code without introducing link-time dependencies. The rest of this document describes how graph was restructured to do this.

Then and now.

How things used to be....

Until now the graph package was included in an application by compiling in the graph source code. If the application was an acedb application the macro ACEDB was defined for the compilation to make sure that acedb specific code in the graph source code was included. This meant no single graph library could be built which could be used by both acedb and non-acedb applications, it also meant that the source code was 'polymorhpic' in a number of ways: some functions had different signatures according to whether ACEDB was defined, some routines had different logic flows, some data structures had different members and so on.

How things are now....

For many reasons it was seen as important to remove this 'polymorphism' and produce a single coherent graph package/library which could be used by acedb and non-acedb applications. This single graph package is built into a single library which can be used by all applications. All acedb specific code has been moved to a single module separate from the graph package which contains all the routines and function calls required by acedb to interface to the standard graph library.

How the restructuring was done

The new graph library has no acedb-specific code in it, it provides the 'bare bones' graphical routines with no acedb database element. acedb applications are then allowed to alter the behaviour of the graph package to allow calling of database routines to set specific types of windows/boxes etc.

The underlying mechanism allowing removal of the ACEDB defined sections of code is the definition of a number of function pointers in the graph library which can be used by an acedb application to register its acedb-specific routines. The graph code initialises these pointers to NULL and so can later test them to see if an acedb function has been registered and call it if it has.

The following fictious example shows the replacement of some ACEDB defined code with such a function call, the original code:


for (i = 0 ; i < limit ; i++)
  {
  some_code ;

#ifdef ACEDB
  lexNNNN(i, key, something) ;
#endif  

  some_more_code 
  }

is replaced with:

for (i = 0 ; i < limit ; i++)
  {
  some_code ;

  if (getACEDBLexFunction() != NULL) (getACEDBLexFunction())(i, key, something) ;

  some_more_code ;
  }

Hence some 'hard-coded' acedb specific code has been replaced with a dynamic function call thus removing the dependency of the graph code on the acedb code.

NOTE that, because this was a fairly large change, all alterations to the code have been marked with C comments with the following format:

/* ACEDB-GRAPH INTERFACE: ....description of change made....               */
Hence the source tree can easily be searched to find all the changes made.

Design decisions

In an ideal world a generalised callback interface could have been introduced into the graph package which would support programs other than acedb. In practice there is not really any justification for this, the only requirement for this interface is that it supports existing acedb functions.

A new module was introduced into the graph package called graphAcedbInterface.c which contains all of the function pointers and code required to support the graph interface for acedb code. The exported functions of this interface are declared in a new header, graphAcedbInterface.h, the internal non-static functions are declared in graphs internal header, graph_.h.

All of the acedb specific code from graph was collected together in one module, acedbgraph.c, and placed in the w4 directory which contains the main module initialisation code for acedb applications. A function was provided in this module that can be called from an acedb application to intialise graph and the graph-acedb interface. This avoids the need for extensive recoding of existing graphical acedb applications. This function which provides the acedb-graph interface is declared in the header acedbgraph.h.

This crude diagram summarises this new interface:

                             ACEDB    *   GRAPH
                                      *
                                      *
        (acedbgraph.h)                *                         (graph_.h)
             |                        *                            |
             V                        *                            V  
acedb_app.c ---> acedbgraph.c --------*--> graphAcedbInterface.c <--- rest of
   |                            A     *                               graph
   |                            |     *                               package
   |         (graphAcedbInterface.h)  *                                 A
   |                                  *                                 |
   |                                  *                                 |
   |                                  *                                 |
   |                       (graph.h)  *                                 |
   |                            |     *                                 |
   |                            V     *                                 |
    ----------------------------------*---------------------------------
                                      *
                                      *
                                      *


The major design decisions were:

  1. to use a function callback mechanism to replace the ACEDB defines allowing the new code to execute the acedb specific code in the same way as it was executed when included by #define.
  2. to provide an acedb specific set of functions in a single graph package module (graphAcedbInterface.c) to allow the registering of data and the callback functions.
  3. to collect all the acedb specific code from the graph package into a single module (acedbgraph.c) outside of the graph package.

Future changes

There should now be no need to include acedb specific code in the graph package with #defines. All new code should follow this model of function callback interface. Ideally, new acedb requirements for the graph package should be dealt with by introducing more generalised 'callback' functions into the graph package rather than by expanding this interface. The intention is to limit this interface to its current size, it is simply an expedient bit of coding to produce a stand-alone graph package and more importantly stand-alone graph library.

Source/Interface/Functions

Source files:

Reflecting the division of function into 'acedb' or 'graph' code, the source files are divided into two sets:

Graph package:

graph.h
does not contain any of this interface
graphAcedbInterface.h
declares all public functions of the interface
graph_.h
declares all non-static private functions used internally in graph to support the interface.
graphAcedbInterface.c
contains all graph package code to support the interface

Acedb code:

acedbgraph.h
declares all public functions for acedb to initialise its interface to the graph graph package.
acedbgraph.c
contains all functions of the interface
Note that non-acedb applications can simply include graph.h while acedb applications include just graphAcedbInterface.h (which include graph.h).

Interface:

The public interface comprises the following elements: The private interface used only within the graph package comprises:

Global variables

none