home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume44 / typhoon / part01 next >
Internet Message Format  |  1994-09-17  |  63KB

  1. From: zeppelin@login.dknet.dk (Thomas B. Pedersen)
  2. Newsgroups: comp.sources.misc
  3. Subject: v44i057:  typhoon - Typhoon Relational Database Management System, Part01/09
  4. Date: 17 Sep 1994 21:44:04 -0500
  5. Organization: Sterling Software
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <csm-v44i057=typhoon.214347@sparky.sterling.com>
  9. X-Md4-Signature: 3ed59d07df131f309b0ca3f158f1f885
  10.  
  11. Submitted-by: zeppelin@login.dknet.dk (Thomas B. Pedersen)
  12. Posting-number: Volume 44, Issue 57
  13. Archive-name: typhoon/part01
  14. Environment: SCO UNIX, Tandem NonStop UNIX, Sun Solaris, AIX, Linux, OS/2
  15.  
  16. Typhoon is a freely available relational database management system for
  17. the UNIX and OS/2 environments. 
  18.  
  19. This release has been prepared in a hurry to get it out as quickly as 
  20. possible. This means that the documentation is rather sparse, since I
  21. haven't had the time to write extensive documentation yet. However, most
  22. of you out there are pretty clever, so you'll probably do fine with the
  23. man pages and the examples.
  24.  
  25. The system works fine and is currently used in a number of professional
  26. applications in Denmark, some of them mission critical.
  27.  
  28. The system was originally inspired by Raima's db_VISTA (today Raima Data
  29. Manager) but is relational rather than network based. Typhoon lacks some of
  30. db_VISTA's features, but also contains a number of nice features not found in 
  31. db_VISTA.
  32.  
  33. All relations are defined in a so called Data Definition Language (ddl) file.
  34. You define the database relations like you would write a C structure with
  35. chars, ints, strings, multidimensional arrays, nested union and structures,
  36. etc. Then you define primary, alternate and foreign keys for each relation.
  37. The Data Definition Language Processor (ddlp) compiles the database defintion
  38. into a binary file which constitutes the database description. The database
  39. relations are accessed via C subroutines which manipulate individual records
  40. within a table.
  41.  
  42.     - Multiple open database
  43.     - Multi-field keys
  44.     - Nested structures in records
  45.     - Controlled unions
  46.     - Referential integrity
  47.     - Variable length fields
  48.     - Null keys (optional keys in db_VISTA, but easier to use)
  49.     - Dynamic opening and closing of database files
  50.  
  51. At present the database has no locking mechanism, believe it or not! The
  52. projects I have used it in, simply didn't need it, even though they were
  53. multi-user environments. But it's in the works!
  54.  
  55. I am currently working on extending the library to support the following:
  56.  
  57.     - Locking
  58.     - Logging
  59.     - Transactions 
  60.     - Paging (to improve performance)
  61.  
  62. The library functions will remain intact, except for a number of new functions.
  63. I expect these things to be ready before the end of the year. Beta testers
  64. are welcome.
  65.  
  66. The library comes with three additional utilities:
  67.  
  68.     dbdview        - Displayes the database definitions.
  69.     tyexport    - Exports tables from a database.
  70.     tyimport    - Imports tables into a database.
  71.  
  72. Originally the library also contained online backup, restore and a replication
  73. server. These tools would need a lot of extra documentation, so I have left
  74. them out for now (the code still contains support for these utilities).
  75. However, if enough people show interest I will probably release them also.
  76.  
  77. Bug reports and mail should be sent to 
  78.  
  79.     Thomas B. Pedersen
  80.     zeppelin@login.dkuug.dk
  81.  
  82. Also, if you have any suggestions as to how I can improve the library, 
  83. documentation or anything else, please don't hesitate to mail me.
  84.  
  85. Thomas B. Pedersen
  86. -------------------------------
  87. #! /bin/sh
  88. # This is a shell archive.  Remove anything before this line, then feed it
  89. # into a shell via "sh file" or similar.  To overwrite existing files,
  90. # type "sh file -c".
  91. # Contents:  typhoon typhoon/examples typhoon/man typhoon/src
  92. #   typhoon/src/bt_funcs.c typhoon/src/h typhoon/src/util
  93. #   typhoon/src/util/ddl.y typhoon/src/util/ddlp.c
  94. #   typhoon/src/util/lex.c
  95. # Wrapped by kent@sparky on Sat Sep 17 21:38:15 1994
  96. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  97. echo If this archive is complete, you will see the following message:
  98. echo '          "shar: End of archive 1 (of 9)."'
  99. if test ! -d 'typhoon' ; then
  100.     echo shar: Creating directory \"'typhoon'\"
  101.     mkdir 'typhoon'
  102. fi
  103. if test ! -d 'typhoon/examples' ; then
  104.     echo shar: Creating directory \"'typhoon/examples'\"
  105.     mkdir 'typhoon/examples'
  106. fi
  107. if test ! -d 'typhoon/man' ; then
  108.     echo shar: Creating directory \"'typhoon/man'\"
  109.     mkdir 'typhoon/man'
  110. fi
  111. if test ! -d 'typhoon/src' ; then
  112.     echo shar: Creating directory \"'typhoon/src'\"
  113.     mkdir 'typhoon/src'
  114. fi
  115. if test -f 'typhoon/src/bt_funcs.c' -a "${1}" != "-c" ; then 
  116.   echo shar: Will not clobber existing file \"'typhoon/src/bt_funcs.c'\"
  117. else
  118.   echo shar: Extracting \"'typhoon/src/bt_funcs.c'\" \(14705 characters\)
  119.   sed "s/^X//" >'typhoon/src/bt_funcs.c' <<'END_OF_FILE'
  120. X/*----------------------------------------------------------------------------
  121. X * File    : bt_funcs
  122. X * Library : typhoon
  123. X * OS      : UNIX, OS/2, DOS
  124. X * Author  : Thomas B. Pedersen
  125. X *
  126. X * Copyright (c) 1994 Thomas B. Pedersen.  All rights reserved.
  127. X *
  128. X * Permission is hereby granted, without written agreement and without
  129. X * license or royalty fees, to use, copy, modify, and distribute this
  130. X * software and its documentation for any purpose, provided that the above
  131. X * copyright notice and the following two  paragraphs appear (1) in all 
  132. X * source copies of this software and (2) in accompanying documentation
  133. X * wherever the programatic interface of this software, or any derivative
  134. X * of it, is described.
  135. X *
  136. X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
  137. X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
  138. X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN 
  139. X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  140. X *
  141. X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
  142. X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  143. X * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" 
  144. X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
  145. X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  146. X *
  147. X * Description:
  148. X *
  149. X * Functions:
  150. X *     btree_add            - Insert a new key in a B-tree.
  151. X *     btree_find            - Find a key in a B-tree.
  152. X *     btree_exist            - See if a key exists in a B-tree.
  153. X *     btree_read            - Read the last key found.
  154. X *     btree_delall        - Delete all keys in a B-tree.
  155. X *   get_rightmostchild    - Find the rightmost child in a subtree.
  156. X *   get_leftmostchild    - Find the leftmost child in a subtree.
  157. X *     btree_frst            - Find the key with the lowest key value in a B-tree.
  158. X *     btree_last            - Find the key with the highest key value in a B-tree.
  159. X *     btree_prev            - Find the previous key in a B-tree.
  160. X *     btree_next            - Find the next key in a B-btree.
  161. X *
  162. X * $Log: bt_funcs.c,v $
  163. X * Revision 1.2  1994/09/17  16:00:11  tbp
  164. X * typhoon.h and environ.h are now included from <>.
  165. X *
  166. X * Revision 1.1  1994/09/13  21:28:28  tbp
  167. X * Added to repository.
  168. X * 
  169. X *
  170. X *--------------------------------------------------------------------------*/
  171. X
  172. Xstatic char rcsid[] = "$Id: bt_funcs.c,v 1.2 1994/09/17 16:00:11 tbp Exp $";
  173. X
  174. X#include <sys/types.h>
  175. X#include <string.h>
  176. X#include <stdio.h>
  177. X#include <fcntl.h>
  178. X#ifdef UNIX
  179. X#    include <unistd.h>
  180. X#else
  181. X#    include <io.h>
  182. X#endif
  183. X#include <typhoon.h>
  184. X#include "ty_dbd.h"
  185. X#include "ty_type.h"
  186. X#include "ty_prot.h"
  187. X#include "ty_glob.h"
  188. X#include "btree.h"
  189. X
  190. X/*--------------------------- Function prototypes --------------------------*/
  191. Xstatic void    get_rightmostchild        PRM( (INDEX *, ulong); )
  192. X       void    get_leftmostchild        PRM( (INDEX *, ulong); )
  193. Xstatic void    synchronize                PRM( (INDEX *); )
  194. X
  195. X
  196. X/*------------------------------- btree_add --------------------------------*\
  197. X *
  198. X * Purpose     : Inserts the key <key> in a B-tree index file.
  199. X *
  200. X * Parameters: I        - B-tree index file descriptor.
  201. X *               key        - Key value to insert.
  202. X *               ref        - Reference to insert together with key.
  203. X *
  204. X * Returns     : S_OKAY        - Key value successfully inserted in B-tree.
  205. X *               S_DUPLICATE    - The key value is already in the B-tree and
  206. X *                              duplicates are not allowed.
  207. X *
  208. X */
  209. X
  210. Xbtree_add(I, key, ref)
  211. XINDEX *I;
  212. Xvoid  *key;
  213. Xulong ref;
  214. X{
  215. X    ulong Ref;
  216. X    ix_addr Addr, moved, p;
  217. X    int i, mid;
  218. X
  219. X    I->curr = 0;
  220. X    I->hold = 0;
  221. X
  222. X    if( d_search(I, key, &p, &i) )
  223. X    {
  224. X        if( I->H.dups )
  225. X        {
  226. X            /* When a duplicate key is already in the tree, the current node
  227. X             * at this point may not be a leaf node. However, insertions
  228. X             * must always be performed in leaf nodes, so we must find the
  229. X             * rightmost entry in the left subtree 
  230. X             */
  231. X
  232. X            if( CHILD(I->node, i) )
  233. X            {
  234. X                get_rightmostchild(I, CHILD(I->node, i));
  235. X                i = I->path[I->level].i;
  236. X                p = I->path[I->level].a;
  237. X            }
  238. X        }
  239. X        else
  240. X            RETURN S_DUPLICATE;
  241. X    }
  242. X
  243. X    I->H.keys++;
  244. X    Addr = 0;
  245. X    Ref = ref;
  246. X    memcpy(I->curkey, key, I->H.keysize);
  247. X
  248. X    do
  249. X    {
  250. X        tupleins(I->node, i, 1);
  251. X        memcpy(KEY(I->node,i), I->curkey, I->H.keysize);
  252. X        CHILD(I->node,i+1) = Addr;
  253. X        REF(I->node,i) = Ref;
  254. X
  255. X        if( NSIZE(I->node) < (ulong)I->H.order )
  256. X        {
  257. X            NSIZE(I->node)++;
  258. X            nodewrite(I, I->node, p);
  259. X            btree_putheader(I);
  260. X            RETURN S_OKAY;
  261. X        }
  262. X        /* split node */
  263. X        mid = I->H.order / 2;
  264. X        /* write left part of node at its old position */
  265. X        NSIZE(I->node) = mid;
  266. X        nodewrite(I, I->node, p);
  267. X        /* Save mid K, A and R */
  268. X        memcpy(I->curkey, KEY(I->node,mid), I->H.keysize);
  269. X        Addr = CHILD(I->node, mid);
  270. X        Ref  = REF(I->node, mid);
  271. X        /* write right part of node at new position */
  272. X        NSIZE(I->node) = I->H.order - mid;
  273. X        memmove(&CHILD(I->node,0), &CHILD(I->node,mid+1), NSIZE(I->node) * I->tsize + sizeof(A_type));
  274. X        Addr = nodewrite(I, I->node, NEWPOS);
  275. X        if( (p = I->path[--I->level].a) != 0 )
  276. X        {
  277. X            noderead(I, I->node, p);                    /* p = I->path[p] */
  278. X/*            nodesearch(I,I->curkey,&i);*/
  279. X            i = I->path[I->level].i;
  280. X        }
  281. X    }
  282. X    while( p );
  283. X    /* Create a new root */
  284. X    noderead(I, I->node, 1);
  285. X    moved = nodewrite(I, I->node, NEWPOS);
  286. X
  287. X    memcpy(KEY(I->node,0), I->curkey, I->H.keysize);
  288. X    CHILD(I->node,0) = moved;
  289. X    CHILD(I->node,1) = Addr;
  290. X    REF(I->node,0) = Ref;
  291. X    NSIZE(I->node) = 1;
  292. X    nodewrite(I, I->node, 1);
  293. X    I->H.timestamp++;
  294. X    btree_putheader(I);
  295. X
  296. X    RETURN S_OKAY;
  297. X}
  298. X
  299. X
  300. X/*------------------------------- btree_find -------------------------------*\
  301. X *
  302. X * Purpose     : Searches for the key value <key> in a B-tree index file.
  303. X *
  304. X * Parameters: I            - B-tree index file descriptor.
  305. X *               key            - Key value to find.
  306. X *               ref            - Contains reference when function returns.
  307. X *
  308. X * Returns     : S_OKAY        - The key value was found. <ref> contains
  309. X *                              reference.
  310. X *               S_NOTFOUND    - The key value was not found.
  311. X *
  312. X */
  313. Xbtree_find(I, key, ref)
  314. XINDEX *I;
  315. Xvoid *key;
  316. Xulong *ref;
  317. X{
  318. X    ix_addr dummy;
  319. X    int i;
  320. X
  321. X    btree_getheader(I);        /* Inserted temporarily */
  322. X
  323. X    if( !d_search(I, key, &dummy, &i) )
  324. X    {
  325. X        /* Do only set hold if there are actually keys in the index */
  326. X        I->hold = I->H.keys > 0 ? 1 : 0;
  327. X        I->curr = 0;
  328. X        RETURN S_NOTFOUND;
  329. X    }
  330. X
  331. X    *ref = REF(I->node, i);
  332. X    memcpy(I->curkey, KEY(I->node, I->path[I->level].i), I->H.keysize);
  333. X    I->hold = 0;
  334. X    I->curr = 1;
  335. X    RETURN S_OKAY;
  336. X}
  337. X
  338. X
  339. X/*------------------------------- btree_keyread -------------------------------*\
  340. X *
  341. X * Purpose     : Copies the contents of the current key value to <buf>.
  342. X *
  343. X * Parameters: I        - B-tree index file descriptor.
  344. X *               buf        - Buffer to copy current key value to.
  345. X *
  346. X * Returns     : S_NOCR    - There is no current key.
  347. X *               S_OKAY    - Key value copied to <buf>.
  348. X *
  349. X */
  350. Xbtree_keyread(I, buf)
  351. XINDEX *I;
  352. Xvoid *buf;
  353. X{
  354. X    if( !I->curr )
  355. X        RETURN S_NOCR;
  356. X
  357. X    memcpy(buf, I->curkey, I->H.keysize);
  358. X    RETURN S_OKAY;
  359. X}
  360. X
  361. X
  362. X/*------------------------------ btree_delall ------------------------------*\
  363. X *
  364. X * Purpose     : Deletes all key values in a B-tree index file.
  365. X *
  366. X * Parameters: I        - B-tree index file descriptor.
  367. X *
  368. X * Returns     : S_OKAY    - All keys deleted.
  369. X *
  370. X */
  371. Xbtree_delall(I)
  372. XINDEX *I;
  373. X{
  374. X    btree_getheader(I);
  375. X    I->H.first_deleted = 0;
  376. X    I->H.keys = 0;
  377. X#ifdef UNIX
  378. X    os_close(open(I->fname, O_TRUNC));
  379. X#else
  380. X    chsize(I->fh, I->H.nodesize);
  381. X#endif
  382. X    I->curr = 0;
  383. X    I->hold = 0;
  384. X    btree_putheader(I);
  385. X
  386. X    RETURN S_OKAY;
  387. X}
  388. X
  389. X
  390. X/*
  391. X * The following macros are used to enhance the readability of the rest of the
  392. X * functions in this file. B-tree traversal can be rather tricky, with lots
  393. X * of pitfalls in it, but these macros should help a great deal. Here is a
  394. X * short explanation of the macros.
  395. X *
  396. X *    Keys        The number of keys in the current node.
  397. X *    Child(i)    The address of the i'th child in the current node.
  398. X *    Key(i)        Pointer to the i'th key in the current node.
  399. X *    Ref(i)        The reference of the i'th key in the current node.
  400. X *    Pos            The current position within the current node.
  401. X *    Addr        The current node address at the current level in the tree.
  402. X *    Level        The current level in the tree.
  403. X *
  404. X */
  405. X
  406. X#define Keys        NSIZE(I->node)
  407. X#define Child(i)    CHILD(I->node, i)
  408. X#define Key(i)        KEY(I->node, i)
  409. X#define Ref(i)        REF(I->node, i)
  410. X#define Pos            (I->path[I->level].i)
  411. X#define Addr        (I->path[I->level].a)
  412. X#define Level        (I->level)
  413. X
  414. X
  415. X/*--------------------------- get_rightmostchild ---------------------------*\
  416. X *
  417. X * Purpose     : Reads the rightmost key in a subtree with root address <addr>.
  418. X *
  419. X * Parameters: I        - B-tree index file descriptor.
  420. X *               addr        - The root address of the subtree.
  421. X *
  422. X * Returns     : Nothing.
  423. X *
  424. X */
  425. X
  426. Xstatic void get_rightmostchild(I, addr)
  427. XINDEX *I;
  428. Xulong addr;
  429. X{
  430. X    /* No tree has root at address 0 */
  431. X    if( !addr )
  432. X        return;
  433. X
  434. X    do
  435. X    {
  436. X        noderead(I, I->node, addr);
  437. X
  438. X        Level++;
  439. X        Addr = addr;
  440. X        Pos  = Keys;
  441. X    }
  442. X    while( addr = Child(Keys) );
  443. X}
  444. X
  445. X
  446. X/*--------------------------- get_leftmostchild ----------------------------*\
  447. X *
  448. X * Purpose     : Reads the leftmost key in a subtree with root address <addr>.
  449. X *
  450. X * Parameters: I        - B-tree index file descriptor.
  451. X *               addr        - The root address of the subtree.
  452. X *
  453. X * Returns     : Nothing.
  454. X *
  455. X */
  456. X
  457. Xvoid get_leftmostchild(I, addr)
  458. XINDEX *I;
  459. Xulong addr;
  460. X{
  461. X    /* No tree has root at address 0 */
  462. X    if( !addr )
  463. X        return;
  464. X
  465. X    do
  466. X    {
  467. X        noderead(I, I->node, addr);
  468. X
  469. X        Level++;
  470. X        Addr = addr;
  471. X        Pos  = 0;
  472. X    }
  473. X    while( addr = Child(0) );
  474. X}
  475. X
  476. X
  477. X/*------------------------------- btree_frst -------------------------------*\
  478. X *
  479. X * Purpose     : Read the smallest key value in a B-tree, i.e. the leftmost key.
  480. X *
  481. X * Parameters: I            - B-tree index file descriptor.
  482. X *               ref            - Contains reference when function returns.
  483. X *
  484. X * Returns     : S_OKAY        - The key was found. <ref> contains reference.
  485. X *               S_NOTFOUND    - The B-tree is empty.
  486. X *
  487. X */
  488. Xbtree_frst(I, ref)
  489. XINDEX *I;
  490. Xulong *ref;
  491. X{
  492. X    I->curr = 0;
  493. X    I->hold = 0;
  494. X    Level = 1;
  495. X    Addr = 1;
  496. X    Pos = 0;
  497. X
  498. X    /* Get the nost recent sequence number */
  499. X       btree_getheader(I);
  500. X    
  501. X    if( noderead(I, I->node, 1) == (ix_addr)-1 )
  502. X        RETURN S_NOTFOUND;
  503. X
  504. X    get_leftmostchild(I, Child(0));
  505. X
  506. X    I->curr = 1;
  507. X    *ref = Ref(Pos);
  508. X    memcpy(I->curkey, Key(Pos), I->H.keysize);
  509. X
  510. X    RETURN S_OKAY;
  511. X}
  512. X
  513. X
  514. X/*------------------------------- btree_last -------------------------------*\
  515. X *
  516. X * Purpose     : Read the greatest key value in a B-tree, i.e. the rightmost key.
  517. X *
  518. X * Parameters: I            - B-tree index file descriptor.
  519. X *               ref            - Contains reference when function returns.
  520. X *
  521. X * Returns     : S_OKAY        - The key was found. <ref> contains reference.
  522. X *               S_NOTFOUND    - The B-tree is empty.
  523. X *
  524. X */
  525. Xbtree_last(I, ref)
  526. XINDEX *I;
  527. Xulong *ref;
  528. X{
  529. X    I->curr = 0;
  530. X    I->hold = 0;
  531. X    Level = 1;
  532. X    Addr = 1;
  533. X
  534. X    /* Get the nost recent sequence number */
  535. X       btree_getheader(I);
  536. X    
  537. X    if( noderead(I, I->node, 1) == (ix_addr)-1 )
  538. X        RETURN S_NOTFOUND;
  539. X
  540. X    Pos = Keys;
  541. X    get_rightmostchild(I, Child(Keys));
  542. X
  543. X    /* Move pos one step leftwards so that Pos is the current key */
  544. X    Pos--;
  545. X    I->curr = 1;
  546. X    *ref = Ref(Pos);
  547. X    memcpy(I->curkey, Key(Pos), I->H.keysize);
  548. X
  549. X    RETURN S_OKAY;
  550. X}
  551. X
  552. X
  553. Xstatic void synchronize(I)
  554. XINDEX *I;
  555. X{
  556. X    ulong old_ts = I->H.timestamp;
  557. X    ulong ref;
  558. X
  559. X     btree_getheader(I);
  560. X
  561. X    if( old_ts != I->H.timestamp )
  562. X        btree_find(I, I->curkey, &ref);
  563. X}
  564. X
  565. X
  566. X
  567. X
  568. X/*------------------------------- btree_prev -------------------------------*\
  569. X *
  570. X * Purpose     : Find key value in a B-tree with less or equal (if duplicates)
  571. X *               key value that the current key. If there is no current key,
  572. X *               the function is equivalent to btree_last(). If the current
  573. X *               position before the call is the leftmost position in the tree,
  574. X *               S_NOTFOUND is returned.
  575. X *
  576. X * Parameters: I            - B-tree index file descriptor.
  577. X *               ref            - Contains reference if a key is found.
  578. X *
  579. X * Returns     : S_OKAY        - Key value found. <ref> contains reference.
  580. X *               S_NOTFOUND    - The key with the smallest value has already
  581. X *                              been reached.
  582. X *
  583. X */
  584. X
  585. Xbtree_prev(I,ref)
  586. XINDEX *I;
  587. Xulong *ref;
  588. X{
  589. X    if( I->shared )
  590. X        synchronize(I);
  591. X
  592. X    if( I->hold )
  593. X        goto out;
  594. X
  595. X    if( !I->curr )
  596. X        return btree_last(I, ref);
  597. X
  598. X    if( Child(Pos) > 0 )                        /* Non-leaf node            */
  599. X    {
  600. X        /* Get the rightmost child in the left subtree */
  601. X        get_rightmostchild(I, Child(Pos));
  602. X    }
  603. X    else if( Pos == 0 )                            /* Leaf node at first pos    */
  604. X    {
  605. X        /* Move upwards until a node with Pos > 0 or root is reached */
  606. X        while( Pos == 0 && Addr != 1 )
  607. X        {
  608. X            Level--;
  609. X            noderead(I, I->node, Addr);
  610. X        }
  611. X
  612. X        if( Pos == 0 && Addr == 1 )
  613. X        {
  614. X            I->curr = 0;
  615. X            RETURN S_NOTFOUND;
  616. X        }
  617. X    }
  618. X    Pos--;
  619. X
  620. Xout:
  621. X    I->curr = 1;
  622. X    I->hold = 0;
  623. X
  624. X    *ref = Ref(Pos);
  625. X    memcpy(I->curkey, Key(Pos), I->H.keysize);
  626. X
  627. X    RETURN S_OKAY;
  628. X}
  629. X
  630. X
  631. X/*------------------------------- btree_next -------------------------------*\
  632. X *
  633. X * Purpose     : Find key value in a B-tree with greater or equal (if duplicates)
  634. X *               key value that the current key. If there is no current key,
  635. X *               the function is equivalent to btree_frst(). If the current
  636. X *               position before the call is the rightmost position in the tree,
  637. X *               S_NOTFOUND is returned.
  638. X *
  639. X * Parameters: I            - B-tree index file descriptor.
  640. X *               ref            - Contains reference if a key is found.
  641. X *
  642. X * Returns     : S_OKAY        - Key value found. <ref> contains reference.
  643. X *               S_NOTFOUND    - The key with the greatest value has already
  644. X *                              been reached.
  645. X *
  646. X */
  647. Xbtree_next(I,ref)
  648. XINDEX *I;
  649. Xulong *ref;
  650. X{
  651. X    if( I->shared )
  652. X        synchronize(I);
  653. X
  654. X    if( I->hold )
  655. X    {
  656. X        /* An unsuccessful keyfind must be handled as a special case:
  657. X         * If we are at the rightmost position in a node, move upwards until
  658. X         * we reach a node where the position is not the rightmost. This
  659. X         * key should be the proper next key in the B-tree.
  660. X         */
  661. X
  662. X        while( Pos == Keys && Level > 1 )
  663. X        {
  664. X            Level--;
  665. X            noderead(I, I->node, Addr);
  666. X         }
  667. X
  668. X        if( Level == 1 && Pos == Keys )
  669. X            RETURN S_NOTFOUND;
  670. X
  671. X        goto out;
  672. X    }
  673. X
  674. X    if( !I->curr )
  675. X        return btree_frst(I, ref);
  676. X
  677. X    if( Child(Pos) > 0 )                        /* Non-leaf node            */
  678. X    {
  679. X        /* Get the leftmost child in the left subtree */
  680. X        Pos++;
  681. X        get_leftmostchild(I, Child(Pos));
  682. X    }
  683. X    else if( Pos >= Keys-1 )                    /* Leaf node at first pos    */
  684. X    {
  685. X#if 0
  686. X        if( Pos == Keys-1 && Addr == 1 )    94/03/17 TBP
  687. X#else
  688. X        if( Pos >= Keys-1 && Addr == 1 )
  689. X#endif
  690. X        {
  691. X            I->curr = 0;
  692. X            RETURN S_NOTFOUND;
  693. X        }
  694. X
  695. X        /* Move upwards until a node with Pos < Keys-1 or root is reached */
  696. X        do
  697. X        {
  698. X            Level--;
  699. X            noderead(I, I->node, Addr);
  700. X        }
  701. X        while( Pos >= Keys && Addr != 1 );
  702. X
  703. X        if( Pos == Keys && Addr == 1 )
  704. X        {
  705. X            I->curr = 0;
  706. X            RETURN S_NOTFOUND;
  707. X        }
  708. X    }
  709. X    else                                        /* Leaf node                */
  710. X        Pos++;
  711. X
  712. Xout:
  713. X    I->curr = 1;
  714. X    I->hold = 0;
  715. X
  716. X    *ref = Ref(Pos);
  717. X    memcpy(I->curkey, Key(Pos), I->H.keysize);
  718. X
  719. X    RETURN S_OKAY;
  720. X}
  721. X/* end-of-file */
  722. X
  723. END_OF_FILE
  724.   if test 14705 -ne `wc -c <'typhoon/src/bt_funcs.c'`; then
  725.     echo shar: \"'typhoon/src/bt_funcs.c'\" unpacked with wrong size!
  726.   fi
  727.   # end of 'typhoon/src/bt_funcs.c'
  728. fi
  729. if test ! -d 'typhoon/src/h' ; then
  730.     echo shar: Creating directory \"'typhoon/src/h'\"
  731.     mkdir 'typhoon/src/h'
  732. fi
  733. if test ! -d 'typhoon/src/util' ; then
  734.     echo shar: Creating directory \"'typhoon/src/util'\"
  735.     mkdir 'typhoon/src/util'
  736. fi
  737. if test -f 'typhoon/src/util/ddl.y' -a "${1}" != "-c" ; then 
  738.   echo shar: Will not clobber existing file \"'typhoon/src/util/ddl.y'\"
  739. else
  740.   echo shar: Extracting \"'typhoon/src/util/ddl.y'\" \(14286 characters\)
  741.   sed "s/^X//" >'typhoon/src/util/ddl.y' <<'END_OF_FILE'
  742. X/*----------------------------------------------------------------------------
  743. X * File    : ddl.y
  744. X * Program : ddlp
  745. X * OS      : UNIX, OS/2, DOS
  746. X * Author  : Thomas B. Pedersen
  747. X *
  748. X * Copyright (c) 1994 Thomas B. Pedersen.  All rights reserved.
  749. X *
  750. X * Permission is hereby granted, without written agreement and without
  751. X * license or royalty fees, to use, copy, modify, and distribute this
  752. X * software and its documentation for any purpose, provided that the above
  753. X * copyright notice and the following two  paragraphs appear (1) in all 
  754. X * source copies of this software and (2) in accompanying documentation
  755. X * wherever the programatic interface of this software, or any derivative
  756. X * of it, is described.
  757. X *
  758. X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
  759. X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
  760. X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN 
  761. X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  762. X *
  763. X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
  764. X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  765. X * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" 
  766. X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
  767. X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  768. X *
  769. X * Description:
  770. X *   Grammar for ddl-files.
  771. X *
  772. X * $Id: ddl.y,v 1.2 1994/09/17 16:11:13 tbp Exp $
  773. X *
  774. X * $Log: ddl.y,v $
  775. X * Revision 1.2  1994/09/17  16:11:13  tbp
  776. X * Added include directive.
  777. X *
  778. X * Added included directive.
  779. X *
  780. X * Added include directive.
  781. X *
  782. X * Revision 1.1  1994/09/13  21:28:51  tbp
  783. X * Added to repository.
  784. X *
  785. X * Added to repository.
  786. X * 
  787. X *
  788. X *--------------------------------------------------------------------------*/
  789. X
  790. X%{
  791. X
  792. X#include <string.h>
  793. X#include <stdarg.h>
  794. X#include <typhoon.h>
  795. X#include "../ty_dbd.h"
  796. X#include "../ty_type.h"
  797. X#include "ddlp.h"
  798. X#include "ddlpsym.h"
  799. X#include "ddlpglob.h"
  800. X
  801. X/*--------------------------- Function prototypes --------------------------*/
  802. Xstatic void add_keymember               PRM( (sym_struct *, char *, int); )
  803. X
  804. X/*---------------------------- Global variables ----------------------------*/
  805. Xstatic unsigned type;               /* Holds FT_.. flags of current field    */
  806. Xstatic int keytype;                 /* Holds KT_... constants                */
  807. Xstatic sym_member *control_field;    /* Field that controls current union    */
  808. X
  809. X
  810. Xstatic fieldid[10];
  811. X
  812. X%}
  813. X
  814. X%union {
  815. X    int     val;
  816. X    char    is_union;
  817. X    char    s[IDENT_LEN+1];
  818. X}
  819. X
  820. X%start database
  821. X
  822. X%token                T_DATABASE T_KEY T_DATA T_FILE T_CONTAINS T_RECORD
  823. X%token                T_UNIQUE T_DEFINE T_CONTROLLED T_MAP T_ARROW
  824. X%token                T_PRIMARY T_ALTERNATE T_FOREIGN T_ON T_DELETE T_RESTRICT
  825. X%token                T_REFERENCES T_UPDATE T_CASCADE T_NULL
  826. X%token                T_CHAR T_SHORT T_INT T_LONG T_SIGNED T_UNSIGNED T_FLOAT 
  827. X%token                T_DOUBLE T_UCHAR T_USHORT T_ULONG T_STRUCT T_UNION
  828. X%token                T_COMPOUND T_ASC T_DESC T_VARIABLE T_BY
  829. X%token <s>            T_IDENT T_STRING
  830. X%token <val>        T_NUMBER T_CHARCONST
  831. X%token                '[' ']' '{' '}' ';' ',' '.' '>'
  832. X%token                '+' '-' '*' '/' '(' ')'
  833. X
  834. X%type <val>            expr opt_sortorder opt_unique opt_null pagesize action
  835. X%type <val>            map_id
  836. X%type <is_union>    struct_or_union
  837. X%type <s>            opt_ident key_type
  838. X
  839. X%left '+' '-'
  840. X%left '*' '/'
  841. X
  842. X%%
  843. X
  844. Xdatabase     : T_DATABASE T_IDENT '{' decl_list '}'
  845. X                 { strcpy(dbname, $2); }
  846. X             ;
  847. X
  848. Xpagesize    : /* use default page size */
  849. X                { $$ = 512;       }
  850. X            | '[' expr ']'
  851. X                {
  852. X                    if( $2 < 512 )
  853. X                    {
  854. X                        printf("Page size too small\n");
  855. X                        $$ = 512;
  856. X                    }
  857. X                    else
  858. X                        $$ = $2;
  859. X                }
  860. X            ;
  861. X
  862. Xdecl_list    : decl  
  863. X            | decl_list decl
  864. X            ;
  865. X
  866. Xdecl        : T_DATA T_FILE pagesize T_STRING T_CONTAINS T_IDENT ';'
  867. X                {
  868. X                    add_contains('d', $6, "");
  869. X                    add_file('d', $4, $3);
  870. X                }
  871. X            | T_KEY T_FILE pagesize T_STRING T_CONTAINS T_IDENT '.' key_type ';'
  872. X                {
  873. X                    char type = strcmp($8, "<ref>") ? 'k' : 'r';
  874. X
  875. X                    add_contains(type, $6, $8);
  876. X                    add_file(type, $4, $3);
  877. X                }
  878. X            | record_head '{' member_list opt_key_list '}'
  879. X                {
  880. X                    sym_endstruct();
  881. X                    record[records-1].size = structnest[curnest+1]->size;
  882. X                    structdef[record[records-1].structid].size = record[records-1].size;
  883. X                }
  884. X            | T_DEFINE T_IDENT expr    { add_define($2, $3);                    }
  885. X            | T_MAP '{' map_list '}'
  886. X            ;
  887. X
  888. Xrecord_head    : T_RECORD T_IDENT        { add_record($2);
  889. X                                      add_structdef($2, 0, 0);
  890. X                                      sym_addstruct($2, 0);                    }
  891. X            ;
  892. X
  893. Xkey_type    : T_IDENT                 { strcpy($$, $1);                         }
  894. X            | T_REFERENCES            { strcpy($$, "<ref>");                    }
  895. X            ;
  896. X
  897. Xmember_list    : member
  898. X            | member_list member
  899. X            ;
  900. X
  901. Xmember        : membertype T_IDENT opt_dimen ';'
  902. X                {
  903. X                    sym_addmember($2, type, NULL);
  904. X                    cur_str->last_member->id = fields;
  905. X
  906. X                    if( type != FT_STRUCT )
  907. X                        add_field($2, type);
  908. X
  909. X                    /* Increase the number of level-0 fields of the record */
  910. X                    if( curnest == 0 )
  911. X                        structdef[record[records-1].structid].members++;
  912. X
  913. X                    type = 0;
  914. X                }
  915. X            | struct_specifier ';'
  916. X            ;
  917. X
  918. Xopt_dimen    : 
  919. X            | dimension opt_varlen_decl
  920. X            ;
  921. X
  922. Xdimension    : array
  923. X            | dimension array
  924. X            ;
  925. X
  926. Xarray        : '[' expr ']'            { dim[dims++] = $2;                        }
  927. X            ;
  928. X
  929. X
  930. Xopt_varlen_decl
  931. X            :
  932. X            | T_VARIABLE T_BY T_IDENT
  933. X                { 
  934. X/*                    if( curnest != 1 )
  935. X                        yyerror("variable size fields cannot be nested");*/
  936. X
  937. X                    if( !(size_field = sym_findmember(structnest[0], $3)) )
  938. X                        yyerror("unknown struct member '%s'", $3);
  939. X                }
  940. X            ;
  941. X
  942. X
  943. X/*--------------------------------------------------------------------------*/
  944. X/*                        Key declaration part                              */
  945. X/*--------------------------------------------------------------------------*/
  946. X
  947. Xopt_key_list: opt_primary_key_decl
  948. X              opt_alternate_key_decl_list
  949. X              opt_foreign_key_decl_list
  950. X            ;
  951. X
  952. X/*--------------------------------------------------------------------------*/
  953. X/*                            Primary key                                   */
  954. X/*--------------------------------------------------------------------------*/
  955. X
  956. Xopt_primary_key_decl
  957. X            : /* No primary key */
  958. X            | T_PRIMARY key_decl ';'
  959. X                {
  960. X                    key[keys-1].type = KT_PRIMARY|KT_UNIQUE;
  961. X                }
  962. X            ;
  963. X
  964. X
  965. X/*--------------------------------------------------------------------------*/
  966. X/*                            Alternate key                                 */
  967. X/*--------------------------------------------------------------------------*/
  968. X
  969. Xopt_alternate_key_decl_list
  970. X            :
  971. X            | alternate_key_decl_list
  972. X            ;
  973. X
  974. Xalternate_key_decl_list
  975. X            : alternate_key_decl
  976. X            | alternate_key_decl_list alternate_key_decl
  977. X            ;
  978. X
  979. Xalternate_key_decl
  980. X            : T_ALTERNATE opt_unique key_decl opt_null ';'
  981. X                {
  982. X                    key[keys-1].type = KT_ALTERNATE | $2 | $4;
  983. X                }
  984. X            ;
  985. X
  986. X
  987. X/*--------------------------------------------------------------------------*/
  988. X/*                             Foreign key                                  */
  989. X/*--------------------------------------------------------------------------*/
  990. X
  991. Xopt_foreign_key_decl_list
  992. X            :
  993. X            | foreign_key_decl_list
  994. X            ;
  995. X
  996. Xforeign_key_decl_list
  997. X            : foreign_key_decl
  998. X            | foreign_key_decl_list foreign_key_decl
  999. X            ;
  1000. X
  1001. X
  1002. Xforeign_key_decl
  1003. X            : T_FOREIGN key_decl T_REFERENCES T_IDENT 
  1004. X              T_ON T_UPDATE action 
  1005. X              T_ON T_DELETE action opt_null ';'
  1006. X                {
  1007. X                    /* Set the record's first_foreign field */
  1008. X                    if( record[records-1].first_foreign == -1 )
  1009. X                        record[records-1].first_foreign = keys-1;
  1010. X
  1011. X                    key[keys-1].type = KT_FOREIGN | $7 | $10 | $11;
  1012. X                    check_foreign_key($4, &key[keys-1]);
  1013. X                }
  1014. X            ;
  1015. X
  1016. Xaction        : T_RESTRICT            { $$ = KT_RESTRICT;                    }
  1017. X            | T_CASCADE             { $$ = KT_CASCADE;
  1018. X                                      yyerror("'cascade' not supported");
  1019. X                                     }
  1020. X            ;
  1021. X
  1022. X
  1023. X/*--------------------------------------------------------------------------*/
  1024. X/*    Key declaration rules used by primary, alternate and foreign keys     */
  1025. X/*--------------------------------------------------------------------------*/
  1026. X
  1027. Xopt_null    : /* not optional */
  1028. X                {
  1029. X                    $$ = 0;
  1030. X                }
  1031. X            | T_NULL T_BY T_IDENT    
  1032. X                {
  1033. X                    sym_member *mem;
  1034. X                    int type;
  1035. X
  1036. X                    if( !(mem = sym_findmember(cur_str, $3)) )
  1037. X                        yyerror("'%s' is not a member the record", $3);
  1038. X                    else
  1039. X                    {
  1040. X                        key[keys-1].null_indicator = mem->id;
  1041. X                        type = FT_GETBASIC(field[mem->id].type);
  1042. X
  1043. X                        if( type != FT_CHAR && type != FT_CHARSTR )
  1044. X                            yyerror("field determiner must be char or string");
  1045. X                    }
  1046. X
  1047. X                    $$ = KT_OPTIONAL;
  1048. X                }
  1049. X            ;
  1050. X
  1051. X
  1052. Xkey_decl    : key_decl_head comkey_member_list '}'
  1053. X                {
  1054. X                    sym_endstruct();
  1055. X
  1056. X                    /* Set the size of the compound key.
  1057. X                    * Foreign keys have special size.
  1058. X                    */
  1059. X                    if( KT_GETBASIC(key[keys-1].type) == KT_FOREIGN )
  1060. X                        key[keys-1].size = sizeof(REF_ENTRY);
  1061. X                    else
  1062. X                        key[keys-1].size = last_str->size;
  1063. X                }
  1064. X            | T_KEY T_IDENT
  1065. X                {
  1066. X                    sym_member *mem;
  1067. X
  1068. X                    if( !(mem = sym_findmember(cur_str, $2)) )
  1069. X                        yyerror("unknown field '%s'", $2);
  1070. X
  1071. X                    add_key($2);
  1072. X                    add_keyfield(mem->id, 1);
  1073. X
  1074. X                    key[keys-1].size = mem->size;
  1075. X                    field[mem->id].type |= FT_KEY;
  1076. X                    field[mem->id].keyid = keys-1;
  1077. X                }
  1078. X            ;
  1079. X
  1080. Xkey_decl_head
  1081. X            : T_KEY T_IDENT '{'
  1082. X                {
  1083. X                    /* Ensure that the key name is not also a field name */
  1084. X                    if( sym_findmember(cur_str, $2) ) 
  1085. X                        yyerror("the key '%s' is already a field name", $2);
  1086. X
  1087. X                    sym_addstruct($2, 0);
  1088. X                    add_key($2);
  1089. X                }
  1090. X            ;
  1091. X
  1092. X
  1093. X/*--------------------------------------------------------------------------*/
  1094. X/*                       Compound key declaration                           */
  1095. X/*--------------------------------------------------------------------------*/
  1096. X
  1097. Xcomkey_member_list
  1098. X            : comkey_member
  1099. X            | comkey_member_list ',' comkey_member
  1100. X            ;
  1101. X
  1102. Xcomkey_member
  1103. X            : T_IDENT opt_sortorder 
  1104. X                {
  1105. X                    add_keymember(structnest[curnest-1], $1, $2);   
  1106. X                }
  1107. X            ;
  1108. X
  1109. Xopt_unique    :                         { $$ = 0;              /* Not unique */}
  1110. X            | T_UNIQUE                { $$ = KT_UNIQUE;     /* Unique */    }
  1111. X            ;
  1112. X
  1113. Xopt_sortorder
  1114. X            : /* default */            { $$ = 1;        /* Ascending */     }
  1115. X            | T_ASC                    { $$ = 1;        /* Ascending */     }
  1116. X            | T_DESC                   { $$ = 0;        /* Descending */    }
  1117. X            ;
  1118. X
  1119. X/*--------------------------------------------------------------------------*/
  1120. X/*                      Structure member definition                         */
  1121. X/*--------------------------------------------------------------------------*/
  1122. X
  1123. Xmembertype    : int_type
  1124. X            | int_sign                { if( type == FT_UNSIGNED )
  1125. X                                          type |= FT_INT;                }
  1126. X            | int_sign int_type
  1127. X            | float_type
  1128. X            | u_type
  1129. X            | T_LONG float_type        { type |= FT_LONG;                    }
  1130. X            ;
  1131. X
  1132. Xint_type    : T_CHAR                 { type |= FT_CHAR;                     }
  1133. X            | T_SHORT                { type |= FT_SHORT;                    }
  1134. X            | T_INT                  { type |= FT_INT;                      }
  1135. X            | T_LONG                 { type |= FT_LONG;                     }
  1136. X            ;
  1137. X
  1138. Xint_sign    : T_SIGNED
  1139. X            | T_UNSIGNED            { type |= FT_UNSIGNED;                }
  1140. X            ;
  1141. X
  1142. Xfloat_type    : T_FLOAT                 { type |= FT_FLOAT;                 }
  1143. X            | T_DOUBLE                { type |= FT_DOUBLE;                }
  1144. X            ;
  1145. X
  1146. Xu_type        : T_UCHAR                 { type |= FT_UNSIGNED|FT_CHAR;         }
  1147. X              | T_USHORT                { type |= FT_UNSIGNED|FT_SHORT;        }
  1148. X              | T_ULONG                 { type |= FT_UNSIGNED|FT_LONG;         }
  1149. X              ;
  1150. X
  1151. Xexpr        : expr '+' expr            { $$ = $1 + $3; }
  1152. X            | expr '-' expr            { $$ = $1 - $3; }
  1153. X            | expr '*' expr            { $$ = $1 * $3; }
  1154. X            | expr '/' expr            { $$ = $1 / $3; }
  1155. X            | '(' expr ')'             { $$ = $2;      }
  1156. X            | T_NUMBER
  1157. X            ;
  1158. X
  1159. X/*--------------------------------------------------------------------------*/
  1160. X/*                       struct or union declaration                        */
  1161. X/*--------------------------------------------------------------------------*/
  1162. X
  1163. Xstruct_specifier
  1164. X            : struct_or_union_opt_ident '{' member_list '}' T_IDENT opt_dimen
  1165. X                {
  1166. X                    sym_struct *str;
  1167. X                    Field *fld;
  1168. X                    Structdef *strdef;
  1169. X
  1170. X                    sym_endstruct();
  1171. X
  1172. X                    str     = structnest[curnest + 1];
  1173. X                    fld     = &field[str->fieldid];
  1174. X                    strdef  = &structdef[ fld->structid ];
  1175. X
  1176. X                    strcpy(fld->name, $5);
  1177. X                    strdef->size    = str->size;
  1178. X                    strdef->members = str->members;
  1179. X
  1180. X                    sym_addmember($5, FT_STRUCT, structnest[curnest+1]);
  1181. X
  1182. X                    fld->size        = cur_str->last_member->size;
  1183. X                    fld->elemsize    = cur_str->last_member->elemsize;
  1184. X                    fld->offset        = cur_str->last_member->offset;
  1185. X
  1186. X                    if( size_field )
  1187. X                    {
  1188. X                        fld->type |= FT_VARIABLE;
  1189. X                        fld->keyid = size_field->id;
  1190. X                        size_field = NULL;
  1191. X                    }
  1192. X                }
  1193. X            | struct_or_union T_IDENT T_IDENT opt_dimen
  1194. X                {                                                  
  1195. X                    sym_struct *str = sym_findstruct($2, $1);
  1196. X
  1197. X                    if( str )
  1198. X                    {
  1199. X                        sym_addmember($3, FT_STRUCT, str);
  1200. X/*                        add_field($3, FT_STRUCT);*/
  1201. X                    }
  1202. X                    /* else error message */
  1203. X                }
  1204. X            ;
  1205. X
  1206. Xstruct_or_union_opt_ident
  1207. X            : struct_or_union opt_ident     
  1208. X                {
  1209. X                    add_field("<struct>", FT_STRUCT);
  1210. X                    sym_addstruct($2, $1);          
  1211. X                    cur_str->fieldid = fields-1;
  1212. X                    field[fields-1].structid = structdefs;
  1213. X
  1214. X                    add_structdef($2, $1, $1 ? control_field->id : 0);
  1215. X
  1216. X                    /* Increase the number of level-0 field of the record.
  1217. X                     * Actually, at this point the grammar we have moved to
  1218. X                     * level 1.
  1219. X                     */
  1220. X                    if( curnest == 1 )
  1221. X                        structdef[record[records-1].structid].members++;
  1222. X                }
  1223. X            ;
  1224. X
  1225. Xstruct_or_union
  1226. X            : T_STRUCT                              
  1227. X                {
  1228. X                    $$ = 0;
  1229. X                }
  1230. X            | T_UNION T_CONTROLLED T_BY T_IDENT
  1231. X                {
  1232. X                    $$ = 1;                                                               
  1233. X                    if( !(control_field = sym_findmember(cur_str, $4)) )
  1234. X                        yyerror("'%s' is not a member of the union/struct '%s'",
  1235. X                        $4, cur_str->name);
  1236. X                }
  1237. X            ;
  1238. X
  1239. Xopt_ident    :                        { *$$ = 0;                           }
  1240. X            | T_IDENT                { strcpy($$, $1);                    }
  1241. X            ;
  1242. X
  1243. X
  1244. X
  1245. X/*--------------------------------------------------------------------------*/
  1246. X/*                                 map_list                                    */
  1247. X/*--------------------------------------------------------------------------*/
  1248. X
  1249. Xmap_list    : map
  1250. X            | map_list map
  1251. X            ;
  1252. X
  1253. Xmap            : map_id T_ARROW map_id ';'    { header.sorttable[$1] = $3;    }
  1254. X            ;
  1255. X
  1256. Xmap_id        : T_CHARCONST                { $$ = $1;                        }
  1257. X            | T_NUMBER                    { $$ = $1;                        }
  1258. X            ;
  1259. X
  1260. X
  1261. X%%
  1262. X
  1263. X#include <stdio.h>
  1264. X
  1265. X
  1266. X
  1267. Xstatic void add_keymember(str, name, sortorder)
  1268. Xsym_struct *str;
  1269. Xchar *name;
  1270. Xint sortorder;
  1271. X{
  1272. X    sym_member *mem;
  1273. X
  1274. X    if( mem = sym_findmember(str, name) )
  1275. X    {
  1276. X        dims = mem->dims;
  1277. X        memcpy(dim, mem->dim, sizeof(*dim) * dims);
  1278. X        sym_addmember(name, mem->type, mem->struc);
  1279. X        add_keyfield(mem->id, sortorder);
  1280. X    }
  1281. X    else
  1282. X        yyerror("unknown struct member '%s'", name);
  1283. X}
  1284. X
  1285. X
  1286. X
  1287. X
  1288. Xextern errors;
  1289. X
  1290. Xyyerror(char *fmt ELLIPSIS)
  1291. X{
  1292. X    va_list ap;
  1293. X
  1294. X    printf("%s %d: ", ddlname, lex_lineno);
  1295. X    va_start(ap, fmt);
  1296. X    vprintf(fmt, ap);
  1297. X    puts("");
  1298. X    va_end(ap);
  1299. X    errors++;
  1300. X    return 0;
  1301. X}
  1302. X
  1303. X/* end-of-file */
  1304. END_OF_FILE
  1305.   if test 14286 -ne `wc -c <'typhoon/src/util/ddl.y'`; then
  1306.     echo shar: \"'typhoon/src/util/ddl.y'\" unpacked with wrong size!
  1307.   fi
  1308.   # end of 'typhoon/src/util/ddl.y'
  1309. fi
  1310. if test -f 'typhoon/src/util/ddlp.c' -a "${1}" != "-c" ; then 
  1311.   echo shar: Will not clobber existing file \"'typhoon/src/util/ddlp.c'\"
  1312. else
  1313.   echo shar: Extracting \"'typhoon/src/util/ddlp.c'\" \(21611 characters\)
  1314.   sed "s/^X//" >'typhoon/src/util/ddlp.c' <<'END_OF_FILE'
  1315. X/*----------------------------------------------------------------------------
  1316. X * File    : ddlp.c
  1317. X * Program : ddlp
  1318. X * OS      : UNIX, OS/2, DOS
  1319. X * Author  : Thomas B. Pedersen
  1320. X *
  1321. X * Copyright (c) 1994 Thomas B. Pedersen.  All rights reserved.
  1322. X *
  1323. X * Permission is hereby granted, without written agreement and without
  1324. X * license or royalty fees, to use, copy, modify, and distribute this
  1325. X * software and its documentation for any purpose, provided that the above
  1326. X * copyright notice and the following two  paragraphs appear (1) in all 
  1327. X * source copies of this software and (2) in accompanying documentation
  1328. X * wherever the programatic interface of this software, or any derivative
  1329. X * of it, is described.
  1330. X *
  1331. X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
  1332. X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
  1333. X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN 
  1334. X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1335. X *
  1336. X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
  1337. X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  1338. X * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" 
  1339. X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
  1340. X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  1341. X *
  1342. X * Description:
  1343. X *   Grammar for ddl-files.
  1344. X *
  1345. X * $Log: ddlp.c,v $
  1346. X * Revision 1.2  1994/09/17  16:00:51  tbp
  1347. X * typhoon.h and environ.h are now included from <>.
  1348. X *
  1349. X * Revision 1.1  1994/09/13  21:28:52  tbp
  1350. X * Added to repository.
  1351. X *
  1352. X * Added to repository.
  1353. X * 
  1354. X *
  1355. X *--------------------------------------------------------------------------*/
  1356. X
  1357. Xstatic char rcsid[] = "$Id: ddlp.c,v 1.2 1994/09/17 16:00:51 tbp Exp $";
  1358. X
  1359. X#include <stdio.h>
  1360. X#include <string.h>
  1361. X#include <ctype.h>
  1362. X#include <fcntl.h>
  1363. X#include <stdarg.h>
  1364. X#ifndef UNIX
  1365. X#  include <sys\types.h>
  1366. X#  include <sys\stat.h>
  1367. X#  include <stdlib.h>
  1368. X#  include <io.h>
  1369. X#endif
  1370. X#define DEFINE_GLOBALS
  1371. X#include <typhoon.h>
  1372. X#include "../ty_dbd.h"
  1373. X#include "../ty_type.h"
  1374. X#include "ddlp.h"
  1375. X#include "ddlpsym.h"
  1376. X#include "ddlpglob.h"
  1377. X#include "ddl_y.h"
  1378. X
  1379. X/*-------------------------- Function prototypes ---------------------------*/
  1380. Xint        yyparse                PRM( (void); )
  1381. Xvoid    align_offset        PRM( (unsigned *, int); )
  1382. Xvoid    check_consistency    PRM( (void); )
  1383. Xvoid    print_fieldname     PRM( (FILE *, int, Id); )
  1384. Xvoid    fix_file            PRM( (void); )
  1385. Xvoid    fix_fields            PRM( (void); )
  1386. X
  1387. X/*---------------------------- Global variables ----------------------------*/
  1388. XFILE *lex_file, *hfile;
  1389. Xint dbdfile;
  1390. X
  1391. Xstatic char paramhelp[] = "\
  1392. XSyntax: ddlp [option]... file[.ddl]\n\
  1393. XOptions:\n\
  1394. X    -a[1|2|4]   Set structure alignment (default is %d)\n\
  1395. X    -f          Only generate field constants for keys\n\
  1396. X    -h<file>    Use <file> as header file\n";
  1397. X
  1398. X
  1399. X
  1400. Xchar *strupr(s)
  1401. Xchar *s;
  1402. X{
  1403. X    char *olds = s;
  1404. X
  1405. X    while( *s )
  1406. X    {
  1407. X        *s = toupper(*s);
  1408. X        s++;
  1409. X    }
  1410. X
  1411. X    return olds;
  1412. X}
  1413. X
  1414. X
  1415. X#ifdef UNIX
  1416. X#ifndef __STDC__
  1417. Xchar *strstr(s1, s2)
  1418. Xchar *s1, *s2;
  1419. X{
  1420. X    int len = strlen(s2);
  1421. X
  1422. X    while( *s1 )
  1423. X    {
  1424. X        if( *s2 == *s1 )
  1425. X            if( !memcmp(*s1,s2,len) )
  1426. X            return s1;
  1427. X        s1++;
  1428. X    }
  1429. X    return NULL;
  1430. X}
  1431. X#endif
  1432. X#endif
  1433. X
  1434. X
  1435. Xistrcmp(s1, s2)
  1436. Xchar *s1, *s2;
  1437. X{
  1438. X       while( tolower(*s1) == tolower(*s2) && *s1 && *s2 )
  1439. X          s1++, s2++;
  1440. X   
  1441. X       return tolower(*s1) - tolower(*s2);
  1442. X}
  1443. X
  1444. X
  1445. X/*------------------------------ align_offset ------------------------------*\
  1446. X *
  1447. X * Purpose   : Align an address to fit the next field type.
  1448. X *
  1449. X * Parameters: offset   - Offset to align.
  1450. X *               type     - Field type (FT_...).
  1451. X *
  1452. X * Returns   : offset   - The aligned offset.
  1453. X *
  1454. X */
  1455. Xvoid align_offset(offset, type)
  1456. Xunsigned *offset;
  1457. Xint type;
  1458. X{
  1459. X    int rem = *offset % align;
  1460. X    int size;
  1461. X
  1462. X/*    if( type == FT_STRUCT )
  1463. X        return;*/
  1464. X
  1465. X    if( !rem || FT_GETBASIC(type) == FT_CHAR || !*offset )
  1466. X        return;
  1467. X
  1468. X    if( type == FT_STRUCT )
  1469. X        size = sizeof(long);
  1470. X    else
  1471. X        size = typeinfo[FT_GETBASIC(type) - 1].size;
  1472. X
  1473. X    if( rem == size )
  1474. X        return;
  1475. X
  1476. X    if( size < align - rem  )
  1477. X        *offset += rem;
  1478. X    else
  1479. X        *offset += align - rem;
  1480. X}
  1481. X
  1482. X
  1483. X/*--------------------------------- add_key --------------------------------*\
  1484. X *
  1485. X * Purpose   : Adds a key definition to the record currently being defined.
  1486. X *
  1487. X * Parameters: name     - Key name
  1488. X *
  1489. X * Returns   : Nothing.
  1490. X *
  1491. X */
  1492. Xvoid add_key(name)
  1493. Xchar *name;
  1494. X{
  1495. X    Key *k = key + keys++;
  1496. X
  1497. X    /* Add an entry to the key table */
  1498. X    k->first_keyfield = keyfields;
  1499. X    k->fields         = 0;
  1500. X    k->size           = 0;
  1501. X    strcpy(k->name, name);
  1502. X
  1503. X    /* Increase the number of keys in the record */
  1504. X    record[records-1].keys++;
  1505. X}
  1506. X
  1507. X
  1508. X/*------------------------------- add_keyfield -----------------------------*\
  1509. X *
  1510. X * Purpose   : Adds a field to the key currently being defined.
  1511. X *
  1512. X * Parameters: id       - Field id.
  1513. X *               ascending   - Is key sorted in ascending order?
  1514. X *
  1515. X * Returns   : Nothing.
  1516. X *
  1517. X */
  1518. X
  1519. Xvoid add_keyfield(id, ascending)
  1520. XId id;
  1521. Xint ascending;
  1522. X{
  1523. X    KeyField *keyfld = keyfield + keyfields++;
  1524. X
  1525. X    keyfld->field  = id;
  1526. X    keyfld->asc    = ascending;
  1527. X
  1528. X    /* The offset is only used in compound keys */
  1529. X    if( key[keys-1].fields )
  1530. X        keyfld->offset = cur_str->last_member->offset;
  1531. X    else
  1532. X        keyfld->offset = 0;
  1533. X
  1534. X    /* Increase the number of fields of the key currently being defined */
  1535. X    key[keys-1].fields++;
  1536. X}
  1537. X
  1538. X
  1539. Xvoid add_define(name, value)
  1540. Xchar *name;
  1541. Xint value;
  1542. X{
  1543. X    strcpy(define[defines].name, name);
  1544. X    define[defines++].value = value;
  1545. X}
  1546. X
  1547. X
  1548. Xvoid add_file(type, name, pagesize)
  1549. Xint type;
  1550. Xchar *name;
  1551. Xunsigned pagesize;
  1552. X{
  1553. X    file[files].id    = -1;             /* Unresolved           */
  1554. X    file[files].type  = type;
  1555. X    file[files].pagesize= pagesize;
  1556. X    strcpy(file[files++].name, name);
  1557. X}
  1558. X
  1559. X
  1560. X/*------------------------------ add_contains ------------------------------*\
  1561. X *
  1562. X * Purpose   : Add a new entry to the contains table. This table is used to
  1563. X *             determine which records and keys references and are referenced
  1564. X *             by the file table entries.
  1565. X *
  1566. X * Parameters: type     - 'k' = key, 'r' = record.
  1567. X *             record   - Record name.
  1568. X *             key      - Key name ("" if type is 'r').
  1569. X *
  1570. X * Returns   : Nothing.
  1571. X *
  1572. X */
  1573. Xvoid add_contains(type, record, key)
  1574. Xint type;
  1575. Xchar *record, *key;
  1576. X{
  1577. X    Contains *con = contains + conts++;
  1578. X
  1579. X    strcpy(con->record, record);
  1580. X    strcpy(con->key, key);
  1581. X    con->fileid = files;
  1582. X    con->type   = type;
  1583. X    con->line   = lex_lineno;
  1584. X}
  1585. X
  1586. X
  1587. X/*------------------------------- add_record -------------------------------*\
  1588. X *
  1589. X * Purpose   : This function adds a new entry to the record table. The fileid
  1590. X *             is set to -1 to indicate that the index into file[] is
  1591. X *             unresolved. This file be fixed by fix_file().
  1592. X *
  1593. X * Parameters: name  - Record name.
  1594. X *
  1595. X * Returns   : Nothing.
  1596. X *
  1597. X */
  1598. Xvoid add_record(name)
  1599. Xchar *name;
  1600. X{
  1601. X    Record *rec = record + records++;
  1602. X    int i;
  1603. X
  1604. X    /* Add an entry to the record table */
  1605. X    rec->first_field    = fields;
  1606. X    rec->first_key        = keys;
  1607. X    rec->first_foreign    = -1;
  1608. X    rec->size            = 0;
  1609. X    rec->is_vlr            = 0;
  1610. X    rec->fileid            = -1;
  1611. X    rec->structid        = structdefs;
  1612. X    strcpy(rec->name, name);
  1613. X
  1614. X    /* If this record has a reference file, <ref_file> must be set */
  1615. X    for( i=0; i<conts; i++ )
  1616. X        if( !strcmp(contains[i].record, name) && !strcmp(contains[i].key, "<ref>") )
  1617. X            break;
  1618. X
  1619. X    if( i < conts )
  1620. X        rec->ref_file = contains[i].fileid;
  1621. X    else
  1622. X        rec->ref_file = -1;
  1623. X
  1624. X    /* No variable length fields have occurred in this record so far */
  1625. X    varlen_field_occurred = 0;
  1626. X}
  1627. X
  1628. X
  1629. X/*------------------------------- add_field --------------------------------*\
  1630. X *
  1631. X * Purpose   : Adds a new entry to the field table.
  1632. X *
  1633. X *             If the <size_field> variable is not empty it contains the
  1634. X *             name of the field that determines the size of the field being
  1635. X *             added. Thus, if <size_field> is non-empty, the field being
  1636. X *             added is of variable length.
  1637. X *
  1638. X * Parameters: name  - Field name.
  1639. X *             type  - Field type. Contains FT_... flags.
  1640. X *
  1641. X * Returns   : Nothing.
  1642. X *
  1643. X */
  1644. Xvoid add_field(name, type)
  1645. Xchar *name;
  1646. Xint type;
  1647. X{
  1648. X    sym_member *mem = cur_str->last_member;
  1649. X    Field *fld = field + fields;
  1650. X    int i;
  1651. X
  1652. X    /* If the field is a char string the FT_CHARSTR flag must be set */
  1653. X    if( FT_GETBASIC(type) == FT_CHAR && mem->size > 1 )
  1654. X    {
  1655. X        type &= ~FT_BASIC;            /* Clear the basic flags and set        */
  1656. X        type |=  FT_CHARSTR;        /* the FT_CHARSTR flag instead             */
  1657. X    }
  1658. X
  1659. X    fld->recid     = records-1;        /* Link field to current record            */
  1660. X    fld->type      = type;
  1661. X    fld->nesting   = curnest;
  1662. X    strcpy(fld->name, name);
  1663. X
  1664. X    if( type != FT_STRUCT )
  1665. X    {
  1666. X        fld->size      = mem->size;
  1667. X        fld->offset    = mem->offset;
  1668. X        fld->elemsize  = mem->elemsize;
  1669. X    }
  1670. X
  1671. X    record[records-1].fields++;
  1672. X
  1673. X    /* Check if the current field is of variable length */
  1674. X    if( size_field )
  1675. X    {
  1676. X        if( mem->dims != 1 )
  1677. X            yyerror("variable size fields must be one-dimension arrays");
  1678. X
  1679. X        if( (size_field->type & (FT_SHORT|FT_UNSIGNED)) != (FT_SHORT|FT_UNSIGNED) )
  1680. X            yyerror("size field '%s' must be 'unsigned short'", size_field->name);
  1681. X
  1682. X        /* Store id of size field in keyid (dirty, but saves space) */
  1683. X        fld->keyid = size_field->id;
  1684. X        fld->type |= FT_VARIABLE;
  1685. X        record[records-1].is_vlr = 1;
  1686. X
  1687. X        size_field = NULL;
  1688. X
  1689. X        /* Ensure that no fixed length fields follow */
  1690. X        varlen_field_occurred = 1;
  1691. X    }
  1692. X    else if( varlen_field_occurred && curnest == 0 )
  1693. X        yyerror("fixed length field '%s' follows variable length field", name);
  1694. X
  1695. X    fields++;
  1696. X}
  1697. X
  1698. X
  1699. X
  1700. X/*------------------------------ add_structdef -----------------------------*\
  1701. X *
  1702. X * Purpose   : Add a structure definition.
  1703. X *
  1704. X * Parameters: name            - Structure name.
  1705. X *               is_union        - Is the structure a union.
  1706. X *               control_field- If <is_union> is true this is the id of the
  1707. X *                               control field.
  1708. X *
  1709. X * Returns   : Nothing.
  1710. X *
  1711. X */
  1712. Xvoid add_structdef(name, is_union, control_field)
  1713. Xchar *name;
  1714. Xint is_union, control_field;
  1715. X{
  1716. X    Structdef *str = structdef + structdefs++;
  1717. X
  1718. X    strcpy(str->name, name);
  1719. X    str->first_member = fields;
  1720. X    str->is_union     = is_union;
  1721. X
  1722. X    if( is_union )
  1723. X        str->control_field = control_field;
  1724. X}
  1725. X
  1726. X
  1727. X
  1728. X
  1729. X/*---------------------------- check_foreign_key ---------------------------*\
  1730. X *
  1731. X * Purpose   : Check that a foreign key matches its target (primary key).
  1732. X *
  1733. X * Parameters: name           - Target record name.
  1734. X *             foreign_key    - Pointer to foreign key.
  1735. X *
  1736. X * Returns   : Nothing.
  1737. X *
  1738. X */
  1739. Xvoid check_foreign_key(name, foreign_key)
  1740. Xchar *name;
  1741. XKey *foreign_key;
  1742. X{
  1743. X    Record        *rec;                  /* Ptr to parent record                 */
  1744. X    Key         *primary_key;        /* Ptr to parent's primary key             */
  1745. X    KeyField *primary_fld;            /* Ptr to first field of primary_key       */
  1746. X    KeyField *foreign_fld;            /* Ptr to first field of foreign_key       */
  1747. X    int i;
  1748. X
  1749. X    /* Check if the record has a primary key */
  1750. X    for( rec=record, i=0; i<records; rec++, i++ )
  1751. X        if( !strcmp(rec->name, name) )
  1752. X            break;
  1753. X
  1754. X    if( i == records )
  1755. X    {
  1756. X        yyerror("unknown target record '%s'", name);
  1757. X        return;
  1758. X    }
  1759. X
  1760. X    if( !rec->keys )
  1761. X    {
  1762. X        yyerror("The target '%s' has no primary key", name);
  1763. X        return;
  1764. X    }
  1765. X
  1766. X    primary_key = &key[ rec->first_key ];
  1767. X
  1768. X    if( KT_GETBASIC(primary_key->type) != KT_PRIMARY )
  1769. X    {
  1770. X        yyerror("The target '%s' has no primary key", name);
  1771. X        return;
  1772. X    }
  1773. X
  1774. X    if( primary_key->fields != foreign_key->fields )
  1775. X    {
  1776. X        yyerror("The foreign key '%s' does not match its target", name);
  1777. X        return;
  1778. X    }
  1779. X
  1780. X    primary_fld = &keyfield[ primary_key->first_keyfield ];
  1781. X    foreign_fld = &keyfield[ foreign_key->first_keyfield ];
  1782. X
  1783. X    /* Find the reference file of the parent */
  1784. X    foreign_key->parent  = rec - record;
  1785. X    rec->dependents++;
  1786. X
  1787. X
  1788. X    if( rec->ref_file == -1 )
  1789. X    {
  1790. X        yyerror("The parent table '%s' has no reference file", name);
  1791. X        return;
  1792. X    }
  1793. X
  1794. X    foreign_key->fileid = rec->ref_file;
  1795. X
  1796. X    /* Compare the format of the primary key with that of the foreign key */
  1797. X    for( i=0; i<primary_key->fields; i++, foreign_fld++, primary_fld++ )
  1798. X    {
  1799. X        if( FT_GETSIGNEDBASIC(field[primary_fld->field].type)  !=
  1800. X            FT_GETSIGNEDBASIC(field[foreign_fld->field].type) )
  1801. X            break;
  1802. X
  1803. X        /* Set sort order */
  1804. X        foreign_fld->asc = primary_fld->asc;
  1805. X    }
  1806. X
  1807. X    if( i < primary_key->fields )
  1808. X    {
  1809. X        yyerror("The foreign key '%s' does not match its target", name);
  1810. X        return;
  1811. X    }
  1812. X}
  1813. X
  1814. X
  1815. X/*-------------------------------- fix_file --------------------------------*\
  1816. X *
  1817. X * Purpose   : This function sets the fileid of all the records and the keys.
  1818. X *
  1819. X * Parameters: None.
  1820. X *
  1821. X * Returns   : Nothing.
  1822. X *
  1823. X */
  1824. Xvoid fix_file()
  1825. X{
  1826. X    Contains *con;
  1827. X    Record *rec;
  1828. X    int i, j, n;
  1829. X
  1830. X    for( i=0, con=contains; i<conts; i++, con++ )
  1831. X    {
  1832. X        /* First find the record entry of this contains */
  1833. X        for( j=0, rec=record; j<records; j++, rec++ )
  1834. X            if( !strcmp(rec->name, con->record) )
  1835. X                break;
  1836. X
  1837. X        if( j == records )
  1838. X        {
  1839. X            printf("unknown record '%s' in contains statement\n", con->record);
  1840. X            continue;
  1841. X        }
  1842. X
  1843. X        /* Link the record or the key to a file and vice versa */
  1844. X        switch( con->type )
  1845. X        {
  1846. X            case 'r':
  1847. X                break;
  1848. X
  1849. X            case 'd':
  1850. X                rec->fileid = con->fileid;
  1851. X
  1852. X                if( rec->is_vlr )
  1853. X                    file[i].type = 'v';
  1854. X                break;
  1855. X
  1856. X            case 'k':
  1857. X                for( n=rec->keys, j=rec->first_key; n--; j++ )
  1858. X                    if( !strcmp( key[j].name, con->key) )
  1859. X                        break;
  1860. X
  1861. X                if( KT_GETBASIC(key[j].type) == KT_FOREIGN )
  1862. X                {
  1863. X                    int tmp = lex_lineno;
  1864. X
  1865. X                    lex_lineno = con->line;
  1866. X                    yyerror("a foreign key cannot be contained in a file");
  1867. X                    lex_lineno = tmp;
  1868. X                    break;
  1869. X                }
  1870. X
  1871. X                if( n < 0 && strcmp(con->key, "<ref>") )
  1872. X                {
  1873. X                    printf("unknown key '%s' contained in file '%s'\n",
  1874. X                        con->key, file[con->fileid].name);
  1875. X                    continue;
  1876. X                }
  1877. X
  1878. X                key[j].fileid = con->fileid;
  1879. X                break;
  1880. X        }
  1881. X
  1882. X        con->entry = j;
  1883. X        file[i].id = j;
  1884. X    }
  1885. X
  1886. X    /* Check that each record is contained is contained in a data file and
  1887. X     * each key is contained in a key file
  1888. X     */
  1889. X    for( i=0, rec=record; i<records; i++, rec++ )
  1890. X    {
  1891. X        Key *keyptr;
  1892. X
  1893. X        /* Calculate the size of the preamble */
  1894. X        if( rec->first_foreign != -1 )
  1895. X            rec->preamble = (rec->keys - (rec->first_foreign - rec->first_key)) 
  1896. X                * sizeof(ulong);
  1897. X
  1898. X        if( rec->fileid == -1 )
  1899. X            printf("record '%s' is not contained in a file\n", rec->name);
  1900. X
  1901. X        /* If the key is not a foreign key, it must be contained in a file */
  1902. X        for( keyptr=&key[rec->first_key], j=0; j<rec->keys; j++, keyptr++ )
  1903. X        {
  1904. X            if( keyptr->fileid == -1 && KT_GETBASIC(keyptr->type) != KT_FOREIGN )
  1905. X            {
  1906. X                printf("key '%s.%s' is not contained in a file\n",
  1907. X                    rec->name, keyptr->name);
  1908. X            }
  1909. X         }
  1910. X    }
  1911. X}
  1912. X
  1913. X
  1914. X
  1915. X/*------------------------------- fix_fields -------------------------------*\
  1916. X *
  1917. X * Purpose   : The parser sets the FT_KEY flags on all fields that is a key
  1918. X *             or part of a key. This flag should be removed for foreign keys.
  1919. X *
  1920. X * Parameters: None.
  1921. X *
  1922. X * Returns   : Nothing.
  1923. X *
  1924. X */
  1925. Xvoid fix_fields()
  1926. X{
  1927. X    Field *fld = field;
  1928. X    int n = fields;
  1929. X   
  1930. X    while( n-- )
  1931. X    {
  1932. X        if( fld->type & FT_KEY )
  1933. X        {
  1934. X            if( KT_GETBASIC(key[fld->keyid].type) == KT_FOREIGN )
  1935. X            fld->type &= ~FT_KEY;
  1936. X        }
  1937. X        fld++;
  1938. X    }
  1939. X}
  1940. X
  1941. X
  1942. X/*---------------------------- print_fieldname -----------------------------*\
  1943. X *
  1944. X * Purpose   : Print a field name and its field id in the header file. If the
  1945. X *               field name is defined in more than one record it is prefixed
  1946. X *               with "<record name>_" to prevent name clashes.
  1947. X *
  1948. X * Parameters: file        - File descriptor.
  1949. X *               fieldno    - Field number.
  1950. X *               fieldid    - Field id.
  1951. X *
  1952. X * Returns   : Nothing.
  1953. X *
  1954. X */
  1955. Xvoid print_fieldname(file, fieldno, fieldid)
  1956. XFILE *file;
  1957. Xint fieldno;
  1958. XId fieldid;
  1959. X{
  1960. X    int i;
  1961. X    Field *fld = field + fieldno;
  1962. X    char *name = fld->name;
  1963. X
  1964. X    if( only_keys && !(field[fieldno].type & FT_KEY) )
  1965. X        return;
  1966. X
  1967. X    fprintf(file, "#define ");
  1968. X
  1969. X    for( i=0; i<fields; i++ )
  1970. X    {
  1971. X        if( field[i].nesting == 0 )
  1972. X        {
  1973. X            if( !strcmp(field[i].name, name) && i != fieldno )
  1974. X            {
  1975. X                /* Found a duplicate field name */
  1976. X                fprintf(file, "%s_", record[field[fieldno].recid].name);
  1977. X                break;
  1978. X            }
  1979. X        }
  1980. X    }
  1981. X
  1982. X    fprintf(file, "%s %ldL\n", name, fieldid);
  1983. X
  1984. X    if( !strcmp(name, "USERCLASS") )
  1985. X    {
  1986. X        puts("AAAAAAARRRRRRRRRGGGGGGGG!!!!!!");
  1987. X        printf("%d, %d\n", only_keys, field[fieldno].type & FT_KEY);
  1988. X    }
  1989. X}
  1990. X
  1991. X
  1992. X
  1993. X#ifdef PROTOTYPES
  1994. Xvoid err_quit(char *s, ...)
  1995. X#else
  1996. Xvoid err_quit(s)
  1997. Xchar *s;
  1998. X#endif
  1999. X{
  2000. X   va_list ap;
  2001. X   
  2002. X   va_start(ap, s);
  2003. X   vfprintf(stderr, s, ap);
  2004. X   puts("");
  2005. X   va_end(ap);
  2006. X   exit(1);
  2007. X}
  2008. X
  2009. X
  2010. Xstatic void init_vars()
  2011. X{
  2012. X    int i;
  2013. X
  2014. X    memset(&header,0,sizeof header);
  2015. X       strcpy(header.version, DBD_VERSION);
  2016. X
  2017. X    /* Initialize the sorttable */
  2018. X    for( i=0; i<256; i++ )
  2019. X        header.sorttable[i] = i;
  2020. X
  2021. X    for( i=0; i<'z'-'a'+1; i++ )
  2022. X        header.sorttable['A' + i] = 'a' + i;
  2023. X}
  2024. X
  2025. X
  2026. Xmain(argc, argv)
  2027. Xchar *argv[];
  2028. X{
  2029. X    char *realname;
  2030. X    char *p;
  2031. X    int i;
  2032. X    long n=0, prev;
  2033. X
  2034. X    puts("Typhoon Data Definition Language Processsor version 2.24");
  2035. X
  2036. X    if( argc == 1 )
  2037. X    {
  2038. X        printf(paramhelp, align);
  2039. X        exit(1);
  2040. X    }
  2041. X
  2042. X    /* Allocate tables */
  2043. X    record        = (Record   *)calloc(RECORDS_MAX   , sizeof(Record));
  2044. X    field        = (Field    *)calloc(FIELDS_MAX    , sizeof(Field));
  2045. X    file        = (File     *)calloc(FILES_MAX     , sizeof(File));
  2046. X    key            = (Key      *)calloc(KEYS_MAX      , sizeof(Key));
  2047. X    keyfield    = (KeyField *)calloc(KEYFIELDS_MAX , sizeof(KeyField));
  2048. X    structdef   = (Structdef*)calloc(STRUCTDEFS_MAX, sizeof(Structdef));
  2049. X
  2050. X    if( !(record && field && file && key && keyfield && structdef) )
  2051. X    {
  2052. X        puts("Not enough memory for tables");
  2053. X        exit(1);
  2054. X    }
  2055. X
  2056. X    /* Initialize tables */
  2057. X    for( i=0; i<KEYS_MAX; i++ )
  2058. X        key[i].fileid = -1;
  2059. X
  2060. X    /* Extract the real name of the file */
  2061. X    if( (realname = strrchr(argv[argc-1], DIR_SWITCH)) != NULL )
  2062. X        realname++;
  2063. X    else
  2064. X        realname = argv[argc-1];
  2065. X
  2066. X    /* remove .ddl extension if present */
  2067. X    if( p = strstr(realname, ".ddl") )
  2068. X        *p = 0;
  2069. X
  2070. X    /* generate file names for .ddl-file, .dbd-file and header file */
  2071. X    sprintf(ddlname, "%s.ddl", argv[argc-1]);
  2072. X    sprintf(dbdname, "%s.dbd", realname);
  2073. X    sprintf(hname, "%s.h", realname);
  2074. X
  2075. X    /* process command line options */
  2076. X    for( i=1; i<argc-1; i++ )
  2077. X    {
  2078. X        if( argv[i][0] == '-' || argv[i][0] == '/' )
  2079. X        {
  2080. X            switch( argv[i][1] )
  2081. X            {
  2082. X                case 'h':
  2083. X                    strcpy(hname, argv[i]+2);
  2084. X                    break;
  2085. X                case 'a':
  2086. X                    align = argv[i][2] - '0';
  2087. X                    if( align != 1 && align != 2 && align != 4 )
  2088. X                        err_quit("alignment must be 1, 2 or 4");
  2089. X                    break;
  2090. X                case 'f':
  2091. X                    only_keys = 1;
  2092. X                    break;
  2093. X                default:
  2094. X                    err_quit("unknown command line option");
  2095. X            }
  2096. X        }
  2097. X        else
  2098. X            err_quit("unknown command line option");
  2099. X    }
  2100. X
  2101. X    init_vars();
  2102. X
  2103. X    /* open files */
  2104. X    if( (lex_file=fopen(ddlname, "r")) == NULL )
  2105. X        err_quit("cannot open file '%s'", ddlname);
  2106. X
  2107. X    if( !(dbdfile=open(dbdname, O_RDWR|O_BINARY|O_TRUNC|O_CREAT, CREATMASK)) )
  2108. X        err_quit("cannot create .dbd file '%s'", dbdname);
  2109. X
  2110. X    if( (hfile=fopen(hname, "w")) == NULL )
  2111. X        err_quit("cannot create header file '%s'", hname);
  2112. X
  2113. X    /*---------- initialize h-file ----------*/
  2114. X    fprintf(hfile, "/*---------- headerfile for %s ----------*/\n", ddlname);
  2115. X    fprintf(hfile, "/* alignment is %d */\n\n", align);
  2116. X
  2117. X    /*---------- Initialize tables and parse input ----------*/
  2118. X    record[0].first_field = 0;
  2119. X
  2120. X    if( !yyparse() )
  2121. X    {
  2122. X        fix_file();
  2123. X        fix_fields();
  2124. X
  2125. X        header.files        = files;
  2126. X        header.keys            = keys;
  2127. X        header.keyfields    = keyfields;
  2128. X        header.records        = records;
  2129. X        header.fields        = fields;
  2130. X        header.structdefs    = structdefs;
  2131. X        header.alignment    = align;
  2132. X
  2133. X        /*---------- write dbd-file ----------*/
  2134. X        write(dbdfile, &header,        sizeof header);
  2135. X        write(dbdfile, file,        sizeof(file[0])        * files);
  2136. X        write(dbdfile, key,            sizeof(key[0])        * keys);
  2137. X        write(dbdfile, keyfield,    sizeof(keyfield[0])    * keyfields);
  2138. X        write(dbdfile, record,        sizeof(record[0])    * records);
  2139. X        write(dbdfile, field,        sizeof(field[0])    * fields);
  2140. X        write(dbdfile, structdef,    sizeof(structdef[0])* structdefs);
  2141. X
  2142. X        /*---------- write h-file ----------*/
  2143. X        fprintf(hfile, "/*---------- structures ----------*/\n");
  2144. X        print_structures();
  2145. X
  2146. X        fprintf(hfile, "/*---------- record names ----------*/\n");
  2147. X        for( i=0; i<records; i++ )
  2148. X            fprintf(hfile, "#define %s %ldL\n", strupr(record[i].name), (i+1) * REC_FACTOR);
  2149. X
  2150. X        for( i=0; i<fields; i++ )
  2151. X            strupr(field[i].name);
  2152. X
  2153. X        fprintf(hfile, "\n/*---------- field names ----------*/\n");
  2154. X        for( i=0, prev=-2; i<fields; i++, n++ )
  2155. X        {
  2156. X            if( field[i].nesting == 0 )
  2157. X            {
  2158. X                if( field[i].recid != prev )
  2159. X                    n = (field[i].recid+1) * REC_FACTOR + 1;
  2160. X
  2161. X                print_fieldname(hfile, i, n);
  2162. X                prev = field[i].recid;
  2163. X            }
  2164. X        }
  2165. X
  2166. X        /* Print all keys that are either a multi-field key or foreign key */
  2167. X        fprintf(hfile, "\n/*---------- key constants ----------*/\n");
  2168. X        for( i=0; i<keys; i++ )
  2169. X        {
  2170. X            /* If the key only has one field, and the name of the key is
  2171. X            * the same as the name of the field, then don't print the key name.
  2172. X            */
  2173. X            if( key[i].fields == 1 && 
  2174. X                !istrcmp(key[i].name, field[ keyfield[key[i].first_keyfield].field].name) )
  2175. X                    continue;   
  2176. X
  2177. X            if( KT_GETBASIC(key[i].type) != KT_FOREIGN )
  2178. X                   fprintf(hfile, "#define %s %d\n", strupr(key[i].name), i);
  2179. X        }
  2180. X
  2181. X        fprintf(hfile, "\n/*---------- integer constants ----------*/\n");
  2182. X        for( i=0; i<defines; i++ )
  2183. X            fprintf(hfile, "#define %s %d\n", define[i].name, define[i].value);
  2184. X    }
  2185. X
  2186. X    fclose(hfile);
  2187. X    fclose(lex_file);
  2188. X    close(dbdfile);
  2189. X
  2190. X    if( !errors )
  2191. X        printf("%d records, %d fields\n", records, fields);
  2192. X    else
  2193. X    {
  2194. X        unlink(dbdname);
  2195. X        unlink(hname);
  2196. X    }
  2197. X
  2198. X    free(record);
  2199. X    free(field);
  2200. X    free(file);
  2201. X    free(key);
  2202. X    free(keyfield);
  2203. X    free(structdef);
  2204. X
  2205. X    printf("%d lines, %d errors\n", lex_lineno, errors);
  2206. X
  2207. X    return errors != 0;
  2208. X}
  2209. X
  2210. X/* end-of-file */
  2211. END_OF_FILE
  2212.   if test 21611 -ne `wc -c <'typhoon/src/util/ddlp.c'`; then
  2213.     echo shar: \"'typhoon/src/util/ddlp.c'\" unpacked with wrong size!
  2214.   fi
  2215.   # end of 'typhoon/src/util/ddlp.c'
  2216. fi
  2217. if test -f 'typhoon/src/util/lex.c' -a "${1}" != "-c" ; then 
  2218.   echo shar: Will not clobber existing file \"'typhoon/src/util/lex.c'\"
  2219. else
  2220.   echo shar: Extracting \"'typhoon/src/util/lex.c'\" \(2849 characters\)
  2221.   sed "s/^X//" >'typhoon/src/util/lex.c' <<'END_OF_FILE'
  2222. X/*----------------------------------------------------------------------------
  2223. X * File    : @(#)lex.c       93/11/08         Copyright (c) 1993-94 CT Danmark
  2224. X * Compiler: UNIX C, Turbo C, Microsoft C
  2225. X * OS      : UNIX, OS/2, DOS
  2226. X * Author  : Thomas B. Pedersen
  2227. X *
  2228. X * Description:
  2229. X *   General functions for lexical analysers.
  2230. X *
  2231. X * Revision History
  2232. X * ----------------------------------------
  2233. X * 11-Nov-1993 tbp  Initial version.
  2234. X *
  2235. X *--------------------------------------------------------------------------*/
  2236. X
  2237. X/*-------------------------- Function prototypes ---------------------------*/
  2238. Xstatic int     keywordcmp        PRM( (char *, char *); )
  2239. X
  2240. X
  2241. X
  2242. Xvoid lex_skip_comment()
  2243. X{
  2244. X    int c, start;
  2245. X
  2246. X    start = lex_lineno;
  2247. X    for( ;; )
  2248. X    {
  2249. X        switch( getc(lex_file) )
  2250. X        {
  2251. X            case '*':
  2252. X                if( (c=getc(lex_file)) == '/' )
  2253. X                    return;
  2254. X                else
  2255. X                    ungetc(c, lex_file);
  2256. X                break;
  2257. X            case '\n':
  2258. X                lex_lineno++;
  2259. X                break;
  2260. X            case '/':
  2261. X                if( (c=getc(lex_file)) == '*' )        /* nested comment        */
  2262. X                    lex_skip_comment();
  2263. X                else
  2264. X                    ungetc(c, lex_file);
  2265. X                break;
  2266. X            case EOF:
  2267. X                fprintf(stderr, "unterminated comment starting in line %d\n", start);
  2268. X                exit(1);
  2269. X        }
  2270. X    }
  2271. X}
  2272. X
  2273. X
  2274. Xstatic keywordcmp(ck,ce)
  2275. Xchar *ck;
  2276. Xchar *ce;
  2277. X{
  2278. X    return strcmp(ck, ((LEX_KEYWORD *)ce)->s);
  2279. X}
  2280. X
  2281. X
  2282. X
  2283. Xlex_parse_keyword(char c)
  2284. X{
  2285. X    char *p = yylval.s;
  2286. X    int i;
  2287. X    LEX_KEYWORD *kword;
  2288. X
  2289. X    *p = c;
  2290. X
  2291. X    do
  2292. X        *++p = getc(lex_file);
  2293. X    while( isalnum(*p) || *p=='_' );
  2294. X
  2295. X    ungetc(*p, lex_file);
  2296. X    *p = '\0';
  2297. X
  2298. X    if( p - yylval.s > sizeof(yylval.s)-1 )
  2299. X    {
  2300. X        fprintf(stderr, "line %d: identifier too long, truncated\n", lex_lineno);
  2301. X        yylval.s[sizeof(yylval.s)-1] = '\0';
  2302. X    }
  2303. X
  2304. X    kword = (LEX_KEYWORD *)bsearch(yylval.s,
  2305. X                             lex_keywordtab,
  2306. X                            lex_keywords,
  2307. X                            sizeof(LEX_KEYWORD),
  2308. X                            (LEX_CMPFUNC)keywordcmp);
  2309. X    if( kword == NULL )
  2310. X    {
  2311. X#ifdef T_NUMBER
  2312. X        /* See if identifier is in define table */
  2313. X        for( i=0; i<defines; i++ )
  2314. X            if( !strcmp(yylval.s, define[i].name) )
  2315. X            {
  2316. X                yylval.val = define[i].value;
  2317. X                return T_NUMBER;
  2318. X            }
  2319. X#endif    
  2320. X        return T_IDENT;
  2321. X    }
  2322. X
  2323. X    return kword->token;
  2324. X}
  2325. X
  2326. X#ifdef T_NUMBER
  2327. Xlex_parse_number(char c)
  2328. X{
  2329. X      yylval.val = 0;
  2330. X    do
  2331. X    {
  2332. X        yylval.val = yylval.val * 10 + c - '0';
  2333. X        c = getc(lex_file);
  2334. X    }
  2335. X    while( isdigit(c) );
  2336. X    ungetc(c, lex_file);
  2337. X
  2338. X    return T_NUMBER;
  2339. X}
  2340. X#endif
  2341. X
  2342. X
  2343. X#ifdef T_STRING
  2344. Xlex_parse_string()
  2345. X{
  2346. X    char *p = yylval.s;
  2347. X
  2348. X    while( (*p = getc(lex_file)) != '"' )
  2349. X    {
  2350. X        if( *p == '\n' )
  2351. X            yyerror("newline in string");
  2352. X        else                
  2353. X            p++;
  2354. X    }
  2355. X
  2356. X    *p = '\0';
  2357. X
  2358. X    return T_STRING;
  2359. X}
  2360. X#endif
  2361. X
  2362. X#ifdef T_CHARCONST
  2363. Xlex_parse_charconst()
  2364. X{
  2365. X    /* ' has already been read */
  2366. X    yylval.val = getc(lex_file);
  2367. X    
  2368. X    if( getc(lex_file) != '\'' )
  2369. X        yyerror("unterminated character constant");
  2370. X        
  2371. X    return T_CHARCONST;
  2372. X}
  2373. X#endif
  2374. X
  2375. Xvoid lex_skip_line(void)
  2376. X{
  2377. X    int c;
  2378. X
  2379. X    while( (c = getc(lex_file)) != '\n' && c != EOF )
  2380. X        ;
  2381. X    if( c == EOF )
  2382. X        ungetc(EOF, lex_file);
  2383. X
  2384. X    lex_lineno++;
  2385. X}
  2386. X
  2387. X/* end-of-file */
  2388. X
  2389. END_OF_FILE
  2390.   if test 2849 -ne `wc -c <'typhoon/src/util/lex.c'`; then
  2391.     echo shar: \"'typhoon/src/util/lex.c'\" unpacked with wrong size!
  2392.   fi
  2393.   # end of 'typhoon/src/util/lex.c'
  2394. fi
  2395. echo shar: End of archive 1 \(of 9\).
  2396. cp /dev/null ark1isdone
  2397. MISSING=""
  2398. for I in 1 2 3 4 5 6 7 8 9 ; do
  2399.     if test ! -f ark${I}isdone ; then
  2400.     MISSING="${MISSING} ${I}"
  2401.     fi
  2402. done
  2403. if test "${MISSING}" = "" ; then
  2404.     echo You have unpacked all 9 archives.
  2405.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2406. else
  2407.     echo You still must unpack the following archives:
  2408.     echo "        " ${MISSING}
  2409. fi
  2410. exit 0
  2411. exit 0 # Just in case...
  2412.