home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume44
/
typhoon
/
part01
next >
Wrap
Internet Message Format
|
1994-09-17
|
63KB
From: zeppelin@login.dknet.dk (Thomas B. Pedersen)
Newsgroups: comp.sources.misc
Subject: v44i057: typhoon - Typhoon Relational Database Management System, Part01/09
Date: 17 Sep 1994 21:44:04 -0500
Organization: Sterling Software
Sender: kent@sparky.sterling.com
Approved: kent@sparky.sterling.com
Message-ID: <csm-v44i057=typhoon.214347@sparky.sterling.com>
X-Md4-Signature: 3ed59d07df131f309b0ca3f158f1f885
Submitted-by: zeppelin@login.dknet.dk (Thomas B. Pedersen)
Posting-number: Volume 44, Issue 57
Archive-name: typhoon/part01
Environment: SCO UNIX, Tandem NonStop UNIX, Sun Solaris, AIX, Linux, OS/2
Typhoon is a freely available relational database management system for
the UNIX and OS/2 environments.
This release has been prepared in a hurry to get it out as quickly as
possible. This means that the documentation is rather sparse, since I
haven't had the time to write extensive documentation yet. However, most
of you out there are pretty clever, so you'll probably do fine with the
man pages and the examples.
The system works fine and is currently used in a number of professional
applications in Denmark, some of them mission critical.
The system was originally inspired by Raima's db_VISTA (today Raima Data
Manager) but is relational rather than network based. Typhoon lacks some of
db_VISTA's features, but also contains a number of nice features not found in
db_VISTA.
All relations are defined in a so called Data Definition Language (ddl) file.
You define the database relations like you would write a C structure with
chars, ints, strings, multidimensional arrays, nested union and structures,
etc. Then you define primary, alternate and foreign keys for each relation.
The Data Definition Language Processor (ddlp) compiles the database defintion
into a binary file which constitutes the database description. The database
relations are accessed via C subroutines which manipulate individual records
within a table.
- Multiple open database
- Multi-field keys
- Nested structures in records
- Controlled unions
- Referential integrity
- Variable length fields
- Null keys (optional keys in db_VISTA, but easier to use)
- Dynamic opening and closing of database files
At present the database has no locking mechanism, believe it or not! The
projects I have used it in, simply didn't need it, even though they were
multi-user environments. But it's in the works!
I am currently working on extending the library to support the following:
- Locking
- Logging
- Transactions
- Paging (to improve performance)
The library functions will remain intact, except for a number of new functions.
I expect these things to be ready before the end of the year. Beta testers
are welcome.
The library comes with three additional utilities:
dbdview - Displayes the database definitions.
tyexport - Exports tables from a database.
tyimport - Imports tables into a database.
Originally the library also contained online backup, restore and a replication
server. These tools would need a lot of extra documentation, so I have left
them out for now (the code still contains support for these utilities).
However, if enough people show interest I will probably release them also.
Bug reports and mail should be sent to
Thomas B. Pedersen
zeppelin@login.dkuug.dk
Also, if you have any suggestions as to how I can improve the library,
documentation or anything else, please don't hesitate to mail me.
Thomas B. Pedersen
-------------------------------
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# Contents: typhoon typhoon/examples typhoon/man typhoon/src
# typhoon/src/bt_funcs.c typhoon/src/h typhoon/src/util
# typhoon/src/util/ddl.y typhoon/src/util/ddlp.c
# typhoon/src/util/lex.c
# Wrapped by kent@sparky on Sat Sep 17 21:38:15 1994
PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 1 (of 9)."'
if test ! -d 'typhoon' ; then
echo shar: Creating directory \"'typhoon'\"
mkdir 'typhoon'
fi
if test ! -d 'typhoon/examples' ; then
echo shar: Creating directory \"'typhoon/examples'\"
mkdir 'typhoon/examples'
fi
if test ! -d 'typhoon/man' ; then
echo shar: Creating directory \"'typhoon/man'\"
mkdir 'typhoon/man'
fi
if test ! -d 'typhoon/src' ; then
echo shar: Creating directory \"'typhoon/src'\"
mkdir 'typhoon/src'
fi
if test -f 'typhoon/src/bt_funcs.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'typhoon/src/bt_funcs.c'\"
else
echo shar: Extracting \"'typhoon/src/bt_funcs.c'\" \(14705 characters\)
sed "s/^X//" >'typhoon/src/bt_funcs.c' <<'END_OF_FILE'
X/*----------------------------------------------------------------------------
X * File : bt_funcs
X * Library : typhoon
X * OS : UNIX, OS/2, DOS
X * Author : Thomas B. Pedersen
X *
X * Copyright (c) 1994 Thomas B. Pedersen. All rights reserved.
X *
X * Permission is hereby granted, without written agreement and without
X * license or royalty fees, to use, copy, modify, and distribute this
X * software and its documentation for any purpose, provided that the above
X * copyright notice and the following two paragraphs appear (1) in all
X * source copies of this software and (2) in accompanying documentation
X * wherever the programatic interface of this software, or any derivative
X * of it, is described.
X *
X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN
X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X *
X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
X * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
X *
X * Description:
X *
X * Functions:
X * btree_add - Insert a new key in a B-tree.
X * btree_find - Find a key in a B-tree.
X * btree_exist - See if a key exists in a B-tree.
X * btree_read - Read the last key found.
X * btree_delall - Delete all keys in a B-tree.
X * get_rightmostchild - Find the rightmost child in a subtree.
X * get_leftmostchild - Find the leftmost child in a subtree.
X * btree_frst - Find the key with the lowest key value in a B-tree.
X * btree_last - Find the key with the highest key value in a B-tree.
X * btree_prev - Find the previous key in a B-tree.
X * btree_next - Find the next key in a B-btree.
X *
X * $Log: bt_funcs.c,v $
X * Revision 1.2 1994/09/17 16:00:11 tbp
X * typhoon.h and environ.h are now included from <>.
X *
X * Revision 1.1 1994/09/13 21:28:28 tbp
X * Added to repository.
X *
X *
X *--------------------------------------------------------------------------*/
X
Xstatic char rcsid[] = "$Id: bt_funcs.c,v 1.2 1994/09/17 16:00:11 tbp Exp $";
X
X#include <sys/types.h>
X#include <string.h>
X#include <stdio.h>
X#include <fcntl.h>
X#ifdef UNIX
X# include <unistd.h>
X#else
X# include <io.h>
X#endif
X#include <typhoon.h>
X#include "ty_dbd.h"
X#include "ty_type.h"
X#include "ty_prot.h"
X#include "ty_glob.h"
X#include "btree.h"
X
X/*--------------------------- Function prototypes --------------------------*/
Xstatic void get_rightmostchild PRM( (INDEX *, ulong); )
X void get_leftmostchild PRM( (INDEX *, ulong); )
Xstatic void synchronize PRM( (INDEX *); )
X
X
X/*------------------------------- btree_add --------------------------------*\
X *
X * Purpose : Inserts the key <key> in a B-tree index file.
X *
X * Parameters: I - B-tree index file descriptor.
X * key - Key value to insert.
X * ref - Reference to insert together with key.
X *
X * Returns : S_OKAY - Key value successfully inserted in B-tree.
X * S_DUPLICATE - The key value is already in the B-tree and
X * duplicates are not allowed.
X *
X */
X
Xbtree_add(I, key, ref)
XINDEX *I;
Xvoid *key;
Xulong ref;
X{
X ulong Ref;
X ix_addr Addr, moved, p;
X int i, mid;
X
X I->curr = 0;
X I->hold = 0;
X
X if( d_search(I, key, &p, &i) )
X {
X if( I->H.dups )
X {
X /* When a duplicate key is already in the tree, the current node
X * at this point may not be a leaf node. However, insertions
X * must always be performed in leaf nodes, so we must find the
X * rightmost entry in the left subtree
X */
X
X if( CHILD(I->node, i) )
X {
X get_rightmostchild(I, CHILD(I->node, i));
X i = I->path[I->level].i;
X p = I->path[I->level].a;
X }
X }
X else
X RETURN S_DUPLICATE;
X }
X
X I->H.keys++;
X Addr = 0;
X Ref = ref;
X memcpy(I->curkey, key, I->H.keysize);
X
X do
X {
X tupleins(I->node, i, 1);
X memcpy(KEY(I->node,i), I->curkey, I->H.keysize);
X CHILD(I->node,i+1) = Addr;
X REF(I->node,i) = Ref;
X
X if( NSIZE(I->node) < (ulong)I->H.order )
X {
X NSIZE(I->node)++;
X nodewrite(I, I->node, p);
X btree_putheader(I);
X RETURN S_OKAY;
X }
X
X /* split node */
X mid = I->H.order / 2;
X
X /* write left part of node at its old position */
X NSIZE(I->node) = mid;
X nodewrite(I, I->node, p);
X
X /* Save mid K, A and R */
X memcpy(I->curkey, KEY(I->node,mid), I->H.keysize);
X Addr = CHILD(I->node, mid);
X Ref = REF(I->node, mid);
X
X /* write right part of node at new position */
X NSIZE(I->node) = I->H.order - mid;
X memmove(&CHILD(I->node,0), &CHILD(I->node,mid+1), NSIZE(I->node) * I->tsize + sizeof(A_type));
X Addr = nodewrite(I, I->node, NEWPOS);
X
X if( (p = I->path[--I->level].a) != 0 )
X {
X noderead(I, I->node, p); /* p = I->path[p] */
X/* nodesearch(I,I->curkey,&i);*/
X i = I->path[I->level].i;
X }
X }
X while( p );
X
X /* Create a new root */
X noderead(I, I->node, 1);
X moved = nodewrite(I, I->node, NEWPOS);
X
X memcpy(KEY(I->node,0), I->curkey, I->H.keysize);
X CHILD(I->node,0) = moved;
X CHILD(I->node,1) = Addr;
X REF(I->node,0) = Ref;
X NSIZE(I->node) = 1;
X nodewrite(I, I->node, 1);
X I->H.timestamp++;
X btree_putheader(I);
X
X RETURN S_OKAY;
X}
X
X
X/*------------------------------- btree_find -------------------------------*\
X *
X * Purpose : Searches for the key value <key> in a B-tree index file.
X *
X * Parameters: I - B-tree index file descriptor.
X * key - Key value to find.
X * ref - Contains reference when function returns.
X *
X * Returns : S_OKAY - The key value was found. <ref> contains
X * reference.
X * S_NOTFOUND - The key value was not found.
X *
X */
Xbtree_find(I, key, ref)
XINDEX *I;
Xvoid *key;
Xulong *ref;
X{
X ix_addr dummy;
X int i;
X
X btree_getheader(I); /* Inserted temporarily */
X
X if( !d_search(I, key, &dummy, &i) )
X {
X /* Do only set hold if there are actually keys in the index */
X I->hold = I->H.keys > 0 ? 1 : 0;
X I->curr = 0;
X RETURN S_NOTFOUND;
X }
X
X *ref = REF(I->node, i);
X memcpy(I->curkey, KEY(I->node, I->path[I->level].i), I->H.keysize);
X I->hold = 0;
X I->curr = 1;
X RETURN S_OKAY;
X}
X
X
X/*------------------------------- btree_keyread -------------------------------*\
X *
X * Purpose : Copies the contents of the current key value to <buf>.
X *
X * Parameters: I - B-tree index file descriptor.
X * buf - Buffer to copy current key value to.
X *
X * Returns : S_NOCR - There is no current key.
X * S_OKAY - Key value copied to <buf>.
X *
X */
Xbtree_keyread(I, buf)
XINDEX *I;
Xvoid *buf;
X{
X if( !I->curr )
X RETURN S_NOCR;
X
X memcpy(buf, I->curkey, I->H.keysize);
X RETURN S_OKAY;
X}
X
X
X/*------------------------------ btree_delall ------------------------------*\
X *
X * Purpose : Deletes all key values in a B-tree index file.
X *
X * Parameters: I - B-tree index file descriptor.
X *
X * Returns : S_OKAY - All keys deleted.
X *
X */
Xbtree_delall(I)
XINDEX *I;
X{
X btree_getheader(I);
X I->H.first_deleted = 0;
X I->H.keys = 0;
X#ifdef UNIX
X os_close(open(I->fname, O_TRUNC));
X#else
X chsize(I->fh, I->H.nodesize);
X#endif
X I->curr = 0;
X I->hold = 0;
X btree_putheader(I);
X
X RETURN S_OKAY;
X}
X
X
X/*
X * The following macros are used to enhance the readability of the rest of the
X * functions in this file. B-tree traversal can be rather tricky, with lots
X * of pitfalls in it, but these macros should help a great deal. Here is a
X * short explanation of the macros.
X *
X * Keys The number of keys in the current node.
X * Child(i) The address of the i'th child in the current node.
X * Key(i) Pointer to the i'th key in the current node.
X * Ref(i) The reference of the i'th key in the current node.
X * Pos The current position within the current node.
X * Addr The current node address at the current level in the tree.
X * Level The current level in the tree.
X *
X */
X
X#define Keys NSIZE(I->node)
X#define Child(i) CHILD(I->node, i)
X#define Key(i) KEY(I->node, i)
X#define Ref(i) REF(I->node, i)
X#define Pos (I->path[I->level].i)
X#define Addr (I->path[I->level].a)
X#define Level (I->level)
X
X
X/*--------------------------- get_rightmostchild ---------------------------*\
X *
X * Purpose : Reads the rightmost key in a subtree with root address <addr>.
X *
X * Parameters: I - B-tree index file descriptor.
X * addr - The root address of the subtree.
X *
X * Returns : Nothing.
X *
X */
X
Xstatic void get_rightmostchild(I, addr)
XINDEX *I;
Xulong addr;
X{
X /* No tree has root at address 0 */
X if( !addr )
X return;
X
X do
X {
X noderead(I, I->node, addr);
X
X Level++;
X Addr = addr;
X Pos = Keys;
X }
X while( addr = Child(Keys) );
X}
X
X
X/*--------------------------- get_leftmostchild ----------------------------*\
X *
X * Purpose : Reads the leftmost key in a subtree with root address <addr>.
X *
X * Parameters: I - B-tree index file descriptor.
X * addr - The root address of the subtree.
X *
X * Returns : Nothing.
X *
X */
X
Xvoid get_leftmostchild(I, addr)
XINDEX *I;
Xulong addr;
X{
X /* No tree has root at address 0 */
X if( !addr )
X return;
X
X do
X {
X noderead(I, I->node, addr);
X
X Level++;
X Addr = addr;
X Pos = 0;
X }
X while( addr = Child(0) );
X}
X
X
X/*------------------------------- btree_frst -------------------------------*\
X *
X * Purpose : Read the smallest key value in a B-tree, i.e. the leftmost key.
X *
X * Parameters: I - B-tree index file descriptor.
X * ref - Contains reference when function returns.
X *
X * Returns : S_OKAY - The key was found. <ref> contains reference.
X * S_NOTFOUND - The B-tree is empty.
X *
X */
Xbtree_frst(I, ref)
XINDEX *I;
Xulong *ref;
X{
X I->curr = 0;
X I->hold = 0;
X Level = 1;
X Addr = 1;
X Pos = 0;
X
X /* Get the nost recent sequence number */
X btree_getheader(I);
X
X if( noderead(I, I->node, 1) == (ix_addr)-1 )
X RETURN S_NOTFOUND;
X
X get_leftmostchild(I, Child(0));
X
X I->curr = 1;
X *ref = Ref(Pos);
X memcpy(I->curkey, Key(Pos), I->H.keysize);
X
X RETURN S_OKAY;
X}
X
X
X/*------------------------------- btree_last -------------------------------*\
X *
X * Purpose : Read the greatest key value in a B-tree, i.e. the rightmost key.
X *
X * Parameters: I - B-tree index file descriptor.
X * ref - Contains reference when function returns.
X *
X * Returns : S_OKAY - The key was found. <ref> contains reference.
X * S_NOTFOUND - The B-tree is empty.
X *
X */
Xbtree_last(I, ref)
XINDEX *I;
Xulong *ref;
X{
X I->curr = 0;
X I->hold = 0;
X Level = 1;
X Addr = 1;
X
X /* Get the nost recent sequence number */
X btree_getheader(I);
X
X if( noderead(I, I->node, 1) == (ix_addr)-1 )
X RETURN S_NOTFOUND;
X
X Pos = Keys;
X get_rightmostchild(I, Child(Keys));
X
X /* Move pos one step leftwards so that Pos is the current key */
X Pos--;
X I->curr = 1;
X *ref = Ref(Pos);
X memcpy(I->curkey, Key(Pos), I->H.keysize);
X
X RETURN S_OKAY;
X}
X
X
Xstatic void synchronize(I)
XINDEX *I;
X{
X ulong old_ts = I->H.timestamp;
X ulong ref;
X
X btree_getheader(I);
X
X if( old_ts != I->H.timestamp )
X btree_find(I, I->curkey, &ref);
X}
X
X
X
X
X/*------------------------------- btree_prev -------------------------------*\
X *
X * Purpose : Find key value in a B-tree with less or equal (if duplicates)
X * key value that the current key. If there is no current key,
X * the function is equivalent to btree_last(). If the current
X * position before the call is the leftmost position in the tree,
X * S_NOTFOUND is returned.
X *
X * Parameters: I - B-tree index file descriptor.
X * ref - Contains reference if a key is found.
X *
X * Returns : S_OKAY - Key value found. <ref> contains reference.
X * S_NOTFOUND - The key with the smallest value has already
X * been reached.
X *
X */
X
Xbtree_prev(I,ref)
XINDEX *I;
Xulong *ref;
X{
X if( I->shared )
X synchronize(I);
X
X if( I->hold )
X goto out;
X
X if( !I->curr )
X return btree_last(I, ref);
X
X if( Child(Pos) > 0 ) /* Non-leaf node */
X {
X /* Get the rightmost child in the left subtree */
X get_rightmostchild(I, Child(Pos));
X }
X else if( Pos == 0 ) /* Leaf node at first pos */
X {
X /* Move upwards until a node with Pos > 0 or root is reached */
X while( Pos == 0 && Addr != 1 )
X {
X Level--;
X noderead(I, I->node, Addr);
X }
X
X if( Pos == 0 && Addr == 1 )
X {
X I->curr = 0;
X RETURN S_NOTFOUND;
X }
X }
X Pos--;
X
Xout:
X I->curr = 1;
X I->hold = 0;
X
X *ref = Ref(Pos);
X memcpy(I->curkey, Key(Pos), I->H.keysize);
X
X RETURN S_OKAY;
X}
X
X
X/*------------------------------- btree_next -------------------------------*\
X *
X * Purpose : Find key value in a B-tree with greater or equal (if duplicates)
X * key value that the current key. If there is no current key,
X * the function is equivalent to btree_frst(). If the current
X * position before the call is the rightmost position in the tree,
X * S_NOTFOUND is returned.
X *
X * Parameters: I - B-tree index file descriptor.
X * ref - Contains reference if a key is found.
X *
X * Returns : S_OKAY - Key value found. <ref> contains reference.
X * S_NOTFOUND - The key with the greatest value has already
X * been reached.
X *
X */
Xbtree_next(I,ref)
XINDEX *I;
Xulong *ref;
X{
X if( I->shared )
X synchronize(I);
X
X if( I->hold )
X {
X /* An unsuccessful keyfind must be handled as a special case:
X * If we are at the rightmost position in a node, move upwards until
X * we reach a node where the position is not the rightmost. This
X * key should be the proper next key in the B-tree.
X */
X
X while( Pos == Keys && Level > 1 )
X {
X Level--;
X noderead(I, I->node, Addr);
X }
X
X if( Level == 1 && Pos == Keys )
X RETURN S_NOTFOUND;
X
X goto out;
X }
X
X if( !I->curr )
X return btree_frst(I, ref);
X
X if( Child(Pos) > 0 ) /* Non-leaf node */
X {
X /* Get the leftmost child in the left subtree */
X Pos++;
X get_leftmostchild(I, Child(Pos));
X }
X else if( Pos >= Keys-1 ) /* Leaf node at first pos */
X {
X#if 0
X if( Pos == Keys-1 && Addr == 1 ) 94/03/17 TBP
X#else
X if( Pos >= Keys-1 && Addr == 1 )
X#endif
X {
X I->curr = 0;
X RETURN S_NOTFOUND;
X }
X
X /* Move upwards until a node with Pos < Keys-1 or root is reached */
X do
X {
X Level--;
X noderead(I, I->node, Addr);
X }
X while( Pos >= Keys && Addr != 1 );
X
X if( Pos == Keys && Addr == 1 )
X {
X I->curr = 0;
X RETURN S_NOTFOUND;
X }
X }
X else /* Leaf node */
X Pos++;
X
Xout:
X I->curr = 1;
X I->hold = 0;
X
X *ref = Ref(Pos);
X memcpy(I->curkey, Key(Pos), I->H.keysize);
X
X RETURN S_OKAY;
X}
X
X/* end-of-file */
X
END_OF_FILE
if test 14705 -ne `wc -c <'typhoon/src/bt_funcs.c'`; then
echo shar: \"'typhoon/src/bt_funcs.c'\" unpacked with wrong size!
fi
# end of 'typhoon/src/bt_funcs.c'
fi
if test ! -d 'typhoon/src/h' ; then
echo shar: Creating directory \"'typhoon/src/h'\"
mkdir 'typhoon/src/h'
fi
if test ! -d 'typhoon/src/util' ; then
echo shar: Creating directory \"'typhoon/src/util'\"
mkdir 'typhoon/src/util'
fi
if test -f 'typhoon/src/util/ddl.y' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'typhoon/src/util/ddl.y'\"
else
echo shar: Extracting \"'typhoon/src/util/ddl.y'\" \(14286 characters\)
sed "s/^X//" >'typhoon/src/util/ddl.y' <<'END_OF_FILE'
X/*----------------------------------------------------------------------------
X * File : ddl.y
X * Program : ddlp
X * OS : UNIX, OS/2, DOS
X * Author : Thomas B. Pedersen
X *
X * Copyright (c) 1994 Thomas B. Pedersen. All rights reserved.
X *
X * Permission is hereby granted, without written agreement and without
X * license or royalty fees, to use, copy, modify, and distribute this
X * software and its documentation for any purpose, provided that the above
X * copyright notice and the following two paragraphs appear (1) in all
X * source copies of this software and (2) in accompanying documentation
X * wherever the programatic interface of this software, or any derivative
X * of it, is described.
X *
X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN
X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X *
X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
X * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
X *
X * Description:
X * Grammar for ddl-files.
X *
X * $Id: ddl.y,v 1.2 1994/09/17 16:11:13 tbp Exp $
X *
X * $Log: ddl.y,v $
X * Revision 1.2 1994/09/17 16:11:13 tbp
X * Added include directive.
X *
X * Added included directive.
X *
X * Added include directive.
X *
X * Revision 1.1 1994/09/13 21:28:51 tbp
X * Added to repository.
X *
X * Added to repository.
X *
X *
X *--------------------------------------------------------------------------*/
X
X%{
X
X#include <string.h>
X#include <stdarg.h>
X#include <typhoon.h>
X#include "../ty_dbd.h"
X#include "../ty_type.h"
X#include "ddlp.h"
X#include "ddlpsym.h"
X#include "ddlpglob.h"
X
X/*--------------------------- Function prototypes --------------------------*/
Xstatic void add_keymember PRM( (sym_struct *, char *, int); )
X
X/*---------------------------- Global variables ----------------------------*/
Xstatic unsigned type; /* Holds FT_.. flags of current field */
Xstatic int keytype; /* Holds KT_... constants */
Xstatic sym_member *control_field; /* Field that controls current union */
X
X
Xstatic fieldid[10];
X
X%}
X
X%union {
X int val;
X char is_union;
X char s[IDENT_LEN+1];
X}
X
X%start database
X
X%token T_DATABASE T_KEY T_DATA T_FILE T_CONTAINS T_RECORD
X%token T_UNIQUE T_DEFINE T_CONTROLLED T_MAP T_ARROW
X%token T_PRIMARY T_ALTERNATE T_FOREIGN T_ON T_DELETE T_RESTRICT
X%token T_REFERENCES T_UPDATE T_CASCADE T_NULL
X%token T_CHAR T_SHORT T_INT T_LONG T_SIGNED T_UNSIGNED T_FLOAT
X%token T_DOUBLE T_UCHAR T_USHORT T_ULONG T_STRUCT T_UNION
X%token T_COMPOUND T_ASC T_DESC T_VARIABLE T_BY
X%token <s> T_IDENT T_STRING
X%token <val> T_NUMBER T_CHARCONST
X%token '[' ']' '{' '}' ';' ',' '.' '>'
X%token '+' '-' '*' '/' '(' ')'
X
X%type <val> expr opt_sortorder opt_unique opt_null pagesize action
X%type <val> map_id
X%type <is_union> struct_or_union
X%type <s> opt_ident key_type
X
X%left '+' '-'
X%left '*' '/'
X
X%%
X
Xdatabase : T_DATABASE T_IDENT '{' decl_list '}'
X { strcpy(dbname, $2); }
X ;
X
Xpagesize : /* use default page size */
X { $$ = 512; }
X | '[' expr ']'
X {
X if( $2 < 512 )
X {
X printf("Page size too small\n");
X $$ = 512;
X }
X else
X $$ = $2;
X }
X ;
X
Xdecl_list : decl
X | decl_list decl
X ;
X
Xdecl : T_DATA T_FILE pagesize T_STRING T_CONTAINS T_IDENT ';'
X {
X add_contains('d', $6, "");
X add_file('d', $4, $3);
X }
X | T_KEY T_FILE pagesize T_STRING T_CONTAINS T_IDENT '.' key_type ';'
X {
X char type = strcmp($8, "<ref>") ? 'k' : 'r';
X
X add_contains(type, $6, $8);
X add_file(type, $4, $3);
X }
X | record_head '{' member_list opt_key_list '}'
X {
X sym_endstruct();
X record[records-1].size = structnest[curnest+1]->size;
X structdef[record[records-1].structid].size = record[records-1].size;
X }
X | T_DEFINE T_IDENT expr { add_define($2, $3); }
X | T_MAP '{' map_list '}'
X ;
X
Xrecord_head : T_RECORD T_IDENT { add_record($2);
X add_structdef($2, 0, 0);
X sym_addstruct($2, 0); }
X ;
X
Xkey_type : T_IDENT { strcpy($$, $1); }
X | T_REFERENCES { strcpy($$, "<ref>"); }
X ;
X
Xmember_list : member
X | member_list member
X ;
X
Xmember : membertype T_IDENT opt_dimen ';'
X {
X sym_addmember($2, type, NULL);
X cur_str->last_member->id = fields;
X
X if( type != FT_STRUCT )
X add_field($2, type);
X
X /* Increase the number of level-0 fields of the record */
X if( curnest == 0 )
X structdef[record[records-1].structid].members++;
X
X type = 0;
X }
X | struct_specifier ';'
X ;
X
Xopt_dimen :
X | dimension opt_varlen_decl
X ;
X
Xdimension : array
X | dimension array
X ;
X
Xarray : '[' expr ']' { dim[dims++] = $2; }
X ;
X
X
Xopt_varlen_decl
X :
X | T_VARIABLE T_BY T_IDENT
X {
X/* if( curnest != 1 )
X yyerror("variable size fields cannot be nested");*/
X
X if( !(size_field = sym_findmember(structnest[0], $3)) )
X yyerror("unknown struct member '%s'", $3);
X }
X ;
X
X
X/*--------------------------------------------------------------------------*/
X/* Key declaration part */
X/*--------------------------------------------------------------------------*/
X
Xopt_key_list: opt_primary_key_decl
X opt_alternate_key_decl_list
X opt_foreign_key_decl_list
X ;
X
X/*--------------------------------------------------------------------------*/
X/* Primary key */
X/*--------------------------------------------------------------------------*/
X
Xopt_primary_key_decl
X : /* No primary key */
X | T_PRIMARY key_decl ';'
X {
X key[keys-1].type = KT_PRIMARY|KT_UNIQUE;
X }
X ;
X
X
X/*--------------------------------------------------------------------------*/
X/* Alternate key */
X/*--------------------------------------------------------------------------*/
X
Xopt_alternate_key_decl_list
X :
X | alternate_key_decl_list
X ;
X
Xalternate_key_decl_list
X : alternate_key_decl
X | alternate_key_decl_list alternate_key_decl
X ;
X
Xalternate_key_decl
X : T_ALTERNATE opt_unique key_decl opt_null ';'
X {
X key[keys-1].type = KT_ALTERNATE | $2 | $4;
X }
X ;
X
X
X/*--------------------------------------------------------------------------*/
X/* Foreign key */
X/*--------------------------------------------------------------------------*/
X
Xopt_foreign_key_decl_list
X :
X | foreign_key_decl_list
X ;
X
Xforeign_key_decl_list
X : foreign_key_decl
X | foreign_key_decl_list foreign_key_decl
X ;
X
X
Xforeign_key_decl
X : T_FOREIGN key_decl T_REFERENCES T_IDENT
X T_ON T_UPDATE action
X T_ON T_DELETE action opt_null ';'
X {
X /* Set the record's first_foreign field */
X if( record[records-1].first_foreign == -1 )
X record[records-1].first_foreign = keys-1;
X
X key[keys-1].type = KT_FOREIGN | $7 | $10 | $11;
X check_foreign_key($4, &key[keys-1]);
X }
X ;
X
Xaction : T_RESTRICT { $$ = KT_RESTRICT; }
X | T_CASCADE { $$ = KT_CASCADE;
X yyerror("'cascade' not supported");
X }
X ;
X
X
X/*--------------------------------------------------------------------------*/
X/* Key declaration rules used by primary, alternate and foreign keys */
X/*--------------------------------------------------------------------------*/
X
Xopt_null : /* not optional */
X {
X $$ = 0;
X }
X | T_NULL T_BY T_IDENT
X {
X sym_member *mem;
X int type;
X
X if( !(mem = sym_findmember(cur_str, $3)) )
X yyerror("'%s' is not a member the record", $3);
X else
X {
X key[keys-1].null_indicator = mem->id;
X type = FT_GETBASIC(field[mem->id].type);
X
X if( type != FT_CHAR && type != FT_CHARSTR )
X yyerror("field determiner must be char or string");
X }
X
X $$ = KT_OPTIONAL;
X }
X ;
X
X
Xkey_decl : key_decl_head comkey_member_list '}'
X {
X sym_endstruct();
X
X /* Set the size of the compound key.
X * Foreign keys have special size.
X */
X if( KT_GETBASIC(key[keys-1].type) == KT_FOREIGN )
X key[keys-1].size = sizeof(REF_ENTRY);
X else
X key[keys-1].size = last_str->size;
X }
X | T_KEY T_IDENT
X {
X sym_member *mem;
X
X if( !(mem = sym_findmember(cur_str, $2)) )
X yyerror("unknown field '%s'", $2);
X
X add_key($2);
X add_keyfield(mem->id, 1);
X
X key[keys-1].size = mem->size;
X field[mem->id].type |= FT_KEY;
X field[mem->id].keyid = keys-1;
X }
X ;
X
Xkey_decl_head
X : T_KEY T_IDENT '{'
X {
X /* Ensure that the key name is not also a field name */
X if( sym_findmember(cur_str, $2) )
X yyerror("the key '%s' is already a field name", $2);
X
X sym_addstruct($2, 0);
X add_key($2);
X }
X ;
X
X
X/*--------------------------------------------------------------------------*/
X/* Compound key declaration */
X/*--------------------------------------------------------------------------*/
X
Xcomkey_member_list
X : comkey_member
X | comkey_member_list ',' comkey_member
X ;
X
Xcomkey_member
X : T_IDENT opt_sortorder
X {
X add_keymember(structnest[curnest-1], $1, $2);
X }
X ;
X
Xopt_unique : { $$ = 0; /* Not unique */}
X | T_UNIQUE { $$ = KT_UNIQUE; /* Unique */ }
X ;
X
Xopt_sortorder
X : /* default */ { $$ = 1; /* Ascending */ }
X | T_ASC { $$ = 1; /* Ascending */ }
X | T_DESC { $$ = 0; /* Descending */ }
X ;
X
X/*--------------------------------------------------------------------------*/
X/* Structure member definition */
X/*--------------------------------------------------------------------------*/
X
Xmembertype : int_type
X | int_sign { if( type == FT_UNSIGNED )
X type |= FT_INT; }
X | int_sign int_type
X | float_type
X | u_type
X | T_LONG float_type { type |= FT_LONG; }
X ;
X
Xint_type : T_CHAR { type |= FT_CHAR; }
X | T_SHORT { type |= FT_SHORT; }
X | T_INT { type |= FT_INT; }
X | T_LONG { type |= FT_LONG; }
X ;
X
Xint_sign : T_SIGNED
X | T_UNSIGNED { type |= FT_UNSIGNED; }
X ;
X
Xfloat_type : T_FLOAT { type |= FT_FLOAT; }
X | T_DOUBLE { type |= FT_DOUBLE; }
X ;
X
Xu_type : T_UCHAR { type |= FT_UNSIGNED|FT_CHAR; }
X | T_USHORT { type |= FT_UNSIGNED|FT_SHORT; }
X | T_ULONG { type |= FT_UNSIGNED|FT_LONG; }
X ;
X
Xexpr : expr '+' expr { $$ = $1 + $3; }
X | expr '-' expr { $$ = $1 - $3; }
X | expr '*' expr { $$ = $1 * $3; }
X | expr '/' expr { $$ = $1 / $3; }
X | '(' expr ')' { $$ = $2; }
X | T_NUMBER
X ;
X
X/*--------------------------------------------------------------------------*/
X/* struct or union declaration */
X/*--------------------------------------------------------------------------*/
X
Xstruct_specifier
X : struct_or_union_opt_ident '{' member_list '}' T_IDENT opt_dimen
X {
X sym_struct *str;
X Field *fld;
X Structdef *strdef;
X
X sym_endstruct();
X
X str = structnest[curnest + 1];
X fld = &field[str->fieldid];
X strdef = &structdef[ fld->structid ];
X
X strcpy(fld->name, $5);
X strdef->size = str->size;
X strdef->members = str->members;
X
X sym_addmember($5, FT_STRUCT, structnest[curnest+1]);
X
X fld->size = cur_str->last_member->size;
X fld->elemsize = cur_str->last_member->elemsize;
X fld->offset = cur_str->last_member->offset;
X
X if( size_field )
X {
X fld->type |= FT_VARIABLE;
X fld->keyid = size_field->id;
X size_field = NULL;
X }
X }
X | struct_or_union T_IDENT T_IDENT opt_dimen
X {
X sym_struct *str = sym_findstruct($2, $1);
X
X if( str )
X {
X sym_addmember($3, FT_STRUCT, str);
X/* add_field($3, FT_STRUCT);*/
X }
X /* else error message */
X }
X ;
X
Xstruct_or_union_opt_ident
X : struct_or_union opt_ident
X {
X add_field("<struct>", FT_STRUCT);
X sym_addstruct($2, $1);
X cur_str->fieldid = fields-1;
X field[fields-1].structid = structdefs;
X
X add_structdef($2, $1, $1 ? control_field->id : 0);
X
X /* Increase the number of level-0 field of the record.
X * Actually, at this point the grammar we have moved to
X * level 1.
X */
X if( curnest == 1 )
X structdef[record[records-1].structid].members++;
X }
X ;
X
Xstruct_or_union
X : T_STRUCT
X {
X $$ = 0;
X }
X | T_UNION T_CONTROLLED T_BY T_IDENT
X {
X $$ = 1;
X if( !(control_field = sym_findmember(cur_str, $4)) )
X yyerror("'%s' is not a member of the union/struct '%s'",
X $4, cur_str->name);
X }
X ;
X
Xopt_ident : { *$$ = 0; }
X | T_IDENT { strcpy($$, $1); }
X ;
X
X
X
X/*--------------------------------------------------------------------------*/
X/* map_list */
X/*--------------------------------------------------------------------------*/
X
Xmap_list : map
X | map_list map
X ;
X
Xmap : map_id T_ARROW map_id ';' { header.sorttable[$1] = $3; }
X ;
X
Xmap_id : T_CHARCONST { $$ = $1; }
X | T_NUMBER { $$ = $1; }
X ;
X
X
X%%
X
X#include <stdio.h>
X
X
X
Xstatic void add_keymember(str, name, sortorder)
Xsym_struct *str;
Xchar *name;
Xint sortorder;
X{
X sym_member *mem;
X
X if( mem = sym_findmember(str, name) )
X {
X dims = mem->dims;
X memcpy(dim, mem->dim, sizeof(*dim) * dims);
X sym_addmember(name, mem->type, mem->struc);
X add_keyfield(mem->id, sortorder);
X }
X else
X yyerror("unknown struct member '%s'", name);
X}
X
X
X
X
Xextern errors;
X
Xyyerror(char *fmt ELLIPSIS)
X{
X va_list ap;
X
X printf("%s %d: ", ddlname, lex_lineno);
X va_start(ap, fmt);
X vprintf(fmt, ap);
X puts("");
X va_end(ap);
X errors++;
X return 0;
X}
X
X/* end-of-file */
END_OF_FILE
if test 14286 -ne `wc -c <'typhoon/src/util/ddl.y'`; then
echo shar: \"'typhoon/src/util/ddl.y'\" unpacked with wrong size!
fi
# end of 'typhoon/src/util/ddl.y'
fi
if test -f 'typhoon/src/util/ddlp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'typhoon/src/util/ddlp.c'\"
else
echo shar: Extracting \"'typhoon/src/util/ddlp.c'\" \(21611 characters\)
sed "s/^X//" >'typhoon/src/util/ddlp.c' <<'END_OF_FILE'
X/*----------------------------------------------------------------------------
X * File : ddlp.c
X * Program : ddlp
X * OS : UNIX, OS/2, DOS
X * Author : Thomas B. Pedersen
X *
X * Copyright (c) 1994 Thomas B. Pedersen. All rights reserved.
X *
X * Permission is hereby granted, without written agreement and without
X * license or royalty fees, to use, copy, modify, and distribute this
X * software and its documentation for any purpose, provided that the above
X * copyright notice and the following two paragraphs appear (1) in all
X * source copies of this software and (2) in accompanying documentation
X * wherever the programatic interface of this software, or any derivative
X * of it, is described.
X *
X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN
X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X *
X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
X * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
X *
X * Description:
X * Grammar for ddl-files.
X *
X * $Log: ddlp.c,v $
X * Revision 1.2 1994/09/17 16:00:51 tbp
X * typhoon.h and environ.h are now included from <>.
X *
X * Revision 1.1 1994/09/13 21:28:52 tbp
X * Added to repository.
X *
X * Added to repository.
X *
X *
X *--------------------------------------------------------------------------*/
X
Xstatic char rcsid[] = "$Id: ddlp.c,v 1.2 1994/09/17 16:00:51 tbp Exp $";
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X#include <fcntl.h>
X#include <stdarg.h>
X#ifndef UNIX
X# include <sys\types.h>
X# include <sys\stat.h>
X# include <stdlib.h>
X# include <io.h>
X#endif
X#define DEFINE_GLOBALS
X#include <typhoon.h>
X#include "../ty_dbd.h"
X#include "../ty_type.h"
X#include "ddlp.h"
X#include "ddlpsym.h"
X#include "ddlpglob.h"
X#include "ddl_y.h"
X
X/*-------------------------- Function prototypes ---------------------------*/
Xint yyparse PRM( (void); )
Xvoid align_offset PRM( (unsigned *, int); )
Xvoid check_consistency PRM( (void); )
Xvoid print_fieldname PRM( (FILE *, int, Id); )
Xvoid fix_file PRM( (void); )
Xvoid fix_fields PRM( (void); )
X
X/*---------------------------- Global variables ----------------------------*/
XFILE *lex_file, *hfile;
Xint dbdfile;
X
Xstatic char paramhelp[] = "\
XSyntax: ddlp [option]... file[.ddl]\n\
XOptions:\n\
X -a[1|2|4] Set structure alignment (default is %d)\n\
X -f Only generate field constants for keys\n\
X -h<file> Use <file> as header file\n";
X
X
X
Xchar *strupr(s)
Xchar *s;
X{
X char *olds = s;
X
X while( *s )
X {
X *s = toupper(*s);
X s++;
X }
X
X return olds;
X}
X
X
X#ifdef UNIX
X#ifndef __STDC__
Xchar *strstr(s1, s2)
Xchar *s1, *s2;
X{
X int len = strlen(s2);
X
X while( *s1 )
X {
X if( *s2 == *s1 )
X if( !memcmp(*s1,s2,len) )
X return s1;
X s1++;
X }
X return NULL;
X}
X#endif
X#endif
X
X
Xistrcmp(s1, s2)
Xchar *s1, *s2;
X{
X while( tolower(*s1) == tolower(*s2) && *s1 && *s2 )
X s1++, s2++;
X
X return tolower(*s1) - tolower(*s2);
X}
X
X
X/*------------------------------ align_offset ------------------------------*\
X *
X * Purpose : Align an address to fit the next field type.
X *
X * Parameters: offset - Offset to align.
X * type - Field type (FT_...).
X *
X * Returns : offset - The aligned offset.
X *
X */
Xvoid align_offset(offset, type)
Xunsigned *offset;
Xint type;
X{
X int rem = *offset % align;
X int size;
X
X/* if( type == FT_STRUCT )
X return;*/
X
X if( !rem || FT_GETBASIC(type) == FT_CHAR || !*offset )
X return;
X
X if( type == FT_STRUCT )
X size = sizeof(long);
X else
X size = typeinfo[FT_GETBASIC(type) - 1].size;
X
X if( rem == size )
X return;
X
X if( size < align - rem )
X *offset += rem;
X else
X *offset += align - rem;
X}
X
X
X/*--------------------------------- add_key --------------------------------*\
X *
X * Purpose : Adds a key definition to the record currently being defined.
X *
X * Parameters: name - Key name
X *
X * Returns : Nothing.
X *
X */
Xvoid add_key(name)
Xchar *name;
X{
X Key *k = key + keys++;
X
X /* Add an entry to the key table */
X k->first_keyfield = keyfields;
X k->fields = 0;
X k->size = 0;
X strcpy(k->name, name);
X
X /* Increase the number of keys in the record */
X record[records-1].keys++;
X}
X
X
X/*------------------------------- add_keyfield -----------------------------*\
X *
X * Purpose : Adds a field to the key currently being defined.
X *
X * Parameters: id - Field id.
X * ascending - Is key sorted in ascending order?
X *
X * Returns : Nothing.
X *
X */
X
Xvoid add_keyfield(id, ascending)
XId id;
Xint ascending;
X{
X KeyField *keyfld = keyfield + keyfields++;
X
X keyfld->field = id;
X keyfld->asc = ascending;
X
X /* The offset is only used in compound keys */
X if( key[keys-1].fields )
X keyfld->offset = cur_str->last_member->offset;
X else
X keyfld->offset = 0;
X
X /* Increase the number of fields of the key currently being defined */
X key[keys-1].fields++;
X}
X
X
Xvoid add_define(name, value)
Xchar *name;
Xint value;
X{
X strcpy(define[defines].name, name);
X define[defines++].value = value;
X}
X
X
Xvoid add_file(type, name, pagesize)
Xint type;
Xchar *name;
Xunsigned pagesize;
X{
X file[files].id = -1; /* Unresolved */
X file[files].type = type;
X file[files].pagesize= pagesize;
X strcpy(file[files++].name, name);
X}
X
X
X/*------------------------------ add_contains ------------------------------*\
X *
X * Purpose : Add a new entry to the contains table. This table is used to
X * determine which records and keys references and are referenced
X * by the file table entries.
X *
X * Parameters: type - 'k' = key, 'r' = record.
X * record - Record name.
X * key - Key name ("" if type is 'r').
X *
X * Returns : Nothing.
X *
X */
Xvoid add_contains(type, record, key)
Xint type;
Xchar *record, *key;
X{
X Contains *con = contains + conts++;
X
X strcpy(con->record, record);
X strcpy(con->key, key);
X con->fileid = files;
X con->type = type;
X con->line = lex_lineno;
X}
X
X
X/*------------------------------- add_record -------------------------------*\
X *
X * Purpose : This function adds a new entry to the record table. The fileid
X * is set to -1 to indicate that the index into file[] is
X * unresolved. This file be fixed by fix_file().
X *
X * Parameters: name - Record name.
X *
X * Returns : Nothing.
X *
X */
Xvoid add_record(name)
Xchar *name;
X{
X Record *rec = record + records++;
X int i;
X
X /* Add an entry to the record table */
X rec->first_field = fields;
X rec->first_key = keys;
X rec->first_foreign = -1;
X rec->size = 0;
X rec->is_vlr = 0;
X rec->fileid = -1;
X rec->structid = structdefs;
X strcpy(rec->name, name);
X
X /* If this record has a reference file, <ref_file> must be set */
X for( i=0; i<conts; i++ )
X if( !strcmp(contains[i].record, name) && !strcmp(contains[i].key, "<ref>") )
X break;
X
X if( i < conts )
X rec->ref_file = contains[i].fileid;
X else
X rec->ref_file = -1;
X
X /* No variable length fields have occurred in this record so far */
X varlen_field_occurred = 0;
X}
X
X
X/*------------------------------- add_field --------------------------------*\
X *
X * Purpose : Adds a new entry to the field table.
X *
X * If the <size_field> variable is not empty it contains the
X * name of the field that determines the size of the field being
X * added. Thus, if <size_field> is non-empty, the field being
X * added is of variable length.
X *
X * Parameters: name - Field name.
X * type - Field type. Contains FT_... flags.
X *
X * Returns : Nothing.
X *
X */
Xvoid add_field(name, type)
Xchar *name;
Xint type;
X{
X sym_member *mem = cur_str->last_member;
X Field *fld = field + fields;
X int i;
X
X /* If the field is a char string the FT_CHARSTR flag must be set */
X if( FT_GETBASIC(type) == FT_CHAR && mem->size > 1 )
X {
X type &= ~FT_BASIC; /* Clear the basic flags and set */
X type |= FT_CHARSTR; /* the FT_CHARSTR flag instead */
X }
X
X fld->recid = records-1; /* Link field to current record */
X fld->type = type;
X fld->nesting = curnest;
X strcpy(fld->name, name);
X
X if( type != FT_STRUCT )
X {
X fld->size = mem->size;
X fld->offset = mem->offset;
X fld->elemsize = mem->elemsize;
X }
X
X record[records-1].fields++;
X
X /* Check if the current field is of variable length */
X if( size_field )
X {
X if( mem->dims != 1 )
X yyerror("variable size fields must be one-dimension arrays");
X
X if( (size_field->type & (FT_SHORT|FT_UNSIGNED)) != (FT_SHORT|FT_UNSIGNED) )
X yyerror("size field '%s' must be 'unsigned short'", size_field->name);
X
X /* Store id of size field in keyid (dirty, but saves space) */
X fld->keyid = size_field->id;
X fld->type |= FT_VARIABLE;
X record[records-1].is_vlr = 1;
X
X size_field = NULL;
X
X /* Ensure that no fixed length fields follow */
X varlen_field_occurred = 1;
X }
X else if( varlen_field_occurred && curnest == 0 )
X yyerror("fixed length field '%s' follows variable length field", name);
X
X fields++;
X}
X
X
X
X/*------------------------------ add_structdef -----------------------------*\
X *
X * Purpose : Add a structure definition.
X *
X * Parameters: name - Structure name.
X * is_union - Is the structure a union.
X * control_field- If <is_union> is true this is the id of the
X * control field.
X *
X * Returns : Nothing.
X *
X */
Xvoid add_structdef(name, is_union, control_field)
Xchar *name;
Xint is_union, control_field;
X{
X Structdef *str = structdef + structdefs++;
X
X strcpy(str->name, name);
X str->first_member = fields;
X str->is_union = is_union;
X
X if( is_union )
X str->control_field = control_field;
X}
X
X
X
X
X/*---------------------------- check_foreign_key ---------------------------*\
X *
X * Purpose : Check that a foreign key matches its target (primary key).
X *
X * Parameters: name - Target record name.
X * foreign_key - Pointer to foreign key.
X *
X * Returns : Nothing.
X *
X */
Xvoid check_foreign_key(name, foreign_key)
Xchar *name;
XKey *foreign_key;
X{
X Record *rec; /* Ptr to parent record */
X Key *primary_key; /* Ptr to parent's primary key */
X KeyField *primary_fld; /* Ptr to first field of primary_key */
X KeyField *foreign_fld; /* Ptr to first field of foreign_key */
X int i;
X
X /* Check if the record has a primary key */
X for( rec=record, i=0; i<records; rec++, i++ )
X if( !strcmp(rec->name, name) )
X break;
X
X if( i == records )
X {
X yyerror("unknown target record '%s'", name);
X return;
X }
X
X if( !rec->keys )
X {
X yyerror("The target '%s' has no primary key", name);
X return;
X }
X
X primary_key = &key[ rec->first_key ];
X
X if( KT_GETBASIC(primary_key->type) != KT_PRIMARY )
X {
X yyerror("The target '%s' has no primary key", name);
X return;
X }
X
X if( primary_key->fields != foreign_key->fields )
X {
X yyerror("The foreign key '%s' does not match its target", name);
X return;
X }
X
X primary_fld = &keyfield[ primary_key->first_keyfield ];
X foreign_fld = &keyfield[ foreign_key->first_keyfield ];
X
X /* Find the reference file of the parent */
X foreign_key->parent = rec - record;
X rec->dependents++;
X
X
X if( rec->ref_file == -1 )
X {
X yyerror("The parent table '%s' has no reference file", name);
X return;
X }
X
X foreign_key->fileid = rec->ref_file;
X
X /* Compare the format of the primary key with that of the foreign key */
X for( i=0; i<primary_key->fields; i++, foreign_fld++, primary_fld++ )
X {
X if( FT_GETSIGNEDBASIC(field[primary_fld->field].type) !=
X FT_GETSIGNEDBASIC(field[foreign_fld->field].type) )
X break;
X
X /* Set sort order */
X foreign_fld->asc = primary_fld->asc;
X }
X
X if( i < primary_key->fields )
X {
X yyerror("The foreign key '%s' does not match its target", name);
X return;
X }
X}
X
X
X/*-------------------------------- fix_file --------------------------------*\
X *
X * Purpose : This function sets the fileid of all the records and the keys.
X *
X * Parameters: None.
X *
X * Returns : Nothing.
X *
X */
Xvoid fix_file()
X{
X Contains *con;
X Record *rec;
X int i, j, n;
X
X for( i=0, con=contains; i<conts; i++, con++ )
X {
X /* First find the record entry of this contains */
X for( j=0, rec=record; j<records; j++, rec++ )
X if( !strcmp(rec->name, con->record) )
X break;
X
X if( j == records )
X {
X printf("unknown record '%s' in contains statement\n", con->record);
X continue;
X }
X
X /* Link the record or the key to a file and vice versa */
X switch( con->type )
X {
X case 'r':
X break;
X
X case 'd':
X rec->fileid = con->fileid;
X
X if( rec->is_vlr )
X file[i].type = 'v';
X break;
X
X case 'k':
X for( n=rec->keys, j=rec->first_key; n--; j++ )
X if( !strcmp( key[j].name, con->key) )
X break;
X
X if( KT_GETBASIC(key[j].type) == KT_FOREIGN )
X {
X int tmp = lex_lineno;
X
X lex_lineno = con->line;
X yyerror("a foreign key cannot be contained in a file");
X lex_lineno = tmp;
X break;
X }
X
X if( n < 0 && strcmp(con->key, "<ref>") )
X {
X printf("unknown key '%s' contained in file '%s'\n",
X con->key, file[con->fileid].name);
X continue;
X }
X
X key[j].fileid = con->fileid;
X break;
X }
X
X con->entry = j;
X file[i].id = j;
X }
X
X /* Check that each record is contained is contained in a data file and
X * each key is contained in a key file
X */
X for( i=0, rec=record; i<records; i++, rec++ )
X {
X Key *keyptr;
X
X /* Calculate the size of the preamble */
X if( rec->first_foreign != -1 )
X rec->preamble = (rec->keys - (rec->first_foreign - rec->first_key))
X * sizeof(ulong);
X
X if( rec->fileid == -1 )
X printf("record '%s' is not contained in a file\n", rec->name);
X
X /* If the key is not a foreign key, it must be contained in a file */
X for( keyptr=&key[rec->first_key], j=0; j<rec->keys; j++, keyptr++ )
X {
X if( keyptr->fileid == -1 && KT_GETBASIC(keyptr->type) != KT_FOREIGN )
X {
X printf("key '%s.%s' is not contained in a file\n",
X rec->name, keyptr->name);
X }
X }
X }
X}
X
X
X
X/*------------------------------- fix_fields -------------------------------*\
X *
X * Purpose : The parser sets the FT_KEY flags on all fields that is a key
X * or part of a key. This flag should be removed for foreign keys.
X *
X * Parameters: None.
X *
X * Returns : Nothing.
X *
X */
Xvoid fix_fields()
X{
X Field *fld = field;
X int n = fields;
X
X while( n-- )
X {
X if( fld->type & FT_KEY )
X {
X if( KT_GETBASIC(key[fld->keyid].type) == KT_FOREIGN )
X fld->type &= ~FT_KEY;
X }
X fld++;
X }
X}
X
X
X/*---------------------------- print_fieldname -----------------------------*\
X *
X * Purpose : Print a field name and its field id in the header file. If the
X * field name is defined in more than one record it is prefixed
X * with "<record name>_" to prevent name clashes.
X *
X * Parameters: file - File descriptor.
X * fieldno - Field number.
X * fieldid - Field id.
X *
X * Returns : Nothing.
X *
X */
Xvoid print_fieldname(file, fieldno, fieldid)
XFILE *file;
Xint fieldno;
XId fieldid;
X{
X int i;
X Field *fld = field + fieldno;
X char *name = fld->name;
X
X if( only_keys && !(field[fieldno].type & FT_KEY) )
X return;
X
X fprintf(file, "#define ");
X
X for( i=0; i<fields; i++ )
X {
X if( field[i].nesting == 0 )
X {
X if( !strcmp(field[i].name, name) && i != fieldno )
X {
X /* Found a duplicate field name */
X fprintf(file, "%s_", record[field[fieldno].recid].name);
X break;
X }
X }
X }
X
X fprintf(file, "%s %ldL\n", name, fieldid);
X
X if( !strcmp(name, "USERCLASS") )
X {
X puts("AAAAAAARRRRRRRRRGGGGGGGG!!!!!!");
X printf("%d, %d\n", only_keys, field[fieldno].type & FT_KEY);
X }
X}
X
X
X
X#ifdef PROTOTYPES
Xvoid err_quit(char *s, ...)
X#else
Xvoid err_quit(s)
Xchar *s;
X#endif
X{
X va_list ap;
X
X va_start(ap, s);
X vfprintf(stderr, s, ap);
X puts("");
X va_end(ap);
X exit(1);
X}
X
X
Xstatic void init_vars()
X{
X int i;
X
X memset(&header,0,sizeof header);
X strcpy(header.version, DBD_VERSION);
X
X /* Initialize the sorttable */
X for( i=0; i<256; i++ )
X header.sorttable[i] = i;
X
X for( i=0; i<'z'-'a'+1; i++ )
X header.sorttable['A' + i] = 'a' + i;
X}
X
X
Xmain(argc, argv)
Xchar *argv[];
X{
X char *realname;
X char *p;
X int i;
X long n=0, prev;
X
X puts("Typhoon Data Definition Language Processsor version 2.24");
X
X if( argc == 1 )
X {
X printf(paramhelp, align);
X exit(1);
X }
X
X /* Allocate tables */
X record = (Record *)calloc(RECORDS_MAX , sizeof(Record));
X field = (Field *)calloc(FIELDS_MAX , sizeof(Field));
X file = (File *)calloc(FILES_MAX , sizeof(File));
X key = (Key *)calloc(KEYS_MAX , sizeof(Key));
X keyfield = (KeyField *)calloc(KEYFIELDS_MAX , sizeof(KeyField));
X structdef = (Structdef*)calloc(STRUCTDEFS_MAX, sizeof(Structdef));
X
X if( !(record && field && file && key && keyfield && structdef) )
X {
X puts("Not enough memory for tables");
X exit(1);
X }
X
X /* Initialize tables */
X for( i=0; i<KEYS_MAX; i++ )
X key[i].fileid = -1;
X
X /* Extract the real name of the file */
X if( (realname = strrchr(argv[argc-1], DIR_SWITCH)) != NULL )
X realname++;
X else
X realname = argv[argc-1];
X
X /* remove .ddl extension if present */
X if( p = strstr(realname, ".ddl") )
X *p = 0;
X
X /* generate file names for .ddl-file, .dbd-file and header file */
X sprintf(ddlname, "%s.ddl", argv[argc-1]);
X sprintf(dbdname, "%s.dbd", realname);
X sprintf(hname, "%s.h", realname);
X
X /* process command line options */
X for( i=1; i<argc-1; i++ )
X {
X if( argv[i][0] == '-' || argv[i][0] == '/' )
X {
X switch( argv[i][1] )
X {
X case 'h':
X strcpy(hname, argv[i]+2);
X break;
X case 'a':
X align = argv[i][2] - '0';
X if( align != 1 && align != 2 && align != 4 )
X err_quit("alignment must be 1, 2 or 4");
X break;
X case 'f':
X only_keys = 1;
X break;
X default:
X err_quit("unknown command line option");
X }
X }
X else
X err_quit("unknown command line option");
X }
X
X init_vars();
X
X /* open files */
X if( (lex_file=fopen(ddlname, "r")) == NULL )
X err_quit("cannot open file '%s'", ddlname);
X
X if( !(dbdfile=open(dbdname, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, CREATMASK)) )
X err_quit("cannot create .dbd file '%s'", dbdname);
X
X if( (hfile=fopen(hname, "w")) == NULL )
X err_quit("cannot create header file '%s'", hname);
X
X /*---------- initialize h-file ----------*/
X fprintf(hfile, "/*---------- headerfile for %s ----------*/\n", ddlname);
X fprintf(hfile, "/* alignment is %d */\n\n", align);
X
X /*---------- Initialize tables and parse input ----------*/
X record[0].first_field = 0;
X
X if( !yyparse() )
X {
X fix_file();
X fix_fields();
X
X header.files = files;
X header.keys = keys;
X header.keyfields = keyfields;
X header.records = records;
X header.fields = fields;
X header.structdefs = structdefs;
X header.alignment = align;
X
X /*---------- write dbd-file ----------*/
X write(dbdfile, &header, sizeof header);
X write(dbdfile, file, sizeof(file[0]) * files);
X write(dbdfile, key, sizeof(key[0]) * keys);
X write(dbdfile, keyfield, sizeof(keyfield[0]) * keyfields);
X write(dbdfile, record, sizeof(record[0]) * records);
X write(dbdfile, field, sizeof(field[0]) * fields);
X write(dbdfile, structdef, sizeof(structdef[0])* structdefs);
X
X /*---------- write h-file ----------*/
X fprintf(hfile, "/*---------- structures ----------*/\n");
X print_structures();
X
X fprintf(hfile, "/*---------- record names ----------*/\n");
X for( i=0; i<records; i++ )
X fprintf(hfile, "#define %s %ldL\n", strupr(record[i].name), (i+1) * REC_FACTOR);
X
X for( i=0; i<fields; i++ )
X strupr(field[i].name);
X
X fprintf(hfile, "\n/*---------- field names ----------*/\n");
X for( i=0, prev=-2; i<fields; i++, n++ )
X {
X if( field[i].nesting == 0 )
X {
X if( field[i].recid != prev )
X n = (field[i].recid+1) * REC_FACTOR + 1;
X
X print_fieldname(hfile, i, n);
X prev = field[i].recid;
X }
X }
X
X /* Print all keys that are either a multi-field key or foreign key */
X fprintf(hfile, "\n/*---------- key constants ----------*/\n");
X for( i=0; i<keys; i++ )
X {
X /* If the key only has one field, and the name of the key is
X * the same as the name of the field, then don't print the key name.
X */
X if( key[i].fields == 1 &&
X !istrcmp(key[i].name, field[ keyfield[key[i].first_keyfield].field].name) )
X continue;
X
X if( KT_GETBASIC(key[i].type) != KT_FOREIGN )
X fprintf(hfile, "#define %s %d\n", strupr(key[i].name), i);
X }
X
X fprintf(hfile, "\n/*---------- integer constants ----------*/\n");
X for( i=0; i<defines; i++ )
X fprintf(hfile, "#define %s %d\n", define[i].name, define[i].value);
X }
X
X fclose(hfile);
X fclose(lex_file);
X close(dbdfile);
X
X if( !errors )
X printf("%d records, %d fields\n", records, fields);
X else
X {
X unlink(dbdname);
X unlink(hname);
X }
X
X free(record);
X free(field);
X free(file);
X free(key);
X free(keyfield);
X free(structdef);
X
X printf("%d lines, %d errors\n", lex_lineno, errors);
X
X return errors != 0;
X}
X
X/* end-of-file */
END_OF_FILE
if test 21611 -ne `wc -c <'typhoon/src/util/ddlp.c'`; then
echo shar: \"'typhoon/src/util/ddlp.c'\" unpacked with wrong size!
fi
# end of 'typhoon/src/util/ddlp.c'
fi
if test -f 'typhoon/src/util/lex.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'typhoon/src/util/lex.c'\"
else
echo shar: Extracting \"'typhoon/src/util/lex.c'\" \(2849 characters\)
sed "s/^X//" >'typhoon/src/util/lex.c' <<'END_OF_FILE'
X/*----------------------------------------------------------------------------
X * File : @(#)lex.c 93/11/08 Copyright (c) 1993-94 CT Danmark
X * Compiler: UNIX C, Turbo C, Microsoft C
X * OS : UNIX, OS/2, DOS
X * Author : Thomas B. Pedersen
X *
X * Description:
X * General functions for lexical analysers.
X *
X * Revision History
X * ----------------------------------------
X * 11-Nov-1993 tbp Initial version.
X *
X *--------------------------------------------------------------------------*/
X
X/*-------------------------- Function prototypes ---------------------------*/
Xstatic int keywordcmp PRM( (char *, char *); )
X
X
X
Xvoid lex_skip_comment()
X{
X int c, start;
X
X start = lex_lineno;
X for( ;; )
X {
X switch( getc(lex_file) )
X {
X case '*':
X if( (c=getc(lex_file)) == '/' )
X return;
X else
X ungetc(c, lex_file);
X break;
X case '\n':
X lex_lineno++;
X break;
X case '/':
X if( (c=getc(lex_file)) == '*' ) /* nested comment */
X lex_skip_comment();
X else
X ungetc(c, lex_file);
X break;
X case EOF:
X fprintf(stderr, "unterminated comment starting in line %d\n", start);
X exit(1);
X }
X }
X}
X
X
Xstatic keywordcmp(ck,ce)
Xchar *ck;
Xchar *ce;
X{
X return strcmp(ck, ((LEX_KEYWORD *)ce)->s);
X}
X
X
X
Xlex_parse_keyword(char c)
X{
X char *p = yylval.s;
X int i;
X LEX_KEYWORD *kword;
X
X *p = c;
X
X do
X *++p = getc(lex_file);
X while( isalnum(*p) || *p=='_' );
X
X ungetc(*p, lex_file);
X *p = '\0';
X
X if( p - yylval.s > sizeof(yylval.s)-1 )
X {
X fprintf(stderr, "line %d: identifier too long, truncated\n", lex_lineno);
X yylval.s[sizeof(yylval.s)-1] = '\0';
X }
X
X kword = (LEX_KEYWORD *)bsearch(yylval.s,
X lex_keywordtab,
X lex_keywords,
X sizeof(LEX_KEYWORD),
X (LEX_CMPFUNC)keywordcmp);
X if( kword == NULL )
X {
X#ifdef T_NUMBER
X /* See if identifier is in define table */
X for( i=0; i<defines; i++ )
X if( !strcmp(yylval.s, define[i].name) )
X {
X yylval.val = define[i].value;
X return T_NUMBER;
X }
X#endif
X return T_IDENT;
X }
X
X return kword->token;
X}
X
X#ifdef T_NUMBER
Xlex_parse_number(char c)
X{
X yylval.val = 0;
X do
X {
X yylval.val = yylval.val * 10 + c - '0';
X c = getc(lex_file);
X }
X while( isdigit(c) );
X ungetc(c, lex_file);
X
X return T_NUMBER;
X}
X#endif
X
X
X#ifdef T_STRING
Xlex_parse_string()
X{
X char *p = yylval.s;
X
X while( (*p = getc(lex_file)) != '"' )
X {
X if( *p == '\n' )
X yyerror("newline in string");
X else
X p++;
X }
X
X *p = '\0';
X
X return T_STRING;
X}
X#endif
X
X#ifdef T_CHARCONST
Xlex_parse_charconst()
X{
X /* ' has already been read */
X yylval.val = getc(lex_file);
X
X if( getc(lex_file) != '\'' )
X yyerror("unterminated character constant");
X
X return T_CHARCONST;
X}
X#endif
X
Xvoid lex_skip_line(void)
X{
X int c;
X
X while( (c = getc(lex_file)) != '\n' && c != EOF )
X ;
X if( c == EOF )
X ungetc(EOF, lex_file);
X
X lex_lineno++;
X}
X
X/* end-of-file */
X
END_OF_FILE
if test 2849 -ne `wc -c <'typhoon/src/util/lex.c'`; then
echo shar: \"'typhoon/src/util/lex.c'\" unpacked with wrong size!
fi
# end of 'typhoon/src/util/lex.c'
fi
echo shar: End of archive 1 \(of 9\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 9 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...