FATS - Fast Access Tree System
Table of Contents
Programming Interfaces
Watcom C/C++ for DOS


The following C/C++ example demonstrates the use of the FATS  indexing commands:

 "C" Create Indexfile
(Creates a index file with the specified characteristics.)
 "O" Open Indexfile
(Makes a index file available for access.)
 "K" Close Indexfile
(Releases a index file from availability.)
 "I" Insert Record
(Insert a new record.)
 "F" Search First
(Gets the key value and record number of the data record with the first key value.)
 "L" Search Last
(Gets the key value and record number of the data record with the last key value.)
 "N" Search Next
(Gets the key value and record number of the data record following the current record.)
 "A" Search Next After
(Gets the key value and record number of the data record whose key value is greater than the requested key value.)
 "E" Search Previous Before
(Gets the key value and record number of the data record whose key value is less than the requested key value.)
 "Y" Auto Refresh
(Specifies file locking and cache modes in single- and multi-user environments.)

/*
   FATS 02.30
   (c) GCS Software, Udo Gertz 1993-1998

   Test program (Watcom C)
 
   Build the test data file customer.dat.

   19-03-2009 U.Gertz
*/ 

   #include <stdio.h>
   #include <io.h>
   #include <fcntl.h>
   #include <sys\types.h>
   #include <sys\stat.h>
   #include <stdlib.h>
   #include <string.h>
   #include <mem.h>
   #include "FATS.h"

/*

   Needed Object Files
   ===================

   To link FATS to your programs you will need the following
   object modules:

        FATS.OBJ        The FATS module for DOS
        FATS_WCS.OBJ    Interface / small-model
        FATS_WCM.OBJ    Interface / medium-model
        FATS_WCC.OBJ    Interface / Compact-model
        FATS_WCL.OBJ    Interface / Large-model

   The following libraries are included on the distribution diskette
   to call the FATS Workstation Engine:

        FATSWCSR.LIB    Interface / Small-model
        FATSWCMR.LIB    Interface / Medium-model
        FATSWCCR.LIB    Interface / Compact-model
        FATSWCLR.LIB    Interface / Large-model

   If you want to make calls to the extended version
   of FATS (FATSXWE.EXE), you have to use the libraries
   FATSXCSR.LIB (small), FATSXCMR.LIB (medium),
   FATSXCCR.LIB (compact) or FATSXCLR.LIB (large).


   Linking a Watcom C Program with FATS
   ====================================

   To compile and link a application that calls FATS,
   use ONE of the following methods:

   1. METHOD: Linking FATS to the program

       WCL /m[?] /l=dos /bt=dos TST1_ENG.C FATS_WC[?].OBJ FATS.OBJ
       [?] == S (small model), M (medium), C (compact), L (large)

   2. METHOD: Calling the Workstation Engine (FATS_WE.EXE)

       WCL /m[?] /l=dos /bt=dos TST1_ENG.C FATSWC[?]R.LIB

       or if you own the extended version of FATS: (FATSXWE.EXE)

       WCL /m[?] /l=dos /bt=dos TST1_ENG.C FATSXC[?]R.LIB


   Calling FATS
   ============

   All commands provided by FATS can be executed with one function:

     unsigned long __cdecl FATSCALL(char *szCmnd,
                   unsigned short *uFATSError, char *szReturnKey);

   The meaning of the used parameters:

      szCmnd         With this command string you specify the actual
                     FATS command. The available commands are described
                     in the user manual.
 
      nErrorcode     Your application must always pass this variable as
                     the status parameter on a FATS call. After the
                     FATS call, the application should always check the
                     value of this variable. FATS returns a errorcode of
                     0 after a successful operation. FATS indicates any
                     errors which occur during processing by returning a
                     nonzero value in the errorcode variable.
                     In the manual you can find a list of all FATS
                     errorcodes and their possible causes.
 
      szReturnKey    This variable will contain the key value of a found
                     key after any normal search command (S,G,F,L,N,P,A,E).
 
      Return Value:  Record Number
*/ 


   struct custdat {
          char DELETEDMARK;
          char ID[6];
          char NAME[26];
          char JOB[26];
          char STREET[26];
          char ZIP[6];
          char CITY[21]; };

   char           szCmnd[256];
   char           szFATSkey[256];
   unsigned short uFATSError;
   unsigned long  dwFATSRecno;

   struct custdat cust;


main ()
{

   char cChar;
   int  hCustomer;
   int  hDemodata;
   int  nCount = 0;
   int  nIOresult;

   /*
      -------> Activation of Network Operation
    
      FATS is standardly equiped for the network environment.
      Nearly all commands can be executed both in single workstation
      and network environment. With the  "Y" Auto Refresh command you
      determine the behavior of FATS accessing all index files.
      Normally it is sufficient to apply this instruction one time at
      the program start whereby the specified access mode will apply
      to all coming opened files, i.e. they are accessed either with
      network (Y\2) or single workstation access (Y\0).

   */  

   // dwFATSRecno = FATSCALL( "Y\\2", &uFATSError, szFATSkey );


   /*
      -------> Open file with test data
   */ 

   hDemodata = open( "..\\..\\..\\DEMODATA\\CUSTOMER.ASC", O_BINARY|O_RDONLY );


   /*
      -------> create data file
   */ 

   printf( "Creating Data File ...\n" );
   hCustomer = creat( "CUSTOMER.DAT", S_IREAD|S_IWRITE );
   setmode( hCustomer, O_BINARY );


   /*
      -------> Create index file
   */ 

   /*
       "C" Create Indexfile
    
      With this command you create an index file, whereby a possibly
      already existing file with the same name is deleted.
      After the file is created it will be opened with the opening
      flags defined with the command  Auto Refresh (Y) and can be
      accessed under the file number you specified.
    
      Max. 200 primary keys per data record can be administered in an
      index file, the max. key length amounts to 240 characters.
    
      Full path names must be specified using forward slashes (/)
      instead of Backslashes (\), because FATS normally uses the
      Backslash character as delimiter.
      You may change the delimiters by placing the desired character
      as the first character of the command string,
      e.g. szCmnd = "&C&C:\ARTICLES.KEY&1&1&A&1". Any character with
      an Ascii code less then 48 will be accepted.
    
      The syntax of the command string:
    
        szCmnd = "C\{Filename}\{KeyLength}\{KeyCount}\{KeyType}\{FileNo}"
    
          FileName   filename, perhaps with an additional path
                     (e.g. C:/DATA/ARTICLES.KEY or ARTICLES.KEY)
    
          KeyLength  Maximum key length (1-250)
                     If you choose to have more than one key for
                     this index file, you may specify the length
                     for each key (separated by a semicolon ";")
                     to conserve diskette space.
                     Otherwise, the maximum length applies to all
                     keys, i.e. every key will occupy the maximum
                     space.
    
          KeyCount   Number of primary keys (1-200)
    
          KeyType    Key type (A = Ascii text, I = Integer)
    
          FileNo     File number (1-40)

   */  

   printf( "Creating Index File ...\n\n" );
   dwFATSRecno = FATSCALL( "C\\CUSTOMER.KEY\\5;25\\4\\A\\1", &uFATSError, szFATSkey );


   /*
      ========================================================================
                Insert Records
      ========================================================================
   */ 

   printf( "290 records will be inserted into the data file.\n" );
   printf( "For each record 4 keys will be stored in the index file.\n" );
   printf( "Please press the [ENTER] key ...\n" );
   cChar = getchar();

   memset( &cust, 0, sizeof( cust ) );

   do {

     nIOresult = read( hDemodata, &cust.ID, 5 );
     nIOresult = read( hDemodata, &cust.NAME, 25 );
     nIOresult = read( hDemodata, &cust.JOB, 25 );
     nIOresult = read( hDemodata, &cust.STREET, 25 );
     nIOresult = read( hDemodata, &cust.ZIP, 5 );

     if ( read( hDemodata, &cust.CITY, 20 ) == 20 ) {

       /*
           "I" Insert Record
        
          This command is used to insert the primary keys of a new
          data record into the index file. After the insert, the
          record number of the new record is returned in the "RECNO"
          variable. You can use this record number to write the data
          record to the data file.
        
          The number of keys included in the command string must equal
          the number of primary keys you specified in the
          Create Indexfile (C) command.
        
          The length of the transferred keys may not exceed the maximum
          key length specified with the Create Indexfile (C) command.
          Variable length keys will be padded with the Ascii char 0 to
          the maximum key length.
        
          The syntax of the command string:
        
            szCmnd = "I\{FileNo}\{KeyStr1}[\{KeyStr2}[\{KeyStr3}]]"
        
              FileNo     File number
        
              KeyStr#    Key value

       */  

       sprintf( szCmnd, "I\\1\\%s\\%s\\%s\\%s%s",
                cust.ID, cust.NAME, cust.JOB, cust.ZIP, cust.CITY );

       dwFATSRecno = FATSCALL( szCmnd, &uFATSError, szFATSkey );

       if ( uFATSError == 0 ) {

         printf( "%s --> RecNo %lu\n", cust.NAME, dwFATSRecno );

         lseek( hCustomer, (dwFATSRecno - 1) * sizeof(cust), SEEK_SET );
         nIOresult = write( hCustomer, &cust, sizeof(cust) );
       }
     }
     nCount++;

   } while ( ( nCount < 290 ) && ( uFATSError == 0 ) );

   close( hDemodata );

   /*
       "K" Close Indexfile
    
      This command closes the index file with the specified
      file number.
    
      If you have activated the cache algorithm with the command
      Auto Refresh (Y), the possibly still in the cache buffers
      presented data are automatically written on the disk.
    
      If the cache is inactive after every FATS command all
      changed data are written on the disk. Therefore closing of
      a file is necessary only before terminating the application.
    
      If you omit the parameter "FileNo", then all opened index
      files are closed. This version is recommended before the
      termination of the application program.
    
      The syntax of the command string:
    
        szCmnd = "K\{FileNo}"
    
          FileNo     File number

   */  

   dwFATSRecno = FATSCALL( "K\\1", &uFATSError, szFATSkey );


   /*
      ========================================================================
                Search
      ========================================================================
   */ 


   /*
       "O" Open Indexfile
    
      With this command you open an existing index file with
      the opening flags defined with the command Auto Refresh (Y).
      After the file was opened it can be accessed under the
      file number you specified. An index file already opened
      with the same file number is closed before this command
      is executed.
    
      Full path names must be specified using forward slashes (/)
      instead of Backslashes (\), because FATS normally uses the
      Backslash character as delimiter.
      You may change the delimiters by placing the desired character
      as the first character of the command string, e.g.
      szCmnd = "&O&C:\ARTICLES.KEY&1". Any character with an Ascii
      code less then 48 will be accepted.
    
      The syntax of the command string:
    
        szCmnd = "O\{FileName}\{FileNo}"
    
          Filename   filename, perhaps with an additional path
                     (e.g. C:/DATEN/ARTICLES.KEY or ARTICLES.KEY)
    
          FileNo     File number

   */  

   dwFATSRecno = FATSCALL( "O\\CUSTOMER.KEY\\1", &uFATSError, szFATSkey );


   /*
      -------> Print all customers, sorted in ascending order by NAME
   */ 

   printf( "\n\n" );
   printf( "This list shows some fields from the Customer Table,\n" );
   printf( "sorted in ascending alphabetical order on the Customers\n" );
   printf( "surname and forename.\n" );
   printf( "Please press the [ENTER] key ...\n" );
   cChar = getchar();

   /*
       "F" Search First
    
      This command enables your application to retrieve the
      record number corresponding to the first key value for
      the specified key number.
    
      The syntax of the command string:
    
        szCmnd = "F\{KeyNo}\{FileNo}"
    
          KeyNo      Key number
    
          FileNo     File number

   */  

   strcpy( szCmnd, "F\\2\\1" );

   do {

     dwFATSRecno = FATSCALL( szCmnd, &uFATSError, szFATSkey );

     if ( uFATSError == 0 ) {

       lseek( hCustomer, (dwFATSRecno - 1) * sizeof(cust), SEEK_SET );
       if ( read(hCustomer, &cust, sizeof(cust)) == sizeof(cust) ) {

         printf( "%s %s --> RecNo %lu\n", cust.NAME, cust.JOB, dwFATSRecno );
       }

       /*
           "A" Search Next After
        
          With this command your application can retrieve the record
          number corresponding to the first key value which is greater
          than the key value you specify.
          If a duplicate key exists, the next higher record number of
          the next duplicate will be returned. The key value you specify
          with "KeyString" don't have to be a valid key in the index file.
        
          Unlike the "Search Next" command, this command can be used in
          a network environment.
        
          The syntax of the command string:
        
            szCmnd = "A\{KeyNo}\{RecNo}\{FileNo}\{KeyString}"
        
              KeyNo      Key number
        
              RecNo      Record number
        
              FileNo     File number
        
              KeyString  Key value

       */  

       sprintf( szCmnd, "A\\2\\%lu\\1\\%s", dwFATSRecno, szFATSkey );
     }

   } while ( uFATSError == 0 );


   /*
      --------> print all customers, sorted in ascending order by JOB
   */ 

   printf( "\n\n" );
   printf( "Two columns - JOB and NAME are displayed, sorted in ascending\n" );
   printf( "order by the JOB field.\n" );
   printf( "Please press the [ENTER] key ...\n" );
   cChar = getchar();

   strcpy( szCmnd, "F\\3\\1" );

   do {

     dwFATSRecno = FATSCALL( szCmnd, &uFATSError, szFATSkey );

     if ( uFATSError == 0 ) {

       lseek( hCustomer, (dwFATSRecno - 1) * sizeof(cust), SEEK_SET );

       if ( read(hCustomer, &cust, sizeof(cust)) == sizeof(cust) ) {

         printf( "%s %s --> RecNo %lu\n", cust.JOB, cust.NAME, dwFATSRecno );
       }

       /*
           "N" Search Next
        
          With this command your application can retrieve
          the record number corresponding to the first key
          value which is greater than the key value recently
          returned by one of the search commands, which have
          to be executed as the latest command.
          If a duplicate key exists, the next higher record
          number of the next duplicate will be returned.
        
          Each modification of the index file by inserting or
          deletion of keys makes an internal pointer invalid
          that is necessary for this instruction. You better
          use the command  Search Next After (A) because this
          can happen in the network environment from any station.
        
          If there is no key in sequence FATS will return an
          errorcode of 15.
        
          The syntax of the command string:
        
            szCmnd = "N\{FileNo}"
        
              FileNo     File number

       */  

       strcpy( szCmnd, "N\\1" );
     }

   } while ( uFATSError == 0 );


   /*
      --------> print list with records sorted by ZIP and CITY
   */ 

   printf( "\n\n" );
   printf( "Three columns - ZIP, CITY and NAME are displayed, sorted in\n" );
   printf( "descending order by ZIP then CITY.\n\n" );
   printf( "Please press the [ENTER] key ...\n" );
   cChar = getchar();

   /*
       "L" Search Last
    
      This command enables your application to retrieve the
      record number corresponding to the last key value for
      the specified key number. If duplicates exist for the
      last key value, the record number returned identifies
      the last duplicate, that is, the one inserted most
      recently.
    
      The syntax of the command string:
    
        szCmnd = "L\{KeyNo}\{FileNo}"
    
          KeyNo      Key number
    
          FileNo     File number

   */  

   strcpy( szCmnd, "L\\4\\1" );

   do {

     dwFATSRecno = FATSCALL( szCmnd, &uFATSError, szFATSkey );

     if ( uFATSError == 0 ) {

       lseek( hCustomer, (dwFATSRecno - 1) * sizeof(cust), SEEK_SET );
       if ( read(hCustomer, &cust, sizeof(cust)) == sizeof(cust) ) {

         printf( "%s %s %s --> RecNo %lu\n", cust.ZIP, cust.CITY,
                 cust.NAME, dwFATSRecno );
       }

       /*
           "E" Search Previous Before
        
          With this command your application can retrieve the record
          number corresponding to the first key value which is less
          than the key value you specify.
          If a duplicate key exists, the next lower record number of
          the previous duplicate will be returned. The key value you
          specify with "KeyString" don't have to be a valid key in the
          index file.
        
          Unlike the "Search Prev" command, this command can be used in
          a network environment.
        
          The syntax of the command string:
        
            szCmnd = "E\{KeyNo}\{RecNo}\{FileNo}\{KeyString}"
        
              KeyNo      Key number
        
              RecNo      Record number
        
              FileNo     File number
        
              KeyString  Key value

       */  

       sprintf( szCmnd, "E\\4\\%lu\\1\\%s", dwFATSRecno, szFATSkey );
     }

   } while ( uFATSError == 0 );


   /*
      --------> Close index file
   */ 

   dwFATSRecno = FATSCALL( "K\\1", &uFATSError, szFATSkey );

   close( hCustomer );

}

© 2008  GCS Software, Udo Gertz