/*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*\
\                                                                          /
/   Header file for                   Copyright (c)  Dmitry A. Kazakov     \
\   Table management                                 St.Petersburg         /
/                                                    Autumn, 1993          \
\                                                                          /
/   (C, ANSI C)                                                            \
\                                     Last revision :  18:48 31 Oct 2001   /
/                                                                          \
\   This library is free software; you can redistribute it and/or modify   /
/   it  under  the  terms  of  the GNU Library General Public License as   \
\   published  by  the Free Software Foundation; either version 2 of the   /
/   License, or (at your option) any later version.                        \
\                                                                          /
/   As a special exception, if other  files  instantiate  generics  from   \
\   this unit, or you link this unit with  other  files  to  produce  an   /
/   executable, this  unit  does  not  by  itself  cause  the  resulting   \
\   executable  to  be  covered  by the GNU General Public License. This   /
/   exception  does  not  however  invalidate  any other reasons why the   \
\   executable file might be covered by the GNU Public License.            /
/                                                                          \
\   This library is distributed in the hope that it will be useful,  but   /
/   WITHOUT   ANY   WARRANTY;  without  even  the  implied  warranty  of   \
\   MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE.  See  the  GNU   /
/   Library General Public License for more details.                       \
\                                                                          /
/   You  should  have  received a copy of the GNU Library General Public   \
\   License  along with this library; if not, write to the Free Software   /
/   Foundation,   Inc.,   59  Temple  Place  -  Suite  330,  Boston,  MA   \
\   02111-1307, USA                                                        /
/                                                                          \
\*\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/*/

#ifndef         Tab_h
#define         Tab_h

#include        "common.h"      /* Common header file           */
/*>

   TABLE MANAGEMENT. The software provides tables searched using  string
   keys. The binary search is used for names of known length. It is also
   possible to search a table for names of unknown length, i.e. to parse
   a string using the table. In this case the search  time  is  near  to
   logarthmic, but in worst case can  be  linear  (when  table  contains
   tokens  like  "a",  "aa", "aaa" and so on). Items in the table can be
   accessed either by their  offsets  (in  alphabethical  order)  or  by
   names. Text parsing is also supported. The following types (typedefs)
   are defined: 

   (o)  TabHeader  is  the table header. The table header is followed by
        the table TOC. 

   (o)  TabItemOfTOC  is the item of the table TOC. The value of element
        is the offset to a TabItemOfTOC. 
   
   (o)  element  is  an  offset  to a table item. It is returned by most
        table  manipulation  functions.  The  offset is counted from the
        table beginning in bytes.

   (o)  item is the pointer to a TabItemOfTOC.

   (o)  table is the pointer to a TabHeader.

<*/
typedef int	element;

typedef struct
{
   int          TotalSize;      /* Table size in bytes          */
   int          TOCSize;        /* Table TOC size in bytes      */
   int          FreeSpace;      /* Unused space in bytes        */
}  TabHeader;

typedef struct
{
   word         ControlField;   /* Data + Item name length      */
   word         DataField;      /* Data                         */
   word         NameField;      /* Name or Offset to it         */      
}  TabItemOfTOC;

typedef    TabHeader         *	table;
typedef    TabItemOfTOC      *	item;

#define    TAB_EMBEDDED_NAME    sizeof (word)
#define    TAB_ITEM_SIZE        sizeof (TabItemOfTOC)

#define    TAB_TOC_BEG(Table)                                   \
           (  (char *) (TabHeader *) (Table)			\
           +  sizeof (TabHeader)				\
	   )
#define    TAB_TOC_END(Table)                                   \
           (  (char *) (TabHeader *) (Table)			\
	   +  ((TabHeader *) (Table))->TOCSize			\
           +  sizeof (TabHeader)				\
           )
#define    TAB_END(Table)                                       \
           (  (char *) (TabHeader *) (Table)			\
	   +  ((TabHeader *) (Table))->TotalSize		\
	   )
#define    TAB_NAME_LENGTH(Item)                                \
           (0x3ff & ((item) Item)-> ControlField)

#define    TAB_NAME_ADDRESS(Table, Item)                        \
           (  TAB_NAME_LENGTH (Item) > TAB_EMBEDDED_NAME        \
           ?  TAB_END (Table) - ((item) (Item))-> NameField     \
           :  (char *) &(((item) (Item))-> NameField)           \
           )
/*>

   TabAdd -- Add new item by name

	Table	- Pointer to the table 
	Name	- Points the name of an item to be added
	Length	- The name length

   This  function  adds  new  a item to table. The parameter Name is the
   name of the item to be added. The parameter Length specifies the name
   length. 

   Returns :

        [+]  A  positive  value means a successful completion. The value
             is  the  character  offset from the table beginninig to the
             TOC element of the newly included item. 
        [0]  Table overflow. The table is not changed.
        [-]  A  negative value is returned if the specified name belongs
             to a table item. The value is the negated offset  from  the
             table beginning to the item. 

<*/
#ifndef NON_ANSI
element TabAdd
(
   table        Table, 
   const char * Name,
   const int    Length
);
#else
element TabAdd ();
#endif  /*> NON_ANSI <*/
/*>

   TabAddI -- Insert new item

	Table	- Points to the table
	Name	- Points to the item name
	Length	- The name length
	Offset	- The offset indicating where the item must be inserted

   This function adds a new item to table. The value  of  the  parameter
   Offset  indicates  where  the item should be inserted. It is the byte
   offset from the table beginning to the place in TOC where the new TOC
   item should be placed. Usually the offset is the negated result of  a
   failed TabFind call. 

   Returns :

        [+]  Offset
	[0]  Zero if there is no space for new item

   !!WARNING!!  No checks are made.  So,  you  should  use  rather  more
                sophisticated function TabAdd which calls first  TabFind
                to check name occlusions and then TabAddI.

<*/
#ifndef NON_ANSI
element TabAddI
(
   table        Table, 
   const char * Name,
   const int    Length,
   element      Offset
);
#else
element TabAddI ();
#endif  /*> NON_ANSI <*/
/*>

   TabCopy -- Copy table to another place

	FromTab	- Points to the table to be copied
	ToTab	- Points to the destination table
	Size	- The number of bytes available for the new table

   This function copies the table. The new table may overlap the old one
   only when ToTab <= FromTab (to  change  the  table  size  use  TabExt
   instead). The parameter Size defines the new table size. So it can be
   changed while copying. 

   Returns :
 
        [0]  New size is too small
        [1]  Successful operation

<*/
#ifndef NON_ANSI
int     TabCopy
(
   const table  FromTab,
   table        ToTab,
   const int    Size
);
#else
int     TabCopy ();
#endif  /*> NON_ANSI <*/
/*>

   TabDel -- Delete an item by name

        Table   - Points to table
        Name    - Points to the name of the item to be deleted
        Length  - The name length

   This function deletes an item from table. The item  is  specified  by
   its name.

   Returns :

        [0]  Zero value means successful operation.
        [-]  A negative value is returned if table does not contain  the
             specified  item.  The  value is the negated offset from the
             table  beginning  to  the item whith the greatest name from
             all the items those names are less than the specified one.

<*/
#ifndef NON_ANSI
element TabDel
(
   table        Table, 
   const char * Name,
   const int    Length
);
#else
element TabDel ();
#endif  /*> NON_ANSI <*/
/*>

   TabDelI -- Delete an item by offset

        Table   -- Points to the table
        Offset  -- The offset of the item to be deleted

   This  function deletes an item from table. It is assumed that TabFind
   was  called  first to determine the offset of the item to be deleted.
   No  checks  are  made,  so  you  should rather use more sophisticated
   function TabDel. 

<*/
#ifndef NON_ANSI
void    TabDelI
(
   table        Table,
   element      Offset
);
#else
void    TabDelI ();
#endif  /*> NON_ANSI <*/
/*>

   TabExt -- Change table size

	Table	- Points to the table
	Size	- The desired table size in bytes

   This  function  changes  the table size. The parameter Size specifies
   the new size. If it is less than the current  table  size  the  table
   will be truncated, otherwise,  enlarged.  In  the  later  case  there
   should be enough free memory space after the end of the table. If the
   new  size  is  less than the used one, the table will be truncated as
   much as possible. 

   Returns :

        New size of the table

<*/
#ifndef NON_ANSI
int     TabExt
(
   table        Table,
   const int    Size
);
#else
int     TabExt ();
#endif  /*> NON_ANSI <*/
/*>

   TabFind -- Search for a name in a table

	Table	- Points to the table
	Name	- Points to the name
	Length	- THe name length

   This function searches for a specified name in the table. Table items
   are arranged in alphabetical order. Therefore,  a  binary  search  is
   possible. 

   Returns :

        [+]  TabFind returns a positive number if search was successful.
             The  returned  value  is  a  character  offset  from  table
             beginning to the found item.
        [-]  A negative value is returned if table does not contain  the
             specified item. This value is the negated offset  from  the
             table  beginning  to  the item whith the greatest name from
             all items those names are less than the specified one.

<*/
#ifndef NON_ANSI
element TabFind
(
   const table  Table,
   const char * Name,
   const int    Length
);
#else
element TabFind ();
#endif  /*> NON_ANSI <*/
/*>

   TabInit -- Initialize empty table

	Table	- Points to the table to be initialized
	Size	- The table size (bytes)

   This function initializes the table. The new table will be empty. 

   Returns :

        [0]  New size is too small.
        [+]  Available free space in the table.

<*/
#ifndef NON_ANSI
int     TabInit
(
   table        Table, 
   const int    Size
);
#else
int     TabInit ();
#endif  /*> NON_ANSI <*/
/*>

   TabItem -- Table item by offset

        Table   - Pointer to the table
        Offset  - Of the item (for example, returned by TabFind)

   This  function returns the pointer to an item previously found by the
   TabFind or by something like it. BE CAREFUL! TabItem is just a macro. 

   Returns :

       Pointer to the table item

<*/
#define    TabItem(Table, Item)                                 \
           (  (item)						\
              (  (char *) (TabHeader *) (Table)			\
              +  (int) (Item)					\
           )  )
/*>

   TabOffset -- Offset of a table item

        Table   - Pointer to the table
        Item    - Pointer to an item

   This function returns the offset to the item (in bytes).  The  offset
   is calculated from the table beginning. BE CAREFUL! The TabOffset  is
   just a macro. 

   Returns :

       Pointer to the table item

<*/
#define    TabOffset(Table, Item)                                 \
                ( (element) ((char *)(Item) - (char *)(Table))  )
/*>

   TabParse -- Context free table search

	Length	- The line length
	String	- Pointer to the line
	Pointer	- The starting line position (0..)
	Table	- Points to the table

   This function searches for a specified name in the table. A partially
   binary search is used. The name to be  searched  is  specified  as  a
   string (the parameter String) indexed by the parameter Pointer. So it
   is assumed that the name starts  with  String  [Pointer],  while  the
   right name boundary is unknown. The  parameter  Length  just  defines
   where the string ends, rather than the actual  length  of  the  name.
   TabParse tries to match a longest item from  the  table.  On  success
   TabParse resets the parameter Pointer to point to the first unmatched
   string  character. So consequtive calls of TabParse will move Pointer
   from  left  to the right. See also TabParseEx which supports multiple
   lines and user-defined wild-card characters. 
   
   Returns :

        [+]  TabParse returns  a  positive  number  if  the  search  was
             successful.  The  returned  value is a byte offset from the
             table beginning to the found item. 
        [0]  Zero  value  is  returned  if  table  does  not contain the
             specified name. 

<*/
#ifndef NON_ANSI
element TabParse
(
   const int    Length,
   const char * String,
   int        * Pointer,
   const table  Table
);
#else
element TabParse ();
#endif  /*> NON_ANSI <*/
/*>

   TabParseData -- The data structure used by TabParseEx

<*/
#ifndef NON_ANSI			/* The call-back	*/
struct TabDataRec
{
   int			Length;		/* Of the current line	*/
   const char	     *	Line;		/* The current line	*/
   int			Pointer;	/* The current position	*/
   char			WildCard;	/* To invoke call-back	*/
   int (*CallBack) (int *, const char **, int *, struct TabDataRec *);
};
typedef struct TabDataRec	TabParseData;
#else
typedef struct
{
   int			Length;		/* Of the current line	*/
   const char	     *	Line;		/* The current line	*/
   int			Pointer;	/* The current position	*/
   char			WildCard;	/* To invoke call-back	*/
   int (*CallBack) ();
}  TabParseData;
#endif  /*> NON_ANSI <*/
/*>

   TabParseEx -- Context free table search (with wild-cards)

	Data	- Points to the structure TabParseData
	Table	- Points to the table

   This function searches for a specified name in the table. A partially
   binary  search  is  used  (see  TabParse).  The parameter Data is the
   pointer  to  the structure TabParseData containing the description of
   the line to be matched, the wild-card character and the  user-defined
   call-back  function  to  match  the  wild-card. The structure has the
   following fields: 

   	Length		- The length of the current line
        Line		- The current line pointer
        Pointer		- The current position within the line (0..)
        WildCard	- The wild-card character
	CallBack	- Pointer to the user-defined call-back function

   When TabParseEx has to match an item character which is equal to  the
   value of the field WildCard against the current  line, it  calls  the
   user-defined call-back function pointed by the  field  CallBack.  The
   value of WildCard is ignored if CallBack is  zero.  The  user-defined
   call-back function has the following parameters: 

	Length	- Pointer to the length of the processed line
	String	- Pointer to the line
	Pointer	- Pointer to the current line position (0..)
        Data	- The pointer to the structure TabParseData

   The call-back function may  change  any  of  its  parameters  Length,
   String and Pointer, if parsing should continue to  a  new  line,  for
   instance. It should return: 

        [0]  The  wild-card  character  matches  the  line.  The  values
             pointed by the parameters Length, String and Pointer should
             be correctly set by the function. 
        [1]  The unmatched part of  the  line  is  less  than  the  wild
             character. Any  modifications  of  the  parameters  Length,
             String and Pointer are ignored. 
        [2]  The  unmatched  part  of  the line is greater than the wild
             character. Any  modifications  of  the  parameters  Length,
             String and Pointer are ignored. 
   
   After completion of TabParseEx, the fields of the  structure  pointed
   by the parameter Data indicate the current line and the  position  in
   it.  They  are  not  modified  if  parsing  fails.  In  any case Line
   [Pointer] is the first unmatched line position. 

   Returns :

        [+]  TabParse returns  a  positive  number  if  the  search  was
             successful.  The  returned  value is a byte offset from the
             table beginning to the found item.
        [0]  Zero  value  is  returned  if  table  does  not contain the
             specified name. 

<*/
#ifndef NON_ANSI
element TabParseEx
(
   TabParseData	     *	Data,
   const table		Table
);
#else
element TabParseEx ();
#endif  /*> NON_ANSI <*/

#endif  /*> Tab_h <*/
