Data Structures
* Database
* User Interface
Database Structures
CONTROL allows for the maintaining of information for an unlimited number of companies. A number of files are maintained for each company. There are essentially three different types of files used in CONTROL: Master, Transaction and Index.
All data files are a collection of fixed size records. The first few records in a file are reserved for special purposes.
N.B. This level of detail on the file contents generally isn't necessary as the routines used to access the data/index/transaction files are quite stable and the issues are generally more related to changing data record layouts/content.
The first 32 bytes of record 0 (zero) is referred to as the file descriptor block and contains control information pertaining to the file
* size of the static and variable parts of the record
* total record size
* number of free records
* free list pointer, etc (see s_fdblk and s_ifdblk in file://ccdev/std/hdrs/common.h ).
This information can be changed using the program spatch.
The remainder of record 0 is the "control record" - used to store operation modifying parameters which can be changed by CONTROL programs: e.g. drcont is used to alter accounts receivable (debtors) control parameters.
For Master files, the second record in the file (record 1) is usually reserved for the 'default' record which is the record that is 'altered' when a new record is added. Hence default values can be set for all fields that can be accessed in the file maintenance program. (default values can be altered by pressing the DEFAULT RECORD key in the Alter option of the appropriate file maintenance program)
Additions to the file are made to the end of the file, that is the next available record in the file. However, if deletions have been made, then the record used will be one from a list of 'free' records within the file. The beginning of the free list is pointed to by a free list pointer in the control record of the file.
The free list is a singly linked list of records and are pointed to by the free list pointer which is adjusted as requests for new records are made or records are added to the free pool.
When a record is deleted, the record is marked as 'free', an linked into the free list, becoming the new head of the list. Similarly, if a free record is requested, then the first available, the records at the had of the free list is returned, and the free list pointer adjusted to the next in the list.
Master Files
Examples of master files are stock.dat (for stock records), debtor.dat for customer records), cred.dat (for supplier records).
In general, each record is separated into two halves, one half for static information (e.g. stock description, customer name and address) and the other half for variable information (e.g. current balance, sales statistics, etc.).
For each record of most master files, one or more singly linked lists of transactions are maintained.
For example a list of financial transactions for the creditor could consist of a linked list of Creditor Adjustments, Sundry Creditor Invoices, Creditor Payments and Creditor Invoices for Stock.
To maintain these lists, two pointers are used - a pointer to the first transaction on the list and a pointer to the last transaction on the list (used for easy linking to the end of the list).
Transactions on a list are linked by the lnkrec field in the transaction (see file:/ccdev/std/hdrs/tran.h) and points to the master file record it belongs to by the ptrrec field. (N.B. The data is an record index rather than a file offset (PM 26/07/2007))
Transaction Files
The transaction files tran.dat and daytrn.dat consist of 128 byte records. The first 100 records are reserved for summary transactions for 100 different transaction types. e.g. record 21 is the summary transaction for DRINVs (Debtor Invoices).
fOR daytrn.dat, each summary transaction record maintains a linked list of batch header transactions of that particular transaction type. The batch header transaction may then contain a list of batch lines which are also maintained via a singly linked list.
A transaction summary record consists of:
* A pointer to the first transaction of this type (batch) - slnkf
* A pointer to the last transaction of this type (batch) - slnkl
* A pointer to the first unposted transaction (for daytrn.dat) - slnkfb
For each header other pointers (record numbers, not memory addresses) are used including:
* lnext - pointer to the next batch this type
* pline - pointer to the first line of this batch
* ptrrec - pointers to the record to which this transaction belongs.
For each line of the batch:
* lnext - points to the next line in this batch.
* phead - points to the batch header transaction.
User Interface Structures
s_outflddes
s_outflddes is used to control CSV output.
struct s_outflddes /* output field descriptor */
00187 {
00188 TINY fldlnk;
00189 UTINY mode;
00190 COUNT line;
00191 COUNT col;
00192 TEXT *fmt GCCALIGN2;
00193 ARGINT *roffset;
00194 TINY rectyp;
00195 TINY type;
00196 COUNT op2type;
00197 VOID *fld2off;
00198 COUNT buf2off;
00199 SHTDEC of_fil;
00200 BOOL (*speclfn)();
00202 } ;* fldlnk is generally used when an earlier s_outflddes record has specified a COMPUTE action and the value here can determine whether or not the record is processed.
* mode - This is generally set to either OUPUT or COMPUTE. When set to COMPUTE then the line member can be set to an operation rather than a line number
* line - either 0 for current line or a fixed value for a totals type destination
* col - column number (starts at 1)
* fmt - field output control (more detail below)
* roffset is an offset into the record to where the data is located
* rectyp is generally an index into the recbuf array
* type defines the type of data the field contains
* speclfn used to compute at run time the value of some data. the result will be referenced by the roffset field and the rectyp field will be set to NORECBUF
e.g.
GLOBAL struct s_outflddes rfc_line[] =
{
{0,OUTPUT,LINE, 1, "15", OFFSET(s_sstock, code), SSTOCK, STRING},
{0,OUTPUT,LINE, 17, "40f", OFFSET(s_tran2, narr),PRODDESC,STRING},
{0,OUTPUT,LINE, 58, "15", &supcode, NORECBUF, STRING},
{0,OUTPUT,LINE, 73, "7.3mrz ", &supp_qty, NORECBUF, SHORTD},
{0,OUTPUT,LINE, 81, "9.3rz ", &suppcost, NORECBUF, SHORTD},
{0,COMPUTE,ADD, 0, "", OFFSET(s_tran, tax),TOTAL,SHORTD, SHORTD, OFFSET(s_tran, tax), TRANL},
{0,COMPUTE,ADD, 0, "", OFFSET(s_tran, amount),TOTAL,SHORTD, SHORTD, OFFSET(s_tran, tax), TRANL},
{0,OUTPUT,ADD, 92, "9.3rz ", OFFSET(s_tran, amount),TRANL,SHORTD,SHORTD, OFFSET(s_tran, amount), TOTAL},
//print the additional info if exists
{0,COMPUTE,TEST,0,"", OFFSET(s_tran2, narr), COMMENT, STRING},
{IF_NULL,OUTPUT,LINE+1,17, "25f ", OFFSET(s_sstock, coment), SSTOCK,STRING},
{IF_NOT_NULL,OUTPUT,LINE+1,17,"60f", OFFSET(s_tran2, narr),COMMENT,STRING},
{0,OUTPUT|SPECIAL,LINE,32,"30",&status_sentence,NORECBUF,STRING,0,0,0,0,get_order_status},
{0,NULL},
01140 } ;Here we write the stock code string from the SSTOCK recbuf data then the narr string from the PRODDESC record. The NORECBUF value signals that we are not referencing data from the recbuf global but a string variable named supcode. The COMPUTE,ADD records add the s_tran.tax field to the s_tran.amount and save the result in the s_tran.amount field to be displayed on the same line as the suppcost variable in column 92.
The "COMPUTE, TEST" record tests a named variable and then the following lines are conditional on that result as to what data is displayed.
To advance the line data is written to we say LINE+1 to increment the current line we are outputting to.
s_field
s_field used on data checking on imported data.
s_flddes
s_flddes used to control user data entry by presenting a mix of prompts and query definitions.
e.g.
GLOBAL struct s_flddes FAR serial_no[] =
02373 {
02374 {0,DISPLAY,Y+2,3,"40t "},
02375 {0,DISPLAY,Y+2,3,"'Number: '"},
02376 {0,INPUT|MUST_IN,Y+2,11,"20t ",OFFSET(s_line_extn,dimlist.narr),LINE_EXTN,STRING},
02377 {0,NULL},
02378 };The first line blanks out an area for the prompt label "Number: " to appear on the current line before we wait for the user to enter a string of up to 20 characters. The OFFSET macro describes the offset into the record buffer we write the result and the record buffer is in a global array named recbuf indexed by LINE_EXTN. The variable length structure is obviously delimited by the NULL trailing record.
s_outflddes Components
The format string is based on the printf style of data formating but VERY different. The data type is specified by the form field type member
* m - minimise decimal places
* r - right justify within field
* c - centre string in field
* f - when used with a string means that the string can fold into a new line as opposed to being truncated within the field. If not a string variable the the following character becomes a fill character.
*t - if following character is a period '.' then the data is right justified otherwise charcater is taken as fill character.
